Added the ability to initialize a project

This commit is contained in:
Netkas 2022-07-09 21:29:37 -04:00
parent 7926ef4077
commit 265cfce65b
10 changed files with 350 additions and 53 deletions

View file

@ -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;
}

View file

@ -0,0 +1,8 @@
<?php
namespace ncc\Abstracts\Options;
abstract class InitializeProjectOptions
{
const CREATE_SOURCE_DIRECTORY = 1;
}

View file

@ -0,0 +1,20 @@
<?php
namespace ncc\Exceptions;
use Exception;
use ncc\Abstracts\ExceptionCodes;
use Throwable;
class ConstantReadonlyException extends Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, ExceptionCodes::ConstantReadonlyException, $previous);
}
}

View file

@ -2,7 +2,11 @@
namespace ncc\Managers;
use ncc\Abstracts\Options\InitializeProjectOptions;
use ncc\Exceptions\MalformedJsonException;
use ncc\Objects\ProjectConfiguration;
use ncc\Objects\ProjectConfiguration\Compiler;
use ncc\Symfony\Component\Uid\Uuid;
class ProjectManager
{
@ -18,6 +22,13 @@
*
* @var string|null
*/
private string $ProjectFilePath;
/**
* The path that points the project's main directory
*
* @var string|null
*/
private string $ProjectPath;
/**
@ -28,6 +39,9 @@
public function __construct(string $selected_directory)
{
$this->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;
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace ncc\Objects;
use ncc\Exceptions\ConstantReadonlyException;
use ncc\Symfony\Component\Uid\Uuid;
use ncc\Utilities\Resolver;
class Constant
{
/**
* The unique hash of the constant
*
* @var string
*/
private $Hash;
/**
* The package that manages this constant
*
* @var string
*/
private $Scope;
/**
* The name of the constant
*
* @var string
*/
private $Name;
/**
* The value of the constant
*
* @var string
*/
private $Value;
/**
* Indicates if the constant is readonly or not
*
* @var bool
*/
private $Readonly;
/**
* Public Constructor
*
* @param string $scope
* @param string $name
* @param string $value
* @param bool $readonly
*/
public function __construct(string $scope, string $name, string $value, bool $readonly=false)
{
$this->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;
}
}

View file

@ -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);
}

View file

@ -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');

View file

@ -0,0 +1,61 @@
<?php
namespace ncc\Runtime;
use ncc\Exceptions\ConstantReadonlyException;
use ncc\Objects\Constant;
use ncc\Utilities\Resolver;
class Constants
{
/**
* The registered constants in memory
*
* @var Constant[]
*/
private static $Constants;
/**
* Registers a new constant
*
* @param string $scope The package name that owns this constant
* @param string $name The name of the constant
* @param string $value The value of the constant
* @param bool $readonly Indicates if the constant cannot be changed with the registerConstant function once it's registered
* @return void
* @throws ConstantReadonlyException
*/
public static function register(string $scope, string $name, string $value, bool $readonly=false)
{
// TODO: Add functionality to convert the constant name to be more memory-friendly with a size limit
$constant_hash = Resolver::resolveConstantHash($scope, $name);
if(isset(self::$Constants[$constant_hash]))
{
self::$Constants[$constant_hash]->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]);
}
}

View file

@ -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));
}
}

View file

@ -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": []
}