diff --git a/.idea/php.xml b/.idea/php.xml index b37795f..71b8d6f 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -12,7 +12,7 @@ - + diff --git a/src/ncc/CLI/Commands/BuildCommand.php b/src/ncc/CLI/Commands/BuildCommand.php index f7d9384..f2bff4f 100644 --- a/src/ncc/CLI/Commands/BuildCommand.php +++ b/src/ncc/CLI/Commands/BuildCommand.php @@ -78,7 +78,6 @@ $options[BuildConfigurationOptions::OUTPUT_FILE] = $output_path; } - // Load the project try { diff --git a/src/ncc/Classes/NccExtension/NccCompiler.php b/src/ncc/Classes/NccExtension/NccCompiler.php index 84047af..e2e83e1 100644 --- a/src/ncc/Classes/NccExtension/NccCompiler.php +++ b/src/ncc/Classes/NccExtension/NccCompiler.php @@ -25,6 +25,7 @@ namespace ncc\Classes\NccExtension; + use ncc\Classes\PackageReader; use ncc\Classes\PackageWriter; use ncc\CLI\Main; use ncc\Enums\Flags\PackageFlags; @@ -43,6 +44,7 @@ use ncc\Objects\Package\Metadata; use ncc\Objects\Package\Resource; use ncc\Objects\ProjectConfiguration\Build\BuildConfiguration; + use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Utilities\Base64; use ncc\Utilities\Console; use ncc\Utilities\Functions; @@ -88,25 +90,26 @@ { $configuration = $this->project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration); $configuration->setOptions(array_merge($configuration->getOptions(), $options)); + $static_dependencies = isset($configuration->getOptions()[BuildConfigurationOptions::STATIC_DEPENDENCIES]); if(count($options) > 0) { $configuration->setOptions(array_merge($configuration->getOptions(), $options)); } - if($configuration->getOutputName() !== null) + if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE])) + { + $package_path = ConstantCompiler::compileConstants( + $this->project_manager->getProjectConfiguration(), $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE] + ); + } + elseif($configuration->getOutputName() !== null) { $package_path = ConstantCompiler::compileConstants($this->project_manager->getProjectConfiguration(), $configuration->getOutputPath()) . DIRECTORY_SEPARATOR . ConstantCompiler::compileConstants($this->project_manager->getProjectConfiguration(), $configuration->getOutputName()); } - elseif(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE])) - { - $package_path = ConstantCompiler::compileConstants( - $this->project_manager->getProjectConfiguration(), $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE] - ); - } else { $package_path = @@ -120,11 +123,18 @@ count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) + count($this->project_manager->getComponents($build_configuration)) + count($this->project_manager->getResources($build_configuration)); + $package_writer = $this->createPackageWriter($package_path, $configuration); - Console::out(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName())); + if($static_dependencies) + { + // Add the static dependencies flag so that the package manager + // Won't try to resolve the dependencies from the system. + $package_writer->addFlag(PackageFlags::STATIC_DEPENDENCIES); + } + // Debugging information if(Resolver::checkLogLevel(LogLevel::DEBUG, Main::getLogLevel())) { @@ -193,31 +203,52 @@ $this->processResource($package_writer, $resource); } - $package_manager = new PackageManager(); - // Add the project dependencies foreach($this->project_manager->getProjectConfiguration()->getBuild()->getDependencies() as $dependency) { - if(isset($configuration->getOptions()[BuildConfigurationOptions::STATIC_DEPENDENCIES])) - { - $package_entry = $package_manager->getPackageLock()->getEntry($dependency->getName()); - $shadow_package = $package_entry->getShadowPackagePath($dependency->getVersion()); - // TODO: Add support for static dependencies - } - - $package_writer->addDependencyConfiguration($dependency); + $this->processDependency($package_writer, $dependency, $static_dependencies); } // Add the build dependencies foreach($configuration->getDependencies() as $dependency) { - $package_writer->addDependencyConfiguration($dependency); + $this->processDependency($package_writer, $dependency, $static_dependencies); } $package_writer->close(); return $package_path; } + /** + * Processes dependencies, optionally recursively + * + * @param PackageWriter $package_writer + * @param Dependency $dependency + * @param bool $static + * @return void + * @throws IOException + */ + private function processDependency(PackageWriter $package_writer, Dependency $dependency, bool $static=false): void + { + Console::outVerbose(sprintf('Processing dependency \'%s=%s\'', $dependency->getName(), $dependency->getVersion())); + + /** @noinspection UnusedFunctionResultInspection */ + $package_writer->addDependencyConfiguration($dependency); + + if(!$static) + { + return; + } + + $entry = (new PackageManager())->getPackageLock()->getVersionEntry($dependency->getName(), $dependency->getVersion()); + $package_writer->merge((new PackageReader($entry->getShadowPackagePath($dependency->getName())))); + + foreach($entry->getDependencies() as $sub_dependency) + { + $this->processDependency($package_writer, $sub_dependency, $static); + } + } + /** * Creates a package writer with the specified options * diff --git a/src/ncc/Classes/PackageReader.php b/src/ncc/Classes/PackageReader.php index eab31ca..b15fbf1 100644 --- a/src/ncc/Classes/PackageReader.php +++ b/src/ncc/Classes/PackageReader.php @@ -270,6 +270,34 @@ return fread($this->package_file, (int)$location[1]); } + /** + * Returns a resource pointer from the package by name + * + * @param string $name + * @return int[] + */ + public function getPointer(string $name): array + { + if(!isset($this->headers[PackageStructure::DIRECTORY][$name])) + { + throw new RuntimeException(sprintf('Resource \'%s\' not found in package', $name)); + } + + $location = explode(':', $this->headers[PackageStructure::DIRECTORY][$name]); + return [(int)$location[0], (int)$location[1]]; + } + + /** + * Returns True if the package contains a resource by name + * + * @param string $name + * @return bool + */ + public function exists(string $name): bool + { + return isset($this->headers[PackageStructure::DIRECTORY][$name]); + } + /** * Returns a resource from the package by pointer * @@ -631,9 +659,9 @@ } /** - * @return false|int + * @return int */ - public function getHeaderLength(): false|int + public function getHeaderLength(): int { return $this->header_length; } diff --git a/src/ncc/Classes/PackageWriter.php b/src/ncc/Classes/PackageWriter.php index 6660b87..d65d58e 100644 --- a/src/ncc/Classes/PackageWriter.php +++ b/src/ncc/Classes/PackageWriter.php @@ -38,6 +38,7 @@ use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Objects\ProjectConfiguration\Installer; use ncc\Extensions\ZiProto\ZiProto; + use ncc\Utilities\Console; class PackageWriter { @@ -351,6 +352,42 @@ $this->addPointer(sprintf('@%s:%s', PackageDirectory::CLASS_POINTER, $class), $offset, $length); } + /** + * Merges the contents of a package reader into the package writer + * + * @param PackageReader $reader + * @return void + */ + public function merge(PackageReader $reader): void + { + $processed_resources = []; + + foreach($reader->getDirectory() as $name => $pointer) + { + switch((int)substr(explode(':', $name, 2)[0], 1)) + { + case PackageDirectory::METADATA: + case PackageDirectory::ASSEMBLY: + case PackageDirectory::INSTALLER: + case PackageDirectory::EXECUTION_UNITS: + Console::outDebug(sprintf('Skipping %s', $name)); + break; + + default: + if(isset($processed_resources[$pointer])) + { + Console::outDebug(sprintf('Merging %s as a pointer', $name)); + $this->addPointer($name, (int)$processed_resources[$pointer][0], (int)$processed_resources[$pointer][1]); + break; + } + + Console::outDebug(sprintf('Merging %s', $name)); + $processed_resources[$pointer] = $this->add($name, $reader->get($name)); + + } + } + } + /** * Finalizes the package by writing the magic bytes, header length, delimiter, headers, and data to the file * diff --git a/src/ncc/Classes/PhpExtension/ExecutableCompiler.php b/src/ncc/Classes/PhpExtension/ExecutableCompiler.php index 619fe36..c0dcb28 100644 --- a/src/ncc/Classes/PhpExtension/ExecutableCompiler.php +++ b/src/ncc/Classes/PhpExtension/ExecutableCompiler.php @@ -71,20 +71,20 @@ // Prepare the gcc command $gcc_path = (new ExecutableFinder())->find('gcc'); - if($configuration->getOutputName() !== null) - { - $binary_path = - ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutputPath()) - . DIRECTORY_SEPARATOR . - ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutputName()); - } - elseif(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE])) + if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE])) { $binary_path = ConstantCompiler::compileConstants( $this->getProjectManager()->getProjectConfiguration(), $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE] ); } + elseif($configuration->getOutputName() !== null) + { + $binary_path = + ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutputPath()) + . DIRECTORY_SEPARATOR . + ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutputName()); + } else { $binary_path = @@ -137,6 +137,22 @@ Console::outVerbose(sprintf('Compiling executable to %s: %s', $binary_path, implode(' ', $gcc_options))); $process->run(static function ($type, $buffer) { + // If $buffer contains multiple lines, split it and output each line separately + if(str_contains($buffer, "\n")) + { + foreach(explode("\n", $buffer) as $line) + { + if($line === '') + { + continue; + } + + Console::outVerbose(rtrim($line, "\n")); + } + + return; + } + Console::outVerbose(rtrim($buffer, "\n")); }); diff --git a/src/ncc/Classes/Runtime.php b/src/ncc/Classes/Runtime.php index 44448f2..d72016e 100644 --- a/src/ncc/Classes/Runtime.php +++ b/src/ncc/Classes/Runtime.php @@ -27,6 +27,7 @@ use Exception; use InvalidArgumentException; use ncc\Enums\FileDescriptor; + use ncc\Enums\Flags\PackageFlags; use ncc\Enums\Versions; use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ImportException; @@ -205,12 +206,15 @@ } // Import dependencies recursively - foreach($package_reader->getDependencies() as $dependency) + if(!$package_reader->getFlag(PackageFlags::STATIC_DEPENDENCIES)) { - $dependency = $package_reader->getDependency($dependency); + foreach($package_reader->getDependencies() as $dependency) + { + $dependency = $package_reader->getDependency($dependency); - /** @noinspection UnusedFunctionResultInspection */ - self::import($dependency->getName(), $dependency->getVersion()); + /** @noinspection UnusedFunctionResultInspection */ + self::import($dependency->getName(), $dependency->getVersion()); + } } return $package_reader->getAssembly()->getPackage(); diff --git a/src/ncc/Enums/Flags/PackageFlags.php b/src/ncc/Enums/Flags/PackageFlags.php index 69f6903..7d43294 100644 --- a/src/ncc/Enums/Flags/PackageFlags.php +++ b/src/ncc/Enums/Flags/PackageFlags.php @@ -31,4 +31,6 @@ public const MEDIUM_COMPRESSION = 'medium_gz'; public const HIGH_COMPRESSION = 'high_gz'; + + public const STATIC_DEPENDENCIES = 'static_dependencies'; } \ No newline at end of file diff --git a/src/ncc/Objects/PackageLock.php b/src/ncc/Objects/PackageLock.php index d2f485f..9f6694a 100644 --- a/src/ncc/Objects/PackageLock.php +++ b/src/ncc/Objects/PackageLock.php @@ -30,6 +30,7 @@ use ncc\Exceptions\ConfigurationException; use ncc\Interfaces\BytecodeObjectInterface; use ncc\Objects\PackageLock\PackageEntry; + use ncc\Objects\PackageLock\VersionEntry; use ncc\Utilities\Functions; class PackageLock implements BytecodeObjectInterface @@ -171,6 +172,18 @@ throw new InvalidArgumentException(sprintf('Package entry %s does not exist', $package_name)); } + /** + * Returns a version entry from a package entry + * + * @param string $package_name + * @param string $version + * @return VersionEntry + */ + public function getVersionEntry(string $package_name, string $version): VersionEntry + { + return $this->getEntry($package_name)->getVersion($version); + } + /** * Adds a new package entry to the package lock file *