Compare commits

..

No commits in common. "master" and "2.0.1" have entirely different histories.

518 changed files with 12971 additions and 18096 deletions

View file

@ -1,136 +0,0 @@
name: CI Pipeline
on:
push:
branches:
- '**'
pull_request:
branches:
- '**'
release:
types:
- created
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, ctype, common, zip
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y git libpq-dev libzip-dev zip make wget gnupg
- name: Install Phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
sudo mv phive.phar /usr/local/bin/phive
- name: Install PHPAB
run: sudo phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Build project
run: make redist
- name: Find NCC build directory
id: find-ncc-dir
run: echo "NCC_DIR=$(find build/ -type d -name 'ncc_*' | head -n 1)" >> $GITHUB_ENV
- name: Upload NCC build directory
uses: actions/upload-artifact@v3
with:
name: ncc-build
path: ${{ env.NCC_DIR }}
- name: Create redist.zip
run: zip -r redist.zip ${{ env.NCC_DIR }}
- name: Upload redist.zip
uses: actions/upload-artifact@v3
with:
name: redist-zip
path: redist.zip
- name: Build Debian package
run: make deb
- name: Find Debian package
id: find-deb
run: echo "DEB_FILE=$(find build/ -type f -name '*.deb' | head -n 1)" >> $GITHUB_ENV
- name: Upload Debian package
uses: actions/upload-artifact@v3
with:
name: ncc-deb
path: ${{ env.DEB_FILE }}
test-install:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download NCC build directory
uses: actions/download-artifact@v3
with:
name: ncc-build
path: build
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, ctype, common, zip
- name: Test NCC installation
run: |
ls -l build
sudo php build/INSTALL --auto
upload-release:
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'release' && github.event.action == 'created'
permissions: write-all
steps:
- name: Download redist.zip
uses: actions/download-artifact@v3
with:
name: redist-zip
path: .
- name: Download Debian package
uses: actions/download-artifact@v3
with:
name: ncc-deb
path: .
- name: Set DEB_FILE environment variable
run: echo "DEB_FILE=$(find . -type f -name '*.deb' | head -n 1)" >> $GITHUB_ENV
- name: Upload redist.zip to release
uses: softprops/action-gh-release@v1
with:
files: redist.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload ncc.deb to release
uses: softprops/action-gh-release@v1
with:
files: ${{ env.DEB_FILE }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

5
.gitignore vendored
View file

@ -8,7 +8,7 @@
build build
# Autoload files # Autoload files
src/ncc/ThirdParty/composer/Semver/autoload_spl.php src/ncc/ThirdParty/composer/semver/autoload_spl.php
src/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php src/ncc/ThirdParty/defuse/php-encryption/autoload_spl.php
src/ncc/ThirdParty/jelix/version/autoload_spl.php src/ncc/ThirdParty/jelix/version/autoload_spl.php
src/ncc/ThirdParty/nikic/PhpParser/autoload_spl.php src/ncc/ThirdParty/nikic/PhpParser/autoload_spl.php
@ -29,6 +29,3 @@ src/ncc/autoload.php
tests/example_project/project.json tests/example_project/project.json
tests/example_project/ncc tests/example_project/ncc
tests/example_project/build tests/example_project/build
/.phpunit.result.cache
/.idea/php-test-framework.xml
/.idea/gbrowser_project.xml

View file

@ -1,7 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
</code_scheme>
</component>

8
.idea/php.xml generated
View file

@ -12,9 +12,10 @@
<component name="PhpIncludePathManager"> <component name="PhpIncludePathManager">
<include_path> <include_path>
<path value="/usr/share/php" /> <path value="/usr/share/php" />
<path value="$PROJECT_DIR$/../loglib" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.3"> <component name="PhpProjectSharedConfiguration" php_language_level="8.2">
<option name="suggestChangeDefaultLanguageLevel" value="false" /> <option name="suggestChangeDefaultLanguageLevel" value="false" />
</component> </component>
<component name="PhpRuntimeConfiguration"> <component name="PhpRuntimeConfiguration">
@ -25,11 +26,6 @@
<component name="PhpStanOptionsConfiguration"> <component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" /> <option name="transferred" value="true" />
</component> </component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings load_method="PHPUNIT_PHAR" custom_loader_path="" phpunit_phar_path="$USER_HOME$/phpunit.phar" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration"> <component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" /> <option name="transferred" value="true" />
</component> </component>

View file

@ -5,219 +5,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.1.6] - 2024-10-29
This update introduces critical bug fixes
### Fixed
- Validate package instance before checking execution policy
## [2.1.5] - 2024-10-14
This update introduces a critical bug fix
## [2.1.4] - 2024-10-13
This update introduces minor bug fixes & improvements
### Added
- Added new constant `%DEFAULT_BUILD_CONFIGURATION%` which points to the project's default build configuration
- Added new dynamic constant `%BUILD_OUTPUT_PATH%` which can be used as `%BUILD_OUTPUT_PATH%:release` to show the
output path of a specific build configuration
- Refactor CI templates to support dynamic build targets
- Added template `phpexe` & `phpgz` for generating executable binaries and compressed executables for the project
### Changed
- Refactor phpmake template to support dynamic build targets
### Fixed
- ncc will now correctly handle package execution where the main unit is not defined in the package instead of
throwing an exception.
- Executable Compiler will now correctly create a directory if it does not exist when compiling a package using gcc
## [2.1.3] - 2024-09-27
This update introduces bug fixes
### Fixed
- Null-pointer fix
## [2.1.2] - 2024-09-27
This update introduces bug fixes
### Added
- Add getter methods for installation lifecycle steps
- Added pre-install & post-install execution unit handling
### Changed
- Updated DocStrings in PackageManager
### Fixed
- Fixed incorrect enum usage in RepositoryMenu
## [2.1.1] - 2024-09-24
This update introduces a couple of new features and quality of life improvements
### Added
- Added new PHP template `phpunit` for generating PhpUnit tests for the project
- Added new PHP template `phpmake` for generating a Makefile for the project
- Added new PHP template `phplib_full` That combines `phplib`, `phpmake` and `phpunit` templates
- Added new PHP template `phpcli_full` That combines `phpcli`, `phplib`, `phpmake` and `phpunit` templates
- Added new PHP template `phpci_github` that generates a Github CI workflow for the project
### Changed
- The template `phpcli` no longer includes a Makefile, instead use `phpmake` to generate a Makefile for the project
### Fixed
- Fixed incorrect enum usage with a logging method call.
## [2.1.0] - 2024-09-20
This update introduces a refactored code-base, code quality improvements, and better exception handling.
### Added
- Added Test unit tests/ncc/Objects/Package/ComponentTest.php
- Added Test unit tests/ncc/Utilities/ResolverTest.php
- Added Test unit tests/ncc/Utilities/SecurityTest.php
- Added Test unit tests/ncc/Utilities/ValidateTest.php
- Add support for runtime constants
### Changed
- Convert Versions constants to enum cases
- Update Scopes to enum and adjust scope checks
- Convert Runners class to enum with string cases
- Convert RegexPatterns constants to enum cases
- Convert ProjectTemplates constants to enum cases
- Convert PackageStructureVersions constants to enum cases
- Convert PackageStructure constants to enum cases
- Convert PackageDirectory constants to enum cases
- Convert LogLevel constants to enum cases
- Convert FileDescriptor constants to enum cases
- Convert ExceptionCodes constants to enum cases
- Convert ConsoleColors constants to enum cases
- Convert CompilerExtensions constants to enum cases
- Convert RepositoryType constants to enum cases
- Convert RepositoryResultType constants to enum cases
- Convert ProjectType constants to enum cases
- Convert HttpRequestType constants to enum cases
- Convert ComposerStabilityTypes constants to enum cases
- Convert ComposerPackageTypes constants to enum cases
- Convert ComponentDataType constants to enum cases
- Convert BuildOutputType constants to enum cases
- Convert AuthenticationType constants to enum cases
- Convert RuntimeConstants constants to enum cases
- Convert InstallConstants constants to enum cases
- Convert DateTimeConstants constants to enum cases
- Convert BuildConstants constants to enum cases
- Convert AssemblyConstants constants to enum cases
- Convert ProjectOptions constants to enum cases
- Convert InstallPackageOptions constants to enum cases
- Convert InitializeProjectOptions constants to enum cases
- Convert ComponentDecodeOptions constants to enum cases
- Convert BuildConfigurationValues constants to enum cases
- Convert BuildConfigurationOptions constants to enum cases
- Convert CompressionOptions constants to enum cases
- Convert PackageFlags constants to enum cases
- Convert NccBuildFlags constants to enum cases
- Convert ComponentFlags constants to enum cases
- Refactor flag handling to use PackageFlags enum directly
- Refactor checkLogLevel to correctly utilize LogLevel cases
- Refactor code to improve readability in Resolver.php
- Update PHP include paths in project configuration
- Refactor logging level checks to use LogLevel enum directly
- Refactor log level parsing with enum method
- Refactor log level checking to enum method
- Updated Symfony/Filesystem from version 6.3.1 to 7.1.2
- Refactor ProjectType handling
- Validate and enforce repository type enum usage
- Updated Composer/Semver to 3.4.3
- Rename 'semver' directory to 'Semver' in composer package
- Refactor project constants handling in NccCompiler
- Updated Symfony/Yaml to version 7.1.4
- Updated Symfony/Uid to version 7.1.4
- Updated Symfony/Process to version 7.1.3
- Updated Symfony/polyfill-ctype to version 1.31.0
- Updated Symfony/polyfill-mbstring to version 1.31.0
- Updated Symfony/polyfill-uuid to version 1.31.0
- Updated nikic/PhpParser to version 5.2.0
### Fixed
- Fixed Division by zero in PackageManager
- Fixed runner argument passing for ExecCommand
### Removed
- Removed EncoderType enum file, unused.
- Removed PackageStandardVersions.php
- Removed ConstantReferences.php
- Removed HttpStatusCodes.php
- Removed CompilerExtensionDefaultVersions.php
- Removed RemoteSourceType
- Removed DependencySourceType
- Removed BuiltinRemoteSourceType
- Removed RuntimeImportOptions
- Remove ComponentFileExtensions enum
- Remove unused import and redundant scope validation method
## [2.0.3] - 2023-10-17
This update includes enhanced support for PHP statements in AST traversal, a friendly CLI Progress Bar, and fixes
related to package version searching, ncc's extension registration, and error handling in PackageManagerMenu.
The changes improve the system's efficiency, error resilience, and user experience.
### Added
- Implemented support in the AST traversal for the PHP statements `include`, `include_once`, `require`, and
`require_once`. These statements are transformed into function calls. With this change, ncc can correctly handle and
import files from system packages or direct binary package files.
- Added new `ConsoleProgressBar` class for UI improvement, imrpoved the CLI Progress Bar inspired by
[pacman](https://wiki.archlinux.org/title/pacman)
### Fixed
- When finding package versions in the package lock, ncc will try to find a satisfying version rather than the exact
version, this is to prevent[CHANGELOG.md](CHANGELOG.md) errors when the package lock contains a version that is not available in the repository.
- Fixed issue when registering ncc's extension, when using the INSTALLER, the installation path used in the process
appears to be incorrect, added a optional parameter to the `registerExtension` method to allow the installer to pass
the correct installation path.
- Add error handling for unspecified package in PackageManagerMenu
## [2.0.2] - 2023-10-13
In this new update, the software introduces a feature for importing static packages without extra dependencies and
supports pulling static versions of packages from repositories. Changes include enhanced security through an updated
fetchPackage method along with improvements in dependency imports and extension registration logic for Debian packages.
Finally, bugs related to unnecessary bundling of some build artifacts and mime type errors in ncc-package.xml have
been fixed.
### Added
- Added support for importing static packages from the system, allowing you to install static packages onto your
system and import them without importing additional dependencies that isn't already included in the package.
- Added the ability to pull static versions of packages from repositories where package names ending with `-static.ncc`
or `_static.ncc` can be pulled if you use the `--prefer-static` or `--static` option when using the `package install`
command. Otherwise, the normal package will be installed, avoiding static versions.
### Changed
- Updated fetchPackage method to include authentication
- Update dependencies import in \ncc\Classes > Runtime > importFromPackage()
- Refactor ncc extension registration logic, this also allows for debian packages to install the ncc extension
automatically.
### Fixed
- Fixed issue where some build artifacts are being bundled with package builds such as `output_path` and `static`
where they should not be included in the package.
- Corrected mistakes in `ncc-package.xml` mime type
## [2.0.1] - 2023-10-11 ## [2.0.1] - 2023-10-11
Added a new feature in `ProjectManager.php` that allows automatic installation of a project's dependencies. The Added a new feature in `ProjectManager.php` that allows automatic installation of a project's dependencies. The

View file

@ -65,7 +65,7 @@ RUN chmod +x /usr/local/bin/install-php-extensions && sync && \
install-php-extensions zip xsl install-php-extensions zip xsl
# Install ncc # Install ncc
RUN php INSTALL --auto RUN php INSTALL --auto; cd ../; rm -rf ncc
# Finalize image # Finalize image
RUN mkdir /app RUN mkdir /app

View file

@ -65,7 +65,7 @@ RUN chmod +x /usr/local/bin/install-php-extensions && sync && \
install-php-extensions zip xsl install-php-extensions zip xsl
# Install ncc # Install ncc
RUN php INSTALL --auto RUN php INSTALL --auto; cd ../; rm -rf ncc
# Finalize image # Finalize image
RUN mkdir /app RUN mkdir /app

View file

@ -18,7 +18,7 @@ DEBIAN_PACKAGE_BUILD_PATH := $(BUILD_PATH)/ncc_$(BUILD_VERSION)_all.deb
# List of paths for autoloading # List of paths for autoloading
AUTOLOAD_PATHS := $(addprefix $(SRC_PATH)/ncc/ThirdParty/, \ AUTOLOAD_PATHS := $(addprefix $(SRC_PATH)/ncc/ThirdParty/, \
composer/Semver \ composer/semver \
defuse/php-encryption \ defuse/php-encryption \
jelix/version \ jelix/version \
nikic/PhpParser \ nikic/PhpParser \
@ -76,6 +76,7 @@ redist: autoload
cp -f $(CONFIG_PATH)/ncc.yaml $(GENERIC_BUILD_PATH)/CLI/template_config.yaml cp -f $(CONFIG_PATH)/ncc.yaml $(GENERIC_BUILD_PATH)/CLI/template_config.yaml
cp -f $(CONFIG_PATH)/default_repositories.json $(GENERIC_BUILD_PATH)/default_repositories.json cp -f $(CONFIG_PATH)/default_repositories.json $(GENERIC_BUILD_PATH)/default_repositories.json
cp -f $(INSTALLER_SRC_PATH)/ncc-package.xml $(GENERIC_BUILD_PATH)/ncc-package.xml cp -f $(INSTALLER_SRC_PATH)/ncc-package.xml $(GENERIC_BUILD_PATH)/ncc-package.xml
cp -f $(INSTALLER_SRC_PATH)/extension $(GENERIC_BUILD_PATH)/extension
chmod +x $(GENERIC_BUILD_PATH)/INSTALL chmod +x $(GENERIC_BUILD_PATH)/INSTALL
cp -f LICENSE $(GENERIC_BUILD_PATH)/LICENSE cp -f LICENSE $(GENERIC_BUILD_PATH)/LICENSE
cp -f README.md $(GENERIC_BUILD_PATH)/README.md cp -f README.md $(GENERIC_BUILD_PATH)/README.md

View file

@ -1,9 +0,0 @@
<?php
$autoload_path = __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'ncc' . DIRECTORY_SEPARATOR . 'autoload.php';
if(!file_exists($autoload_path))
{
throw new Exception("Autoload file not found");
}
require $autoload_path;

View file

@ -1,11 +0,0 @@
<phpunit bootstrap="bootstrap.php">
<testsuites>
<testsuite name="ncc Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<server name="KERNEL_DIR" value="app/"/>
</php>
</phpunit>

View file

@ -13,7 +13,7 @@
$third_party_path = __DIR__ . DIRECTORY_SEPARATOR . 'ThirdParty' . DIRECTORY_SEPARATOR; $third_party_path = __DIR__ . DIRECTORY_SEPARATOR . 'ThirdParty' . DIRECTORY_SEPARATOR;
$target_files = [ $target_files = [
__DIR__ . DIRECTORY_SEPARATOR . 'autoload_spl.php', __DIR__ . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'composer' . DIRECTORY_SEPARATOR . 'Semver' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'composer' . DIRECTORY_SEPARATOR . 'semver' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'defuse' . DIRECTORY_SEPARATOR . 'php-encryption' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'defuse' . DIRECTORY_SEPARATOR . 'php-encryption' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'jelix' . DIRECTORY_SEPARATOR . 'version' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'jelix' . DIRECTORY_SEPARATOR . 'version' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'nikic' . DIRECTORY_SEPARATOR . 'PhpParser' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'nikic' . DIRECTORY_SEPARATOR . 'PhpParser' . DIRECTORY_SEPARATOR . 'autoload_spl.php',

View file

@ -2,7 +2,7 @@ Package: ncc
Source: ncc Source: ncc
Section: devel Section: devel
Priority: optional Priority: optional
Version: 2.0.4 Version: 2.0.1
Maintainer: netkas <netkas@nosial.net> Maintainer: netkas <netkas@nosial.net>
Build-Depends: debhelper-compat (= 13) Build-Depends: debhelper-compat (= 13)
Standards-Version: 4.5.1 Standards-Version: 4.5.1

View file

@ -24,7 +24,7 @@
* @param array $options * @param array $options
* @return string * @return string
*/ */
function import(string $package, string $version=Versions::LATEST->value, array $options=[]): string function import(string $package, string $version=Versions::LATEST, array $options=[]): string
{ {
try try
{ {

View file

@ -41,7 +41,8 @@
'installer', 'installer',
'checksum.bin', 'checksum.bin',
'build_files', 'build_files',
'ncc.sh' 'ncc.sh',
'extension'
]; ];
ncc\Utilities\Console::out('Creating build_files ...'); ncc\Utilities\Console::out('Creating build_files ...');

View file

@ -242,6 +242,23 @@
$NCC_FILESYSTEM->mkdir($NCC_INSTALL_PATH, 0755); $NCC_FILESYSTEM->mkdir($NCC_INSTALL_PATH, 0755);
try
{
if(is_file(__DIR__ . DIRECTORY_SEPARATOR . 'default_repositories.json'))
{
Functions::initializeFiles(Functions::loadJsonFile(__DIR__ . DIRECTORY_SEPARATOR . 'default_repositories.json', Functions::FORCE_ARRAY));
}
else
{
Functions::initializeFiles();
}
}
catch(Exception $e)
{
Console::outException('Cannot initialize NCC files, ' . $e->getMessage(), $e, 1);
return;
}
// Copy files to the installation path // Copy files to the installation path
try try
{ {
@ -255,12 +272,10 @@
} }
$total_items = count($build_files); $total_items = count($build_files);
//$processed_items = 1; $processed_items = 1;
$progress_bar = new \ncc\Utilities\ConsoleProgressBar('Installing ncc', $total_items);
foreach ($build_files as $item) foreach ($build_files as $item)
{ {
$progress_bar->setMiscText($item, true);
$source = __DIR__ . DIRECTORY_SEPARATOR . $item; $source = __DIR__ . DIRECTORY_SEPARATOR . $item;
$destination = $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $item; $destination = $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $item;
@ -283,30 +298,8 @@
} }
} }
//++$processed_items; ++$processed_items;
//Console::inlineProgressBar($processed_items, $total_items); Console::inlineProgressBar($processed_items, $total_items);
$progress_bar->increaseValue(1, true);
}
$progress_bar->setMiscText('done', true);
unset($progress_bar);
// Initialize ncc's files
try
{
if(is_file(__DIR__ . DIRECTORY_SEPARATOR . 'default_repositories.json'))
{
Functions::initializeFiles($NCC_INSTALL_PATH, Functions::loadJsonFile(__DIR__ . DIRECTORY_SEPARATOR . 'default_repositories.json', Functions::FORCE_ARRAY));
}
else
{
Functions::initializeFiles($NCC_INSTALL_PATH);
}
}
catch(Exception $e)
{
Console::outException('Cannot initialize NCC files, ' . $e->getMessage(), $e, 1);
return;
} }
@ -352,6 +345,83 @@
} }
} }
// Register the ncc extension
try
{
Console::out('Registering extension');
$extension_shortcut = str_ireplace('%ncc_install', $NCC_INSTALL_PATH, IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'extension'));
}
catch(Exception $e)
{
Console::outException(sprintf('Failed to read file \'%s\', %s', __DIR__ . DIRECTORY_SEPARATOR . 'extension', $e->getMessage()), $e, 1);
return;
}
// Remove all the old extensions first.
/**
* @param string $path
* @param Filesystem $filesystem
* @param string $extension_shortcut
* @return bool
*/
function install_extension(string $path, Filesystem $filesystem, string $extension_shortcut): bool
{
if ($filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
{
$filesystem->remove($path . DIRECTORY_SEPARATOR . 'ncc');
}
try
{
IO::fwrite($path . DIRECTORY_SEPARATOR . 'ncc', $extension_shortcut);
}
catch (\ncc\Exceptions\IOException $e)
{
Console::outException($e->getMessage(), $e, 1);
return false;
}
return $filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc');
}
if(function_exists('get_include_path'))
{
$default_share = DIRECTORY_SEPARATOR . 'usr' . DIRECTORY_SEPARATOR . 'share' . DIRECTORY_SEPARATOR . 'php';
$include_paths = explode(':', get_include_path());
$extension_registered = false;
if(!in_array($default_share, $include_paths))
{
foreach($include_paths as $path)
{
if($extension_registered)
{
break;
}
switch($path)
{
// Ignore local files
case '.':
case '..':
break;
// First real include path is /usr/share/php
default:
// Install the extension
$extension_registered = install_extension($path, $NCC_FILESYSTEM, $extension_shortcut);
break;
}
}
}
else
{
// Remove the old extension
install_extension($default_share, $NCC_FILESYSTEM, $extension_shortcut);
}
}
// Backup the configuration file // Backup the configuration file
$config_backup = null; $config_backup = null;

View file

@ -21,11 +21,11 @@
--> -->
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/ncc"> <mime-type type="application/ncc-package">
<comment>ncc package binary</comment> <comment>ncc package binary</comment>
<magic priority="50"> <magic priority="50">
<match type="string" value="ncc_pkg" offset="0"/> <match type="string" value="ncc_pkg" offset="0"/>
</magic> </magic>
<glob pattern="*.ncc"/> <glob pattern="*.ncc_pkg"/>
</mime-type> </mime-type>
</mime-info> </mime-info>

View file

@ -75,7 +75,7 @@
if($output_path !== null) if($output_path !== null)
{ {
$options[BuildConfigurationOptions::OUTPUT_FILE->value] = $output_path; $options[BuildConfigurationOptions::OUTPUT_FILE] = $output_path;
} }
// Load the project // Load the project
@ -92,7 +92,7 @@
// Build the project // Build the project
try try
{ {
$build_configuration = $args['config'] ?? $args['c'] ?? BuildConfigurationValues::DEFAULT->value; $build_configuration = $args['config'] ?? $args['c'] ?? BuildConfigurationValues::DEFAULT;
$output = $project_manager->build($build_configuration, $options); $output = $project_manager->build($build_configuration, $options);
} }
catch (Exception $e) catch (Exception $e)

View file

@ -24,11 +24,9 @@
use Exception; use Exception;
use ncc\Classes\Runtime; use ncc\Classes\Runtime;
use ncc\CLI\Main;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\Resolver;
class ExecCommand class ExecCommand
{ {
@ -42,12 +40,6 @@
{ {
$package = $args['package'] ?? null; $package = $args['package'] ?? null;
$version = $args['exec-version'] ?? 'latest'; $version = $args['exec-version'] ?? 'latest';
$program_arguments = [];
if(isset($args['exec-args']))
{
$program_arguments = Resolver::splitArguments(Main::getRawArgs(), '--exec-args');
}
if($package === null) if($package === null)
{ {
@ -66,7 +58,7 @@
try try
{ {
return Runtime::execute($package_name, $program_arguments); return Runtime::execute($package_name);
} }
catch(Exception $e) catch(Exception $e)
{ {

View file

@ -58,7 +58,7 @@
try try
{ {
Functions::initializeFiles(null, $default_repositories); Functions::initializeFiles($default_repositories);
} }
catch(Exception $e) catch(Exception $e)
{ {

View file

@ -50,12 +50,7 @@
private static $args; private static $args;
/** /**
* @var array * @var string|null
*/
private static $raw_args;
/**
* @var LogLevel|null
*/ */
private static $log_level; private static $log_level;
@ -68,7 +63,6 @@
public static function start(array $argv): int public static function start(array $argv): int
{ {
self::$args = Resolver::parseArguments(implode(' ', $argv)); self::$args = Resolver::parseArguments(implode(' ', $argv));
self::$raw_args = $argv;
if(!isset(self::$args['ncc-cli'])) if(!isset(self::$args['ncc-cli']))
{ {
@ -97,14 +91,30 @@
if(isset(self::$args['l']) || isset(self::$args['log-level'])) if(isset(self::$args['l']) || isset(self::$args['log-level']))
{ {
self::$log_level = LogLevel::fromOrDefault(strtolower(self::$args['l'] ?? self::$args['log-level'])); switch(strtolower(self::$args['l'] ?? self::$args['log-level']))
{
case LogLevel::SILENT:
case LogLevel::FATAL:
case LogLevel::ERROR:
case LogLevel::WARNING:
case LogLevel::INFO:
case LogLevel::DEBUG:
case LogLevel::VERBOSE:
self::$log_level = strtolower(self::$args['l'] ?? self::$args['log-level']);
break;
default:
Console::outWarning('Unknown log level: ' . (self::$args['l'] ?? self::$args['log-level']) . ', using \'info\'');
self::$log_level = LogLevel::INFO;
break;
}
} }
else else
{ {
self::$log_level = LogLevel::INFO; self::$log_level = LogLevel::INFO;
} }
if(self::$log_level->checkLogLevel(LogLevel::DEBUG)) if(Resolver::checkLogLevel(self::$log_level, LogLevel::DEBUG))
{ {
Console::outDebug('Debug logging enabled'); Console::outDebug('Debug logging enabled');
@ -115,12 +125,12 @@
Console::outDebug(sprintf('args: %s', json_encode(self::$args, JSON_UNESCAPED_SLASHES))); Console::outDebug(sprintf('args: %s', json_encode(self::$args, JSON_UNESCAPED_SLASHES)));
} }
if(in_array(NccBuildFlags::UNSTABLE->value, NCC_VERSION_FLAGS, true)) if(in_array(NccBuildFlags::UNSTABLE, NCC_VERSION_FLAGS, true))
{ {
Console::outWarning('This is an unstable build of ncc, expect some features to not work as expected'); Console::outWarning('This is an unstable build of ncc, expect some features to not work as expected');
} }
if(in_array(NccBuildFlags::BETA->value, NCC_VERSION_FLAGS, true)) if(in_array(NccBuildFlags::BETA, NCC_VERSION_FLAGS, true))
{ {
Console::outWarning('This is a beta build of ncc, expect some features to not work as expected'); Console::outWarning('This is a beta build of ncc, expect some features to not work as expected');
} }
@ -220,19 +230,9 @@
} }
/** /**
* Returns the raw arguments passed to ncc * @return string
*
* @return array
*/ */
public static function getRawArgs(): array public static function getLogLevel(): string
{
return self::$raw_args;
}
/**
* @return LogLevel
*/
public static function getLogLevel(): LogLevel
{ {
if(self::$log_level === null) if(self::$log_level === null)
{ {

View file

@ -101,7 +101,7 @@
if(isset($args['v'])) if(isset($args['v']))
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('Insufficient permissions, cannot modify configuration values', true, 1); Console::outError('Insufficient permissions, cannot modify configuration values', true, 1);
return 1; return 1;

View file

@ -187,7 +187,7 @@
{ {
$ResolvedScope = Resolver::resolveScope(); $ResolvedScope = Resolver::resolveScope();
if($ResolvedScope !== Scopes::SYSTEM->value) if($ResolvedScope !== Scopes::SYSTEM)
{ {
Console::outError('Insufficient permissions to add entries'); Console::outError('Insufficient permissions to add entries');
} }
@ -313,7 +313,7 @@
{ {
$ResolvedScope = Resolver::resolveScope(); $ResolvedScope = Resolver::resolveScope();
if($ResolvedScope !== Scopes::SYSTEM->value) if($ResolvedScope !== Scopes::SYSTEM)
{ {
Console::outError('Insufficient permissions to remove entries'); Console::outError('Insufficient permissions to remove entries');
} }

View file

@ -132,7 +132,7 @@
*/ */
private static function installPackage(array $args): int private static function installPackage(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You cannot install packages in a user scope, please run this command as root', true, 1); Console::outError('You cannot install packages in a user scope, please run this command as root', true, 1);
return 1; return 1;
@ -145,32 +145,16 @@
$repository_manager = new RepositoryManager(); $repository_manager = new RepositoryManager();
$package_manager = new PackageManager(); $package_manager = new PackageManager();
if($package === null)
{
Console::outError('No package specified', true, 1);
return 1;
}
$options = []; $options = [];
if(isset($args['reinstall'])) if(isset($args['reinstall']))
{ {
$options[InstallPackageOptions::REINSTALL->value] = true; $options[InstallPackageOptions::REINSTALL] = true;
}
if(isset($args['prefer-static']) || isset($args['static']))
{
$options[InstallPackageOptions::PREFER_STATIC->value] = true;
} }
if(isset($args['skip-dependencies'])) if(isset($args['skip-dependencies']))
{ {
$options[InstallPackageOptions::SKIP_DEPENDENCIES->value] = true; $options[InstallPackageOptions::SKIP_DEPENDENCIES] = true;
}
if(isset($args['build-source']))
{
$options[InstallPackageOptions::BUILD_SOURCE->value] = true;
} }
if($authentication !== null) if($authentication !== null)
@ -204,7 +188,7 @@
$authentication_entry = $entry->getPassword(); $authentication_entry = $entry->getPassword();
} }
if(preg_match(RegexPatterns::REMOTE_PACKAGE->value, $package) === 1) if(preg_match(RegexPatterns::REMOTE_PACKAGE, $package) === 1)
{ {
$package_input = RemotePackageInput::fromString($package); $package_input = RemotePackageInput::fromString($package);
@ -393,7 +377,7 @@
*/ */
private static function uninstallPackage($args): int private static function uninstallPackage($args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You cannot uninstall packages in a user scope, please run this command as root', true, 1); Console::outError('You cannot uninstall packages in a user scope, please run this command as root', true, 1);
return 1; return 1;
@ -424,7 +408,7 @@
*/ */
private static function uninstallAllPackages(array $args): int private static function uninstallAllPackages(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You cannot uninstall all packages in a user scope, please run this command as root', true, 1); Console::outError('You cannot uninstall all packages in a user scope, please run this command as root', true, 1);
return 1; return 1;
@ -460,7 +444,7 @@
*/ */
private static function fixBrokenPackages(array $args): int private static function fixBrokenPackages(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You cannot fix broken packages in a user scope, please run this command as root', true, 1); Console::outError('You cannot fix broken packages in a user scope, please run this command as root', true, 1);
return 1; return 1;
@ -564,8 +548,6 @@
new CliHelpSection(['install', '--package', '-p', '--version', '-v'], 'Installs a specified ncc package version'), new CliHelpSection(['install', '--package', '-p', '--version', '-v'], 'Installs a specified ncc package version'),
new CliHelpSection(['install', '-p', '--skip-dependencies'], 'Installs a specified ncc package but skips the installation of dependencies'), new CliHelpSection(['install', '-p', '--skip-dependencies'], 'Installs a specified ncc package but skips the installation of dependencies'),
new CliHelpSection(['install', '-p', '--reinstall'], 'Installs a specified ncc package, reinstall if already installed'), new CliHelpSection(['install', '-p', '--reinstall'], 'Installs a specified ncc package, reinstall if already installed'),
new CliHelpSection(['install', '--prefer-static', '--static'], 'Installs a static version of the package from the remote repository if available'),
new CliHelpSection(['install', '--build-source'], 'Forces ncc to build the packages from source rather than trying to use a pre-built binary'),
new CliHelpSection(['uninstall', '--package', '-p'], 'Uninstalls a specified ncc package'), new CliHelpSection(['uninstall', '--package', '-p'], 'Uninstalls a specified ncc package'),
new CliHelpSection(['uninstall', '--package', '-p', '--version', '-v'], 'Uninstalls a specified ncc package version'), new CliHelpSection(['uninstall', '--package', '-p', '--version', '-v'], 'Uninstalls a specified ncc package version'),
new CliHelpSection(['uninstall-all'], 'Uninstalls all packages'), new CliHelpSection(['uninstall-all'], 'Uninstalls all packages'),

View file

@ -23,7 +23,6 @@
namespace ncc\CLI\Management; namespace ncc\CLI\Management;
use Exception; use Exception;
use ncc\Enums\CompilerExtensions;
use ncc\Enums\ProjectTemplates; use ncc\Enums\ProjectTemplates;
use ncc\Enums\Scopes; use ncc\Enums\Scopes;
use ncc\Managers\CredentialManager; use ncc\Managers\CredentialManager;
@ -103,12 +102,7 @@
if(isset($args['ext'])) if(isset($args['ext']))
{ {
$compiler_extension = CompilerExtensions::tryFrom($args['ext']); $compiler_extension = $args['ext'];
if($compiler_extension === null)
{
Console::outError('Invalid compiler extension, please specify a valid compiler extension', true, 1);
return 1;
}
} }
else else
{ {
@ -140,7 +134,7 @@
*/ */
private static function installProject(array $args): int private static function installProject(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You cannot install packages in a user scope, please run this command as root', true, 1); Console::outError('You cannot install packages in a user scope, please run this command as root', true, 1);
return 1; return 1;
@ -298,9 +292,9 @@
} }
Console::out(PHP_EOL . 'Available Templates:'); Console::out(PHP_EOL . 'Available Templates:');
foreach(ProjectTemplates::cases() as $template) foreach(ProjectTemplates::ALL as $template)
{ {
Console::out(' ' . $template->value); Console::out(' ' . $template);
} }
return 0; return 0;

View file

@ -25,7 +25,6 @@
use Exception; use Exception;
use ncc\Enums\ConsoleColors; use ncc\Enums\ConsoleColors;
use ncc\Enums\Scopes; use ncc\Enums\Scopes;
use ncc\Enums\Types\RepositoryType;
use ncc\Managers\RepositoryManager; use ncc\Managers\RepositoryManager;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Objects\RepositoryConfiguration; use ncc\Objects\RepositoryConfiguration;
@ -119,7 +118,7 @@
$output = sprintf('%s (%s) [%s]', $output = sprintf('%s (%s) [%s]',
$source->getName(), $source->getName(),
Console::formatColor($source->getHost(), ConsoleColors::GREEN), Console::formatColor($source->getHost(), ConsoleColors::GREEN),
Console::formatColor($source->getType()->value, ConsoleColors::YELLOW) Console::formatColor($source->getType(), ConsoleColors::YELLOW)
); );
if(!$source->isSsl()) if(!$source->isSsl())
@ -142,7 +141,7 @@
*/ */
private static function addEntry(array $args): int private static function addEntry(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You must be running as root to add a new repository', true, 1); Console::outError('You must be running as root to add a new repository', true, 1);
return 1; return 1;
@ -165,13 +164,6 @@
return 1; return 1;
} }
$parsed_type = RepositoryType::tryFrom($type);
if($parsed_type === null)
{
Console::outError(sprintf('Unknown repository type \'%s\'.', $type), true, 1);
return 1;
}
if($host === null) if($host === null)
{ {
Console::outError(sprintf('Missing required argument \'%s\'.', 'host'), true, 1); Console::outError(sprintf('Missing required argument \'%s\'.', 'host'), true, 1);
@ -180,7 +172,7 @@
try try
{ {
(new RepositoryManager())->addRepository(new RepositoryConfiguration($name, $host, $parsed_type, $ssl)); (new RepositoryManager())->addRepository(new RepositoryConfiguration($name, $host, $type, $ssl));
} }
catch(Exception $e) catch(Exception $e)
{ {
@ -238,7 +230,7 @@
*/ */
private static function removeEntry(array $args): int private static function removeEntry(array $args): int
{ {
if(Resolver::resolveScope() !== Scopes::SYSTEM->value) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
Console::outError('You must be running as root to remove a repository', true, 1); Console::outError('You must be running as root to remove a repository', true, 1);
return 1; return 1;

View file

@ -31,7 +31,6 @@
use ncc\Classes\PhpExtension\PhpRunner; use ncc\Classes\PhpExtension\PhpRunner;
use ncc\Enums\Runners; use ncc\Enums\Runners;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IntegrityException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException; use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException; use ncc\Exceptions\OperationException;
@ -55,11 +54,11 @@
{ {
$bin = match($unit->getExecutionPolicy()->getRunner()) $bin = match($unit->getExecutionPolicy()->getRunner())
{ {
Runners::PHP->value => (new ExecutableFinder())->find('php'), Runners::PHP => (new ExecutableFinder())->find('php'),
Runners::BASH->value => (new ExecutableFinder())->find('bash'), Runners::BASH => (new ExecutableFinder())->find('bash'),
Runners::PYTHON->value => (new ExecutableFinder())->find('python'), Runners::PYTHON => (new ExecutableFinder())->find('python'),
Runners::LUA->value => (new ExecutableFinder())->find('lua'), Runners::LUA => (new ExecutableFinder())->find('lua'),
Runners::PERL->value => (new ExecutableFinder())->find('perl'), Runners::PERL => (new ExecutableFinder())->find('perl'),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $unit->getExecutionPolicy()->getName(), $unit->getExecutionPolicy()->getRunner())) default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $unit->getExecutionPolicy()->getName(), $unit->getExecutionPolicy()->getRunner()))
}; };
@ -77,19 +76,11 @@
{ {
$process->setTimeout($unit->getExecutionPolicy()->getExecute()->getTimeout()); $process->setTimeout($unit->getExecutionPolicy()->getExecute()->getTimeout());
} }
else
{
$process->setTimeout(null);
}
if($unit->getExecutionPolicy()->getExecute()->getIdleTimeout() !== null) if($unit->getExecutionPolicy()->getExecute()->getIdleTimeout() !== null)
{ {
$process->setIdleTimeout($unit->getExecutionPolicy()->getExecute()->getIdleTimeout()); $process->setIdleTimeout($unit->getExecutionPolicy()->getExecute()->getIdleTimeout());
} }
else
{
$process->setIdleTimeout(null);
}
return $process; return $process;
} }
@ -118,8 +109,8 @@
$execution_unit = ExecutionUnit::fromArray(ZiProto::decode(IO::fread($unit_path))); $execution_unit = ExecutionUnit::fromArray(ZiProto::decode(IO::fread($unit_path)));
return match ($execution_unit->getExecutionPolicy()->getRunner()) return match ($execution_unit->getExecutionPolicy()->getRunner())
{ {
Runners::PHP->value => PhpRunner::executeUnit($execution_unit, $args), Runners::PHP => PhpRunner::executeUnit($execution_unit, $args),
Runners::BASH->value => BashRunner::executeUnit($execution_unit, $args), Runners::BASH => BashRunner::executeUnit($execution_unit, $args),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())), default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())),
}; };
} }
@ -138,7 +129,6 @@
* @return int * @return int
* @throws ConfigurationException * @throws ConfigurationException
* @throws OperationException * @throws OperationException
* @throws IntegrityException
*/ */
public static function executeFromPackage(PackageReader $package_reader, string $policy_name, array $args=[]): int public static function executeFromPackage(PackageReader $package_reader, string $policy_name, array $args=[]): int
{ {
@ -148,8 +138,8 @@
{ {
return match ($execution_unit->getExecutionPolicy()->getRunner()) return match ($execution_unit->getExecutionPolicy()->getRunner())
{ {
Runners::PHP->value => PhpRunner::executeUnit($execution_unit, $args, false), Runners::PHP => PhpRunner::executeUnit($execution_unit, $args, false),
Runners::BASH->value => BashRunner::executeUnit($execution_unit, $args), Runners::BASH => BashRunner::executeUnit($execution_unit, $args),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())), default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())),
}; };
} }

View file

@ -25,7 +25,6 @@
use CurlHandle; use CurlHandle;
use Exception; use Exception;
use JsonException; use JsonException;
use ncc\Enums\Options\InstallPackageOptions;
use ncc\Enums\Types\AuthenticationType; use ncc\Enums\Types\AuthenticationType;
use ncc\Enums\Types\HttpRequestType; use ncc\Enums\Types\HttpRequestType;
use ncc\Enums\Types\RepositoryResultType; use ncc\Enums\Types\RepositoryResultType;
@ -39,7 +38,6 @@
use ncc\Objects\Vault\Password\AccessToken; use ncc\Objects\Vault\Password\AccessToken;
use ncc\Objects\Vault\Password\UsernamePassword; use ncc\Objects\Vault\Password\UsernamePassword;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache; use ncc\Utilities\RuntimeCache;
use RuntimeException; use RuntimeException;
@ -48,7 +46,7 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST->value, ?AuthenticationType $authentication=null, array $options=[]): RepositoryResult public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST, ?AuthenticationType $authentication=null): RepositoryResult
{ {
try try
{ {
@ -65,9 +63,9 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST->value, ?AuthenticationType $authentication=null, array $options=[]): RepositoryResult public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST, ?AuthenticationType $authentication=null): RepositoryResult
{ {
return self::getReleasePackage($repository, $vendor, $project, $version, $authentication, $options); return self::getReleasePackage($repository, $vendor, $project, $version, $authentication);
} }
/** /**
@ -98,21 +96,15 @@
'User-Agent: ncc' 'User-Agent: ncc'
]; ];
if($authentication !== null) if($authentication !== null)
{ {
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -169,7 +161,7 @@
*/ */
private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication=null): RepositoryResult private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication=null): RepositoryResult
{ {
if($tag === Versions::LATEST->value) if($tag === Versions::LATEST)
{ {
$tag = self::getLatestTag($repository, $group, $project, $authentication); $tag = self::getLatestTag($repository, $group, $project, $authentication);
} }
@ -193,17 +185,10 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_URL => $endpoint, CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -212,11 +197,11 @@
if(isset($response['zipball_url'])) if(isset($response['zipball_url']))
{ {
$result = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE->value, $tag); $result = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE, $tag);
} }
elseif(isset($response['tarball_url'])) elseif(isset($response['tarball_url']))
{ {
$result = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE->value, $tag); $result = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE, $tag);
} }
else else
{ {
@ -260,17 +245,10 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_URL => $endpoint, CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -320,124 +298,14 @@
* @param string $project The project to get the release for (eg; "ncc" or "libs/config") * @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0") * @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used. * @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @param array $options Optional. An array of options to use when fetching the package
* @return RepositoryResult The URL to the archive * @return RepositoryResult The URL to the archive
* @throws AuthenticationException * @throws AuthenticationException
* @throws NetworkException * @throws NetworkException
*/ */
private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null, array $options=[]): RepositoryResult private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{ {
/** @noinspection DuplicatedCode */ /** @noinspection DuplicatedCode */
if($release === Versions::LATEST->value) if($release === Versions::LATEST)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$endpoint = sprintf('%s://%s/api/v1/repos/%s/%s/releases/tags/%s',
$repository->isSsl() ? 'https' : 'http',
$repository->getHost(),
rawurlencode($group),
rawurlencode($project),
rawurlencode($release)
);
if(RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: ncc'
];
if($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
}
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [
CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value,
CURLOPT_HTTPHEADER => $headers
]);
Console::outDebug(sprintf('Fetching release package for %s/%s/%s from %s',
$group, $project, $release, $endpoint));
$response = self::processHttpResponse($curl, $group, $project);
if(!isset($response['assets']))
{
throw new NetworkException(sprintf('Failed to get release %s package url for %s/%s',
$release, $group, $project));
}
$static_preferred = isset($options[InstallPackageOptions::PREFER_STATIC->value]);
$preferred_asset = null;
$fallback_asset = null;
foreach($response['assets'] as $asset)
{
if($static_preferred && preg_match('/(_static|-static)\.ncc$/', $asset['name']))
{
$preferred_asset = $asset;
}
elseif(preg_match('/\.ncc$/', $asset['name']))
{
$fallback_asset = $asset;
}
}
$target_asset = $preferred_asset ?: $fallback_asset;
if($target_asset)
{
$asset_url = $target_asset['browser_download_url'] ?? null;
if($asset_url)
{
$result = new RepositoryResult($asset_url, RepositoryResultType::PACKAGE->value, $release);
RuntimeCache::set($endpoint, $result);
return $result;
}
throw new NetworkException(sprintf('No direct asset URL found for %s/%s/%s', $group, $project, $release));
}
throw new NetworkException(sprintf('No ncc package found for %s/%s/%s', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @param array $options Optional. An array of options to use when fetching the archive
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{
/** @noinspection DuplicatedCode */
if ($release === Versions::LATEST->value)
{ {
$release = self::getLatestRelease($repository, $group, $project, $authentication); $release = self::getLatestRelease($repository, $group, $project, $authentication);
} }
@ -461,17 +329,80 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint); curl_setopt_array($curl, [
CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers
]);
if($resolved_host !== null) Console::outDebug(sprintf('Fetching release package for %s/%s/%s from %s', $group, $project, $release, $endpoint));
$response = self::processHttpResponse($curl, $group, $project);
if(!isset($response['assets']))
{ {
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]); throw new NetworkException(sprintf('Failed to get release %s package url for %s/%s', $release, $group, $project));
}
foreach($response['assets'] as $asset)
{
if(isset($asset['name'], $asset['browser_download_url']) && preg_match('/\.ncc$/', $asset['name']))
{
$result = new RepositoryResult($asset['browser_download_url'], RepositoryResultType::PACKAGE, $release);
RuntimeCache::set($endpoint, $result);
return $result;
}
}
throw new NetworkException(sprintf('No ncc package found for %s/%s/%s', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{
/** @noinspection DuplicatedCode */
if ($release === Versions::LATEST)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$endpoint = sprintf('%s://%s/api/v1/repos/%s/%s/releases/tags/%s', ($repository->isSsl() ? 'https' : 'http'), $repository->getHost(), rawurlencode($group), rawurlencode($project), rawurlencode($release));
if (RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: ncc'
];
if ($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
} }
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_URL => $endpoint, CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -480,11 +411,11 @@
if(isset($response['zipball_url'])) if(isset($response['zipball_url']))
{ {
$results = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE->value, $release); $results = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE, $release);
} }
elseif(isset($response['tarball_url'])) elseif(isset($response['tarball_url']))
{ {
$results = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE->value, $release); $results = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE, $release);
} }
else else
{ {
@ -515,7 +446,7 @@
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()));
case AuthenticationType::USERNAME_PASSWORD: case AuthenticationType::USERNAME_PASSWORD:
if($authentication instanceof UsernamePassword) if($authentication instanceof UsernamePassword)
@ -524,7 +455,7 @@
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()));
} }
return $headers; return $headers;
@ -552,14 +483,14 @@
if($response === false) if($response === false)
{ {
Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $group, $project, curl_error($curl), $retry_count + 1)); Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $vendor, $project, curl_error($curl), $retry_count + 1));
$retry_count++; $retry_count++;
} }
} }
if($response === false) if($response === false)
{ {
throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $group, $project, curl_error($curl))); throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $vendor, $project, curl_error($curl)));
} }
switch(curl_getinfo($curl, CURLINFO_HTTP_CODE)) switch(curl_getinfo($curl, CURLINFO_HTTP_CODE))

View file

@ -25,7 +25,6 @@
use CurlHandle; use CurlHandle;
use Exception; use Exception;
use JsonException; use JsonException;
use ncc\Enums\Options\InstallPackageOptions;
use ncc\Enums\Types\AuthenticationType; use ncc\Enums\Types\AuthenticationType;
use ncc\Enums\Types\HttpRequestType; use ncc\Enums\Types\HttpRequestType;
use ncc\Enums\Types\RepositoryResultType; use ncc\Enums\Types\RepositoryResultType;
@ -47,7 +46,7 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST->value, ?AuthenticationType $authentication=null, array $options=[]): RepositoryResult public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST, ?AuthenticationType $authentication=null): RepositoryResult
{ {
try try
{ {
@ -64,9 +63,9 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST->value, ?AuthenticationType $authentication = null, array $options=[]): RepositoryResult public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST, ?AuthenticationType $authentication = null): RepositoryResult
{ {
return self::getReleasePackage($repository, $vendor, $project, $version, $authentication, $options); return self::getReleasePackage($repository, $vendor, $project, $version, $authentication);
} }
/** /**
@ -104,7 +103,7 @@
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -161,7 +160,7 @@
*/ */
private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication = null): RepositoryResult private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication = null): RepositoryResult
{ {
if($tag === Versions::LATEST->value) if($tag === Versions::LATEST)
{ {
$tag = self::getLatestTag($repository, $group, $project, $authentication); $tag = self::getLatestTag($repository, $group, $project, $authentication);
} }
@ -186,7 +185,7 @@
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_NOBODY => true, CURLOPT_NOBODY => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers, CURLOPT_HTTPHEADER => $headers,
CURLOPT_FOLLOWLOCATION => true CURLOPT_FOLLOWLOCATION => true
]); ]);
@ -207,7 +206,7 @@
throw new NetworkException(sprintf('Server responded with HTTP code %s when getting tag archive for %s/%s/%s', $http_code, $group, $project, $tag)); throw new NetworkException(sprintf('Server responded with HTTP code %s when getting tag archive for %s/%s/%s', $http_code, $group, $project, $tag));
} }
$result = new RepositoryResult(curl_getinfo($curl, CURLINFO_EFFECTIVE_URL), RepositoryResultType::SOURCE->value, $tag); $result = new RepositoryResult(curl_getinfo($curl, CURLINFO_EFFECTIVE_URL), RepositoryResultType::SOURCE, $tag);
curl_close($curl); curl_close($curl);
RuntimeCache::set($endpoint, $result); RuntimeCache::set($endpoint, $result);
@ -249,7 +248,7 @@
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -299,97 +298,14 @@
* @param string $project The project to get the release for (eg; "ncc" or "libs/config") * @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0") * @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used. * @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @param array $options Optional. An array of options to use when fetching the package
* @return RepositoryResult The URL to the archive * @return RepositoryResult The URL to the archive
* @throws AuthenticationException * @throws AuthenticationException
* @throws NetworkException * @throws NetworkException
*/ */
private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null, array $options=[]): RepositoryResult private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{ {
/** @noinspection DuplicatedCode */ /** @noinspection DuplicatedCode */
if($release === Versions::LATEST->value) if($release === Versions::LATEST)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$endpoint = sprintf('%s://%s/repos/%s/%s/releases/tags/%s', $repository->isSsl() ? 'https' : 'http', $repository->getHost(), $group, $project, $release);
if(RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Accept: application/vnd.github+json',
'X-GitHub-Api-Version: 2022-11-28',
'User-Agent: ncc'
];
if($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
}
curl_setopt_array($curl, [CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_HTTPHEADER => $headers]);
Console::outDebug(sprintf('Fetching release package for %s/%s/%s from %s', $group, $project, $release, $endpoint));
$response = self::processHttpResponse($curl, $group, $project);
if(!isset($response['assets']))
{
throw new NetworkException(sprintf('Failed to get release package for %s/%s/%s: No assets found', $group, $project, $release));
}
$static_preferred = isset($options[InstallPackageOptions::PREFER_STATIC->value]);
$preferred_asset = null;
$fallback_asset = null;
foreach($response['assets'] as $asset)
{
if($static_preferred && preg_match('/(_static|-static)\.ncc$/', $asset['name']))
{
$preferred_asset = $asset;
}
elseif(preg_match('/\.ncc$/', $asset['name']))
{
$fallback_asset = $asset;
}
}
$target_asset = $preferred_asset ?: $fallback_asset;
if($target_asset)
{
$asset_url = $target_asset['browser_download_url'];
$result = new RepositoryResult($asset_url, RepositoryResultType::PACKAGE->value, $release);
RuntimeCache::set($endpoint, $result);
return $result;
}
throw new NetworkException(sprintf('Failed to get release package for %s/%s/%s: No assets found', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication = null): RepositoryResult
{
/** @noinspection DuplicatedCode */
if($release === Versions::LATEST->value)
{ {
$release = self::getLatestRelease($repository, $group, $project, $authentication); $release = self::getLatestRelease($repository, $group, $project, $authentication);
} }
@ -415,7 +331,76 @@
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers
]);
Console::outDebug(sprintf('Fetching release package for %s/%s/%s from %s', $group, $project, $release, $endpoint));
$response = self::processHttpResponse($curl, $group, $project);
if(!isset($response['assets']))
{
throw new NetworkException(sprintf('Failed to get release package for %s/%s/%s: No assets found', $group, $project, $release));
}
foreach($response['assets'] as $asset)
{
if(preg_match('/\.ncc$/', $asset['name']) === 1)
{
$result = new RepositoryResult($asset['browser_download_url'], RepositoryResultType::PACKAGE, $release);
RuntimeCache::set($endpoint, $result);
return $result;
}
}
throw new NetworkException(sprintf('Failed to get release package for %s/%s/%s: No assets found', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication = null): RepositoryResult
{
/** @noinspection DuplicatedCode */
if($release === Versions::LATEST)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$endpoint = sprintf('%s://%s/repos/%s/%s/releases/tags/%s', ($repository->isSsl() ? 'https' : 'http'), $repository->getHost(), $group, $project, $release);
if(RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Accept: application/vnd.github+json',
'X-GitHub-Api-Version: 2022-11-28',
'User-Agent: ncc'
];
if($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -425,11 +410,11 @@
if(isset($response['zipball_url'])) if(isset($response['zipball_url']))
{ {
$result = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE->value, $release); $result = new RepositoryResult($response['zipball_url'], RepositoryResultType::SOURCE, $release);
} }
elseif(isset($response['tarball_url'])) elseif(isset($response['tarball_url']))
{ {
$result = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE->value, $release); $result = new RepositoryResult($response['tarball_url'], RepositoryResultType::SOURCE, $release);
} }
else else
{ {
@ -459,7 +444,7 @@
$headers[] = 'Authorization: Bearer ' . $authentication->getAccessToken(); $headers[] = 'Authorization: Bearer ' . $authentication->getAccessToken();
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()));
case AuthenticationType::USERNAME_PASSWORD: case AuthenticationType::USERNAME_PASSWORD:
if($authentication instanceof UsernamePassword) if($authentication instanceof UsernamePassword)
@ -468,7 +453,7 @@
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()));
} }
return $headers; return $headers;
@ -496,14 +481,14 @@
if($response === false) if($response === false)
{ {
Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $group, $project, curl_error($curl), $retry_count + 1)); Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $vendor, $project, curl_error($curl), $retry_count + 1));
$retry_count++; $retry_count++;
} }
} }
if($response === false) if($response === false)
{ {
throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $group, $project, curl_error($curl))); throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $vendor, $project, curl_error($curl)));
} }
switch (curl_getinfo($curl, CURLINFO_HTTP_CODE)) switch (curl_getinfo($curl, CURLINFO_HTTP_CODE))

