# pkgmngr
This merge introduces a fully implemented package manager, various optimizations and changes to extension compiler php. - Implemented proper log error levels for the CLI (So stuff like `--log` and `-l` will work, and when using `verbose` or `debug` levels, special effects such as the inline progress bar will not be shown. - Implemented `--no-color` - Various bug fixes and minor optimizations to the code-base - Fixed various installer bug - Added some more documentation (But it's unfinished) ## Resolved issues & Work Items checklist A list of issues that this merge resolves or is in progress of resolving - [ ✅ issue #21 ](https://git.n64.cc/nosial/ncc/-/issues/21) **Add first-time install program files to be constructed** - Commit [b8c88bf4226e88760df221bb95070b8c34f3768d](b8c88bf422
) addresses this issue by implementing a method that initializes non-existent directories & files and setting the correct permissions for their intended purpose - [ ✅ Work Item #14 ](https://git.n64.cc/nosial/ncc/-/work_items/15) **Implement a CLI command to display all installed packages on the system** - Commit [3e52a30096653e3bf212b4e7e36ce6f94d245ee3](3e52a30096
) Implements a CLI command by implementing a method to walk through the PackageLock and display all the installed packages indicated by the current PackageLock state - [ ✅ Work Item #13 ](https://git.n64.cc/nosial/ncc/-/work_items/14) **Implement a CLI command for uninstalling packages** - By result this also resolves [Work Item #12](https://git.n64.cc/nosial/ncc/-/work_items/13) **Implement Uninstaller** with commit [8da4f532a146d626db1ee388eeb763ae14523589](8da4f532a1
), [263f50a6680f26c47c04c92941ac9cc82b2b43d3](263f50a668
) & [2390c6395cc60a5221a0c3064283200ed47273da](2390c6395c
) by implementing uninstallation methods to the PackageManager & into the CLI Menu for Package Managing - [ ✅ Work Item #10 ](https://git.n64.cc/nosial/ncc/-/work_items/11) **Implement Installer** - [ ✅ Work item #9 ](https://git.n64.cc/nosial/ncc/-/work_items/10) **Create PackageManager Class and implement Install() method** - [ ✅ Work item #8 ](https://git.n64.cc/nosial/ncc/-/issues/8) **Implement Package Manager** - [ ✅ Work item #7 ](https://git.n64.cc/nosial/ncc/-/issues/7) **Implement PackageLock**
This commit is contained in:
commit
d03f31fe6a
90 changed files with 6796 additions and 847 deletions
3
.idea/scopes/NCC_Source_files.xml
generated
Normal file
3
.idea/scopes/NCC_Source_files.xml
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="NCC Source files" pattern="file[ncc]:src/ncc/Managers//*||file[ncc]:src/ncc/Abstracts//*||file[ncc]:src/ncc/Exceptions//*||file[ncc]:src/ncc/Runtime//*||file[ncc]:src/ncc/Extensions//*||file[ncc]:src/ncc/CLI//*||file[ncc]:src/ncc/Classes//*||file[ncc]:src/ncc/Objects//*||file[ncc]:src/ncc/Interfaces//*||file[ncc]:src/ncc/Utilities//*||file:src/ncc/ncc.php||file:src/ncc/ncc||file:src/ncc/banner_basic||file:src/ncc/autoload_spl.php||file:src/ncc/autoload.php" />
|
||||
</component>
|
3
.idea/scopes/Third_Party_Source_Files.xml
generated
Normal file
3
.idea/scopes/Third_Party_Source_Files.xml
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="Third Party Source Files" pattern="file[ncc]:src/ncc/ThirdParty//*" />
|
||||
</component>
|
BIN
assets/pkg_struct_1.0.png
Normal file
BIN
assets/pkg_struct_1.0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
151
docs/project_configuration/execution_policy.md
Normal file
151
docs/project_configuration/execution_policy.md
Normal file
|
@ -0,0 +1,151 @@
|
|||
# Execution Policies
|
||||
|
||||
**Updated on Sunday, November 20, 2022**
|
||||
|
||||
An execution policy is a policy defined in the Project
|
||||
configuration file (`project.json`) that can be used
|
||||
to execute a script or program in any stage of the package
|
||||
|
||||
For instance, you can have a script that is executed before
|
||||
the build process starts, or in different installation stages
|
||||
when the user is installing your package you can have a unit
|
||||
run before or after the installation/uninstallation process
|
||||
starts.#
|
||||
|
||||
Use cases such as this allows you to properly implement
|
||||
and control your program's files & assets that are not
|
||||
handled by NCC's compiler extensions.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<!-- TOC -->
|
||||
* [Execution Policies](#execution-policies)
|
||||
* [Table of Contents](#table-of-contents)
|
||||
* [JSON Example](#json-example)
|
||||
* [ExecutionPolicy Object](#executionpolicy-object)
|
||||
* [Object Properties](#object-properties)
|
||||
* [JSON Example](#json-example)
|
||||
* [ExecutionConfiguration Object](#executionconfiguration-object)
|
||||
* [Object Properties](#object-properties)
|
||||
* [JSON Example](#json-example)
|
||||
* [ExitHandler Object](#exithandler-object)
|
||||
* [Object Properties](#object-properties)
|
||||
* [JSON Example](#json-example)
|
||||
<!-- TOC -->
|
||||
|
||||
|
||||
## JSON Example
|
||||
|
||||
```json
|
||||
{
|
||||
"execution_policies": {
|
||||
"main": {
|
||||
"runner": "php",
|
||||
"message": "Running main %ASSEMBLY.PACKAGE%",
|
||||
"exec": {
|
||||
"target": "scripts/main.php",
|
||||
"working_directory": "%INSTALL_PATH.SRC%",
|
||||
"silent": false
|
||||
}
|
||||
},
|
||||
"hello_world": {
|
||||
"runner": "shell",
|
||||
"message": "Running HTOP",
|
||||
"options": {
|
||||
"htop": null
|
||||
},
|
||||
"exec": {
|
||||
"tty": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
## ExecutionPolicy Object
|
||||
|
||||
Execution Policies for your project **must** have unique
|
||||
names, because they way you tell NCC to execute these
|
||||
policies is by referencing their name in the configuration.
|
||||
|
||||
Invalid names/undefined policies will raise errors when
|
||||
building the project
|
||||
|
||||
### Object Properties
|
||||
|
||||
| Property Name | Value Type | Example Value | Description |
|
||||
|-----------------|---------------------------------|----------------------|--------------------------------------------------------------------------------------------|
|
||||
| `runner` | string | bash | The name of a supported runner instance, see runners in this document |
|
||||
| `message` | string, null | Starting foo_bar ... | *Optional* the message to display before running the execution policy |
|
||||
| `exec` | ExecutionConfiguration | N/A | The configuration object that tells how the runner should execute the process |
|
||||
| `exit_handlers` | ExitHandlersConfiguration, null | N/A | *Optional* Exit Handler Configurations that tells NCC how to handle exits from the process |
|
||||
|
||||
### JSON Example
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "foo_bar",
|
||||
"runner": "bash",
|
||||
"message": "Running foo_bar ...",
|
||||
"exec": null,
|
||||
"exit_handlers": null
|
||||
}
|
||||
```
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
## ExecutionConfiguration Object
|
||||
|
||||
### Object Properties
|
||||
|
||||
| Property Name | Value Type | Example Value | Description |
|
||||
|---------------------|-------------------|---------------------------------|------------------------------------------------------------------------|
|
||||
| `target` | `string` | scripts/foo_bar.bash | The target file to execute |
|
||||
| `working_directory` | `string`, `null` | %INSTALL_PATH.SRC% | *optional* The working directory to execute the process in |
|
||||
| `options` | `array`, `null` | {"run": null, "log": "verbose"} | Commandline Parameters to pass on to the target or process |
|
||||
| `silent` | `boolean`, `null` | False | Indicates if the target should run silently, by default this is false. |
|
||||
| `tty` | `boolean`, `null` | False | Indicates if the target should run in TTY mode |
|
||||
| `timeout` | `integer`, `null` | 60 | The amount of seconds to wait before the process is killed |
|
||||
|
||||
### JSON Example
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "scripts/foo_bar.bash",
|
||||
"working_directory": "%INSTALL_PATH.SRC%",
|
||||
"options": {"run": null, "log": "verbose"},
|
||||
"silent": false,
|
||||
"tty": false,
|
||||
"timeout": 10
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
## ExitHandler Object
|
||||
|
||||
An exit handler is executed once the specified exit code is
|
||||
returned or the process exits with an error or normally, if
|
||||
an exit handler is specified it will be executed.
|
||||
|
||||
### Object Properties
|
||||
|
||||
| Property Name | Value Type | Example Value | Description |
|
||||
|---------------|--------------------|---------------|------------------------------------------------------------------------------|
|
||||
| `message` | `string` | Hello World! | The message to display when the exit handler is triggered |
|
||||
| `end_process` | `boolean`, `null` | False | *optional* Kills the process after this exit handler is triggered |
|
||||
| `run` | `string`, `null` | `null` | *optional* A execution policy to execute once this exit handler is triggered |
|
||||
| `exit_code` | `int`, `null` | 1 | The exit code that triggers this exit handler |
|
||||
### JSON Example
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World",
|
||||
"end_process": false,
|
||||
"run": null,
|
||||
"exit_code": 1
|
||||
}
|
||||
```
|
|
@ -12,12 +12,8 @@
|
|||
|
||||
<?PHP
|
||||
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\ComponentVersionNotFoundException;
|
||||
use ncc\Abstracts\ConsoleColors;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Managers\CredentialManager;
|
||||
use ncc\ncc;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
|
||||
|
@ -29,7 +25,7 @@
|
|||
use ncc\ThirdParty\Symfony\Yaml\Yaml;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\Utilities\Validate;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
@ -82,6 +78,7 @@
|
|||
// Initialize NCC
|
||||
try
|
||||
{
|
||||
define('NCC_CLI_MODE', 1);
|
||||
ncc::initialize();
|
||||
}
|
||||
catch (FileNotFoundException|\ncc\Exceptions\RuntimeException $e)
|
||||
|
@ -192,7 +189,7 @@
|
|||
];
|
||||
foreach($required_files as $path)
|
||||
{
|
||||
if(!file_exists($path))
|
||||
if(!$NCC_FILESYSTEM->exists($path))
|
||||
{
|
||||
Console::outError('Missing file \'' . $path . '\', installation failed.', true, 1);
|
||||
exit(1);
|
||||
|
@ -202,7 +199,7 @@
|
|||
// Preform the checksum validation
|
||||
if(!$NCC_BYPASS_CHECKSUM)
|
||||
{
|
||||
if(!file_exists($NCC_CHECKSUM))
|
||||
if(!$NCC_FILESYSTEM->exists($NCC_CHECKSUM))
|
||||
{
|
||||
Console::outWarning('The file \'checksum.bin\' was not found, the contents of the program cannot be verified to be safe');
|
||||
}
|
||||
|
@ -210,7 +207,16 @@
|
|||
{
|
||||
Console::out('Running checksum');
|
||||
|
||||
$checksum = ZiProto::decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin'));
|
||||
try
|
||||
{
|
||||
$checksum = ZiProto::decode(IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin'));
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError($e->getMessage(), true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$checksum_failed = false;
|
||||
|
||||
foreach($checksum as $path => $hash)
|
||||
|
@ -239,24 +245,33 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Check for required extensions
|
||||
$curl_available = true;
|
||||
foreach(Validate::requiredExtensions() as $ext => $installed)
|
||||
// Check the installed extensions and report
|
||||
Console::out('Checking installed extensions...');
|
||||
$extensions = Validate::requiredExtensions();
|
||||
foreach($extensions as $ext => $installed)
|
||||
{
|
||||
if(!$installed)
|
||||
if($installed)
|
||||
{
|
||||
switch($ext)
|
||||
{
|
||||
case 'curl':
|
||||
Console::outWarning('This installer requires the \'curl\' extension to install composer');
|
||||
$curl_available = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::outWarning('The extension \'' . $ext . '\' is not installed, compatibility without it is not guaranteed');
|
||||
break;
|
||||
}
|
||||
Console::out("$ext ... " . Console::formatColor("installed", ConsoleColors::LightGreen));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out("$ext ... " . Console::formatColor("missing", ConsoleColors::LightRed));
|
||||
}
|
||||
}
|
||||
|
||||
// Check for curl if the installer requires it
|
||||
$curl_available = true;
|
||||
if(!$extensions['curl'])
|
||||
{
|
||||
if(getParameter($NCC_ARGS, 'install-composer') !== null)
|
||||
{
|
||||
Console::outError('This installer requires the \'curl\' extension to install composer', true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$curl_available = false;
|
||||
Console::outWarning('The extension \'curl\' is not installed, the installer will not be able to install composer');
|
||||
}
|
||||
|
||||
// Attempt to load version information
|
||||
|
@ -283,14 +298,16 @@
|
|||
|
||||
try
|
||||
{
|
||||
Console::out($full_name . ' Version: ' . $component->getVersion());
|
||||
Console::out(Console::formatColor($full_name, ConsoleColors::Green) . ' Version: ' . Console::formatColor($component->getVersion(), ConsoleColors::LightMagenta));
|
||||
}
|
||||
catch (ComponentVersionNotFoundException $e)
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outWarning('Cannot determine component version of ' . $full_name);
|
||||
Console::outWarning('Cannot determine component version of ' . Console::formatColor($full_name, ConsoleColors::Green));
|
||||
}
|
||||
}
|
||||
|
||||
Console::out('Starting installation');
|
||||
|
||||
// Determine the installation path
|
||||
$skip_prompt = false;
|
||||
$install_dir_arg = getParameter($NCC_ARGS, 'install-dir');
|
||||
|
@ -304,7 +321,7 @@
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if(file_exists($install_dir_arg . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
if($NCC_FILESYSTEM->exists($install_dir_arg . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install');
|
||||
$NCC_INSTALL_PATH = $install_dir_arg;
|
||||
|
@ -323,9 +340,9 @@
|
|||
{
|
||||
$user_input = null;
|
||||
$user_input = Console::getInput("Installation Path (Default: $NCC_INSTALL_PATH): ");
|
||||
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input))
|
||||
if(strlen($user_input) > 0 && $NCC_FILESYSTEM->exists($user_input) && Validate::unixFilepath($user_input))
|
||||
{
|
||||
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
if($NCC_FILESYSTEM->exists($user_input . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
$NCC_INSTALL_PATH = $user_input;
|
||||
break;
|
||||
|
@ -346,7 +363,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Determine the data path
|
||||
$skip_prompt = false;
|
||||
$data_dir_arg = getParameter($NCC_ARGS, 'data-dir');
|
||||
|
@ -360,7 +376,7 @@
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if(file_exists($data_dir_arg . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
if($NCC_FILESYSTEM->exists($data_dir_arg . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
{
|
||||
$NCC_DATA_PATH = $data_dir_arg;
|
||||
$skip_prompt = true;
|
||||
|
@ -379,9 +395,9 @@
|
|||
{
|
||||
$user_input = null;
|
||||
$user_input = Console::getInput("Data Path (Default: $NCC_DATA_PATH): ");
|
||||
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input))
|
||||
if(strlen($user_input) > 0 && $NCC_FILESYSTEM->exists($user_input) && Validate::unixFilepath($user_input))
|
||||
{
|
||||
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
if($NCC_FILESYSTEM->exists($user_input . DIRECTORY_SEPARATOR . 'package.lck'))
|
||||
{
|
||||
$NCC_DATA_PATH = $user_input;
|
||||
break;
|
||||
|
@ -409,14 +425,17 @@
|
|||
{
|
||||
$update_composer = true;
|
||||
}
|
||||
elseif(getParameter($NCC_ARGS, 'install-composer') !== null)
|
||||
{
|
||||
$update_composer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out("Note: This doesn't affect your current install of composer (if you have composer installed)");
|
||||
$update_composer = Console::getBooleanInput('Do you want to install composer for NCC? (Recommended)');
|
||||
if(!$NCC_AUTO_MODE)
|
||||
{
|
||||
Console::out("Note: This doesn't affect your current install of composer (if you have composer installed)");
|
||||
$update_composer = Console::getBooleanInput('Do you want to install composer for NCC? (Recommended)');
|
||||
}
|
||||
else
|
||||
{
|
||||
$update_composer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -424,6 +443,7 @@
|
|||
$update_composer = false;
|
||||
}
|
||||
|
||||
|
||||
if(!$NCC_AUTO_MODE)
|
||||
{
|
||||
if(!Console::getBooleanInput('Do you want install NCC?'))
|
||||
|
@ -435,14 +455,22 @@
|
|||
|
||||
// Backup the configuration file
|
||||
$config_backup = null;
|
||||
if(file_exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml'))
|
||||
if($NCC_FILESYSTEM->exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml'))
|
||||
{
|
||||
Console::out('ncc.yaml will be updated');
|
||||
$config_backup = file_get_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml');
|
||||
try
|
||||
{
|
||||
$config_backup = IO::fread($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError($e->getMessage(), true, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare installation
|
||||
if(file_exists($NCC_INSTALL_PATH))
|
||||
if($NCC_FILESYSTEM->exists($NCC_INSTALL_PATH))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -455,35 +483,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Create the required directories
|
||||
$required_dirs = [
|
||||
$NCC_INSTALL_PATH,
|
||||
$NCC_DATA_PATH,
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'packages',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'repos',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'downloads',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'data',
|
||||
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'ext',
|
||||
];
|
||||
$NCC_FILESYSTEM->mkdir($NCC_INSTALL_PATH, 0755);
|
||||
|
||||
$NCC_FILESYSTEM->mkdir($required_dirs, 0755);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config'], 0777);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache'], 0777);
|
||||
|
||||
// Verify directories exist
|
||||
foreach($required_dirs as $dir)
|
||||
try
|
||||
{
|
||||
if(!file_exists($dir))
|
||||
{
|
||||
Console::outError("Cannot create directory '$dir', please verify if you have write permissions to the directory.");
|
||||
exit(1);
|
||||
}
|
||||
Functions::initializeFiles();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError('Cannot initialize NCC files, ' . $e->getMessage());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Install composer
|
||||
if($curl_available && $update_composer)
|
||||
if($update_composer)
|
||||
{
|
||||
Console::out('Installing composer for NCC');
|
||||
|
||||
|
@ -501,11 +514,10 @@
|
|||
fclose($fp);
|
||||
|
||||
Console::out('Running composer installer');
|
||||
// TODO: Unescaped shell arguments are a security issue
|
||||
$Process = Process::fromShellCommandline(implode(' ', [
|
||||
$NCC_PHP_EXECUTABLE,
|
||||
$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer-setup.php',
|
||||
'--install-dir=' . $NCC_INSTALL_PATH,
|
||||
escapeshellcmd($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer-setup.php'),
|
||||
'--install-dir=' . escapeshellcmd($NCC_INSTALL_PATH),
|
||||
'--filename=composer.phar'
|
||||
]));
|
||||
$Process->setWorkingDirectory($NCC_INSTALL_PATH);
|
||||
|
@ -536,7 +548,15 @@
|
|||
|
||||
// Install NCC
|
||||
Console::out('Copying files to \'' . $NCC_INSTALL_PATH . '\'');
|
||||
$build_files = explode("\n", file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'build_files'));
|
||||
try
|
||||
{
|
||||
$build_files = explode("\n", IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'build_files'));
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError($e->getMessage(), true, 1);
|
||||
return;
|
||||
}
|
||||
$total_items = count($build_files);
|
||||
$processed_items = 0;
|
||||
|
||||
|
@ -561,7 +581,7 @@
|
|||
$NCC_FILESYSTEM->copy(__DIR__ . DIRECTORY_SEPARATOR . $file, $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file);
|
||||
$NCC_FILESYSTEM->chmod([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file], 0755);
|
||||
|
||||
if(!file_exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file))
|
||||
if(!$NCC_FILESYSTEM->exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file))
|
||||
{
|
||||
Console::outError('Cannot create file \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file . '\', installation failed.');
|
||||
exit(1);
|
||||
|
@ -573,32 +593,19 @@
|
|||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
// Create credential store if needed
|
||||
Console::out('Processing Credential Store');
|
||||
$credential_manager = new CredentialManager();
|
||||
|
||||
try
|
||||
{
|
||||
$credential_manager->constructStore();
|
||||
}
|
||||
catch (AccessDeniedException|\ncc\Exceptions\RuntimeException $e)
|
||||
{
|
||||
Console::outError('Cannot construct credential store, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$NCC_FILESYSTEM->touch([PathFinder::getPackageLock(Scopes::System)]);
|
||||
}
|
||||
catch (InvalidScopeException $e)
|
||||
{
|
||||
Console::outError('Cannot create package lock, ' . $e->getMessage());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Generate executable shortcut
|
||||
Console::out('Creating shortcut');
|
||||
$executable_shortcut = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'ncc.sh');
|
||||
|
||||
try
|
||||
{
|
||||
$executable_shortcut = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'ncc.sh');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError($e->getMessage(), true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$executable_shortcut = str_ireplace('%php_exec', $NCC_PHP_EXECUTABLE, $executable_shortcut);
|
||||
$executable_shortcut = str_ireplace('%ncc_exec', $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut);
|
||||
|
||||
|
@ -611,41 +618,65 @@
|
|||
foreach($bin_paths as $path)
|
||||
{
|
||||
// Delete old versions of the executable shortcuts.
|
||||
if(file_exists($path . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
if($NCC_FILESYSTEM->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
$NCC_FILESYSTEM->remove($path . DIRECTORY_SEPARATOR . 'ncc');
|
||||
}
|
||||
|
||||
if($NCC_FILESYSTEM->exists([$path]))
|
||||
if($NCC_FILESYSTEM->exists($path))
|
||||
{
|
||||
file_put_contents($path . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut);
|
||||
$NCC_FILESYSTEM->chmod([$path . DIRECTORY_SEPARATOR . 'ncc'], 0755);
|
||||
try
|
||||
{
|
||||
IO::fwrite($path . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut);
|
||||
break;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outException($e->getMessage(), $e, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register the ncc extension
|
||||
Console::out('Registering extension');
|
||||
$extension_shortcut = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'extension');
|
||||
try
|
||||
{
|
||||
$extension_shortcut = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'extension');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outError($e->getMessage(), true, 1);
|
||||
return;
|
||||
}
|
||||
$extension_shortcut = str_ireplace('%ncc_install', $NCC_INSTALL_PATH, $extension_shortcut);
|
||||
|
||||
// Remove all the old extensions first.
|
||||
/**
|
||||
* @param string $path
|
||||
* @param Filesystem $NCC_FILESYSTEM
|
||||
* @param Filesystem $filesystem
|
||||
* @param string $extension_shortcut
|
||||
* @return bool
|
||||
*/
|
||||
function install_extension(string $path, Filesystem $NCC_FILESYSTEM, string $extension_shortcut): bool
|
||||
function install_extension(string $path, Filesystem $filesystem, string $extension_shortcut): bool
|
||||
{
|
||||
if (file_exists($path . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
if ($filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
$NCC_FILESYSTEM->remove($path . DIRECTORY_SEPARATOR . 'ncc');
|
||||
$filesystem->remove($path . DIRECTORY_SEPARATOR . 'ncc');
|
||||
}
|
||||
|
||||
file_put_contents($path . DIRECTORY_SEPARATOR . 'ncc', $extension_shortcut);
|
||||
$NCC_FILESYSTEM->chmod([$path . DIRECTORY_SEPARATOR . 'ncc'], 0755);
|
||||
try
|
||||
{
|
||||
IO::fwrite($path . DIRECTORY_SEPARATOR . 'ncc', $extension_shortcut);
|
||||
}
|
||||
catch (\ncc\Exceptions\IOException $e)
|
||||
{
|
||||
Console::outException($e->getMessage(), $e, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_exists($path . DIRECTORY_SEPARATOR . 'ncc')) {
|
||||
if ($filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -745,7 +776,15 @@
|
|||
Console::out('Updating ncc.yaml');
|
||||
}
|
||||
|
||||
file_put_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml', Yaml::dump($config_obj));
|
||||
try
|
||||
{
|
||||
IO::fwrite($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml', Yaml::dump($config_obj));
|
||||
}
|
||||
catch (\ncc\Exceptions\IOException $e)
|
||||
{
|
||||
Console::outException($e->getMessage(), $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Console::out('NCC version: ' . NCC_VERSION_NUMBER . ' has been successfully installed');
|
||||
Console::out('For licensing information see \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'LICENSE\' or run \'ncc help --license\'');
|
||||
|
|
14
src/ncc/Abstracts/ConstantReferences.php
Normal file
14
src/ncc/Abstracts/ConstantReferences.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts;
|
||||
|
||||
abstract class ConstantReferences
|
||||
{
|
||||
const Assembly = 'assembly';
|
||||
|
||||
const Build = 'build';
|
||||
|
||||
const DateTime = 'date_time';
|
||||
|
||||
const Install = 'install';
|
||||
}
|
|
@ -6,12 +6,17 @@
|
|||
use ncc\Exceptions\AutoloadGeneratorException;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\BuildException;
|
||||
use ncc\Exceptions\ComponentChecksumException;
|
||||
use ncc\Exceptions\ComponentDecodeException;
|
||||
use ncc\Exceptions\ComponentVersionNotFoundException;
|
||||
use ncc\Exceptions\ConstantReadonlyException;
|
||||
use ncc\Exceptions\DirectoryNotFoundException;
|
||||
use ncc\Exceptions\ExecutionUnitNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InstallationException;
|
||||
use ncc\Exceptions\InvalidConstantNameException;
|
||||
use ncc\Exceptions\InvalidCredentialsEntryException;
|
||||
use ncc\Exceptions\InvalidExecutionPolicyName;
|
||||
use ncc\Exceptions\InvalidPackageException;
|
||||
use ncc\Exceptions\InvalidPackageNameException;
|
||||
use ncc\Exceptions\InvalidProjectBuildConfiguration;
|
||||
|
@ -21,12 +26,25 @@
|
|||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Exceptions\InvalidVersionConfigurationException;
|
||||
use ncc\Exceptions\InvalidVersionNumberException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Exceptions\NoAvailableUnitsException;
|
||||
use ncc\Exceptions\NoUnitsFoundException;
|
||||
use ncc\Exceptions\PackageAlreadyInstalledException;
|
||||
use ncc\Exceptions\PackageLockException;
|
||||
use ncc\Exceptions\PackageNotFoundException;
|
||||
use ncc\Exceptions\PackageParsingException;
|
||||
use ncc\Exceptions\ProjectAlreadyExistsException;
|
||||
use ncc\Exceptions\ProjectConfigurationNotFoundException;
|
||||
use ncc\Exceptions\ResourceChecksumException;
|
||||
use ncc\Exceptions\RunnerExecutionException;
|
||||
use ncc\Exceptions\RuntimeException;
|
||||
use ncc\Exceptions\UndefinedExecutionPolicyException;
|
||||
use ncc\Exceptions\UnsupportedComponentTypeException;
|
||||
use ncc\Exceptions\UnsupportedCompilerExtensionException;
|
||||
use ncc\Exceptions\UnsupportedPackageException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Exceptions\VersionNotFoundException;
|
||||
|
||||
/**
|
||||
* @author Zi Xing Narrakas
|
||||
|
@ -174,6 +192,96 @@
|
|||
*/
|
||||
const BuildException = -1727;
|
||||
|
||||
/**
|
||||
* @see PackageParsingException
|
||||
*/
|
||||
const PackageParsingException = -1728;
|
||||
|
||||
/**
|
||||
* @see PackageLockException
|
||||
*/
|
||||
const PackageLockException = -1729;
|
||||
|
||||
/**
|
||||
* @see InstallationException
|
||||
*/
|
||||
const InstallationException = -1730;
|
||||
|
||||
/**
|
||||
* @see UnsupportedComponentTypeException
|
||||
*/
|
||||
const UnsupportedComponentTypeException = -1731;
|
||||
|
||||
/**
|
||||
* @see ComponentDecodeException
|
||||
*/
|
||||
const ComponentDecodeException = -1732;
|
||||
|
||||
/**
|
||||
* @see ComponentChecksumException
|
||||
*/
|
||||
const ComponentChecksumException = -1733;
|
||||
|
||||
/**
|
||||
* @see ResourceChecksumException
|
||||
*/
|
||||
const ResourceChecksumException = -1734;
|
||||
|
||||
/**
|
||||
* @see IOException
|
||||
*/
|
||||
const IOException = -1735;
|
||||
|
||||
/**
|
||||
* @see UnsupportedRunnerException
|
||||
*/
|
||||
const UnsupportedRunnerException = -1736;
|
||||
|
||||
/**
|
||||
* @see VersionNotFoundException
|
||||
*/
|
||||
const VersionNotFoundException = -1737;
|
||||
|
||||
/**
|
||||
* @see UndefinedExecutionPolicyException
|
||||
*/
|
||||
const UndefinedExecutionPolicyException = -1738;
|
||||
|
||||
/**
|
||||
* @see InvalidExecutionPolicyName
|
||||
*/
|
||||
const InvalidExecutionPolicyName = -1739;
|
||||
|
||||
/**
|
||||
* @see ProjectConfigurationNotFoundException
|
||||
*/
|
||||
const ProjectConfigurationNotFoundException = -1740;
|
||||
|
||||
/**
|
||||
* @see RunnerExecutionException
|
||||
*/
|
||||
const RunnerExecutionException = -1741;
|
||||
|
||||
/**
|
||||
* @see NoAvailableUnitsException
|
||||
*/
|
||||
const NoAvailableUnitsException = -1742;
|
||||
|
||||
/**
|
||||
* @see ExecutionUnitNotFoundException
|
||||
*/
|
||||
const ExecutionUnitNotFoundException = -1743;
|
||||
|
||||
/**
|
||||
* @see PackageAlreadyInstalledException
|
||||
*/
|
||||
const PackageAlreadyInstalledException = -1744;
|
||||
|
||||
/**
|
||||
* @see PackageNotFoundException
|
||||
*/
|
||||
const PackageNotFoundException = -1745;
|
||||
|
||||
/**
|
||||
* All the exception codes from NCC
|
||||
*/
|
||||
|
@ -205,6 +313,23 @@
|
|||
self::InvalidPropertyValueException,
|
||||
self::InvalidVersionConfigurationException,
|
||||
self::UnsupportedExtensionVersionException,
|
||||
self::BuildException
|
||||
self::BuildException,
|
||||
self::PackageParsingException,
|
||||
self::PackageLockException,
|
||||
self::InstallationException,
|
||||
self::UnsupportedComponentTypeException,
|
||||
self::ComponentDecodeException,
|
||||
self::ResourceChecksumException,
|
||||
self::IOException,
|
||||
self::UnsupportedRunnerException,
|
||||
self::VersionNotFoundException,
|
||||
self::UndefinedExecutionPolicyException,
|
||||
self::InvalidExecutionPolicyName,
|
||||
self::ProjectConfigurationNotFoundException,
|
||||
self::RunnerExecutionException,
|
||||
self::NoAvailableUnitsException,
|
||||
self::ExecutionUnitNotFoundException,
|
||||
self::PackageAlreadyInstalledException,
|
||||
self::PackageNotFoundException
|
||||
];
|
||||
}
|
30
src/ncc/Abstracts/LogLevel.php
Normal file
30
src/ncc/Abstracts/LogLevel.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts;
|
||||
|
||||
abstract class LogLevel
|
||||
{
|
||||
const Silent = 'silent';
|
||||
|
||||
const Verbose = 'verbose';
|
||||
|
||||
const Debug = 'debug';
|
||||
|
||||
const Info = 'info';
|
||||
|
||||
const Warning = 'warn';
|
||||
|
||||
const Error = 'error';
|
||||
|
||||
const Fatal = 'fatal';
|
||||
|
||||
const All = [
|
||||
self::Silent,
|
||||
self::Verbose,
|
||||
self::Debug,
|
||||
self::Info,
|
||||
self::Warning,
|
||||
self::Error,
|
||||
self::Fatal,
|
||||
];
|
||||
}
|
|
@ -5,4 +5,6 @@
|
|||
abstract class BuildConfigurationValues
|
||||
{
|
||||
const DefaultConfiguration = 'default';
|
||||
|
||||
const AllConfigurations = 'all';
|
||||
}
|
12
src/ncc/Abstracts/PackageStructureVersions.php
Normal file
12
src/ncc/Abstracts/PackageStructureVersions.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts;
|
||||
|
||||
abstract class PackageStructureVersions
|
||||
{
|
||||
const _1_0 = '1.0';
|
||||
|
||||
const ALL = [
|
||||
self::_1_0
|
||||
];
|
||||
}
|
|
@ -23,4 +23,6 @@
|
|||
const WindowsPath = '/^(([%][^\/:*?<>""|]*[%])|([a-zA-Z][:])|(\\\\))((\\\\{1})|((\\\\{1})[^\\\\]([^\/:*?<>""|]*))+)$/m';
|
||||
|
||||
const ConstantName = '/^([^\x00-\x7F]|[\w_\ \.\+\-]){2,64}$/';
|
||||
|
||||
const ExecutionPolicyName = '/^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/m';
|
||||
}
|
8
src/ncc/Abstracts/Runners.php
Normal file
8
src/ncc/Abstracts/Runners.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts;
|
||||
|
||||
abstract class Runners
|
||||
{
|
||||
const php = 'php';
|
||||
}
|
51
src/ncc/Abstracts/SpecialConstants/AssemblyConstants.php
Normal file
51
src/ncc/Abstracts/SpecialConstants/AssemblyConstants.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts\SpecialConstants;
|
||||
|
||||
abstract class AssemblyConstants
|
||||
{
|
||||
/**
|
||||
* Assembly's Name Property
|
||||
*/
|
||||
const AssemblyName = '%ASSEMBLY.NAME%';
|
||||
|
||||
/**
|
||||
* Assembly's Package Property
|
||||
*/
|
||||
const AssemblyPackage = '%ASSEMBLY.PACKAGE%';
|
||||
|
||||
/**
|
||||
* Assembly's Description Property
|
||||
*/
|
||||
const AssemblyDescription = '%ASSEMBLY.DESCRIPTION%';
|
||||
|
||||
/**
|
||||
* Assembly's Company Property
|
||||
*/
|
||||
const AssemblyCompany = '%ASSEMBLY.COMPANY%';
|
||||
|
||||
/**
|
||||
* Assembly's Product Property
|
||||
*/
|
||||
const AssemblyProduct = '%ASSEMBLY.PRODUCT%';
|
||||
|
||||
/**
|
||||
* Assembly's Copyright Property
|
||||
*/
|
||||
const AssemblyCopyright = '%ASSEMBLY.COPYRIGHT%';
|
||||
|
||||
/**
|
||||
* Assembly's Trademark Property
|
||||
*/
|
||||
const AssemblyTrademark = '%ASSEMBLY.TRADEMARK%';
|
||||
|
||||
/**
|
||||
* Assembly's Version Property
|
||||
*/
|
||||
const AssemblyVersion = '%ASSEMBLY.VERSION%';
|
||||
|
||||
/**
|
||||
* Assembly's UUID property
|
||||
*/
|
||||
const AssemblyUid = '%ASSEMBLY.UID%';
|
||||
}
|
26
src/ncc/Abstracts/SpecialConstants/BuildConstants.php
Normal file
26
src/ncc/Abstracts/SpecialConstants/BuildConstants.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts\SpecialConstants;
|
||||
|
||||
abstract class BuildConstants
|
||||
{
|
||||
/**
|
||||
* The Unix Timestamp for when the package was compiled
|
||||
*/
|
||||
const CompileTimestamp = '%COMPILE_TIMESTAMP%';
|
||||
|
||||
/**
|
||||
* The version of NCC that was used to compile the package
|
||||
*/
|
||||
const NccBuildVersion = '%NCC_BUILD_VERSION%';
|
||||
|
||||
/**
|
||||
* NCC Build Flags exploded into spaces
|
||||
*/
|
||||
const NccBuildFlags = '%NCC_BUILD_FLAGS%';
|
||||
|
||||
/**
|
||||
* NCC Build Branch
|
||||
*/
|
||||
const NccBuildBranch = '%NCC_BUILD_BRANCH%';
|
||||
}
|
162
src/ncc/Abstracts/SpecialConstants/DateTimeConstants.php
Normal file
162
src/ncc/Abstracts/SpecialConstants/DateTimeConstants.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts\SpecialConstants;
|
||||
|
||||
abstract class DateTimeConstants
|
||||
{
|
||||
// Day Format
|
||||
|
||||
/**
|
||||
* Day of the month, 2 digits with leading zeros
|
||||
*/
|
||||
const d = '%d%'; // 01 through 31
|
||||
|
||||
/**
|
||||
* A textual representation of a day, three letters
|
||||
*/
|
||||
const D = '%D%'; // Mon through Sun
|
||||
|
||||
/**
|
||||
* Day of the month without leading zeros
|
||||
*/
|
||||
const j = '%j%'; // 1 through 31
|
||||
|
||||
/**
|
||||
* A full textual representation of the day of the week
|
||||
*/
|
||||
const l = '%l%'; // Sunday through Saturday
|
||||
|
||||
/**
|
||||
* ISO 8601 numeric representation of the day of the week
|
||||
*/
|
||||
const N = '%N%'; // 1 (Monday) to 7 (Sunday)
|
||||
|
||||
/**
|
||||
* English ordinal suffix for the day of the month, 2 characters
|
||||
*/
|
||||
const S = '%S%'; // st, nd, rd, th
|
||||
|
||||
/**
|
||||
* Numeric representation of the day of the week
|
||||
*/
|
||||
const w = '%w%'; // 0 (sunday) through 6 (Saturday)
|
||||
|
||||
/**
|
||||
* The day of the year (starting from 0)
|
||||
*/
|
||||
const z = '%z%'; // 0 through 365
|
||||
|
||||
|
||||
|
||||
// Week Format
|
||||
|
||||
/**
|
||||
* ISO 8601 week number of year, weeks starting on Monday
|
||||
*/
|
||||
const W = '%W%'; // 42 (42nd week in year)
|
||||
|
||||
|
||||
|
||||
// Month Format
|
||||
|
||||
/**
|
||||
* A full textual representation of a month, such as January or March
|
||||
*/
|
||||
const F = '%F%'; // January through December
|
||||
|
||||
/**
|
||||
* Numeric representation of a month, with leading zeros
|
||||
*/
|
||||
const m = '%m%'; // 01 through 12
|
||||
|
||||
/**
|
||||
* A short textual representation of a month, three letters
|
||||
*/
|
||||
const M = '%M%'; // Jan through Dec
|
||||
|
||||
/**
|
||||
* Numeric representation of a month, without leading zeros
|
||||
*/
|
||||
const n = '%n%'; // 1 through 12
|
||||
|
||||
/**
|
||||
* Number of days in the given month
|
||||
*/
|
||||
const t = '%t%'; // 28 through 31
|
||||
|
||||
|
||||
|
||||
// Year format
|
||||
/**
|
||||
* Whether it's a leap year
|
||||
*/
|
||||
const L = '%L%'; // 1 (leap year), 0 otherwise
|
||||
|
||||
/**
|
||||
* ISO 8601 week-numbering year. This has the same value as Y,
|
||||
* except that if the ISO week number (W) belongs to the previous
|
||||
* or next year, that year is used instead.
|
||||
*/
|
||||
const o = '%o%'; // Same as Y, except that it use week number to decide which year it falls onto
|
||||
|
||||
/**
|
||||
* A full numeric representation of a year, at least 4 digits, with - for years BCE.
|
||||
*/
|
||||
const Y = '%Y%'; // 1991, 2012, 2014, ...
|
||||
|
||||
/**
|
||||
* A two digit representation of a year
|
||||
*/
|
||||
const y = '%y%'; // 91, 12, 14, ...
|
||||
|
||||
// Time Format
|
||||
/**
|
||||
* Lowercase Ante meridiem and Post meridiem
|
||||
*/
|
||||
const a = '%a%'; // am or pm
|
||||
|
||||
/**
|
||||
* Uppercase Ante meridiem and Post meridiem
|
||||
*/
|
||||
const A = '%A%'; // AM or PM
|
||||
|
||||
/**
|
||||
* Swatch Internet time
|
||||
*/
|
||||
const B = '%B%'; // 000 through 999
|
||||
|
||||
/**
|
||||
* 12-hour format of an hour without leading zeros
|
||||
*/
|
||||
const g = '%g%'; // 1 through 12
|
||||
|
||||
/**
|
||||
* 24-hour format of an hour without leading zeros
|
||||
*/
|
||||
const G = '%G%'; // 0 through 23
|
||||
|
||||
/**
|
||||
* 12-hour format of an hour with leading zeros
|
||||
*/
|
||||
const h = '%h%'; // 01 through 12
|
||||
|
||||
/**
|
||||
* 24-hour format of an hour with leading zeros
|
||||
*/
|
||||
const H = '%H%'; // 01 through 23
|
||||
|
||||
/**
|
||||
* Minutes with leading zeros
|
||||
*/
|
||||
const i = '%i%'; // 01 through 59
|
||||
|
||||
/**
|
||||
* Seconds with leading zeros
|
||||
*/
|
||||
const s = '%s%'; // 00 through 59
|
||||
|
||||
// DateTime format
|
||||
const c = '%c%'; // 2004-02-12T15:19:21
|
||||
const r = '%r%'; // Thu, 21 Dec 2000 16:01:07
|
||||
const u = '%u%'; // Unix Timestamp (seconds since Jan 1 1970 00:00:00)
|
||||
}
|
14
src/ncc/Abstracts/SpecialConstants/InstallConstants.php
Normal file
14
src/ncc/Abstracts/SpecialConstants/InstallConstants.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts\SpecialConstants;
|
||||
|
||||
abstract class InstallConstants
|
||||
{
|
||||
const InstallationPath = '%INSTALL_PATH%';
|
||||
|
||||
const BinPath = '%INSTALL_PATH.BIN%';
|
||||
|
||||
const SourcePath = '%INSTALL_PATH.SRC%';
|
||||
|
||||
const DataPath = '%INSTALL_PATH.DATA%';
|
||||
}
|
8
src/ncc/Abstracts/SpecialConstants/RuntimeConstants.php
Normal file
8
src/ncc/Abstracts/SpecialConstants/RuntimeConstants.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts\SpecialConstants;
|
||||
|
||||
abstract class RuntimeConstants
|
||||
{
|
||||
const CWD = '%CWD%';
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Abstracts;
|
||||
|
||||
abstract class SpecialFormat
|
||||
{
|
||||
const AssemblyName = '%ASSEMBLY.NAME%';
|
||||
|
||||
const AssemblyPackage = '%ASSEMBLY.PACKAGE%';
|
||||
|
||||
const AssemblyDescription = '%ASSEMBLY.DESCRIPTION%';
|
||||
|
||||
const AssemblyCompany = '%ASSEMBLY.COMPANY%';
|
||||
|
||||
const AssemblyProduct = '%ASSEMBLY.PRODUCT%';
|
||||
|
||||
const AssemblyCopyright = '%ASSEMBLY.COPYRIGHT%';
|
||||
|
||||
const AssemblyTrademark = '%ASSEMBLY.TRADEMARK%';
|
||||
|
||||
const AssemblyVersion = '%ASSEMBLY.VERSION%';
|
||||
|
||||
const AssemblyUid = '%ASSEMBLY.UID%';
|
||||
|
||||
const CompileTimestamp = '%COMPILE_TIMESTAMP%';
|
||||
|
||||
const NccBuildVersion = '%NCC_BUILD_VERSION%';
|
||||
|
||||
const NccBuildArgs = '%NCC_BUILD_FLAGS%';
|
||||
|
||||
const NccBuildBranch = '%NCC_BUILD_BRANCH%';
|
||||
}
|
|
@ -13,4 +13,9 @@
|
|||
* The current version of the package structure file format
|
||||
*/
|
||||
const PackageStructureVersion = '1.0';
|
||||
|
||||
/**
|
||||
* The current version of the package lock structure file format
|
||||
*/
|
||||
const PackageLockVersion = '1.0.0';
|
||||
}
|
|
@ -3,16 +3,9 @@
|
|||
namespace ncc\CLI;
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
use ncc\Abstracts\CompilerExtensions;
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Classes\PhpExtension\Compiler;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Interfaces\CompilerInterface;
|
||||
use ncc\Managers\ProjectManager;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\Utilities\Console;
|
||||
|
||||
class BuildMenu
|
||||
|
@ -22,8 +15,9 @@
|
|||
*
|
||||
* @param $args
|
||||
* @return void
|
||||
* @noinspection PhpNoReturnAttributeCanBeAddedInspection
|
||||
*/
|
||||
#[NoReturn] public static function start($args): void
|
||||
public static function start($args): void
|
||||
{
|
||||
if(isset($args['help']))
|
||||
{
|
||||
|
@ -48,12 +42,6 @@
|
|||
{
|
||||
$path_arg = ($args['path'] ?? $args['p']);
|
||||
|
||||
// Append trailing slash
|
||||
if(substr($path_arg, -1) !== DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$path_arg .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
// Check if the path exists
|
||||
if(!file_exists($path_arg) || !is_dir($path_arg))
|
||||
{
|
||||
|
@ -67,92 +55,38 @@
|
|||
$project_path = getcwd();
|
||||
}
|
||||
|
||||
// Load the project
|
||||
try
|
||||
{
|
||||
$ProjectConfiguration = ProjectConfiguration::fromFile($project_path . DIRECTORY_SEPARATOR . 'project.json');
|
||||
}
|
||||
catch (FileNotFoundException $e)
|
||||
{
|
||||
Console::outException('Cannot find the file \'project.json\'', $e, 1);
|
||||
return;
|
||||
}
|
||||
catch (MalformedJsonException $e)
|
||||
{
|
||||
Console::outException('The file \'project.json\' contains malformed json data, please verify the syntax of the file', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Select the correct compiler for the specified extension
|
||||
switch(strtolower($ProjectConfiguration->Project->Compiler->Extension))
|
||||
{
|
||||
case CompilerExtensions::PHP:
|
||||
/** @var CompilerInterface $Compiler */
|
||||
$Compiler = new Compiler($ProjectConfiguration);
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::outError('The extension '. $ProjectConfiguration->Project->Compiler->Extension . ' is not supported', true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$build_configuration = BuildConfigurationValues::DefaultConfiguration;
|
||||
|
||||
if(isset($args['config']))
|
||||
{
|
||||
$build_configuration = $args['config'];
|
||||
}
|
||||
|
||||
// Auto-resolve to the default configuration if `default` is used or not specified
|
||||
if($build_configuration == BuildConfigurationValues::DefaultConfiguration)
|
||||
{
|
||||
$build_configuration = $ProjectConfiguration->Build->DefaultConfiguration;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$ProjectConfiguration->Build->getBuildConfiguration($build_configuration);
|
||||
}
|
||||
catch (BuildConfigurationNotFoundException $e)
|
||||
{
|
||||
Console::outException('The build configuration \'' . $build_configuration . '\' does not exist in the project configuration', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Console::out(
|
||||
' ===== BUILD INFO ===== ' . PHP_EOL .
|
||||
' Package Name: ' . $ProjectConfiguration->Assembly->Package . PHP_EOL .
|
||||
' Version: ' . $ProjectConfiguration->Assembly->Version . PHP_EOL .
|
||||
' Compiler Extension: ' . $ProjectConfiguration->Project->Compiler->Extension . PHP_EOL .
|
||||
' Compiler Version: ' . $ProjectConfiguration->Project->Compiler->MaximumVersion . ' - ' . $ProjectConfiguration->Project->Compiler->MinimumVersion . PHP_EOL .
|
||||
' Build Configuration: ' . $build_configuration . PHP_EOL
|
||||
);
|
||||
|
||||
Console::out('Preparing package');
|
||||
|
||||
try
|
||||
{
|
||||
$Compiler->prepare($project_path, $build_configuration);
|
||||
$ProjectManager = new ProjectManager($project_path);
|
||||
$ProjectManager->load();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outException('The package preparation process failed', $e, 1);
|
||||
Console::outException('Failed to load Project Configuration (project.json)', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Console::out('Compiling package');
|
||||
|
||||
// Build the project
|
||||
try
|
||||
{
|
||||
$Compiler->build($project_path);
|
||||
$build_configuration = BuildConfigurationValues::DefaultConfiguration;
|
||||
if(isset($args['config']))
|
||||
{
|
||||
$build_configuration = $args['config'];
|
||||
}
|
||||
|
||||
$output = $ProjectManager->build($build_configuration);
|
||||
|
||||
Console::out('Successfully built ' . $output);
|
||||
exit(0);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outException('Build Failed', $e, 1);
|
||||
Console::outException('Failed to build project', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\CLI;
|
||||
|
||||
class Functions
|
||||
{
|
||||
/**
|
||||
* Simple print function with builtin EOL terminator
|
||||
*
|
||||
* @param string $out
|
||||
* @param bool $eol
|
||||
* @param int $padding
|
||||
* @param int $pad_type
|
||||
* @param string $pad_string
|
||||
* @return void
|
||||
*/
|
||||
public static function print(string $out, bool $eol=true, int $padding=0, int $pad_type=0, string $pad_string=' ')
|
||||
{
|
||||
if($padding > 0)
|
||||
{
|
||||
$out = str_pad($out, $padding, $pad_string, $pad_type);
|
||||
}
|
||||
|
||||
if($eol)
|
||||
{
|
||||
$out = $out . PHP_EOL;
|
||||
}
|
||||
|
||||
print($out);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\CLI;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\Abstracts\NccBuildFlags;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\RuntimeException;
|
||||
|
@ -12,6 +15,16 @@
|
|||
|
||||
class Main
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $args;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private static $log_level;
|
||||
|
||||
/**
|
||||
* Executes the main CLI process
|
||||
*
|
||||
|
@ -20,9 +33,9 @@
|
|||
*/
|
||||
public static function start($argv): void
|
||||
{
|
||||
$args = Resolver::parseArguments(implode(' ', $argv));
|
||||
self::$args = Resolver::parseArguments(implode(' ', $argv));
|
||||
|
||||
if(isset($args['ncc-cli']))
|
||||
if(isset(self::$args['ncc-cli']))
|
||||
{
|
||||
// Initialize NCC
|
||||
try
|
||||
|
@ -41,6 +54,38 @@
|
|||
// Define CLI stuff
|
||||
define('NCC_CLI_MODE', 1);
|
||||
|
||||
if(isset(self::$args['l']) || isset(self::$args['log-level']))
|
||||
{
|
||||
switch(strtolower(self::$args['l'] ?? self::$args['log-level']))
|
||||
{
|
||||
case LogLevel::Silent:
|
||||
case LogLevel::Fatal:
|
||||
case LogLevel::Error:
|
||||
case LogLevel::Warning:
|
||||
case LogLevel::Info:
|
||||
case LogLevel::Debug:
|
||||
case LogLevel::Verbose:
|
||||
self::$log_level = strtolower(self::$args['l'] ?? self::$args['log-level']);
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::outWarning('Unknown log level: ' . (self::$args['l'] ?? self::$args['log-level']) . ', using \'info\'');
|
||||
self::$log_level = LogLevel::Info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$log_level = LogLevel::Info;
|
||||
}
|
||||
|
||||
if(Resolver::checkLogLevel(self::$log_level, LogLevel::Debug))
|
||||
{
|
||||
Console::outDebug('Debug logging enabled');
|
||||
Console::outDebug(sprintf('consts: %s', json_encode(ncc::getConstants(), JSON_UNESCAPED_SLASHES)));
|
||||
Console::outDebug(sprintf('args: %s', json_encode(self::$args, JSON_UNESCAPED_SLASHES)));
|
||||
}
|
||||
|
||||
if(in_array(NccBuildFlags::Unstable, NCC_VERSION_FLAGS))
|
||||
{
|
||||
Console::outWarning('This is an unstable build of NCC, expect some features to not work as expected');
|
||||
|
@ -48,37 +93,59 @@
|
|||
|
||||
try
|
||||
{
|
||||
switch(strtolower($args['ncc-cli']))
|
||||
switch(strtolower(self::$args['ncc-cli']))
|
||||
{
|
||||
default:
|
||||
Console::out('Unknown command ' . strtolower($args['ncc-cli']));
|
||||
Console::out('Unknown command ' . strtolower(self::$args['ncc-cli']));
|
||||
exit(1);
|
||||
|
||||
case 'project':
|
||||
ProjectMenu::start($args);
|
||||
ProjectMenu::start(self::$args);
|
||||
exit(0);
|
||||
|
||||
case 'build':
|
||||
BuildMenu::start($args);
|
||||
BuildMenu::start(self::$args);
|
||||
exit(0);
|
||||
|
||||
case 'credential':
|
||||
CredentialMenu::start($args);
|
||||
CredentialMenu::start(self::$args);
|
||||
exit(0);
|
||||
|
||||
case 'package':
|
||||
PackageManagerMenu::start(self::$args);
|
||||
exit(0);
|
||||
|
||||
case '1':
|
||||
case 'help':
|
||||
HelpMenu::start($args);
|
||||
HelpMenu::start(self::$args);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outException('Error: ' . $e->getMessage() . ' (Code: ' . $e->getCode() . ')', $e, 1);
|
||||
Console::outException($e->getMessage() . ' (Code: ' . $e->getCode() . ')', $e, 1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getArgs()
|
||||
{
|
||||
return self::$args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getLogLevel(): string
|
||||
{
|
||||
if(self::$log_level == null)
|
||||
self::$log_level = LogLevel::Info;
|
||||
return self::$log_level;
|
||||
}
|
||||
|
||||
}
|
345
src/ncc/CLI/PackageManagerMenu.php
Normal file
345
src/ncc/CLI/PackageManagerMenu.php
Normal file
|
@ -0,0 +1,345 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\CLI;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ConsoleColors;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\PackageLockException;
|
||||
use ncc\Exceptions\VersionNotFoundException;
|
||||
use ncc\Managers\PackageManager;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\Resolver;
|
||||
|
||||
class PackageManagerMenu
|
||||
{
|
||||
/**
|
||||
* Displays the main help menu
|
||||
*
|
||||
* @param $args
|
||||
* @return void
|
||||
*/
|
||||
public static function start($args): void
|
||||
{
|
||||
if(isset($args['install']))
|
||||
{
|
||||
try
|
||||
{
|
||||
self::installPackage($args);
|
||||
return;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outException('Installation Failed', $e, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($args['uninstall']))
|
||||
{
|
||||
try
|
||||
{
|
||||
self::uninstallPackage($args);
|
||||
return;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outException('Uninstallation Failed', $e, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($args['list']))
|
||||
{
|
||||
try
|
||||
{
|
||||
self::getInstallPackages();
|
||||
return;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outException('List Failed', $e, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self::displayOptions();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays all installed packages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function getInstallPackages(): void
|
||||
{
|
||||
$package_manager = new PackageManager();
|
||||
|
||||
try
|
||||
{
|
||||
$installed_packages = $package_manager->getInstalledPackages();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
Console::out('No packages installed');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
foreach($installed_packages as $package => $versions)
|
||||
{
|
||||
if(count($versions) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($versions as $version)
|
||||
{
|
||||
try
|
||||
{
|
||||
$package_version = $package_manager->getPackageVersion($package, $version);
|
||||
if($package_version == null)
|
||||
throw new Exception();
|
||||
|
||||
Console::out(sprintf('%s==%s (%s)',
|
||||
Console::formatColor($package, ConsoleColors::LightGreen),
|
||||
Console::formatColor($version, ConsoleColors::LightMagenta),
|
||||
$package_manager->getPackageVersion($package, $version)->Compiler->Extension
|
||||
));
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
Console::out(sprintf('%s==%s',
|
||||
Console::formatColor($package, ConsoleColors::LightGreen),
|
||||
Console::formatColor($version, ConsoleColors::LightMagenta)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $args
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private static function installPackage($args): void
|
||||
{
|
||||
$path = ($args['path'] ?? $args['p']);
|
||||
$package_manager = new PackageManager();
|
||||
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Insufficient permission to install packages');
|
||||
|
||||
if(!file_exists($path) || !is_file($path) || !is_readable($path))
|
||||
throw new FileNotFoundException('The specified file \'' . $path .' \' does not exist or is not readable.');
|
||||
|
||||
$user_confirmation = false;
|
||||
if(isset($args['y']) || isset($args['Y']))
|
||||
{
|
||||
$user_confirmation = (bool)($args['y'] ?? $args['Y']);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$package = Package::load($path);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outException('Error while loading package', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Console::out('Package installation details' . PHP_EOL);
|
||||
if(!is_null($package->Assembly->UUID))
|
||||
Console::out(' UUID: ' . Console::formatColor($package->Assembly->UUID, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Package))
|
||||
Console::out(' Package: ' . Console::formatColor($package->Assembly->Package, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Name))
|
||||
Console::out(' Name: ' . Console::formatColor($package->Assembly->Name, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Version))
|
||||
Console::out(' Version: ' . Console::formatColor($package->Assembly->Version, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Description))
|
||||
Console::out(' Description: ' . Console::formatColor($package->Assembly->Description, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Product))
|
||||
Console::out(' Product: ' . Console::formatColor($package->Assembly->Product, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Company))
|
||||
Console::out(' Company: ' . Console::formatColor($package->Assembly->Company, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Copyright))
|
||||
Console::out(' Copyright: ' . Console::formatColor($package->Assembly->Copyright, ConsoleColors::LightGreen));
|
||||
if(!is_null($package->Assembly->Trademark))
|
||||
Console::out(' Trademark: ' . Console::formatColor($package->Assembly->Trademark, ConsoleColors::LightGreen));
|
||||
Console::out((string)null);
|
||||
|
||||
if(count($package->Dependencies) > 0)
|
||||
{
|
||||
$dependencies = [];
|
||||
foreach($package->Dependencies as $dependency)
|
||||
{
|
||||
$dependencies[] = sprintf('%s v%s',
|
||||
Console::formatColor($dependency->Name, ConsoleColors::Green),
|
||||
Console::formatColor($dependency->Version, ConsoleColors::LightMagenta)
|
||||
);
|
||||
}
|
||||
|
||||
Console::out('The following dependencies will be installed:');
|
||||
Console::out(sprintf(' %s', implode(', ', $dependencies)) . PHP_EOL);
|
||||
}
|
||||
|
||||
Console::out(sprintf('Extension: %s',
|
||||
Console::formatColor($package->Header->CompilerExtension->Extension, ConsoleColors::Green)
|
||||
));
|
||||
|
||||
if($package->Header->CompilerExtension->MaximumVersion !== null)
|
||||
Console::out(sprintf('Maximum Version: %s',
|
||||
Console::formatColor($package->Header->CompilerExtension->MaximumVersion, ConsoleColors::LightMagenta)
|
||||
));
|
||||
|
||||
if($package->Header->CompilerExtension->MinimumVersion !== null)
|
||||
Console::out(sprintf('Minimum Version: %s',
|
||||
Console::formatColor($package->Header->CompilerExtension->MinimumVersion, ConsoleColors::LightMagenta)
|
||||
));
|
||||
|
||||
if(!$user_confirmation)
|
||||
$user_confirmation = Console::getBooleanInput(sprintf('Do you want to install %s', $package->Assembly->Package));
|
||||
|
||||
if($user_confirmation)
|
||||
{
|
||||
try
|
||||
{
|
||||
$package_manager->install($path);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outException('Installation Failed', $e, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Console::outError('User cancelled installation', true, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a version of a package or all versions of a package
|
||||
*
|
||||
* @param $args
|
||||
* @return void
|
||||
* @throws VersionNotFoundException
|
||||
*/
|
||||
private static function uninstallPackage($args): void
|
||||
{
|
||||
$selected_package = ($args['package'] ?? $args['pkg']);
|
||||
$selected_version = null;
|
||||
if(isset($args['v']))
|
||||
$selected_version = $args['v'];
|
||||
if(isset($args['version']))
|
||||
$selected_version = $args['version'];
|
||||
|
||||
$user_confirmation = null;
|
||||
// For undefined array key warnings
|
||||
if(isset($args['y']) || isset($args['Y']))
|
||||
$user_confirmation = (bool)($args['y'] ?? $args['Y']);
|
||||
|
||||
if($selected_package == null)
|
||||
Console::outError('Missing argument \'package\'', true, 1);
|
||||
|
||||
$package_manager = new PackageManager();
|
||||
|
||||
try
|
||||
{
|
||||
$package_entry = $package_manager->getPackage($selected_package);
|
||||
}
|
||||
catch (PackageLockException $e)
|
||||
{
|
||||
Console::outException('PackageLock error', $e, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
$version_entry = null;
|
||||
if($version_entry !== null && $package_entry !== null)
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$version_entry = $package_entry->getVersion($version_entry, false);
|
||||
|
||||
if($package_entry == null)
|
||||
{
|
||||
Console::outError(sprintf('Package "%s" is not installed', $selected_package), true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if($version_entry == null & $selected_version !== null)
|
||||
{
|
||||
Console::outError(sprintf('Package "%s==%s" is not installed', $selected_package, $selected_version), true, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if($user_confirmation == null)
|
||||
{
|
||||
if($selected_version !== null)
|
||||
{
|
||||
if(!Console::getBooleanInput(sprintf('Do you want to uninstall %s==%s', $selected_package, $selected_version)))
|
||||
{
|
||||
Console::outError('User cancelled operation', true, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!Console::getBooleanInput(sprintf('Do you want to uninstall all versions of %s', $selected_package)))
|
||||
{
|
||||
Console::outError('User cancelled operation', true, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if($selected_version !== null)
|
||||
{
|
||||
$package_manager->uninstallPackageVersion($selected_package, $selected_version);
|
||||
}
|
||||
else
|
||||
{
|
||||
$package_manager->uninstallPackage($selected_package);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outException('Uninstallation failed', $e, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the main options section
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function displayOptions(): void
|
||||
{
|
||||
$options = [
|
||||
new CliHelpSection(['help'], 'Displays this help menu about the value command'),
|
||||
new CliHelpSection(['install', '--path', '-p'], 'Installs a specified NCC package file'),
|
||||
new CliHelpSection(['list'], 'Lists all installed packages on the system'),
|
||||
];
|
||||
|
||||
$options_padding = Functions::detectParametersPadding($options) + 4;
|
||||
|
||||
Console::out('Usage: ncc install {command} [options]');
|
||||
Console::out('Options:' . PHP_EOL);
|
||||
foreach($options as $option)
|
||||
{
|
||||
Console::out(' ' . $option->toString($options_padding));
|
||||
}
|
||||
}
|
||||
}
|
129
src/ncc/Classes/NccExtension/ConstantCompiler.php
Normal file
129
src/ncc/Classes/NccExtension/ConstantCompiler.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Classes\NccExtension;
|
||||
|
||||
use ncc\Abstracts\SpecialConstants\BuildConstants;
|
||||
use ncc\Abstracts\SpecialConstants\DateTimeConstants;
|
||||
use ncc\Abstracts\SpecialConstants\InstallConstants;
|
||||
use ncc\Abstracts\SpecialConstants\AssemblyConstants;
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\Objects\ProjectConfiguration\Assembly;
|
||||
|
||||
class ConstantCompiler
|
||||
{
|
||||
/**
|
||||
* Compiles assembly constants about the project (Usually used during compiling time)
|
||||
*
|
||||
* @param string|null $input
|
||||
* @param Assembly $assembly
|
||||
* @return string|null
|
||||
* @noinspection PhpUnnecessaryLocalVariableInspection
|
||||
*/
|
||||
public static function compileAssemblyConstants(?string $input, Assembly $assembly): ?string
|
||||
{
|
||||
if($input == null)
|
||||
return null;
|
||||
|
||||
$input = str_replace(AssemblyConstants::AssemblyName, $assembly->Name, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyPackage, $assembly->Package, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyDescription, $assembly->Description, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyCompany, $assembly->Company, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyProduct, $assembly->Product, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyCopyright, $assembly->Copyright, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyTrademark, $assembly->Trademark, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyVersion, $assembly->Version, $input);
|
||||
$input = str_replace(AssemblyConstants::AssemblyUid, $assembly->UUID, $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles build constants about the NCC build (Usually used during compiling time)
|
||||
*
|
||||
* @param string|null $input
|
||||
* @return string|null
|
||||
* @noinspection PhpUnnecessaryLocalVariableInspection
|
||||
*/
|
||||
public static function compileBuildConstants(?string $input): ?string
|
||||
{
|
||||
if($input == null)
|
||||
return null;
|
||||
|
||||
$input = str_replace(BuildConstants::CompileTimestamp, time(), $input);
|
||||
$input = str_replace(BuildConstants::NccBuildVersion, NCC_VERSION_NUMBER, $input);
|
||||
$input = str_replace(BuildConstants::NccBuildFlags, implode(' ', NCC_VERSION_FLAGS), $input);
|
||||
$input = str_replace(BuildConstants::NccBuildBranch, NCC_VERSION_BRANCH, $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles installation constants (Usually used during compiling time)
|
||||
*
|
||||
* @param string|null $input
|
||||
* @param InstallationPaths $installationPaths
|
||||
* @return string|null
|
||||
* @noinspection PhpUnnecessaryLocalVariableInspection
|
||||
*/
|
||||
public static function compileInstallConstants(?string $input, InstallationPaths $installationPaths): ?string
|
||||
{
|
||||
if($input == null)
|
||||
return null;
|
||||
|
||||
$input = str_replace(InstallConstants::InstallationPath, $installationPaths->getInstallationPath(), $input);
|
||||
$input = str_replace(InstallConstants::BinPath, $installationPaths->getBinPath(), $input);
|
||||
$input = str_replace(InstallConstants::SourcePath, $installationPaths->getSourcePath(), $input);
|
||||
$input = str_replace(InstallConstants::DataPath, $installationPaths->getDataPath(), $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles DateTime constants from a Unix Timestamp
|
||||
*
|
||||
* @param string|null $input
|
||||
* @param int $timestamp
|
||||
* @return string|null
|
||||
* @noinspection PhpUnnecessaryLocalVariableInspection
|
||||
*/
|
||||
public static function compileDateTimeConstants(?string $input, int $timestamp): ?string
|
||||
{
|
||||
if($input == null)
|
||||
return null;
|
||||
|
||||
$input = str_replace(DateTimeConstants::d, date('d', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::D, date('D', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::j, date('j', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::l, date('l', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::N, date('N', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::S, date('S', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::w, date('w', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::z, date('z', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::W, date('W', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::F, date('F', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::m, date('m', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::M, date('M', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::n, date('n', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::t, date('t', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::L, date('L', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::o, date('o', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::Y, date('Y', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::y, date('y', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::a, date('a', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::A, date('A', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::B, date('B', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::g, date('g', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::G, date('G', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::h, date('h', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::H, date('H', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::i, date('i', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::s, date('s', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::c, date('c', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::r, date('r', $timestamp), $input);
|
||||
$input = str_replace(DateTimeConstants::u, date('u', $timestamp), $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
}
|
307
src/ncc/Classes/NccExtension/PackageCompiler.php
Normal file
307
src/ncc/Classes/NccExtension/PackageCompiler.php
Normal file
|
@ -0,0 +1,307 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Classes\NccExtension;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\CompilerExtensions;
|
||||
use ncc\Abstracts\ConstantReferences;
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Classes\PhpExtension\Compiler;
|
||||
use ncc\CLI\Main;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\BuildException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Exceptions\PackagePreparationFailedException;
|
||||
use ncc\Exceptions\ProjectConfigurationNotFoundException;
|
||||
use ncc\Exceptions\UnsupportedCompilerExtensionException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Interfaces\CompilerInterface;
|
||||
use ncc\Managers\ProjectManager;
|
||||
use ncc\ncc;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\Objects\ProjectConfiguration\Assembly;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\Resolver;
|
||||
|
||||
class PackageCompiler
|
||||
{
|
||||
/**
|
||||
* Compiles the project into a package
|
||||
*
|
||||
* @param ProjectManager $manager
|
||||
* @param string $build_configuration
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
* @throws BuildException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws MalformedJsonException
|
||||
* @throws PackagePreparationFailedException
|
||||
* @throws ProjectConfigurationNotFoundException
|
||||
* @throws UnsupportedCompilerExtensionException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public static function compile(ProjectManager $manager, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
|
||||
{
|
||||
$configuration = $manager->getProjectConfiguration();
|
||||
|
||||
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
|
||||
{
|
||||
foreach($configuration->Assembly->toArray() as $prop => $value)
|
||||
Console::outDebug(sprintf('assembly.%s: %s', $prop, ($value ?? 'n/a')));
|
||||
foreach($configuration->Project->Compiler->toArray() as $prop => $value)
|
||||
Console::outDebug(sprintf('compiler.%s: %s', $prop, ($value ?? 'n/a')));
|
||||
}
|
||||
|
||||
// Select the correct compiler for the specified extension
|
||||
/** @noinspection PhpSwitchCanBeReplacedWithMatchExpressionInspection */
|
||||
switch(strtolower($configuration->Project->Compiler->Extension))
|
||||
{
|
||||
case CompilerExtensions::PHP:
|
||||
/** @var CompilerInterface $Compiler */
|
||||
$Compiler = new Compiler($configuration, $manager->getProjectPath());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedCompilerExtensionException('The compiler extension \'' . $configuration->Project->Compiler->Extension . '\' is not supported');
|
||||
}
|
||||
|
||||
$build_configuration = $configuration->Build->getBuildConfiguration($build_configuration)->Name;
|
||||
$Compiler->prepare($build_configuration);
|
||||
$Compiler->build();
|
||||
|
||||
return PackageCompiler::writePackage(
|
||||
$manager->getProjectPath(), $Compiler->getPackage(), $configuration, $build_configuration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the execution policies of the package
|
||||
*
|
||||
* @param string $path
|
||||
* @param ProjectConfiguration $configuration
|
||||
* @return array
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public static function compileExecutionPolicies(string $path, ProjectConfiguration $configuration): array
|
||||
{
|
||||
if(count($configuration->ExecutionPolicies) == 0)
|
||||
return [];
|
||||
|
||||
Console::out('Compiling Execution Policies');
|
||||
$total_items = count($configuration->ExecutionPolicies);
|
||||
$execution_units = [];
|
||||
$processed_items = 0;
|
||||
|
||||
/** @var ProjectConfiguration\ExecutionPolicy $policy */
|
||||
foreach($configuration->ExecutionPolicies as $policy)
|
||||
{
|
||||
if($total_items > 5)
|
||||
{
|
||||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
$unit_path = Functions::correctDirectorySeparator($path . $policy->Execute->Target);
|
||||
$execution_units[] = Functions::compileRunner($unit_path, $policy);
|
||||
}
|
||||
|
||||
if(ncc::cliMode() && $total_items > 5)
|
||||
print(PHP_EOL);
|
||||
|
||||
return $execution_units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the finished package to disk, returns the output path
|
||||
*
|
||||
* @param string $path
|
||||
* @param Package $package
|
||||
* @param ProjectConfiguration $configuration
|
||||
* @param string $build_configuration
|
||||
* @return string
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
* @throws BuildException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function writePackage(string $path, Package $package, ProjectConfiguration $configuration, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
|
||||
{
|
||||
// Write the package to disk
|
||||
$FileSystem = new Filesystem();
|
||||
$BuildConfiguration = $configuration->Build->getBuildConfiguration($build_configuration);
|
||||
if($FileSystem->exists($path . $BuildConfiguration->OutputPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
$FileSystem->remove($path . $BuildConfiguration->OutputPath);
|
||||
}
|
||||
catch(\ncc\ThirdParty\Symfony\Filesystem\Exception\IOException $e)
|
||||
{
|
||||
throw new BuildException('Cannot delete directory \'' . $path . $BuildConfiguration->OutputPath . '\', ' . $e->getMessage(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally write the package to the disk
|
||||
$FileSystem->mkdir($path . $BuildConfiguration->OutputPath);
|
||||
$output_file = $path . $BuildConfiguration->OutputPath . DIRECTORY_SEPARATOR . $package->Assembly->Package . '.ncc';
|
||||
$FileSystem->touch($output_file);
|
||||
|
||||
try
|
||||
{
|
||||
$package->save($output_file);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new IOException('Cannot write to output file', $e);
|
||||
}
|
||||
|
||||
return $output_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the special formatted constants
|
||||
*
|
||||
* @param Package $package
|
||||
* @param int $timestamp
|
||||
* @return array
|
||||
*/
|
||||
public static function compileRuntimeConstants(Package $package, int $timestamp): array
|
||||
{
|
||||
$compiled_constants = [];
|
||||
|
||||
foreach($package->Header->RuntimeConstants as $name => $value)
|
||||
{
|
||||
$compiled_constants[$name] = self::compileConstants($value, [
|
||||
ConstantReferences::Assembly => $package->Assembly,
|
||||
ConstantReferences::DateTime => $timestamp,
|
||||
ConstantReferences::Build => null
|
||||
]);
|
||||
}
|
||||
|
||||
return $compiled_constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the constants in the package object
|
||||
*
|
||||
* @param Package $package
|
||||
* @param array $refs
|
||||
* @return void
|
||||
*/
|
||||
public static function compilePackageConstants(Package &$package, array $refs): void
|
||||
{
|
||||
if($package->Assembly !== null)
|
||||
{
|
||||
$assembly = [];
|
||||
foreach($package->Assembly->toArray() as $key => $value)
|
||||
{
|
||||
$assembly[$key] = self::compileConstants($value, $refs);
|
||||
}
|
||||
$package->Assembly = Assembly::fromArray($assembly);
|
||||
unset($assembly);
|
||||
}
|
||||
|
||||
if($package->ExecutionUnits !== null && count($package->ExecutionUnits) > 0)
|
||||
{
|
||||
$units = [];
|
||||
foreach($package->ExecutionUnits as $executionUnit)
|
||||
{
|
||||
$units[] = self::compileExecutionUnitConstants($executionUnit, $refs);
|
||||
}
|
||||
$package->ExecutionUnits = $units;
|
||||
unset($units);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the constants in a given execution unit
|
||||
*
|
||||
* @param Package\ExecutionUnit $unit
|
||||
* @param array $refs
|
||||
* @return Package\ExecutionUnit
|
||||
*/
|
||||
public static function compileExecutionUnitConstants(Package\ExecutionUnit $unit, array $refs): Package\ExecutionUnit
|
||||
{
|
||||
$unit->ExecutionPolicy->Message = self::compileConstants($unit->ExecutionPolicy->Message, $refs);
|
||||
|
||||
if($unit->ExecutionPolicy->ExitHandlers !== null)
|
||||
{
|
||||
if($unit->ExecutionPolicy->ExitHandlers->Success !== null)
|
||||
{
|
||||
$unit->ExecutionPolicy->ExitHandlers->Success->Message = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Success->Message, $refs);
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->ExitHandlers->Error !== null)
|
||||
{
|
||||
$unit->ExecutionPolicy->ExitHandlers->Error->Message = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Error->Message, $refs);
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->ExitHandlers->Warning !== null)
|
||||
{
|
||||
$unit->ExecutionPolicy->ExitHandlers->Warning->Error = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Warning->Message, $refs);
|
||||
}
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->Execute !== null)
|
||||
{
|
||||
if($unit->ExecutionPolicy->Execute->Target !== null)
|
||||
{
|
||||
$unit->ExecutionPolicy->Execute->Target = self::compileConstants($unit->ExecutionPolicy->Execute->Target, $refs);
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->Execute->WorkingDirectory !== null)
|
||||
{
|
||||
$unit->ExecutionPolicy->Execute->WorkingDirectory = self::compileConstants($unit->ExecutionPolicy->Execute->WorkingDirectory, $refs);
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->Execute->Options !== null && count($unit->ExecutionPolicy->Execute->Options) > 0)
|
||||
{
|
||||
$options = [];
|
||||
foreach($unit->ExecutionPolicy->Execute->Options as $key=>$value)
|
||||
{
|
||||
$options[self::compileConstants($key, $refs)] = self::compileConstants($value, $refs);
|
||||
}
|
||||
$unit->ExecutionPolicy->Execute->Options = $options;
|
||||
}
|
||||
}
|
||||
|
||||
return $unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles multiple types of constants
|
||||
*
|
||||
* @param string|null $value
|
||||
* @param array $refs
|
||||
* @return string|null
|
||||
*/
|
||||
public static function compileConstants(?string $value, array $refs): ?string
|
||||
{
|
||||
if($value == null)
|
||||
return null;
|
||||
|
||||
if(isset($refs[ConstantReferences::Assembly]))
|
||||
$value = ConstantCompiler::compileAssemblyConstants($value, $refs[ConstantReferences::Assembly]);
|
||||
|
||||
if(isset($refs[ConstantReferences::Build]))
|
||||
$value = ConstantCompiler::compileBuildConstants($value);
|
||||
|
||||
if(isset($refs[ConstantReferences::DateTime]))
|
||||
$value = ConstantCompiler::compileDateTimeConstants($value, $refs[ConstantReferences::DateTime]);
|
||||
|
||||
if(isset($refs[ConstantReferences::Install]))
|
||||
$value = ConstantCompiler::compileInstallConstants($value, $refs[ConstantReferences::Install]);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
47
src/ncc/Classes/NccExtension/Runner.php
Normal file
47
src/ncc/Classes/NccExtension/Runner.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Classes\NccExtension;
|
||||
|
||||
use ncc\Abstracts\Runners;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\ExecutionUnitNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\NoAvailableUnitsException;
|
||||
use ncc\Exceptions\RunnerExecutionException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Managers\ExecutionPointerManager;
|
||||
use ncc\Objects\ExecutionPointers\ExecutionPointer;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
|
||||
class Runner
|
||||
{
|
||||
/**
|
||||
* Temporarily executes an execution unit, removes it once it is executed
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @param ExecutionUnit $unit
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws UnsupportedRunnerException
|
||||
* @throws ExecutionUnitNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws NoAvailableUnitsException
|
||||
* @throws RunnerExecutionException
|
||||
*/
|
||||
public static function temporaryExecute(string $package, string $version, ExecutionUnit $unit)
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Cannot temporarily execute a unit with insufficent permissions');
|
||||
|
||||
$ExecutionPointerManager = new ExecutionPointerManager();
|
||||
$ExecutionPointerManager->addUnit($package, $version, $unit, true);
|
||||
$ExecutionPointerManager->executeUnit($package, $version, $unit->ExecutionPolicy->Name);
|
||||
$ExecutionPointerManager->cleanTemporaryUnits();;
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Classes;
|
||||
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
|
||||
class PackageParser
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $PackagePath;
|
||||
|
||||
/**
|
||||
* Package Parser public constructor.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->PackagePath = $path;
|
||||
$this->parseFile();
|
||||
}
|
||||
|
||||
private function parseFile()
|
||||
{
|
||||
if(file_exists($this->PackagePath) == false)
|
||||
{
|
||||
throw new FileNotFoundException('The given package path \'' . $this->PackagePath . '\' does not exist');
|
||||
}
|
||||
|
||||
if(is_file($this->PackagePath) == false)
|
||||
{
|
||||
throw new FileNotFoundException('The given package path \'' . $this->PackagePath . '\' is not a file');
|
||||
}
|
||||
|
||||
$file_handler = fopen($this->PackagePath, 'rb');
|
||||
$header = fread($file_handler, 14);
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Classes\PhpExtension;
|
||||
|
||||
use ArrayIterator;
|
||||
use ncc\Abstracts\ComponentFileExtensions;
|
||||
use ncc\Exceptions\AutoloadGeneratorException;
|
||||
use ncc\Exceptions\NoUnitsFoundException;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\ThirdParty\theseer\Autoload\CollectorException;
|
||||
use ncc\ThirdParty\theseer\Autoload\CollectorResult;
|
||||
use ncc\ThirdParty\theseer\Autoload\Config;
|
||||
use ncc\ThirdParty\theseer\Autoload\Factory;
|
||||
use ncc\ThirdParty\theseer\DirectoryScanner\Exception;
|
||||
use ncc\Utilities\Console;
|
||||
use SplFileInfo;
|
||||
|
||||
class AutoloaderGenerator
|
||||
{
|
||||
/**
|
||||
* @var ProjectConfiguration
|
||||
*/
|
||||
private ProjectConfiguration $project;
|
||||
|
||||
/**
|
||||
* @param ProjectConfiguration $project
|
||||
*/
|
||||
public function __construct(ProjectConfiguration $project)
|
||||
{
|
||||
$this->project = $project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the project and generates the autoloader source code.
|
||||
*
|
||||
* @param string $src
|
||||
* @param string $output
|
||||
* @param bool $static
|
||||
* @return string
|
||||
* @throws AutoloadGeneratorException
|
||||
* @throws CollectorException
|
||||
* @throws Exception
|
||||
* @throws NoUnitsFoundException
|
||||
*/
|
||||
public function generateAutoload(string $src, string $output, bool $static=false): string
|
||||
{
|
||||
// Construct configuration
|
||||
$configuration = new Config([$src]);
|
||||
$configuration->setFollowSymlinks(false); // Don't follow symlinks, it won't work on some systems.
|
||||
$configuration->setOutputFile($output);
|
||||
$configuration->setTrusting(false); // Paranoid
|
||||
// Official PHP file extensions that are missing from the default configuration (whatever)
|
||||
$configuration->setInclude(ComponentFileExtensions::Php);
|
||||
|
||||
// Construct factory
|
||||
$factory = new Factory();
|
||||
$factory->setConfig($configuration);
|
||||
|
||||
// Create Collector
|
||||
$result = self::runCollector($factory, $configuration);
|
||||
|
||||
// Exception raises when there are no files in the project that can be processed by the autoloader
|
||||
if(!$result->hasUnits())
|
||||
{
|
||||
throw new NoUnitsFoundException('No units were found in the project');
|
||||
}
|
||||
|
||||
if(!$result->hasDuplicates())
|
||||
{
|
||||
foreach($result->getDuplicates() as $unit => $files)
|
||||
{
|
||||
Console::outWarning((count($files) -1). ' duplicate unit(s) detected in the project: ' . $unit);
|
||||
}
|
||||
}
|
||||
|
||||
$template = @file_get_contents($configuration->getTemplate());
|
||||
if ($template === false)
|
||||
{
|
||||
throw new AutoloadGeneratorException("Failed to read the template file '" . $configuration->getTemplate() . "'");
|
||||
}
|
||||
|
||||
$builder = $factory->getRenderer($result);
|
||||
return $builder->render($template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the target directories through the collector and returns the collector results.
|
||||
*
|
||||
* @param Factory $factory
|
||||
* @param Config $config
|
||||
* @return CollectorResult
|
||||
* @throws CollectorException
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function runCollector(Factory $factory, Config $config): CollectorResult
|
||||
{
|
||||
$collector = $factory->getCollector();
|
||||
foreach($config->getDirectories() as $directory)
|
||||
{
|
||||
if(is_dir($directory))
|
||||
{
|
||||
$scanner = $factory->getScanner()->getIterator($directory);
|
||||
$collector->processDirectory($scanner);
|
||||
unset($scanner);
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = new SplFileInfo($directory);
|
||||
$filter = $factory->getFilter(new ArrayIterator(array($file)));
|
||||
foreach($filter as $file)
|
||||
{
|
||||
$collector->processFile($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $collector->getResult();
|
||||
}
|
||||
|
||||
}
|
|
@ -8,22 +8,26 @@
|
|||
use FilesystemIterator;
|
||||
use ncc\Abstracts\ComponentFileExtensions;
|
||||
use ncc\Abstracts\ComponentDataType;
|
||||
use ncc\Abstracts\ConstantReferences;
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Classes\NccExtension\PackageCompiler;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\BuildException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\PackagePreparationFailedException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Interfaces\CompilerInterface;
|
||||
use ncc\ncc;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\ThirdParty\nikic\PhpParser\Error;
|
||||
use ncc\ThirdParty\nikic\PhpParser\ParserFactory;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
|
||||
use ncc\Utilities\Base64;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\IO;
|
||||
use SplFileInfo;
|
||||
|
||||
class Compiler implements CompilerInterface
|
||||
|
@ -39,28 +43,30 @@
|
|||
private $package;
|
||||
|
||||
/**
|
||||
* @var ProjectConfiguration\BuildConfiguration|null
|
||||
* @var string
|
||||
*/
|
||||
private $selected_build_configuration;
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @param ProjectConfiguration $project
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct(ProjectConfiguration $project)
|
||||
public function __construct(ProjectConfiguration $project, string $path)
|
||||
{
|
||||
$this->project = $project;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the PHP package by generating the Autoloader and detecting all components & resources
|
||||
* This function must be called before calling the build function, otherwise the operation will fail
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $build_configuration
|
||||
* @return void
|
||||
* @throws PackagePreparationFailedException
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
*/
|
||||
public function prepare(string $path, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void
|
||||
public function prepare(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -72,40 +78,29 @@
|
|||
throw new PackagePreparationFailedException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
// Auto-select the default build configuration
|
||||
if($build_configuration == BuildConfigurationValues::DefaultConfiguration)
|
||||
{
|
||||
$build_configuration = $this->project->Build->DefaultConfiguration;
|
||||
}
|
||||
|
||||
// Select the build configuration
|
||||
try
|
||||
{
|
||||
$this->selected_build_configuration = $this->project->Build->getBuildConfiguration($build_configuration);
|
||||
}
|
||||
catch (BuildConfigurationNotFoundException $e)
|
||||
{
|
||||
throw new PackagePreparationFailedException($e->getMessage(), $e);
|
||||
}
|
||||
$selected_build_configuration = $this->project->Build->getBuildConfiguration($build_configuration);
|
||||
|
||||
// Create the package object
|
||||
$this->package = new Package();
|
||||
$this->package->Assembly = $this->project->Assembly;
|
||||
$this->package->Dependencies = $this->project->Build->Dependencies;
|
||||
$this->package->MainExecutionPolicy = $this->project->Build->Main;
|
||||
|
||||
// Add both the defined constants from the build configuration and the global constants.
|
||||
// Global constants are overridden
|
||||
$this->package->Header->RuntimeConstants = array_merge($this->selected_build_configuration->DefineConstants, $this->package->Header->RuntimeConstants);
|
||||
$this->package->Header->RuntimeConstants = array_merge($this->project->Build->DefineConstants, $this->package->Header->RuntimeConstants);
|
||||
$this->package->Header->RuntimeConstants = [];
|
||||
$this->package->Header->RuntimeConstants = array_merge(
|
||||
$selected_build_configuration->DefineConstants,
|
||||
$this->project->Build->DefineConstants,
|
||||
$this->package->Header->RuntimeConstants
|
||||
);
|
||||
|
||||
$this->package->Header->CompilerExtension = $this->project->Project->Compiler;
|
||||
$this->package->Header->CompilerVersion = NCC_VERSION_NUMBER;
|
||||
|
||||
if(ncc::cliMode())
|
||||
{
|
||||
Console::out('Scanning project files');
|
||||
Console::out('theseer\DirectoryScanner - Copyright (c) 2009-2014 Arne Blankerts <arne@blankerts.de> All rights reserved.');
|
||||
}
|
||||
Console::out('Scanning project files');
|
||||
Console::out('theseer\DirectoryScanner - Copyright (c) 2009-2014 Arne Blankerts <arne@blankerts.de> All rights reserved.');
|
||||
|
||||
// First scan the project files and create a file struct.
|
||||
$DirectoryScanner = new DirectoryScanner();
|
||||
|
@ -121,18 +116,12 @@
|
|||
|
||||
// Include file components that can be compiled
|
||||
$DirectoryScanner->setIncludes(ComponentFileExtensions::Php);
|
||||
$DirectoryScanner->setExcludes($this->selected_build_configuration->ExcludeFiles);
|
||||
|
||||
// Append trailing slash to the end of the path if it's not already there
|
||||
if(substr($path, -1) !== DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
$source_path = $path . $this->project->Build->SourcePath;
|
||||
$DirectoryScanner->setExcludes($selected_build_configuration->ExcludeFiles);
|
||||
$source_path = $this->path . $this->project->Build->SourcePath;
|
||||
|
||||
// TODO: Re-implement the scanning process outside the compiler, as this is will be redundant
|
||||
// Scan for components first.
|
||||
Console::out('Scanning for components... ', false);
|
||||
Console::out('Scanning for components... ');
|
||||
/** @var SplFileInfo $item */
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
foreach($DirectoryScanner($source_path, True) as $item)
|
||||
|
@ -142,22 +131,20 @@
|
|||
continue;
|
||||
|
||||
$Component = new Package\Component();
|
||||
$Component->Name = Functions::removeBasename($item->getPathname(), $path);
|
||||
$Component->Name = Functions::removeBasename($item->getPathname(), $this->path);
|
||||
$this->package->Components[] = $Component;
|
||||
|
||||
Console::outVerbose(sprintf('found component %s', $Component->Name));
|
||||
}
|
||||
|
||||
if(ncc::cliMode())
|
||||
if(count($this->package->Components) > 0)
|
||||
{
|
||||
if(count($this->package->Components) > 0)
|
||||
{
|
||||
Console::out(count($this->package->Components) . ' component(s) found');
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out('No components found');
|
||||
}
|
||||
Console::out(count($this->package->Components) . ' component(s) found');
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out('No components found');
|
||||
}
|
||||
|
||||
|
||||
// Clear previous excludes and includes
|
||||
$DirectoryScanner->setExcludes([]);
|
||||
|
@ -165,10 +152,10 @@
|
|||
|
||||
// Ignore component files
|
||||
$DirectoryScanner->setExcludes(array_merge(
|
||||
$this->selected_build_configuration->ExcludeFiles, ComponentFileExtensions::Php
|
||||
$selected_build_configuration->ExcludeFiles, ComponentFileExtensions::Php
|
||||
));
|
||||
|
||||
Console::out('Scanning for resources... ', false);
|
||||
Console::out('Scanning for resources... ');
|
||||
/** @var SplFileInfo $item */
|
||||
foreach($DirectoryScanner($source_path) as $item)
|
||||
{
|
||||
|
@ -177,174 +164,185 @@
|
|||
continue;
|
||||
|
||||
$Resource = new Package\Resource();
|
||||
$Resource->Name = Functions::removeBasename($item->getPathname(), $path);
|
||||
$Resource->Name = Functions::removeBasename($item->getPathname(), $this->path);
|
||||
$this->package->Resources[] = $Resource;
|
||||
|
||||
}
|
||||
|
||||
if(ncc::cliMode())
|
||||
{
|
||||
if(count($this->package->Resources) > 0)
|
||||
{
|
||||
Console::out(count($this->package->Resources) . ' resources(s) found');
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out('No resources found');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the package by parsing the AST contents of the components and resources
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
* @throws BuildException
|
||||
*/
|
||||
public function build(string $path): string
|
||||
{
|
||||
if($this->package == null)
|
||||
{
|
||||
throw new BuildException('The prepare() method must be called before building the package');
|
||||
}
|
||||
|
||||
// Append trailing slash to the end of the path if it's not already there
|
||||
if(substr($path, -1) !== DIRECTORY_SEPARATOR)
|
||||
{
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
// Runtime variables
|
||||
$components = [];
|
||||
$resources = [];
|
||||
$processed_items = 0;
|
||||
$total_items = 0;
|
||||
|
||||
if(count($this->package->Components) > 0)
|
||||
{
|
||||
if(ncc::cliMode())
|
||||
{
|
||||
Console::out('Compiling components');
|
||||
$total_items = count($this->package->Components);
|
||||
}
|
||||
|
||||
// Process the components and attempt to create an AST representation of the source
|
||||
foreach($this->package->Components as $component)
|
||||
{
|
||||
if(ncc::cliMode() && $total_items > 5)
|
||||
{
|
||||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
$content = file_get_contents(Functions::correctDirectorySeparator($path . $component->Name));
|
||||
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||
|
||||
try
|
||||
{
|
||||
$stmts = $parser->parse($content);
|
||||
$encoded = json_encode($stmts);
|
||||
|
||||
if($encoded === false)
|
||||
{
|
||||
$component->DataType = ComponentDataType::b64encoded;
|
||||
$component->Data = Base64::encode($content);
|
||||
$component->Checksum = hash('sha1', $component->Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$component->DataType = ComponentDataType::AST;
|
||||
$component->Data = json_decode($encoded, true);
|
||||
$component->Checksum = null;
|
||||
}
|
||||
}
|
||||
catch(Error $e)
|
||||
{
|
||||
$component->DataType = ComponentDataType::b64encoded;
|
||||
$component->Data = Base64::encode($content);
|
||||
$component->Checksum = hash('sha1', $component->Data);
|
||||
unset($e);
|
||||
}
|
||||
|
||||
$component->Name = str_replace($this->project->Build->SourcePath, (string)null, $component->Name);
|
||||
$components[] = $component;
|
||||
$processed_items += 1;
|
||||
}
|
||||
|
||||
if(ncc::cliMode() && $total_items > 5)
|
||||
{
|
||||
print(PHP_EOL);
|
||||
}
|
||||
|
||||
// Update the components
|
||||
$this->package->Components = $components;
|
||||
Console::outVerbose(sprintf('found resource %s', $Resource->Name));
|
||||
}
|
||||
|
||||
if(count($this->package->Resources) > 0)
|
||||
{
|
||||
// Process the resources
|
||||
if(ncc::cliMode())
|
||||
{
|
||||
Console::out('Processing resources');
|
||||
$processed_items = 0;
|
||||
$total_items = count($this->package->Resources);
|
||||
}
|
||||
|
||||
foreach($this->package->Resources as $resource)
|
||||
{
|
||||
if(ncc::cliMode() && $total_items > 5)
|
||||
{
|
||||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
// Get the data and
|
||||
$resource->Data = file_get_contents(Functions::correctDirectorySeparator($path . $resource->Name));
|
||||
$resource->Data = Base64::encode($resource->Data);
|
||||
$resource->Checksum = hash('sha1', $resource->Data);
|
||||
$resource->Name = str_replace($this->project->Build->SourcePath, (string)null, $resource->Name);
|
||||
$resources[] = $resource;
|
||||
}
|
||||
|
||||
// Update the resources
|
||||
$this->package->Resources = $resources;
|
||||
Console::out(count($this->package->Resources) . ' resources(s) found');
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::out('No resources found');
|
||||
}
|
||||
}
|
||||
|
||||
if(ncc::cliMode())
|
||||
/**
|
||||
* Executes the compile process in the correct order and returns the finalized Package object
|
||||
*
|
||||
* @return Package|null
|
||||
* @throws AccessDeniedException
|
||||
* @throws BuildException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function build(): ?Package
|
||||
{
|
||||
$this->compileExecutionPolicies();
|
||||
$this->compileComponents();
|
||||
$this->compileResources();
|
||||
|
||||
PackageCompiler::compilePackageConstants($this->package, [
|
||||
ConstantReferences::Assembly => $this->project->Assembly,
|
||||
ConstantReferences::Build => null,
|
||||
ConstantReferences::DateTime => time()
|
||||
]);
|
||||
|
||||
return $this->getPackage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the resources of the package
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws BuildException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function compileResources(): void
|
||||
{
|
||||
if($this->package == null)
|
||||
throw new BuildException('The prepare() method must be called before building the package');
|
||||
|
||||
if(count($this->package->Resources) == 0)
|
||||
return;
|
||||
|
||||
// Process the resources
|
||||
Console::out('Processing resources');
|
||||
$total_items = count($this->package->Resources);
|
||||
$processed_items = 0;
|
||||
$resources = [];
|
||||
|
||||
foreach($this->package->Resources as $resource)
|
||||
{
|
||||
if($total_items > 5)
|
||||
print(PHP_EOL);
|
||||
Console::out($this->package->Assembly->Package . ' compiled successfully');
|
||||
{
|
||||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
// Get the data and
|
||||
$resource->Data = IO::fread(Functions::correctDirectorySeparator($this->path . $resource->Name));
|
||||
$resource->Data = Base64::encode($resource->Data);
|
||||
$resource->Name = str_replace($this->project->Build->SourcePath, (string)null, $resource->Name);
|
||||
$resource->updateChecksum();
|
||||
$resources[] = $resource;
|
||||
|
||||
Console::outDebug(sprintf('processed resource %s', $resource->Name));
|
||||
}
|
||||
|
||||
// Write the package to disk
|
||||
$FileSystem = new Filesystem();
|
||||
// Update the resources
|
||||
$this->package->Resources = $resources;
|
||||
}
|
||||
|
||||
if($FileSystem->exists($path . $this->selected_build_configuration->OutputPath))
|
||||
/**
|
||||
* Compiles the components of the package
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws BuildException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function compileComponents(): void
|
||||
{
|
||||
if($this->package == null)
|
||||
throw new BuildException('The prepare() method must be called before building the package');
|
||||
|
||||
if(count($this->package->Components) == 0)
|
||||
return;
|
||||
|
||||
Console::out('Compiling components');
|
||||
$total_items = count($this->package->Components);
|
||||
$processed_items = 0;
|
||||
$components = [];
|
||||
|
||||
// Process the components and attempt to create an AST representation of the source
|
||||
foreach($this->package->Components as $component)
|
||||
{
|
||||
if($total_items > 5)
|
||||
{
|
||||
Console::inlineProgressBar($processed_items, $total_items);
|
||||
}
|
||||
|
||||
$content = IO::fread(Functions::correctDirectorySeparator($this->path . $component->Name));
|
||||
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
||||
|
||||
try
|
||||
{
|
||||
$FileSystem->remove($path . $this->selected_build_configuration->OutputPath);
|
||||
$stmts = $parser->parse($content);
|
||||
$encoded = json_encode($stmts);
|
||||
unset($stmts);
|
||||
|
||||
if($encoded === false)
|
||||
{
|
||||
$component->DataType = ComponentDataType::b64encoded;
|
||||
$component->Data = Base64::encode($content);
|
||||
}
|
||||
else
|
||||
{
|
||||
$component->DataType = ComponentDataType::AST;
|
||||
$component->Data = json_decode($encoded, true);
|
||||
}
|
||||
}
|
||||
catch(IOException $e)
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new BuildException('Cannot delete directory \'' . $path . $this->selected_build_configuration->OutputPath . '\', ' . $e->getMessage(), $e);
|
||||
$component->DataType = ComponentDataType::b64encoded;
|
||||
$component->Data = Base64::encode($content);
|
||||
unset($e);
|
||||
}
|
||||
|
||||
unset($parser);
|
||||
|
||||
$component->Name = str_replace($this->project->Build->SourcePath, (string)null, $component->Name);
|
||||
$component->updateChecksum();
|
||||
$components[] = $component;
|
||||
$processed_items += 1;
|
||||
|
||||
Console::outDebug(sprintf('processed component %s (%s)', $component->Name, $component->DataType));
|
||||
}
|
||||
|
||||
// Finally write the package to the disk
|
||||
$FileSystem->mkdir($path . $this->selected_build_configuration->OutputPath);
|
||||
$output_file = $path . $this->selected_build_configuration->OutputPath . DIRECTORY_SEPARATOR . $this->package->Assembly->Package . '.ncc';
|
||||
$FileSystem->touch($output_file);
|
||||
|
||||
try
|
||||
if(ncc::cliMode() && $total_items > 5)
|
||||
{
|
||||
$this->package->save($output_file);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new BuildException('Cannot write to output file', $e);
|
||||
print(PHP_EOL);
|
||||
}
|
||||
|
||||
return $output_file;
|
||||
// Update the components
|
||||
$this->package->Components = $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function compileExecutionPolicies(): void
|
||||
{
|
||||
PackageCompiler::compileExecutionPolicies($this->path, $this->project);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getPackage(): ?Package
|
||||
{
|
||||
return $this->package;
|
||||
}
|
||||
|
||||
}
|
342
src/ncc/Classes/PhpExtension/Installer.php
Normal file
342
src/ncc/Classes/PhpExtension/Installer.php
Normal file
|
@ -0,0 +1,342 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Classes\PhpExtension;
|
||||
|
||||
use ArrayIterator;
|
||||
use Exception;
|
||||
use ncc\Abstracts\ComponentDataType;
|
||||
use ncc\Abstracts\ComponentFileExtensions;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\ComponentChecksumException;
|
||||
use ncc\Exceptions\ComponentDecodeException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\NoUnitsFoundException;
|
||||
use ncc\Exceptions\ResourceChecksumException;
|
||||
use ncc\Exceptions\UnsupportedComponentTypeException;
|
||||
use ncc\Interfaces\InstallerInterface;
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\Package\Component;
|
||||
use ncc\ThirdParty\nikic\PhpParser\Comment;
|
||||
use ncc\ThirdParty\nikic\PhpParser\Node;
|
||||
use ncc\ThirdParty\nikic\PhpParser\PrettyPrinter\Standard;
|
||||
use ncc\ThirdParty\theseer\Autoload\CollectorException;
|
||||
use ncc\ThirdParty\theseer\Autoload\CollectorResult;
|
||||
use ncc\ThirdParty\theseer\Autoload\Config;
|
||||
use ncc\ThirdParty\theseer\Autoload\Factory;
|
||||
use ncc\Utilities\Base64;
|
||||
use ncc\Utilities\IO;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use RuntimeException;
|
||||
use SplFileInfo;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
|
||||
class Installer implements InstallerInterface
|
||||
{
|
||||
/**
|
||||
* @var ReflectionClass[] Node type to reflection class map
|
||||
*/
|
||||
private $reflectionClassCache;
|
||||
|
||||
/**
|
||||
* @var Package
|
||||
*/
|
||||
private $package;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(Package $package)
|
||||
{
|
||||
$this->package = $package;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the given component and returns the decoded component as a string representation
|
||||
* If the processed component does not result in a string representation, none will be returned.
|
||||
*
|
||||
* @param Component $component
|
||||
* @return string|null
|
||||
* @throws ComponentChecksumException
|
||||
* @throws ComponentDecodeException
|
||||
* @throws UnsupportedComponentTypeException
|
||||
*/
|
||||
public function processComponent(Package\Component $component): ?string
|
||||
{
|
||||
if($component->Data == null)
|
||||
return null;
|
||||
|
||||
if(!$component->validateChecksum())
|
||||
throw new ComponentChecksumException('Checksum validation failed for component ' . $component->Name . ', the package may be corrupted.');
|
||||
|
||||
switch($component->DataType)
|
||||
{
|
||||
case ComponentDataType::AST:
|
||||
try
|
||||
{
|
||||
$stmts = $this->decodeRecursive($component->Data);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new ComponentDecodeException('Cannot decode component: ' . $component->Name . ', ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$prettyPrinter = new Standard();
|
||||
return $prettyPrinter->prettyPrintFile($stmts);
|
||||
|
||||
case ComponentDataType::b64encoded:
|
||||
return Base64::decode($component->Data);
|
||||
|
||||
case ComponentDataType::Plain:
|
||||
return $component->Data;
|
||||
|
||||
default:
|
||||
throw new UnsupportedComponentTypeException('Unsupported component type \'' . $component->DataType . '\'');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function preInstall(InstallationPaths $installationPaths): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function postInstall(InstallationPaths $installationPaths): void
|
||||
{
|
||||
$autoload_path = $installationPaths->getBinPath() . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
$autoload_src = $this->generateAutoload($installationPaths->getSourcePath(), $autoload_path);
|
||||
IO::fwrite($autoload_path, $autoload_src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the given resource and returns the string representation of the resource
|
||||
*
|
||||
* @param Package\Resource $resource
|
||||
* @return string|null
|
||||
* @throws ResourceChecksumException
|
||||
*/
|
||||
public function processResource(Package\Resource $resource): ?string
|
||||
{
|
||||
if(!$resource->validateChecksum())
|
||||
throw new ResourceChecksumException('Checksum validation failed for resource ' . $resource->Name . ', the package may be corrupted.');
|
||||
return Base64::decode($resource->Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return array|Comment|Node
|
||||
* @throws ReflectionException
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
*/
|
||||
private function decodeRecursive($value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
if (isset($value['nodeType']))
|
||||
{
|
||||
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc')
|
||||
{
|
||||
return $this->decodeComment($value);
|
||||
}
|
||||
return $this->decodeNode($value);
|
||||
}
|
||||
return $this->decodeArray($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @return array
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function decodeArray(array $array) : array
|
||||
{
|
||||
$decodedArray = [];
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$decodedArray[$key] = $this->decodeRecursive($value);
|
||||
}
|
||||
return $decodedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return Node
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function decodeNode(array $value) : Node
|
||||
{
|
||||
$nodeType = $value['nodeType'];
|
||||
if (!is_string($nodeType))
|
||||
{
|
||||
throw new RuntimeException('Node type must be a string');
|
||||
}
|
||||
|
||||
$reflectionClass = $this->reflectionClassFromNodeType($nodeType);
|
||||
/** @var Node $node */
|
||||
$node = $reflectionClass->newInstanceWithoutConstructor();
|
||||
|
||||
if (isset($value['attributes'])) {
|
||||
if (!is_array($value['attributes']))
|
||||
{
|
||||
throw new RuntimeException('Attributes must be an array');
|
||||
}
|
||||
|
||||
$node->setAttributes($this->decodeArray($value['attributes']));
|
||||
}
|
||||
|
||||
foreach ($value as $name => $subNode) {
|
||||
if ($name === 'nodeType' || $name === 'attributes')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$node->$name = $this->decodeRecursive($subNode);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return Comment
|
||||
*/
|
||||
private function decodeComment(array $value) : Comment
|
||||
{
|
||||
$className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
|
||||
if (!isset($value['text']))
|
||||
{
|
||||
throw new RuntimeException('Comment must have text');
|
||||
}
|
||||
|
||||
return new $className(
|
||||
$value['text'],
|
||||
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
|
||||
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nodeType
|
||||
* @return ReflectionClass
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function reflectionClassFromNodeType(string $nodeType) : ReflectionClass
|
||||
{
|
||||
if (!isset($this->reflectionClassCache[$nodeType]))
|
||||
{
|
||||
$className = $this->classNameFromNodeType($nodeType);
|
||||
$this->reflectionClassCache[$nodeType] = new ReflectionClass($className);
|
||||
}
|
||||
return $this->reflectionClassCache[$nodeType];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nodeType
|
||||
* @return string
|
||||
*/
|
||||
private function classNameFromNodeType(string $nodeType) : string
|
||||
{
|
||||
$className = 'ncc\\ThirdParty\\nikic\\PhpParser\\Node\\' . strtr($nodeType, '_', '\\');
|
||||
if (class_exists($className))
|
||||
{
|
||||
return $className;
|
||||
}
|
||||
|
||||
$className .= '_';
|
||||
if (class_exists($className))
|
||||
{
|
||||
return $className;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unknown node type \"$nodeType\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the project and generates the autoloader source code.
|
||||
*
|
||||
* @param string $src
|
||||
* @param string $output
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws CollectorException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws NoUnitsFoundException
|
||||
*/
|
||||
private function generateAutoload(string $src, string $output): string
|
||||
{
|
||||
// Construct configuration
|
||||
$configuration = new Config([$src]);
|
||||
$configuration->setFollowSymlinks(false); // Don't follow symlinks, it won't work on some systems.
|
||||
$configuration->setTrusting(true); // Paranoid
|
||||
$configuration->setOutputFile($output);
|
||||
$configuration->setStaticMode(false);
|
||||
// Official PHP file extensions that are missing from the default configuration (whatever)
|
||||
$configuration->setInclude(ComponentFileExtensions::Php);
|
||||
$configuration->setQuietMode(true);
|
||||
|
||||
// Construct factory
|
||||
$factory = new Factory();
|
||||
$factory->setConfig($configuration);
|
||||
|
||||
// Create Collector
|
||||
$result = self::runCollector($factory, $configuration);
|
||||
|
||||
// Exception raises when there are no files in the project that can be processed by the autoloader
|
||||
if(!$result->hasUnits())
|
||||
{
|
||||
throw new NoUnitsFoundException('No units were found in the project');
|
||||
}
|
||||
|
||||
$template = IO::fread($configuration->getTemplate());
|
||||
|
||||
$builder = $factory->getRenderer($result);
|
||||
return $builder->render($template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the target directories through the collector and returns the collector results.
|
||||
*
|
||||
* @param Factory $factory
|
||||
* @param Config $config
|
||||
* @return CollectorResult
|
||||
* @throws CollectorException
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function runCollector(Factory $factory, Config $config): CollectorResult
|
||||
{
|
||||
$collector = $factory->getCollector();
|
||||
foreach($config->getDirectories() as $directory)
|
||||
{
|
||||
if(is_dir($directory))
|
||||
{
|
||||
$scanner = $factory->getScanner()->getIterator($directory);
|
||||
$collector->processDirectory($scanner);
|
||||
unset($scanner);
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = new SplFileInfo($directory);
|
||||
$filter = $factory->getFilter(new ArrayIterator(array($file)));
|
||||
foreach($filter as $file)
|
||||
{
|
||||
$collector->processFile($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $collector->getResult();
|
||||
}
|
||||
}
|
67
src/ncc/Classes/PhpExtension/Runner.php
Normal file
67
src/ncc/Classes/PhpExtension/Runner.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Classes\PhpExtension;
|
||||
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\RunnerExecutionException;
|
||||
use ncc\Interfaces\RunnerInterface;
|
||||
use ncc\Objects\ExecutionPointers\ExecutionPointer;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
|
||||
use ncc\ThirdParty\Symfony\Process\Process;
|
||||
use ncc\Utilities\Base64;
|
||||
use ncc\Utilities\IO;
|
||||
|
||||
class Runner implements RunnerInterface
|
||||
{
|
||||
/**
|
||||
* @param string $path
|
||||
* @param ExecutionPolicy $policy
|
||||
* @return ExecutionUnit
|
||||
* @throws FileNotFoundException
|
||||
* @throws AccessDeniedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit
|
||||
{
|
||||
$execution_unit = new ExecutionUnit();
|
||||
$target_file = $path;
|
||||
if(!file_exists($target_file) && !is_file($target_file))
|
||||
throw new FileNotFoundException($target_file);
|
||||
$policy->Execute->Target = null;
|
||||
$execution_unit->ExecutionPolicy = $policy;
|
||||
$execution_unit->Data = Base64::encode(IO::fread($target_file));
|
||||
|
||||
return $execution_unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file extension to use for the target file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getFileExtension(): string
|
||||
{
|
||||
return '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExecutionPointer $pointer
|
||||
* @return Process
|
||||
* @throws RunnerExecutionException
|
||||
*/
|
||||
public static function prepareProcess(ExecutionPointer $pointer): Process
|
||||
{
|
||||
$php_bin = new ExecutableFinder();
|
||||
$php_bin = $php_bin->find('php');
|
||||
if($php_bin == null)
|
||||
throw new RunnerExecutionException('Cannot locate PHP executable');
|
||||
|
||||
if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0)
|
||||
return new Process(array_merge([$php_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options));
|
||||
return new Process([$php_bin, $pointer->FilePointer]);
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/ComponentChecksumException.php
Normal file
28
src/ncc/Exceptions/ComponentChecksumException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class ComponentChecksumException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::ComponentChecksumException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/ComponentDecodeException.php
Normal file
28
src/ncc/Exceptions/ComponentDecodeException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class ComponentDecodeException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::ComponentDecodeException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
8
src/ncc/Exceptions/ExecutionUnitNotFoundException.php
Normal file
8
src/ncc/Exceptions/ExecutionUnitNotFoundException.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
class ExecutionUnitNotFoundException extends \Exception
|
||||
{
|
||||
|
||||
}
|
28
src/ncc/Exceptions/IOException.php
Normal file
28
src/ncc/Exceptions/IOException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class IOException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::IOException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/InstallationException.php
Normal file
28
src/ncc/Exceptions/InstallationException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class InstallationException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::InstallationException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
14
src/ncc/Exceptions/InvalidExecutionPolicyName.php
Normal file
14
src/ncc/Exceptions/InvalidExecutionPolicyName.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class InvalidExecutionPolicyName extends Exception
|
||||
{
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/NoAvailableUnitsException.php
Normal file
28
src/ncc/Exceptions/NoAvailableUnitsException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class NoAvailableUnitsException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::NoAvailableUnitsException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/PackageAlreadyInstalledException.php
Normal file
28
src/ncc/Exceptions/PackageAlreadyInstalledException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class PackageAlreadyInstalledException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::PackageAlreadyInstalledException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/PackageLockException.php
Normal file
28
src/ncc/Exceptions/PackageLockException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class PackageLockException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::PackageLockException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/PackageNotFoundException.php
Normal file
28
src/ncc/Exceptions/PackageNotFoundException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class PackageNotFoundException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::PackageNotFoundException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/PackageParsingException.php
Normal file
28
src/ncc/Exceptions/PackageParsingException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class PackageParsingException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::PackageParsingException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
13
src/ncc/Exceptions/ProjectConfigurationNotFoundException.php
Normal file
13
src/ncc/Exceptions/ProjectConfigurationNotFoundException.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ProjectConfigurationNotFoundException extends Exception
|
||||
{
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $previous);
|
||||
}
|
||||
}
|
29
src/ncc/Exceptions/ResourceChecksumException.php
Normal file
29
src/ncc/Exceptions/ResourceChecksumException.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class ResourceChecksumException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/RunnerExecutionException.php
Normal file
28
src/ncc/Exceptions/RunnerExecutionException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class RunnerExecutionException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::RunnerExecutionException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/UndefinedExecutionPolicyException.php
Normal file
28
src/ncc/Exceptions/UndefinedExecutionPolicyException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class UndefinedExecutionPolicyException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::UndefinedExecutionPolicyException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/UnsupportedComponentTypeException.php
Normal file
28
src/ncc/Exceptions/UnsupportedComponentTypeException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class UnsupportedComponentTypeException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::UnsupportedComponentTypeException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
11
src/ncc/Exceptions/UnsupportedRunnerException.php
Normal file
11
src/ncc/Exceptions/UnsupportedRunnerException.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
class UnsupportedRunnerException extends \Exception
|
||||
{
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
28
src/ncc/Exceptions/VersionNotFoundException.php
Normal file
28
src/ncc/Exceptions/VersionNotFoundException.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
|
||||
namespace ncc\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ExceptionCodes;
|
||||
use Throwable;
|
||||
|
||||
class VersionNotFoundException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var Throwable|null
|
||||
*/
|
||||
private ?Throwable $previous;
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, ExceptionCodes::VersionNotFoundException, $previous);
|
||||
$this->message = $message;
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
|
@ -3,23 +3,79 @@
|
|||
namespace ncc\Interfaces;
|
||||
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\BuildException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
|
||||
interface CompilerInterface
|
||||
{
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param ProjectConfiguration $project
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct(ProjectConfiguration $project, string $path);
|
||||
|
||||
/**
|
||||
* Prepares the package for the build process, this method is called before build()
|
||||
*
|
||||
* @param string $path The path that the project file is located in (project.json)
|
||||
* @param string $build_configuration The build configuration to use to build the project
|
||||
* @return void
|
||||
*/
|
||||
public function prepare(string $path, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void;
|
||||
public function prepare(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void;
|
||||
|
||||
/**
|
||||
* Builds the package, returns the output path of the build
|
||||
* Executes the compile process in the correct order and returns the finalized Package object
|
||||
*
|
||||
* @param string $path The path that the project file is located in (project.json)
|
||||
* @return string Returns the output path of the build
|
||||
* @return Package|null
|
||||
* @throws AccessDeniedException
|
||||
* @throws BuildException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function build(string $path): string;
|
||||
public function build(): ?Package;
|
||||
|
||||
/**
|
||||
* Compiles the components of the package
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function compileComponents(): void;
|
||||
|
||||
/**
|
||||
* Compiles the resources of the package
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function compileResources(): void;
|
||||
|
||||
/**
|
||||
* Compiles the execution policies of the package
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function compileExecutionPolicies(): void;
|
||||
|
||||
/**
|
||||
* Returns the current state of the package
|
||||
*
|
||||
* @return Package|null
|
||||
*/
|
||||
public function getPackage(): ?Package;
|
||||
}
|
59
src/ncc/Interfaces/InstallerInterface.php
Normal file
59
src/ncc/Interfaces/InstallerInterface.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Interfaces;
|
||||
|
||||
use Exception;
|
||||
use ncc\Exceptions\ComponentChecksumException;
|
||||
use ncc\Exceptions\ComponentDecodeException;
|
||||
use ncc\Exceptions\UnsupportedComponentTypeException;
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\Package\Component;
|
||||
|
||||
interface InstallerInterface
|
||||
{
|
||||
/**
|
||||
* Public Constructor
|
||||
*
|
||||
* @param Package $package
|
||||
*/
|
||||
public function __construct(Package $package);
|
||||
|
||||
/**
|
||||
* Processes the component and optionally returns a string of the final component
|
||||
*
|
||||
* @param Component $component
|
||||
* @return string|null
|
||||
* @throws ComponentChecksumException
|
||||
* @throws ComponentDecodeException
|
||||
* @throws UnsupportedComponentTypeException
|
||||
*/
|
||||
public function processComponent(Package\Component $component): ?string;
|
||||
|
||||
/**
|
||||
* Processes the resource and optionally returns a string of the final resource
|
||||
*
|
||||
* @param Package\Resource $resource
|
||||
* @return string|null
|
||||
* @throws
|
||||
*/
|
||||
public function processResource(Package\Resource $resource): ?string;
|
||||
|
||||
/**
|
||||
* Method called before the installation stage begins
|
||||
*
|
||||
* @param InstallationPaths $installationPaths
|
||||
* @throws Exception
|
||||
* @return void
|
||||
*/
|
||||
public function preInstall(InstallationPaths $installationPaths): void;
|
||||
|
||||
/**
|
||||
* Method called after the installation stage is completed and all the files have been installed
|
||||
*
|
||||
* @param InstallationPaths $installationPaths
|
||||
* @throws Exception
|
||||
* @return void
|
||||
*/
|
||||
public function postInstall(InstallationPaths $installationPaths): void;
|
||||
}
|
44
src/ncc/Interfaces/RunnerInterface.php
Normal file
44
src/ncc/Interfaces/RunnerInterface.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Interfaces;
|
||||
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\RunnerExecutionException;
|
||||
use ncc\Objects\ExecutionPointers\ExecutionPointer;
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\ThirdParty\Symfony\Process\Process;
|
||||
|
||||
interface RunnerInterface
|
||||
{
|
||||
/**
|
||||
* Processes the ExecutionPolicy
|
||||
*
|
||||
* @param string $path
|
||||
* @param ExecutionPolicy $policy
|
||||
* @return ExecutionUnit
|
||||
* @throws FileNotFoundException
|
||||
* @throws AccessDeniedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit;
|
||||
|
||||
/**
|
||||
* Returns the file extension to use for the target file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getFileExtension(): string;
|
||||
|
||||
/**
|
||||
* Prepares a process object for the execution pointer
|
||||
*
|
||||
* @param ExecutionPointer $pointer
|
||||
* @return Process
|
||||
* @throws RunnerExecutionException
|
||||
*/
|
||||
public static function prepareProcess(ExecutionPointer $pointer): Process;
|
||||
}
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
namespace ncc\Managers;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Abstracts\Versions;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\InvalidCredentialsEntryException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\RuntimeException;
|
||||
use ncc\Objects\Vault;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
@ -26,6 +29,7 @@
|
|||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$this->CredentialsPath = PathFinder::getDataPath(Scopes::System) . DIRECTORY_SEPARATOR . 'credentials.store';
|
||||
}
|
||||
|
||||
|
@ -51,7 +55,7 @@
|
|||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws RuntimeException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function constructStore(): void
|
||||
{
|
||||
|
@ -68,12 +72,7 @@
|
|||
$VaultObject = new Vault();
|
||||
$VaultObject->Version = Versions::CredentialsStoreVersion;
|
||||
|
||||
if(!@file_put_contents($this->CredentialsPath, ZiProto::encode($VaultObject->toArray())))
|
||||
{
|
||||
throw new RuntimeException('Cannot create file \'' . $this->CredentialsPath . '\'');
|
||||
}
|
||||
|
||||
chmod($this->CredentialsPath, 0600);
|
||||
IO::fwrite($this->CredentialsPath, ZiProto::encode($VaultObject->toArray()), 0600);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,6 +80,7 @@
|
|||
*
|
||||
* @return Vault
|
||||
* @throws AccessDeniedException
|
||||
* @throws IOException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getVault(): Vault
|
||||
|
@ -94,17 +94,15 @@
|
|||
|
||||
try
|
||||
{
|
||||
$Vault = ZiProto::decode(file_get_contents($this->CredentialsPath));
|
||||
$Vault = ZiProto::decode(IO::fread($this->CredentialsPath));
|
||||
}
|
||||
catch(\Exception $e)
|
||||
catch(Exception $e)
|
||||
{
|
||||
// TODO: Implement error-correction for corrupted credentials store.
|
||||
throw new RuntimeException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$Vault = Vault::fromArray($Vault);
|
||||
|
||||
return $Vault;
|
||||
return Vault::fromArray($Vault);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,15 +111,16 @@
|
|||
* @param Vault $vault
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function saveVault(Vault $vault)
|
||||
public function saveVault(Vault $vault): void
|
||||
{
|
||||
if(!$this->checkAccess())
|
||||
{
|
||||
throw new AccessDeniedException('Cannot write to credentials store without system permissions');
|
||||
}
|
||||
|
||||
file_put_contents($this->CredentialsPath, ZiProto::encode($vault->toArray()));
|
||||
IO::fwrite($this->CredentialsPath, ZiProto::encode($vault->toArray()), 0600);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,8 +131,9 @@
|
|||
* @throws AccessDeniedException
|
||||
* @throws InvalidCredentialsEntryException
|
||||
* @throws RuntimeException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function registerEntry(Vault\Entry $entry)
|
||||
public function registerEntry(Vault\Entry $entry): void
|
||||
{
|
||||
if(!preg_match('/^[\w-]+$/', $entry->Alias))
|
||||
{
|
||||
|
@ -152,7 +152,7 @@
|
|||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getCredentialsPath()
|
||||
public function getCredentialsPath(): ?string
|
||||
{
|
||||
return $this->CredentialsPath;
|
||||
}
|
||||
|
|
424
src/ncc/Managers/ExecutionPointerManager.php
Normal file
424
src/ncc/Managers/ExecutionPointerManager.php
Normal file
|
@ -0,0 +1,424 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Managers;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\Runners;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Classes\PhpExtension\Runner;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\ExecutionUnitNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\NoAvailableUnitsException;
|
||||
use ncc\Exceptions\RunnerExecutionException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Objects\ExecutionPointers;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\ExitHandle;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
use ncc\ThirdParty\Symfony\Process\Process;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
||||
class ExecutionPointerManager
|
||||
{
|
||||
/**
|
||||
* The path for where all the runners are located
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $RunnerPath;
|
||||
|
||||
/**
|
||||
* An array of temporary unit names to destroy once the object is destroyed
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $TemporaryUnits;
|
||||
|
||||
/**
|
||||
* Deletes all the temporary files on destruct
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->cleanTemporaryUnits();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->RunnerPath = PathFinder::getRunnerPath(Scopes::System);
|
||||
$this->TemporaryUnits = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all temporary files and directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cleanTemporaryUnits(): void
|
||||
{
|
||||
if(count($this->TemporaryUnits) == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
foreach($this->TemporaryUnits as $datum)
|
||||
{
|
||||
$this->removeUnit($datum['package'], $datum['version'], $datum['name']);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Package ID for the execution pointers
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @return string
|
||||
*/
|
||||
private function getPackageId(string $package, string $version): string
|
||||
{
|
||||
return hash('haval128,4', $package . $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Execution Unit to the
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @param ExecutionUnit $unit
|
||||
* @param bool $temporary
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws UnsupportedRunnerException
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function addUnit(string $package, string $version, ExecutionUnit $unit, bool $temporary=false): void
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Cannot add new ExecutionUnit \'' . $unit->ExecutionPolicy->Name .'\' for ' . $package . ', insufficient permissions');
|
||||
|
||||
$package_id = $this->getPackageId($package, $version);
|
||||
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
|
||||
$package_bin_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id;
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
// Either load or create the pointers file
|
||||
if(!$filesystem->exists($package_config_path))
|
||||
{
|
||||
$execution_pointers = new ExecutionPointers($package, $version);
|
||||
}
|
||||
else
|
||||
{
|
||||
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
|
||||
}
|
||||
|
||||
$bin_file = $package_bin_path . DIRECTORY_SEPARATOR . hash('haval128,4', $unit->ExecutionPolicy->Name);
|
||||
$bin_file .= match ($unit->ExecutionPolicy->Runner) {
|
||||
Runners::php => Runner::getFileExtension(),
|
||||
default => throw new UnsupportedRunnerException('The runner \'' . $unit->ExecutionPolicy->Runner . '\' is not supported'),
|
||||
};
|
||||
|
||||
if($filesystem->exists($bin_file) && $temporary)
|
||||
return;
|
||||
|
||||
if(!$filesystem->exists($package_bin_path))
|
||||
$filesystem->mkdir($package_bin_path);
|
||||
|
||||
if($filesystem->exists($bin_file))
|
||||
$filesystem->remove($bin_file);
|
||||
|
||||
IO::fwrite($bin_file, $unit->Data);
|
||||
$execution_pointers->addUnit($unit, $bin_file);
|
||||
IO::fwrite($package_config_path, ZiProto::encode($execution_pointers->toArray(true)));
|
||||
|
||||
if($temporary)
|
||||
{
|
||||
$this->TemporaryUnits[] = [
|
||||
'package' => $package,
|
||||
'version' => $version,
|
||||
'unit' => $unit->ExecutionPolicy->Name
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and removes the installed unit
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @param string $name
|
||||
* @return bool
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function removeUnit(string $package, string $version, string $name): bool
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Cannot remove ExecutionUnit \'' . $name .'\' for ' . $package . ', insufficient permissions');
|
||||
|
||||
$package_id = $this->getPackageId($package, $version);
|
||||
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
|
||||
$package_bin_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id;
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
if(!$filesystem->exists($package_config_path))
|
||||
return false;
|
||||
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
|
||||
$unit = $execution_pointers->getUnit($name);
|
||||
if($unit == null)
|
||||
return false;
|
||||
$results = $execution_pointers->deleteUnit($name);
|
||||
|
||||
// Delete everything if there are no execution pointers configured
|
||||
if(count($execution_pointers->getPointers()) == 0)
|
||||
{
|
||||
$filesystem->remove($package_config_path);
|
||||
$filesystem->remove($package_bin_path);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Delete the single execution pointer file
|
||||
if($filesystem->exists($unit->FilePointer))
|
||||
$filesystem->remove($unit->FilePointer);
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of configured units for a package version
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @return array
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getUnits(string $package, string $version): array
|
||||
{
|
||||
$package_id = $this->getPackageId($package, $version);
|
||||
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
|
||||
|
||||
if(!file_exists($package_config_path))
|
||||
return [];
|
||||
|
||||
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
|
||||
$results = [];
|
||||
foreach($execution_pointers->getPointers() as $pointer)
|
||||
{
|
||||
$results[] = $pointer->ExecutionPolicy->Name;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a unit
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @param string $name
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws ExecutionUnitNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws NoAvailableUnitsException
|
||||
* @throws UnsupportedRunnerException
|
||||
* @throws RunnerExecutionException
|
||||
*/
|
||||
public function executeUnit(string $package, string $version, string $name): void
|
||||
{
|
||||
$package_id = $this->getPackageId($package, $version);
|
||||
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
|
||||
|
||||
if(!file_exists($package_config_path))
|
||||
throw new NoAvailableUnitsException('There is no available units for \'' . $package . '=' .$version .'\'');
|
||||
|
||||
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
|
||||
$unit = $execution_pointers->getUnit($name);
|
||||
|
||||
if($unit == null)
|
||||
throw new ExecutionUnitNotFoundException('The execution unit \'' . $name . '\' was not found for \'' . $package . '=' .$version .'\'');
|
||||
|
||||
$process = match (strtolower($unit->ExecutionPolicy->Runner))
|
||||
{
|
||||
Runners::php => Runner::prepareProcess($unit),
|
||||
default => throw new UnsupportedRunnerException('The runner \'' . $unit->ExecutionPolicy->Runner . '\' is not supported'),
|
||||
};
|
||||
|
||||
if($unit->ExecutionPolicy->Execute->WorkingDirectory !== null)
|
||||
$process->setWorkingDirectory($unit->ExecutionPolicy->Execute->WorkingDirectory);
|
||||
if($unit->ExecutionPolicy->Execute->Timeout !== null)
|
||||
$process->setTimeout((float)$unit->ExecutionPolicy->Execute->Timeout);
|
||||
|
||||
if($unit->ExecutionPolicy->Execute->Silent)
|
||||
{
|
||||
$process->disableOutput();
|
||||
$process->setTty(false);
|
||||
}
|
||||
elseif($unit->ExecutionPolicy->Execute->Tty)
|
||||
{
|
||||
$process->enableOutput();
|
||||
$process->setTty(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$process->enableOutput();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if($unit->ExecutionPolicy->Message !== null)
|
||||
Console::out($unit->ExecutionPolicy->Message);
|
||||
|
||||
$process->run(function ($type, $buffer) {
|
||||
Console::out($buffer);
|
||||
});
|
||||
|
||||
$process->wait();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
unset($e);
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error);
|
||||
}
|
||||
|
||||
if($unit->ExecutionPolicy->ExitHandlers !== null)
|
||||
{
|
||||
if($process->isSuccessful() && $unit->ExecutionPolicy->ExitHandlers->Success !== null)
|
||||
{
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Success);
|
||||
}
|
||||
elseif($process->isSuccessful() && $unit->ExecutionPolicy->ExitHandlers->Error !== null)
|
||||
{
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Success, $process);
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Warning, $process);
|
||||
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error, $process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily executes a
|
||||
*
|
||||
* @param Package $package
|
||||
* @param string $unit_name
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws ExecutionUnitNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws NoAvailableUnitsException
|
||||
* @throws RunnerExecutionException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function temporaryExecute(Package $package, string $unit_name): void
|
||||
{
|
||||
// First get the execution unit from the package.
|
||||
$unit = $package->getExecutionUnit($unit_name);
|
||||
|
||||
// Get the required units
|
||||
$required_units = [];
|
||||
if($unit->ExecutionPolicy->ExitHandlers !== null)
|
||||
{
|
||||
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Success?->Run;
|
||||
if($required_unit !== null)
|
||||
$required_units[] = $required_unit;
|
||||
|
||||
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Warning?->Run;
|
||||
if($required_unit !== null)
|
||||
$required_units[] = $required_unit;
|
||||
|
||||
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Error?->Run;
|
||||
if($required_unit !== null)
|
||||
$required_units = $required_unit;
|
||||
}
|
||||
|
||||
// Install the units temporarily
|
||||
$this->addUnit($package->Assembly->Package, $package->Assembly->Version, $unit, true);
|
||||
foreach($required_units as $r_unit)
|
||||
{
|
||||
$this->addUnit($package->Assembly->Package, $package->Assembly->Version, $r_unit, true);
|
||||
}
|
||||
|
||||
$this->executeUnit($package->Assembly->Package, $package->Assembly->Version, $unit_name);
|
||||
$this->cleanTemporaryUnits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an exit handler object.
|
||||
*
|
||||
* If Process is Null and EndProcess is true, the method will end the process
|
||||
* if Process is not Null the exit handler will only execute if the process' exit code is the same
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @param ExitHandle $exitHandle
|
||||
* @param Process|null $process
|
||||
* @return bool
|
||||
* @throws AccessDeniedException
|
||||
* @throws ExecutionUnitNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws NoAvailableUnitsException
|
||||
* @throws RunnerExecutionException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function handleExit(string $package, string $version, ExitHandle $exitHandle, ?Process $process=null): bool
|
||||
{
|
||||
if($exitHandle->Message !== null)
|
||||
Console::out($exitHandle->Message);
|
||||
|
||||
if($process !== null && !$exitHandle->EndProcess)
|
||||
{
|
||||
if($exitHandle->ExitCode !== $process->getExitCode())
|
||||
return false;
|
||||
}
|
||||
elseif($exitHandle->EndProcess)
|
||||
{
|
||||
exit($exitHandle->ExitCode);
|
||||
}
|
||||
|
||||
if($exitHandle->Run !== null)
|
||||
{
|
||||
$this->executeUnit($package, $version, $exitHandle->Run);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
152
src/ncc/Managers/PackageLockManager.php
Normal file
152
src/ncc/Managers/PackageLockManager.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpPropertyOnlyWrittenInspection */
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Managers;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\PackageLockException;
|
||||
use ncc\Objects\PackageLock;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\Utilities\RuntimeCache;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
||||
class PackageLockManager
|
||||
{
|
||||
/**
|
||||
* @var PackageLock|null
|
||||
*/
|
||||
private $PackageLock;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $PackageLockPath;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$this->PackageLockPath = PathFinder::getPackageLock(Scopes::System);
|
||||
|
||||
try
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
catch (PackageLockException $e)
|
||||
{
|
||||
unset($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the PackageLock from the disk
|
||||
*
|
||||
* @return void
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function load(): void
|
||||
{
|
||||
if(RuntimeCache::get($this->PackageLockPath) !== null)
|
||||
{
|
||||
$this->PackageLock = RuntimeCache::get($this->PackageLockPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if(file_exists($this->PackageLockPath) && is_file($this->PackageLockPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Console::outDebug('reading package lock file');
|
||||
$data = IO::fread($this->PackageLockPath);
|
||||
if(strlen($data) > 0)
|
||||
{
|
||||
$this->PackageLock = PackageLock::fromArray(ZiProto::decode($data));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->PackageLock = new PackageLock();
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new PackageLockException('The PackageLock file cannot be parsed', $e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->PackageLock = new PackageLock();
|
||||
}
|
||||
|
||||
RuntimeCache::set($this->PackageLockPath, $this->PackageLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the PackageLock to disk
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
// Don't save something that isn't loaded lol
|
||||
if($this->PackageLock == null)
|
||||
return;
|
||||
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Cannot write to PackageLock, insufficient permissions');
|
||||
|
||||
try
|
||||
{
|
||||
IO::fwrite($this->PackageLockPath, ZiProto::encode($this->PackageLock->toArray(true)), 0755);
|
||||
RuntimeCache::set($this->PackageLockPath, $this->PackageLock);
|
||||
}
|
||||
catch(IOException $e)
|
||||
{
|
||||
throw new PackageLockException('Cannot save the package lock file to disk', $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the package lock file if it doesn't exist
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function constructLockFile(): void
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
catch (PackageLockException $e)
|
||||
{
|
||||
unset($e);
|
||||
$this->PackageLock = new PackageLock();
|
||||
}
|
||||
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PackageLock|null
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function getPackageLock(): ?PackageLock
|
||||
{
|
||||
if($this->PackageLock == null)
|
||||
$this->load();
|
||||
return $this->PackageLock;
|
||||
}
|
||||
}
|
490
src/ncc/Managers/PackageManager.php
Normal file
490
src/ncc/Managers/PackageManager.php
Normal file
|
@ -0,0 +1,490 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Managers;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\CompilerExtensions;
|
||||
use ncc\Abstracts\ConstantReferences;
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Classes\NccExtension\PackageCompiler;
|
||||
use ncc\Classes\PhpExtension\Installer;
|
||||
use ncc\CLI\Main;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InstallationException;
|
||||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\PackageAlreadyInstalledException;
|
||||
use ncc\Exceptions\PackageLockException;
|
||||
use ncc\Exceptions\PackageNotFoundException;
|
||||
use ncc\Exceptions\PackageParsingException;
|
||||
use ncc\Exceptions\UnsupportedCompilerExtensionException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Exceptions\VersionNotFoundException;
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\Objects\PackageLock\PackageEntry;
|
||||
use ncc\Objects\PackageLock\VersionEntry;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
|
||||
use ncc\Utilities\Console;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\Utilities\PathFinder;
|
||||
use ncc\Utilities\Resolver;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
use SplFileInfo;
|
||||
|
||||
class PackageManager
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $PackagesPath;
|
||||
|
||||
/**
|
||||
* @var PackageLockManager|null
|
||||
*/
|
||||
private $PackageLockManager;
|
||||
|
||||
/**
|
||||
* @throws InvalidScopeException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->PackagesPath = PathFinder::getPackagesPath(Scopes::System);
|
||||
$this->PackageLockManager = new PackageLockManager();
|
||||
$this->PackageLockManager->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a local package onto the system
|
||||
*
|
||||
* @param string $input
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws InstallationException
|
||||
* @throws PackageAlreadyInstalledException
|
||||
* @throws PackageLockException
|
||||
* @throws PackageParsingException
|
||||
* @throws UnsupportedCompilerExtensionException
|
||||
* @throws UnsupportedRunnerException
|
||||
* @throws VersionNotFoundException
|
||||
*/
|
||||
public function install(string $input): string
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Insufficient permission to install packages');
|
||||
|
||||
Console::outVerbose(sprintf('Installing %s', $input));
|
||||
if(!file_exists($input) || !is_file($input) || !is_readable($input))
|
||||
throw new FileNotFoundException('The specified file \'' . $input .' \' does not exist or is not readable.');
|
||||
|
||||
$package = Package::load($input);
|
||||
|
||||
if($this->getPackageVersion($package->Assembly->Package, $package->Assembly->Version) !== null)
|
||||
throw new PackageAlreadyInstalledException('The package ' . $package->Assembly->Package . '==' . $package->Assembly->Version . ' is already installed');
|
||||
|
||||
$extension = $package->Header->CompilerExtension->Extension;
|
||||
$installation_paths = new InstallationPaths($this->PackagesPath . DIRECTORY_SEPARATOR . $package->Assembly->Package . '==' . $package->Assembly->Version);
|
||||
$installer = match ($extension) {
|
||||
CompilerExtensions::PHP => new Installer($package),
|
||||
default => throw new UnsupportedCompilerExtensionException('The compiler extension \'' . $extension . '\' is not supported'),
|
||||
};
|
||||
$execution_pointer_manager = new ExecutionPointerManager();
|
||||
PackageCompiler::compilePackageConstants($package, [
|
||||
ConstantReferences::Install => $installation_paths
|
||||
]);
|
||||
|
||||
Console::outVerbose(sprintf('Successfully parsed %s', $package->Assembly->Package));
|
||||
|
||||
if(Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
|
||||
{
|
||||
Console::outDebug(sprintf('installer.install_path: %s', $installation_paths->getInstallationPath()));
|
||||
Console::outDebug(sprintf('installer.data_path: %s', $installation_paths->getDataPath()));
|
||||
Console::outDebug(sprintf('installer.bin_path: %s', $installation_paths->getBinPath()));
|
||||
Console::outDebug(sprintf('installer.src_path: %s', $installation_paths->getSourcePath()));
|
||||
|
||||
foreach($package->Assembly->toArray() as $prop => $value)
|
||||
Console::outDebug(sprintf('assembly.%s: %s', $prop, ($value ?? 'n/a')));
|
||||
foreach($package->Header->CompilerExtension->toArray() as $prop => $value)
|
||||
Console::outDebug(sprintf('header.compiler.%s: %s', $prop, ($value ?? 'n/a')));
|
||||
}
|
||||
|
||||
Console::out('Installing ' . $package->Assembly->Package);
|
||||
|
||||
// 4 For Directory Creation, preInstall, postInstall & initData methods
|
||||
$steps = (4 + count($package->Components) + count ($package->Resources) + count ($package->ExecutionUnits));
|
||||
|
||||
// Include the Execution units
|
||||
if($package->Installer?->PreInstall !== null)
|
||||
$steps += count($package->Installer->PreInstall);
|
||||
if($package->Installer?->PostInstall!== null)
|
||||
$steps += count($package->Installer->PostInstall);
|
||||
|
||||
$current_steps = 0;
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
try
|
||||
{
|
||||
$filesystem->mkdir($installation_paths->getInstallationPath(), 0755);
|
||||
$filesystem->mkdir($installation_paths->getBinPath(), 0755);
|
||||
$filesystem->mkdir($installation_paths->getDataPath(), 0755);
|
||||
$filesystem->mkdir($installation_paths->getSourcePath(), 0755);
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InstallationException('Error while creating directory, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
self::initData($package, $installation_paths);
|
||||
Console::outDebug(sprintf('saving shadow package to %s', $installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'pkg'));
|
||||
$package->save($installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'pkg');
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InstallationException('Cannot initialize package install, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
// Execute the pre-installation stage before the installation stage
|
||||
try
|
||||
{
|
||||
$installer->preInstall($installation_paths);
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new InstallationException('Pre installation stage failed, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
if($package->Installer?->PreInstall !== null && count($package->Installer->PreInstall) > 0)
|
||||
{
|
||||
foreach($package->Installer->PreInstall as $unit_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$execution_pointer_manager->temporaryExecute($package, $unit_name);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outWarning('Cannot execute unit ' . $unit_name . ', ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
}
|
||||
|
||||
// Process & Install the components
|
||||
foreach($package->Components as $component)
|
||||
{
|
||||
Console::outDebug(sprintf('processing component %s (%s)', $component->Name, $component->DataType));
|
||||
|
||||
try
|
||||
{
|
||||
$data = $installer->processComponent($component);
|
||||
if($data !== null)
|
||||
{
|
||||
$component_path = $installation_paths->getSourcePath() . DIRECTORY_SEPARATOR . $component->Name;
|
||||
$component_dir = dirname($component_path);
|
||||
if(!$filesystem->exists($component_dir))
|
||||
$filesystem->mkdir($component_dir);
|
||||
IO::fwrite($component_path, $data);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InstallationException('Cannot process one or more components, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
|
||||
// Process & Install the resources
|
||||
foreach($package->Resources as $resource)
|
||||
{
|
||||
Console::outDebug(sprintf('processing resource %s', $resource->Name));
|
||||
|
||||
try
|
||||
{
|
||||
$data = $installer->processResource($resource);
|
||||
if($data !== null)
|
||||
{
|
||||
$resource_path = $installation_paths->getSourcePath() . DIRECTORY_SEPARATOR . $resource->Name;
|
||||
$resource_dir = dirname($resource_path);
|
||||
if(!$filesystem->exists($resource_dir))
|
||||
$filesystem->mkdir($resource_dir);
|
||||
IO::fwrite($resource_path, $data);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InstallationException('Cannot process one or more resources, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
|
||||
// Install execution units
|
||||
// TODO: Implement symlink support
|
||||
if(count($package->ExecutionUnits) > 0)
|
||||
{
|
||||
$execution_pointer_manager = new ExecutionPointerManager();
|
||||
$unit_paths = [];
|
||||
|
||||
foreach($package->ExecutionUnits as $executionUnit)
|
||||
{
|
||||
$execution_pointer_manager->addUnit($package->Assembly->Package, $package->Assembly->Version, $executionUnit);
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
|
||||
IO::fwrite($installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'exec', ZiProto::encode($unit_paths));
|
||||
}
|
||||
|
||||
// Execute the post-installation stage after the installation is complete
|
||||
try
|
||||
{
|
||||
$installer->postInstall($installation_paths);
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new InstallationException('Post installation stage failed, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
if($package->Installer?->PostInstall !== null && count($package->Installer->PostInstall) > 0)
|
||||
{
|
||||
foreach($package->Installer->PostInstall as $unit_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$execution_pointer_manager->temporaryExecute($package, $unit_name);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outWarning('Cannot execute unit ' . $unit_name . ', ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$current_steps += 1;
|
||||
Console::inlineProgressBar($current_steps, $steps);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getPackageLockManager()->getPackageLock()->addPackage($package, $installation_paths->getInstallationPath());
|
||||
$this->getPackageLockManager()->save();
|
||||
|
||||
return $package->Assembly->Package;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing package entry, returns null if no such entry exists
|
||||
*
|
||||
* @param string $package
|
||||
* @return PackageEntry|null
|
||||
* @throws PackageLockException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function getPackage(string $package): ?PackageEntry
|
||||
{
|
||||
return $this->getPackageLockManager()->getPackageLock()->getPackage($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing version entry, returns null if no such entry exists
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @return VersionEntry|null
|
||||
* @throws VersionNotFoundException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function getPackageVersion(string $package, string $version): ?VersionEntry
|
||||
{
|
||||
return $this->getPackage($package)?->getVersion($version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest version of the package, or null if there is no entry
|
||||
*
|
||||
* @param string $package
|
||||
* @return VersionEntry|null
|
||||
* @throws VersionNotFoundException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function getLatestVersion(string $package): ?VersionEntry
|
||||
{
|
||||
return $this->getPackage($package)?->getVersion($this->getPackage($package)?->getLatestVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all packages and their installed versions
|
||||
*
|
||||
* @return array
|
||||
* @throws PackageLockException
|
||||
* @throws PackageLockException
|
||||
*/
|
||||
public function getInstalledPackages(): array
|
||||
{
|
||||
return $this->getPackageLockManager()->getPackageLock()->getPackages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a package version
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws PackageLockException
|
||||
* @throws PackageNotFoundException
|
||||
* @throws VersionNotFoundException
|
||||
*/
|
||||
public function uninstallPackageVersion(string $package, string $version): void
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Insufficient permission to uninstall packages');
|
||||
|
||||
$version_entry = $this->getPackageVersion($package, $version);
|
||||
if($version_entry == null)
|
||||
throw new PackageNotFoundException(sprintf('The package %s==%s was not found', $package, $version));
|
||||
|
||||
Console::out(sprintf('Uninstalling %s==%s', $package, $version));
|
||||
Console::outVerbose(sprintf('Removing package %s==%s from PackageLock', $package, $version));
|
||||
if(!$this->getPackageLockManager()->getPackageLock()->removePackageVersion($package, $version))
|
||||
Console::outDebug('warning: removing package from package lock failed');
|
||||
|
||||
$this->getPackageLockManager()->save();
|
||||
|
||||
Console::outVerbose('Removing package files');
|
||||
$scanner = new DirectoryScanner();
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
/** @var SplFileInfo $item */
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
foreach($scanner($version_entry->Location, true) as $item)
|
||||
{
|
||||
if(is_file($item->getPath()))
|
||||
{
|
||||
Console::outDebug(sprintf('deleting %s', $item->getPath()));
|
||||
$filesystem->remove($item->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
$filesystem->remove($version_entry->Location);
|
||||
|
||||
if($version_entry->ExecutionUnits !== null && count($version_entry->ExecutionUnits) > 0)
|
||||
{
|
||||
Console::outVerbose('Uninstalling execution units');
|
||||
|
||||
$execution_pointer_manager = new ExecutionPointerManager();
|
||||
foreach($version_entry->ExecutionUnits as $executionUnit)
|
||||
{
|
||||
if(!$execution_pointer_manager->removeUnit($package, $version, $executionUnit->ExecutionPolicy->Name))
|
||||
Console::outDebug(sprintf('warning: removing execution unit %s failed', $executionUnit->ExecutionPolicy->Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls all versions of a package
|
||||
*
|
||||
* @param string $package
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws PackageLockException
|
||||
* @throws PackageNotFoundException
|
||||
* @throws VersionNotFoundException
|
||||
*/
|
||||
public function uninstallPackage(string $package): void
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Insufficient permission to uninstall packages');
|
||||
|
||||
$package_entry = $this->getPackage($package);
|
||||
if($package_entry == null)
|
||||
throw new PackageNotFoundException(sprintf('The package %s was not found', $package));
|
||||
|
||||
foreach($package_entry->getVersions() as $version)
|
||||
{
|
||||
$version_entry = $package_entry->getVersion($version);
|
||||
try
|
||||
{
|
||||
$this->uninstallPackageVersion($package, $version_entry->Version);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Console::outDebug(sprintf('warning: unable to uninstall package %s==%s, %s (%s)', $package, $version_entry->Version, $e->getMessage(), $e->getCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Package $package
|
||||
* @param InstallationPaths $paths
|
||||
* @throws InstallationException
|
||||
*/
|
||||
private static function initData(Package $package, InstallationPaths $paths): void
|
||||
{
|
||||
// Create data files
|
||||
$dependencies = [];
|
||||
foreach($package->Dependencies as $dependency)
|
||||
{
|
||||
$dependencies[] = $dependency->toArray(true);
|
||||
}
|
||||
|
||||
$data_files = [
|
||||
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'assembly' =>
|
||||
ZiProto::encode($package->Assembly->toArray(true)),
|
||||
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'ext' =>
|
||||
ZiProto::encode($package->Header->CompilerExtension->toArray(true)),
|
||||
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'const' =>
|
||||
ZiProto::encode($package->Header->RuntimeConstants),
|
||||
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'dependencies' =>
|
||||
ZiProto::encode($dependencies),
|
||||
];
|
||||
|
||||
foreach($data_files as $file => $data)
|
||||
{
|
||||
try
|
||||
{
|
||||
IO::fwrite($file, $data);
|
||||
}
|
||||
catch (IOException $e)
|
||||
{
|
||||
throw new InstallationException('Cannot write to file \'' . $file . '\', ' . $e->getMessage(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PackageLockManager|null
|
||||
*/
|
||||
private function getPackageLockManager(): ?PackageLockManager
|
||||
{
|
||||
if($this->PackageLockManager == null)
|
||||
{
|
||||
$this->PackageLockManager = new PackageLockManager();
|
||||
}
|
||||
|
||||
return $this->PackageLockManager;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,26 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Managers;
|
||||
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Abstracts\Options\InitializeProjectOptions;
|
||||
use ncc\Classes\NccExtension\PackageCompiler;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\BuildException;
|
||||
use ncc\Exceptions\DirectoryNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidPackageNameException;
|
||||
use ncc\Exceptions\InvalidProjectNameException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Exceptions\PackagePreparationFailedException;
|
||||
use ncc\Exceptions\ProjectAlreadyExistsException;
|
||||
use ncc\Exceptions\ProjectConfigurationNotFoundException;
|
||||
use ncc\Exceptions\UnsupportedCompilerExtensionException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Objects\ProjectConfiguration;
|
||||
use ncc\Objects\ProjectConfiguration\Compiler;
|
||||
use ncc\ThirdParty\Symfony\Uid\Uuid;
|
||||
|
@ -14,84 +28,77 @@
|
|||
|
||||
class ProjectManager
|
||||
{
|
||||
/**
|
||||
* The selected directory for managing the project
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private ?string $SelectedDirectory;
|
||||
|
||||
/**
|
||||
* The path that points to the project's main project.json file
|
||||
*
|
||||
* @var string|null
|
||||
* @var string
|
||||
*/
|
||||
private ?string $ProjectFilePath;
|
||||
private $ProjectFilePath;
|
||||
|
||||
/**
|
||||
* The path that points the project's main directory
|
||||
*
|
||||
* @var string|null
|
||||
* @var string
|
||||
*/
|
||||
private ?string $ProjectPath;
|
||||
private $ProjectPath;
|
||||
|
||||
/**
|
||||
* The loaded project configuration, null if no project file is loaded
|
||||
*
|
||||
* @var ProjectConfiguration|null
|
||||
*/
|
||||
private $ProjectConfiguration;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*
|
||||
* @param string $selected_directory
|
||||
* @param string $path
|
||||
* @throws AccessDeniedException
|
||||
* @throws DirectoryNotFoundException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws MalformedJsonException
|
||||
* @throws ProjectConfigurationNotFoundException
|
||||
*/
|
||||
public function __construct(string $selected_directory)
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->SelectedDirectory = $selected_directory;
|
||||
$this->ProjectFilePath = null;
|
||||
$this->ProjectPath = null;
|
||||
|
||||
$this->detectProjectPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the project path from the selected directory
|
||||
* Returns false if the selected directory is not a proper project or an initialized project
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function detectProjectPath(): void
|
||||
{
|
||||
$selected_directory = $this->SelectedDirectory;
|
||||
|
||||
// Auto-resolve the trailing slash
|
||||
/** @noinspection PhpStrFunctionsInspection */
|
||||
if(substr($selected_directory, -1) !== '/')
|
||||
if(substr($path, -1) !== '/')
|
||||
{
|
||||
$selected_directory .= DIRECTORY_SEPARATOR;
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
// Detect if the folder exists or not
|
||||
if(!file_exists($selected_directory) || !is_dir($selected_directory))
|
||||
if(!file_exists($path) || !is_dir($path))
|
||||
{
|
||||
return;
|
||||
throw new DirectoryNotFoundException('The given directory \'' . $path .'\' does not exist');
|
||||
}
|
||||
|
||||
$this->ProjectPath = $selected_directory;
|
||||
$this->ProjectFilePath = $selected_directory . 'project.json';
|
||||
$this->ProjectPath = $path;
|
||||
$this->ProjectFilePath = $path . 'project.json';
|
||||
|
||||
if(file_exists($this->ProjectFilePath))
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the project structure
|
||||
*
|
||||
* // TODO: Correct the unexpected path behavior issue when initializing a project
|
||||
*
|
||||
* @param Compiler $compiler
|
||||
* @param string $name
|
||||
* @param string $package
|
||||
* @param string $src
|
||||
* @param string|null $src
|
||||
* @param array $options
|
||||
* @throws InvalidPackageNameException
|
||||
* @throws InvalidProjectNameException
|
||||
* @throws MalformedJsonException
|
||||
* @throws ProjectAlreadyExistsException
|
||||
*/
|
||||
public function initializeProject(Compiler $compiler, string $name, string $package, string $src, array $options=[]): void
|
||||
public function initializeProject(Compiler $compiler, string $name, string $package, ?string $src=null, array $options=[]): void
|
||||
{
|
||||
// Validate the project information first
|
||||
if(!Validate::packageName($package))
|
||||
|
@ -109,41 +116,43 @@
|
|||
throw new ProjectAlreadyExistsException('A project has already been initialized in \'' . $this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json' . '\'');
|
||||
}
|
||||
|
||||
$Project = new ProjectConfiguration();
|
||||
$this->ProjectConfiguration = new ProjectConfiguration();
|
||||
|
||||
// Set the compiler information
|
||||
$Project->Project->Compiler = $compiler;
|
||||
$this->ProjectConfiguration->Project->Compiler = $compiler;
|
||||
|
||||
// Set the assembly information
|
||||
$Project->Assembly->Name = $name;
|
||||
$Project->Assembly->Package = $package;
|
||||
$Project->Assembly->Version = '1.0.0';
|
||||
$Project->Assembly->UUID = Uuid::v1()->toRfc4122();
|
||||
$this->ProjectConfiguration->Assembly->Name = $name;
|
||||
$this->ProjectConfiguration->Assembly->Package = $package;
|
||||
$this->ProjectConfiguration->Assembly->Version = '1.0.0';
|
||||
$this->ProjectConfiguration->Assembly->UUID = Uuid::v1()->toRfc4122();
|
||||
|
||||
// Set the build information
|
||||
$Project->Build->SourcePath = $src;
|
||||
$Project->Build->DefaultConfiguration = 'debug';
|
||||
$this->ProjectConfiguration->Build->SourcePath = $src;
|
||||
if($this->ProjectConfiguration->Build->SourcePath == null)
|
||||
$this->ProjectConfiguration->Build->SourcePath = $this->ProjectPath;
|
||||
$this->ProjectConfiguration->Build->DefaultConfiguration = 'debug';
|
||||
|
||||
// Assembly constants if the program wishes to check for this
|
||||
$Project->Build->DefineConstants['ASSEMBLY_NAME'] = '%ASSEMBLY.NAME%';
|
||||
$Project->Build->DefineConstants['ASSEMBLY_PACKAGE'] = '%ASSEMBLY.PACKAGE%';
|
||||
$Project->Build->DefineConstants['ASSEMBLY_VERSION'] = '%ASSEMBLY.VERSION%';
|
||||
$Project->Build->DefineConstants['ASSEMBLY_UID'] = '%ASSEMBLY.UID%';
|
||||
$this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_NAME'] = '%ASSEMBLY.NAME%';
|
||||
$this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_PACKAGE'] = '%ASSEMBLY.PACKAGE%';
|
||||
$this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_VERSION'] = '%ASSEMBLY.VERSION%';
|
||||
$this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_UID'] = '%ASSEMBLY.UID%';
|
||||
|
||||
// Generate configurations
|
||||
$DebugConfiguration = new ProjectConfiguration\BuildConfiguration();
|
||||
$DebugConfiguration->Name = 'debug';
|
||||
$DebugConfiguration->OutputPath = 'build/debug';
|
||||
$DebugConfiguration->DefineConstants["DEBUG"] = '1'; // Debugging constant if the program wishes to check for this
|
||||
$Project->Build->Configurations[] = $DebugConfiguration;
|
||||
$this->ProjectConfiguration->Build->Configurations[] = $DebugConfiguration;
|
||||
$ReleaseConfiguration = new ProjectConfiguration\BuildConfiguration();
|
||||
$ReleaseConfiguration->Name = 'release';
|
||||
$ReleaseConfiguration->OutputPath = 'build/release';
|
||||
$ReleaseConfiguration->DefineConstants["DEBUG"] = '0'; // Debugging constant if the program wishes to check for this
|
||||
$Project->Build->Configurations[] = $ReleaseConfiguration;
|
||||
$this->ProjectConfiguration->Build->Configurations[] = $ReleaseConfiguration;
|
||||
|
||||
// Finally create project.json
|
||||
$Project->toFile($this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json');
|
||||
$this->ProjectConfiguration->toFile($this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json');
|
||||
|
||||
// And create the project directory for additional assets/resources
|
||||
$Folders = [
|
||||
|
@ -166,15 +175,59 @@
|
|||
switch($option)
|
||||
{
|
||||
case InitializeProjectOptions::CREATE_SOURCE_DIRECTORY:
|
||||
if(!file_exists($this->ProjectPath . DIRECTORY_SEPARATOR . 'src'))
|
||||
if(!file_exists($this->ProjectConfiguration->Build->SourcePath))
|
||||
{
|
||||
mkdir($this->ProjectPath . DIRECTORY_SEPARATOR . 'src');
|
||||
mkdir($this->ProjectConfiguration->Build->SourcePath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a project configuration is loaded or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function projectLoaded(): bool
|
||||
{
|
||||
if($this->ProjectConfiguration == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to load the project configuration
|
||||
*
|
||||
* @return void
|
||||
* @throws MalformedJsonException
|
||||
* @throws ProjectConfigurationNotFoundException
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
if(!file_exists($this->ProjectFilePath) && !is_file($this->ProjectFilePath))
|
||||
throw new ProjectConfigurationNotFoundException('The project configuration file \'' . $this->ProjectFilePath . '\' was not found');
|
||||
|
||||
$this->ProjectConfiguration = ProjectConfiguration::fromFile($this->ProjectFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the project configuration
|
||||
*
|
||||
* @return void
|
||||
* @throws MalformedJsonException
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if(!$this->projectLoaded())
|
||||
return;
|
||||
$this->ProjectConfiguration->toFile($this->ProjectFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
|
@ -182,4 +235,49 @@
|
|||
{
|
||||
return $this->ProjectFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProjectConfiguration|null
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws MalformedJsonException
|
||||
* @throws ProjectConfigurationNotFoundException
|
||||
*/
|
||||
public function getProjectConfiguration(): ?ProjectConfiguration
|
||||
{
|
||||
if($this->ProjectConfiguration == null)
|
||||
$this->load();
|
||||
return $this->ProjectConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getProjectPath(): ?string
|
||||
{
|
||||
return $this->ProjectPath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compiles the project into a package
|
||||
*
|
||||
* @param string $build_configuration
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws MalformedJsonException
|
||||
* @throws ProjectConfigurationNotFoundException
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
* @throws BuildException
|
||||
* @throws PackagePreparationFailedException
|
||||
* @throws UnsupportedCompilerExtensionException
|
||||
* @throws UnsupportedRunnerException
|
||||
*/
|
||||
public function build(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
|
||||
{
|
||||
return PackageCompiler::compile($this, $build_configuration);
|
||||
}
|
||||
}
|
171
src/ncc/Objects/ExecutionPointers.php
Normal file
171
src/ncc/Objects/ExecutionPointers.php
Normal file
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects;
|
||||
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Objects\ExecutionPointers\ExecutionPointer;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Utilities\Validate;
|
||||
|
||||
class ExecutionPointers
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $Package;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $Version;
|
||||
|
||||
/**
|
||||
* @var ExecutionPointer[]
|
||||
*/
|
||||
private $Pointers;
|
||||
|
||||
/**
|
||||
* @param string|null $package
|
||||
* @param string|null $version
|
||||
*/
|
||||
public function __construct(?string $package=null, ?string $version=null)
|
||||
{
|
||||
$this->Package = $package;
|
||||
$this->Version = $version;
|
||||
$this->Pointers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Execution Unit as a pointer
|
||||
*
|
||||
* @param ExecutionUnit $unit
|
||||
* @param bool $overwrite
|
||||
* @return bool
|
||||
*/
|
||||
public function addUnit(ExecutionUnit $unit, string $bin_file, bool $overwrite=true): bool
|
||||
{
|
||||
if(Validate::exceedsPathLength($bin_file))
|
||||
return false;
|
||||
|
||||
if(!file_exists($bin_file))
|
||||
throw new FileNotFoundException('The file ' . $unit->Data . ' does not exist, cannot add unit \'' . $unit->ExecutionPolicy->Name . '\'');
|
||||
|
||||
if($overwrite)
|
||||
{
|
||||
$this->deleteUnit($unit->ExecutionPolicy->Name);
|
||||
}
|
||||
elseif($this->getUnit($unit->ExecutionPolicy->Name) !== null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->Pointers[] = new ExecutionPointer($unit, $bin_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing unit from execution pointers
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteUnit(string $name): bool
|
||||
{
|
||||
$unit = $this->getUnit($name);
|
||||
if($unit == null)
|
||||
return false;
|
||||
|
||||
$new_pointers = [];
|
||||
foreach($this->Pointers as $pointer)
|
||||
{
|
||||
if($pointer->ExecutionPolicy->Name !== $name)
|
||||
$new_pointers[] = $pointer;
|
||||
}
|
||||
|
||||
$this->Pointers = $new_pointers;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing unit from the pointers
|
||||
*
|
||||
* @param string $name
|
||||
* @return ExecutionPointer|null
|
||||
*/
|
||||
public function getUnit(string $name): ?ExecutionPointer
|
||||
{
|
||||
foreach($this->Pointers as $pointer)
|
||||
{
|
||||
if($pointer->ExecutionPolicy->Name == $name)
|
||||
return $pointer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of execution pointers that are currently configured
|
||||
*
|
||||
* @return array|ExecutionPointer[]
|
||||
*/
|
||||
public function getPointers(): array
|
||||
{
|
||||
return $this->Pointers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the package that uses these execution policies.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->Version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the package that uses these execution policies
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPackage(): string
|
||||
{
|
||||
return $this->Package;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
$pointers = [];
|
||||
foreach($this->Pointers as $pointer)
|
||||
{
|
||||
$pointers[] = $pointer->toArray($bytecode);
|
||||
}
|
||||
return $pointers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return ExecutionPointers
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
foreach($data as $datum)
|
||||
{
|
||||
$object->Pointers[] = ExecutionPointer::fromArray($datum);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
78
src/ncc/Objects/ExecutionPointers/ExecutionPointer.php
Normal file
78
src/ncc/Objects/ExecutionPointers/ExecutionPointer.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ExecutionPointers;
|
||||
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class ExecutionPointer
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $ID;
|
||||
|
||||
/**
|
||||
* The execution policy for this execution unit
|
||||
*
|
||||
* @var ExecutionPolicy
|
||||
*/
|
||||
public $ExecutionPolicy;
|
||||
|
||||
/**
|
||||
* The file pointer for where the target script should be executed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $FilePointer;
|
||||
|
||||
/**
|
||||
* Public Constructor with optional ExecutionUnit parameter to construct object from
|
||||
*
|
||||
* @param ExecutionUnit|null $unit
|
||||
*/
|
||||
public function __construct(?ExecutionUnit $unit=null, ?string $bin_file=null)
|
||||
{
|
||||
if($unit == null)
|
||||
return;
|
||||
|
||||
$this->ID = $unit->getID();
|
||||
$this->ExecutionPolicy = $unit->ExecutionPolicy;
|
||||
$this->FilePointer = $bin_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('id') : 'id') => $this->ID,
|
||||
($bytecode ? Functions::cbc('execution_policy') : 'execution_policy') => $this->ExecutionPolicy->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('file_pointer') : 'file_pointer') => $this->FilePointer,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return ExecutionPointer
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->ID = Functions::array_bc($data, 'id');
|
||||
$object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy');
|
||||
$object->FilePointer = Functions::array_bc($data, 'file_pointer');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
61
src/ncc/Objects/InstallationPaths.php
Normal file
61
src/ncc/Objects/InstallationPaths.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects;
|
||||
|
||||
class InstallationPaths
|
||||
{
|
||||
/**
|
||||
* The path of where the package will be installed at
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $InstallationPath;
|
||||
|
||||
/**
|
||||
* @param string $installation_path
|
||||
*/
|
||||
public function __construct(string $installation_path)
|
||||
{
|
||||
$this->InstallationPath = $installation_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data path where NCC's metadata & runtime information is stored
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDataPath(): string
|
||||
{
|
||||
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'ncc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source path for where the package resides
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSourcePath(): string
|
||||
{
|
||||
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'src';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for where executables are located
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBinPath(): string
|
||||
{
|
||||
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'bin';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInstallationPath(): string
|
||||
{
|
||||
return $this->InstallationPath;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\NccVersionInformation;
|
||||
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\ComponentVersionNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Utilities\IO;
|
||||
|
||||
class Component
|
||||
{
|
||||
|
@ -25,18 +31,19 @@
|
|||
*
|
||||
* @return string
|
||||
* @throws ComponentVersionNotFoundException
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
$third_party_path = NCC_EXEC_LOCATION . DIRECTORY_SEPARATOR . 'ThirdParty' . DIRECTORY_SEPARATOR;
|
||||
$component_path = $third_party_path . $this->Vendor . DIRECTORY_SEPARATOR . $this->PackageName . DIRECTORY_SEPARATOR;
|
||||
|
||||
if(file_exists($component_path . 'VERSION') == false)
|
||||
{
|
||||
if(!file_exists($component_path . 'VERSION'))
|
||||
throw new ComponentVersionNotFoundException('The file \'' . $component_path . 'VERSION' . '\' does not exist');
|
||||
}
|
||||
|
||||
return file_get_contents($component_path . 'VERSION');
|
||||
return IO::fread($component_path . 'VERSION');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,17 +4,24 @@
|
|||
|
||||
namespace ncc\Objects;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\EncoderType;
|
||||
use ncc\Abstracts\PackageStructureVersions;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidPackageException;
|
||||
use ncc\Exceptions\InvalidProjectConfigurationException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\PackageParsingException;
|
||||
use ncc\Objects\Package\Component;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\Package\Header;
|
||||
use ncc\Objects\Package\Installer;
|
||||
use ncc\Objects\Package\MagicBytes;
|
||||
use ncc\Objects\Package\MainExecutionPolicy;
|
||||
use ncc\Objects\Package\Resource;
|
||||
use ncc\Objects\ProjectConfiguration\Assembly;
|
||||
use ncc\Objects\ProjectConfiguration\Dependency;
|
||||
use ncc\Utilities\Functions;
|
||||
use ncc\Utilities\IO;
|
||||
use ncc\ZiProto\ZiProto;
|
||||
|
||||
class Package
|
||||
|
@ -50,7 +57,7 @@
|
|||
/**
|
||||
* The Main Execution Policy object for the package if the package is an executable package.
|
||||
*
|
||||
* @var MainExecutionPolicy|null
|
||||
* @var string|null
|
||||
*/
|
||||
public $MainExecutionPolicy;
|
||||
|
||||
|
@ -61,6 +68,13 @@
|
|||
*/
|
||||
public $Installer;
|
||||
|
||||
/**
|
||||
* An array of execution units defined in the package
|
||||
*
|
||||
* @var ExecutionUnit[]
|
||||
*/
|
||||
public $ExecutionUnits;
|
||||
|
||||
/**
|
||||
* An array of resources that the package depends on
|
||||
*
|
||||
|
@ -83,6 +97,7 @@
|
|||
$this->MagicBytes = new MagicBytes();
|
||||
$this->Header = new Header();
|
||||
$this->Assembly = new Assembly();
|
||||
$this->ExecutionUnits = [];
|
||||
$this->Components = [];
|
||||
$this->Dependencies = [];
|
||||
$this->Resources = [];
|
||||
|
@ -126,16 +141,141 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the execution unit with the given name
|
||||
*
|
||||
* @param string $name
|
||||
* @return ExecutionUnit|null
|
||||
*/
|
||||
public function getExecutionUnit(string $name): ?ExecutionUnit
|
||||
{
|
||||
foreach($this->ExecutionUnits as $unit)
|
||||
{
|
||||
if($unit->ExecutionPolicy->Name == $name)
|
||||
return $unit;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the package contents to disk
|
||||
*
|
||||
* @param string $output_path
|
||||
* @return void
|
||||
* @throws IOException
|
||||
*/
|
||||
public function save(string $output_path): void
|
||||
{
|
||||
$package_contents = $this->MagicBytes->toString() . ZiProto::encode($this->toArray(true));
|
||||
file_put_contents($output_path, $package_contents);
|
||||
IO::fwrite($output_path, $package_contents, 0777);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to parse the specified package path and returns the object representation
|
||||
* of the package, including with the MagicBytes representation that is in the
|
||||
* file headers.
|
||||
*
|
||||
* @param string $path
|
||||
* @return Package
|
||||
* @throws FileNotFoundException
|
||||
* @throws PackageParsingException
|
||||
*/
|
||||
public static function load(string $path): Package
|
||||
{
|
||||
if(!file_exists($path) || !is_file($path) || !is_readable($path))
|
||||
{
|
||||
throw new FileNotFoundException('The file ' . $path . ' does not exist or is not readable');
|
||||
}
|
||||
|
||||
$handle = fopen($path, "rb");
|
||||
$header = fread($handle, 256); // Read the first 256 bytes of the file
|
||||
fclose($handle);
|
||||
|
||||
if(!strtoupper(substr($header, 0, 11)) == 'NCC_PACKAGE')
|
||||
throw new PackageParsingException('The package \'' . $path . '\' does not appear to be a valid NCC Package (Missing Header)');
|
||||
|
||||
// Extract the package structure version
|
||||
$package_structure_version = strtoupper(substr($header, 11, 3));
|
||||
|
||||
if(!in_array($package_structure_version, PackageStructureVersions::ALL))
|
||||
throw new PackageParsingException('The package \'' . $path . '\' has a package structure version of ' . $package_structure_version . ' which is not supported by this version NCC');
|
||||
|
||||
// Extract the package encoding type and package type
|
||||
$encoding_header = strtoupper(substr($header, 14, 5));
|
||||
$encoding_type = substr($encoding_header, 0, 3);
|
||||
$package_type = substr($encoding_header, 3, 2);
|
||||
|
||||
$magic_bytes = new MagicBytes();
|
||||
$magic_bytes->PackageStructureVersion = $package_structure_version;
|
||||
|
||||
// Determine the encoding type
|
||||
switch($encoding_type)
|
||||
{
|
||||
case '300':
|
||||
$magic_bytes->Encoder = EncoderType::ZiProto;
|
||||
$magic_bytes->IsCompressed = false;
|
||||
$magic_bytes->IsEncrypted = false;
|
||||
break;
|
||||
|
||||
case '301':
|
||||
$magic_bytes->Encoder = EncoderType::ZiProto;
|
||||
$magic_bytes->IsCompressed = true;
|
||||
$magic_bytes->IsEncrypted = false;
|
||||
break;
|
||||
|
||||
case '310':
|
||||
$magic_bytes->Encoder = EncoderType::ZiProto;
|
||||
$magic_bytes->IsCompressed = false;
|
||||
$magic_bytes->IsEncrypted = true;
|
||||
break;
|
||||
|
||||
case '311':
|
||||
$magic_bytes->Encoder = EncoderType::ZiProto;
|
||||
$magic_bytes->IsCompressed = true;
|
||||
$magic_bytes->IsEncrypted = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new PackageParsingException('Cannot determine the encoding type for the package \'' . $path . '\' (Got ' . $encoding_type . ')');
|
||||
}
|
||||
|
||||
// Determine the package type
|
||||
switch($package_type)
|
||||
{
|
||||
case '40':
|
||||
$magic_bytes->IsInstallable = true;
|
||||
$magic_bytes->IsExecutable = false;
|
||||
break;
|
||||
|
||||
case '41':
|
||||
$magic_bytes->IsInstallable = false;
|
||||
$magic_bytes->IsExecutable = true;
|
||||
break;
|
||||
|
||||
case '42':
|
||||
$magic_bytes->IsInstallable = true;
|
||||
$magic_bytes->IsExecutable = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new PackageParsingException('Cannot determine the package type for the package \'' . $path . '\' (Got ' . $package_type . ')');
|
||||
}
|
||||
|
||||
// TODO: Implement encryption and compression parsing
|
||||
|
||||
// Assuming all is good, load the entire fire into memory and parse its contents
|
||||
try
|
||||
{
|
||||
$package = Package::fromArray(ZiProto::decode(substr(IO::fread($path), strlen($magic_bytes->toString()))));
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new PackageParsingException('Cannot decode the contents of the package \'' . $path . '\', invalid encoding or the package is corrupted, ' . $e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$package->MagicBytes = $magic_bytes;
|
||||
return $package;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,13 +301,17 @@
|
|||
foreach($this->Resources as $resource)
|
||||
$_resources[] = $resource->toArray($bytecode);
|
||||
|
||||
$_execution_units = [];
|
||||
foreach($this->ExecutionUnits as $unit)
|
||||
$_execution_units[] = $unit->toArray($bytecode);
|
||||
|
||||
return [
|
||||
($bytecode ? Functions::cbc('header') : 'header') => $this->Header?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('assembly') : 'assembly') => $this->Assembly?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('header') : 'header') => $this?->Header?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('assembly') : 'assembly') => $this?->Assembly?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $_dependencies,
|
||||
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->MainExecutionPolicy?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('installer') : 'installer') => $this->Installer?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this?->MainExecutionPolicy,
|
||||
($bytecode ? Functions::cbc('installer') : 'installer') => $this?->Installer?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('execution_units') : 'execution_units') => $_execution_units,
|
||||
($bytecode ? Functions::cbc('resources') : 'resources') => $_resources,
|
||||
($bytecode ? Functions::cbc('components') : 'components') => $_components
|
||||
];
|
||||
|
@ -190,8 +334,6 @@
|
|||
$object->Assembly = Assembly::fromArray($object->Assembly);
|
||||
|
||||
$object->MainExecutionPolicy = Functions::array_bc($data, 'main_execution_policy');
|
||||
if($object->MainExecutionPolicy !== null)
|
||||
$object->MainExecutionPolicy = MainExecutionPolicy::fromArray($object->MainExecutionPolicy);
|
||||
|
||||
$object->Installer = Functions::array_bc($data, 'installer');
|
||||
if($object->Installer !== null)
|
||||
|
@ -224,6 +366,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
$_execution_units = Functions::array_bc($data, 'execution_units');
|
||||
if($_execution_units !== null)
|
||||
{
|
||||
foreach($_execution_units as $unit)
|
||||
{
|
||||
$object->ExecutionUnits[] = ExecutionUnit::fromArray($unit);
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\Package;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
@ -33,12 +35,12 @@
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Checksum;
|
||||
private $Checksum;
|
||||
|
||||
/**
|
||||
* The raw data of the component, this is to be processed by the compiler extension
|
||||
*
|
||||
* @var string
|
||||
* @var mixed
|
||||
*/
|
||||
public $Data;
|
||||
|
||||
|
@ -51,17 +53,32 @@
|
|||
public function validateChecksum(): bool
|
||||
{
|
||||
if($this->Checksum === null)
|
||||
return false;
|
||||
return true; // Return true if the checksum is empty
|
||||
|
||||
if($this->Data === null)
|
||||
return false;
|
||||
return true; // Return true if the data is null
|
||||
|
||||
if(hash('sha1', $this->Data) !== $this->Checksum)
|
||||
return false;
|
||||
if(hash('sha1', $this->Data, true) !== $this->Checksum)
|
||||
return false; // Return false if the checksum failed
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum of the resource
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateChecksum(): void
|
||||
{
|
||||
$this->Checksum = null;
|
||||
|
||||
if(gettype($this->Data) == 'string')
|
||||
{
|
||||
$this->Checksum = hash('sha1', $this->Data, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the component.
|
||||
*
|
||||
|
|
71
src/ncc/Objects/Package/ExecutionUnit.php
Normal file
71
src/ncc/Objects/Package/ExecutionUnit.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\Package;
|
||||
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class ExecutionUnit
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $ID;
|
||||
|
||||
/**
|
||||
* The execution policy for this execution unit
|
||||
*
|
||||
* @var ExecutionPolicy
|
||||
*/
|
||||
public $ExecutionPolicy;
|
||||
|
||||
/**
|
||||
* The data of the unit to execute
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Data;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('execution_policy') : 'execution_policy') => $this->ExecutionPolicy->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('data') : 'data') => $this->Data,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return static
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy');
|
||||
$object->Data = Functions::array_bc($data, 'data');
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getID(): string
|
||||
{
|
||||
if($this->ID == null)
|
||||
$this->ID = hash('sha1', $this->ExecutionPolicy->Name);
|
||||
return $this->ID;
|
||||
}
|
||||
|
||||
}
|
|
@ -68,6 +68,9 @@
|
|||
$object->RuntimeConstants = Functions::array_bc($data, 'runtime_constants');
|
||||
$object->CompilerVersion = Functions::array_bc($data, 'compiler_version');
|
||||
|
||||
if($object->CompilerExtension !== null)
|
||||
$object->CompilerExtension = Compiler::fromArray($object->CompilerExtension);
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,81 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\Package;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class Installer
|
||||
{
|
||||
/**
|
||||
* An array of execution policies to execute pre install
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreInstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post install
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostInstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute pre uninstall
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreUninstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post uninstall
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostUninstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute pre update
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreUpdate;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post update
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostUpdate;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
* Returns null if all properties are not set
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
public function toArray(bool $bytecode=false): ?array
|
||||
{
|
||||
return [];
|
||||
if(
|
||||
$this->PreInstall == null && $this->PostInstall == null &&
|
||||
$this->PreUninstall == null && $this->PostUninstall == null &&
|
||||
$this->PreUpdate == null && $this->PostUpdate == null
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
($bytecode ? Functions::cbc('pre_install') : 'pre_install') => ($this->PreInstall == null ? null : $this->PreInstall),
|
||||
($bytecode ? Functions::cbc('post_install') : 'post_install') => ($this->PostInstall == null ? null : $this->PostInstall),
|
||||
($bytecode ? Functions::cbc('pre_uninstall') : 'pre_uninstall') => ($this->PreUninstall == null ? null : $this->PreUninstall),
|
||||
($bytecode? Functions::cbc('post_uninstall') : 'post_uninstall') => ($this->PostUninstall == null ? null : $this->PostUninstall),
|
||||
($bytecode? Functions::cbc('pre_update') : 'pre_update') => ($this->PreUpdate == null ? null : $this->PreUpdate),
|
||||
($bytecode? Functions::cbc('post_update') : 'post_update') => ($this->PostUpdate == null ? null : $this->PostUpdate)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,11 +83,19 @@
|
|||
*
|
||||
* @param array $data
|
||||
* @return Installer
|
||||
* @noinspection DuplicatedCode
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->PreInstall = Functions::array_bc($data, 'pre_install');
|
||||
$object->PostInstall = Functions::array_bc($data, 'post_install');
|
||||
$object->PreUninstall = Functions::array_bc($data, 'pre_uninstall');
|
||||
$object->PostUninstall = Functions::array_bc($data, 'post_uninstall');
|
||||
$object->PreUpdate = Functions::array_bc($data, 'pre_update');
|
||||
$object->PostUpdate = Functions::array_bc($data, 'post_update');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -147,6 +147,12 @@
|
|||
// NCC_PACKAGE1.030140
|
||||
$magic_bytes .= '40';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no type is specified, default to installable only
|
||||
// NCC_PACKAGE1.030140
|
||||
$magic_bytes .= '40';
|
||||
}
|
||||
|
||||
return $magic_bytes;
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Objects\Package;
|
||||
|
||||
class MainExecutionPolicy
|
||||
{
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return MainExecutionPolicy
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Checksum;
|
||||
private $Checksum;
|
||||
|
||||
/**
|
||||
* The raw data of the resource
|
||||
|
@ -44,12 +44,27 @@
|
|||
if($this->Data === null)
|
||||
return false;
|
||||
|
||||
if(hash('sha1', $this->Data) !== $this->Checksum)
|
||||
if(hash('sha1', $this->Data, true) !== $this->Checksum)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum of the resource
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateChecksum(): void
|
||||
{
|
||||
$this->Checksum = null;
|
||||
|
||||
if(gettype($this->Data) == 'string')
|
||||
{
|
||||
$this->Checksum = hash('sha1', $this->Data, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the resource.
|
||||
*
|
||||
|
|
194
src/ncc/Objects/PackageLock.php
Normal file
194
src/ncc/Objects/PackageLock.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects;
|
||||
|
||||
use ncc\Abstracts\Versions;
|
||||
use ncc\Objects\PackageLock\PackageEntry;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class PackageLock
|
||||
{
|
||||
/**
|
||||
* The version of package lock file structure
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $PackageLockVersion;
|
||||
|
||||
/**
|
||||
* The Unix Timestamp for when this package lock file was last updated
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $LastUpdatedTimestamp;
|
||||
|
||||
/**
|
||||
* An array of installed packages in the PackageLock file
|
||||
*
|
||||
* @var PackageEntry[]
|
||||
*/
|
||||
public $Packages;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->PackageLockVersion = Versions::PackageLockVersion;
|
||||
$this->Packages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the version and timestamp
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function update(): void
|
||||
{
|
||||
$this->PackageLockVersion = Versions::PackageLockVersion;
|
||||
$this->LastUpdatedTimestamp = time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Package $package
|
||||
* @param string $install_path
|
||||
* @return void
|
||||
*/
|
||||
public function addPackage(Package $package, string $install_path): void
|
||||
{
|
||||
if(!isset($this->Packages[$package->Assembly->Package]))
|
||||
{
|
||||
$package_entry = new PackageEntry();
|
||||
$package_entry->addVersion($package, $install_path, true);
|
||||
$package_entry->Name = $package->Assembly->Package;
|
||||
$this->Packages[$package->Assembly->Package] = $package_entry;
|
||||
$this->update();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->Packages[$package->Assembly->Package]->addVersion($package, true);
|
||||
$this->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a package version entry, removes the entire entry if there are no installed versions
|
||||
*
|
||||
* @param string $package
|
||||
* @param string $version
|
||||
* @return bool
|
||||
*/
|
||||
public function removePackageVersion(string $package, string $version): bool
|
||||
{
|
||||
if(isset($this->Packages[$package]))
|
||||
{
|
||||
$r = $this->Packages[$package]->removeVersion($version);
|
||||
|
||||
// Remove the entire package entry if there's no installed versions
|
||||
if($this->Packages[$package]->getLatestVersion() == null && $r)
|
||||
{
|
||||
unset($this->Packages[$package]);
|
||||
}
|
||||
|
||||
$this->update();
|
||||
return $r;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an entire package entry
|
||||
*
|
||||
* @param string $package
|
||||
* @return bool
|
||||
*/
|
||||
public function removePackage(string $package): bool
|
||||
{
|
||||
if(isset($this->Packages[$package]))
|
||||
{
|
||||
unset($this->Packages[$package]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an existing package entry, returns null if no such entry exists
|
||||
*
|
||||
* @param string $package
|
||||
* @return PackageEntry|null
|
||||
*/
|
||||
public function getPackage(string $package): ?PackageEntry
|
||||
{
|
||||
if(isset($this->Packages[$package]))
|
||||
{
|
||||
return $this->Packages[$package];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all packages and their installed versions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPackages(): array
|
||||
{
|
||||
$results = [];
|
||||
foreach($this->Packages as $package => $entry)
|
||||
$results[$package] = $entry->getVersions();
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
$package_entries = [];
|
||||
foreach($this->Packages as $entry)
|
||||
{
|
||||
$package_entries[] = $entry->toArray($bytecode);
|
||||
}
|
||||
|
||||
return [
|
||||
($bytecode ? Functions::cbc('package_lock_version') : 'package_lock_version') => $this->PackageLockVersion,
|
||||
($bytecode ? Functions::cbc('last_updated_timestamp') : 'last_updated_timestamp') => $this->LastUpdatedTimestamp,
|
||||
($bytecode ? Functions::cbc('packages') : 'packages') => $package_entries
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return static
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$packages = Functions::array_bc($data, 'packages');
|
||||
if($packages !== null)
|
||||
{
|
||||
foreach($packages as $_datum)
|
||||
{
|
||||
$entry = PackageEntry::fromArray($_datum);
|
||||
$object->Packages[$entry->Name] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
$object->PackageLockVersion = Functions::array_bc($data, 'package_lock_version');
|
||||
$object->LastUpdatedTimestamp = Functions::array_bc($data, 'last_updated_timestamp');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
64
src/ncc/Objects/PackageLock/DependencyEntry.php
Normal file
64
src/ncc/Objects/PackageLock/DependencyEntry.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\PackageLock;
|
||||
|
||||
use ncc\Objects\ProjectConfiguration\Dependency;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class DependencyEntry
|
||||
{
|
||||
/**
|
||||
* The name of the package dependency
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $PackageName;
|
||||
|
||||
/**
|
||||
* The version of the package dependency
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Version;
|
||||
|
||||
public function __construct(?Dependency $dependency=null)
|
||||
{
|
||||
if($dependency !== null)
|
||||
{
|
||||
$this->PackageName = $dependency->Name;
|
||||
$this->Version = $dependency->Version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('package_name') : 'package_name') => $this->PackageName,
|
||||
($bytecode ? Functions::cbc('version') : 'version') => $this->Version,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return DependencyEntry
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->PackageName = Functions::array_bc($data, 'package_name');
|
||||
$object->Version = Functions::array_bc($data, 'version');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
235
src/ncc/Objects/PackageLock/PackageEntry.php
Normal file
235
src/ncc/Objects/PackageLock/PackageEntry.php
Normal file
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\PackageLock;
|
||||
|
||||
use ncc\Exceptions\VersionNotFoundException;
|
||||
use ncc\Objects\Package;
|
||||
use ncc\ThirdParty\jelix\Version\VersionComparator;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class PackageEntry
|
||||
{
|
||||
/**
|
||||
* The name of the package that's installed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Name;
|
||||
|
||||
/**
|
||||
* The latest version of the package entry, this is updated automatically
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $LatestVersion;
|
||||
|
||||
/**
|
||||
* An array of installed versions for this package
|
||||
*
|
||||
* @var VersionEntry[]
|
||||
*/
|
||||
public $Versions;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Versions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and returns a version of the package
|
||||
*
|
||||
* @param string $version
|
||||
* @param bool $throw_exception
|
||||
* @return VersionEntry|null
|
||||
* @throws VersionNotFoundException
|
||||
*/
|
||||
public function getVersion(string $version, bool $throw_exception=false): ?VersionEntry
|
||||
{
|
||||
foreach($this->Versions as $versionEntry)
|
||||
{
|
||||
if($versionEntry->Version == $version)
|
||||
{
|
||||
return $versionEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if($throw_exception)
|
||||
throw new VersionNotFoundException('The version entry is not found');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes version entry from the package
|
||||
*
|
||||
* @param string $version
|
||||
* @return bool
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function removeVersion(string $version): bool
|
||||
{
|
||||
$count = 0;
|
||||
$found_node = false;
|
||||
foreach($this->Versions as $versionEntry)
|
||||
{
|
||||
if($versionEntry->Version == $version)
|
||||
{
|
||||
$found_node = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$count += 1;
|
||||
}
|
||||
|
||||
if($found_node)
|
||||
{
|
||||
unset($this->Versions[$count]);
|
||||
$this->updateLatestVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new version entry to the package, if overwrite is true then
|
||||
* the entry will be overwritten if it exists, otherwise it will return
|
||||
* false.
|
||||
*
|
||||
* @param Package $package
|
||||
* @param string $install_path
|
||||
* @param bool $overwrite
|
||||
* @return bool
|
||||
*/
|
||||
public function addVersion(Package $package, string $install_path, bool $overwrite=false): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($this->getVersion($package->Assembly->Version) !== null)
|
||||
{
|
||||
if (!$overwrite) return false;
|
||||
$this->removeVersion($package->Assembly->Version);
|
||||
}
|
||||
}
|
||||
catch (VersionNotFoundException $e)
|
||||
{
|
||||
unset($e);
|
||||
}
|
||||
|
||||
$version = new VersionEntry();
|
||||
$version->Version = $package->Assembly->Version;
|
||||
$version->Compiler = $package->Header->CompilerExtension;
|
||||
$version->ExecutionUnits = $package->ExecutionUnits;
|
||||
$version->MainExecutionPolicy = $package->MainExecutionPolicy;
|
||||
$version->Location = $install_path;
|
||||
|
||||
foreach($package->Dependencies as $dependency)
|
||||
{
|
||||
$version->Dependencies[] = new DependencyEntry($dependency);
|
||||
}
|
||||
|
||||
$this->Versions[] = $version;
|
||||
$this->updateLatestVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates and returns the latest version of this package entry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updateLatestVersion(): void
|
||||
{
|
||||
$latest_version = null;
|
||||
foreach($this->Versions as $version)
|
||||
{
|
||||
$version = $version->Version;
|
||||
if($latest_version == null)
|
||||
{
|
||||
$latest_version = $version;
|
||||
continue;
|
||||
}
|
||||
if(VersionComparator::compareVersion($version, $latest_version))
|
||||
$latest_version = $version;
|
||||
}
|
||||
|
||||
$this->LatestVersion = $latest_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLatestVersion(): ?string
|
||||
{
|
||||
return $this->LatestVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all versions installed
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getVersions(): array
|
||||
{
|
||||
$r = [];
|
||||
|
||||
foreach($this->Versions as $version)
|
||||
{
|
||||
$r[] = $version->Version;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
$versions = [];
|
||||
foreach($this->Versions as $version)
|
||||
{
|
||||
$versions[] = $version->toArray($bytecode);
|
||||
}
|
||||
|
||||
return [
|
||||
($bytecode ? Functions::cbc('name') : 'name') => $this->Name,
|
||||
($bytecode ? Functions::cbc('latest_version') : 'latest_version') => $this->LatestVersion,
|
||||
($bytecode ? Functions::cbc('versions') : 'versions') => $versions,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return PackageEntry
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->Name = Functions::array_bc($data, 'name');
|
||||
$object->LatestVersion = Functions::array_bc($data, 'latest_version');
|
||||
$versions = Functions::array_bc($data, 'versions');
|
||||
|
||||
if($versions !== null)
|
||||
{
|
||||
foreach($versions as $_datum)
|
||||
{
|
||||
$object->Versions[] = VersionEntry::fromArray($_datum);
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
}
|
126
src/ncc/Objects/PackageLock/VersionEntry.php
Normal file
126
src/ncc/Objects/PackageLock/VersionEntry.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\PackageLock;
|
||||
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\Compiler;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class VersionEntry
|
||||
{
|
||||
/**
|
||||
* The version of the package that's installed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Version;
|
||||
|
||||
/**
|
||||
* The compiler extension used for the package
|
||||
*
|
||||
* @var Compiler
|
||||
*/
|
||||
public $Compiler;
|
||||
|
||||
/**
|
||||
* An array of packages that this package depends on
|
||||
*
|
||||
* @var DependencyEntry[]
|
||||
*/
|
||||
public $Dependencies;
|
||||
|
||||
/**
|
||||
* @var ExecutionUnit[]
|
||||
*/
|
||||
public $ExecutionUnits;
|
||||
|
||||
/**
|
||||
* The main execution policy for this version entry if applicable
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $MainExecutionPolicy;
|
||||
|
||||
/**
|
||||
* The path where the package is located
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Location;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Dependencies = [];
|
||||
$this->ExecutionUnits = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
$dependencies = [];
|
||||
foreach($this->Dependencies as $dependency)
|
||||
{
|
||||
$dependencies[] = $dependency->toArray($bytecode);
|
||||
}
|
||||
|
||||
$execution_units = [];
|
||||
foreach($this->ExecutionUnits as $executionUnit)
|
||||
{
|
||||
$execution_units[] = $executionUnit->toArray($bytecode);
|
||||
}
|
||||
|
||||
return [
|
||||
($bytecode ? Functions::cbc('version') : 'version') => $this->Version,
|
||||
($bytecode ? Functions::cbc('compiler') : 'compiler') => $this->Compiler->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $dependencies,
|
||||
($bytecode ? Functions::cbc('execution_units') : 'execution_units') => $execution_units,
|
||||
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->MainExecutionPolicy,
|
||||
($bytecode ? Functions::cbc('location') : 'location') => $this->Location,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return VersionEntry
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
$object->Version = Functions::array_bc($data, 'version');
|
||||
$object->Compiler = Compiler::fromArray(Functions::array_bc($data, 'compiler'));
|
||||
$object->MainExecutionPolicy = Functions::array_bc($data, 'main_execution_policy');
|
||||
$object->Location = Functions::array_bc($data, 'location');
|
||||
|
||||
$dependencies = Functions::array_bc($data, 'dependencies');
|
||||
if($dependencies !== null)
|
||||
{
|
||||
foreach($dependencies as $_datum)
|
||||
{
|
||||
$object->Dependencies[] = DependencyEntry::fromArray($_datum);
|
||||
}
|
||||
}
|
||||
|
||||
$execution_units = Functions::array_bc($data, 'execution_units');
|
||||
if($execution_units !== null)
|
||||
{
|
||||
foreach($execution_units as $_datum)
|
||||
{
|
||||
$object->ExecutionUnits[] = ExecutionUnit::fromArray($_datum);
|
||||
}
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,29 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidConstantNameException;
|
||||
use ncc\Exceptions\InvalidProjectBuildConfiguration;
|
||||
use ncc\Exceptions\InvalidProjectConfigurationException;
|
||||
use ncc\Exceptions\InvalidPropertyValueException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Exceptions\RuntimeException;
|
||||
use ncc\Exceptions\UndefinedExecutionPolicyException;
|
||||
use ncc\Exceptions\UnsupportedCompilerExtensionException;
|
||||
use ncc\Exceptions\UnsupportedExtensionVersionException;
|
||||
use ncc\Objects\ProjectConfiguration\Assembly;
|
||||
use ncc\Objects\ProjectConfiguration\Build;
|
||||
use ncc\Objects\ProjectConfiguration\BuildConfiguration;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\Objects\ProjectConfiguration\Installer;
|
||||
use ncc\Objects\ProjectConfiguration\Project;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
|
@ -36,6 +47,20 @@
|
|||
*/
|
||||
public $Assembly;
|
||||
|
||||
/**
|
||||
* An array of execution policies
|
||||
*
|
||||
* @var ExecutionPolicy[]
|
||||
*/
|
||||
public $ExecutionPolicies;
|
||||
|
||||
/**
|
||||
* Execution Policies to execute by the NCC installer
|
||||
*
|
||||
* @var Installer|null
|
||||
*/
|
||||
public $Installer;
|
||||
|
||||
/**
|
||||
* Build configuration for the project
|
||||
*
|
||||
|
@ -50,6 +75,7 @@
|
|||
{
|
||||
$this->Project = new Project();
|
||||
$this->Assembly = new Assembly();
|
||||
$this->ExecutionPolicies = [];
|
||||
$this->Build = new Build();
|
||||
}
|
||||
|
||||
|
@ -58,13 +84,15 @@
|
|||
*
|
||||
* @param bool $throw_exception
|
||||
* @return bool
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
* @throws InvalidConstantNameException
|
||||
* @throws InvalidProjectBuildConfiguration
|
||||
* @throws InvalidProjectConfigurationException
|
||||
* @throws InvalidPropertyValueException
|
||||
* @throws RuntimeException
|
||||
* @throws UndefinedExecutionPolicyException
|
||||
* @throws UnsupportedCompilerExtensionException
|
||||
* @throws UnsupportedExtensionVersionException
|
||||
* @throws InvalidProjectBuildConfiguration
|
||||
* @throws InvalidConstantNameException
|
||||
*/
|
||||
public function validate(bool $throw_exception=True): bool
|
||||
{
|
||||
|
@ -77,9 +105,170 @@
|
|||
if(!$this->Build->validate($throw_exception))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
$this->getRequiredExecutionPolicies(BuildConfigurationValues::AllConfigurations);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
if($throw_exception)
|
||||
throw $e;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return ExecutionPolicy|null
|
||||
*/
|
||||
private function getExecutionPolicy(string $name): ?ExecutionPolicy
|
||||
{
|
||||
foreach($this->ExecutionPolicies as $executionPolicy)
|
||||
{
|
||||
if($executionPolicy->Name == $name)
|
||||
return $executionPolicy;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a check on the project configuration and determines what policies are required
|
||||
*
|
||||
* @param string $build_configuration
|
||||
* @return array
|
||||
* @throws BuildConfigurationNotFoundException
|
||||
* @throws UndefinedExecutionPolicyException
|
||||
*/
|
||||
public function getRequiredExecutionPolicies(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): array
|
||||
{
|
||||
if($this->ExecutionPolicies == null || count($this->ExecutionPolicies) == 0)
|
||||
return [];
|
||||
|
||||
$defined_polices = [];
|
||||
$required_policies = [];
|
||||
/** @var ExecutionPolicy $execution_policy */
|
||||
foreach($this->ExecutionPolicies as $execution_policy)
|
||||
{
|
||||
$defined_polices[] = $execution_policy->Name;
|
||||
$execution_policy->validate();
|
||||
}
|
||||
|
||||
// Check the installer by batch
|
||||
if($this->Installer !== null)
|
||||
{
|
||||
$array_rep = $this->Installer->toArray();
|
||||
/** @var string[] $value */
|
||||
foreach($array_rep as $key => $value)
|
||||
{
|
||||
if($value == null || count($value) == 0)
|
||||
continue;
|
||||
|
||||
foreach($value as $unit)
|
||||
{
|
||||
if(!in_array($unit, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The property \'' . $key . '\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
|
||||
if(!in_array($unit, $required_policies))
|
||||
$required_policies[] = $unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->Build->PreBuild !== null && count($this->Build->PostBuild) > 0)
|
||||
{
|
||||
foreach($this->Build->PostBuild as $unit)
|
||||
{
|
||||
if(!in_array($unit, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The property \'build.pre_build\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
|
||||
if(!in_array($unit, $required_policies))
|
||||
$required_policies[] = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->Build->PostBuild !== null && count($this->Build->PostBuild) > 0)
|
||||
{
|
||||
foreach($this->Build->PostBuild as $unit)
|
||||
{
|
||||
if(!in_array($unit, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The property \'build.pre_build\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
|
||||
if(!in_array($unit, $required_policies))
|
||||
$required_policies[] = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
switch($build_configuration)
|
||||
{
|
||||
case BuildConfigurationValues::AllConfigurations:
|
||||
/** @var BuildConfiguration $configuration */
|
||||
foreach($this->Build->Configurations as $configuration)
|
||||
{
|
||||
foreach($this->processBuildPolicies($configuration, $defined_polices) as $policy)
|
||||
{
|
||||
if(!in_array($policy, $required_policies))
|
||||
$required_policies[] = $policy;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$configuration = $this->Build->getBuildConfiguration($build_configuration);
|
||||
foreach($this->processBuildPolicies($configuration, $defined_polices) as $policy)
|
||||
{
|
||||
if(!in_array($policy, $required_policies))
|
||||
$required_policies[] = $policy;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($required_policies as $policy)
|
||||
{
|
||||
$execution_policy = $this->getExecutionPolicy($policy);
|
||||
if($execution_policy->ExitHandlers !== null)
|
||||
{
|
||||
if(
|
||||
$execution_policy->ExitHandlers->Success !== null &&
|
||||
$execution_policy->ExitHandlers->Success->Run !== null
|
||||
)
|
||||
{
|
||||
if(!in_array($execution_policy->ExitHandlers->Success->Run, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Success exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Success->Run . '\'');
|
||||
|
||||
if(!in_array($execution_policy->ExitHandlers->Success->Run, $required_policies))
|
||||
$required_policies[] = $execution_policy->ExitHandlers->Success->Run;
|
||||
}
|
||||
|
||||
if(
|
||||
$execution_policy->ExitHandlers->Warning !== null &&
|
||||
$execution_policy->ExitHandlers->Warning->Run !== null
|
||||
)
|
||||
{
|
||||
if(!in_array($execution_policy->ExitHandlers->Warning->Run, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Warning exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Warning->Run . '\'');
|
||||
|
||||
if(!in_array($execution_policy->ExitHandlers->Warning->Run, $required_policies))
|
||||
$required_policies[] = $execution_policy->ExitHandlers->Warning->Run;
|
||||
}
|
||||
|
||||
if(
|
||||
$execution_policy->ExitHandlers->Error !== null &&
|
||||
$execution_policy->ExitHandlers->Error->Run !== null
|
||||
)
|
||||
{
|
||||
if(!in_array($execution_policy->ExitHandlers->Error->Run, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Error exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Error->Run . '\'');
|
||||
|
||||
if(!in_array($execution_policy->ExitHandlers->Error->Run, $required_policies))
|
||||
$required_policies[] = $execution_policy->ExitHandlers->Error->Run;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $required_policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
|
@ -88,9 +277,15 @@
|
|||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
$execution_policies = [];
|
||||
foreach($this->ExecutionPolicies as $executionPolicy)
|
||||
{
|
||||
$execution_policies[$executionPolicy->Name] = $executionPolicy->toArray($bytecode);
|
||||
}
|
||||
return [
|
||||
($bytecode ? Functions::cbc('project') : 'project') => $this->Project->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('assembly') : 'assembly') => $this->Assembly->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('execution_policies') : 'execution_policies') => $execution_policies,
|
||||
($bytecode ? Functions::cbc('build') : 'build') => $this->Build->toArray($bytecode),
|
||||
];
|
||||
}
|
||||
|
@ -128,7 +323,26 @@
|
|||
|
||||
$ProjectConfigurationObject->Project = Project::fromArray(Functions::array_bc($data, 'project'));
|
||||
$ProjectConfigurationObject->Assembly = Assembly::fromArray(Functions::array_bc($data, 'assembly'));
|
||||
$ProjectConfigurationObject->ExecutionPolicies = Functions::array_bc($data, 'execution_policies');
|
||||
$ProjectConfigurationObject->Build = Build::fromArray(Functions::array_bc($data, 'build'));
|
||||
$ProjectConfigurationObject->Installer = Functions::array_bc($data, 'installer');
|
||||
|
||||
if($ProjectConfigurationObject->Installer !== null)
|
||||
$ProjectConfigurationObject->Installer = Installer::fromArray($ProjectConfigurationObject->Installer);
|
||||
|
||||
if($ProjectConfigurationObject->ExecutionPolicies == null)
|
||||
{
|
||||
$ProjectConfigurationObject->ExecutionPolicies = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
$policies = [];
|
||||
foreach($ProjectConfigurationObject->ExecutionPolicies as $policy)
|
||||
{
|
||||
$policies[] = ExecutionPolicy::fromArray($policy);
|
||||
}
|
||||
$ProjectConfigurationObject->ExecutionPolicies = $policies;
|
||||
}
|
||||
|
||||
return $ProjectConfigurationObject;
|
||||
}
|
||||
|
@ -140,10 +354,45 @@
|
|||
* @return ProjectConfiguration
|
||||
* @throws FileNotFoundException
|
||||
* @throws MalformedJsonException
|
||||
* @throws AccessDeniedException
|
||||
* @throws IOException
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public static function fromFile(string $path): ProjectConfiguration
|
||||
{
|
||||
return ProjectConfiguration::fromArray(Functions::loadJsonFile($path, Functions::FORCE_ARRAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BuildConfiguration $configuration
|
||||
* @param array $defined_polices
|
||||
* @return array
|
||||
* @throws UndefinedExecutionPolicyException
|
||||
*/
|
||||
private function processBuildPolicies(BuildConfiguration $configuration, array $defined_polices): array
|
||||
{
|
||||
$required_policies = [];
|
||||
|
||||
if ($configuration->PreBuild !== null && count($configuration->PreBuild) > 0)
|
||||
{
|
||||
foreach ($configuration->PreBuild as $unit)
|
||||
{
|
||||
if (!in_array($unit, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The property \'pre_build\' in the build configuration \'' . $configuration->Name . '\' calls for an undefined execution policy \'' . $unit . '\'');
|
||||
$required_policies[] = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
if ($configuration->PostBuild !== null && count($configuration->PostBuild) > 0)
|
||||
{
|
||||
foreach ($configuration->PostBuild as $unit)
|
||||
{
|
||||
if (!in_array($unit, $defined_polices))
|
||||
throw new UndefinedExecutionPolicyException('The property \'pre_build\' in the build configuration \'' . $configuration->Name . '\' calls for an undefined execution policy \'' . $unit . '\'');
|
||||
$required_policies[] = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
return $required_policies;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
namespace ncc\Objects\ProjectConfiguration;
|
||||
|
||||
use ncc\Abstracts\Options\BuildConfigurationValues;
|
||||
use ncc\Exceptions\BuildConfigurationNotFoundException;
|
||||
use ncc\Exceptions\InvalidConstantNameException;
|
||||
use ncc\Exceptions\InvalidProjectBuildConfiguration;
|
||||
|
@ -51,6 +52,13 @@
|
|||
*/
|
||||
public $Scope;
|
||||
|
||||
/**
|
||||
* The execution policy to use as the main execution point
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $Main;
|
||||
|
||||
/**
|
||||
* An array of constants to define by default
|
||||
*
|
||||
|
@ -58,6 +66,20 @@
|
|||
*/
|
||||
public $DefineConstants;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute pre build
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $PreBuild;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post build
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $PostBuild;
|
||||
|
||||
/**
|
||||
* An array of dependencies that are required by default
|
||||
*
|
||||
|
@ -125,6 +147,7 @@
|
|||
* Returns an array of all the build configurations defined in the project configuration
|
||||
*
|
||||
* @return array
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getBuildConfigurations(): array
|
||||
{
|
||||
|
@ -148,6 +171,9 @@
|
|||
*/
|
||||
public function getBuildConfiguration(string $name): BuildConfiguration
|
||||
{
|
||||
if($name == BuildConfigurationValues::DefaultConfiguration)
|
||||
$name = $this->DefaultConfiguration;
|
||||
|
||||
foreach($this->Configurations as $configuration)
|
||||
{
|
||||
if($configuration->Name == $name)
|
||||
|
@ -174,7 +200,10 @@
|
|||
$ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('options') : 'options')] = $this->Options;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('scope') : 'scope')] = $this->Scope;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('main') : 'main')] = $this->Main;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('pre_build') : 'pre_build')] = $this->PreBuild;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('post_build') : 'post_build')] = $this->PostBuild;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = [];
|
||||
|
||||
foreach($this->Dependencies as $dependency)
|
||||
|
@ -207,7 +236,10 @@
|
|||
$BuildObject->ExcludeFiles = (Functions::array_bc($data, 'exclude_files') ?? []);
|
||||
$BuildObject->Options = (Functions::array_bc($data, 'options') ?? []);
|
||||
$BuildObject->Scope = Functions::array_bc($data, 'scope');
|
||||
$BuildObject->Main = Functions::array_bc($data, 'main');
|
||||
$BuildObject->DefineConstants = (Functions::array_bc($data, 'define_constants') ?? []);
|
||||
$BuildObject->PreBuild = (Functions::array_bc($data, 'pre_build') ?? []);
|
||||
$BuildObject->PostBuild = (Functions::array_bc($data, 'post_build') ?? []);
|
||||
|
||||
if(Functions::array_bc($data, 'dependencies') !== null)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,20 @@
|
|||
*/
|
||||
public $ExcludeFiles;
|
||||
|
||||
/**
|
||||
* An array of policies to execute pre-building the package
|
||||
*
|
||||
* @var string[]|string
|
||||
*/
|
||||
public $PreBuild;
|
||||
|
||||
/**
|
||||
* An array of policies to execute post-building the package
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $PostBuild;
|
||||
|
||||
/**
|
||||
* Dependencies required for the build configuration, cannot conflict with the
|
||||
* default dependencies
|
||||
|
@ -64,6 +78,8 @@
|
|||
$this->OutputPath = 'build';
|
||||
$this->DefineConstants = [];
|
||||
$this->ExcludeFiles = [];
|
||||
$this->PreBuild = [];
|
||||
$this->PostBuild = [];
|
||||
$this->Dependencies = [];
|
||||
}
|
||||
|
||||
|
@ -84,6 +100,7 @@
|
|||
$ReturnResults[($bytecode ? Functions::cbc('output_path') : 'output_path')] = $this->OutputPath;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('pre_build') : 'pre_build')] = $this->PreBuild;
|
||||
$ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = [];
|
||||
|
||||
foreach($this->Dependencies as $dependency)
|
||||
|
@ -105,36 +122,30 @@
|
|||
$BuildConfigurationObject = new BuildConfiguration();
|
||||
|
||||
if(Functions::array_bc($data, 'name') !== null)
|
||||
{
|
||||
$BuildConfigurationObject->Name = Functions::array_bc($data, 'name');
|
||||
}
|
||||
|
||||
if(Functions::array_bc($data, 'options') !== null)
|
||||
{
|
||||
$BuildConfigurationObject->Options = Functions::array_bc($data, 'options');
|
||||
}
|
||||
|
||||
if(Functions::array_bc($data, 'output_path') !== null)
|
||||
{
|
||||
$BuildConfigurationObject->OutputPath = Functions::array_bc($data, 'output_path');
|
||||
}
|
||||
|
||||
if(Functions::array_bc($data, 'define_constants') !== null)
|
||||
{
|
||||
$BuildConfigurationObject->DefineConstants = Functions::array_bc($data, 'define_constants');
|
||||
}
|
||||
|
||||
if(Functions::array_bc($data, 'exclude_files') !== null)
|
||||
{
|
||||
$BuildConfigurationObject->ExcludeFiles = Functions::array_bc($data, 'exclude_files');
|
||||
}
|
||||
|
||||
if(Functions::array_bc($data, 'pre_build') !== null)
|
||||
$BuildConfigurationObject->PreBuild = Functions::array_bc($data, 'pre_build');
|
||||
|
||||
if(Functions::array_bc($data, 'post_build') !== null)
|
||||
$BuildConfigurationObject->PostBuild = Functions::array_bc($data, 'post_build');
|
||||
|
||||
if(Functions::array_bc($data, 'dependencies') !== null)
|
||||
{
|
||||
foreach(Functions::array_bc($data, 'dependencies') as $item)
|
||||
{
|
||||
$BuildConfigurationObject->Dependencies[] = Dependency::fromArray($item);
|
||||
}
|
||||
}
|
||||
|
||||
return $BuildConfigurationObject;
|
||||
|
|
98
src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php
Normal file
98
src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ProjectConfiguration;
|
||||
|
||||
use ncc\Objects\InstallationPaths;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\Execute;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\ExitHandlers;
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class ExecutionPolicy
|
||||
{
|
||||
/**
|
||||
* The unique name of the execution policy
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Name;
|
||||
|
||||
/**
|
||||
* The name of a supported runner instance
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Runner;
|
||||
|
||||
/**
|
||||
* The message to display when the policy is invoked
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $Message;
|
||||
|
||||
/**
|
||||
* The execution process of the policy
|
||||
*
|
||||
* @var Execute
|
||||
*/
|
||||
public $Execute;
|
||||
|
||||
/**
|
||||
* The configuration for exit handling
|
||||
*
|
||||
* @var ExitHandlers
|
||||
*/
|
||||
public $ExitHandlers;
|
||||
|
||||
/**
|
||||
* @param bool $throw_exception
|
||||
* @return bool
|
||||
*/
|
||||
public function validate(bool $throw_exception=True): bool
|
||||
{
|
||||
// TODO: Implement validation method
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('name') : 'name') => $this->Name,
|
||||
($bytecode ? Functions::cbc('runner') : 'runner') => $this->Runner,
|
||||
($bytecode ? Functions::cbc('message') : 'message') => $this->Message,
|
||||
($bytecode ? Functions::cbc('exec') : 'exec') => $this->Execute?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('exit_handlers') : 'exit_handlers') => $this->ExitHandlers?->toArray($bytecode),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return ExecutionPolicy
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->Name = Functions::array_bc($data, 'name');
|
||||
$object->Runner = Functions::array_bc($data, 'runner');
|
||||
$object->Message = Functions::array_bc($data, 'message');
|
||||
$object->Execute = Functions::array_bc($data, 'exec');
|
||||
$object->ExitHandlers = Functions::array_bc($data, 'exit_handlers');
|
||||
|
||||
if($object->Execute !== null)
|
||||
$object->Execute = Execute::fromArray($object->Execute);
|
||||
|
||||
if($object->ExitHandlers !== null)
|
||||
$object->ExitHandlers = ExitHandlers::fromArray($object->ExitHandlers);
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
103
src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php
Normal file
103
src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class Execute
|
||||
{
|
||||
/**
|
||||
* The target file to execute
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Target;
|
||||
|
||||
/**
|
||||
* The working directory to execute the policy in, if not specified the
|
||||
* value "%CWD%" will be used as the default
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $WorkingDirectory;
|
||||
|
||||
/**
|
||||
* An array of options to pass on to the process
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
public $Options;
|
||||
|
||||
/**
|
||||
* Indicates if the output should be displayed or suppressed
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $Silent;
|
||||
|
||||
/**
|
||||
* Indicates if the process should run in Tty mode (Overrides Silent mode)
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $Tty;
|
||||
|
||||
/**
|
||||
* The number of seconds to wait before giving up on the process, will automatically execute the error handler
|
||||
* if one is set.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $Timeout;
|
||||
|
||||
/**
|
||||
* Public Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Tty = false;
|
||||
$this->Silent = false;
|
||||
$this->Timeout = null;
|
||||
$this->WorkingDirectory = "%CWD%";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('target') : 'target') => $this->Target,
|
||||
($bytecode ? Functions::cbc('working_directory') : 'working_directory') => $this->WorkingDirectory,
|
||||
($bytecode ? Functions::cbc('options') : 'options') => $this->Options,
|
||||
($bytecode ? Functions::cbc('silent') : 'silent') => $this->Silent,
|
||||
($bytecode ? Functions::cbc('tty') : 'tty') => $this->Tty,
|
||||
($bytecode ? Functions::cbc('timeout') : 'timeout') => $this->Timeout
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return Execute
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->Target = Functions::array_bc($data, 'target');
|
||||
$object->WorkingDirectory = Functions::array_bc($data, 'working_directory');
|
||||
$object->Options = Functions::array_bc($data, 'options');
|
||||
$object->Silent = Functions::array_bc($data, 'silent');
|
||||
$object->Tty = Functions::array_bc($data, 'tty');
|
||||
$object->Timeout = Functions::array_bc($data, 'timeout');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class ExitHandle
|
||||
{
|
||||
/**
|
||||
* The message to display when the handle is triggered
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $Message;
|
||||
|
||||
/**
|
||||
* Indicates if the process should exit if the handle is triggered,
|
||||
* by default NCC will choose the applicable value for this property,
|
||||
* for instance; if the exit handle is registered for "error", the
|
||||
* property will be set to true, otherwise for "success" and "warning"
|
||||
* the property will be false.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $EndProcess;
|
||||
|
||||
/**
|
||||
* The name of another execution policy to execute (optionally) when this exit handle is triggered
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $Run;
|
||||
|
||||
/**
|
||||
* The exit code that needs to be returned from the process to trigger this handle
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $ExitCode;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('message') : 'message') => $this->Message,
|
||||
($bytecode ? Functions::cbc('end_process') : 'end_process') => $this->EndProcess,
|
||||
($bytecode ? Functions::cbc('run') : 'run') => $this->Run,
|
||||
($bytecode ? Functions::cbc('exit_code') : 'exit_code') => $this->ExitCode,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return ExitHandle
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->Message = Functions::array_bc($data, 'message');
|
||||
$object->EndProcess = Functions::array_bc($data, 'end_process');
|
||||
$object->Run = Functions::array_bc($data, 'run');
|
||||
$object->ExitCode = Functions::array_bc($data, 'exit_code');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class ExitHandlers
|
||||
{
|
||||
/**
|
||||
* The handle to execute when the process exits with a success exit code
|
||||
*
|
||||
* @var ExitHandle
|
||||
*/
|
||||
public $Success;
|
||||
|
||||
/**
|
||||
* The handle to execute when the process exits with a warning exit code
|
||||
*
|
||||
* @var ExitHandle
|
||||
*/
|
||||
public $Warning;
|
||||
|
||||
/**
|
||||
* The handle to execute when the process exits with a error exit code
|
||||
*
|
||||
* @var ExitHandle
|
||||
*/
|
||||
public $Error;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('success') : 'success') => $this->Success?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('warning') : 'warning') => $this->Warning?->toArray($bytecode),
|
||||
($bytecode ? Functions::cbc('error') : 'error') => $this->Error?->toArray($bytecode),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs object from an array representation
|
||||
*
|
||||
* @param array $data
|
||||
* @return ExitHandlers
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->Success = Functions::array_bc($data, 'success');
|
||||
if($object->Success !== null)
|
||||
$object->Success = ExitHandle::fromArray($object->Success);
|
||||
|
||||
$object->Warning = Functions::array_bc($data, 'warning');
|
||||
if($object->Warning !== null)
|
||||
$object->Warning = ExitHandle::fromArray($object->Warning);
|
||||
|
||||
$object->Error = Functions::array_bc($data, 'error');
|
||||
if($object->Error !== null)
|
||||
$object->Error = ExitHandle::fromArray($object->Error);
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
88
src/ncc/Objects/ProjectConfiguration/Installer.php
Normal file
88
src/ncc/Objects/ProjectConfiguration/Installer.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Objects\ProjectConfiguration;
|
||||
|
||||
use ncc\Utilities\Functions;
|
||||
|
||||
class Installer
|
||||
{
|
||||
/**
|
||||
* An array of execution policies to execute pre-installation
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreInstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post-installation
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostInstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute pre-uninstallation
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreUninstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post-uninstallation
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostUninstall;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute pre-update
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PreUpdate;
|
||||
|
||||
/**
|
||||
* An array of execution policies to execute post-update
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
public $PostUpdate;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the object
|
||||
*
|
||||
* @param bool $bytecode
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(bool $bytecode=false): array
|
||||
{
|
||||
return [
|
||||
($bytecode ? Functions::cbc('pre_install') : 'pre_install') => $this->PreInstall,
|
||||
($bytecode? Functions::cbc('post_install') : 'post_install') => $this->PostInstall,
|
||||
($bytecode? Functions::cbc('pre_uninstall') : 'pre_uninstall') => $this->PostUninstall,
|
||||
($bytecode? Functions::cbc('post_uninstall') : 'post_uninstall') => $this->PostUninstall,
|
||||
($bytecode? Functions::cbc('pre_update') : 'pre_update') => $this->PreUpdate,
|
||||
($bytecode? Functions::cbc('post_update') : 'post_update') => $this->PostUpdate
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Installer
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
$object->PreInstall = Functions::array_bc($data, 'pre_install');
|
||||
$object->PostInstall = Functions::array_bc($data, 'post_install');
|
||||
$object->PreUninstall = Functions::array_bc($data, 'pre_uninstall');
|
||||
$object->PostUninstall = Functions::array_bc($data, 'post_uninstall');
|
||||
$object->PreUpdate = Functions::array_bc($data, 'pre_update');
|
||||
$object->PostUpdate = Functions::array_bc($data, 'post_update');
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,10 @@
|
|||
*/
|
||||
public static function encode(string $string): string
|
||||
{
|
||||
// Builtin function is faster than raw implementation
|
||||
if(function_exists('base64_encode'))
|
||||
return base64_encode($string);
|
||||
|
||||
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
|
||||
$bit_pattern = '';
|
||||
$padding = 0;
|
||||
|
@ -54,6 +58,9 @@
|
|||
*/
|
||||
public static function decode(string $string): string
|
||||
{
|
||||
if(function_exists('base64_decode'))
|
||||
return base64_encode($string);
|
||||
|
||||
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
|
||||
$bit_pattern = '';
|
||||
$padding = substr_count(substr(strrev($string), 0, 2), '=');
|
||||
|
|
|
@ -4,10 +4,17 @@
|
|||
|
||||
use Exception;
|
||||
use ncc\Abstracts\ConsoleColors;
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\CLI\Main;
|
||||
use ncc\ncc;
|
||||
|
||||
class Console
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $largestTickLength = 0;
|
||||
|
||||
/**
|
||||
* Inline Progress bar, created by dealnews.com.
|
||||
*
|
||||
|
@ -23,6 +30,20 @@
|
|||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null)
|
||||
{
|
||||
switch(Main::getLogLevel())
|
||||
{
|
||||
case LogLevel::Verbose:
|
||||
case LogLevel::Debug:
|
||||
case LogLevel::Silent:
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static $start_time;
|
||||
|
||||
// if we go over our bound, just ignore it
|
||||
|
@ -44,6 +65,7 @@
|
|||
$status_bar.="=";
|
||||
}
|
||||
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$disp=number_format($perc*100, 0);
|
||||
|
||||
$status_bar.=" ] $disp% $value/$total";
|
||||
|
@ -74,18 +96,54 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a verbose prefix to the message
|
||||
*
|
||||
* @param string $log_level
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
private static function setPrefix(string $log_level, string $input): string
|
||||
{
|
||||
$input = match ($log_level) {
|
||||
LogLevel::Verbose => self::formatColor('VRB:', ConsoleColors::LightCyan) . " $input",
|
||||
LogLevel::Debug => self::formatColor('DBG:', ConsoleColors::LightMagenta) . " $input",
|
||||
LogLevel::Info => self::formatColor('INF:', ConsoleColors::White) . " $input",
|
||||
LogLevel::Warning => self::formatColor('WRN:', ConsoleColors::Yellow) . " $input",
|
||||
LogLevel::Error => self::formatColor('ERR:', ConsoleColors::LightRed) . " $input",
|
||||
LogLevel::Fatal => self::formatColor('FTL:', ConsoleColors::LightRed) . " $input",
|
||||
default => self::formatColor('MSG:', ConsoleColors::Default) . " $input",
|
||||
};
|
||||
|
||||
$tick_time = (string)microtime(true);
|
||||
if(strlen($tick_time) > self::$largestTickLength)
|
||||
self::$largestTickLength = strlen($tick_time);
|
||||
if(strlen($tick_time) < self::$largestTickLength)
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$tick_time = str_pad($tick_time, (strlen($tick_time) + (self::$largestTickLength - strlen($tick_time))), ' ', STR_PAD_RIGHT);
|
||||
|
||||
return '[' . $tick_time . ' - ' . date('TH:i:sP') . '] ' . $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple output function
|
||||
*
|
||||
* @param string $message
|
||||
* @param bool $newline
|
||||
* @param bool $no_prefix
|
||||
* @return void
|
||||
*/
|
||||
public static function out(string $message, bool $newline=true): void
|
||||
public static function out(string $message, bool $newline=true, bool $no_prefix=false): void
|
||||
{
|
||||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Info, Main::getLogLevel()))
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()) && !$no_prefix)
|
||||
$message = self::setPrefix(LogLevel::Info, $message);
|
||||
|
||||
if($newline)
|
||||
{
|
||||
print($message . PHP_EOL);
|
||||
|
@ -95,6 +153,58 @@
|
|||
print($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output debug message
|
||||
*
|
||||
* @param string $message
|
||||
* @param bool $newline
|
||||
* @return void
|
||||
*/
|
||||
public static function outDebug(string $message, bool $newline=true): void
|
||||
{
|
||||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
|
||||
return;
|
||||
|
||||
$backtrace = null;
|
||||
if(function_exists('debug_backtrace'))
|
||||
$backtrace = debug_backtrace();
|
||||
$trace_msg = null;
|
||||
if($backtrace !== null && isset($backtrace[1]))
|
||||
{
|
||||
$trace_msg = Console::formatColor($backtrace[1]['class'], ConsoleColors::LightGray);
|
||||
$trace_msg .= $backtrace[1]['type'];
|
||||
$trace_msg .= Console::formatColor($backtrace[1]['function'] . '()', ConsoleColors::LightGreen);
|
||||
$trace_msg .= ' > ';
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnnecessaryStringCastInspection */
|
||||
$message = self::setPrefix(LogLevel::Debug, (string)$trace_msg . $message);
|
||||
|
||||
self::out($message, $newline, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output debug message
|
||||
*
|
||||
* @param string $message
|
||||
* @param bool $newline
|
||||
* @return void
|
||||
*/
|
||||
public static function outVerbose(string $message, bool $newline=true): void
|
||||
{
|
||||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
|
||||
return;
|
||||
|
||||
self::out(self::setPrefix(LogLevel::Verbose, $message), $newline, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats the text to have a different color and returns the formatted value
|
||||
*
|
||||
|
@ -105,6 +215,11 @@
|
|||
*/
|
||||
public static function formatColor(string $input, string $color_code, bool $persist=true): string
|
||||
{
|
||||
if(Main::getArgs() !== null && isset(Main::getArgs()['no-color']))
|
||||
{
|
||||
return $input;
|
||||
}
|
||||
|
||||
if($persist)
|
||||
{
|
||||
return $color_code . $input . ConsoleColors::Default;
|
||||
|
@ -125,6 +240,15 @@
|
|||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Warning, Main::getLogLevel()))
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
|
||||
{
|
||||
self::out(self::setPrefix(LogLevel::Warning, $message), $newline, true);
|
||||
return;
|
||||
}
|
||||
|
||||
self::out(self::formatColor('Warning: ', ConsoleColors::Yellow) . $message, $newline);
|
||||
}
|
||||
|
||||
|
@ -141,7 +265,17 @@
|
|||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
self::out(self::formatColor(ConsoleColors::Red, 'Error: ') . $message, $newline);
|
||||
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Error, Main::getLogLevel()))
|
||||
return;
|
||||
|
||||
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
|
||||
{
|
||||
self::out(self::setPrefix(LogLevel::Error, $message), $newline, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::out(self::formatColor(ConsoleColors::Red, 'Error: ') . $message, $newline);
|
||||
}
|
||||
|
||||
if($exit_code !== null)
|
||||
{
|
||||
|
@ -162,11 +296,12 @@
|
|||
if(!ncc::cliMode())
|
||||
return;
|
||||
|
||||
if(strlen($message) > 0)
|
||||
if(strlen($message) > 0 && Resolver::checkLogLevel(LogLevel::Error, Main::getLogLevel()))
|
||||
{
|
||||
self::out(self::formatColor('Error: ' . $message, ConsoleColors::Red));
|
||||
self::out(PHP_EOL . self::formatColor('Error: ', ConsoleColors::Red) . $message);
|
||||
}
|
||||
|
||||
Console::out(PHP_EOL . '===== Exception Details =====');
|
||||
self::outExceptionDetails($e);
|
||||
|
||||
if($exit_code !== null)
|
||||
|
@ -189,6 +324,39 @@
|
|||
$trace_header = self::formatColor($e->getFile() . ':' . $e->getLine(), ConsoleColors::Magenta);
|
||||
$trace_error = self::formatColor('error: ', ConsoleColors::Red);
|
||||
self::out($trace_header . ' ' . $trace_error . $e->getMessage());
|
||||
self::out(sprintf('Error code: %s', $e->getCode()));
|
||||
$trace = $e->getTrace();
|
||||
if(count($trace) > 1)
|
||||
{
|
||||
self::out('Stack Trace:');
|
||||
foreach($trace as $item)
|
||||
{
|
||||
self::out( ' - ' . self::formatColor($item['file'], ConsoleColors::Red) . ':' . $item['line']);
|
||||
}
|
||||
}
|
||||
|
||||
if(Main::getArgs() !== null)
|
||||
{
|
||||
if(isset(Main::getArgs()['dbg-ex']))
|
||||
{
|
||||
try
|
||||
{
|
||||
$dump = [
|
||||
'constants' => ncc::getConstants(),
|
||||
'exception' => Functions::exceptionToArray($e)
|
||||
];
|
||||
IO::fwrite(getcwd() . DIRECTORY_SEPARATOR . time() . '.json', json_encode($dump, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), 0777);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
self::outWarning('Cannot dump exception details, ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self::out('You can pass on \'--dbg-ex\' option to dump the exception details to a json file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,9 +2,22 @@
|
|||
|
||||
namespace ncc\Utilities;
|
||||
|
||||
use Exception;
|
||||
use ncc\Abstracts\Runners;
|
||||
use ncc\Abstracts\Scopes;
|
||||
use ncc\Classes\PhpExtension\Runner;
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\InvalidScopeException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use ncc\Exceptions\MalformedJsonException;
|
||||
use ncc\Exceptions\UnsupportedRunnerException;
|
||||
use ncc\Managers\CredentialManager;
|
||||
use ncc\Managers\PackageLockManager;
|
||||
use ncc\Objects\CliHelpSection;
|
||||
use ncc\Objects\Package\ExecutionUnit;
|
||||
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
|
||||
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* @author Zi Xing Narrakas
|
||||
|
@ -22,11 +35,15 @@
|
|||
* Calculates a byte-code representation of the input using CRC32
|
||||
*
|
||||
* @param string $input
|
||||
* @return int
|
||||
* @return string
|
||||
*/
|
||||
public static function cbc(string $input): int
|
||||
public static function cbc(string $input): string
|
||||
{
|
||||
return hexdec(hash('crc32', $input, true));
|
||||
$cache = RuntimeCache::get("cbc_$input");
|
||||
if($cache !== null)
|
||||
return $cache;
|
||||
|
||||
return RuntimeCache::set("cbc_$input", hash('crc32', $input, true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +53,7 @@
|
|||
* @param array $data
|
||||
* @param string $select
|
||||
* @return mixed|null
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
*/
|
||||
public static function array_bc(array $data, string $select)
|
||||
{
|
||||
|
@ -54,7 +72,9 @@
|
|||
* @param string $path
|
||||
* @param int $flags
|
||||
* @return mixed
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws MalformedJsonException
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
*/
|
||||
|
@ -65,7 +85,7 @@
|
|||
throw new FileNotFoundException($path);
|
||||
}
|
||||
|
||||
return self::loadJson(file_get_contents($path), $flags);
|
||||
return self::loadJson(IO::fread($path), $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,6 +118,7 @@
|
|||
* @return string
|
||||
* @throws MalformedJsonException
|
||||
* @noinspection PhpMissingParamTypeInspection
|
||||
* @noinspection PhpUnusedLocalVariableInspection
|
||||
*/
|
||||
public static function encodeJson($value, int $flags=0): string
|
||||
{
|
||||
|
@ -123,7 +144,7 @@
|
|||
* @return void
|
||||
* @throws MalformedJsonException
|
||||
*/
|
||||
public static function encodeJsonFile($value, string $path, int $flags=0)
|
||||
public static function encodeJsonFile($value, string $path, int $flags=0): void
|
||||
{
|
||||
file_put_contents($path, self::encodeJson($value, $flags));
|
||||
}
|
||||
|
@ -160,16 +181,19 @@
|
|||
* @param string $copyright
|
||||
* @param bool $basic_ascii
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function getBanner(string $version, string $copyright, bool $basic_ascii=false): string
|
||||
{
|
||||
if($basic_ascii)
|
||||
{
|
||||
$banner = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_basic');
|
||||
$banner = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_basic');
|
||||
}
|
||||
else
|
||||
{
|
||||
$banner = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_extended');
|
||||
$banner = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_extended');
|
||||
}
|
||||
|
||||
$banner_version = str_pad($version, 21);
|
||||
|
@ -219,26 +243,125 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts the input string into a Bas64 encoding before returning it as a
|
||||
* byte representation
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
* @param string $path
|
||||
* @param ExecutionPolicy $policy
|
||||
* @return ExecutionUnit
|
||||
* @throws UnsupportedRunnerException
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function byteEncode(string $string): string
|
||||
public static function compileRunner(string $path, ExecutionPolicy $policy): ExecutionUnit
|
||||
{
|
||||
return convert_uuencode(Base64::encode($string));
|
||||
return match (strtolower($policy->Runner)) {
|
||||
Runners::php => Runner::processUnit($path, $policy),
|
||||
default => throw new UnsupportedRunnerException('The runner \'' . $policy->Runner . '\' is not supported'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the input string back into the normal string representation that was encoded
|
||||
* by the byteEncode() function
|
||||
* Returns an array representation of the exception
|
||||
*
|
||||
* @param string $string
|
||||
* @param Exception $e
|
||||
* @return array
|
||||
*/
|
||||
public static function exceptionToArray(Exception $e): array
|
||||
{
|
||||
$exception = [
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'trace' => null,
|
||||
'trace_string' => $e->getTraceAsString(),
|
||||
];
|
||||
|
||||
if($e->getPrevious() !== null)
|
||||
{
|
||||
$exception['trace'] = self::exceptionToArray($e);
|
||||
}
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the input bytes and converts it to a readable unit representation
|
||||
*
|
||||
* @param int $bytes
|
||||
* @param int $decimals
|
||||
* @return string
|
||||
*/
|
||||
public static function byteDecode(string $string): string
|
||||
public static function b2u(int $bytes, int $decimals=2): string
|
||||
{
|
||||
return base64_decode(convert_uudecode($string));
|
||||
$size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
|
||||
$factor = floor((strlen($bytes) - 1) / 3);
|
||||
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes NCC files
|
||||
*
|
||||
* @return void
|
||||
* @throws AccessDeniedException
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public static function initializeFiles(): void
|
||||
{
|
||||
if(Resolver::resolveScope() !== Scopes::System)
|
||||
throw new AccessDeniedException('Cannot initialize NCC files, insufficient permissions');
|
||||
|
||||
Console::outVerbose('Initializing NCC files');
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
if(!$filesystem->exists(PathFinder::getDataPath(Scopes::System)))
|
||||
{
|
||||
Console::outDebug(sprintf('Initializing %s', PathFinder::getDataPath(Scopes::System)));
|
||||
$filesystem->mkdir(PathFinder::getDataPath(Scopes::System), 0755);
|
||||
}
|
||||
|
||||
if(!$filesystem->exists(PathFinder::getCachePath(Scopes::System)))
|
||||
{
|
||||
Console::outDebug(sprintf('Initializing %s', PathFinder::getCachePath(Scopes::System)));
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$filesystem->mkdir(PathFinder::getCachePath(Scopes::System), 0777);
|
||||
}
|
||||
|
||||
if(!$filesystem->exists(PathFinder::getRunnerPath(Scopes::System)))
|
||||
{
|
||||
Console::outDebug(sprintf('Initializing %s', PathFinder::getRunnerPath(Scopes::System)));
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$filesystem->mkdir(PathFinder::getRunnerPath(Scopes::System), 0755);
|
||||
}
|
||||
|
||||
if(!$filesystem->exists(PathFinder::getPackagesPath(Scopes::System)))
|
||||
{
|
||||
Console::outDebug(sprintf('Initializing %s', PathFinder::getPackagesPath(Scopes::System)));
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$filesystem->mkdir(PathFinder::getPackagesPath(Scopes::System), 0755);
|
||||
}
|
||||
|
||||
// Create credential store if needed
|
||||
try
|
||||
{
|
||||
Console::outVerbose('Processing Credential Store');
|
||||
$credential_manager = new CredentialManager();
|
||||
$credential_manager->constructStore();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outError('Cannot construct credential store, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
|
||||
}
|
||||
|
||||
// Create package lock if needed
|
||||
try
|
||||
{
|
||||
Console::outVerbose('Processing Package Lock');
|
||||
$package_manager = new PackageLockManager();
|
||||
$package_manager->constructLockFile();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Console::outError('Cannot construct Package Lock, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
|
||||
}
|
||||
}
|
||||
}
|
97
src/ncc/Utilities/IO.php
Normal file
97
src/ncc/Utilities/IO.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Utilities;
|
||||
|
||||
use ncc\Exceptions\AccessDeniedException;
|
||||
use ncc\Exceptions\FileNotFoundException;
|
||||
use ncc\Exceptions\IOException;
|
||||
use SplFileInfo;
|
||||
use SplFileObject;
|
||||
|
||||
class IO
|
||||
{
|
||||
/**
|
||||
* Attempts to write the specified file, with proper error handling
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $data
|
||||
* @param int $perms
|
||||
* @param string $mode
|
||||
* @return void
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function fwrite(string $uri, string $data, int $perms=0644, string $mode='w'): void
|
||||
{
|
||||
$fileInfo = new SplFileInfo($uri);
|
||||
|
||||
if(!is_dir($fileInfo->getPath()))
|
||||
{
|
||||
throw new IOException(sprintf('Attempted to write data to a directory instead of a file: (%s)', $uri));
|
||||
}
|
||||
|
||||
Console::outDebug(sprintf('writing %s of data to %s', Functions::b2u(strlen($data)), $uri));
|
||||
$file = new SplFileObject($uri, $mode);
|
||||
|
||||
if (!$file->flock(LOCK_EX | LOCK_NB))
|
||||
{
|
||||
throw new IOException(sprintf('Unable to obtain lock on file: (%s)', $uri));
|
||||
}
|
||||
elseif (!$file->fwrite($data))
|
||||
{
|
||||
throw new IOException(sprintf('Unable to write content to file: (%s)... to (%s)', substr($data,0,25), $uri));
|
||||
}
|
||||
elseif (!$file->flock(LOCK_UN))
|
||||
{
|
||||
throw new IOException(sprintf('Unable to remove lock on file: (%s)', $uri));
|
||||
}
|
||||
elseif (!@chmod($uri, $perms))
|
||||
{
|
||||
throw new IOException(sprintf('Unable to chmod: (%s) to (%s)', $uri, $perms));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read the specified file
|
||||
*
|
||||
* @param string $uri
|
||||
* @param string $mode
|
||||
* @param int|null $length
|
||||
* @return string
|
||||
* @throws AccessDeniedException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static function fread(string $uri, string $mode='r', ?int $length=null): string
|
||||
{
|
||||
$fileInfo = new SplFileInfo($uri);
|
||||
|
||||
if(!is_dir($fileInfo->getPath()))
|
||||
{
|
||||
throw new IOException(sprintf('Attempted to read data from a directory instead of a file: (%s)', $uri));
|
||||
}
|
||||
|
||||
if(!file_exists($uri))
|
||||
{
|
||||
throw new FileNotFoundException(sprintf('Cannot find file %s', $uri));
|
||||
}
|
||||
|
||||
if(!is_readable($uri))
|
||||
{
|
||||
throw new AccessDeniedException(sprintf('Insufficient permissions to read %s', $uri));
|
||||
}
|
||||
|
||||
$file = new SplFileObject($uri, $mode);
|
||||
if($length == null)
|
||||
{
|
||||
$length = $file->getSize();
|
||||
}
|
||||
|
||||
if($length == 0)
|
||||
{
|
||||
return (string)null;
|
||||
}
|
||||
|
||||
Console::outDebug(sprintf('reading %s', $uri));
|
||||
return $file->fread($length);
|
||||
}
|
||||
}
|
|
@ -145,49 +145,16 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the path where temporary files are stored
|
||||
* Returns the path where Runner bin files are located and installed
|
||||
*
|
||||
* @param string $scope
|
||||
* @param bool $win32
|
||||
* @return string
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public static function getTmpPath(string $scope=Scopes::Auto, bool $win32=false): string
|
||||
public static function getRunnerPath(string $scope=Scopes::Auto, bool $win32=false): string
|
||||
{
|
||||
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'tmp';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration file
|
||||
*
|
||||
* @param string $scope
|
||||
* @param bool $win32
|
||||
* @return string
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public static function getConfigurationFile(string $scope=Scopes::Auto, bool $win32=false): string
|
||||
{
|
||||
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'config';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the configuration files the current user can access (For global-cross referencing)
|
||||
*
|
||||
* @param bool $win32
|
||||
* @return array
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public static function getConfigurationFiles(bool $win32=false): array
|
||||
{
|
||||
$results = [];
|
||||
$results[] = self::getConfigurationFile(Scopes::System, $win32);
|
||||
|
||||
if(!in_array(self::getConfigurationFile(Scopes::User, $win32), $results))
|
||||
{
|
||||
$results[] = self::getConfigurationFile(Scopes::User, $win32);
|
||||
}
|
||||
|
||||
return $results;
|
||||
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'runners';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,18 +202,4 @@
|
|||
{
|
||||
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'ext';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file path where files for the given extension is stored
|
||||
*
|
||||
* @param string $extension_name
|
||||
* @param string $scope
|
||||
* @param bool $win32
|
||||
* @return string
|
||||
* @throws InvalidScopeException
|
||||
*/
|
||||
public static function getNamedExtensionPath(string $extension_name, string $scope=Scopes::Auto, bool $win32=false): string
|
||||
{
|
||||
return self::getExtensionPath($scope, $win32) . DIRECTORY_SEPARATOR . Security::sanitizeFilename($extension_name);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Utilities;
|
||||
/** @noinspection PhpMissingFieldTypeInspection */
|
||||
|
||||
namespace ncc\Utilities;
|
||||
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\Abstracts\Scopes;
|
||||
|
||||
class Resolver
|
||||
{
|
||||
/**
|
||||
* The cache value of the User ID
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private static $UserIdCache;
|
||||
|
||||
/**
|
||||
* @param string|null $input
|
||||
* @return string
|
||||
|
@ -20,10 +30,13 @@
|
|||
|
||||
$input = strtoupper($input);
|
||||
|
||||
if(self::$UserIdCache == null)
|
||||
self::$UserIdCache = posix_getuid();
|
||||
|
||||
// Resolve the scope if it's set to automatic
|
||||
if($input == Scopes::Auto)
|
||||
{
|
||||
if(posix_getuid() == 0)
|
||||
if(self::$UserIdCache == 0)
|
||||
{
|
||||
$input = Scopes::System;
|
||||
}
|
||||
|
@ -34,7 +47,7 @@
|
|||
}
|
||||
|
||||
// Auto-Correct the scope if the current user ID is 0
|
||||
if($input == Scopes::User && posix_getuid() == 0)
|
||||
if($input == Scopes::User && self::$UserIdCache == 0)
|
||||
{
|
||||
$input = Scopes::System;
|
||||
}
|
||||
|
@ -45,9 +58,12 @@
|
|||
/**
|
||||
* Parse arguments
|
||||
*
|
||||
* @param array|string [$message] input arguments
|
||||
* @param array|string $message [$message] input arguments
|
||||
* @param int $max_arguments
|
||||
* @return array Configs Key/Value
|
||||
* @noinspection RegExpRedundantEscape
|
||||
* @noinspection RegExpSimplifiable
|
||||
* @noinspection PhpMissingParamTypeInspection
|
||||
*/
|
||||
public static function parseArguments($message=null, int $max_arguments=1000): array
|
||||
{
|
||||
|
@ -135,4 +151,94 @@
|
|||
{
|
||||
return hash('haval128,3', self::resolveFullConstantName($scope, $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the input level matches the current level
|
||||
*
|
||||
* @param string|null $input
|
||||
* @param string|null $current_level
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkLogLevel(?string $input, ?string $current_level): bool
|
||||
{
|
||||
if($input == null)
|
||||
return false;
|
||||
if($current_level == null)
|
||||
return false;
|
||||
|
||||
$input = strtolower($input);
|
||||
if(!Validate::checkLogLevel($input))
|
||||
return false;
|
||||
|
||||
$current_level = strtolower($current_level);
|
||||
if(!Validate::checkLogLevel($current_level))
|
||||
return false;
|
||||
|
||||
switch($current_level)
|
||||
{
|
||||
case LogLevel::Debug:
|
||||
$levels = [
|
||||
LogLevel::Debug,
|
||||
LogLevel::Verbose,
|
||||
LogLevel::Info,
|
||||
LogLevel::Warning,
|
||||
LogLevel::Fatal,
|
||||
LogLevel::Error
|
||||
];
|
||||
if(in_array($input, $levels))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case LogLevel::Verbose:
|
||||
$levels = [
|
||||
LogLevel::Verbose,
|
||||
LogLevel::Info,
|
||||
LogLevel::Warning,
|
||||
LogLevel::Fatal,
|
||||
LogLevel::Error
|
||||
];
|
||||
if(in_array($input, $levels))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case LogLevel::Info:
|
||||
$levels = [
|
||||
LogLevel::Info,
|
||||
LogLevel::Warning,
|
||||
LogLevel::Fatal,
|
||||
LogLevel::Error
|
||||
];
|
||||
if(in_array($input, $levels))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case LogLevel::Warning:
|
||||
$levels = [
|
||||
LogLevel::Warning,
|
||||
LogLevel::Fatal,
|
||||
LogLevel::Error
|
||||
];
|
||||
if(in_array($input, $levels))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case LogLevel::Error:
|
||||
$levels = [
|
||||
LogLevel::Fatal,
|
||||
LogLevel::Error
|
||||
];
|
||||
if(in_array($input, $levels))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case LogLevel::Fatal:
|
||||
if($input == LogLevel::Fatal)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
default:
|
||||
case LogLevel::Silent:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
40
src/ncc/Utilities/RuntimeCache.php
Normal file
40
src/ncc/Utilities/RuntimeCache.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace ncc\Utilities;
|
||||
|
||||
class RuntimeCache
|
||||
{
|
||||
/**
|
||||
* An array of cache entries
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $cache = [];
|
||||
|
||||
/**
|
||||
* Sets a value, returns the value
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set($key, $value)
|
||||
{
|
||||
self::$cache[$key] = $value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an existing value, null if it doesn't exist
|
||||
*
|
||||
* @param $key
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function get($key)
|
||||
{
|
||||
if(isset(self::$cache[$key]))
|
||||
return self::$cache[$key];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace ncc\Utilities;
|
||||
|
||||
use ncc\Abstracts\LogLevel;
|
||||
use ncc\Abstracts\RegexPatterns;
|
||||
use ncc\Abstracts\Scopes;
|
||||
|
||||
|
@ -208,4 +209,53 @@
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the execution policy name
|
||||
*
|
||||
* @param string $input
|
||||
* @return bool
|
||||
*/
|
||||
public static function executionPolicyName(string $input): bool
|
||||
{
|
||||
if($input == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!preg_match(RegexPatterns::ExecutionPolicyName, $input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given log level is valid or not
|
||||
*
|
||||
* @param string $input
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkLogLevel(string $input): bool
|
||||
{
|
||||
if(!in_array(strtolower($input), LogLevel::All))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if given input exceeds the path length limit
|
||||
*
|
||||
* @param string $input
|
||||
* @return bool
|
||||
*/
|
||||
public static function exceedsPathLength(string $input): bool
|
||||
{
|
||||
if(strlen($input) > 4096)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
9
tests/package_lock/load_package_lock.php
Normal file
9
tests/package_lock/load_package_lock.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
require(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'autoload.php');
|
||||
|
||||
\ncc\ncc::initialize();
|
||||
$package_lock_manager = new \ncc\Managers\PackageLockManager();
|
||||
$package_lock_manager->load();
|
||||
|
||||
var_dump($package_lock_manager->getPackageLock());
|
Loading…
Add table
Reference in a new issue