diff --git a/src/ncc/Classes/NccExtension/NccCompiler.php b/src/ncc/Classes/NccExtension/NccCompiler.php index 176547a..c529d03 100644 --- a/src/ncc/Classes/NccExtension/NccCompiler.php +++ b/src/ncc/Classes/NccExtension/NccCompiler.php @@ -317,7 +317,8 @@ { $metadata = new Metadata($this->project_manager->getProjectConfiguration()->getProject()->getCompiler()); - $metadata->setOptions($this->project_manager->getProjectConfiguration()->getBuild()->getOptions($build_configuration)); + $metadata->addOptions($this->project_manager->getProjectConfiguration()->getBuild()->getOptions($build_configuration)); + $metadata->addOptions($this->project_manager->getProjectConfiguration()->getProject()->getOptions()); $metadata->setUpdateSource($this->project_manager->getProjectConfiguration()->getProject()->getUpdateSource()); $metadata->setMainExecutionPolicy($this->project_manager->getProjectConfiguration()->getBuild()->getMain()); $metadata->setInstaller($this->project_manager->getProjectConfiguration()->getInstaller()); diff --git a/src/ncc/Managers/PackageManager.php b/src/ncc/Managers/PackageManager.php index b32acaa..b5a50dc 100644 --- a/src/ncc/Managers/PackageManager.php +++ b/src/ncc/Managers/PackageManager.php @@ -38,6 +38,7 @@ use ncc\Enums\Options\ComponentDecodeOptions; use ncc\Enums\Options\InitializeProjectOptions; use ncc\Enums\Options\InstallPackageOptions; + use ncc\Enums\Options\ProjectOptions; use ncc\Enums\RegexPatterns; use ncc\Enums\Scopes; use ncc\Enums\Types\ProjectType; @@ -54,6 +55,7 @@ use ncc\Objects\RemotePackageInput; use ncc\ThirdParty\Symfony\Filesystem\Filesystem; use ncc\Utilities\Console; + use ncc\Utilities\Functions; use ncc\Utilities\IO; use ncc\Utilities\PathFinder; use ncc\Utilities\Resolver; @@ -374,6 +376,56 @@ throw new IOException(sprintf('Failed to add package to package lock file due to an exception: %s', $e->getMessage()), $e); } + if($package_reader->getMetadata()->getOption(ProjectOptions::CREATE_SYMLINK) === null) + { + // Remove the symlink if it exists + if($this->package_lock->getEntry($package_reader->getAssembly()->getPackage())->isSymlinkRegistered()) + { + if(is_file(PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_reader->getAssembly()->getName()))) + { + Console::outVerbose(sprintf( + 'Removing symlink for %s=%s at %s', + $package_reader->getAssembly()->getPackage(), $package_reader->getAssembly()->getVersion(), + PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_reader->getAssembly()->getName()) + )); + $filesystem->remove(PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_reader->getAssembly()->getName())); + } + } + + $this->package_lock->getEntry($package_reader->getAssembly()->getPackage())->setSymlinkRegistered(false); + } + else + { + // Register/Update the symlink + $symlink = PathFinder::findBinPath() . DIRECTORY_SEPARATOR . strtolower($package_reader->getAssembly()->getName()); + + if(is_file($symlink) && !$this->package_lock->getEntry($package_reader->getAssembly()->getPackage())->isSymlinkRegistered()) + { + // Avoid overwriting already existing symlinks that are not handled by ncc + Console::outWarning(sprintf( + 'A symlink already exists at %s, skipping symlink creation for %s=%s', + $symlink, $package_reader->getAssembly()->getPackage(), $package_reader->getAssembly()->getVersion() + )); + } + else + { + Console::outVerbose(sprintf( + 'Creating symlink for %s=%s at %s', + $package_reader->getAssembly()->getPackage(), $package_reader->getAssembly()->getVersion(), $symlink + )); + + if(is_file($symlink)) + { + $filesystem->remove($symlink); + } + + IO::fwrite($symlink, Functions::createExecutionPointer($package_reader->getAssembly()->getPackage(), $package_reader->getAssembly()->getVersion())); + chmod($symlink, 0755); // Make it executable + + $this->package_lock->getEntry($package_reader->getAssembly()->getPackage())->setSymlinkRegistered(true); + } + } + $this->saveLock(); if(!isset($options[InstallPackageOptions::SKIP_DEPENDENCIES])) diff --git a/src/ncc/Objects/Package/Metadata.php b/src/ncc/Objects/Package/Metadata.php index 3b29015..1d75e34 100644 --- a/src/ncc/Objects/Package/Metadata.php +++ b/src/ncc/Objects/Package/Metadata.php @@ -45,7 +45,7 @@ private $compiler_version; /** - * @var array|null + * @var array */ private $options; @@ -120,9 +120,9 @@ /** * Returns an array of options associated with the package * - * @return array|null + * @return array */ - public function getOptions(): ?array + public function getOptions(): array { return $this->options; } @@ -130,13 +130,29 @@ /** * Sets an array of options associated with the package * - * @param array|null $options + * @param array $options */ - public function setOptions(?array $options): void + public function setOptions(array $options): void { $this->options = $options; } + /** + * Adds an option associated with the package + * + * @param array $options + * @return void + */ + public function addOptions(array $options): void + { + if($this->options === null) + { + $this->options = []; + } + + $this->options = array_merge($this->options, $options); + } + /** * Sets an option associated with the package * diff --git a/src/ncc/Objects/PackageLock/PackageEntry.php b/src/ncc/Objects/PackageLock/PackageEntry.php index 24fa37f..4dd321a 100644 --- a/src/ncc/Objects/PackageLock/PackageEntry.php +++ b/src/ncc/Objects/PackageLock/PackageEntry.php @@ -61,6 +61,11 @@ */ private $update_source; + /** + * @var bool + */ + private $symlink_registered; + /** * Public Constructor */ @@ -68,6 +73,7 @@ { $this->name = $name; $this->versions = $versions; + $this->symlink_registered = false; } /** @@ -90,6 +96,22 @@ return $this->update_source; } + /** + * @return bool + */ + public function isSymlinkRegistered(): bool + { + return $this->symlink_registered; + } + + /** + * @param bool $symlink_registered + */ + public function setSymlinkRegistered(bool $symlink_registered): void + { + $this->symlink_registered = $symlink_registered; + } + /** * Returns the path to where the package is installed * @@ -456,6 +478,7 @@ ($bytecode ? Functions::cbc('name') : 'name') => $this->name, ($bytecode ? Functions::cbc('versions') : 'versions') => $versions, ($bytecode ? Functions::cbc('update_source') : 'update_source') => ($this->update_source?->toArray($bytecode)), + ($bytecode ? Functions::cbc('symlink_registered') : 'symlink_registered') => $this->symlink_registered, ]; } @@ -490,6 +513,7 @@ $object->update_source = UpdateSource::fromArray($update_source); } + $object->symlink_registered = Functions::array_bc($data, 'symlink_registered') ?? false; return $object; } diff --git a/src/ncc/Utilities/Functions.php b/src/ncc/Utilities/Functions.php index 21767e3..a4ba99d 100644 --- a/src/ncc/Utilities/Functions.php +++ b/src/ncc/Utilities/Functions.php @@ -26,6 +26,7 @@ use FilesystemIterator; use JsonException; use ncc\Enums\Scopes; + use ncc\Enums\Versions; use ncc\Exceptions\IOException; use ncc\Exceptions\OperationException; use ncc\Exceptions\PathNotFoundException; @@ -627,4 +628,19 @@ $input = str_replace('.', '_', $input); return strtolower(trim(preg_replace('/[^a-zA-Z0-9_]/', '', preg_replace('/([a-z])([A-Z])/', '$1_$2', $input)), '_')); } + + /** + * Returns a shell script that can be used to execute the given package + * + * @param string $package_name + * @param string $version + * @return string + */ + public static function createExecutionPointer(string $package_name, string $version=Versions::LATEST): string + { + $content = "#!/bin/sh\n"; + $content .= sprintf('exec ncc exec --package "%s" --exec-version "%s" --exec-args "$@"', $package_name, $version); + + return $content; + } } \ No newline at end of file diff --git a/src/ncc/Utilities/PathFinder.php b/src/ncc/Utilities/PathFinder.php index 1817e42..0548204 100644 --- a/src/ncc/Utilities/PathFinder.php +++ b/src/ncc/Utilities/PathFinder.php @@ -22,6 +22,8 @@ namespace ncc\Utilities; + use RuntimeException; + class PathFinder { /** @@ -103,4 +105,33 @@ { return self::getDataPath() . DIRECTORY_SEPARATOR . 'ncc.yaml'; } + + /** + * Returns the path where binaries are stored + * + * @return string + */ + public static function findBinPath(): string + { + $path_directories = explode(PATH_SEPARATOR, getenv('PATH')); + + // Check if the bin directory is in the path + if(in_array(DIRECTORY_SEPARATOR . 'usr' . DIRECTORY_SEPARATOR . 'bin', $path_directories)) + { + return DIRECTORY_SEPARATOR . 'usr' . DIRECTORY_SEPARATOR . 'bin'; + } + + Console::outWarning('The /usr/bin directory is not in the PATH environment variable, an alternative will be used'); + + // If not, find something appropriate + foreach($path_directories as $path_directory) + { + if(is_dir($path_directory) && is_writable($path_directory)) + { + return $path_directory; + } + } + + throw new RuntimeException('Could not find a suitable bin directory in the PATH environment variable'); + } } \ No newline at end of file diff --git a/tests/projects/lib/src/TestLib/test.php b/tests/projects/lib/src/TestLib/test.php deleted file mode 100644 index 1dc36db..0000000 --- a/tests/projects/lib/src/TestLib/test.php +++ /dev/null @@ -1,5 +0,0 @@ -