View file

@ -25,7 +25,6 @@
use CurlHandle; use CurlHandle;
use Exception; use Exception;
use JsonException; use JsonException;
use ncc\Enums\Options\InstallPackageOptions;
use ncc\Enums\Types\AuthenticationType; use ncc\Enums\Types\AuthenticationType;
use ncc\Enums\Types\HttpRequestType; use ncc\Enums\Types\HttpRequestType;
use ncc\Enums\Types\RepositoryResultType; use ncc\Enums\Types\RepositoryResultType;
@ -39,7 +38,6 @@
use ncc\Objects\Vault\Password\AccessToken; use ncc\Objects\Vault\Password\AccessToken;
use ncc\Objects\Vault\Password\UsernamePassword; use ncc\Objects\Vault\Password\UsernamePassword;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache; use ncc\Utilities\RuntimeCache;
use RuntimeException; use RuntimeException;
@ -48,7 +46,7 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST->value, ?AuthenticationType $authentication=null, array $options=[]): RepositoryResult public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST, ?AuthenticationType $authentication=null): RepositoryResult
{ {
try try
{ {
@ -65,9 +63,9 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST->value, ?AuthenticationType $authentication=null, array $options=[]): RepositoryResult public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version=Versions::LATEST, ?AuthenticationType $authentication=null): RepositoryResult
{ {
return self::getReleasePackage($repository, $vendor, $project, $version, $authentication, $options); return self::getReleasePackage($repository, $vendor, $project, $version, $authentication);
} }
/** /**
@ -104,17 +102,10 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_URL => $endpoint, CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -172,7 +163,7 @@
*/ */
private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication=null): RepositoryResult private static function getTagArchive(RepositoryConfiguration $repository, string $group, string $project, string $tag, ?AuthenticationInterface $authentication=null): RepositoryResult
{ {
if($tag === Versions::LATEST->value) if($tag === Versions::LATEST)
{ {
$tag = self::getLatestTag($repository, $group, $project, $authentication); $tag = self::getLatestTag($repository, $group, $project, $authentication);
} }
@ -195,17 +186,10 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_NOBODY => true, CURLOPT_NOBODY => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers, CURLOPT_HTTPHEADER => $headers,
CURLOPT_FOLLOWLOCATION => true CURLOPT_FOLLOWLOCATION => true
]); ]);
@ -225,7 +209,7 @@
throw new NetworkException(sprintf('Server responded with HTTP code %s when getting tag archive for %s/%s/%s', $http_code, $group, $project, $tag)); throw new NetworkException(sprintf('Server responded with HTTP code %s when getting tag archive for %s/%s/%s', $http_code, $group, $project, $tag));
} }
$results = new RepositoryResult(curl_getinfo($curl, CURLINFO_EFFECTIVE_URL), RepositoryResultType::SOURCE->value, $tag); $results = new RepositoryResult(curl_getinfo($curl, CURLINFO_EFFECTIVE_URL), RepositoryResultType::SOURCE, $tag);
RuntimeCache::set($endpoint, $results); RuntimeCache::set($endpoint, $results);
return $results; return $results;
@ -265,16 +249,9 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -323,106 +300,14 @@
* @param string $project The project to get the release for (eg; "ncc" or "libs/config") * @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0") * @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used. * @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @param array $options Optional. The options to use for the request
* @return RepositoryResult The URL to the archive * @return RepositoryResult The URL to the archive
* @throws AuthenticationException * @throws AuthenticationException
* @throws NetworkException * @throws NetworkException
*/ */
private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null, array $options=[]): RepositoryResult private static function getReleasePackage(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{
if($release === Versions::LATEST->value)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$project = str_replace('.', '/', $project);
$endpoint = sprintf('%s://%s/api/v4/projects/%s%%2F%s/releases/%s', $repository->isSsl() ? 'https' : 'http', $repository->getHost(), $group, rawurlencode($project), rawurlencode($release));
if(RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: ncc'
];
if($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
}
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value,
CURLOPT_HTTPHEADER => $headers
]);
$response = self::processHttpResponse($curl, $group, $project);
$static_preferred = isset($options[InstallPackageOptions::PREFER_STATIC->value]);
$preferred_asset = null;
$fallback_asset = null;
foreach($response['assets']['links'] as $asset)
{
if($static_preferred && preg_match('/(_static|-static)\.ncc$/', $asset['name']) === 1)
{
$preferred_asset = $asset;
}
elseif(preg_match('/\.ncc$/', $asset['name']) === 1)
{
$fallback_asset = $asset;
}
}
$target_asset = $preferred_asset ?: $fallback_asset;
if ($target_asset)
{
$asset_url = $target_asset['direct_asset_url'] ?? $target_asset['url'] ?? null;
if ($asset_url)
{
$result = new RepositoryResult($asset_url, RepositoryResultType::PACKAGE->value, $release);
RuntimeCache::set($endpoint, $result);
return $result;
}
throw new NetworkException(sprintf('No direct asset URL found for %s/%s/%s', $group, $project, $release));
}
throw new NetworkException(sprintf('No ncc package found for %s/%s/%s', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{ {
/** @noinspection DuplicatedCode */ /** @noinspection DuplicatedCode */
if($release === Versions::LATEST->value) if($release === Versions::LATEST)
{ {
$release = self::getLatestRelease($repository, $group, $project, $authentication); $release = self::getLatestRelease($repository, $group, $project, $authentication);
} }
@ -447,16 +332,84 @@
$headers = self::injectAuthentication($authentication, $curl, $headers); $headers = self::injectAuthentication($authentication, $curl, $headers);
} }
$resolved_host = Resolver::getResolveOption($endpoint); curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers
]);
if($resolved_host !== null) $response = self::processHttpResponse($curl, $group, $project);
foreach($response['assets']['links'] as $asset)
{ {
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]); if(preg_match('/\.ncc$/', $asset['name']) === 1)
{
if(isset($asset['direct_asset_url']))
{
$result = new RepositoryResult($asset['direct_asset_url'], RepositoryResultType::PACKAGE, $release);
}
elseif(isset($asset['url']))
{
$result = new RepositoryResult($asset['url'], RepositoryResultType::PACKAGE, $release);
}
else
{
throw new NetworkException(sprintf('No direct asset URL found for %s/%s/%s', $group, $project, $release));
}
RuntimeCache::set($endpoint, $result);
return $result;
}
}
throw new NetworkException(sprintf('No ncc package found for %s/%s/%s', $group, $project, $release));
}
/**
* Returns a downloadable archive of the specified release for the specified group and project.
* The function will try to find a .zip archive first, and if it can't find one, it will
* try to find a .tar.gz archive. If it can't find either, it will throw an exception.
*
* @param RepositoryConfiguration $repository The remote repository to make the request to
* @param string $group The group to get the release for (eg; "Nosial")
* @param string $project The project to get the release for (eg; "ncc" or "libs/config")
* @param string $release The release to get the release for (eg; "v1.0.0")
* @param AuthenticationInterface|null $authentication Optional. The authentication to use. If null, No authentication will be used.
* @return RepositoryResult The URL to the archive
* @throws AuthenticationException
* @throws NetworkException
*/
private static function getReleaseArchive(RepositoryConfiguration $repository, string $group, string $project, string $release, ?AuthenticationInterface $authentication=null): RepositoryResult
{
/** @noinspection DuplicatedCode */
if($release === Versions::LATEST)
{
$release = self::getLatestRelease($repository, $group, $project, $authentication);
}
$project = str_replace('.', '/', $project); // Gitlab doesn't like dots in project names (eg; "libs/config" becomes "libs%2Fconfig")
$endpoint = sprintf('%s://%s/api/v4/projects/%s%%2F%s/releases/%s', $repository->isSsl() ? 'https' : 'http', $repository->getHost(), $group, rawurlencode($project), rawurlencode($release));
if(RuntimeCache::exists($endpoint))
{
return RuntimeCache::get($endpoint);
}
$curl = curl_init($endpoint);
$headers = [
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: ncc'
];
if($authentication !== null)
{
$headers = self::injectAuthentication($authentication, $curl, $headers);
} }
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -476,11 +429,11 @@
if($asset['format'] === 'zip') if($asset['format'] === 'zip')
{ {
$results = new RepositoryResult($asset['url'], RepositoryResultType::SOURCE->value, $release); $results = new RepositoryResult($asset['url'], RepositoryResultType::SOURCE, $release);
} }
elseif($asset['format'] === 'tar') elseif($asset['format'] === 'tar')
{ {
$results = new RepositoryResult($asset['url'], RepositoryResultType::SOURCE->value, $release); $results = new RepositoryResult($asset['url'], RepositoryResultType::SOURCE, $release);
} }
else else
{ {
@ -507,23 +460,23 @@
{ {
switch($authentication->getAuthenticationType()) switch($authentication->getAuthenticationType())
{ {
case AuthenticationType::ACCESS_TOKEN->value: case AuthenticationType::ACCESS_TOKEN:
if($authentication instanceof AccessToken) if($authentication instanceof AccessToken)
{ {
$headers[] = 'Private-Token: ' . $authentication->getAccessToken(); $headers[] = 'Private-Token: ' . $authentication->getAccessToken();
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Access Token, got %s instead', $authentication->getAuthenticationType()));
case AuthenticationType::USERNAME_PASSWORD->value: case AuthenticationType::USERNAME_PASSWORD:
if($authentication instanceof UsernamePassword) if($authentication instanceof UsernamePassword)
{ {
curl_setopt($curl, CURLOPT_USERPWD, $authentication->getUsername() . ':' . $authentication->getPassword()); curl_setopt($curl, CURLOPT_USERPWD, $authentication->getUsername() . ':' . $authentication->getPassword());
break; break;
} }
throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()->value)); throw new AuthenticationException(sprintf('Invalid authentication type for Username/Password, got %s instead', $authentication->getAuthenticationType()));
} }
return $headers; return $headers;
@ -551,14 +504,14 @@
if($response === false) if($response === false)
{ {
Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $group, $project, curl_error($curl), $retry_count + 1)); Console::outWarning(sprintf('HTTP request failed for %s/%s: %s, retrying (%s/3)', $vendor, $project, curl_error($curl), $retry_count + 1));
$retry_count++; $retry_count++;
} }
} }
if($response === false) if($response === false)
{ {
throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $group, $project, curl_error($curl))); throw new NetworkException(sprintf('HTTP request failed for %s/%s: %s', $vendor, $project, curl_error($curl)));
} }
switch (curl_getinfo($curl, CURLINFO_HTTP_CODE)) switch (curl_getinfo($curl, CURLINFO_HTTP_CODE))

