diff --git a/src/config/ncc.yaml b/src/config/ncc.yaml index f552647..36c6488 100644 --- a/src/config/ncc.yaml +++ b/src/config/ncc.yaml @@ -19,9 +19,6 @@ ncc: php: # The main executable path for PHP that NCC should use executable_path: "/usr/bin/php" - runtime: - # Whether to initialize NCC when running `require('ncc');` - initialize_on_require: true git: # if git is enabled or not diff --git a/src/installer/installer b/src/installer/installer index a064276..9996434 100644 --- a/src/installer/installer +++ b/src/installer/installer @@ -14,11 +14,11 @@ use ncc\Abstracts\ConsoleColors; use ncc\Exceptions\FileNotFoundException; -use ncc\Managers\RemoteSourcesManager; -use ncc\ncc; + use ncc\Managers\RemoteSourcesManager; + use ncc\ncc; use ncc\Objects\CliHelpSection; -use ncc\Objects\DefinedRemoteSource; -use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException; + use ncc\Objects\DefinedRemoteSource; + use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException; use ncc\ThirdParty\Symfony\Filesystem\Filesystem; use ncc\ThirdParty\Symfony\Process\Exception\ProcessFailedException; use ncc\ThirdParty\Symfony\Process\ExecutableFinder; diff --git a/src/ncc/CLI/Commands/ExecCommand.php b/src/ncc/CLI/Commands/ExecCommand.php index a5d3171..5411b99 100644 --- a/src/ncc/CLI/Commands/ExecCommand.php +++ b/src/ncc/CLI/Commands/ExecCommand.php @@ -4,9 +4,8 @@ use Exception; use ncc\Managers\ExecutionPointerManager; + use ncc\Managers\PackageLockManager; use ncc\Objects\CliHelpSection; - use ncc\Objects\Package\ExecutionUnit; - use ncc\ThirdParty\Symfony\Process\Process; use ncc\Utilities\Console; use ncc\Utilities\Functions; @@ -21,8 +20,9 @@ public static function start($args): void { $package = $args['package'] ?? null; - $version = $args['version'] ?? 'latest'; - $entry = $args['entry'] ?? null; + $version = $args['exec-version'] ?? 'latest'; + $unit_name = $args['exec-unit'] ?? 'main'; + $set_args = $args['exec-args'] ?? null; if($package == null) { @@ -30,24 +30,32 @@ exit(0); } - $arguments = []; - $whitelist_arguments = [ - 'package', - 'version', - 'entry', - 'help', - ]; - foreach($args as $key => $value) - { - if(!in_array($key, $whitelist_arguments)) - $arguments[$key] = $value; - } - + $package_lock_manager = new PackageLockManager(); $execution_pointer_manager = new ExecutionPointerManager(); try { - $units = $execution_pointer_manager->getUnits($package, $version); + $package_entry = $package_lock_manager->getPackageLock()->getPackage($package); + } + catch(Exception $e) + { + Console::outException('Package ' . $package . ' is not installed', $e, 1); + return; + } + + try + { + $version_entry = $package_entry->getVersion($version); + } + catch(Exception $e) + { + Console::outException('Version ' . $version . ' is not installed', $e, 1); + return; + } + + try + { + $units = $execution_pointer_manager->getUnits($package_entry->Name, $version_entry->Version); } catch(Exception $e) { @@ -55,70 +63,30 @@ return; } - if(!isset($units[$entry])) + if(!in_array($unit_name, $units)) { - Console::outError(sprintf('Cannot find execution point \'%s\' in package \'%s\'', $entry, $package), true, 1); + Console::outError(sprintf('Unit \'%s\' is not configured for package \'%s\'', $unit_name, $package), true, 1); return; } - /** @var ExecutionUnit $exec_unit */ - $exec_unit = $units[$entry]; - $exec_path = ''; + $options = []; - $process = new Process(array_merge([$exec_path], $arguments)); - if($exec_unit->ExecutionPolicy->Execute->Pty !== null) - $process->setPty($exec_unit->ExecutionPolicy->Execute->Pty); - - if($exec_unit->ExecutionPolicy->Execute->Tty !== null) + if($set_args != null) { - $process->setTty($exec_unit->ExecutionPolicy->Execute->Tty); - $process->setPty(false); + global $argv; + $args_index = array_search('--exec-args', $argv); + $options = array_slice($argv, $args_index + 1); } - if($exec_unit->ExecutionPolicy->Execute->WorkingDirectory !== null) - $process->setWorkingDirectory($exec_unit->ExecutionPolicy->Execute->WorkingDirectory); - if($exec_unit->ExecutionPolicy->Execute->EnvironmentVariables !== null) - $process->setEnv($exec_unit->ExecutionPolicy->Execute->EnvironmentVariables); - if($exec_unit->ExecutionPolicy->Execute->Timeout !== null) - $process->setTimeout($exec_unit->ExecutionPolicy->Execute->Timeout); - if($exec_unit->ExecutionPolicy->Execute->IdleTimeout !== null) - $process->setIdleTimeout($exec_unit->ExecutionPolicy->Execute->IdleTimeout); - if($exec_unit->ExecutionPolicy->Execute->Options !== null) - $process->setOptions($exec_unit->ExecutionPolicy->Execute->Options); - - if($process->isTty() || $process->isPty()) + try { - $process->start(); - $process->wait(); + exit($execution_pointer_manager->executeUnit($package_entry->Name, $version_entry->Version, $unit_name, $options)); } - else + catch(Exception $e) { - $process->start(); - - while($process->isRunning()) - { - if($exec_unit->ExecutionPolicy->Execute->Silent) - { - $process->wait(); - } - else - { - $process->waitUntil(function($type, $buffer) - { - if($type == Process::ERR) - { - Console::outError($buffer); - } - else - { - Console::out($buffer); - } - }); - } - } + Console::outException(sprintf('Cannot execute execution point \'%s\' in package \'%s\'', $unit_name, $package), $e, 1); + return; } - - exit(0); } /** @@ -131,8 +99,9 @@ $options = [ new CliHelpSection(['help'], 'Displays this help menu about the value command'), new CliHelpSection(['exec', '--package'], '(Required) The package to execute'), - new CliHelpSection(['--version'], '(default: latest) The version of the package to execute'), - new CliHelpSection(['--entry'], '(default: main) The entry point of the package to execute'), + new CliHelpSection(['--exec-version'], '(default: latest) The version of the package to execute'), + new CliHelpSection(['--exec-unit'], '(default: main) The unit point of the package to execute'), + new CliHelpSection(['--exec-args'], '(optional) Anything past this point will be passed to the execution unit'), ]; $options_padding = Functions::detectParametersPadding($options) + 4; @@ -148,8 +117,8 @@ Console::out(' The arguments to pass to the program'); Console::out(PHP_EOL . 'Example Usage:' . PHP_EOL); Console::out(' ncc exec --package com.example.program'); - Console::out(' ncc exec --package com.example.program --version 1.0.0'); - Console::out(' ncc exec --package com.example.program --version 1.0.0 --entry setup'); - Console::out(' ncc exec --package com.example.program --foo --bar --extra=test'); + Console::out(' ncc exec --package com.example.program --exec-version 1.0.0'); + Console::out(' ncc exec --package com.example.program --exec-version 1.0.0 --unit setup'); + Console::out(' ncc exec --package com.example.program --exec-args --foo --bar --extra=test'); } } \ No newline at end of file diff --git a/src/ncc/CLI/Main.php b/src/ncc/CLI/Main.php index a0f03d0..7b0a308 100644 --- a/src/ncc/CLI/Main.php +++ b/src/ncc/CLI/Main.php @@ -8,6 +8,7 @@ use ncc\Abstracts\LogLevel; use ncc\Abstracts\NccBuildFlags; use ncc\CLI\Commands\BuildCommand; + use ncc\CLI\Commands\ExecCommand; use ncc\CLI\Management\ConfigMenu; use ncc\CLI\Management\CredentialMenu; use ncc\CLI\Management\PackageManagerMenu; @@ -107,36 +108,40 @@ { default: Console::out('Unknown command ' . strtolower(self::$args['ncc-cli'])); - exit(1); + break; case 'project': ProjectMenu::start(self::$args); - exit(0); + break; case 'build': BuildCommand::start(self::$args); - exit(0); + break; + + case 'exec': + ExecCommand::start(self::$args); + break; case 'cred': CredentialMenu::start(self::$args); - exit(0); + break; case 'package': PackageManagerMenu::start(self::$args); - exit(0); + break; case 'config': ConfigMenu::start(self::$args); - exit(0); + break; case 'source': SourcesMenu::start(self::$args); - exit(0); + break; case '1': case 'help': HelpMenu::start(self::$args); - exit(0); + break; } } catch(Exception $e) @@ -145,6 +150,7 @@ exit(1); } + exit(0); } } diff --git a/src/ncc/CLI/Management/PackageManagerMenu.php b/src/ncc/CLI/Management/PackageManagerMenu.php index c8b0982..2b4ebab 100644 --- a/src/ncc/CLI/Management/PackageManagerMenu.php +++ b/src/ncc/CLI/Management/PackageManagerMenu.php @@ -256,6 +256,7 @@ $package_version = $package_manager->getPackageVersion($package, $version); if($package_version == null) continue; + Console::out(sprintf('%s=%s (%s)', Console::formatColor($package, ConsoleColors::LightGreen), Console::formatColor($version, ConsoleColors::LightMagenta), @@ -265,9 +266,10 @@ catch(Exception $e) { unset($e); - Console::out(sprintf('%s=%s', + Console::out(sprintf('%s=%s (%s)', Console::formatColor($package, ConsoleColors::LightGreen), - Console::formatColor($version, ConsoleColors::LightMagenta) + Console::formatColor($version, ConsoleColors::LightMagenta), + Console::formatColor('N/A', ConsoleColors::LightRed) )); } } diff --git a/src/ncc/CLI/Management/ProjectMenu.php b/src/ncc/CLI/Management/ProjectMenu.php index 233ceb2..1eab0bf 100644 --- a/src/ncc/CLI/Management/ProjectMenu.php +++ b/src/ncc/CLI/Management/ProjectMenu.php @@ -64,6 +64,7 @@ else { Console::outError('The selected source directory \'' . $full_path . '\' was not found or is not a directory', true, 1); + return; } } else diff --git a/src/ncc/Classes/BashExtension/BashRunner.php b/src/ncc/Classes/BashExtension/BashRunner.php index 6a8e953..f9aaf5d 100644 --- a/src/ncc/Classes/BashExtension/BashRunner.php +++ b/src/ncc/Classes/BashExtension/BashRunner.php @@ -26,7 +26,7 @@ throw new FileNotFoundException($path); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -38,16 +38,4 @@ { return '.bash'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $bash_bin = PathFinder::findRunner(Runners::bash); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$bash_bin, '-c', $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$bash_bin, '-c', $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/ComposerExtension/ComposerSourceBuiltin.php b/src/ncc/Classes/ComposerExtension/ComposerSourceBuiltin.php index 55da655..79583e1 100644 --- a/src/ncc/Classes/ComposerExtension/ComposerSourceBuiltin.php +++ b/src/ncc/Classes/ComposerExtension/ComposerSourceBuiltin.php @@ -479,7 +479,8 @@ self::prepareProcess($process, $tmp_dir, $options); Console::outDebug(sprintf('executing %s', $process->getCommandLine())); - $process->run(function ($type, $buffer) { + $process->run(function ($type, $buffer) + { Console::out($buffer, false); }); diff --git a/src/ncc/Classes/LuaExtension/LuaRunner.php b/src/ncc/Classes/LuaExtension/LuaRunner.php index fba88c4..fa15e75 100644 --- a/src/ncc/Classes/LuaExtension/LuaRunner.php +++ b/src/ncc/Classes/LuaExtension/LuaRunner.php @@ -23,7 +23,7 @@ $execution_unit = new ExecutionUnit(); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -35,16 +35,4 @@ { return '.lua'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $lua_bin = PathFinder::findRunner(Runners::lua); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$lua_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$lua_bin, $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/NccExtension/PackageCompiler.php b/src/ncc/Classes/NccExtension/PackageCompiler.php index bc90f78..c9de1a0 100644 --- a/src/ncc/Classes/NccExtension/PackageCompiler.php +++ b/src/ncc/Classes/NccExtension/PackageCompiler.php @@ -157,6 +157,8 @@ /** @var ProjectConfiguration\ExecutionPolicy $policy */ foreach($configuration->ExecutionPolicies as $policy) { + Console::outVerbose(sprintf('Compiling Execution Policy %s', $policy->Name)); + if($total_items > 5) { Console::inlineProgressBar($processed_items, $total_items); @@ -245,7 +247,7 @@ $units = []; foreach($package->ExecutionUnits as $executionUnit) { - Console::outDebug(sprintf('compiling execution unit consts %s (%s)', $executionUnit->Name, implode(', ', array_keys($refs)))); + Console::outDebug(sprintf('compiling execution unit consts %s (%s)', $executionUnit->ExecutionPolicy->Name, implode(', ', array_keys($refs)))); $units[] = self::compileExecutionUnitConstants($executionUnit, $refs); } $package->ExecutionUnits = $units; diff --git a/src/ncc/Classes/PerlExtension/PerlRunner.php b/src/ncc/Classes/PerlExtension/PerlRunner.php index 0be4cdb..325badc 100644 --- a/src/ncc/Classes/PerlExtension/PerlRunner.php +++ b/src/ncc/Classes/PerlExtension/PerlRunner.php @@ -26,7 +26,7 @@ if(!file_exists($path) && !is_file($path)) throw new FileNotFoundException($path); $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -38,16 +38,4 @@ { return '.pl'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $perl_bin = PathFinder::findRunner(Runners::perl); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$perl_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$perl_bin, $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/PhpExtension/PhpCompiler.php b/src/ncc/Classes/PhpExtension/PhpCompiler.php index f9a74e9..a422f84 100644 --- a/src/ncc/Classes/PhpExtension/PhpCompiler.php +++ b/src/ncc/Classes/PhpExtension/PhpCompiler.php @@ -92,14 +92,14 @@ $this->package->MainExecutionPolicy = $this->project->Build->Main; // Add the option to create a symbolic link to the package - if($this->project->Build->CreateSymlink) + if(isset($this->project->Project->Options['create_symlink']) && $this->project->Project->Options['create_symlink'] === True) $this->package->Header->Options['create_symlink'] = true; // Add both the defined constants from the build configuration and the global constants. // Global constants are overridden $this->package->Header->RuntimeConstants = []; $this->package->Header->RuntimeConstants = array_merge( - ($selected_build_configuration?->DefineConstants ?? []), + ($selected_build_configuration->DefineConstants ?? []), ($this->project->Build->DefineConstants ?? []), ($this->package->Header->RuntimeConstants ?? []) ); @@ -108,6 +108,10 @@ $this->package->Header->CompilerVersion = NCC_VERSION_NUMBER; $this->package->Header->Options = $this->project->Project->Options; + if($this->project->Project->UpdateSource !== null) + { + $this->package->Header->UpdateSource = $this->project->Project->UpdateSource; + } Console::outDebug('scanning project files'); Console::outDebug('theseer\DirectoryScanner - Copyright (c) 2009-2014 Arne Blankerts All rights reserved.'); @@ -161,8 +165,8 @@ } // Clear previous excludes and includes - $DirectoryScanner->setExcludes([]); - $DirectoryScanner->setIncludes([]); + $DirectoryScanner->setExcludes(); + $DirectoryScanner->setIncludes(); // Ignore component files if($selected_build_configuration->ExcludeFiles !== null && count($selected_build_configuration->ExcludeFiles) > 0) @@ -423,7 +427,7 @@ */ public function compileExecutionPolicies(): void { - PackageCompiler::compileExecutionPolicies($this->path, $this->project); + $this->package->ExecutionUnits = PackageCompiler::compileExecutionPolicies($this->path, $this->project); } /** diff --git a/src/ncc/Classes/PhpExtension/PhpRunner.php b/src/ncc/Classes/PhpExtension/PhpRunner.php index 6792057..962ae44 100644 --- a/src/ncc/Classes/PhpExtension/PhpRunner.php +++ b/src/ncc/Classes/PhpExtension/PhpRunner.php @@ -33,7 +33,7 @@ throw new FileNotFoundException($path); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -47,18 +47,4 @@ { return '.php'; } - - /** - * @param ExecutionPointer $pointer - * @return Process - * @throws RunnerExecutionException - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $php_bin = PathFinder::findRunner(Runners::php); - - 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]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/PythonExtension/Python2Runner.php b/src/ncc/Classes/PythonExtension/Python2Runner.php index 0f8ca05..ddbaa0f 100644 --- a/src/ncc/Classes/PythonExtension/Python2Runner.php +++ b/src/ncc/Classes/PythonExtension/Python2Runner.php @@ -26,7 +26,7 @@ throw new FileNotFoundException($path); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -38,16 +38,4 @@ { return '.py'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $python_bin = PathFinder::findRunner(Runners::python2); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$python_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$python_bin, $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/PythonExtension/Python3Runner.php b/src/ncc/Classes/PythonExtension/Python3Runner.php index 94b5447..a610d21 100644 --- a/src/ncc/Classes/PythonExtension/Python3Runner.php +++ b/src/ncc/Classes/PythonExtension/Python3Runner.php @@ -26,7 +26,7 @@ throw new FileNotFoundException($path); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -38,16 +38,4 @@ { return '.py'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $python_bin = PathFinder::findRunner(Runners::python3); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$python_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$python_bin, $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Classes/PythonExtension/PythonRunner.php b/src/ncc/Classes/PythonExtension/PythonRunner.php index d3b2baa..ed40778 100644 --- a/src/ncc/Classes/PythonExtension/PythonRunner.php +++ b/src/ncc/Classes/PythonExtension/PythonRunner.php @@ -26,7 +26,7 @@ throw new FileNotFoundException($path); $policy->Execute->Target = null; $execution_unit->ExecutionPolicy = $policy; - $execution_unit->Data = Base64::encode(IO::fread($path)); + $execution_unit->Data = IO::fread($path); return $execution_unit; } @@ -38,16 +38,4 @@ { return '.py'; } - - /** - * @inheritDoc - */ - public static function prepareProcess(ExecutionPointer $pointer): Process - { - $python_bin = PathFinder::findRunner(Runners::python); - - if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0) - return new Process(array_merge([$python_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options)); - return new Process([$python_bin, $pointer->FilePointer]); - } } \ No newline at end of file diff --git a/src/ncc/Interfaces/RunnerInterface.php b/src/ncc/Interfaces/RunnerInterface.php index 1d92644..bd0c73f 100644 --- a/src/ncc/Interfaces/RunnerInterface.php +++ b/src/ncc/Interfaces/RunnerInterface.php @@ -32,12 +32,4 @@ */ 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; } \ No newline at end of file diff --git a/src/ncc/Managers/ExecutionPointerManager.php b/src/ncc/Managers/ExecutionPointerManager.php index 9b89551..f522625 100644 --- a/src/ncc/Managers/ExecutionPointerManager.php +++ b/src/ncc/Managers/ExecutionPointerManager.php @@ -9,6 +9,7 @@ use ncc\Abstracts\Scopes; use ncc\Classes\BashExtension\BashRunner; use ncc\Classes\LuaExtension\LuaRunner; + use ncc\Classes\NccExtension\ConstantCompiler; use ncc\Classes\PerlExtension\PerlRunner; use ncc\Classes\PhpExtension\PhpRunner; use ncc\Classes\PythonExtension\Python2Runner; @@ -109,6 +110,7 @@ */ private function getPackageId(string $package, string $version): string { + Console::outDebug(sprintf('calculating package id for %s=%s', $package, $version)); return hash('haval128,4', $package . $version); } @@ -263,8 +265,14 @@ $package_id = $this->getPackageId($package, $version); $package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx'; + Console::outDebug(sprintf('package_id=%s', $package_id)); + Console::outDebug(sprintf('package_config_path=%s', $package_config_path)); + if(!file_exists($package_config_path)) + { + Console::outWarning(sprintf('Path \'%s\' does not exist', $package_config_path)); return []; + } $execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path))); $results = []; @@ -277,20 +285,40 @@ return $results; } - public function getUnit(string $package, string $version, string $name): ExecutionUnit + /** + * Returns an existing ExecutionUnit for a package version + * + * @param string $package + * @param string $version + * @param string $name + * @return ExecutionPointers\ExecutionPointer + * @throws AccessDeniedException + * @throws FileNotFoundException + * @throws IOException + */ + public function getUnit(string $package, string $version, string $name): ExecutionPointers\ExecutionPointer { - Console::outVerbose(sprintf('getting execution unit %s for %s', $name, $package)); + /** @noinspection DuplicatedCode */ + if(Resolver::resolveScope() !== Scopes::System) + throw new AccessDeniedException('Cannot remove ExecutionUnit \'' . $name .'\' for ' . $package . ', insufficient permissions'); + + Console::outVerbose(sprintf('Removing ExecutionUnit \'%s\' for %s', $name, $package)); $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; - if(!file_exists($package_config_path)) - throw new NoAvailableUnitsException('No ExecutionUnits available for ' . $package); + Console::outDebug(sprintf('package_id=%s', $package_id)); + Console::outDebug(sprintf('package_config_path=%s', $package_config_path)); + Console::outDebug(sprintf('package_bin_path=%s', $package_bin_path)); + $filesystem = new Filesystem(); + if(!$filesystem->exists($package_config_path)) + { + throw new FileNotFoundException(sprintf('Path \'%s\' does not exist', $package_config_path)); + } $execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path))); - $unit = $execution_pointers->getUnit($name); - - + return $execution_pointers->getUnit($name); } /** @@ -299,16 +327,17 @@ * @param string $package * @param string $version * @param string $name - * @return void + * @param array $args + * @return int * @throws AccessDeniedException * @throws ExecutionUnitNotFoundException * @throws FileNotFoundException * @throws IOException * @throws NoAvailableUnitsException - * @throws UnsupportedRunnerException * @throws RunnerExecutionException + * @throws UnsupportedRunnerException */ - public function executeUnit(string $package, string $version, string $name): void + public function executeUnit(string $package, string $version, string $name, array $args=[]): int { Console::outVerbose(sprintf('executing unit %s for %s', $name, $package)); @@ -327,23 +356,33 @@ Console::outDebug(sprintf('unit=%s', $unit->ExecutionPolicy->Name)); Console::outDebug(sprintf('runner=%s', $unit->ExecutionPolicy->Runner)); Console::outDebug(sprintf('file=%s', $unit->FilePointer)); + Console::outDebug(sprintf('pass_thru_args=%s', json_encode($args, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE))); - $process = match (strtolower($unit->ExecutionPolicy->Runner)) + // Handle the arguments + if($unit->ExecutionPolicy->Execute->Options !== null && count($unit->ExecutionPolicy->Execute->Options) > 0) { - Runners::bash => BashRunner::prepareProcess($unit), - Runners::php => PhpRunner::prepareProcess($unit), - Runners::perl => PerlRunner::prepareProcess($unit), - Runners::python => PythonRunner::prepareProcess($unit), - Runners::python2 => Python2Runner::prepareProcess($unit), - Runners::python3 => Python3Runner::prepareProcess($unit), - Runners::lua => LuaRunner::prepareProcess($unit), - default => throw new UnsupportedRunnerException('The runner \'' . $unit->ExecutionPolicy->Runner . '\' is not supported'), - }; + $args = array_merge($args, $unit->ExecutionPolicy->Execute->Options); + + foreach($unit->ExecutionPolicy->Execute->Options as $option) + { + $args[] = ConstantCompiler::compileRuntimeConstants($option); + } + } + + $process = new Process(array_merge([ + PathFinder::findRunner(strtolower($unit->ExecutionPolicy->Runner)), + $unit->FilePointer + ], $args)); if($unit->ExecutionPolicy->Execute->WorkingDirectory !== null) - $process->setWorkingDirectory($unit->ExecutionPolicy->Execute->WorkingDirectory); + { + $process->setWorkingDirectory(ConstantCompiler::compileRuntimeConstants($unit->ExecutionPolicy->Execute->WorkingDirectory)); + } + if($unit->ExecutionPolicy->Execute->Timeout !== null) + { $process->setTimeout((float)$unit->ExecutionPolicy->Execute->Timeout); + } if($unit->ExecutionPolicy->Execute->Silent) { @@ -364,6 +403,8 @@ Console::outDebug(sprintf('timeout=%s', ($process->getTimeout() ?? 0))); Console::outDebug(sprintf('silent=%s', ($unit->ExecutionPolicy->Execute->Silent ? 'true' : 'false'))); Console::outDebug(sprintf('tty=%s', ($unit->ExecutionPolicy->Execute->Tty ? 'true' : 'false'))); + Console::outDebug(sprintf('options=%s', implode(' ', $args))); + Console::outDebug(sprintf('cmd=%s', $process->getCommandLine())); try { @@ -402,6 +443,8 @@ $this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error, $process); } } + + return $process->getExitCode(); } /** diff --git a/src/ncc/Managers/PackageManager.php b/src/ncc/Managers/PackageManager.php index 3b4e6cc..86c4eca 100644 --- a/src/ncc/Managers/PackageManager.php +++ b/src/ncc/Managers/PackageManager.php @@ -309,13 +309,15 @@ } // Install execution units - if(count($package->ExecutionUnits) > 0) + if($package->ExecutionUnits !== null && count($package->ExecutionUnits) > 0) { $execution_pointer_manager = new ExecutionPointerManager(); $unit_paths = []; + /** @var Package\ExecutionUnit $executionUnit */ foreach($package->ExecutionUnits as $executionUnit) { + Console::outDebug(sprintf('processing execution unit %s', $executionUnit->ExecutionPolicy->Name)); $execution_pointer_manager->addUnit($package->Assembly->Package, $package->Assembly->Version, $executionUnit); $current_steps += 1; Console::inlineProgressBar($current_steps, $steps); @@ -751,14 +753,21 @@ try { $version_entry = $this->getPackageVersion($package_e[0], $package_e[1]); - $tree[$package] = null; - if($version_entry->Dependencies !== null && count($version_entry->Dependencies) > 0) + if($version_entry == null) { - $tree[$package] = []; - foreach($version_entry->Dependencies as $dependency) + Console::outWarning('Version ' . $package_e[1] . ' of package ' . $package_e[0] . ' not found'); + } + else + { + $tree[$package] = null; + if($version_entry->Dependencies !== null && count($version_entry->Dependencies) > 0) { - $dependency_name = sprintf('%s=%s', $dependency->PackageName, $dependency->Version); - $tree[$package] = $this->getPackageTree($tree[$package], $dependency_name); + $tree[$package] = []; + foreach($version_entry->Dependencies as $dependency) + { + $dependency_name = sprintf('%s=%s', $dependency->PackageName, $dependency->Version); + $tree[$package] = $this->getPackageTree($tree[$package], $dependency_name); + } } } } diff --git a/src/ncc/Managers/RemoteSourcesManager.php b/src/ncc/Managers/RemoteSourcesManager.php index 95f156b..f1e3df1 100644 --- a/src/ncc/Managers/RemoteSourcesManager.php +++ b/src/ncc/Managers/RemoteSourcesManager.php @@ -37,7 +37,7 @@ public function __construct() { /** @noinspection PhpUnhandledExceptionInspection */ - $this->DefinedSourcesPath = PathFinder::getRemouteSources(Scopes::System); + $this->DefinedSourcesPath = PathFinder::getRemoteSources(Scopes::System); $this->load(); } diff --git a/src/ncc/Objects/ExecutionPointers.php b/src/ncc/Objects/ExecutionPointers.php index 9181c03..ceedb5b 100644 --- a/src/ncc/Objects/ExecutionPointers.php +++ b/src/ncc/Objects/ExecutionPointers.php @@ -7,6 +7,7 @@ use ncc\Exceptions\FileNotFoundException; use ncc\Objects\ExecutionPointers\ExecutionPointer; use ncc\Objects\Package\ExecutionUnit; + use ncc\Utilities\Functions; use ncc\Utilities\Validate; class ExecutionPointers @@ -41,8 +42,10 @@ * Adds an Execution Unit as a pointer * * @param ExecutionUnit $unit + * @param string $bin_file * @param bool $overwrite * @return bool + * @throws FileNotFoundException */ public function addUnit(ExecutionUnit $unit, string $bin_file, bool $overwrite=true): bool { @@ -96,6 +99,7 @@ */ public function getUnit(string $name): ?ExecutionPointer { + /** @var ExecutionPointer $pointer */ foreach($this->Pointers as $pointer) { if($pointer->ExecutionPolicy->Name == $name) @@ -148,7 +152,11 @@ { $pointers[] = $pointer->toArray($bytecode); } - return $pointers; + return [ + ($bytecode ? Functions::cbc('package') : 'package') => $this->Package, + ($bytecode ? Functions::cbc('version') : 'version') => $this->Version, + ($bytecode ? Functions::cbc('pointers') : 'pointers') => $pointers + ]; } /** @@ -161,9 +169,18 @@ { $object = new self(); - foreach($data as $datum) + $object->Version = Functions::array_bc($data, 'version'); + $object->Package = Functions::array_bc($data, 'package'); + $object->Pointers = Functions::array_bc($data, 'pointers'); + + if($object->Pointers !== null) { - $object->Pointers[] = ExecutionPointer::fromArray($datum); + $pointers = []; + foreach($object->Pointers as $pointer) + { + $pointers[] = ExecutionPointer::fromArray($pointer); + } + $object->Pointers = $pointers; } return $object; diff --git a/src/ncc/Objects/ExecutionPointers/ExecutionPointer.php b/src/ncc/Objects/ExecutionPointers/ExecutionPointer.php index 9a5747e..4328640 100644 --- a/src/ncc/Objects/ExecutionPointers/ExecutionPointer.php +++ b/src/ncc/Objects/ExecutionPointers/ExecutionPointer.php @@ -33,6 +33,7 @@ * Public Constructor with optional ExecutionUnit parameter to construct object from * * @param ExecutionUnit|null $unit + * @param string|null $bin_file */ public function __construct(?ExecutionUnit $unit=null, ?string $bin_file=null) { @@ -73,6 +74,9 @@ $object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy'); $object->FilePointer = Functions::array_bc($data, 'file_pointer'); + if($object->ExecutionPolicy !== null) + $object->ExecutionPolicy = ExecutionPolicy::fromArray($object->ExecutionPolicy); + return $object; } } \ No newline at end of file diff --git a/src/ncc/Objects/Package/ExecutionUnit.php b/src/ncc/Objects/Package/ExecutionUnit.php index 75940cc..fd02648 100644 --- a/src/ncc/Objects/Package/ExecutionUnit.php +++ b/src/ncc/Objects/Package/ExecutionUnit.php @@ -55,6 +55,9 @@ $object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy'); $object->Data = Functions::array_bc($data, 'data'); + if($object->ExecutionPolicy !== null) + $object->ExecutionPolicy = ExecutionPolicy::fromArray($object->ExecutionPolicy); + return $object; } diff --git a/src/ncc/Objects/PackageLock/PackageEntry.php b/src/ncc/Objects/PackageLock/PackageEntry.php index 2c58990..3a301e5 100644 --- a/src/ncc/Objects/PackageLock/PackageEntry.php +++ b/src/ncc/Objects/PackageLock/PackageEntry.php @@ -5,6 +5,7 @@ namespace ncc\Objects\PackageLock; use ncc\Abstracts\Scopes; + use ncc\Abstracts\Versions; use ncc\Exceptions\InvalidPackageNameException; use ncc\Exceptions\InvalidScopeException; use ncc\Exceptions\VersionNotFoundException; @@ -64,6 +65,9 @@ */ public function getVersion(string $version, bool $throw_exception=false): ?VersionEntry { + if($version == Versions::Latest) + $version = $this->LatestVersion; + foreach($this->Versions as $versionEntry) { if($versionEntry->Version == $version) @@ -142,6 +146,9 @@ $version->MainExecutionPolicy = $package->MainExecutionPolicy; $version->Location = $install_path; + foreach($version->ExecutionUnits as $unit) + $unit->Data = null; + foreach($package->Dependencies as $dependency) { $version->Dependencies[] = new DependencyEntry($dependency); diff --git a/src/ncc/Objects/ProjectConfiguration.php b/src/ncc/Objects/ProjectConfiguration.php index 216091f..4d49f68 100644 --- a/src/ncc/Objects/ProjectConfiguration.php +++ b/src/ncc/Objects/ProjectConfiguration.php @@ -9,6 +9,7 @@ use ncc\Exceptions\AccessDeniedException; use ncc\Exceptions\BuildConfigurationNotFoundException; use ncc\Exceptions\FileNotFoundException; + use ncc\Exceptions\InvalidBuildConfigurationException; use ncc\Exceptions\InvalidConstantNameException; use ncc\Exceptions\InvalidProjectBuildConfiguration; use ncc\Exceptions\InvalidProjectConfigurationException; @@ -93,6 +94,7 @@ * @throws UndefinedExecutionPolicyException * @throws UnsupportedCompilerExtensionException * @throws UnsupportedExtensionVersionException + * @throws InvalidBuildConfigurationException */ public function validate(bool $throw_exception=True): bool { @@ -116,6 +118,41 @@ return false; } + if($this->Build->Main !== null) + { + if($this->ExecutionPolicies == null || count($this->ExecutionPolicies) == 0) + { + if($throw_exception) + throw new UndefinedExecutionPolicyException(sprintf('Build configuration build.main uses an execution policy "%s" but no policies are defined', $this->Build->Main)); + return false; + } + + + $found = false; + foreach($this->ExecutionPolicies as $policy) + { + if($policy->Name == $this->Build->Main) + { + $found = true; + break; + } + } + + if(!$found) + { + if($throw_exception) + throw new UndefinedExecutionPolicyException(sprintf('Build configuration build.main points to a undefined execution policy "%s"', $this->Build->Main)); + return false; + } + + if($this->Build->Main == BuildConfigurationValues::AllConfigurations) + { + if($throw_exception) + throw new InvalidBuildConfigurationException(sprintf('Build configuration build.main cannot be set to "%s"', BuildConfigurationValues::AllConfigurations)); + return false; + } + } + return true; } diff --git a/src/ncc/Objects/ProjectConfiguration/Build.php b/src/ncc/Objects/ProjectConfiguration/Build.php index 6f095f3..cbb3cd7 100644 --- a/src/ncc/Objects/ProjectConfiguration/Build.php +++ b/src/ncc/Objects/ProjectConfiguration/Build.php @@ -61,14 +61,6 @@ */ public $Main; - /** - * If Main is not null, and this is true. - * NCC Will create a symlink to the main executable in the installation directory. - * - * @var bool - */ - public $CreateSymlink; - /** * An array of constants to define by default * @@ -114,7 +106,6 @@ $this->DefineConstants = []; $this->Dependencies = []; $this->Configurations = []; - $this->CreateSymlink = false; } /** @@ -286,10 +277,7 @@ if($this->Scope !== null) $ReturnResults[($bytecode ? Functions::cbc('scope') : 'scope')] = $this->Scope; if($this->Main !== null) - { $ReturnResults[($bytecode ? Functions::cbc('main') : 'main')] = $this->Main; - $ReturnResults[($bytecode ? Functions::cbc('create_symlink') : 'create_symlink')] = $this->CreateSymlink; - } if($this->DefineConstants !== null && count($this->DefineConstants) > 0) $ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants; if($this->PreBuild !== null && count($this->PreBuild) > 0) @@ -334,7 +322,6 @@ $BuildObject->Options = (Functions::array_bc($data, 'options') ?? []); $BuildObject->Scope = Functions::array_bc($data, 'scope'); $BuildObject->Main = Functions::array_bc($data, 'main'); - $BuildObject->CreateSymlink = (Functions::array_bc($data, 'create_symlink') ?? false); $BuildObject->DefineConstants = (Functions::array_bc($data, 'define_constants') ?? []); $BuildObject->PreBuild = (Functions::array_bc($data, 'pre_build') ?? []); $BuildObject->PostBuild = (Functions::array_bc($data, 'post_build') ?? []); diff --git a/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php b/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php index be98067..7a2f488 100644 --- a/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php +++ b/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php @@ -94,7 +94,7 @@ $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->Execute = Functions::array_bc($data, 'execute'); $object->ExitHandlers = Functions::array_bc($data, 'exit_handlers'); if($object->Execute !== null) diff --git a/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php b/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php index b9184e6..0edf196 100644 --- a/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php +++ b/src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php @@ -24,9 +24,9 @@ public $WorkingDirectory; /** - * An array of options to pass on to the process + * Options to pass to the process * - * @var array|null + * @var array */ public $Options; @@ -51,13 +51,6 @@ */ public $Tty; - /** - * Indicates if the process should run in Pty mode (Overrides Silent mode) - * - * @var bool|null - */ - public $Pty; - /** * The number of seconds to wait before giving up on the process, will automatically execute the error handler * if one is set. diff --git a/src/ncc/Utilities/PathFinder.php b/src/ncc/Utilities/PathFinder.php index 8093f7d..a2ea82e 100644 --- a/src/ncc/Utilities/PathFinder.php +++ b/src/ncc/Utilities/PathFinder.php @@ -184,6 +184,17 @@ return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'sources'; } + /** + * @param string $scope + * @param bool $win32 + * @return string + * @throws InvalidScopeException + */ + public static function getSymlinkDictionary(string $scope=Scopes::Auto, bool $win32=false): string + { + return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'symlinks'; + } + /** * Returns an array of all the package lock files the current user can access (For global-cross referencing) *