From 265cfce65b0749736470ce2dbc0a53b6757c73e7 Mon Sep 17 00:00:00 2001 From: Netkas Date: Sat, 9 Jul 2022 21:29:37 -0400 Subject: [PATCH] Added the ability to initialize a project --- src/ncc/Abstracts/ExceptionCodes.php | 6 + .../Options/InitializeProjectOptions.php | 8 + .../Exceptions/ConstantReadonlyException.php | 20 +++ src/ncc/Managers/ProjectManager.php | 95 +++++++++--- src/ncc/Objects/Constant.php | 137 ++++++++++++++++++ src/ncc/Objects/ProjectConfiguration.php | 6 + .../BuildConfiguration.php | 28 ---- src/ncc/Runtime/Constants.php | 61 ++++++++ src/ncc/Utilities/Resolver.php | 23 +++ tests/project_configuration/project.json | 19 ++- 10 files changed, 350 insertions(+), 53 deletions(-) create mode 100644 src/ncc/Abstracts/Options/InitializeProjectOptions.php create mode 100644 src/ncc/Exceptions/ConstantReadonlyException.php create mode 100644 src/ncc/Objects/Constant.php create mode 100644 src/ncc/Runtime/Constants.php diff --git a/src/ncc/Abstracts/ExceptionCodes.php b/src/ncc/Abstracts/ExceptionCodes.php index 85f2e5e..528e29b 100644 --- a/src/ncc/Abstracts/ExceptionCodes.php +++ b/src/ncc/Abstracts/ExceptionCodes.php @@ -4,6 +4,7 @@ use ncc\Exceptions\AccessDeniedException; use ncc\Exceptions\ComponentVersionNotFoundException; + use ncc\Exceptions\ConstantReadonlyException; use ncc\Exceptions\DirectoryNotFoundException; use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\InvalidCredentialsEntryException; @@ -62,4 +63,9 @@ * @see ComponentVersionNotFoundException */ const ComponentVersionNotFoundException = -1708; + + /** + * @see ConstantReadonlyException + */ + const ConstantReadonlyException = -1709; } \ No newline at end of file diff --git a/src/ncc/Abstracts/Options/InitializeProjectOptions.php b/src/ncc/Abstracts/Options/InitializeProjectOptions.php new file mode 100644 index 0000000..16c0605 --- /dev/null +++ b/src/ncc/Abstracts/Options/InitializeProjectOptions.php @@ -0,0 +1,8 @@ +SelectedDirectory = $selected_directory; + $this->ProjectFilePath = null; + $this->ProjectPath = null; + $this->detectProjectPath(); } @@ -42,6 +56,7 @@ $selected_directory = $this->SelectedDirectory; // Auto-resolve the trailing slash + /** @noinspection PhpStrFunctionsInspection */ if(substr($selected_directory, -1) !== '/') { $selected_directory .= $selected_directory . DIRECTORY_SEPARATOR; @@ -56,37 +71,81 @@ // Detect if project.json exists in the directory if(file_exists($selected_directory . 'project.json') == true) { - $this->ProjectPath = $selected_directory . 'project.json'; + $this->ProjectPath = $selected_directory; + $this->ProjectFilePath = $selected_directory . 'project.json'; return true; } - // If not, check for pointer files - $pointer_files = [ - '.ppm_package', // Backwards Compatibility - '.ncc_project' - ]; - - foreach($pointer_files as $pointer_file) - { - if(file_exists($selected_directory . $pointer_file) && is_file($selected_directory . $pointer_file)) - { - // TODO: Complete this - } - } - - return true; + return false; } /** * Initializes the project sturcture * * @param Compiler $compiler + * @param string $source * @param string $name * @param string $package - * @return bool + * @param array $options + * @throws MalformedJsonException */ - public function initializeProject(Compiler $compiler, string $name, string $package): bool + public function initializeProject(Compiler $compiler, string $source, string $name, string $package, array $options=[]) { + $Project = new ProjectConfiguration(); + // Set the compiler information + $Project->Project->Compiler = $compiler; + + // Set the assembly information + $Project->Assembly->Name = $name; + $Project->Assembly->Package = $package; + $Project->Assembly->UUID = Uuid::v1()->toRfc4122(); + + // Set the build information + $Project->Build->SourcePath = $source; + $Project->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%'; + + // 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; + $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; + + // Finally create project.json + $Project->toFile($this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json'); + + // Process options + foreach($options as $option) + { + switch($option) + { + case InitializeProjectOptions::CREATE_SOURCE_DIRECTORY: + if(file_exists($source) == false) + { + mkdir($source); + } + break; + } + } + } + + /** + * @return string|null + */ + public function getProjectFilePath(): ?string + { + return $this->ProjectFilePath; } } \ No newline at end of file diff --git a/src/ncc/Objects/Constant.php b/src/ncc/Objects/Constant.php new file mode 100644 index 0000000..b25df7f --- /dev/null +++ b/src/ncc/Objects/Constant.php @@ -0,0 +1,137 @@ +Scope = $scope; + $this->Name = $name; + $this->Value = $value; + $this->Readonly = $readonly; + $this->Hash = Resolver::resolveConstantHash($this->Scope, $this->Name); + } + + /** + * Returns the constant value + * + * @return string + */ + public function __toString(): string + { + return $this->Value; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->Value; + } + + /** + * Gets the full name of the constant + * + * @return string + */ + public function getFullName(): string + { + return Resolver::resolveFullConstantName($this->Scope, $this->Name); + } + + /** + * @param string $value + * @throws ConstantReadonlyException + */ + public function setValue(string $value, bool $readonly=false): void + { + if($this->Readonly == true) + { + throw new ConstantReadonlyException('Cannot set value to the constant \'' . $this->getFullName() . '\', constant is readonly'); + } + + $this->Value = $value; + $this->Readonly = $readonly; + } + + /** + * @return bool + */ + public function isReadonly(): bool + { + return $this->Readonly; + } + + /** + * @return string + */ + public function getHash(): string + { + return $this->Hash; + } + + /** + * @return string + */ + public function getScope(): string + { + return $this->Scope; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->Name; + } + } \ No newline at end of file diff --git a/src/ncc/Objects/ProjectConfiguration.php b/src/ncc/Objects/ProjectConfiguration.php index d4435af..cd8376d 100644 --- a/src/ncc/Objects/ProjectConfiguration.php +++ b/src/ncc/Objects/ProjectConfiguration.php @@ -89,6 +89,12 @@ */ public function toFile(string $path, bool $bytecode=false) { + if(!$bytecode) + { + Functions::encodeJsonFile($this->toArray($bytecode), $path, Functions::FORCE_ARRAY | Functions::PRETTY | Functions::ESCAPE_UNICODE); + return; + } + Functions::encodeJsonFile($this->toArray($bytecode), $path, Functions::FORCE_ARRAY); } diff --git a/src/ncc/Objects/ProjectConfiguration/BuildConfiguration.php b/src/ncc/Objects/ProjectConfiguration/BuildConfiguration.php index 0797d16..cc80ef6 100644 --- a/src/ncc/Objects/ProjectConfiguration/BuildConfiguration.php +++ b/src/ncc/Objects/ProjectConfiguration/BuildConfiguration.php @@ -26,13 +26,6 @@ */ public $Options; - /** - * Indicates if the libraries and resources for the build configuration are statically linked - * - * @var bool - */ - public $StaticLinking; - /** * The build output path for the build configuration, eg; build/%BUILD.NAME% * @@ -47,13 +40,6 @@ */ public $DefineConstants; - /** - * Indicates if one or more constants cannot be defined, it should result in a runtime error. - * - * @var bool - */ - public $StrictConstants; - /** * An array of files to exclude in this build configuration * @@ -75,10 +61,8 @@ public function __construct() { $this->Options = []; - $this->StaticLinking = false; $this->OutputPath = 'build'; $this->DefineConstants = []; - $this->StrictConstants = false; $this->ExcludeFiles = []; $this->Dependencies = []; } @@ -97,10 +81,8 @@ $ReturnResults[($bytecode ? Functions::cbc('name') : 'name')] = $this->Name; $ReturnResults[($bytecode ? Functions::cbc('options') : 'options')] = $this->Options; - $ReturnResults[($bytecode ? Functions::cbc('static_linking') : 'static_linking')] = $this->StaticLinking; $ReturnResults[($bytecode ? Functions::cbc('output_path') : 'output_path')] = $this->OutputPath; $ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants; - $ReturnResults[($bytecode ? Functions::cbc('strict_constants') : 'strict_constants')] = $this->StrictConstants; $ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles; $ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = []; @@ -132,11 +114,6 @@ $BuildConfigurationObject->Options = Functions::array_bc($data, 'options'); } - if(Functions::array_bc($data, 'static_linking') !== null) - { - $BuildConfigurationObject->StaticLinking = Functions::array_bc($data, 'static_linking'); - } - if(Functions::array_bc($data, 'output_path') !== null) { $BuildConfigurationObject->OutputPath = Functions::array_bc($data, 'output_path'); @@ -147,11 +124,6 @@ $BuildConfigurationObject->DefineConstants = Functions::array_bc($data, 'define_constants'); } - if(Functions::array_bc($data, 'strict_constants') !== null) - { - $BuildConfigurationObject->StrictConstants = Functions::array_bc($data, 'strict_constants'); - } - if(Functions::array_bc($data, 'exclude_files') !== null) { $BuildConfigurationObject->ExcludeFiles = Functions::array_bc($data, 'exclude_files'); diff --git a/src/ncc/Runtime/Constants.php b/src/ncc/Runtime/Constants.php new file mode 100644 index 0000000..2e7366a --- /dev/null +++ b/src/ncc/Runtime/Constants.php @@ -0,0 +1,61 @@ +setValue($value, $readonly); + return; + } + + self::$Constants[$constant_hash] = new Constant($scope, $name, $value, $readonly); + } + + /** + * Deletes the constant + * + * @param string $scope + * @param string $name + * @return void + * @throws ConstantReadonlyException + */ + public static function delete(string $scope, string $name) + { + $constant_hash = Resolver::resolveConstantHash($scope, $name); + + if(isset(self::$Constants[$constant_hash]) && self::$Constants[$constant_hash]->isReadonly()) + { + throw new ConstantReadonlyException('Cannot delete the constant \'' . self::$Constants[$constant_hash]->getFullName() . '\', constant is readonly'); + } + + unset(self::$Constants[$constant_hash]); + } + } \ No newline at end of file diff --git a/src/ncc/Utilities/Resolver.php b/src/ncc/Utilities/Resolver.php index 96ce931..036248a 100644 --- a/src/ncc/Utilities/Resolver.php +++ b/src/ncc/Utilities/Resolver.php @@ -112,4 +112,27 @@ return $configs; } + /** + * Resolves the constant's full name + * + * @param string $scope + * @param string $name + * @return string + */ + public static function resolveFullConstantName(string $scope, string $name): string + { + return $scope . '.(' . $name . ')'; + } + + /** + * Resolves the constant's unique hash + * + * @param string $scope + * @param string $name + * @return string + */ + public static function resolveConstantHash(string $scope, string $name): string + { + return hash('haval128,3', self::resolveFullConstantName($scope, $name)); + } } \ No newline at end of file diff --git a/tests/project_configuration/project.json b/tests/project_configuration/project.json index 3658298..b9ef2fa 100644 --- a/tests/project_configuration/project.json +++ b/tests/project_configuration/project.json @@ -26,7 +26,12 @@ ], "options": {}, "scope": "user", - "define_constants": {"%ASSEMBLY.NAME%_HELLO": "Hello World!"}, + "define_constants": { + "ASSEMBLY_NAME": "%ASSEMBLY.NAME%", + "ASSEMBLY_PACKAGE": "%ASSEMBLY.PACKAGE%", + "ASSEMBLY_VERSION": "%ASSEMBLY.VERSION%", + "ASSEMBLY_UID": "%ASSEMBLY.UID%" + }, "dependencies": [ {"name": "mbstring", "source": "extension", "version": "latest"}, {"name": "com.example.dependency", "source": "default@github/example/ncc_dependency", "version": "latest"}, @@ -36,10 +41,10 @@ { "name": "debug", "options": {}, - "static_linking": true, "output_path": "build/debug", - "define_constants": {"%ASSEMBLY.NAME%_DEBUG": "1"}, - "strict_constants": false, + "define_constants": { + "DEBUG": "1" + }, "exclude_files": [], "dependencies": [ {"name": "x-debug", "source": "extension", "version": "latest"} @@ -48,10 +53,10 @@ { "name": "release", "options": {}, - "static_linking": true, "output_path": "build/release", - "define_constants": {}, - "strict_constants": false, + "define_constants": { + "DEBUG": "0" + }, "exclude_files": [], "dependencies": [] }