View file

@ -22,10 +22,8 @@
namespace ncc\Classes\NccExtension; namespace ncc\Classes\NccExtension;
use InvalidArgumentException;
use ncc\Enums\SpecialConstants\BuildConstants; use ncc\Enums\SpecialConstants\BuildConstants;
use ncc\Enums\SpecialConstants\DateTimeConstants; use ncc\Enums\SpecialConstants\DateTimeConstants;
use ncc\Enums\SpecialConstants\GeneralConstants;
use ncc\Enums\SpecialConstants\InstallConstants; use ncc\Enums\SpecialConstants\InstallConstants;
use ncc\Enums\SpecialConstants\AssemblyConstants; use ncc\Enums\SpecialConstants\AssemblyConstants;
use ncc\Enums\SpecialConstants\RuntimeConstants; use ncc\Enums\SpecialConstants\RuntimeConstants;
@ -49,67 +47,6 @@
$input = self::compileBuildConstants($input); $input = self::compileBuildConstants($input);
$input = self::compileDateTimeConstants($input, time()); $input = self::compileDateTimeConstants($input, time());
$input = self::compileRuntimeConstants($input); $input = self::compileRuntimeConstants($input);
$input = self::compileGeneralConstants($input, $project_configuration);
return $input;
}
/**
* Compiles general constants from the given input string based on the provided project configuration.
*
* @param string|null $input The input string containing constants to be compiled.
* @param ProjectConfiguration $project_configuration The project configuration used to resolve constants.
* @return string|null The input string with constants replaced, or null if the input was null.
*/
public static function compileGeneralConstants(?string $input, ProjectConfiguration $project_configuration): ?string
{
if ($input === null)
{
return null;
}
// Replace %DEFAULT_BUILD_CONFIGURATION%
$input = str_replace(
[
GeneralConstants::DEFAULT_BUILD_CONFIGURATION->value
],
[
$project_configuration->getBuild()->getDefaultConfiguration()
],
$input
);
if (str_starts_with($input, GeneralConstants::BUILD_OUTPUT_PATH->value))
{
$build_name = null;
if (preg_match('/' . preg_quote(GeneralConstants::BUILD_OUTPUT_PATH->value, '/') . ':(\S+)/', $input, $matches))
{
$build_name = $matches[1];
}
if ($build_name === null)
{
Console::outWarning(sprintf("Cannot compile constant %s because it's not valid, usage: %%CONSTANT%%:<name>", $input));
}
else
{
try
{
$output_path = $project_configuration->getBuild()->getBuildConfiguration($build_name)->getOutput();
$input = preg_replace(
'/' . preg_quote(GeneralConstants::BUILD_OUTPUT_PATH->value, '/') . ':\S+/',
$output_path,
$input,
1
);
}
catch (InvalidArgumentException $e)
{
Console::outError(sprintf("Cannot compile constant %s because it does not point to an existing build configuration name", $input));
}
}
}
return $input; return $input;
} }
@ -130,10 +67,10 @@
$input = str_replace( $input = str_replace(
[ [
AssemblyConstants::ASSEMBLY_NAME->value, AssemblyConstants::ASSEMBLY_NAME,
AssemblyConstants::ASSEMBLY_PACKAGE->value, AssemblyConstants::ASSEMBLY_PACKAGE,
AssemblyConstants::ASSEMBLY_VERSION->value, AssemblyConstants::ASSEMBLY_VERSION,
AssemblyConstants::ASSEMBLY_UID->value, AssemblyConstants::ASSEMBLY_UID
], ],
[ [
$assembly->getName(), $assembly->getName(),
@ -144,27 +81,27 @@
if($assembly->getDescription() !== null) if($assembly->getDescription() !== null)
{ {
$input = str_replace(AssemblyConstants::ASSEMBLY_DESCRIPTION->value, $assembly->getDescription(), $input); $input = str_replace(AssemblyConstants::ASSEMBLY_DESCRIPTION, $assembly->getDescription(), $input);
} }
if($assembly->getCompany() !== null) if($assembly->getCompany() !== null)
{ {
$input = str_replace(AssemblyConstants::ASSEMBLY_COMPANY->value, $assembly->getCompany(), $input); $input = str_replace(AssemblyConstants::ASSEMBLY_COMPANY, $assembly->getCompany(), $input);
} }
if($assembly->getProduct() !== null) if($assembly->getProduct() !== null)
{ {
$input = str_replace(AssemblyConstants::ASSEMBLY_PRODUCT->value, $assembly->getProduct(), $input); $input = str_replace(AssemblyConstants::ASSEMBLY_PRODUCT, $assembly->getProduct(), $input);
} }
if($assembly->getCopyright() !== null) if($assembly->getCopyright() !== null)
{ {
$input = str_replace(AssemblyConstants::ASSEMBLY_COPYRIGHT->value, $assembly->getCopyright(), $input); $input = str_replace(AssemblyConstants::ASSEMBLY_COPYRIGHT, $assembly->getCopyright(), $input);
} }
if($assembly->getTrademark() !== null) if($assembly->getTrademark() !== null)
{ {
$input = str_replace(AssemblyConstants::ASSEMBLY_TRADEMARK->value, $assembly->getTrademark(), $input); $input = str_replace(AssemblyConstants::ASSEMBLY_TRADEMARK, $assembly->getTrademark(), $input);
} }
return $input; return $input;
} }
@ -184,10 +121,10 @@
return str_replace( return str_replace(
[ [
BuildConstants::COMPILE_TIMESTAMP->value, BuildConstants::COMPILE_TIMESTAMP,
BuildConstants::NCC_BUILD_VERSION->value, BuildConstants::NCC_BUILD_VERSION,
BuildConstants::NCC_BUILD_FLAGS->value, BuildConstants::NCC_BUILD_FLAGS,
BuildConstants::NCC_BUILD_BRANCH->value BuildConstants::NCC_BUILD_BRANCH
], ],
[ [
time(), time(),
@ -213,10 +150,10 @@
return str_replace( return str_replace(
[ [
InstallConstants::INSTALL_PATH->value, InstallConstants::INSTALL_PATH,
InstallConstants::INSTALL_PATH_BIN->value, InstallConstants::INSTALL_PATH_BIN,
InstallConstants::INSTALL_PATH_SRC->value, InstallConstants::INSTALL_PATH_SRC,
InstallConstants::INSTALL_PATH_DATA->value InstallConstants::INSTALL_PATH_DATA
], ],
[ [
$installation_paths->getInstallationpath(), $installation_paths->getInstallationpath(),
@ -241,36 +178,36 @@
} }
return str_replace([ return str_replace([
DateTimeConstants::d->value, DateTimeConstants::d,
DateTimeConstants::D->value, DateTimeConstants::D,
DateTimeConstants::j->value, DateTimeConstants::j,
DateTimeConstants::l->value, DateTimeConstants::l,
DateTimeConstants::N->value, DateTimeConstants::N,
DateTimeConstants::S->value, DateTimeConstants::S,
DateTimeConstants::w->value, DateTimeConstants::w,
DateTimeConstants::z->value, DateTimeConstants::z,
DateTimeConstants::W->value, DateTimeConstants::W,
DateTimeConstants::F->value, DateTimeConstants::F,
DateTimeConstants::m->value, DateTimeConstants::m,
DateTimeConstants::M->value, DateTimeConstants::M,
DateTimeConstants::n->value, DateTimeConstants::n,
DateTimeConstants::t->value, DateTimeConstants::t,
DateTimeConstants::L->value, DateTimeConstants::L,
DateTimeConstants::o->value, DateTimeConstants::o,
DateTimeConstants::Y->value, DateTimeConstants::Y,
DateTimeConstants::y->value, DateTimeConstants::y,
DateTimeConstants::a->value, DateTimeConstants::a,
DateTimeConstants::A->value, DateTimeConstants::A,
DateTimeConstants::B->value, DateTimeConstants::B,
DateTimeConstants::g->value, DateTimeConstants::g,
DateTimeConstants::G->value, DateTimeConstants::G,
DateTimeConstants::h->value, DateTimeConstants::h,
DateTimeConstants::H->value, DateTimeConstants::H,
DateTimeConstants::i->value, DateTimeConstants::i,
DateTimeConstants::s->value, DateTimeConstants::s,
DateTimeConstants::c->value, DateTimeConstants::c,
DateTimeConstants::r->value, DateTimeConstants::r,
DateTimeConstants::u->value DateTimeConstants::u
], ],
[ [
date('d', $timestamp), date('d', $timestamp),
@ -320,7 +257,7 @@
if(function_exists('getcwd')) if(function_exists('getcwd'))
{ {
$input = str_replace(RuntimeConstants::CWD->value, getcwd(), $input); $input = str_replace(RuntimeConstants::CWD, getcwd(), $input);
} }
else else
{ {
@ -329,7 +266,7 @@
if(function_exists('getmypid')) if(function_exists('getmypid'))
{ {
$input = str_replace(RuntimeConstants::PID->value, getmypid(), $input); $input = str_replace(RuntimeConstants::PID, getmypid(), $input);
} }
else else
{ {
@ -338,7 +275,7 @@
if(function_exists('getmyuid')) if(function_exists('getmyuid'))
{ {
$input = str_replace(RuntimeConstants::UID->value, getmyuid(), $input); $input = str_replace(RuntimeConstants::UID, getmyuid(), $input);
} }
else else
{ {
@ -347,7 +284,7 @@
if(function_exists('getmygid')) if(function_exists('getmygid'))
{ {
$input = str_replace(RuntimeConstants::GID->value, getmygid(), $input); $input = str_replace(RuntimeConstants::GID, getmygid(), $input);
} }
else else
{ {
@ -356,7 +293,7 @@
if(function_exists('get_current_user')) if(function_exists('get_current_user'))
{ {
$input = str_replace(RuntimeConstants::USER->value, get_current_user(), $input); $input = str_replace(RuntimeConstants::USER, get_current_user(), $input);
} }
else else
{ {

View file

@ -47,7 +47,6 @@
use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Utilities\Base64; use ncc\Utilities\Base64;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\ConsoleProgressBar;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
@ -59,17 +58,11 @@
*/ */
private $project_manager; private $project_manager;
/**
* @var array
*/
private $merged_dependencies;
/** /**
* @param ProjectManager $project_manager * @param ProjectManager $project_manager
*/ */
public function __construct(ProjectManager $project_manager) public function __construct(ProjectManager $project_manager)
{ {
$this->merged_dependencies = [];
$this->project_manager = $project_manager; $this->project_manager = $project_manager;
} }
@ -93,17 +86,16 @@
* @throws PathNotFoundException * @throws PathNotFoundException
* @noinspection UnusedFunctionResultInspection * @noinspection UnusedFunctionResultInspection
*/ */
public function build(string $build_configuration=BuildConfigurationValues::DEFAULT->value, array $options=[]): string public function build(string $build_configuration=BuildConfigurationValues::DEFAULT, array $options=[]): string
{ {
$this->merged_dependencies = [];
$configuration = $this->project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration); $configuration = $this->project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration);
$configuration->setOptions(array_merge($configuration->getOptions(), $options)); $configuration->setOptions(array_merge($configuration->getOptions(), $options));
$static_dependencies = isset($configuration->getOptions()[BuildConfigurationOptions::STATIC_DEPENDENCIES->value]); $static_dependencies = isset($configuration->getOptions()[BuildConfigurationOptions::STATIC_DEPENDENCIES]);
if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE->value])) if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE]))
{ {
$package_path = ConstantCompiler::compileConstants( $package_path = ConstantCompiler::compileConstants(
$this->project_manager->getProjectConfiguration(), $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE->value] $this->project_manager->getProjectConfiguration(), $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE]
); );
} }
else else
@ -111,15 +103,15 @@
$package_path = ConstantCompiler::compileConstants($this->project_manager->getProjectConfiguration(), $configuration->getOutput()); $package_path = ConstantCompiler::compileConstants($this->project_manager->getProjectConfiguration(), $configuration->getOutput());
} }
//$progress = 0; $progress = 0;
$steps = $steps =
count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) + count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) +
count($this->project_manager->getComponents($build_configuration)) + count($this->project_manager->getComponents($build_configuration)) +
count($this->project_manager->getResources($build_configuration)); count($this->project_manager->getResources($build_configuration));
$progress_bar = new ConsoleProgressBar(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName()), $steps);
$package_writer = $this->createPackageWriter($package_path, $configuration); $package_writer = $this->createPackageWriter($package_path, $configuration);
Console::outVerbose(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName())); Console::out(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName()));
if($static_dependencies) if($static_dependencies)
{ {
@ -129,7 +121,7 @@
} }
// Debugging information // Debugging information
if(LogLevel::DEBUG->checkLogLevel(Main::getLogLevel())) if(Resolver::checkLogLevel(LogLevel::DEBUG, Main::getLogLevel()))
{ {
foreach($this->project_manager->getProjectConfiguration()->getAssembly()->toArray() as $prop => $value) foreach($this->project_manager->getProjectConfiguration()->getAssembly()->toArray() as $prop => $value)
{ {
@ -163,51 +155,39 @@
if(count($execution_units) === 0) if(count($execution_units) === 0)
{ {
//$progress = count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()); $progress = count($this->project_manager->getProjectConfiguration()->getExecutionPolicies());
//Console::inlineProgressBar($progress, $steps); Console::inlineProgressBar($progress, $steps);
$progress_bar->increaseValue(count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()), true);
Console::outWarning('The project contains execution policies but none of them are used'); Console::outWarning('The project contains execution policies but none of them are used');
} }
foreach($execution_units as $unit) foreach($execution_units as $unit)
{ {
$progress_bar->setMiscText(basename($unit->getExecutionPolicy()->getName())); $progress++;
//$progress++; Console::inlineProgressBar($progress, $steps);
//Console::inlineProgressBar($progress, $steps);
$package_writer->addExecutionUnit($unit); $package_writer->addExecutionUnit($unit);
$progress_bar->increaseValue(1, true);
} }
} }
// Compile package components // Compile package components
foreach($this->project_manager->getComponents($build_configuration) as $component) foreach($this->project_manager->getComponents($build_configuration) as $component)
{ {
//$progress++; $progress++;
//Console::inlineProgressBar($progress, $steps); Console::inlineProgressBar($progress, $steps);
$progress_bar->setMiscText(basename($component));
Console::outVerbose(sprintf('Compiling \'%s\'', $component)); Console::outVerbose(sprintf('Compiling \'%s\'', $component));
$this->processComponent($package_writer, $component); $this->processComponent($package_writer, $component);
$progress_bar->increaseValue(1, true);
} }
// Compile package resources // Compile package resources
foreach($this->project_manager->getResources($build_configuration) as $resource) foreach($this->project_manager->getResources($build_configuration) as $resource)
{ {
//$progress++; $progress++;
//Console::inlineProgressBar($progress, $steps); Console::inlineProgressBar($progress, $steps);
$progress_bar->setMiscText(basename($resource));
Console::outVerbose(sprintf('Processing \'%s\'', $resource)); Console::outVerbose(sprintf('Processing \'%s\'', $resource));
$this->processResource($package_writer, $resource); $this->processResource($package_writer, $resource);
$progress_bar->increaseValue(1, true);
} }
$progress_bar->setMiscText('done', true);
unset($progress_bar);
Console::out(sprintf('Processing dependencies...'));
// Add the project dependencies // Add the project dependencies
foreach($this->project_manager->getProjectConfiguration()->getBuild()->getDependencies() as $dependency) foreach($this->project_manager->getProjectConfiguration()->getBuild()->getDependencies() as $dependency)
{ {
@ -231,7 +211,6 @@
* @param Dependency $dependency * @param Dependency $dependency
* @param bool $static * @param bool $static
* @return void * @return void
* @throws ConfigurationException
* @throws IOException * @throws IOException
*/ */
private function processDependency(PackageWriter $package_writer, Dependency $dependency, bool $static=false): void private function processDependency(PackageWriter $package_writer, Dependency $dependency, bool $static=false): void
@ -241,14 +220,13 @@
/** @noinspection UnusedFunctionResultInspection */ /** @noinspection UnusedFunctionResultInspection */
$package_writer->addDependencyConfiguration($dependency); $package_writer->addDependencyConfiguration($dependency);
if(!$static || in_array($dependency->getName(), $this->merged_dependencies, true)) if(!$static)
{ {
return; return;
} }
$entry = (new PackageManager())->getPackageLock()->getVersionEntry($dependency->getName(), $dependency->getVersion()); $entry = (new PackageManager())->getPackageLock()->getVersionEntry($dependency->getName(), $dependency->getVersion());
$package_writer->merge((new PackageReader($entry->getShadowPackagePath($dependency->getName())))); $package_writer->merge((new PackageReader($entry->getShadowPackagePath($dependency->getName()))));
$this->merged_dependencies[] = $dependency->getName();
foreach($entry->getDependencies() as $sub_dependency) foreach($entry->getDependencies() as $sub_dependency)
{ {
@ -269,25 +247,25 @@
{ {
$package_writer = new PackageWriter($path); $package_writer = new PackageWriter($path);
if(isset($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION->value])) if(isset($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]))
{ {
$package_writer->addFlag(PackageFlags::COMPRESSION); $package_writer->addFlag(PackageFlags::COMPRESSION);
switch(strtolower($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION->value])) switch(strtolower($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]))
{ {
case BuildConfigurationOptions\CompressionOptions::HIGH->value: case BuildConfigurationOptions\CompressionOptions::HIGH:
$package_writer->addFlag(PackageFlags::HIGH_COMPRESSION); $package_writer->addFlag(PackageFlags::HIGH_COMPRESSION);
break; break;
case BuildConfigurationOptions\CompressionOptions::MEDIUM->value: case BuildConfigurationOptions\CompressionOptions::MEDIUM:
$package_writer->addFlag(PackageFlags::MEDIUM_COMPRESSION); $package_writer->addFlag(PackageFlags::MEDIUM_COMPRESSION);
break; break;
case BuildConfigurationOptions\CompressionOptions::LOW->value: case BuildConfigurationOptions\CompressionOptions::LOW:
$package_writer->addFlag(PackageFlags::LOW_COMPRESSION); $package_writer->addFlag(PackageFlags::LOW_COMPRESSION);
break; break;
default: default:
throw new NotSupportedException(sprintf('The compression level \'%s\' is not supported', $build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION->value])); throw new NotSupportedException(sprintf('The compression level \'%s\' is not supported', $build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]));
} }
} }
@ -335,38 +313,16 @@
* @param string $build_configuration * @param string $build_configuration
* @return void * @return void
*/ */
public function processMetadata(PackageWriter $package_writer, string $build_configuration=BuildConfigurationValues::DEFAULT->value): void public function processMetadata(PackageWriter $package_writer, string $build_configuration=BuildConfigurationValues::DEFAULT): void
{ {
$metadata = new Metadata($this->project_manager->getProjectConfiguration()->getProject()->getCompiler()); $metadata = new Metadata($this->project_manager->getProjectConfiguration()->getProject()->getCompiler());
$metadata->addOptions($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->addOptions($this->project_manager->getProjectConfiguration()->getProject()->getOptions());
$metadata->addConstants($this->project_manager->getConstants($build_configuration));
$metadata->setUpdateSource($this->project_manager->getProjectConfiguration()->getProject()->getUpdateSource()); $metadata->setUpdateSource($this->project_manager->getProjectConfiguration()->getProject()->getUpdateSource());
$metadata->setMainExecutionPolicy($this->project_manager->getProjectConfiguration()->getBuild()->getMain()); $metadata->setMainExecutionPolicy($this->project_manager->getProjectConfiguration()->getBuild()->getMain());
$metadata->setInstaller($this->project_manager->getProjectConfiguration()->getInstaller()); $metadata->setInstaller($this->project_manager->getProjectConfiguration()->getInstaller());
// Strip out 'output_file' build artifact.
if(isset($metadata->getOptions()[BuildConfigurationOptions::OUTPUT_FILE->value]))
{
$metadata->removeOption(BuildConfigurationOptions::OUTPUT_FILE->value);
}
// Strip out 'static' build artifact, PackageFlags::STATIC_DEPENDENCIES is used instead
// Making this option redundant.
if(isset($metadata->getOptions()[BuildConfigurationOptions::STATIC_DEPENDENCIES->value]))
{
$metadata->removeOption(BuildConfigurationOptions::STATIC_DEPENDENCIES->value);
}
$compiled_constants = [];
foreach($this->project_manager->getConstants() as $constant => $value)
{
$compiled_constants[$constant] = ConstantCompiler::compileConstants($this->project_manager->getProjectConfiguration(), $value);
}
$metadata->addConstants($compiled_constants);
/** @noinspection UnusedFunctionResultInspection */ /** @noinspection UnusedFunctionResultInspection */
$package_writer->setMetadata($metadata); $package_writer->setMetadata($metadata);
} }

View file

@ -29,7 +29,6 @@
use ncc\Enums\Flags\PackageFlags; use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\PackageDirectory; use ncc\Enums\PackageDirectory;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IntegrityException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
@ -84,11 +83,6 @@
*/ */
private $package_file; private $package_file;
/**
* @var string
*/
private $package_path;
/** /**
* @var array * @var array
*/ */
@ -107,9 +101,7 @@
throw new IOException(sprintf('File \'%s\' does not exist', $file_path)); throw new IOException(sprintf('File \'%s\' does not exist', $file_path));
} }
$this->package_path = $file_path;
$this->package_file = fopen($file_path, 'rb'); $this->package_file = fopen($file_path, 'rb');
if($this->package_file === false) if($this->package_file === false)
{ {
throw new IOException(sprintf('Failed to open file \'%s\'', $file_path)); throw new IOException(sprintf('Failed to open file \'%s\'', $file_path));
@ -175,38 +167,27 @@
throw new IOException(sprintf('File \'%s\' is not a valid package file (corrupted header)', $file_path), $e); throw new IOException(sprintf('File \'%s\' is not a valid package file (corrupted header)', $file_path), $e);
} }
if(!isset($this->headers[PackageStructure::FILE_VERSION->value])) if(!isset($this->headers[PackageStructure::FILE_VERSION]))
{ {
throw new IOException(sprintf('File \'%s\' is not a valid package file (invalid header)', $file_path)); throw new IOException(sprintf('File \'%s\' is not a valid package file (invalid header)', $file_path));
} }
// Seek the data until the end of the package (FF AA 55 F0) // Seek the data until the end of the package (FF AA 55 F0)
fseek($this->package_file, $this->data_offset); fseek($this->package_file, $this->data_offset);
$buffer = '';
while(!feof($this->package_file)) while(!feof($this->package_file))
{ {
$current_chunk = fread($this->package_file, 1024); $buffer = fread($this->package_file, 1024);
$this->data_length += strlen($current_chunk); $this->data_length += strlen($buffer);
$buffer .= $current_chunk;
// If we detect the end-of-data byte sequence
if (($position = strpos($buffer, "\xFF\xAA\x55\xF0")) !== false) if (($position = strpos($buffer, "\xFF\xAA\x55\xF0")) !== false)
{ {
$this->data_length -= strlen($buffer) - $position; $this->data_length -= strlen($buffer) - $position;
$this->package_length += $this->data_length + 4; $this->package_length += $this->data_length + 4;
break; break;
} }
// Check if the buffer is 1MB or larger
if(strlen($buffer) > 1048576)
{
// Remove the first 512kb of the buffer
$buffer = substr($buffer, 512000);
} }
} if($this->data_length === null)
if($this->data_length === null || $this->data_length === 0)
{ {
throw new IOException(sprintf('File \'%s\' is not a valid package file (missing end of package)', $file_path)); throw new IOException(sprintf('File \'%s\' is not a valid package file (missing end of package)', $file_path));
} }
@ -231,7 +212,7 @@
*/ */
public function getFileVersion(): string public function getFileVersion(): string
{ {
return $this->headers[PackageStructure::FILE_VERSION->value]; return $this->headers[PackageStructure::FILE_VERSION];
} }
/** /**
@ -241,7 +222,7 @@
*/ */
public function getFlags(): array public function getFlags(): array
{ {
return $this->headers[PackageStructure::FLAGS->value]; return $this->headers[PackageStructure::FLAGS];
} }
/** /**
@ -252,7 +233,7 @@
*/ */
public function getFlag(string $name): bool public function getFlag(string $name): bool
{ {
return in_array($name, $this->headers[PackageStructure::FLAGS->value], true); return in_array($name, $this->headers[PackageStructure::FLAGS], true);
} }
/** /**
@ -262,7 +243,7 @@
*/ */
public function getDirectory(): array public function getDirectory(): array
{ {
return $this->headers[PackageStructure::DIRECTORY->value]; return $this->headers[PackageStructure::DIRECTORY];
} }
/** /**
@ -273,15 +254,15 @@
*/ */
public function get(string $name): string public function get(string $name): string
{ {
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$name]))
{ {
throw new RuntimeException(sprintf('File \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new RuntimeException(sprintf('File \'%s\' not found in package', $name));
} }
$location = explode(':', $this->headers[PackageStructure::DIRECTORY->value][$name]); $location = explode(':', $this->headers[PackageStructure::DIRECTORY][$name]);
fseek($this->package_file, ($this->data_offset + (int)$location[0])); fseek($this->package_file, ($this->data_offset + (int)$location[0]));
if(in_array(PackageFlags::COMPRESSION->value, $this->headers[PackageStructure::FLAGS->value], true)) if(in_array(PackageFlags::COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{ {
return gzuncompress(fread($this->package_file, (int)$location[1])); return gzuncompress(fread($this->package_file, (int)$location[1]));
} }
@ -297,12 +278,12 @@
*/ */
public function getPointer(string $name): array public function getPointer(string $name): array
{ {
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$name]))
{ {
throw new RuntimeException(sprintf('Resource \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new RuntimeException(sprintf('Resource \'%s\' not found in package', $name));
} }
$location = explode(':', $this->headers[PackageStructure::DIRECTORY->value][$name]); $location = explode(':', $this->headers[PackageStructure::DIRECTORY][$name]);
return [(int)$location[0], (int)$location[1]]; return [(int)$location[0], (int)$location[1]];
} }
@ -314,7 +295,7 @@
*/ */
public function exists(string $name): bool public function exists(string $name): bool
{ {
return isset($this->headers[PackageStructure::DIRECTORY->value][$name]); return isset($this->headers[PackageStructure::DIRECTORY][$name]);
} }
/** /**
@ -335,31 +316,22 @@
* *
* @return Assembly * @return Assembly
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getAssembly(): Assembly public function getAssembly(): Assembly
{ {
$directory = sprintf('@%s', PackageDirectory::ASSEMBLY->value); $directory = sprintf('@%s', PackageDirectory::ASSEMBLY);
if(isset($this->cache[$directory])) if(isset($this->cache[$directory]))
{ {
return $this->cache[$directory]; return $this->cache[$directory];
} }
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$directory])) if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
throw new ConfigurationException(sprintf('Assembly object not found in package \'%s\'', $this->package_path)); throw new ConfigurationException('Package does not contain an assembly');
} }
try
{
$assembly = Assembly::fromArray(ZiProto::decode($this->get($directory))); $assembly = Assembly::fromArray(ZiProto::decode($this->get($directory)));
}
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode assembly from package \'%s\' using ZiProto: %s', $this->package_path, $e->getMessage()), $e);
}
$this->cache[$directory] = $assembly; $this->cache[$directory] = $assembly;
return $assembly; return $assembly;
} }
@ -369,36 +341,22 @@
* *
* @return Metadata * @return Metadata
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getMetadata(): Metadata public function getMetadata(): Metadata
{ {
$directory = sprintf('@%s', PackageDirectory::METADATA->value); $directory = sprintf('@%s', PackageDirectory::METADATA);
if(isset($this->cache[$directory])) if(isset($this->cache[$directory]))
{ {
return $this->cache[$directory]; return $this->cache[$directory];
} }
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$directory])) if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
throw new ConfigurationException(sprintf('Metadata object not found in package \'%s\'', $this->package_path)); throw new ConfigurationException('Package does not contain metadata');
} }
try
{
$metadata = Metadata::fromArray(ZiProto::decode($this->get($directory))); $metadata = Metadata::fromArray(ZiProto::decode($this->get($directory)));
}
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode metadata from package \'%s\' using ZiProto: %s', $this->package_path, $e->getMessage()), $e);
}
foreach($this->getFlags() as $flag)
{
$metadata->setOption($flag, true);
}
$this->cache[$directory] = $metadata; $this->cache[$directory] = $metadata;
return $metadata; return $metadata;
} }
@ -407,31 +365,22 @@
* Optional. Returns the package's installer * Optional. Returns the package's installer
* *
* @return Installer|null * @return Installer|null
* @throws IntegrityException
*/ */
public function getInstaller(): ?Installer public function getInstaller(): ?Installer
{ {
$directory = sprintf('@%s', PackageDirectory::INSTALLER->value); $directory = sprintf('@%s', PackageDirectory::INSTALLER);
if(isset($this->cache[$directory])) if(isset($this->cache[$directory]))
{ {
return $this->cache[$directory]; return $this->cache[$directory];
} }
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$directory])) if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
return null; return null;
} }
try
{
$installer = Installer::fromArray(ZiProto::decode($this->get($directory))); $installer = Installer::fromArray(ZiProto::decode($this->get($directory)));
}
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode installer from package \'%s\' using ZiProto: %s', $this->package_path, $e->getMessage()), $e);
}
$this->cache[$directory] = $installer; $this->cache[$directory] = $installer;
return $installer; return $installer;
} }
@ -444,9 +393,9 @@
public function getDependencies(): array public function getDependencies(): array
{ {
$dependencies = []; $dependencies = [];
$directory = sprintf('@%s:', PackageDirectory::DEPENDENCIES->value); $directory = sprintf('@%s:', PackageDirectory::DEPENDENCIES);
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, $directory)) if(str_starts_with($name, $directory))
{ {
@ -463,25 +412,17 @@
* @param string $name * @param string $name
* @return Dependency * @return Dependency
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getDependency(string $name): Dependency public function getDependency(string $name): Dependency
{ {
$dependency_name = sprintf('@%s:%s', PackageDirectory::DEPENDENCIES->value, $name); $dependency_name = sprintf('@%s:%s', PackageDirectory::DEPENDENCIES, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$dependency_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$dependency_name]))
{ {
throw new ConfigurationException(sprintf('Dependency \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new ConfigurationException(sprintf('Dependency \'%s\' not found in package', $name));
} }
try
{
return Dependency::fromArray(ZiProto::decode($this->get($dependency_name))); return Dependency::fromArray(ZiProto::decode($this->get($dependency_name)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode dependency \'%s\' from package \'%s\' using ZiProto: %s', $name, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns a dependency from the package by pointer * Returns a dependency from the package by pointer
@ -489,19 +430,12 @@
* @param int $pointer * @param int $pointer
* @param int $length * @param int $length
* @return Dependency * @return Dependency
* @throws IntegrityException * @throws ConfigurationException
*/ */
public function getDependencyByPointer(int $pointer, int $length): Dependency public function getDependencyByPointer(int $pointer, int $length): Dependency
{
try
{ {
return Dependency::fromArray(ZiProto::decode($this->getByPointer($pointer, $length))); return Dependency::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode dependency from pointer \'%s\' with length \'%s\' from package \'%s\' using ZiProto: %s', $pointer, $length, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns an array of execution units from the package * Returns an array of execution units from the package
@ -511,9 +445,9 @@
public function getExecutionUnits(): array public function getExecutionUnits(): array
{ {
$execution_units = []; $execution_units = [];
$directory = sprintf('@%s:', PackageDirectory::EXECUTION_UNITS->value); $directory = sprintf('@%s:', PackageDirectory::EXECUTION_UNITS);
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, $directory)) if(str_starts_with($name, $directory))
{ {
@ -530,36 +464,17 @@
* @param string $name * @param string $name
* @return ExecutionUnit * @return ExecutionUnit
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getExecutionUnit(string $name): ExecutionUnit public function getExecutionUnit(string $name): ExecutionUnit
{ {
$execution_unit_name = sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS->value, $name); $execution_unit_name = sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$execution_unit_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$execution_unit_name]))
{ {
throw new ConfigurationException(sprintf('Execution unit \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new ConfigurationException(sprintf('Execution unit \'%s\' not found in package', $name));
} }
try
{
return ExecutionUnit::fromArray(ZiProto::decode($this->get($execution_unit_name))); return ExecutionUnit::fromArray(ZiProto::decode($this->get($execution_unit_name)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode execution unit \'%s\' from package file \'%s\' using ZiProto: %s', $name, $this->package_path, $e->getMessage()), $e);
}
}
/**
* Checks if an execution unit with the specified name exists in the package.
*
* @param string $name The name of the execution unit to check.
* @return bool True if the execution unit exists, false otherwise.
*/
public function executionUnitExists(string $name): bool
{
return isset($this->headers[PackageStructure::DIRECTORY->value][sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS->value, $name)]);
}
/** /**
* Returns an execution unit from the package by pointer * Returns an execution unit from the package by pointer
@ -567,19 +482,12 @@
* @param int $pointer * @param int $pointer
* @param int $length * @param int $length
* @return ExecutionUnit * @return ExecutionUnit
* @throws IntegrityException * @throws ConfigurationException
*/ */
public function getExecutionUnitByPointer(int $pointer, int $length): ExecutionUnit public function getExecutionUnitByPointer(int $pointer, int $length): ExecutionUnit
{
try
{ {
return ExecutionUnit::fromArray(ZiProto::decode($this->getByPointer($pointer, $length))); return ExecutionUnit::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode execution unit from pointer \'%s\' with length \'%s\' from package \'%s\' using ZiProto: %s', $pointer, $length, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns the package's component pointers * Returns the package's component pointers
@ -589,9 +497,9 @@
public function getComponents(): array public function getComponents(): array
{ {
$components = []; $components = [];
$directory = sprintf('@%s:', PackageDirectory::COMPONENTS->value); $directory = sprintf('@%s:', PackageDirectory::COMPONENTS);
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, $directory)) if(str_starts_with($name, $directory))
{ {
@ -610,9 +518,9 @@
public function getClassMap(): array public function getClassMap(): array
{ {
$class_map = []; $class_map = [];
$directory = sprintf('@%s:', PackageDirectory::CLASS_POINTER->value); $directory = sprintf('@%s:', PackageDirectory::CLASS_POINTER);
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, $directory)) if(str_starts_with($name, $directory))
{ {
@ -629,25 +537,17 @@
* @param string $name * @param string $name
* @return Component * @return Component
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getComponent(string $name): Component public function getComponent(string $name): Component
{ {
$component_name = sprintf('@%s:%s', PackageDirectory::COMPONENTS->value, $name); $component_name = sprintf('@%s:%s', PackageDirectory::COMPONENTS, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$component_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$component_name]))
{ {
throw new ConfigurationException(sprintf('Component \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new ConfigurationException(sprintf('Component \'%s\' not found in package', $name));
} }
try
{
return Component::fromArray(ZiProto::decode($this->get($component_name))); return Component::fromArray(ZiProto::decode($this->get($component_name)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode component \'%s\' from package \'%s\' using ZiProto: %s', $name, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns a component from the package by pointer * Returns a component from the package by pointer
@ -655,19 +555,12 @@
* @param int $pointer * @param int $pointer
* @param int $length * @param int $length
* @return Component * @return Component
* @throws IntegrityException * @throws ConfigurationException
*/ */
public function getComponentByPointer(int $pointer, int $length): Component public function getComponentByPointer(int $pointer, int $length): Component
{
try
{ {
return Component::fromArray(ZiProto::decode($this->getByPointer($pointer, $length))); return Component::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode component from pointer \'%s\' with length \'%s\' from package \'%s\' using ZiProto: %s', $pointer, $length, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns a component from the package by a class pointer * Returns a component from the package by a class pointer
@ -675,25 +568,17 @@
* @param string $class * @param string $class
* @return Component * @return Component
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getComponentByClass(string $class): Component public function getComponentByClass(string $class): Component
{ {
$class_name = sprintf('@%s:%s', PackageDirectory::CLASS_POINTER->value, $class); $class_name = sprintf('@%s:%s', PackageDirectory::CLASS_POINTER, $class);
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$class_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$class_name]))
{ {
throw new ConfigurationException(sprintf('Class map \'%s\' not found in package \'%s\'', $class, $this->package_path)); throw new ConfigurationException(sprintf('Class map \'%s\' not found in package', $class));
} }
try
{
return Component::fromArray(ZiProto::decode($this->get($class_name))); return Component::fromArray(ZiProto::decode($this->get($class_name)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode component from class pointer \'%s\' from package \'%s\' using ZiProto: %s', $class, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns an array of resource pointers from the package * Returns an array of resource pointers from the package
@ -703,9 +588,9 @@
public function getResources(): array public function getResources(): array
{ {
$resources = []; $resources = [];
$directory = sprintf('@%s:', PackageDirectory::RESOURCES->value); $directory = sprintf('@%s:', PackageDirectory::RESOURCES);
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, $directory)) if(str_starts_with($name, $directory))
{ {
@ -722,25 +607,17 @@
* @param string $name * @param string $name
* @return Resource * @return Resource
* @throws ConfigurationException * @throws ConfigurationException
* @throws IntegrityException
*/ */
public function getResource(string $name): Resource public function getResource(string $name): Resource
{ {
$resource_name = sprintf('@%s:%s', PackageDirectory::RESOURCES->value, $name); $resource_name = sprintf('@%s:%s', PackageDirectory::RESOURCES, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY->value][$resource_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$resource_name]))
{ {
throw new ConfigurationException(sprintf('Resource \'%s\' not found in package \'%s\'', $name, $this->package_path)); throw new ConfigurationException(sprintf('Resource \'%s\' not found in package', $name));
} }
try
{
return Resource::fromArray(ZiProto::decode($this->get($resource_name))); return Resource::fromArray(ZiProto::decode($this->get($resource_name)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode resource \'%s\' from package \'%s\' using ZiProto: %s', $name, $this->package_path, $e->getMessage()), $e);
}
}
/** /**
* Returns a resource from the package by pointer * Returns a resource from the package by pointer
@ -748,38 +625,12 @@
* @param int $pointer * @param int $pointer
* @param int $length * @param int $length
* @return Resource * @return Resource
* @throws IntegrityException * @throws ConfigurationException
*/ */
public function getResourceByPointer(int $pointer, int $length): Resource public function getResourceByPointer(int $pointer, int $length): Resource
{
try
{ {
return Resource::fromArray(ZiProto::decode($this->getByPointer($pointer, $length))); return Resource::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
catch(Exception $e)
{
throw new IntegrityException(sprintf('Failed to decode resource from pointer \'%s\' with length \'%s\' from package \'%s\' using ZiProto: %s', $pointer, $length, $this->package_path, $e->getMessage()), $e);
}
}
/**
* Searches the package's directory for a file that matches the given filename
*
* @param string $filename
* @return string|false
*/
public function find(string $filename): string|false
{
foreach($this->headers[PackageStructure::DIRECTORY->value] as $name => $location)
{
if(str_ends_with($name, $filename))
{
return $name;
}
}
return false;
}
/** /**
* Returns the offset of the package * Returns the offset of the package

View file

@ -25,12 +25,10 @@
namespace ncc\Classes; namespace ncc\Classes;
use InvalidArgumentException;
use ncc\Enums\Flags\PackageFlags; use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\PackageDirectory; use ncc\Enums\PackageDirectory;
use ncc\Enums\PackageStructure; use ncc\Enums\PackageStructure;
use ncc\Enums\PackageStructureVersions; use ncc\Enums\PackageStructureVersions;
use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
@ -41,7 +39,6 @@
use ncc\Objects\ProjectConfiguration\Installer; use ncc\Objects\ProjectConfiguration\Installer;
use ncc\Extensions\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\ConsoleProgressBar;
class PackageWriter class PackageWriter
{ {
@ -109,9 +106,9 @@
$this->temp_file = @fopen($this->temporary_path, 'wb'); // Create a temporary data file $this->temp_file = @fopen($this->temporary_path, 'wb'); // Create a temporary data file
$this->package_file = @fopen($file_path, 'wb'); $this->package_file = @fopen($file_path, 'wb');
$this->headers = [ $this->headers = [
PackageStructure::FILE_VERSION->value => PackageStructureVersions::_2_0->value, PackageStructure::FILE_VERSION => PackageStructureVersions::_2_0,
PackageStructure::FLAGS->value => [], PackageStructure::FLAGS => [],
PackageStructure::DIRECTORY->value => [] PackageStructure::DIRECTORY => []
]; ];
if($this->temp_file === false || $this->package_file === false) if($this->temp_file === false || $this->package_file === false)
@ -127,7 +124,7 @@
*/ */
public function getFileVersion(): string public function getFileVersion(): string
{ {
return (string)$this->headers[PackageStructure::FILE_VERSION->value]; return (string)$this->headers[PackageStructure::FILE_VERSION];
} }
/** /**
@ -138,7 +135,7 @@
*/ */
public function setFileVersion(string $version): void public function setFileVersion(string $version): void
{ {
$this->headers[PackageStructure::FILE_VERSION->value] = $version; $this->headers[PackageStructure::FILE_VERSION] = $version;
} }
/** /**
@ -148,13 +145,13 @@
*/ */
public function getFlags(): array public function getFlags(): array
{ {
return (array)$this->headers[PackageStructure::FLAGS->value]; return (array)$this->headers[PackageStructure::FLAGS];
} }
/** /**
* Sets the package flags * Sets the package flags
* *
* @param string[]|PackageFlags[] $flags * @param array $flags
* @return void * @return void
* @throws IOException * @throws IOException
*/ */
@ -165,47 +162,26 @@
throw new IOException('Cannot set flags after data has been written to the package'); throw new IOException('Cannot set flags after data has been written to the package');
} }
foreach($flags as $flag) $this->headers[PackageStructure::FLAGS] = $flags;
{
if(is_string($flag))
{
$flag = PackageFlags::tryFrom($flag);
if($flag === null)
{
throw new InvalidArgumentException(sprintf('Unexpected flag: %s', $flag));
}
}
$this->headers[PackageStructure::FLAGS->value] = $flag->value;
}
} }
/** /**
* Adds a flag to the package * Adds a flag to the package
* *
* @param PackageFlags|string $flag * @param string $flag
* @return void * @return void
* @throws IOException * @throws IOException
*/ */
public function addFlag(PackageFlags|string $flag): void public function addFlag(string $flag): void
{ {
if(is_string($flag))
{
$flag = PackageFlags::tryFrom($flag);
if($flag === null)
{
throw new InvalidArgumentException(sprintf('Unexpected flag: %s', $flag));
}
}
if($this->data_written) if($this->data_written)
{ {
throw new IOException('Cannot add a flag after data has been written to the package'); throw new IOException('Cannot add a flag after data has been written to the package');
} }
if(!in_array($flag, $this->headers[PackageStructure::FLAGS->value], true)) if(!in_array($flag, $this->headers[PackageStructure::FLAGS], true))
{ {
$this->headers[PackageStructure::FLAGS->value][] = $flag->value; $this->headers[PackageStructure::FLAGS][] = $flag;
} }
} }
@ -216,23 +192,14 @@
* @return void * @return void
* @throws IOException * @throws IOException
*/ */
public function removeFlag(PackageFlags|string $flag): void public function removeFlag(string $flag): void
{ {
if(is_string($flag))
{
$flag = PackageFlags::tryFrom($flag);
if($flag === null)
{
throw new InvalidArgumentException(sprintf('Unexpected flag: %s', $flag));
}
}
if($this->data_written) if($this->data_written)
{ {
throw new IOException('Cannot remove a flag after data has been written to the package'); throw new IOException('Cannot remove a flag after data has been written to the package');
} }
$this->headers[PackageStructure::FLAGS->value] = array_diff($this->headers[PackageStructure::FLAGS->value], [$flag->value]); $this->headers[PackageStructure::FLAGS] = array_diff($this->headers[PackageStructure::FLAGS], [$flag]);
} }
/** /**
@ -244,22 +211,22 @@
*/ */
public function add(string $name, string $data): array public function add(string $name, string $data): array
{ {
if(isset($this->headers[PackageStructure::DIRECTORY->value][$name])) if(isset($this->headers[PackageStructure::DIRECTORY][$name]))
{ {
return explode(':', $this->headers[PackageStructure::DIRECTORY->value][$name]); return explode(':', $this->headers[PackageStructure::DIRECTORY][$name]);
} }
if(in_array(PackageFlags::COMPRESSION->value, $this->headers[PackageStructure::FLAGS->value], true)) if(in_array(PackageFlags::COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{ {
if(in_array(PackageFlags::LOW_COMPRESSION->value, $this->headers[PackageStructure::FLAGS->value], true)) if(in_array(PackageFlags::LOW_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{ {
$data = gzcompress($data, 1); $data = gzcompress($data, 1);
} }
else if(in_array(PackageFlags::MEDIUM_COMPRESSION->value, $this->headers[PackageStructure::FLAGS->value], true)) else if(in_array(PackageFlags::MEDIUM_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{ {
$data = gzcompress($data, 6); $data = gzcompress($data, 6);
} }
else if(in_array(PackageFlags::HIGH_COMPRESSION->value, $this->headers[PackageStructure::FLAGS->value], true)) else if(in_array(PackageFlags::HIGH_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{ {
$data = gzcompress($data, 9); $data = gzcompress($data, 9);
} }
@ -270,7 +237,7 @@
} }
$pointer = sprintf("%d:%d", ftell($this->temp_file), strlen($data)); $pointer = sprintf("%d:%d", ftell($this->temp_file), strlen($data));
$this->headers[PackageStructure::DIRECTORY->value][$name] = $pointer; $this->headers[PackageStructure::DIRECTORY][$name] = $pointer;
$this->data_written = true; $this->data_written = true;
fwrite($this->temp_file, $data); fwrite($this->temp_file, $data);
@ -287,12 +254,12 @@
*/ */
public function addPointer(string $name, int $offset, int $length): void public function addPointer(string $name, int $offset, int $length): void
{ {
if(isset($this->headers[PackageStructure::DIRECTORY->value][$name])) if(isset($this->headers[PackageStructure::DIRECTORY][$name]))
{ {
return; return;
} }
$this->headers[PackageStructure::DIRECTORY->value][$name] = sprintf("%d:%d", $offset, $length); $this->headers[PackageStructure::DIRECTORY][$name] = sprintf("%d:%d", $offset, $length);
} }
/** /**
@ -303,7 +270,7 @@
*/ */
public function setAssembly(Assembly $assembly): array public function setAssembly(Assembly $assembly): array
{ {
return $this->add(sprintf('@%s', PackageDirectory::ASSEMBLY->value), ZiProto::encode($assembly->toArray(true))); return $this->add(sprintf('@%s', PackageDirectory::ASSEMBLY), ZiProto::encode($assembly->toArray(true)));
} }
/** /**
@ -314,7 +281,7 @@
*/ */
public function setMetadata(Metadata $metadata): array public function setMetadata(Metadata $metadata): array
{ {
return $this->add(sprintf('@%s', PackageDirectory::METADATA->value), ZiProto::encode($metadata->toArray(true))); return $this->add(sprintf('@%s', PackageDirectory::METADATA), ZiProto::encode($metadata->toArray(true)));
} }
/** /**
@ -325,7 +292,7 @@
*/ */
public function setInstaller(Installer $installer): array public function setInstaller(Installer $installer): array
{ {
return $this->add(sprintf('@%s', PackageDirectory::INSTALLER->value), ZiProto::encode($installer->toArray(true))); return $this->add(sprintf('@%s', PackageDirectory::INSTALLER), ZiProto::encode($installer->toArray(true)));
} }
/** /**
@ -336,7 +303,7 @@
*/ */
public function addDependencyConfiguration(Dependency $dependency): array public function addDependencyConfiguration(Dependency $dependency): array
{ {
return $this->add(sprintf('@%s:%s', PackageDirectory::DEPENDENCIES->value, $dependency->getName()), ZiProto::encode($dependency->toArray(true))); return $this->add(sprintf('@%s:%s', PackageDirectory::DEPENDENCIES, $dependency->getName()), ZiProto::encode($dependency->toArray(true)));
} }
/** /**
@ -347,7 +314,7 @@
*/ */
public function addExecutionUnit(ExecutionUnit $unit): array public function addExecutionUnit(ExecutionUnit $unit): array
{ {
return $this->add(sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS->value, $unit->getExecutionPolicy()->getName()), ZiProto::encode($unit->toArray(true))); return $this->add(sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS, $unit->getExecutionPolicy()->getName()), ZiProto::encode($unit->toArray(true)));
} }
/** /**
@ -358,7 +325,7 @@
*/ */
public function addComponent(Component $component): array public function addComponent(Component $component): array
{ {
return $this->add(sprintf('@%s:%s', PackageDirectory::COMPONENTS->value, $component->getName()), ZiProto::encode($component->toArray(true))); return $this->add(sprintf('@%s:%s', PackageDirectory::COMPONENTS, $component->getName()), ZiProto::encode($component->toArray(true)));
} }
/** /**
@ -369,7 +336,7 @@
*/ */
public function addResource(Resource $resource): array public function addResource(Resource $resource): array
{ {
return $this->add(sprintf('@%s:%s', PackageDirectory::RESOURCES->value, $resource->getName()), ZiProto::encode($resource->toArray(true))); return $this->add(sprintf('@%s:%s', PackageDirectory::RESOURCES, $resource->getName()), ZiProto::encode($resource->toArray(true)));
} }
/** /**
@ -382,7 +349,7 @@
*/ */
public function mapClass(string $class, int $offset, int $length): void public function mapClass(string $class, int $offset, int $length): void
{ {
$this->addPointer(sprintf('@%s:%s', PackageDirectory::CLASS_POINTER->value, $class), $offset, $length); $this->addPointer(sprintf('@%s:%s', PackageDirectory::CLASS_POINTER, $class), $offset, $length);
} }
/** /**
@ -390,23 +357,19 @@
* *
* @param PackageReader $reader * @param PackageReader $reader
* @return void * @return void
* @throws ConfigurationException
*/ */
public function merge(PackageReader $reader): void public function merge(PackageReader $reader): void
{ {
$progress_bar = new ConsoleProgressBar(sprintf('Merging %s', $reader->getAssembly()->getPackage()), count($reader->getDirectory()));
$processed_resources = []; $processed_resources = [];
foreach($reader->getDirectory() as $name => $pointer) foreach($reader->getDirectory() as $name => $pointer)
{ {
$progress_bar->setMiscText($name, true);
switch((int)substr(explode(':', $name, 2)[0], 1)) switch((int)substr(explode(':', $name, 2)[0], 1))
{ {
case PackageDirectory::METADATA->value: case PackageDirectory::METADATA:
case PackageDirectory::ASSEMBLY->value: case PackageDirectory::ASSEMBLY:
case PackageDirectory::INSTALLER->value: case PackageDirectory::INSTALLER:
case PackageDirectory::EXECUTION_UNITS->value: case PackageDirectory::EXECUTION_UNITS:
Console::outDebug(sprintf('Skipping %s', $name)); Console::outDebug(sprintf('Skipping %s', $name));
break; break;
@ -420,13 +383,9 @@
Console::outDebug(sprintf('Merging %s', $name)); Console::outDebug(sprintf('Merging %s', $name));
$processed_resources[$pointer] = $this->add($name, $reader->get($name)); $processed_resources[$pointer] = $this->add($name, $reader->get($name));
}
$progress_bar->increaseValue(1, true);
} }
}
$progress_bar->setMiscText('done', true);
unset($progress_bar);
} }
/** /**

View file

@ -35,10 +35,9 @@
use ncc\Interfaces\RepositoryInterface; use ncc\Interfaces\RepositoryInterface;
use ncc\Objects\RepositoryConfiguration; use ncc\Objects\RepositoryConfiguration;
use ncc\Objects\RepositoryResult; use ncc\Objects\RepositoryResult;
use ncc\ThirdParty\composer\semver\Comparator; use ncc\ThirdParty\composer\Semver\Comparator;
use ncc\ThirdParty\composer\semver\Semver; use ncc\ThirdParty\composer\Semver\Semver;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache; use ncc\Utilities\RuntimeCache;
use RuntimeException; use RuntimeException;
@ -47,9 +46,9 @@
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST->value, ?AuthenticationType $authentication = null, array $options=[]): RepositoryResult public static function fetchSourceArchive(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST, ?AuthenticationType $authentication = null): RepositoryResult
{ {
if($version === Versions::LATEST->value) if($version === Versions::LATEST)
{ {
$version = self::getLatestVersion($repository, $vendor, $project); $version = self::getLatestVersion($repository, $vendor, $project);
} }
@ -71,16 +70,9 @@
'User-Agent: ncc' 'User-Agent: ncc'
]; ];
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -99,14 +91,14 @@
throw new NetworkException(sprintf('Invalid response from %s/%s, version %s does not have a dist URL', $vendor, $project, $version)); throw new NetworkException(sprintf('Invalid response from %s/%s, version %s does not have a dist URL', $vendor, $project, $version));
} }
return new RepositoryResult($response['package']['versions'][$version]['dist']['url'], RepositoryResultType::SOURCE->value, $version); return new RepositoryResult($response['package']['versions'][$version]['dist']['url'], RepositoryResultType::SOURCE, $version);
} }
/** /**
* @inheritDoc * @inheritDoc
* @throws NotSupportedException * @throws NotSupportedException
*/ */
public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST->value, ?AuthenticationType $authentication = null, array $options=[]): RepositoryResult public static function fetchPackage(RepositoryConfiguration $repository, string $vendor, string $project, string $version = Versions::LATEST, ?AuthenticationType $authentication = null): RepositoryResult
{ {
throw new NotSupportedException('Fetching ncc packages from Packagist is not supported'); throw new NotSupportedException('Fetching ncc packages from Packagist is not supported');
} }
@ -138,16 +130,9 @@
'User-Agent: ncc' 'User-Agent: ncc'
]; ];
$resolved_host = Resolver::getResolveOption($endpoint);
if($resolved_host !== null)
{
curl_setopt($curl, CURLOPT_RESOLVE, [$resolved_host]);
}
curl_setopt_array($curl, [ curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => HttpRequestType::GET->value, CURLOPT_CUSTOMREQUEST => HttpRequestType::GET,
CURLOPT_HTTPHEADER => $headers CURLOPT_HTTPHEADER => $headers
]); ]);
@ -178,21 +163,23 @@
{ {
$versions = self::getVersions($repository, $vendor, $project); $versions = self::getVersions($repository, $vendor, $project);
// Filter out pre-release versions such as alpha, beta, rc, dev /** @noinspection KeysFragmentationWithArrayFunctionsInspection */
$versions = array_filter($versions, static function($version) $versions = array_filter($versions, static function($version)
{ {
return !preg_match('/-alpha|-beta|-rc|dev/i', $version); return !preg_match('/-alpha|-beta|-rc|dev/i', $version);
}); });
// Sort versions in descending order using Semver::rsort usort($versions, static function($a, $b)
$versions = Semver::rsort($versions); {
return Comparator::lessThanOrEqualTo($a, $b) ? 1 : -1;
});
if (!isset($versions[0])) if($versions[0] === null)
{ {
throw new NetworkException(sprintf('Failed to resolve latest version for %s/%s', $vendor, $project)); throw new NetworkException(sprintf('Failed to resolve latest version for %s/%s', $vendor, $project));
} }
return $versions[0]; // The first version in the sorted array is the latest return $versions[0];
} }
/** /**

View file

@ -24,13 +24,33 @@
use ncc\ThirdParty\nikic\PhpParser\Comment; use ncc\ThirdParty\nikic\PhpParser\Comment;
use ncc\ThirdParty\nikic\PhpParser\Node; use ncc\ThirdParty\nikic\PhpParser\Node;
use ncc\ThirdParty\nikic\PhpParser\NodeTraverser;
use ReflectionClass; use ReflectionClass;
use ReflectionException; use ReflectionException;
use RuntimeException; use RuntimeException;
class AstWalker class AstWalker
{ {
/**
* Returns an array representation of the node recursively
*
* @param array|Node $node
* @return array
*/
public static function serialize(array|Node $node): array
{
if(is_array($node))
{
$serialized = [];
foreach($node as $sub_node)
{
$serialized[] = $sub_node->jsonSerialize();
}
return $serialized;
}
return $node->jsonSerialize();
}
/** /**
* Returns an array of classes associated with the node recursively * Returns an array of classes associated with the node recursively
* *
@ -40,10 +60,9 @@
*/ */
public static function extractClasses(Node|array $node, string $prefix=''): array public static function extractClasses(Node|array $node, string $prefix=''): array
{ {
$classes = [];
if(is_array($node)) if(is_array($node))
{ {
$classes = [];
foreach($node as $sub_node) foreach($node as $sub_node)
{ {
/** @noinspection SlowArrayOperationsInLoopInspection */ /** @noinspection SlowArrayOperationsInLoopInspection */
@ -52,6 +71,8 @@
return $classes; return $classes;
} }
$classes = [];
if ($node instanceof Node\Stmt\ClassLike) if ($node instanceof Node\Stmt\ClassLike)
{ {
$classes[] = $prefix . $node->name; $classes[] = $prefix . $node->name;
@ -59,9 +80,9 @@
if ($node instanceof Node\Stmt\Namespace_) if ($node instanceof Node\Stmt\Namespace_)
{ {
if ($node->name && $node->name->getParts()) if ($node->name && $node->name->parts)
{ {
$prefix .= implode('\\', $node->name->getParts()) . '\\'; $prefix .= implode('\\', $node->name->parts) . '\\';
} }
else else
{ {
@ -91,4 +112,146 @@
return $classes; return $classes;
} }
/**
* Reconstructs nodes from an array representation recursively
*
* @param $value
* @return array|Comment|Node
* @noinspection PhpMissingReturnTypeInspection
* @throws ReflectionException
*/
public static function decodeRecursive($value)
{
if (is_array($value))
{
if (isset($value['nodeType']))
{
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc')
{
return self::decodeComment($value);
}
return self::decodeNode($value);
}
return self::decodeArray($value);
}
return $value;
}
/**
* Decodes an array by recursively decoding each value
*
* @param array $array
* @return array
* @throws ReflectionException
*/
private static function decodeArray(array $array) : array
{
$decoded_array = [];
foreach ($array as $key => $value)
{
$decoded_array[$key] = self::decodeRecursive($value);
}
return $decoded_array;
}
/**
* Returns the node from the node type
*
* @param array $value
* @return Node
* @throws ReflectionException
*/
private static function decodeNode(array $value) : Node
{
$node_type = $value['nodeType'];
if (!is_string($node_type))
{
throw new RuntimeException('Node type must be a string');
}
/** @var Node $node */
$node = self::reflectionClassFromNodeType($node_type)->newInstanceWithoutConstructor();
if (isset($value['attributes'])) {
if (!is_array($value['attributes']))
{
throw new RuntimeException('Attributes must be an array');
}
$node->setAttributes(self::decodeArray($value['attributes']));
}
foreach ($value as $name => $sub_node) {
if ($name === 'nodeType' || $name === 'attributes')
{
continue;
}
$node->$name = self::decodeRecursive($sub_node);
}
return $node;
}
/**
* Returns the comment from the node type
*
* @param array $value
* @return Comment
*/
private static function decodeComment(array $value): Comment
{
$class_name = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
if (!isset($value['text']))
{
throw new RuntimeException('Comment must have text');
}
return new $class_name(
$value['text'],
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
);
}
/**
* Returns the reflection class from the node type
*
* @param string $node_type
* @return ReflectionClass
* @throws ReflectionException
*/
private static function reflectionClassFromNodeType(string $node_type): ReflectionClass
{
return new ReflectionClass(self::classNameFromNodeType($node_type));
}
/**
* Returns the class name from the node type
*
* @param string $nodeType
* @return string
*/
private static function classNameFromNodeType(string $nodeType): string
{
$class_name = 'ncc\\ThirdParty\\nikic\\PhpParser\\Node\\' . str_replace('_', '\\', $nodeType);
if (class_exists($class_name))
{
return $class_name;
}
$class_name .= '_';
if (class_exists($class_name))
{
return $class_name;
}
throw new RuntimeException("Unknown node type \"$nodeType\"");
}
} }

View file

@ -31,7 +31,6 @@
use ncc\ThirdParty\Symfony\Process\ExecutableFinder; use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\ThirdParty\Symfony\Process\Process; use ncc\ThirdParty\Symfony\Process\Process;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\ConsoleProgressBar;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
@ -41,7 +40,7 @@
* @inheritDoc * @inheritDoc
* @throws BuildException * @throws BuildException
*/ */
public function build(string $build_configuration = BuildConfigurationValues::DEFAULT->value, array $options=[]): string public function build(string $build_configuration = BuildConfigurationValues::DEFAULT, array $options=[]): string
{ {
$configuration = $this->getProjectManager()->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration); $configuration = $this->getProjectManager()->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration);
@ -50,14 +49,14 @@
$configuration->setOptions(array_merge($configuration->getOptions(), $options)); $configuration->setOptions(array_merge($configuration->getOptions(), $options));
} }
if(!isset($configuration->getOptions()[BuildConfigurationOptions::NCC_CONFIGURATION->value])) if(!isset($configuration->getOptions()[BuildConfigurationOptions::NCC_CONFIGURATION]))
{ {
throw new BuildException(sprintf("Unable to compile the binary, the build configuration '%s' does not have a ncc_configuration.", $build_configuration)); throw new BuildException(sprintf("Unable to compile the binary, the build configuration '%s' does not have a ncc_configuration.", $build_configuration));
} }
// Build the ncc package first // Build the ncc package first
Console::outVerbose('Building ncc package.'); Console::outVerbose('Building ncc package.');
$ncc_package = parent::build($configuration->getOptions()[BuildConfigurationOptions::NCC_CONFIGURATION->value]); $ncc_package = parent::build($configuration->getOptions()[BuildConfigurationOptions::NCC_CONFIGURATION]);
// Prepare the ncc package for compilation // Prepare the ncc package for compilation
$hex_dump_file = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . $this->getProjectManager()->getProjectConfiguration()->getAssembly()->getName() . '.c'; $hex_dump_file = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . $this->getProjectManager()->getProjectConfiguration()->getAssembly()->getName() . '.c';
@ -72,11 +71,11 @@
// Prepare the gcc command // Prepare the gcc command
$gcc_path = (new ExecutableFinder())->find('gcc'); $gcc_path = (new ExecutableFinder())->find('gcc');
if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE->value])) if(isset($configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE]))
{ {
$binary_path = ConstantCompiler::compileConstants( $binary_path = ConstantCompiler::compileConstants(
$this->getProjectManager()->getProjectConfiguration(), $this->getProjectManager()->getProjectConfiguration(),
$configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE->value] $configuration->getOptions()[BuildConfigurationOptions::OUTPUT_FILE]
); );
} }
else else
@ -84,12 +83,6 @@
$binary_path = ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutput()); $binary_path = ConstantCompiler::compileConstants($this->getProjectManager()->getProjectConfiguration(), $configuration->getOutput());
} }
// Create the directory recursively if it does not exist
if(!is_dir(dirname($binary_path)))
{
mkdir(dirname($binary_path), 0777, true);
}
if($gcc_path === null) if($gcc_path === null)
{ {
throw new BuildException("Unable to find gcc executable, please make sure it is installed and in your PATH environment variable."); throw new BuildException("Unable to find gcc executable, please make sure it is installed and in your PATH environment variable.");
@ -175,37 +168,34 @@
*/ */
private function hexDump(string $input_path, string $output_path, string $variable_name): void private function hexDump(string $input_path, string $output_path, string $variable_name): void
{ {
Console::outVerbose(sprintf('Processing %s to hex dump', $input_path)); Console::out(sprintf('Processing %s to hex dump', $input_path));
$input = fopen($input_path, 'rb'); $input = fopen($input_path, 'rb');
$output = fopen($output_path, 'wb'); $output = fopen($output_path, 'wb');
$byte_count = 0; $byte_count = 0;
$progress_bar = new ConsoleProgressBar(sprintf('HexDump %s', $input_path), filesize($input_path)); $total_bytes = filesize($input_path);
fwrite($output, sprintf("unsigned char %s[] = {\n", Functions::toSnakeCase($variable_name))); fwrite($output, sprintf("unsigned char %s[] = {\n", Functions::toSnakeCase($variable_name)));
// Convert the binary data to hex and write it to the output file using chunks
// Convert the binary data to hex and write it to the output file
while (!feof($input)) while (!feof($input))
{ {
$bytes = fread($input, 5026); Console::inlineProgressBar(ftell($input), $total_bytes);
$len = strlen($bytes);
for ($i = 0; $i < $len; $i++) $byte = fread($input, 1);
if (strlen($byte) === 1)
{ {
fwrite($output, sprintf(" 0x%02x,", ord($bytes[$i]))); fwrite($output, sprintf(" 0x%02x,", ord($byte)));
$byte_count++; $byte_count++;
}
// Write 12 bytes per line or when reaching the end of the file // Write 12 bytes per line or when reaching the end of the file
if ($byte_count === 12 || ($i == $len - 1 && feof($input))) if ($byte_count === 12 || feof($input))
{ {
fwrite($output, "\n"); fwrite($output, "\n");
$byte_count = 0; $byte_count = 0;
} }
} }
$progress_bar->increaseValue($len, true);
$progress_bar->setMiscText(sprintf('Processed (%d/%d)', $progress_bar->getValue(), $progress_bar->getMaxValue()));
}
// Close the output file // Close the output file
fseek($output, -2, SEEK_END); fseek($output, -2, SEEK_END);
fwrite($output, "\n"); fwrite($output, "\n");
@ -214,9 +204,5 @@
// Finally, close the input and output files // Finally, close the input and output files
fclose($input); fclose($input);
fclose($output); fclose($output);
// Close the progress bar
$progress_bar->setMiscText('done', true);
unset($progress_bar);
} }
} }

View file

@ -1,74 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension;
use ncc\ThirdParty\nikic\PhpParser\Node;
use ncc\ThirdParty\nikic\PhpParser\NodeVisitorAbstract;
use ncc\Utilities\Console;
class ExpressionTraverser extends NodeVisitorAbstract
{
/**
* @var string|null
*/
private ?string $package;
/**
* ExpressionTraverser constructor.
*
* @param string|null $package
*/
public function __construct(?string $package)
{
$this->package = $package;
}
/**
* @param Node $node
* @return array|int|Node|null
*/
public function leaveNode(Node $node): array|int|Node|null
{
if($node instanceof Node\Expr\Include_)
{
Console::outDebug(sprintf('Processing ExpressionTraverser on: %s', $node->getType()));
$args = [$node->expr];
if(!is_null($this->package))
{
$args[] = new Node\Arg(new Node\Scalar\String_($this->package));
}
$types = [
Node\Expr\Include_::TYPE_INCLUDE => '\ncc\Classes\Runtime::runtimeInclude',
Node\Expr\Include_::TYPE_INCLUDE_ONCE => '\ncc\Classes\Runtime::runtimeIncludeOnce',
Node\Expr\Include_::TYPE_REQUIRE => '\ncc\Classes\Runtime::runtimeRequire',
Node\Expr\Include_::TYPE_REQUIRE_ONCE => '\ncc\Classes\Runtime::runtimeRequireOnce',
];
return new Node\Expr\FuncCall(new Node\Name($types[$node->type]), $args);
}
return null;
}
}

View file

@ -30,9 +30,7 @@
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Extensions\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\ThirdParty\nikic\PhpParser\NodeDumper;
use ncc\ThirdParty\nikic\PhpParser\ParserFactory; use ncc\ThirdParty\nikic\PhpParser\ParserFactory;
use ncc\ThirdParty\nikic\PhpParser\PhpVersion;
use ncc\Utilities\Base64; use ncc\Utilities\Base64;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
@ -54,9 +52,10 @@
try try
{ {
$stmts = ((new ParserFactory())->createForNewestSupportedVersion())->parse(IO::fread($file_path)); $stmts = (new ParserFactory())->create(ParserFactory::PREFER_PHP7)->parse(IO::fread($file_path));
$component = new Component($component_name, ZiProto::encode(Serializer::nodesToArray($stmts)), ComponentDataType::AST);
$component->addFlag(ComponentFlags::PHP_AST->value); $component = new Component($component_name, ZiProto::encode($stmts), ComponentDataType::AST);
$component->addFlag(ComponentFlags::PHP_AST);
$pointer = $package_writer->addComponent($component); $pointer = $package_writer->addComponent($component);
foreach(AstWalker::extractClasses($stmts) as $class) foreach(AstWalker::extractClasses($stmts) as $class)
@ -72,7 +71,7 @@
} }
$component = new Component($component_name, Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED); $component = new Component($component_name, Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED);
$component->addFlag(ComponentFlags::PHP_B64->value); $component->addFlag(ComponentFlags::PHP_B64);
$package_writer->addComponent($component); $package_writer->addComponent($component);
} }
} }

View file

@ -44,7 +44,7 @@
*/ */
public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int
{ {
if($unit->getExecutionPolicy()->getRunner() !== Runners::PHP->value) if($unit->getExecutionPolicy()->getRunner() !== Runners::PHP)
{ {
throw new InvalidArgumentException(sprintf('The execution unit %s is not a php execution unit', $unit->getExecutionPolicy()->getName())); throw new InvalidArgumentException(sprintf('The execution unit %s is not a php execution unit', $unit->getExecutionPolicy()->getName()));
} }

View file

@ -1,151 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2024, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension;
use ncc\ThirdParty\nikic\PhpParser\Comment;
use ncc\ThirdParty\nikic\PhpParser\Node;
use ncc\ThirdParty\nikic\PhpParser\NodeAbstract;
use ReflectionClass;
use RuntimeException;
use function is_array;
use function is_string;
class Serializer
{
/** @var ReflectionClass<Node>[] Node type to reflection class map */
private static array $reflectionClassCache;
/**
* @param NodeAbstract[] $nodeAbstracts
* @return array
*/
public static function nodesToArray(array $nodeAbstracts): array
{
$serialized = [];
foreach ($nodeAbstracts as $nodeAbstract)
{
$serialized[] = $nodeAbstract->jsonSerialize();
}
return $serialized;
}
/**
* @param array $nodeAbstracts
* @return NodeAbstract[]
*/
public static function arrayToNodes(array $nodeAbstracts): array
{
return self::decodeRecursive($nodeAbstracts);
}
/**
* @param mixed $value
* @return mixed
*/
private static function decodeRecursive($value) {
if (is_array($value)) {
if (isset($value['nodeType'])) {
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') {
return self::decodeComment($value);
}
return self::decodeNode($value);
}
return self::decodeArray($value);
}
return $value;
}
private static function decodeArray(array $array): array {
$decodedArray = [];
foreach ($array as $key => $value) {
$decodedArray[$key] = self::decodeRecursive($value);
}
return $decodedArray;
}
private static function decodeNode(array $value): Node {
$nodeType = $value['nodeType'];
if (!is_string($nodeType)) {
throw new RuntimeException('Node type must be a string');
}
$reflectionClass = self::reflectionClassFromNodeType($nodeType);
$node = $reflectionClass->newInstanceWithoutConstructor();
if (isset($value['attributes'])) {
if (!is_array($value['attributes'])) {
throw new RuntimeException('Attributes must be an array');
}
$node->setAttributes(self::decodeArray($value['attributes']));
}
foreach ($value as $name => $subNode) {
if ($name === 'nodeType' || $name === 'attributes') {
continue;
}
$node->$name = self::decodeRecursive($subNode);
}
return $node;
}
private static function decodeComment(array $value): Comment {
$className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
if (!isset($value['text'])) {
throw new RuntimeException('Comment must have text');
}
return new $className(
$value['text'],
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
);
}
private static function reflectionClassFromNodeType(string $nodeType): ReflectionClass {
if (!isset(self::$reflectionClassCache[$nodeType])) {
$className = self::classNameFromNodeType($nodeType);
self::$reflectionClassCache[$nodeType] = new ReflectionClass($className);
}
return self::$reflectionClassCache[$nodeType];
}
/** @return class-string<Node> */
private static function classNameFromNodeType(string $nodeType): string {
$className = '\\ncc\\ThirdParty\\nikic\\PhpParser\\Node\\' . strtr($nodeType, '_', '\\');
if (class_exists($className)) {
return $className;
}
$className .= '_';
if (class_exists($className)) {
return $className;
}
throw new RuntimeException("Unknown node type \"$nodeType\"");
}
}

View file

@ -49,31 +49,32 @@
public static function applyTemplate(ProjectManager $project_manager): void public static function applyTemplate(ProjectManager $project_manager): void
{ {
$project_manager->getProjectConfiguration()->addExecutionPolicy( $project_manager->getProjectConfiguration()->addExecutionPolicy(
new ExecutionPolicy('main_policy', Runners::PHP->value, new ExecutionPolicy\Execute('main')) new ExecutionPolicy('main_policy', Runners::PHP, new ExecutionPolicy\Execute('main'))
); );
$project_manager->getProjectConfiguration()->getBuild()->setMain('main_policy'); $project_manager->getProjectConfiguration()->getBuild()->setMain('main_policy');
$project_manager->getProjectConfiguration()->getProject()->addOption(ProjectOptions::CREATE_SYMLINK->value, true); $project_manager->getProjectConfiguration()->getProject()->addOption(ProjectOptions::CREATE_SYMLINK, true);
// Create the release build configuration // Create the release build configuration
$release_executable = new BuildConfiguration('release_executable', $release_executable = new BuildConfiguration('release_executable',
'build' . DIRECTORY_SEPARATOR . 'release' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_NAME->value 'build' . DIRECTORY_SEPARATOR . 'release' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_NAME
); );
$release_executable->setBuildType(BuildOutputType::EXECUTABLE->value); $release_executable->setBuildType(BuildOutputType::EXECUTABLE);
$release_executable->setOption(BuildConfigurationOptions::NCC_CONFIGURATION->value, 'release'); $release_executable->setOption(BuildConfigurationOptions::NCC_CONFIGURATION, 'release');
$project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($release_executable); $project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($release_executable);
// Create the debug build configuration // Create the debug build configuration
$debug_executable = new BuildConfiguration('debug_executable', $debug_executable = new BuildConfiguration('debug_executable',
'build' . DIRECTORY_SEPARATOR . 'debug' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_NAME->value 'build' . DIRECTORY_SEPARATOR . 'debug' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_NAME
); );
$debug_executable->setDefinedConstant('DEBUG', '1'); $debug_executable->setDefinedConstant('DEBUG', '1');
$debug_executable->setBuildType(BuildOutputType::EXECUTABLE->value); $debug_executable->setBuildType(BuildOutputType::EXECUTABLE);
$debug_executable->setOption(BuildConfigurationOptions::NCC_CONFIGURATION->value, 'debug'); $debug_executable->setOption(BuildConfigurationOptions::NCC_CONFIGURATION, 'debug');
$project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($debug_executable); $project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($debug_executable);
self::writeProgramTemplate($project_manager); self::writeProgramTemplate($project_manager);
self::writeMainEntryTemplate($project_manager); self::writeMainEntryTemplate($project_manager);
self::writeMakefileTemplate($project_manager);
$project_manager->save(); $project_manager->save();
} }
@ -113,4 +114,22 @@
) )
); );
} }
/**
* Writes the Makefile to the project directory
*
* @param ProjectManager $project_manager
* @return void
* @throws IOException
* @throws PathNotFoundException
*/
private static function writeMakefileTemplate(ProjectManager $project_manager): void
{
IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'Makefile',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'Makefile.tpl')
)
);
}
} }

View file

@ -1,61 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2024, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension\Templates;
use ncc\Enums\Options\BuildConfigurationOptions;
use ncc\Enums\SpecialConstants\AssemblyConstants;
use ncc\Enums\Types\BuildOutputType;
use ncc\Exceptions\IOException;
use ncc\Interfaces\TemplateInterface;
use ncc\Managers\ProjectManager;
use ncc\Objects\ProjectConfiguration\Build\BuildConfiguration;
class CompressedTemplate implements TemplateInterface
{
/**
* @inheritDoc
* @throws IOException
*/
public static function applyTemplate(ProjectManager $project_manager): void
{
// Create the release build configuration
$release_compressed = new BuildConfiguration('release-compressed',
'build' . DIRECTORY_SEPARATOR . 'release' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_PACKAGE->value . '.gz.ncc'
);
$release_compressed->setBuildType(BuildOutputType::NCC_PACKAGE->value);
$release_compressed->setOption(BuildConfigurationOptions::COMPRESSION->value, BuildConfigurationOptions\CompressionOptions::HIGH->value);
$project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($release_compressed);
// Create the debug build configuration
$debug_compressed = new BuildConfiguration('debug-compressed',
'build' . DIRECTORY_SEPARATOR . 'debug' . DIRECTORY_SEPARATOR . AssemblyConstants::ASSEMBLY_PACKAGE->value . '.gz.ncc'
);
$debug_compressed->setBuildType(BuildOutputType::NCC_PACKAGE->value);
$debug_compressed->setOption(BuildConfigurationOptions::COMPRESSION->value, BuildConfigurationOptions\CompressionOptions::HIGH->value);
$debug_compressed->setDefinedConstant('DEBUG', '1');
$project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($debug_compressed);
$project_manager->save();
}
}

View file

@ -1,77 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2024, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension\Templates;
use ncc\Enums\Options\BuildConfigurationOptions;
use ncc\Enums\SpecialConstants\AssemblyConstants;
use ncc\Enums\Types\BuildOutputType;
use ncc\Exceptions\IOException;
use ncc\Interfaces\TemplateInterface;
use ncc\Managers\ProjectManager;
use ncc\Objects\ProjectConfiguration\Build\BuildConfiguration;
class ExecutableTemplate implements TemplateInterface
{
/**
* @inheritDoc
* @throws IOException
*/
public static function applyTemplate(ProjectManager $project_manager): void
{
foreach($project_manager->getProjectConfiguration()->getBuild()->getBuildConfigurations() as $build_configuration)
{
$executable_name = sprintf('%s-executable', $build_configuration);
$configuration = $project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration);
// Skip if the executable version of the build configuration already exists
if($project_manager->getProjectConfiguration()->getBuild()->buildConfigurationExists($executable_name))
{
continue;
}
// Skip if the build configuration is not an ncc package that the executable can be based on
if($configuration->getBuildType() !== BuildOutputType::NCC_PACKAGE->value)
{
continue;
}
if(isset($configuration->getOptions()[BuildConfigurationOptions::COMPRESSION->value]))
{
$output = dirname($configuration->getOutput()) . DIRECTORY_SEPARATOR . str_replace('-', '_', $executable_name);
}
else
{
$output = dirname($configuration->getOutput()) . DIRECTORY_SEPARATOR . str_replace('-', '_', $executable_name) . '_gz';
}
// Create the executable build configuration
$executable = new BuildConfiguration($executable_name, $output);
$executable->setBuildType(BuildOutputType::EXECUTABLE->value);
$executable->setOption(BuildConfigurationOptions::NCC_CONFIGURATION->value, $configuration->getName());
$project_manager->getProjectConfiguration()->getBuild()->addBuildConfiguration($executable);
}
$project_manager->save();
}
}

View file

@ -1,117 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2024, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension\Templates;
use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Managers\ProjectManager;
use ncc\Utilities\IO;
class GitHubWorkflowTemplate
{
/**
* @inheritDoc
* @param ProjectManager $project_manager
* @throws IOException
* @throws PathNotFoundException
*/
public static function applyTemplate(ProjectManager $project_manager): void
{
self::writeCiTemplate($project_manager);
}
/**
* Writes the Makefile to the project directory
*
* @param ProjectManager $project_manager
* @return void
* @throws IOException
* @throws PathNotFoundException
*/
private static function writeCiTemplate(ProjectManager $project_manager): void
{
$ci_dir = $project_manager->getProjectPath() . DIRECTORY_SEPARATOR . '.github' . DIRECTORY_SEPARATOR . 'workflows';
if(!file_exists($ci_dir))
{
mkdir($ci_dir, 0777, true);
}
$template = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'github_ci.yml.tpl');
$default_configuration = $project_manager->getProjectConfiguration()->getBuild()->getDefaultConfiguration();
$builds = [];
$releases = [];
$downloads = [];
foreach($project_manager->getProjectConfiguration()->getBuild()->getBuildConfigurations() as $build_name)
{
$build_template = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'github_ci_build.yml.tpl');
$build_template = str_replace('%TPL_BUILD_NAME%', $build_name, $build_template);
$build_template = str_replace('%TPL_BUILD_OUTPUT%',
$project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_name)->getOutput(),
$build_template
);
$builds[$build_name] = $build_template;
$download_template = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'github_ci_download.yml.tpl');
$download_template = str_replace('%TPL_BUILD_NAME%', $build_name, $download_template);
$downloads[$build_name] = $download_template;
$release_template = str_repeat(' ', 12) . $build_name . DIRECTORY_SEPARATOR . basename(
$project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_name)->getOutput()
);
$releases[$build_name] = $release_template;
}
$build_jobs = '';
foreach($builds as $name => $build_template)
{
$build_jobs .= $build_template . PHP_EOL;
}
$download_jobs = '';
foreach($downloads as $name => $download_template)
{
$download_jobs .= $download_template . PHP_EOL;
}
$release_jobs = '';
foreach($releases as $name => $release_template)
{
$release_jobs .= $release_template . PHP_EOL;
}
$template = str_replace('%TPL_BUILDS%', $build_jobs, $template);
$template = str_replace('%TPL_DOWNLOAD_ARTIFACTS%', $download_jobs, $template);
$template = str_replace('%TPL_ARTIFACT_FILES%', $release_jobs, $template);
$template = str_replace('%TPL_BUILD_NAMES%', implode(', ', array_keys($builds)), $template);
$template = str_replace('%TPL_DEFAULT_BUILD_CONFIGURATION%', $default_configuration, $template);
$template = str_replace('%TPL_DEFAULT_ARTIFACT_BUILD_OUTPUT%', $default_configuration . DIRECTORY_SEPARATOR . basename(
$project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($default_configuration)->getOutput()
), $template);
IO::fwrite($ci_dir . DIRECTORY_SEPARATOR . 'ncc_workflow.yml',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), $template)
);
}
}

