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->getCompiler()->toArray() as $prop => $value) { Console::outDebug(sprintf('compiler.%s: %s', $prop, ($value ?? 'n/a'))); } } // Select the correct compiler for the specified extension if (strtolower($configuration->project->getCompiler()->getExtension()) === CompilerExtensions::PHP) { /** @var CompilerInterface $Compiler */ $Compiler = new PhpCompiler($configuration, $manager->getProjectPath()); } else { throw new NotSupportedException('The compiler extension \'' . $configuration->project->getCompiler()->getExtension() . '\' is not supported'); } $build_configuration = $configuration->build->getBuildConfiguration($build_configuration)->getName(); Console::out(sprintf('Building %s=%s', $configuration->assembly->getPackage(), $configuration->assembly->getVersion())); $Compiler->prepare($build_configuration); $Compiler->build(); return self::writePackage( $manager->getProjectPath(), $Compiler->getPackage(), $configuration, $build_configuration ); } /** * Attempts to detect the project type and convert it accordingly before compiling * Returns the compiled package path * * @param string $path * @param string|null $version * @return string * @throws BuildException */ public static function tryCompile(string $path, ?string $version=null): string { $project_type = Resolver::detectProjectType($path); try { if($project_type->ProjectType === ProjectType::COMPOSER) { $project_path = ComposerSourceBuiltin::fromLocal($project_type->ProjectPath); } elseif($project_type->ProjectType === ProjectType::NCC) { $project_manager = new ProjectManager($project_type->ProjectPath); $project_manager->getProjectConfiguration()->assembly->setVersion($version); $project_path = $project_manager->build(); } else { throw new NotSupportedException(sprintf('Failed to compile %s, project type %s is not supported', $project_type->ProjectPath, $project_type->ProjectType)); } if($version !== null) { $package = Package::load($project_path); $package->assembly->setVersion(Functions::convertToSemVer($version)); $package->save($project_path); } return $project_path; } catch(Exception $e) { throw new BuildException('Failed to build project', $e); } } /** * Compiles the execution policies of the package * * @param string $path * @param ProjectConfiguration $configuration * @return array * @throws IOException * @throws NotSupportedException * @throws PathNotFoundException */ public static function compileExecutionPolicies(string $path, ProjectConfiguration $configuration): array { if(count($configuration->execution_policies) === 0) { return []; } Console::out('Compiling Execution Policies'); $total_items = count($configuration->execution_policies); $execution_units = []; $processed_items = 1; /** @var ProjectConfiguration\ExecutionPolicy $policy */ foreach($configuration->execution_policies as $policy) { Console::outVerbose(sprintf('Compiling Execution Policy %s', $policy->getName())); /** @noinspection DisconnectedForeachInstructionInspection */ if($total_items > 5) { Console::inlineProgressBar($processed_items, $total_items); } $unit_path = Functions::correctDirectorySeparator($path . $policy->getExecute()->getTarget()); $execution_units[] = Functions::compileRunner($unit_path, $policy); } if($total_items > 5 && ncc::cliMode()) { 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 IOException * @throws ConfigurationException */ public static function writePackage(string $path, Package $package, ProjectConfiguration $configuration, string $build_configuration=BuildConfigurationValues::DEFAULT): string { Console::outVerbose(sprintf('Writing package to %s', $path)); // Write the package to disk $FileSystem = new Filesystem(); $BuildConfiguration = $configuration->build->getBuildConfiguration($build_configuration); if(!$FileSystem->exists($path . $BuildConfiguration->getOutputPath())) { Console::outDebug(sprintf('creating output directory %s', $path . $BuildConfiguration->getOutputPath())); $FileSystem->mkdir($path . $BuildConfiguration->getOutputPath()); } // Finally write the package to the disk $FileSystem->mkdir($path . $BuildConfiguration->getOutputPath()); $output_file = $path . $BuildConfiguration->getOutputPath() . DIRECTORY_SEPARATOR . $package->assembly->getPackage() . '.ncc'; if($FileSystem->exists($output_file)) { Console::outDebug(sprintf('removing existing package %s', $output_file)); $FileSystem->remove($output_file); } $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 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) { Console::outDebug(sprintf('compiling constant Assembly.%s (%s)', $key, implode(', ', array_keys($refs)))); $assembly[$key] = self::compileConstants($value, $refs); } $package->assembly = Assembly::fromArray($assembly); unset($assembly); } if($package->execution_units !== null && count($package->execution_units) > 0) { $units = []; foreach($package->execution_units as $executionUnit) { Console::outDebug(sprintf('compiling execution unit constant %s (%s)', $executionUnit->getExecutionPolicy()->getName(), implode(', ', array_keys($refs)))); $units[] = self::compileExecutionUnitConstants($executionUnit, $refs); } $package->execution_units = $units; unset($units); } $compiled_constants = []; foreach($package->header->getRuntimeConstants() as $name => $value) { Console::outDebug(sprintf('compiling runtime constant %s (%s)', $name, implode(', ', array_keys($refs)))); $compiled_constants[$name] = self::compileConstants($value, $refs); } $options = []; foreach($package->header->getOptions() as $name => $value) { if(is_array($value)) { $options[$name] = []; foreach($value as $key => $val) { if(!is_string($val)) { continue; } Console::outDebug(sprintf('compiling option %s.%s (%s)', $name, $key, implode(', ', array_keys($refs)))); $options[$name][$key] = self::compileConstants($val, $refs); } } else { Console::outDebug(sprintf('compiling option %s (%s)', $name, implode(', ', array_keys($refs)))); $options[$name] = self::compileConstants((string)$value, $refs); } } $package->header->setOptions($options); $package->header->setRuntimeConstants($compiled_constants); } /** * 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->getExecutionPolicy()->setMessage(self::compileConstants($unit->getExecutionPolicy()->getMessage(), $refs)); if($unit->getExecutionPolicy()->getExitHandlers() !== null) { if($unit->getExecutionPolicy()->getExitHandlers()->getSuccess()?->getMessage() !== null) { $unit->getExecutionPolicy()->getExitHandlers()->getSuccess()?->setMessage( self::compileConstants($unit->getExecutionPolicy()->getExitHandlers()->getSuccess()->getMessage(), $refs) ); } if($unit->getExecutionPolicy()->getExitHandlers()->getError()?->getMessage() !== null) { $unit->getExecutionPolicy()->getExitHandlers()->getError()?->setMessage( self::compileConstants($unit->getExecutionPolicy()->getExitHandlers()->getError()->getMessage(), $refs) ); } if($unit->getExecutionPolicy()->getExitHandlers()->getWarning()?->getMessage() !== null) { $unit->getExecutionPolicy()->getExitHandlers()->getWarning()?->setMessage( self::compileConstants($unit->getExecutionPolicy()->getExitHandlers()->getWarning()->getMessage(), $refs) ); } } if($unit->getExecutionPolicy()->getExecute() !== null) { $unit->getExecutionPolicy()->getExecute()->setTarget(self::compileConstants($unit->getExecutionPolicy()->getExecute()->getTarget(), $refs)); $unit->getExecutionPolicy()->getExecute()->setWorkingDirectory(self::compileConstants($unit->getExecutionPolicy()->getExecute()->getWorkingDirectory(), $refs)); if(count($unit->getExecutionPolicy()->getExecute()->getOptions()) > 0) { $options = []; foreach($unit->getExecutionPolicy()->getExecute()->getOptions() as $key=> $value) { $options[self::compileConstants($key, $refs)] = self::compileConstants($value, $refs); } $unit->getExecutionPolicy()->getExecute()->setOptions($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::DATE_TIME])) { $value = ConstantCompiler::compileDateTimeConstants($value, $refs[ConstantReferences::DATE_TIME]); } if(isset($refs[ConstantReferences::INSTALL])) { $value = ConstantCompiler::compileInstallConstants($value, $refs[ConstantReferences::INSTALL]); } if(isset($refs[ConstantReferences::RUNTIME])) { $value = ConstantCompiler::compileRuntimeConstants($value); } return $value; } }