View file

@ -48,14 +48,8 @@
*/ */
private static function createClassTemplate(ProjectManager $project_manager): void private static function createClassTemplate(ProjectManager $project_manager): void
{ {
$class_directory = $project_manager->getProjectSourcePath() . DIRECTORY_SEPARATOR . $project_manager->getProjectConfiguration()->getAssembly()->getName();
if(!file_exists($class_directory))
{
mkdir($class_directory, 0777, true);
}
IO::fwrite( IO::fwrite(
$class_directory . DIRECTORY_SEPARATOR . $project_manager->getProjectConfiguration()->getAssembly()->getName() . '.php', $project_manager->getProjectSourcePath() . DIRECTORY_SEPARATOR . $project_manager->getProjectConfiguration()->getAssembly()->getName() . '.php',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'class.php.tpl') IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'class.php.tpl')
) )

View file

@ -1,21 +1,20 @@
# Variables # Variables
DEFAULT_CONFIGURATION ?= %TPL_DEFAULT_BUILD_CONFIGURATION% CONFIG ?= release
LOG_LEVEL = debug LOG_LEVEL = debug
OUTDIR = build/$(CONFIG)
PACKAGE = $(OUTDIR)/%ASSEMBLY.PACKAGE%.ncc
# Default Target # Default Target
all: %TPL_BUILD_NAMES% all: build
# Build Steps # Build Steps
%TPL_BUILDS% build:
ncc build --config=$(CONFIG) --log-level $(LOG_LEVEL)
install: %TPL_DEFAULT_BUILD_CONFIGURATION% install:
ncc package install --package=%TPL_DEFAULT_BUILD_PATH% --skip-dependencies --build-source --reinstall -y --log-level $(LOG_LEVEL) ncc package install --package=$(PACKAGE) --skip-dependencies --reinstall -y --log-level $(LOG_LEVEL)
test: %TPL_DEFAULT_BUILD_CONFIGURATION%
[ -f phpunit.xml ] || { echo "phpunit.xml not found"; exit 1; }
phpunit
clean: clean:
rm -rf build rm -rf build
.PHONY: all install test clean %TPL_BUILD_NAMES% .PHONY: all build install clean

View file

@ -1,78 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2024, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension\Templates;
use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Managers\ProjectManager;
use ncc\Utilities\IO;
class MakefileTemplate
{
/**
* @inheritDoc
* @param ProjectManager $project_manager
* @throws IOException
* @throws PathNotFoundException
*/
public static function applyTemplate(ProjectManager $project_manager): void
{
self::writeMakefileTemplate($project_manager);
}
/**
* Writes the Makefile template for the given project.
*
* @param ProjectManager $project_manager The project manager containing project configurations.
* @throws IOException If there is an error reading or writing files.
* @throws PathNotFoundException If a required file path is not found.
*/
private static function writeMakefileTemplate(ProjectManager $project_manager): void
{
$makefile_template = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'Makefile.tpl');
$builds = [];
foreach($project_manager->getProjectConfiguration()->getBuild()->getBuildConfigurations() as $build_name)
{
$builds[$build_name] = str_replace('%TPL_BUILD_NAME%', $build_name, IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'make_build.tpl'));
}
$default_build = $project_manager->getProjectConfiguration()->getBuild()->getDefaultConfiguration();
$makefile_template = str_replace('%TPL_DEFAULT_BUILD_CONFIGURATION%', $default_build, $makefile_template);
$makefile_template = str_replace('%TPL_DEFAULT_BUILD_PATH%', $project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($default_build)->getOutput(), $makefile_template);
$makefile_template = str_replace('%TPL_BUILD_NAMES%', implode(' ', array_keys($builds)), $makefile_template);
$build_template = '';
foreach($builds as $name => $template)
{
$build_template .= $template . PHP_EOL;
}
$makefile_template = str_replace('%TPL_BUILDS%', $build_template, $makefile_template);
IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'Makefile',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), $makefile_template)
);
}
}

View file

@ -1,93 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension\Templates;
use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Enums\Options\BuildConfigurationOptions;
use ncc\Enums\Options\ProjectOptions;
use ncc\Enums\Runners;
use ncc\Enums\SpecialConstants\AssemblyConstants;
use ncc\Enums\Types\BuildOutputType;
use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\TemplateInterface;
use ncc\Managers\ProjectManager;
use ncc\Objects\ProjectConfiguration\Build\BuildConfiguration;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\IO;
class PhpUnitTemplate implements TemplateInterface
{
/**
* Applies the necessary templates for the given project.
*
* @param ProjectManager $project_manager Manager responsible for handling project-related tasks.
*
* @return void
*/
public static function applyTemplate(ProjectManager $project_manager): void
{
self::createPhpUnitBootstrapTemplate($project_manager);
self::createPhpUnitTemplate($project_manager);
}
/**
* Creates a PHPUnit template in the specified project directory.
*
* @param ProjectManager $project_manager The project manager instance containing project configuration and path details.
* @return void
* @throws IOException
* @throws PathNotFoundException
*/
private static function createPhpUnitTemplate(ProjectManager $project_manager): void
{
IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'phpunit.xml',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.tpl')
)
);
if(!file_exists($project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'tests'))
{
mkdir($project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'tests');
}
}
/**
* Creates the PHPUnit bootstrap template file for the given project.
*
* @param ProjectManager $project_manager The project manager instance handling project configuration and paths.
* @return void
*/
private static function createPhpUnitBootstrapTemplate(ProjectManager $project_manager): void
{
IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'bootstrap.php',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'bootstrap.php.tpl')
)
);
}
}

View file

@ -1,3 +0,0 @@
<?php
require 'ncc';
import('%ASSEMBLY.PACKAGE%');

View file

@ -1,187 +0,0 @@
name: CI
on:
push:
branches:
- '**'
release:
types: [created]
workflow_dispatch:
jobs:
%TPL_BUILDS%
# Checking for phpunit.xml
check-phpunit:
runs-on: ubuntu-latest
outputs:
phpunit-exists: ${{ steps.check.outputs.phpunit-exists }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check for phpunit.xml
id: check
run: |
if [ -f phpunit.xml ]; then
echo "phpunit-exists=true" >> $GITHUB_OUTPUT
else
echo "phpunit-exists=false" >> $GITHUB_OUTPUT
fi
# Checking for phpdoc.dist.xml
check-phpdoc:
runs-on: ubuntu-latest
outputs:
phpdoc-exists: ${{ steps.check.outputs.phpdoc-exists }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check for phpdoc.dist.xml
id: check
run: |
if [ -f phpdoc.dist.xml ]; then
echo "phpdoc-exists=true" >> $GITHUB_OUTPUT
else
echo "phpdoc-exists=false" >> $GITHUB_OUTPUT
fi
generate-phpdoc:
needs: [%TPL_DEFAULT_BUILD_CONFIGURATION%, check-phpdoc]
runs-on: ubuntu-latest
container:
image: php:8.3
if: needs.check-phpdoc.outputs.phpdoc-exists == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Download PHPDocumentor
run: |
wget https://phpdoc.org/phpDocumentor.phar
chmod +x phpDocumentor.phar
- name: Generate PHPDoc
run: |
php phpDocumentor.phar -d src -t docs
- name: Archive PHPDoc
run: |
zip -r docs.zip docs
- name: Upload PHPDoc
uses: actions/upload-artifact@v4
with:
name: documentation
path: docs.zip
test:
needs: [%TPL_BUILD_NAMES%, check-phpunit]
runs-on: ubuntu-latest
container:
image: php:8.3
if: needs.check-phpunit.outputs.phpunit-exists == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: %TPL_DEFAULT_BUILD_CONFIGURATION%
path: %TPL_DEFAULT_BUILD_CONFIGURATION%
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
curl -sSLf -o /usr/local/bin/install-php-extensions https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions
chmod +x /usr/local/bin/install-php-extensions
install-php-extensions zip
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Install NCC packages
run: |
ncc package install --package="%TPL_DEFAULT_ARTIFACT_BUILD_OUTPUT%" --build-source --reinstall -y --log-level debug
- name: Run PHPUnit tests
run: |
wget https://phar.phpunit.de/phpunit-11.3.phar
php phpunit-11.3.phar --configuration phpunit.xml --log-junit reports/junit.xml --log-teamcity reports/teamcity --testdox-html reports/testdox.html --testdox-text reports/testdox.txt
- name: Upload test reports
uses: actions/upload-artifact@v4
with:
name: reports
path: reports
release-documentation:
needs: generate-phpdoc
permissions: write-all
runs-on: ubuntu-latest
container:
image: php:8.3
if: github.event_name == 'release'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download documentation artifact
uses: actions/download-artifact@v4
with:
name: documentation
path: documentation
- name: Upload documentation artifact
uses: softprops/action-gh-release@v1
with:
files: |
documentation/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-artifacts:
needs: [%TPL_BUILD_NAMES%]
permissions: write-all
runs-on: ubuntu-latest
container:
image: php:8.3
if: github.event_name == 'release'
steps:
- name: Checkout repository
uses: actions/checkout@v4
%TPL_DOWNLOAD_ARTIFACTS%

View file

@ -1,49 +0,0 @@
%TPL_BUILD_NAME%:
runs-on: ubuntu-latest
container:
image: php:8.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt update -yqq
apt install git libpq-dev libzip-dev zip make wget gnupg -yqq
- name: Install phive
run: |
wget -O phive.phar https://phar.io/releases/phive.phar
wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc
gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x9D8A98B29B2D5D79
gpg --verify phive.phar.asc phive.phar
chmod +x phive.phar
mv phive.phar /usr/local/bin/phive
- name: Install phab
run: |
phive install phpab --global --trust-gpg-keys 0x2A8299CE842DD38C
- name: Install latest version of NCC
run: |
git clone https://git.n64.cc/nosial/ncc.git
cd ncc
make redist
NCC_DIR=$(find build/ -type d -name "ncc_*" | head -n 1)
if [ -z "$NCC_DIR" ]; then
echo "NCC build directory not found"
exit 1
fi
php "$NCC_DIR/INSTALL" --auto
cd .. && rm -rf ncc
- name: Build project
run: |
ncc build --config %TPL_BUILD_NAME% --build-source --log-level debug
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: %TPL_BUILD_NAME%
path: %TPL_BUILD_OUTPUT%

View file

@ -1,12 +0,0 @@
- name: Download %TPL_BUILD_NAME% artifact
uses: actions/download-artifact@v4
with:
name: %TPL_BUILD_NAME%
path: %TPL_BUILD_NAME%
- name: Upload %TPL_BUILD_NAME% artifact to release
uses: softprops/action-gh-release@v1
with:
files: |
%TPL_BUILD_NAME%/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,2 +0,0 @@
%TPL_BUILD_NAME%:
ncc build --config=%TPL_BUILD_NAME% --log-level $(LOG_LEVEL)

View file

@ -1,11 +0,0 @@
<phpunit bootstrap="bootstrap.php">
<testsuites>
<testsuite name="%ASSEMBLY.NAME% Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<server name="KERNEL_DIR" value="app/"/>
</php>
</phpunit>

View file

@ -29,12 +29,9 @@
use ncc\Enums\FileDescriptor; use ncc\Enums\FileDescriptor;
use ncc\Enums\Flags\PackageFlags; use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\Options\BuildConfigurationOptions; use ncc\Enums\Options\BuildConfigurationOptions;
use ncc\Enums\Options\ComponentDecodeOptions;
use ncc\Enums\PackageDirectory;
use ncc\Enums\Versions; use ncc\Enums\Versions;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\ImportException; use ncc\Exceptions\ImportException;
use ncc\Exceptions\IntegrityException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException; use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException; use ncc\Exceptions\OperationException;
@ -42,14 +39,8 @@
use ncc\Extensions\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use ncc\Managers\PackageManager; use ncc\Managers\PackageManager;
use ncc\Objects\Package\Metadata; use ncc\Objects\Package\Metadata;
use ncc\Utilities\Console;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache;
use ncc\Utilities\Validate;
use RuntimeException; use RuntimeException;
use Throwable;
use function trigger_error;
class Runtime class Runtime
{ {
@ -68,26 +59,19 @@
*/ */
private static $package_manager; private static $package_manager;
/**
* @var array
*/
private static $included_files = [];
/** /**
* Executes the main execution point of an imported package and returns the evaluated result * Executes the main execution point of an imported package and returns the evaluated result
* This method may exit the program without returning a value * This method may exit the program without returning a value
* *
* @param string $package * @param string $package
* @param array $arguments
* @return mixed * @return mixed
* @throws ConfigurationException * @throws ConfigurationException
* @throws IOException * @throws IOException
* @throws IntegrityException
* @throws NotSupportedException * @throws NotSupportedException
* @throws OperationException
* @throws PathNotFoundException * @throws PathNotFoundException
* @throws OperationException
*/ */
public static function execute(string $package, array $arguments=[]): int public static function execute(string $package): int
{ {
if(!self::isImported($package)) if(!self::isImported($package))
{ {
@ -96,12 +80,6 @@
if(self::$imported_packages[$package] instanceof PackageReader) if(self::$imported_packages[$package] instanceof PackageReader)
{ {
if(self::$imported_packages[$package]?->getMetadata()?->getMainExecutionPolicy() === null)
{
Console::out('The package does not have a main execution policy, skipping execution');
return 0;
}
return ExecutionUnitRunner::executeFromPackage( return ExecutionUnitRunner::executeFromPackage(
self::$imported_packages[$package], self::$imported_packages[$package],
self::$imported_packages[$package]->getMetadata()->getMainExecutionPolicy() self::$imported_packages[$package]->getMetadata()->getMainExecutionPolicy()
@ -110,7 +88,7 @@
if(is_string(self::$imported_packages[$package])) if(is_string(self::$imported_packages[$package]))
{ {
$metadata_path = self::$imported_packages[$package] . DIRECTORY_SEPARATOR . FileDescriptor::METADATA->value; $metadata_path = self::$imported_packages[$package] . DIRECTORY_SEPARATOR . FileDescriptor::METADATA;
if(!is_file($metadata_path)) if(!is_file($metadata_path))
{ {
@ -119,8 +97,7 @@
return ExecutionUnitRunner::executeFromSystem( return ExecutionUnitRunner::executeFromSystem(
self::$imported_packages[$package], self::$imported_packages[$package],
Metadata::fromArray(ZiProto::decode(IO::fread($metadata_path)))->getMainExecutionPolicy(), Metadata::fromArray(ZiProto::decode(IO::fread($metadata_path)))->getMainExecutionPolicy()
$arguments
); );
} }
@ -133,7 +110,7 @@
* @return string * @return string
* @throws ImportException * @throws ImportException
*/ */
public static function import(string $package, string $version=Versions::LATEST->value): string public static function import(string $package, string $version=Versions::LATEST): string
{ {
if(self::isImported($package)) if(self::isImported($package))
{ {
@ -172,7 +149,7 @@
} }
} }
throw new RuntimeException(sprintf('Failed to import package "%s" because it does not exist', $package)); throw new RuntimeException('Importing from a package name is not supported yet');
} }
/** /**
@ -185,7 +162,7 @@
* @throws NotSupportedException * @throws NotSupportedException
* @throws PathNotFoundException * @throws PathNotFoundException
*/ */
private static function importFromSystem(string $package, string $version=Versions::LATEST->value): string private static function importFromSystem(string $package, string $version=Versions::LATEST): string
{ {
if(!self::getPackageManager()->getPackageLock()->entryExists($package)) if(!self::getPackageManager()->getPackageLock()->entryExists($package))
{ {
@ -193,7 +170,6 @@
} }
$entry = self::getPackageManager()->getPackageLock()->getEntry($package); $entry = self::getPackageManager()->getPackageLock()->getEntry($package);
self::$imported_packages[$package] = $entry->getPath($version);
foreach($entry->getClassMap($version) as $class => $component_name) foreach($entry->getClassMap($version) as $class => $component_name)
{ {
@ -201,96 +177,33 @@
self::$class_map[strtolower($class)] = $component_path; self::$class_map[strtolower($class)] = $component_path;
} }
if($entry->getMetadata($version)->getOption(BuildConfigurationOptions::REQUIRE_FILES->value) !== null) self::$imported_packages[$package] = $entry->getPath($version);
{
foreach($entry->getMetadata($version)->getOption(BuildConfigurationOptions::REQUIRE_FILES->value) as $item)
{
$required_file = $entry->getPath($version) . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . $item;
try
{
if(!file_exists($required_file))
{
throw new PathNotFoundException($required_file);
}
// Get the file contents and prepare it
$evaluated_code = IO::fread($required_file);
// Remove the PHP tags
$evaluated_code = preg_replace('/^<\?php|<\?PHP/', '', $evaluated_code, 1);
// Replace __DIR__ with the actual directory that the file is in
$evaluated_code = str_replace('__DIR__', sprintf('"%s"', dirname($required_file)), $evaluated_code);
set_error_handler(function ($error_number, $message, $file, $line) use ($item, $package)
{
throw new ImportException(sprintf('Fatal Evaluation Error: Failed to import "%s" from %s on %s:%s: %s', $item, $package, $file, $line, $message));
});
// Evaluate the code
eval($evaluated_code);
restore_error_handler();
unset($evaluated_code);
}
catch (ConfigurationException $e)
{
throw new ImportException(sprintf('%s: Failed to import "%s" from %s: %s', $required_file, $item, $package, $e->getMessage()), $e);
}
catch(ImportException $e)
{
throw $e;
}
catch (Throwable $e)
{
throw new ImportException(sprintf('%s: Failed to import "%s" from %s: %s', $required_file, $item, $package, $e->getMessage()), $e);
}
}
}
$safe_package_name = strtoupper($entry->getAssembly($version)->getName());
foreach($entry->getMetadata($version)->getConstants() as $constant => $value)
{
$constant_full_name = sprintf("%s_%s", $safe_package_name, $constant);
// Skip if already defined.
if(defined($constant_full_name))
{
if(RuntimeCache::get(sprintf("defined_%s", $constant_full_name)))
{
continue;
}
trigger_error(sprintf('Cannot define constant %s from package %s because the constant is already defined', $constant_full_name, $package), E_USER_WARNING);
continue;
}
if(!Validate::constantName($constant_full_name))
{
// trigger warning only
trigger_error(sprintf('Cannot define constant %s from package %s because the constant name is invalid', $constant_full_name, $package), E_USER_WARNING);
continue;
}
RuntimeCache::set(sprintf("defined_%s", $constant_full_name), true);
define($constant_full_name, $value);
}
if(isset($entry->getMetadata($version)->getOptions()[PackageFlags::STATIC_DEPENDENCIES->value]))
{
// Fake import the dependencies
foreach($entry->getVersion($version)->getDependencies() as $dependency)
{
self::$imported_packages[$dependency->getName()] = $entry->getPath($version);
}
}
else
{
// Import dependencies recursively // Import dependencies recursively
foreach($entry->getVersion($version)->getDependencies() as $dependency) foreach($entry->getVersion($version)->getDependencies() as $dependency)
{ {
/** @noinspection UnusedFunctionResultInspection */ /** @noinspection UnusedFunctionResultInspection */
self::import($dependency->getName(), $dependency->getVersion()); self::import($dependency->getName(), $dependency->getVersion());
} }
if($entry->getMetadata($version)->getOption(BuildConfigurationOptions::REQUIRE_FILES) !== null)
{
foreach($entry->getMetadata($version)->getOption(BuildConfigurationOptions::REQUIRE_FILES) as $item)
{
try
{
// Get the file contents and prepare it
$required_file = IO::fread($entry->getPath($version) . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . $item);
$required_file = preg_replace('/^<\?php|<\?PHP/', '', $required_file, 1);
eval($required_file);
unset($required_file);
}
catch(ConfigurationException $e)
{
throw new ImportException(sprintf('Failed to import "%s" from %s: %s', $item, $package, $e->getMessage()), $e);
}
}
} }
return $package; return $package;
@ -302,9 +215,10 @@
* @param string $package_path * @param string $package_path
* @return string * @return string
* @throws ConfigurationException * @throws ConfigurationException
* @throws IOException
* @throws ImportException * @throws ImportException
* @throws IntegrityException
* @throws OperationException * @throws OperationException
* @throws PathNotFoundException
*/ */
private static function importFromPackage(string $package_path): string private static function importFromPackage(string $package_path): string
{ {
@ -339,9 +253,9 @@
} }
// Import the required files // Import the required files
if($package_reader->getMetadata()->getOption(BuildConfigurationOptions::REQUIRE_FILES->value) !== null) if($package_reader->getMetadata()->getOption(BuildConfigurationOptions::REQUIRE_FILES) !== null)
{ {
foreach($package_reader->getMetadata()->getOption(BuildConfigurationOptions::REQUIRE_FILES->value) as $item) foreach($package_reader->getMetadata()->getOption(BuildConfigurationOptions::REQUIRE_FILES) as $item)
{ {
try try
{ {
@ -354,18 +268,9 @@
} }
} }
if($package_reader->getFlag(PackageFlags::STATIC_DEPENDENCIES->value))
{
// Fake import the dependencies
foreach($package_reader->getDependencies() as $dependency_name)
{
$dependency = $package_reader->getDependency($dependency_name);
self::$imported_packages[$dependency->getName()] = $package_reader;
}
}
else
{
// Import dependencies recursively // Import dependencies recursively
if(!$package_reader->getFlag(PackageFlags::STATIC_DEPENDENCIES))
{
foreach($package_reader->getDependencies() as $dependency) foreach($package_reader->getDependencies() as $dependency)
{ {
$dependency = $package_reader->getDependency($dependency); $dependency = $package_reader->getDependency($dependency);
@ -421,6 +326,7 @@
if(is_string(self::$class_map[$class]) && is_file(self::$class_map[$class])) if(is_string(self::$class_map[$class]) && is_file(self::$class_map[$class]))
{ {
require_once self::$class_map[$class]; require_once self::$class_map[$class];
return;
} }
} }
@ -436,289 +342,4 @@
return self::$package_manager; return self::$package_manager;
} }
/**
* Returns an array of included files both from the php runtime and ncc runtime
*
* @return array
*/
public static function runtimeGetIncludedFiles(): array
{
return array_merge(get_included_files(), self::$included_files);
}
/**
* Evaluates and executes PHP code with error handling, this function
* gracefully handles <?php ?> tags and exceptions the same way as the
* require/require_once/include/include_once expressions
*
* @param string $code The PHP code to be executed
*/
public static function extendedEvaluate(string $code): void
{
if(ob_get_level() > 0)
{
ob_clean();
}
$exceptions = [];
$code = preg_replace_callback('/<\?php(.*?)\?>/s', static function ($matches) use (&$exceptions)
{
ob_start();
try
{
eval($matches[1]);
}
catch (Throwable $e)
{
$exceptions[] = $e;
}
return ob_get_clean();
}, $code);
ob_start();
try
{
eval('?>' . $code);
}
catch (Throwable $e)
{
$exceptions[] = $e;
}
if (!empty($exceptions))
{
print(ob_get_clean());
$exception_stack = null;
foreach ($exceptions as $e)
{
if($exception_stack === null)
{
$exception_stack = $e;
}
else
{
$exception_stack = new Exception($exception_stack->getMessage(), $exception_stack->getCode(), $e);
}
}
throw new RuntimeException('An exception occurred while evaluating the code', 0, $exception_stack);
}
print(ob_get_clean());
}
/**
* Returns the content of the aquired file
*
* @param string $path
* @param string|null $package
* @return string
* @throws ConfigurationException
* @throws IOException
* @throws OperationException
* @throws PathNotFoundException
* @throws IntegrityException
*/
private static function acquireFile(string $path, ?string $package=null): string
{
$cwd_checked = false; // sanity check to prevent checking the cwd twice
// Check if the file is absolute
if(is_file($path))
{
Console::outDebug(sprintf('Acquired file "%s" from absolute path', $path));
return IO::fread($path);
}
// Since $package is not null, let's try to acquire the file from the package
if($package !== null && isset(self::$imported_packages[$package]))
{
$base_path = basename($path);
if(self::$imported_packages[$package] instanceof PackageReader)
{
$acquired_file = self::$imported_packages[$package]->find($base_path);
Console::outDebug(sprintf('Acquired file "%s" from package "%s"', $path, $package));
return match (Resolver::componentType($acquired_file))
{
PackageDirectory::RESOURCES->value => self::$imported_packages[$package]->getResource(Resolver::componentName($acquired_file))->getData(),
PackageDirectory::COMPONENTS->value => self::$imported_packages[$package]->getComponent(Resolver::componentName($acquired_file))->getData([ComponentDecodeOptions::AS_FILE->value]),
default => throw new IOException(sprintf('Unable to acquire file "%s" from package "%s" because it is not a resource or component', $path, $package)),
};
}
if(is_dir(self::$imported_packages[$package]))
{
$base_path = basename($path);
foreach(IO::scan(self::$imported_packages[$package]) as $file)
{
if(str_ends_with($file, $base_path))
{
Console::outDebug(sprintf('Acquired file "%s" from package "%s"', $path, $package));
return IO::fread($file);
}
}
}
}
// If not, let's try the include_path
foreach(explode(PATH_SEPARATOR, get_include_path()) as $file_path)
{
if($file_path === '.' && !$cwd_checked)
{
$cwd_checked = true;
$file_path = getcwd();
}
if(is_file($file_path . DIRECTORY_SEPARATOR . $path))
{
Console::outDebug(sprintf('Acquired file "%s" from include_path', $path));
return IO::fread($file_path . DIRECTORY_SEPARATOR . $path);
}
if(is_file($file_path . DIRECTORY_SEPARATOR . basename($path)))
{
Console::outDebug(sprintf('Acquired file "%s" from include_path (using basename)', $path));
return IO::fread($file_path . DIRECTORY_SEPARATOR . basename($path));
}
}
// Check the current working directory
if(!$cwd_checked)
{
if(is_file(getcwd() . DIRECTORY_SEPARATOR . $path))
{
Console::outDebug(sprintf('Acquired file "%s" from current working directory', $path));
return IO::fread(getcwd() . DIRECTORY_SEPARATOR . $path);
}
if(is_file(getcwd() . DIRECTORY_SEPARATOR . basename($path)))
{
Console::outDebug(sprintf('Acquired file "%s" from current working directory (using basename)', $path));
return IO::fread(getcwd() . DIRECTORY_SEPARATOR . basename($path));
}
}
// Check the calling script's directory
$called_script_directory = dirname(debug_backtrace()[0]['file']);
$file_path = $called_script_directory . DIRECTORY_SEPARATOR . $path;
if(is_file($file_path))
{
Console::outDebug(sprintf('Acquired file "%s" from calling script\'s directory', $path));
return IO::fread($file_path);
}
throw new IOException(sprintf('Unable to acquire file "%s" because it does not exist', $path));
}
/**
* Includes a file at runtime
*
* @param string $path
* @param string|null $package
* @return void
*/
public static function runtimeInclude(string $path, ?string $package=null): void
{
try
{
$acquired_file = self::acquireFile($path, $package);
}
catch(Exception $e)
{
$package ?
Console::outWarning(sprintf('Failed to acquire file "%s" from package "%s" at runtime: %s', $path, $package, $e->getMessage())) :
Console::outWarning(sprintf('Failed to acquire file "%s" at runtime: %s', $path, $e->getMessage()));
return;
}
$acquired_name = $path;
if(!is_file($path))
{
$acquired_name = hash('crc32', $acquired_file);
}
if(!in_array($acquired_name, self::$included_files, true))
{
self::$included_files[] = sprintf('virtual(%s)', $acquired_name);
}
self::extendedEvaluate($acquired_file);
}
/**
* Includes a file at runtime if it's not already included
*
* @param string $path
* @param string|null $package
* @return void
*/
public static function runtimeIncludeOnce(string $path, ?string $package=null): void
{
if(in_array($path, self::runtimeGetIncludedFiles(), true))
{
return;
}
self::runtimeInclude($path, $package);
}
/**
* Requires a file at runtime, throws an exception if the file failed to require
*
* @param string $path
* @param string|null $package
* @return void
*/
public static function runtimeRequire(string $path, ?string $package=null): void
{
try
{
$acquired_file = self::acquireFile($path, $package);
}
catch(Exception $e)
{
$package ?
throw new RuntimeException(sprintf('Failed to acquire file "%s" from package "%s" at runtime: %s', $path, $package, $e->getMessage()), $e->getCode(), $e) :
throw new RuntimeException(sprintf('Failed to acquire file "%s" at runtime: %s', $path, $e->getMessage()), $e->getCode(), $e);
}
$acquired_name = $path;
if(!is_file($path))
{
$acquired_name = hash('crc32', $acquired_file);
}
if(!in_array($acquired_name, self::$included_files, true))
{
self::$included_files[] = sprintf('virtual(%s)', $acquired_name);
}
self::extendedEvaluate($acquired_file);
}
/**
* Requires a file at runtime if it's not already required
*
* @param string $path
* @return void
*/
public static function runtimeRequireOnce(string $path): void
{
if(in_array($path, self::runtimeGetIncludedFiles(), true))
{
return;
}
self::runtimeRequire($path);
}
} }

View file

@ -0,0 +1,33 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class CompilerExtensionDefaultVersions
{
// ----------------------------------------------------------------
// [0] = MinimumVersion
// [1] = MaximumVersion
// ----------------------------------------------------------------
public const PHP = ['8.0', '8.2'];
}

View file

@ -24,6 +24,5 @@
final class CompilerExtensionSupportedVersions final class CompilerExtensionSupportedVersions
{ {
// TODO: Cannot convert this to enum, try another way
public const PHP = ['8.0', '8.1', '8.2']; public const PHP = ['8.0', '8.1', '8.2'];
} }

View file

@ -22,7 +22,11 @@
namespace ncc\Enums; namespace ncc\Enums;
enum CompilerExtensions : string final class CompilerExtensions
{ {
case PHP = 'php'; public const PHP = 'php';
public const ALL = [
CompilerExtensions::PHP
];
} }

View file

@ -0,0 +1,33 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class ComponentFileExtensions
{
/**
* The file extensions that the PHP compiler extension will accept as components.
*
* @var array
*/
public const PHP = ['*.php', '*.php3', '*.php4', '*.php5', '*.phtml'];
}

View file

@ -22,39 +22,39 @@
namespace ncc\Enums; namespace ncc\Enums;
enum ConsoleColors : string final class ConsoleColors
{ {
case DEFAULT = "\e[39m"; public const DEFAULT = "\e[39m";
case BLACK = "\e[30m"; public const BLACK = "\e[30m";
case RED = "\e[31m"; public const RED = "\e[31m";
case GREEN = "\e[32m"; public const GREEN = "\e[32m";
case YELLOW = "\e[33m"; public const YELLOW = "\e[33m";
case BLUE = "\e[34m"; public const BLUE = "\e[34m";
case MAGENTA = "\e[35m"; public const MAGENTA = "\e[35m";
case CYAN = "\e[36m"; public const CYAN = "\e[36m";
case LIGHT_GREY = "\e[37m"; public const LIGHT_GREY = "\e[37m";
case DARK_GREY = "\e[90m"; public const DARK_GREY = "\e[90m";
case LIGHT_RED = "\e[91m"; public const LIGHT_RED = "\e[91m";
case LIGHT_GREEN = "\e[92m"; public const LIGHT_GREEN = "\e[92m";
case LIGHT_YELLOW = "\e[93m"; public const LIGHT_YELLOW = "\e[93m";
case LIGHT_BLUE = "\e[94m"; public const LIGHT_BLUE = "\e[94m";
case LIGHT_MAGENTA = "\e[95m"; public const LIGHT_MAGENTA = "\e[95m";
case LIGHT_CYAN = "\e[96m"; public const LIGHT_CYAN = "\e[96m";
case WHITE = "\e[97m"; public const WHITE = "\e[97m";
} }

View file

@ -0,0 +1,36 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class ConstantReferences
{
public const ASSEMBLY = 'assembly';
public const BUILD = 'build';
public const DATE_TIME = 'date_time';
public const INSTALL = 'install';
public const RUNTIME = 'runtime';
}

View file

@ -26,80 +26,95 @@
* @author Zi Xing Narrakas * @author Zi Xing Narrakas
* @copyright Copyright (C) 2022-2023. Nosial - All Rights Reserved. * @copyright Copyright (C) 2022-2023. Nosial - All Rights Reserved.
*/ */
enum ExceptionCodes : int final class ExceptionCodes
{ {
/** /**
* @see RuntimeException * @see RuntimeException
*/ */
case RUNTIME = -1706; public const RUNTIME = -1706;
/** /**
* @see BuildException * @see BuildException
*/ */
case BUILD_EXCEPTION = -1727; public const BUILD_EXCEPTION = -1727;
/** /**
* @see IOException * @see IOException
*/ */
case IO_EXCEPTION = -1735; public const IO_EXCEPTION = -1735;
/** /**
* @see ComposerException * @see ComposerException
*/ */
case COMPOSER_EXCEPTION = -1749; public const COMPOSER_EXCEPTION = -1749;
/** /**
* @see AuthenticationException * @see AuthenticationException
*/ */
case AUTHENTICATION_EXCEPTION = -1760; public const AUTHENTICATION_EXCEPTION = -1760;
/** /**
* @see NotSupportedException * @see NotSupportedException
*/ */
case NOT_SUPPORTED_EXCEPTION = -1761; public const NOT_SUPPORTED_EXCEPTION = -1761;
/** /**
* @see ArchiveException * @see ArchiveException
*/ */
case ARCHIVE_EXCEPTION = -1764; public const ARCHIVE_EXCEPTION = -1764;
/** /**
* @see PathNotFoundException * @see PathNotFoundException
*/ */
case PATH_NOT_FOUND = -1769; public const PATH_NOT_FOUND = -1769;
/** /**
* @see GitException * @see GitException
*/ */
case GIT_EXCEPTION = -1770; public const GIT_EXCEPTION = -1770;
/** /**
* @see ConfigurationException * @see ConfigurationException
*/ */
case CONFIGURATION_EXCEPTION = -1772; public const CONFIGURATION_EXCEPTION = -1772;
/** /**
* @see PackageException * @see PackageException
*/ */
case PACKAGE_EXCEPTION = -1773; public const PACKAGE_EXCEPTION = -1773;
/** /**
* @see NetworkException * @see NetworkException
*/ */
case NETWORK_EXCEPTION = -1774; public const NETWORK_EXCEPTION = -1774;
/** /**
* @see IntegrityException * @see IntegrityException
*/ */
case INTEGRITY_EXCEPTION = -1775; public const INTEGRITY_EXCEPTION = -1775;
/** /**
* @see OperationException * @see OperationException
*/ */
case OPERATION_EXCEPTION = -1776; public const OPERATION_EXCEPTION = -1776;
/** /**
* @see ImportException * All the exception codes from NCC
*/ */
case IMPORT_EXCEPTION = -1777; public const All = [
self::RUNTIME,
self::BUILD_EXCEPTION,
self::IO_EXCEPTION,
self::COMPOSER_EXCEPTION,
self::AUTHENTICATION_EXCEPTION,
self::NOT_SUPPORTED_EXCEPTION,
self::ARCHIVE_EXCEPTION,
self::PATH_NOT_FOUND,
self::GIT_EXCEPTION,
self::CONFIGURATION_EXCEPTION,
self::PACKAGE_EXCEPTION,
self::NETWORK_EXCEPTION,
self::INTEGRITY_EXCEPTION,
self::OPERATION_EXCEPTION
];
} }

View file

@ -22,17 +22,17 @@
namespace ncc\Enums; namespace ncc\Enums;
enum FileDescriptor : string final class FileDescriptor
{ {
case ASSEMBLY = 'ASSEMBLY'; public const ASSEMBLY = 'ASSEMBLY';
case METADATA = 'METADATA'; public const METADATA = 'METADATA';
case INSTALLER = 'INSTALLER'; public const INSTALLER = 'INSTALLER';
case CLASS_MAP = 'CLASS_MAP'; public const CLASS_MAP = 'CLASS_MAP';
case UPDATE = 'UPDATE'; public const UPDATE = 'UPDATE';
case SHADOW_PACKAGE = 'SHADOW_PKG'; public const SHADOW_PACKAGE = 'SHADOW_PKG';
} }

View file

@ -22,15 +22,23 @@
namespace ncc\Enums\Flags; namespace ncc\Enums\Flags;
enum ComponentFlags : string final class ComponentFlags
{ {
/** /**
* Indicates that the component is the AST of a PHP file encoded with msgpack. * Indicates that the component is the AST of a PHP file encoded with msgpack.
*/ */
case PHP_AST = 'php_ast'; public const PHP_AST = 'php_ast';
/** /**
* Indicates that the component is a PHP file encoded with base64. * Indicates that the component is a PHP file encoded with base64.
*/ */
case PHP_B64 = 'php_b64'; public const PHP_B64 = 'php_b64';
/**
* All the possible flags of a component
*/
public const ALL = [
self::PHP_AST,
self::PHP_B64
];
} }

View file

@ -22,16 +22,16 @@
namespace ncc\Enums\Flags; namespace ncc\Enums\Flags;
enum NccBuildFlags : string final class NccBuildFlags
{ {
/** /**
* Indicates if the build is currently unstable and some features may not work correctly * Indicates if the build is currently unstable and some features may not work correctly
* and can cause errors * and can cause errors
*/ */
case UNSTABLE = 'unstable'; public const UNSTABLE = 'unstable';
/** /**
* Indicates if the build is currently in beta testing phase * Indicates if the build is currently in beta testing phase
*/ */
case BETA = 'beta'; public const BETA = 'beta';
} }

View file

@ -22,15 +22,15 @@
namespace ncc\Enums\Flags; namespace ncc\Enums\Flags;
enum PackageFlags : string final class PackageFlags
{ {
case COMPRESSION = 'gzip'; public const COMPRESSION = 'gzip';
case LOW_COMPRESSION = 'low_gz`'; public const LOW_COMPRESSION = 'low_gz`';
case MEDIUM_COMPRESSION = 'medium_gz'; public const MEDIUM_COMPRESSION = 'medium_gz';
case HIGH_COMPRESSION = 'high_gz'; public const HIGH_COMPRESSION = 'high_gz';
case STATIC_DEPENDENCIES = 'static_dependencies'; public const STATIC_DEPENDENCIES = 'static_dependencies';
} }

View file

@ -0,0 +1,124 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class HttpStatusCodes
{
public const OK = 200;
public const CREATED = 201;
public const ACCEPTED = 202;
public const NO_CONTENT = 204;
public const MOVED_PERMANENTLY = 301;
public const FOUND = 302;
public const SEE_OTHER = 303;
public const NOT_MODIFIED = 304;
public const TEMPORARY_REDIRECT = 307;
public const PERMANENT_REDIRECT = 308;
public const BAD_REQUEST = 400;
public const UNAUTHORIZED = 401;
public const FORBIDDEN = 403;
public const NOT_FOUND = 404;
public const METHOD_NOT_ALLOWED = 405;
public const NOT_ACCEPTABLE = 406;
public const REQUEST_TIMEOUT = 408;
public const CONFLICT = 409;
public const GONE = 410;
public const LENGTH_REQUIRED = 411;
public const PRECONDITION_FAILED = 412;
public const PAYLOAD_TOO_LARGE = 413;
public const URI_TOO_LONG = 414;
public const UNSUPPORTED_MEDIA_TYPE = 415;
public const RANGE_NOT_SATISFIABLE = 416;
public const EXPECTATION_FAILED = 417;
public const IM_A_TEAPOT = 418;
public const MISDIRECTED_REQUEST = 421;
public const UNPROCESSABLE_ENTITY = 422;
public const LOCKED = 423;
public const FAILED_DEPENDENCY = 424;
public const UPGRADE_REQUIRED = 426;
public const PRECONDITION_REQUIRED = 428;
public const TOO_MANY_REQUESTS = 429;
public const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
public const UNAVAILABLE_FOR_LEGAL_REASONS = 451;
public const INTERNAL_SERVER_ERROR = 500;
public const NOT_IMPLEMENTED = 501;
public const BAD_GATEWAY = 502;
public const SERVICE_UNAVAILABLE = 503;
public const GATEWAY_TIMEOUT = 504;
public const HTTP_VERSION_NOT_SUPPORTED = 505;
public const VARIANT_ALSO_NEGOTIATES = 506;
public const INSUFFICIENT_STORAGE = 507;
public const LOOP_DETECTED = 508;
public const NOT_EXTENDED = 510;
public const NETWORK_AUTHENTICATION_REQUIRED = 511;
public const ALL = [
self::OK,
self::CREATED,
self::ACCEPTED,
self::NO_CONTENT,
self::MOVED_PERMANENTLY,
self::FOUND,
self::SEE_OTHER,
self::NOT_MODIFIED,
self::TEMPORARY_REDIRECT,
self::PERMANENT_REDIRECT,
self::BAD_REQUEST,
self::UNAUTHORIZED,
self::FORBIDDEN,
self::NOT_FOUND,
self::METHOD_NOT_ALLOWED,
self::NOT_ACCEPTABLE,
self::REQUEST_TIMEOUT,
self::CONFLICT,
self::GONE,
self::LENGTH_REQUIRED,
self::PRECONDITION_FAILED,
self::PAYLOAD_TOO_LARGE,
self::URI_TOO_LONG,
self::UNSUPPORTED_MEDIA_TYPE,
self::RANGE_NOT_SATISFIABLE,
self::EXPECTATION_FAILED,
self::IM_A_TEAPOT,
self::MISDIRECTED_REQUEST,
self::UNPROCESSABLE_ENTITY,
self::LOCKED,
self::FAILED_DEPENDENCY,
self::UPGRADE_REQUIRED,
self::PRECONDITION_REQUIRED,
self::TOO_MANY_REQUESTS,
self::REQUEST_HEADER_FIELDS_TOO_LARGE,
self::UNAVAILABLE_FOR_LEGAL_REASONS,
self::INTERNAL_SERVER_ERROR,
self::NOT_IMPLEMENTED,
self::BAD_GATEWAY,
self::SERVICE_UNAVAILABLE,
self::GATEWAY_TIMEOUT,
self::HTTP_VERSION_NOT_SUPPORTED,
self::VARIANT_ALSO_NEGOTIATES,
self::INSUFFICIENT_STORAGE,
self::LOOP_DETECTED,
self::NOT_EXTENDED,
self::NETWORK_AUTHENTICATION_REQUIRED
];
}

View file

@ -22,65 +22,29 @@
namespace ncc\Enums; namespace ncc\Enums;
use ncc\Utilities\Validate; final class LogLevel
enum LogLevel : string
{ {
case SILENT = 'silent'; public const SILENT = 'silent';
case VERBOSE = 'verbose'; public const VERBOSE = 'verbose';
case DEBUG = 'debug'; public const DEBUG = 'debug';
case INFO = 'info'; public const INFO = 'info';
case WARNING = 'warn'; public const WARNING = 'warn';
case ERROR = 'error'; public const ERROR = 'error';
case FATAL = 'fatal'; public const FATAL = 'fatal';
/** public const ALL = [
* Checks if the current log level permits logging at the specified level. self::SILENT,
* self::VERBOSE,
* @param LogLevel|null $current_level The log level to be checked. If null, the method returns false. self::DEBUG,
* @return bool Returns true if logging is permitted at the specified level, otherwise false. self::INFO,
*/ self::WARNING,
public function checkLogLevel(?LogLevel $current_level): bool self::ERROR,
{ self::FATAL,
if ($current_level === null) ];
{
return false;
}
return match ($current_level)
{
LogLevel::DEBUG => in_array($this, [LogLevel::DEBUG, LogLevel::VERBOSE, LogLevel::INFO, LogLevel::WARNING, LogLevel::FATAL, LogLevel::ERROR], true),
LogLevel::VERBOSE => in_array($this, [LogLevel::VERBOSE, LogLevel::INFO, LogLevel::WARNING, LogLevel::FATAL, LogLevel::ERROR], true),
LogLevel::INFO => in_array($this, [LogLevel::INFO, LogLevel::WARNING, LogLevel::FATAL, LogLevel::ERROR], true),
LogLevel::WARNING => in_array($this, [LogLevel::WARNING, LogLevel::FATAL, LogLevel::ERROR], true),
LogLevel::ERROR => in_array($this, [LogLevel::FATAL, LogLevel::ERROR], true),
LogLevel::FATAL => $this === LogLevel::FATAL,
default => false,
};
}
/**
* Converts the given string input to a LogLevel.
* If the input is invalid or not found, it defaults to LogLevel::INFO.
*
* @param string $input The input string to be converted to a LogLevel.
* @return LogLevel Returns the corresponding LogLevel for the input string or LogLevel::INFO if not found.
*/
public static function fromOrDefault(string $input): LogLevel
{
$value = self::tryFrom($input);
if($value === null)
{
return self::INFO;
}
return $value;
}
} }

View file

@ -22,15 +22,15 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum BuildConfigurationOptions : string final class BuildConfigurationOptions
{ {
case COMPRESSION = 'compression'; public const COMPRESSION = 'compression';
case REQUIRE_FILES = 'require_files'; public const REQUIRE_FILES = 'require_files';
case NCC_CONFIGURATION = 'ncc_configuration'; public const NCC_CONFIGURATION = 'ncc_configuration';
case OUTPUT_FILE = 'output_file'; public const OUTPUT_FILE = 'output_file';
case STATIC_DEPENDENCIES = 'static'; public const STATIC_DEPENDENCIES = 'static';
} }

View file

@ -22,11 +22,11 @@
namespace ncc\Enums\Options\BuildConfigurationOptions; namespace ncc\Enums\Options\BuildConfigurationOptions;
enum CompressionOptions : string final class CompressionOptions
{ {
case HIGH = 'high'; public const HIGH = 'high';
case MEDIUM = 'medium'; public const MEDIUM = 'medium';
case LOW = 'low'; public const LOW = 'low';
} }

View file

@ -22,9 +22,9 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum BuildConfigurationValues : string final class BuildConfigurationValues
{ {
case DEFAULT = 'default'; public const DEFAULT = 'default';
case ALL = 'all'; public const ALL = 'all';
} }

View file

@ -22,7 +22,7 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum ComponentDecodeOptions : string final class ComponentDecodeOptions
{ {
case AS_FILE = 'as_file'; public const AS_FILE = 'as_file';
} }

View file

@ -22,25 +22,25 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum InitializeProjectOptions : string final class InitializeProjectOptions
{ {
/** /**
* A custom path to the project's source directory * A custom path to the project's source directory
*/ */
case PROJECT_SRC_PATH = 'PROJECT_SRC_PATH'; public const PROJECT_SRC_PATH = 'PROJECT_SRC_PATH';
/** /**
* A boolean option that indicates whether to overwrite the project file if it already exists * A boolean option that indicates whether to overwrite the project file if it already exists
*/ */
case OVERWRITE_PROJECT_FILE = 'OVERWRITE_PROJECT_FILE'; public const OVERWRITE_PROJECT_FILE = 'OVERWRITE_PROJECT_FILE';
/** /**
* Composer Only, used to define the package's real version * Composer Only, used to define the package's real version
*/ */
case COMPOSER_PACKAGE_VERSION = 'COMPOSER_PACKAGE_VERSION'; public const COMPOSER_PACKAGE_VERSION = 'COMPOSER_PACKAGE_VERSION';
/** /**
* Composer Only, used to define the package's update source * Composer Only, used to define the package's update source
*/ */
case COMPOSER_REMOTE_SOURCE = 'COMPOSER_REMOTE_SOURCE'; public const COMPOSER_REMOTE_SOURCE = 'COMPOSER_REMOTE_SOURCE';
} }

View file

@ -22,7 +22,7 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum InstallPackageOptions : string final class InstallPackageOptions
{ {
/** /**
* Skips the installation of dependencies of the package * Skips the installation of dependencies of the package
@ -30,23 +30,11 @@
* @warning This will cause the package to fail to import of * @warning This will cause the package to fail to import of
* the dependencies are not met * the dependencies are not met
*/ */
case SKIP_DEPENDENCIES = 'skip-dependencies'; public const SKIP_DEPENDENCIES = 'skip_dependencies';
/** /**
* Reinstall all packages if they are already installed, * Reinstall all packages if they are already installed,
* Including dependencies if they are being processed. * Including dependencies if they are being processed.
*/ */
case REINSTALL = 'reinstall'; public const REINSTALL = 'reinstall';
/**
* Installs a static version of the package if it's available
* otherwise it will install non-static version
*/
case PREFER_STATIC = 'prefer-static';
/**
* Forces ncc to build packages from source rather than trying to obtain
* a pre-built version of the package
*/
case BUILD_SOURCE = 'build-source';
} }

View file

@ -22,7 +22,7 @@
namespace ncc\Enums\Options; namespace ncc\Enums\Options;
enum ProjectOptions : string final class ProjectOptions
{ {
case CREATE_SYMLINK = 'create_symlink'; public const CREATE_SYMLINK = 'create_symlink';
} }

View file

@ -0,0 +1,38 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Options;
final class RuntimeImportOptions
{
/**
* Indicates if the import should require PHP's autoload.php file
* for the package (Only applies to PHP packages)
*/
public const IMPORT_AUTOLOADER = 'import_autoloader';
/**
* Indicates if the import should require all static files
* for the package (Only applies to PHP packages)
*/
public const IMPORT_STATIC_FILES = 'import_static_files';
}

View file

@ -22,21 +22,21 @@
namespace ncc\Enums; namespace ncc\Enums;
enum PackageDirectory : int final class PackageDirectory
{ {
case ASSEMBLY = 0x61737365; public const ASSEMBLY = 0x61737365;
case METADATA = 0x6D657461; public const METADATA = 0x6D657461;
case INSTALLER = 0x696E7374; public const INSTALLER = 0x696E7374;
case DEPENDENCIES = 0x64657065; public const DEPENDENCIES = 0x64657065;
case EXECUTION_UNITS = 0x65786563; public const EXECUTION_UNITS = 0x65786563;
case COMPONENTS = 0x636F6D70; public const COMPONENTS = 0x636F6D70;
case RESOURCES = 0x7265736F; public const RESOURCES = 0x7265736F;
case CLASS_POINTER = 0x636C6173; public const CLASS_POINTER = 0x636C6173;
} }

View file

@ -0,0 +1,28 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class PackageStandardVersions
{
public const VERSION_1 = '1.0';
}

View file

@ -22,11 +22,11 @@
namespace ncc\Enums; namespace ncc\Enums;
enum PackageStructure : int final class PackageStructure
{ {
case FILE_VERSION = 0x73746669; public const FILE_VERSION = 0x73746669;
case FLAGS = 0x73736166; public const FLAGS = 0x73736166;
case DIRECTORY = 0x6f746365; public const DIRECTORY = 0x6f746365;
} }

View file

@ -22,15 +22,23 @@
namespace ncc\Enums; namespace ncc\Enums;
enum PackageStructureVersions : string final class PackageStructureVersions
{ {
/** /**
* ncc 1.0.0 to 1.0.3 * ncc 1.0.0 to 1.0.3
*/ */
case _1_0 = '1.0'; public const _1_0 = '1.0';
/** /**
* ncc 1.0.4 and above * ncc 1.0.4 and above
*/ */
case _2_0 = '2.0'; public const _2_0 = '2.0';
/**
* All supported versions
*/
public const ALL = [
self::_1_0,
self::_2_0
];
} }

View file

@ -22,81 +22,23 @@
namespace ncc\Enums; namespace ncc\Enums;
enum ProjectTemplates : string final class ProjectTemplates
{ {
/** /**
* A template that is used to create a PHP library project * A template that is used to create a PHP library project
*/ */
case PHP_LIBRARY = 'phplib'; public const PHP_LIBRARY = 'phplib';
/** /**
* A template that is used to create a PHP CLI application project * A template that is used to create a PHP CLI application project
*/ */
case PHP_CLI = 'phpcli'; public const PHP_CLI = 'phpcli';
/** /**
* A template for generating a Makefile for the PHP project * An array of all the available project templates
*/ */
case PHP_MAKE = 'phpmake'; public const ALL = [
self::PHP_LIBRARY,
/** self::PHP_CLI
* A template used for creating PHP Unit testing bootstrap ];
*/
case PHP_UNIT = 'phpunit';
/**
* A template that is used to create a PHP executable project
*/
case PHP_COMPRESSED = 'phpgz';
/**
* A template that is used to create a PHP executable project
*/
case PHP_EXECUTABLE = 'phpexe';
/**
* Template that combines PHP_LIBRARY, PHP_MAKE and PHP_UNIT in one
*/
case PHP_LIBRARY_FULL = 'phplib_full';
/**
* Template that combines PHP_LIBRARY, PHP_MAKE, PHP_UNIT and PHP_CLI in one
*/
case PHP_CLI_FULL = 'phpcli_full';
/**
* Template that applies a GitHub workflow CI that builds the project, tests the project and creates
* automatic builds for releases
*/
case PHP_GITHUB_CI = 'phpci_github';
/**
* Suggests the closest matching `ProjectTemplates` instance based on the given input string.
*
* @param string $input The input string to compare against.
* @return ProjectTemplates|null The closest matching `ProjectTemplates` instance, or null if no close match is found.
*/
public static function suggest(string $input): ?ProjectTemplates
{
$closest = null;
$shortest_distance = -1;
foreach (self::cases() as $case)
{
$distance = levenshtein($input, $case->value);
if ($distance === 0)
{
return $case;
}
if ($shortest_distance === -1 || $distance < $shortest_distance)
{
$closest = $case;
$shortest_distance = $distance;
}
}
return $closest ?: null;
}
} }

View file

@ -26,27 +26,27 @@
* @author Zi Xing Narrakas * @author Zi Xing Narrakas
* @copyright Copyright (C) 2022-2023. Nosial - All Rights Reserved. * @copyright Copyright (C) 2022-2023. Nosial - All Rights Reserved.
*/ */
enum RegexPatterns : string final class RegexPatterns
{ {
case UUID = '{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di'; public const UUID = '{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di';
case PACKAGE_NAME_FORMAT = '/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$/'; public const PACKAGE_NAME_FORMAT = '/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$/';
case COMPOSER_VERSION_FORMAT = '/^([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$/'; public const COMPOSER_VERSION_FORMAT = '/^([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$/';
case PYTHON_VERSION_FORMAT = '/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$/'; public const PYTHON_VERSION_FORMAT = '/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?$/';
case SEMANTIC_VERSIONING_2 = '/^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/m'; public const SEMANTIC_VERSIONING_2 = '/^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/m';
case UNIX_PATH = '/^(((?:\.\/|\.\.\/|\/)?(?:\.?\w+\/)*)(\.?\w+\.?\w+))$/m'; public const UNIX_PATH = '/^(((?:\.\/|\.\.\/|\/)?(?:\.?\w+\/)*)(\.?\w+\.?\w+))$/m';
case CONSTANT_NAME = '/^([^\x00-\x7F]|[\w_.+]){2,64}$/'; public const CONSTANT_NAME = '/^([^\x00-\x7F]|[\w_\ \.\+\-]){2,64}$/';
case EXECUTION_POLICY_NAME = '/^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/m'; public const EXECUTION_POLICY_NAME = '/^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/m';
/** /**
* @author <purplex> * @author <purplex>
*/ */
case REMOTE_PACKAGE = '/^(?<vendor>[^\/\n]+)\/(?<package>[^:=\n@]+)(?:=(?<version>[^:@\n]+))?(?::(?<branch>[^@\n]+))?@(?<source>.*)$/m'; public const REMOTE_PACKAGE = '/^(?<vendor>[^\/\n]+)\/(?<package>[^:=\n@]+)(?:=(?<version>[^:@\n]+))?(?::(?<branch>[^@\n]+))?@(?<source>.*)$/m';
} }

View file

@ -22,15 +22,25 @@
namespace ncc\Enums; namespace ncc\Enums;
enum Runners : string final class Runners
{ {
case PHP = 'php'; public const PHP = 'php';
case BASH = 'bash'; public const BASH = 'bash';
case PYTHON = 'python'; public const PYTHON = 'python';
case PERL = 'perl'; public const PERL = 'perl';
case LUA = 'lua'; public const LUA = 'lua';
public const ALL = [
self::PHP,
self::BASH,
self::PYTHON,
self::PYTHON_3,
self::PYTHON_2,
self::PERL,
self::LUA
];
} }

View file

@ -22,9 +22,9 @@
namespace ncc\Enums; namespace ncc\Enums;
enum Scopes : string final class Scopes
{ {
case USER = 'USER'; public const USER = 'USER';
case SYSTEM = 'SYSTEM'; public const SYSTEM = 'SYSTEM';
} }

View file

@ -22,50 +22,50 @@
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\SpecialConstants;
enum AssemblyConstants : string final class AssemblyConstants
{ {
/** /**
* Assembly's Name Property * Assembly's Name Property
*/ */
case ASSEMBLY_NAME = '%ASSEMBLY.NAME%'; public const ASSEMBLY_NAME = '%ASSEMBLY.NAME%';
/** /**
* Assembly's Package Property * Assembly's Package Property
*/ */
case ASSEMBLY_PACKAGE = '%ASSEMBLY.PACKAGE%'; public const ASSEMBLY_PACKAGE = '%ASSEMBLY.PACKAGE%';
/** /**
* Assembly's Description Property * Assembly's Description Property
*/ */
case ASSEMBLY_DESCRIPTION = '%ASSEMBLY.DESCRIPTION%'; public const ASSEMBLY_DESCRIPTION = '%ASSEMBLY.DESCRIPTION%';
/** /**
* Assembly's Company Property * Assembly's Company Property
*/ */
case ASSEMBLY_COMPANY = '%ASSEMBLY.COMPANY%'; public const ASSEMBLY_COMPANY = '%ASSEMBLY.COMPANY%';
/** /**
* Assembly's Product Property * Assembly's Product Property
*/ */
case ASSEMBLY_PRODUCT = '%ASSEMBLY.PRODUCT%'; public const ASSEMBLY_PRODUCT = '%ASSEMBLY.PRODUCT%';
/** /**
* Assembly's Copyright Property * Assembly's Copyright Property
*/ */
case ASSEMBLY_COPYRIGHT = '%ASSEMBLY.COPYRIGHT%'; public const ASSEMBLY_COPYRIGHT = '%ASSEMBLY.COPYRIGHT%';
/** /**
* Assembly's Trademark Property * Assembly's Trademark Property
*/ */
case ASSEMBLY_TRADEMARK = '%ASSEMBLY.TRADEMARK%'; public const ASSEMBLY_TRADEMARK = '%ASSEMBLY.TRADEMARK%';
/** /**
* Assembly's Version Property * Assembly's Version Property
*/ */
case ASSEMBLY_VERSION = '%ASSEMBLY.VERSION%'; public const ASSEMBLY_VERSION = '%ASSEMBLY.VERSION%';
/** /**
* Assembly's UUID property * Assembly's UUID property
*/ */
case ASSEMBLY_UID = '%ASSEMBLY.UID%'; public const ASSEMBLY_UID = '%ASSEMBLY.UID%';
} }

View file

@ -22,25 +22,25 @@
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\SpecialConstants;
enum BuildConstants : string final class BuildConstants
{ {
/** /**
* The Unix Timestamp for when the package was compiled * The Unix Timestamp for when the package was compiled
*/ */
case COMPILE_TIMESTAMP = '%COMPILE_TIMESTAMP%'; public const COMPILE_TIMESTAMP = '%COMPILE_TIMESTAMP%';
/** /**
* The version of NCC that was used to compile the package * The version of NCC that was used to compile the package
*/ */
case NCC_BUILD_VERSION = '%NCC_BUILD_VERSION%'; public const NCC_BUILD_VERSION = '%NCC_BUILD_VERSION%';
/** /**
* NCC Build Flags exploded into spaces * NCC Build Flags exploded into spaces
*/ */
case NCC_BUILD_FLAGS = '%NCC_BUILD_FLAGS%'; public const NCC_BUILD_FLAGS = '%NCC_BUILD_FLAGS%';
/** /**
* NCC Build Branch * NCC Build Branch
*/ */
case NCC_BUILD_BRANCH = '%NCC_BUILD_BRANCH%'; public const NCC_BUILD_BRANCH = '%NCC_BUILD_BRANCH%';
} }

View file

@ -22,49 +22,49 @@
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\SpecialConstants;
enum DateTimeConstants : string final class DateTimeConstants
{ {
// Day Format // Day Format
/** /**
* Day of the month, 2 digits with leading zeros * Day of the month, 2 digits with leading zeros
*/ */
case d = '%d%'; // 01 through 31 public const d = '%d%'; // 01 through 31
/** /**
* A textual representation of a day, three letters * A textual representation of a day, three letters
*/ */
case D = '%D%'; // Mon through Sun public const D = '%D%'; // Mon through Sun
/** /**
* Day of the month without leading zeros * Day of the month without leading zeros
*/ */
case j = '%j%'; // 1 through 31 public const j = '%j%'; // 1 through 31
/** /**
* A full textual representation of the day of the week * A full textual representation of the day of the week
*/ */
case l = '%l%'; // Sunday through Saturday public const l = '%l%'; // Sunday through Saturday
/** /**
* ISO 8601 numeric representation of the day of the week * ISO 8601 numeric representation of the day of the week
*/ */
case N = '%N%'; // 1 (Monday) to 7 (Sunday) public const N = '%N%'; // 1 (Monday) to 7 (Sunday)
/** /**
* English ordinal suffix for the day of the month, 2 characters * English ordinal suffix for the day of the month, 2 characters
*/ */
case S = '%S%'; // st, nd, rd, th public const S = '%S%'; // st, nd, rd, th
/** /**
* Numeric representation of the day of the week * Numeric representation of the day of the week
*/ */
case w = '%w%'; // 0 (sunday) through 6 (Saturday) public const w = '%w%'; // 0 (sunday) through 6 (Saturday)
/** /**
* The day of the year (starting from 0) * The day of the year (starting from 0)
*/ */
case z = '%z%'; // 0 through 365 public const z = '%z%'; // 0 through 365
@ -73,7 +73,7 @@
/** /**
* ISO 8601 week number of year, weeks starting on Monday * ISO 8601 week number of year, weeks starting on Monday
*/ */
case W = '%W%'; // 42 (42nd week in year) public const W = '%W%'; // 42 (42nd week in year)
@ -82,27 +82,27 @@
/** /**
* A full textual representation of a month, such as January or March * A full textual representation of a month, such as January or March
*/ */
case F = '%F%'; // January through December public const F = '%F%'; // January through December
/** /**
* Numeric representation of a month, with leading zeros * Numeric representation of a month, with leading zeros
*/ */
case m = '%m%'; // 01 through 12 public const m = '%m%'; // 01 through 12
/** /**
* A short textual representation of a month, three letters * A short textual representation of a month, three letters
*/ */
case M = '%M%'; // Jan through Dec public const M = '%M%'; // Jan through Dec
/** /**
* Numeric representation of a month, without leading zeros * Numeric representation of a month, without leading zeros
*/ */
case n = '%n%'; // 1 through 12 public const n = '%n%'; // 1 through 12
/** /**
* Number of days in the given month * Number of days in the given month
*/ */
case t = '%t%'; // 28 through 31 public const t = '%t%'; // 28 through 31
@ -110,73 +110,73 @@
/** /**
* Whether it's a leap year * Whether it's a leap year
*/ */
case L = '%L%'; // 1 (leap year), 0 otherwise public const L = '%L%'; // 1 (leap year), 0 otherwise
/** /**
* ISO 8601 week-numbering year. This has the same value as Y, * ISO 8601 week-numbering year. This has the same value as Y,
* except that if the ISO week number (W) belongs to the previous * except that if the ISO week number (W) belongs to the previous
* or next year, that year is used instead. * or next year, that year is used instead.
*/ */
case o = '%o%'; // Same as Y, except that it use week number to decide which year it falls onto public const o = '%o%'; // Same as Y, except that it use week number to decide which year it falls onto
/** /**
* A full numeric representation of a year, at least 4 digits, with - for years BCE. * A full numeric representation of a year, at least 4 digits, with - for years BCE.
*/ */
case Y = '%Y%'; // 1991, 2012, 2014, ... public const Y = '%Y%'; // 1991, 2012, 2014, ...
/** /**
* A two digit representation of a year * A two digit representation of a year
*/ */
case y = '%y%'; // 91, 12, 14, ... public const y = '%y%'; // 91, 12, 14, ...
// Time Format // Time Format
/** /**
* Lowercase Ante meridiem and Post meridiem * Lowercase Ante meridiem and Post meridiem
*/ */
case a = '%a%'; // am or pm public const a = '%a%'; // am or pm
/** /**
* Uppercase Ante meridiem and Post meridiem * Uppercase Ante meridiem and Post meridiem
*/ */
case A = '%A%'; // AM or PM public const A = '%A%'; // AM or PM
/** /**
* Swatch Internet time * Swatch Internet time
*/ */
case B = '%B%'; // 000 through 999 public const B = '%B%'; // 000 through 999
/** /**
* 12-hour format of an hour without leading zeros * 12-hour format of an hour without leading zeros
*/ */
case g = '%g%'; // 1 through 12 public const g = '%g%'; // 1 through 12
/** /**
* 24-hour format of an hour without leading zeros * 24-hour format of an hour without leading zeros
*/ */
case G = '%G%'; // 0 through 23 public const G = '%G%'; // 0 through 23
/** /**
* 12-hour format of an hour with leading zeros * 12-hour format of an hour with leading zeros
*/ */
case h = '%h%'; // 01 through 12 public const h = '%h%'; // 01 through 12
/** /**
* 24-hour format of an hour with leading zeros * 24-hour format of an hour with leading zeros
*/ */
case H = '%H%'; // 01 through 23 public const H = '%H%'; // 01 through 23
/** /**
* Minutes with leading zeros * Minutes with leading zeros
*/ */
case i = '%i%'; // 01 through 59 public const i = '%i%'; // 01 through 59
/** /**
* Seconds with leading zeros * Seconds with leading zeros
*/ */
case s = '%s%'; // 00 through 59 public const s = '%s%'; // 00 through 59
// DateTime format // DateTime format
case c = '%c%'; // 2004-02-12T15:19:21 public const c = '%c%'; // 2004-02-12T15:19:21
case r = '%r%'; // Thu, 21 Dec 2000 16:01:07 public const r = '%r%'; // Thu, 21 Dec 2000 16:01:07
case u = '%u%'; // Unix Timestamp (seconds since Jan 1 1970 00:00:00) public const u = '%u%'; // Unix Timestamp (seconds since Jan 1 1970 00:00:00)
} }

View file

@ -22,13 +22,13 @@
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\SpecialConstants;
enum InstallConstants : string final class InstallConstants
{ {
case INSTALL_PATH = '%INSTALL_PATH%'; public const INSTALL_PATH = '%INSTALL_PATH%';
case INSTALL_PATH_BIN = '%INSTALL_PATH.BIN%'; public const INSTALL_PATH_BIN = '%INSTALL_PATH.BIN%';
case INSTALL_PATH_SRC = '%INSTALL_PATH.SRC%'; public const INSTALL_PATH_SRC = '%INSTALL_PATH.SRC%';
case INSTALL_PATH_DATA = '%INSTALL_PATH.DATA%'; public const INSTALL_PATH_DATA = '%INSTALL_PATH.DATA%';
} }

View file

@ -22,11 +22,11 @@
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\SpecialConstants;
enum RuntimeConstants : string final class RuntimeConstants
{ {
case CWD = '%CWD%'; public const CWD = '%CWD%';
case PID = '%PID%'; public const PID = '%PID%';
case UID = '%UID%'; public const UID = '%UID%';
case GID = '%GID%'; public const GID = '%GID%';
case USER = '%USER%'; public const USER = '%USER%';
} }

View file

@ -22,15 +22,15 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum AuthenticationType : int final class AuthenticationType
{ {
/** /**
* A combination of a username and password is used for authentication * A combination of a username and password is used for authentication
*/ */
case USERNAME_PASSWORD = 1; public const USERNAME_PASSWORD = 1;
/** /**
* A single private access token is used for authentication * A single private access token is used for authentication
*/ */
case ACCESS_TOKEN = 2; public const ACCESS_TOKEN = 2;
} }

View file

@ -22,8 +22,8 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum BuildOutputType : string final class BuildOutputType
{ {
case NCC_PACKAGE = 'ncc'; public const NCC_PACKAGE = 'ncc';
case EXECUTABLE = 'executable'; public const EXECUTABLE = 'executable';
} }

View file

@ -1,6 +1,6 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2024, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
@ -20,18 +20,18 @@
* *
*/ */
namespace ncc\Enums\SpecialConstants; namespace ncc\Enums\Types;
enum GeneralConstants : string final class BuiltinRemoteSourceType
{ {
/** /**
* The project's default build configuration * The remote source indicates the package is to be
* fetched using the composer utility.
*/ */
case DEFAULT_BUILD_CONFIGURATION = '%DEFAULT_BUILD_CONFIGURATION%'; public const COMPOSER = 'composer';
/**
* Configurable build output path public const ALL = [
*/ self::COMPOSER
case BUILD_OUTPUT_PATH = '%BUILD_OUTPUT_PATH%'; ];
} }

View file

@ -22,25 +22,35 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum ComponentDataType : string final class ComponentDataType
{ {
/** /**
* Indicates whether the component is represented as an AST representation * Indicates whether the component is represented as an AST representation
*/ */
case AST = 'ast'; public const AST = 'ast';
/** /**
* Indicates whether the component is represented as plaintext * Indicates whether the component is represented as plaintext
*/ */
case PLAIN = 'plain'; public const PLAIN = 'plain';
/** /**
* Indicates whether the component is represented as binary or executable * Indicates whether the component is represented as binary or executable
*/ */
case BINARY = 'binary'; public const BINARY = 'binary';
/** /**
* Indicates whether the component is represented as as a base64 encoded string (Raw bytes' representation) * Indicates whether the component is represented as as a base64 encoded string (Raw bytes' representation)
*/ */
case BASE64_ENCODED = 'b64enc'; public const BASE64_ENCODED = 'b64enc';
/**
* All the possible data types of a component
*/
public const ALL = [
self::AST,
self::PLAIN,
self::BINARY,
self::BASE64_ENCODED
];
} }

View file

@ -22,12 +22,12 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum ComposerPackageTypes : string final class ComposerPackageTypes
{ {
/** /**
* This is the default. It will copy the files to `vendor` * This is the default. It will copy the files to `vendor`
*/ */
case LIBRARY = 'library'; public const LIBRARY = 'library';
/** /**
* This denotes a project rather than a library. For example * This denotes a project rather than a library. For example
@ -37,7 +37,7 @@
* to provide listings of projects to initialize when creating * to provide listings of projects to initialize when creating
* a new workspace. * a new workspace.
*/ */
case PROJECT = 'project'; public const PROJECT = 'project';
/** /**
* An empty package that contains requirements and will trigger * An empty package that contains requirements and will trigger
@ -45,11 +45,11 @@
* anything to the filesystem. As such, it does not require a * anything to the filesystem. As such, it does not require a
* a dist or source key to be installable * a dist or source key to be installable
*/ */
case METAPACKAGE = 'metapackage'; public const METAPACKAGE = 'metapackage';
/** /**
* A package of type `composer-plugin` may provide an installer * A package of type `composer-plugin` may provide an installer
* for other packages that have a custom type. * for other packages that have a custom type.
*/ */
case COMPOSER_PLUGIN = 'composer-plugin'; public const COMPOSER_PLUGIN = 'composer-plugin';
} }

View file

@ -22,15 +22,15 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum ComposerStabilityTypes : string final class ComposerStabilityTypes
{ {
case DEV = 'dev'; public const DEV = 'dev';
case ALPHA = 'alpha'; public const ALPHA = 'alpha';
case BETA = 'beta'; public const BETA = 'beta';
case RC = 'rc'; public const RC = 'rc';
case STABLE ='stable'; public const STABLE ='stable';
} }

View file

@ -0,0 +1,49 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Types;
final class DependencySourceType
{
/**
* The dependency pointer does not point to a package
*/
public const NONE = 'none';
/**
* Indicates if the dependency is statically linked and the
* reference points to the compiled package of the dependency
*/
public const STATIC = 'static';
/**
* Indicates if the pointer reference points to a remote source
* to fetch the dependency from
*/
public const REMOTE = 'remote';
/**
* Indicates if the pointer reference points to a relative file with the
* filename format "{package_name}=={version}.ncc" to fetch the dependency from
*/
public const LOCAL = 'local';
}

View file

@ -0,0 +1,28 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Types;
final class EncoderType
{
public const ZI_PROTO = '3';
}

View file

@ -22,10 +22,10 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum HttpRequestType : string final class HttpRequestType
{ {
case GET = 'GET'; public const GET = 'GET';
case POST = 'POST'; public const POST = 'POST';
case PUT = 'PUT'; public const PUT = 'PUT';
case DELETE = 'DELETE'; public const DELETE = 'DELETE';
} }

View file

@ -22,9 +22,14 @@
namespace ncc\Enums\Types; namespace ncc\Enums\Types;
enum ProjectType : string final class ProjectType
{ {
case COMPOSER = 'composer'; public const COMPOSER = 'composer';
case NCC = 'ncc'; public const NCC = 'ncc';
public const ALL = [
self::COMPOSER,
self::NCC,
];
} }

View file

@ -0,0 +1,56 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Types;
final class RemoteSourceType
{
/**
* A builtin source type is not defined by the user but handled by
* an extension built into NCC
*/
public const BUILTIN = 'builtin';
/**
* A defined source type is defined by the user in the remote sources file
* and handled by an extension designed by passing on the information of
* the source to the extension
*/
public const DEFINED = 'defined';
/**
* Unsupported or invalid source type
*/
public const UNKNOWN = 'unknown';
/**
* No remote source type
*/
public const NONE = 'none';
public const All = [
self::BUILTIN,
self::DEFINED,
self::UNKNOWN,
self::NONE
];
}

Some files were not shown because too many files have changed in this diff Show more