commit c64c037b4265d8e5bd57667652aa2c4399b9721b

Author: Netkas
Date:   Fri Nov 25 01:04:27 2022 -0500

    Added PackageNotFoundException.php

:100644 100644 8387d15 9ffda6d M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 88bd370 A	src/ncc/Exceptions/PackageNotFoundException.php
 2 files changed, 36 insertions(+), 1 deletion(-)

commit 8da4f532a146d626db1ee388eeb763ae14523589
Author: Netkas
Date:   Fri Nov 25 01:03:50 2022 -0500

    Added uninstallation method to the CLI

:100644 100644 73d7ad6 319eac9 M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 109 insertions(+), 1 deletion(-)

commit 99298b12a7a3de539a9047016d4170db11fe0e61
Author: Netkas
Date:   Fri Nov 25 01:03:27 2022 -0500

    Updated \ncc\Managers > PackageManager > uninstallPackageVersion() to save the PackageLock once modifications are done

:100644 100644 174f704 3719e2b M	src/ncc/Managers/PackageManager.php
 1 file changed, 3 insertions(+)

commit 44d8a489ccb15abb7ec7645c3f438d828b4a1570
Author: Netkas
Date:   Fri Nov 25 00:47:27 2022 -0500

    Minor correction in \ncc\Utilities > Console > outException()

:100644 100644 8646fbb 30bd0ff M	src/ncc/Utilities/Console.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 5132089e76f8a41976acf59655a80593ec11a39f
Author: Netkas
Date:   Fri Nov 25 00:36:11 2022 -0500

    Added void return type to \ncc\Managers > PackageManager > uninstallPackage()

:100644 100644 d586c92 174f704 M	src/ncc/Managers/PackageManager.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 2390c6395cc60a5221a0c3064283200ed47273da
Author: Netkas
Date:   Fri Nov 25 00:35:42 2022 -0500

    Added method uninstallPackage() to \ncc\Managers > PackageManager

:100644 100644 d84281b d586c92 M	src/ncc/Managers/PackageManager.php
 1 file changed, 33 insertions(+)

commit 263f50a6680f26c47c04c92941ac9cc82b2b43d3
Author: Netkas
Date:   Fri Nov 25 00:35:12 2022 -0500

    Added method uninstallPackageVersion() to \ncc\Managers > PackageManager

:100644 100644 ddf601a d84281b M	src/ncc/Managers/PackageManager.php
 1 file changed, 59 insertions(+)

commit cf4b7844bb256dbfb367e93907813bf9328517e2
Author: Netkas
Date:   Fri Nov 25 00:12:38 2022 -0500

    Updated \ncc\Utilities > Console > outExceptionDetails() to display Error Code

:100644 100644 cb7c985 8646fbb M	src/ncc/Utilities/Console.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 2bbef1ccbe9001d84be7306b721e7f11834f7cf5
Author: Netkas
Date:   Thu Nov 24 23:24:59 2022 -0500

    Corrected parameters

:100644 100644 d605afb 73d7ad6 M	src/ncc/CLI/PackageManagerMenu.php
:100644 100644 1348644 ddf601a M	src/ncc/Managers/PackageManager.php
:100644 100644 9e2b72d 3e4d055 M	src/ncc/Objects/PackageLock.php
 3 files changed, 5 insertions(+), 5 deletions(-)

commit 7a0ed8206fd0feffd26a73aad246f93ab1ac5250
Author: Netkas
Date:   Thu Nov 24 18:29:27 2022 -0500

    Added pkg_struct_1.0.png

:000000 100644 0000000 31b102a A	assets/pkg_struct_1.0.png
 1 file changed, 0 insertions(+), 0 deletions(-)

commit 58d2b0fd0ebf7b0fe54506fc3eae5cf0c7d44d7a
Author: Netkas
Date:   Thu Nov 24 18:20:39 2022 -0500

    Added ExitHandler Object to execution_policy.md

:100644 100644 66106c9 f5b851b M	docs/project_configuration/execution_policy.md
 1 file changed, 32 insertions(+), 1 deletion(-)

commit 188c840ed3a881829125efa22cb02019273b2c80
Author: Netkas
Date:   Thu Nov 24 18:13:19 2022 -0500

    Corrected permission

:100644 100644 3ab3f48 26732b9 M	src/installer/installer
 1 file changed, 1 insertion(+), 1 deletion(-)

commit c5620f3d5c68777f28987b710c5b550a1e83fbf0
Author: Netkas
Date:   Thu Nov 24 17:58:16 2022 -0500

    Various improvements

:100644 100644 73ff4fa 3ab3f48 M	src/installer/installer
:100644 100644 ba501c9 ade05ec M	src/ncc/Classes/PhpExtension/Installer.php
:100644 100644 da030cc 4c7d6cb M	src/ncc/Managers/PackageLockManager.php
:100644 100644 2a87036 1348644 M	src/ncc/Managers/PackageManager.php
:100644 100644 630a9e0 1838950 M	src/ncc/Utilities/Functions.php
:100644 100644 947d8b1 5e08303 M	src/ncc/Utilities/PathFinder.php
 6 files changed, 18 insertions(+), 66 deletions(-)

commit 9458446e18dc12dfff814e9c918f71c9fb033435
Author: Netkas
Date:   Thu Nov 24 17:28:58 2022 -0500

    Optimized installer

:100644 100644 6f9ae9c 73ff4fa M	src/installer/installer
 1 file changed, 5 insertions(+), 23 deletions(-)

commit b8c88bf4226e88760df221bb95070b8c34f3768d
Author: Netkas
Date:   Thu Nov 24 17:26:37 2022 -0500

    Added method initializeFiles() to \ncc\Utilities > Functions

:100644 100644 9aa235b 630a9e0 M	src/ncc/Utilities/Functions.php
 1 file changed, 79 insertions(+)

commit c456a398932ca6864142e659ccec4de309c56398
Author: Netkas
Date:   Thu Nov 24 17:23:28 2022 -0500

    Added method constructLockFile() in \ncc\Managers > PackageLockManager

:100644 100644 0969e8f da030cc M	src/ncc/Managers/PackageLockManager.php
 1 file changed, 21 insertions(+)

commit e4f07b382802bbd15df33a9c27ab4518c831b8f1
Author: Netkas
Date:   Thu Nov 24 17:17:39 2022 -0500

    Removed two unused methods

:100644 100644 0324a49 947d8b1 M	src/ncc/Utilities/PathFinder.php
 1 file changed, 47 deletions(-)

commit cdd91090173e175e519e215e84abd7a557db0200
Author: Netkas
Date:   Thu Nov 24 17:06:35 2022 -0500

    Unset $e

:100644 100644 f7606f5 d605afb M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 1 insertion(+)

commit dfc4ddc89b5fab99cc225361dcbc9a67e1b53b0b
Author: Netkas
Date:   Thu Nov 24 17:06:15 2022 -0500

    Implemented 'y' arg to \ncc\CLI > PackageManagerMenu > installPackage()

:100644 100644 84c946e f7606f5 M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 8 insertions(+), 2 deletions(-)

commit 145fa07b8a6efac13824a9d00f2ac2ad2db3a245
Author: Netkas
Date:   Thu Nov 24 17:02:12 2022 -0500

    Minor optimization in \ncc\CLI > PackageManagerMenu > getInstalledPackages()

:100644 100644 b5addce 84c946e M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 24 insertions(+), 22 deletions(-)

commit 3e52a30096653e3bf212b4e7e36ce6f94d245ee3
Author: Netkas
Date:   Thu Nov 24 17:01:06 2022 -0500

    Implemented method getInstalledPackages() to \ncc\CLI > PackageManagerMenu

:100644 100644 97babba b5addce M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 67 insertions(+), 1 deletion(-)

commit cb8e4a67378fb073a34da1f3921dacfb66cd0a95
Author: Netkas
Date:   Thu Nov 24 16:48:28 2022 -0500

    Implemented installPackage() in \ncc\CLI > PackageManagerMenu

:100644 100644 87306f5 97babba M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 109 insertions(+), 3 deletions(-)

commit 5bfd226ba347eea55b99848d5ef30e0d29fb9e27
Author: Netkas
Date:   Tue Nov 22 02:02:30 2022 -0500

    Updated method \ncc\Utilities > Console > formatColor() to respect the '--no-color' parameter

:100644 100644 af70c49 cb7c985 M	src/ncc/Utilities/Console.php
 1 file changed, 5 insertions(+)

commit fdd3c921cc734a6d9a385e520de7011a583aea63
Author: Netkas
Date:   Tue Nov 22 01:43:56 2022 -0500

    Added package install check to \ncc\Managers > PackageManagers > install()

:100644 100644 cbf94ce 2a87036 M	src/ncc/Managers/PackageManager.php
 1 file changed, 7 insertions(+)

commit 5180174e8a0a26405eb775ceccad75db68144530
Author: Netkas
Date:   Tue Nov 22 01:41:49 2022 -0500

    Added Exception PackageAlreadyInstalledException.php

:100644 100644 d285c46 8387d15 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 fbf5c49 A	src/ncc/Exceptions/PackageAlreadyInstalledException.php
 2 files changed, 36 insertions(+), 1 deletion(-)

commit c9923612fe689e83fb9301418c4faae6b14f1151
Merge: 5de462a 2a49dbc
Author: Netkas
Date:   Tue Nov 22 01:34:50 2022 -0500

    Merge remote-tracking branch 'origin/pkgmngr' into pkgmngr

commit 5de462a45b378d94e22caf23e21ca1986d9c693b
Author: Netkas
Date:   Tue Nov 22 01:18:28 2022 -0500

    Load if null in \ncc\Managers > PackageLockManager > getPackageLock()
    Updated @throws in PackageManager.php
    Added method getPackages() to \ncc\Managers > PackageManager
    Added method getPackages() to \ncc\Objects > PackageLock
    Added parameter 'install_path' to \ncc\Objects\PackageLock > PackageEntry > addVersion()
    Added property 'Location' to \ncc\Objects\PackageLock > versionEntry
    Added method \ncc\Objects > PackageLock > getPackage()
    Added method getPackage(), getPackageVersion(), getLatestVersion() to \ncc\Managers > PackageManager

:100644 100644 93d924d 0969e8f M	src/ncc/Managers/PackageLockManager.php
:100644 100644 5acd0a6 cbf94ce M	src/ncc/Managers/PackageManager.php
:100644 100644 e2e84d9 9e2b72d M	src/ncc/Objects/PackageLock.php
:100644 100644 3447fca 43cf7a9 M	src/ncc/Objects/PackageLock/PackageEntry.php
:100644 100644 88de3f0 f512c4a M	src/ncc/Objects/PackageLock/VersionEntry.php
 5 files changed, 106 insertions(+), 8 deletions(-)

commit 2a49dbc224ec1328d040762857aa716f8b605041
Author: Netkas
Date:   Tue Nov 22 01:32:51 2022 -0500

    Load if null in \ncc\Managers > PackageLockManager > getPackageLock()

:100644 100644 93d924d 0969e8f M	src/ncc/Managers/PackageLockManager.php
 1 file changed, 3 insertions(+)

commit f576d2cd48fc70b4573cc7636f4f30b1225ac6bc
Author: Netkas
Date:   Tue Nov 22 01:32:13 2022 -0500

    Updated @throws in PackageManager.php

:100644 100644 c81b493 cbf94ce M	src/ncc/Managers/PackageManager.php
 1 file changed, 6 insertions(+)

commit 5c9ab0dd00a2985ed98b61684e438c6d4081a92b
Author: Netkas
Date:   Tue Nov 22 01:27:26 2022 -0500

    Added method getPackages() to \ncc\Managers > PackageManager

:100644 100644 16447d6 c81b493 M	src/ncc/Managers/PackageManager.php
 1 file changed, 11 insertions(+), 1 deletion(-)

commit 6ae9ed251c0db0bc26be23444d06aa76287a705e
Author: Netkas
Date:   Tue Nov 22 01:26:22 2022 -0500

    Added method getPackages() to \ncc\Objects > PackageLock

:100644 100644 97adbeb 9e2b72d M	src/ncc/Objects/PackageLock.php
 1 file changed, 13 insertions(+)

commit f23673fe3fa2a22fd0e2d3cd3da71aced2124940
Author: Netkas
Date:   Tue Nov 22 01:20:53 2022 -0500

    Added parameter 'install_path' to \ncc\Objects\PackageLock > PackageEntry > addVersion()

:100644 100644 3447fca 43cf7a9 M	src/ncc/Objects/PackageLock/PackageEntry.php
 1 file changed, 3 insertions(+), 1 deletion(-)

commit 80304b778984c88f92825a3de52c632f944e2e61
Author: Netkas
Date:   Tue Nov 22 01:19:57 2022 -0500

    Added property 'Location' to \ncc\Objects\PackageLock > versionEntry

:100644 100644 88de3f0 f512c4a M	src/ncc/Objects/PackageLock/VersionEntry.php
 1 file changed, 9 insertions(+)

commit 74078ab6f1ebeee2f1de0c5a683ac178974949ca
Author: Netkas
Date:   Tue Nov 22 01:19:07 2022 -0500

    Added method \ncc\Objects > PackageLock > getPackage()

:100644 100644 e2e84d9 97adbeb M	src/ncc/Objects/PackageLock.php
 1 file changed, 19 insertions(+), 2 deletions(-)

commit 20e1a7caa4bef6a8d77a58d7ffed782e1d984b65
Author: Netkas
Date:   Tue Nov 22 01:18:28 2022 -0500

    Added method getPackage(), getPackageVersion(), getLatestVersion() to \ncc\Managers > PackageManager

:100644 100644 5acd0a6 16447d6 M	src/ncc/Managers/PackageManager.php
 1 file changed, 42 insertions(+), 4 deletions(-)

commit 048d9774930fa435118a075853713c3410c6adc9
Author: Netkas
Date:   Tue Nov 22 00:58:48 2022 -0500

    Removed extension dir in \ncc\Managers > PackageManager > install()

:100644 100644 95a20f5 5acd0a6 M	src/ncc/Managers/PackageManager.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit b1f64293d4e4b413341775beef3d97f8502ae90b
Author: Netkas
Date:   Tue Nov 22 00:57:11 2022 -0500

    Updated \ncc\Managers > PackageManager > install()

:100644 100644 f83bdef 95a20f5 M	src/ncc/Managers/PackageManager.php
 1 file changed, 3 insertions(+), 2 deletions(-)

commit b32c0c431a0e71cdf5118d9d92af342ff7bcbc4e
Author: Netkas
Date:   Tue Nov 22 00:56:18 2022 -0500

    Corrected return type in \ncc\Utilities > RuntimeCache > set()

:100644 100644 622885e 996db9c M	src/ncc/Utilities/RuntimeCache.php
 1 file changed, 2 insertions(+), 2 deletions(-)

commit 0f0ec6fead748e3f91f3966dd372c3d012eb874a
Author: Netkas
Date:   Tue Nov 22 00:55:47 2022 -0500

    Added PackageLock cache

:100644 100644 f8e35d1 93d924d M	src/ncc/Managers/PackageLockManager.php
 1 file changed, 10 insertions(+)

commit 84a51870bd6df93302eeae988ab2d448ca42e38f
Author: Netkas
Date:   Tue Nov 22 00:44:53 2022 -0500

    Added scope check to \ncc\Managers > PackageManager > install()

:100644 100644 18dd0e4 f83bdef M	src/ncc/Managers/PackageManager.php
 1 file changed, 3 insertions(+)

commit 8fd9d023d88992479461f9c3155b5d91e5a0b8d0
Author: Netkas
Date:   Tue Nov 22 00:24:49 2022 -0500

    Added debugging and verbose statements

:100644 100644 28a5210 a2a269f M	src/ncc/CLI/Main.php
:100644 100644 871e9aa 8ac9bae M	src/ncc/Classes/NccExtension/PackageCompiler.php
:100644 100644 5a86ecf d6df577 M	src/ncc/Classes/PhpExtension/Compiler.php
:100644 100644 c5c8e76 ba501c9 M	src/ncc/Classes/PhpExtension/Installer.php
:100644 100644 9524f49 f8e35d1 M	src/ncc/Managers/PackageLockManager.php
:100644 100644 2d37ba0 18dd0e4 M	src/ncc/Managers/PackageManager.php
 6 files changed, 45 insertions(+), 5 deletions(-)

commit aec9944b3698f3e2ad07c76f3599f07ffc209165
Author: Netkas
Date:   Mon Nov 21 22:31:39 2022 -0500

    Added Debugging messages in fwrite() and fread() in \ncc\Utilities > IO

:100644 100644 aefa858 7b9c5be M	src/ncc/Utilities/IO.php
 1 file changed, 2 insertions(+)

commit 8e4afc6ff84044a1f9954d1e98bc22dfa6a3bf43
Author: Netkas
Date:   Mon Nov 21 22:31:07 2022 -0500

    Improved method cbc() in \ncc\Utilities > Functions to cache hash results in RuntimeCache

:100644 100644 bd23434 9aa235b M	src/ncc/Utilities/Functions.php
 1 file changed, 19 insertions(+), 1 deletion(-)

commit ff1ed0a41b3385a4389907b6f7a68d19ad626e2d
Author: Netkas
Date:   Mon Nov 21 22:30:04 2022 -0500

    Added \ncc\Utilities > RuntimeCache

:000000 100644 0000000 622885e A	src/ncc/Utilities/RuntimeCache.php
 1 file changed, 40 insertions(+)

commit 8e4bad74eaa00e5d231310feea576e88adbb790a
Author: Netkas
Date:   Mon Nov 21 22:04:57 2022 -0500

    Improved various functoins in Console.php

:100644 100644 0969216 af70c49 M	src/ncc/Utilities/Console.php
 1 file changed, 70 insertions(+), 4 deletions(-)

commit 4da4278d55af50c4f3d147ebf43f638b0edf1c5a
Author: Netkas
Date:   Mon Nov 21 17:43:28 2022 -0500

    addded validate() method to \ncc\Objects\ProjectConfiguration > ExecutionPolicy

:100644 100644 151909c b627a30 M	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php
 1 file changed, 10 insertions(+), 1 deletion(-)

commit 65f159604e47f3608ecd2384ae270cb51bf0d4ff
Author: Netkas
Date:   Mon Nov 21 17:41:57 2022 -0500

    Changed verbose log prefix

:100644 100644 cceedef 0969216 M	src/ncc/Utilities/Console.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 1e9c8dad0a12b25b2f98569b61879edfc23e9b49
Author: Netkas
Date:   Mon Nov 21 17:41:33 2022 -0500

    Still add default to property in \ncc\CLI > Main  > start()

:100644 100644 088905a 28a5210 M	src/ncc/CLI/Main.php
 1 file changed, 9 insertions(+), 7 deletions(-)

commit 857141d93a7e4a75425eb097962ff4f09b453d0e
Author: Netkas
Date:   Mon Nov 21 17:41:05 2022 -0500

    Corrected switch statement in \ncc\Utilities > Resolver > checkLogLevel()

:100644 100644 bc3636a 4d172a0 M	src/ncc/Utilities/Resolver.php
 1 file changed, 11 insertions(+), 11 deletions(-)

commit 94985da3d603e5e79597dd945a4a251bfbd4c357
Author: Netkas
Date:   Mon Nov 21 17:40:30 2022 -0500

    Added debugging stuff

:100644 100644 0041096 871e9aa M	src/ncc/Classes/NccExtension/PackageCompiler.php
 1 file changed, 11 insertions(+)

commit 03920cec86228d086bf29fd72109ec8e0ba23c44
Author: Netkas
Date:   Mon Nov 21 17:40:04 2022 -0500

    Added some debugging stuff

:100644 100644 ab40863 5a86ecf M	src/ncc/Classes/PhpExtension/Compiler.php
 1 file changed, 5 insertions(+), 2 deletions(-)

commit 37a594751808d3beb24933f279a2a78c812ae872
Author: Netkas
Date:   Mon Nov 21 16:18:29 2022 -0500

    Updated method inlineProgressBar() in \ncc\Utilities > Console to return if log levels are Debug, Verbose or Silent.

:100644 100644 af9ac44 cceedef M	src/ncc/Utilities/Console.php
 1 file changed, 14 insertions(+)

commit a2aba15483962a091c4e515751eb4c08efc4e67d
Author: Netkas
Date:   Mon Nov 21 16:15:13 2022 -0500

    Various bug fixes

:100644 100644 c34f9e5 088905a M	src/ncc/CLI/Main.php
:100644 100644 aa63562 c5c8e76 M	src/ncc/Classes/PhpExtension/Installer.php
:100644 100644 d315024 9524f49 M	src/ncc/Managers/PackageLockManager.php
:100644 100644 84be772 2d37ba0 M	src/ncc/Managers/PackageManager.php
:100644 100644 8011059 4dad3a6 M	src/ncc/Objects/Package.php
:100644 100644 fdf1136 e2e84d9 M	src/ncc/Objects/PackageLock.php
:100644 100644 df4071b 82be14e M	src/ncc/Objects/PackageLock/DependencyEntry.php
:100644 100644 7b27d0d 3447fca M	src/ncc/Objects/PackageLock/PackageEntry.php
:100644 100644 5be0cd7 88de3f0 M	src/ncc/Objects/PackageLock/VersionEntry.php
:100644 100644 2d5e5e8 aefa858 M	src/ncc/Utilities/IO.php
 10 files changed, 100 insertions(+), 79 deletions(-)

commit ab02c328b945d888cc375d823a02370fcf1ca9b0
Author: Netkas
Date:   Mon Nov 21 14:23:34 2022 -0500

    Added test load_package_lock.php

:000000 100644 0000000 258c388 A	tests/package_lock/load_package_lock.php
 1 file changed, 9 insertions(+)

commit 3db549c5661c4195287d36a5fc04c722ecadcbf7
Author: Netkas
Date:   Sun Nov 20 23:13:57 2022 -0500

    Removed length null check for files that are empty (0 bytes)

:100644 100644 c886bb2 2d5e5e8 M	src/ncc/Utilities/IO.php
 1 file changed, 2 deletions(-)

commit 96272441672a5ef32dabf57e1dda58506f182aa9
Author: Netkas
Date:   Sun Nov 20 18:56:09 2022 -0500

    Added Null-check in \ncc\Utilities > Resolver > checkLogLevel()

:100644 100644 4dd84f3 bc3636a M	src/ncc/Utilities/Resolver.php
 1 file changed, 8 insertions(+), 3 deletions(-)

commit 75bdd974a080559ee57b454d11a7afe55bf7ad3f
Author: Netkas
Date:   Sun Nov 20 18:55:21 2022 -0500

     - Added LineBreak for outException()
     - Use 0777 for `perms` when dumping exception details so non-root users can delete the file

:100644 100644 ad4251a af9ac44 M	src/ncc/Utilities/Console.php
 1 file changed, 2 insertions(+), 2 deletions(-)

commit 68dc12898294f9387140185b724612b03847dc81
Author: Netkas
Date:   Sun Nov 20 18:32:35 2022 -0500

    Added execution_policy.md to docs

:000000 100644 0000000 66106c9 A	docs/project_configuration/execution_policy.md
 1 file changed, 120 insertions(+)

commit 24e1243ca44a172976d7c4e79385e13a220325ff
Author: Netkas
Date:   Sat Nov 19 00:18:10 2022 -0500

    Added constant compiling implementation for ExecutionUnits

:100644 100644 9784ca4 0041096 M	src/ncc/Classes/NccExtension/PackageCompiler.php
:100644 100644 0c71cdd ab40863 M	src/ncc/Classes/PhpExtension/Compiler.php
:100644 100644 7afb335 84be772 M	src/ncc/Managers/PackageManager.php
 3 files changed, 113 insertions(+), 22 deletions(-)

commit 9a4db305699ad841bc343910840ea8692524da40
Author: Netkas
Date:   Fri Nov 18 05:31:41 2022 -0500

    Deleted unused Functions.php

:100644 000000 dceff6e 0000000 D	src/ncc/CLI/Functions.php
 1 file changed, 31 deletions(-)

commit 5b2efbc828a977cb060c6c7f96153c24f1135c61
Author: Netkas
Date:   Fri Nov 18 05:27:53 2022 -0500

    Added ConstantReferences to \ncc\Abstracts

:000000 100644 0000000 43cf7ae A	src/ncc/Abstracts/ConstantReferences.php
 1 file changed, 14 insertions(+)

commit 73a52a112b97500c6cf2f0dc304585f562400d2f
Author: Netkas
Date:   Fri Nov 18 00:40:19 2022 -0500

    Renamed ProjectConstants to AssemblyConstants

:100644 100644 b3facbb 1f277c4 R096	src/ncc/Abstracts/SpecialConstants/ProjectConstants.php	src/ncc/Abstracts/SpecialConstants/AssemblyConstants.php
:100644 100644 b561239 5ab4597 M	src/ncc/Classes/NccExtension/ConstantCompiler.php
 2 files changed, 11 insertions(+), 11 deletions(-)

commit 286cd53f7a09c0a21a2d903d20ade5dccc67b200
Author: Netkas
Date:   Fri Nov 18 00:37:57 2022 -0500

    Updated method install() in \ncc\Managers > PackageManager to handle ExecutionUnits and execute units pre- or post-installation stages

:100644 100644 ca6abd7 7afb335 M	src/ncc/Managers/PackageManager.php
 1 file changed, 50 insertions(+), 17 deletions(-)

commit d77e2900c8d9c6a089073a27710c6162ad0c487e
Author: Netkas
Date:   Fri Nov 18 00:36:13 2022 -0500

    Added method getExecutionUnit() to \ncc\Objects > Package

:100644 100644 2ac9535 8011059 M	src/ncc/Objects/Package.php
 1 file changed, 17 insertions(+)

commit 7fa280f6772b18e3f9c7586bbf4c31e8cee84b82
Author: Netkas
Date:   Fri Nov 18 00:35:48 2022 -0500

    Implemented \ncc\Objects\Package > Installer

:100644 100644 cbeb8b0 c368aac M	src/ncc/Objects/Package/Installer.php
 1 file changed, 74 insertions(+), 3 deletions(-)

commit 0c86fcffa1e0bca94b122544f5a426e657488bc5
Author: Netkas
Date:   Fri Nov 18 00:35:26 2022 -0500

    Added method temporaryExecute() to \ncc\Managers > ExecutionPointerManager and some optimizations & corrections to the class.

:100644 100644 d68afa2 bedd2b5 M	src/ncc/Managers/ExecutionPointerManager.php
 1 file changed, 54 insertions(+), 7 deletions(-)

commit 163aa8c1bf4b7d1fc10c12ff4c5fec08cc457308
Author: Netkas
Date:   Mon Nov 14 22:31:05 2022 -0500

    Optimized Resolver.php

:100644 100644 0e62cf9 4dd84f3 M	src/ncc/Utilities/Resolver.php
 1 file changed, 19 insertions(+), 4 deletions(-)

commit 2671e79d1bc60093c30fc3d6be7c29af8956eff1
Author: Netkas
Date:   Mon Nov 14 20:55:01 2022 -0500

    Added Runner.php

:000000 100644 0000000 2133137 A	src/ncc/Classes/NccExtension/Runner.php
 1 file changed, 47 insertions(+)

commit edab8bfb484fb890ba771f0e3f68a6d71e4a23ba
Author: Netkas
Date:   Mon Nov 14 20:54:39 2022 -0500

    Improved RunnerInterface to be more minimal

:100644 100644 d77c5e1 fe8dbb4 M	src/ncc/Classes/PhpExtension/Runner.php
:100644 100644 f52c6ad 4d118c4 M	src/ncc/Interfaces/RunnerInterface.php
 2 files changed, 38 insertions(+), 16 deletions(-)

commit 0ed789acca6a7fe6b22cb3e9d0f653f2a925c1bc
Author: Netkas
Date:   Mon Nov 14 20:53:54 2022 -0500

    Updated Constructor in \ncc\Objects\ExecutionPointers > ExecutionPointer

:100644 100644 19d6b25 9a5747e M	src/ncc/Objects/ExecutionPointers/ExecutionPointer.php
 1 file changed, 2 insertions(+), 2 deletions(-)

commit e8c1b1da41c0d6cb4f9875be7eeab9b24f174eda
Author: Netkas
Date:   Mon Nov 14 20:53:26 2022 -0500

    Updated Constructor and added methods toArray() and fromArray() to \ncc\Objects > ExecutionPointers

:100644 100644 3ac4e56 9181c03 M	src/ncc/Objects/ExecutionPointers.php
 1 file changed, 46 insertions(+), 8 deletions(-)

commit 03829e43ef6567cd193af6125d7c04b685ecd2ed
Author: Netkas
Date:   Mon Nov 14 20:52:49 2022 -0500

    Added small file delete condition in \ncc\Managers > ExecutionPointerManager > addUnit()

:100644 100644 fc31539 d68afa2 M	src/ncc/Managers/ExecutionPointerManager.php
 1 file changed, 4 insertions(+)

commit 807bee0236b77d0f6e75e57df8a46a2376f0caa2
Author: Netkas
Date:   Mon Nov 14 20:47:32 2022 -0500

    Added ExecutionPointerManager.php

:000000 100644 0000000 fc31539 A	src/ncc/Managers/ExecutionPointerManager.php
 1 file changed, 373 insertions(+)

commit 7db5c31b8686624349eb8e1bc30e6dde74bcc66d
Author: Netkas
Date:   Mon Nov 14 14:56:29 2022 -0500

    Added ExecutionUnitNotFoundException.php
    Added NoAvailableUnitsException.php
    Added RunnerExecutionException.php
    Added ExecutionPointer.php
    Added ExecutionPointers.php

:100644 100644 305dbeb d285c46 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 228f512 A	src/ncc/Exceptions/ExecutionUnitNotFoundException.php
:000000 100644 0000000 56d61ac A	src/ncc/Exceptions/NoAvailableUnitsException.php
:000000 100644 0000000 e568dd1 A	src/ncc/Exceptions/RunnerExecutionException.php
:000000 100644 0000000 3ac4e56 A	src/ncc/Objects/ExecutionPointers.php
:000000 100644 0000000 19d6b25 A	src/ncc/Objects/ExecutionPointers/ExecutionPointer.php
 6 files changed, 297 insertions(+), 1 deletion(-)

commit f1b451ca290f81e78a66e50a25001f733f11cfe1
Author: Netkas
Date:   Mon Nov 14 14:28:15 2022 -0500

    Added method getRunnerPath() to \ncc\Utilities > PathFinder

:100644 100644 373c0fa 0324a49 M	src/ncc/Utilities/PathFinder.php
 1 file changed, 13 insertions(+)

commit 4c49846b3585ee0550758a79daef86b16c249ba4
Author: Netkas
Date:   Mon Nov 14 14:27:43 2022 -0500

    Added method exceedsPathLength() to \ncc\Utilities > Validate

:100644 100644 bbfe3a6 368f6ac M	src/ncc/Utilities/Validate.php
 1 file changed, 14 insertions(+)

commit d4cea6b095e09e649fca5e239f8ef47d02b92c52
Author: Netkas
Date:   Sun Nov 13 19:38:28 2022 -0500

    Added PackageLockManager.php

:000000 100644 0000000 d315024 A	src/ncc/Managers/PackageLockManager.php
 1 file changed, 115 insertions(+)

commit e77e0408a8ba1990e3bb49861112b4f0badadcfa
Author: Netkas
Date:   Sun Nov 13 19:38:02 2022 -0500

    Added PackageManager.php

:000000 100644 0000000 ca6abd7 A	src/ncc/Managers/PackageManager.php
 1 file changed, 247 insertions(+)

commit ec8f00c4c7a74c8798fb9d302559b15909733ccb
Author: Netkas
Date:   Sun Nov 13 19:35:10 2022 -0500

    Updated Method \ncc\Objects > PackageLock > addPackage() to add versions even when package entry exists.

:100644 100644 10bc0de fdf1136 M	src/ncc/Objects/PackageLock.php
 1 file changed, 5 insertions(+)

commit 1f43d8b3c9496cdab9b06a0ada184363cfac68e7
Author: Netkas
Date:   Sun Nov 13 19:27:18 2022 -0500

    Added MainExecutionPolicy property set in \ncc\Classes\PhpExtension > Compiler > prepare()

:100644 100644 dbf710c 0c71cdd M	src/ncc/Classes/PhpExtension/Compiler.php
 1 file changed, 1 insertion(+)

commit 95844595ae13c8eaa4d8a56c756da0d1e52fd96e
Author: Netkas
Date:   Sun Nov 13 18:53:12 2022 -0500

    Added 'AllConfigurations' to \ncc\Abstracts\Options > BuildConfigurationValues

:100644 100644 3f90126 9b9d555 M	src/ncc/Abstracts/Options/BuildConfigurationValues.php
 1 file changed, 2 insertions(+)

commit 3fa456ed888670e89eeae6f9a2de8c77a0495e9c
Author: Netkas
Date:   Sun Nov 13 18:52:20 2022 -0500

    Cleaned up build method in NCC

:100644 100644 32d9731 e88d85a M	src/ncc/CLI/BuildMenu.php
:100644 100644 d03964a 9784ca4 M	src/ncc/Classes/NccExtension/PackageCompiler.php
:100644 100644 a9d0e42 286910b M	src/ncc/Managers/ProjectManager.php
 3 files changed, 216 insertions(+), 147 deletions(-)

commit 300d6326082e0b603a61e2a0eff0dfe0350cc768
Author: Netkas
Date:   Sun Nov 13 18:51:25 2022 -0500

    Added logging properties in \ncc\CLI > Main

:100644 100644 74151af c34f9e5 M	src/ncc/CLI/Main.php
 1 file changed, 33 insertions(+)

commit 6edf0fb514ea4ef079fd013f58a2c0f046abbf36
Author: Netkas
Date:   Sun Nov 13 16:52:58 2022 -0500

    Implemented LogLevel
    Added LogLevel.php

:000000 100644 0000000 6817c6e A	src/ncc/Abstracts/LogLevel.php
:100644 100644 f91cf37 ad4251a M	src/ncc/Utilities/Console.php
:100644 100644 036248a 0e62cf9 M	src/ncc/Utilities/Resolver.php
:100644 100644 77362be bbfe3a6 M	src/ncc/Utilities/Validate.php
 4 files changed, 179 insertions(+), 1 deletion(-)

commit 729d84168869591be79b463a60314b8511cfe8c4
Author: Netkas
Date:   Sun Nov 13 16:21:14 2022 -0500

    Added ExceptionHandling in Console.php

:100644 100644 f08f5fa f91cf37 M	src/ncc/Utilities/Console.php
 1 file changed, 6 insertions(+), 10 deletions(-)

commit 3daad842b9278b5e89e04a7e00367bda108c0a04
Author: Netkas
Date:   Sun Nov 13 12:51:15 2022 -0500

    Added ProjectConfigurationNotFoundException.php

:100644 100644 e12d9f9 305dbeb M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 2897f72 A	src/ncc/Exceptions/ProjectConfigurationNotFoundException.php
 2 files changed, 21 insertions(+), 1 deletion(-)

commit dc110111dcc57e6dae272340bc82da5c1b654823
Author: Netkas
Date:   Sat Nov 12 07:15:48 2022 -0500

    Formatting

:100644 100644 6abd7e5 87306f5 M	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 1 insertion(+), 2 deletions(-)

commit 825023118cc951a1e6270d277a184c1474b926da
Author: Netkas
Date:   Sat Nov 12 07:10:57 2022 -0500

    Changed MainExecutionPolicy property type from ExecutionPolicy to string
    Added MainExecutionPolicy to \ncc\Objects\PackageLock > VersionEntry

:100644 100644 5da50a1 2ac9535 M	src/ncc/Objects/Package.php
:100644 100644 f209b68 7b27d0d M	src/ncc/Objects/PackageLock/PackageEntry.php
:100644 100644 0387937 5be0cd7 M	src/ncc/Objects/PackageLock/VersionEntry.php
 3 files changed, 12 insertions(+), 5 deletions(-)

commit f7a1b6ed1691b2edfe6ec145c50ad5f6dcc7534f
Author: Netkas
Date:   Sat Nov 12 06:51:43 2022 -0500

    Added methods removeVersion(), getLatestVersion(), getVersions() to \ncc\Objects\PackageLock > PackageEntry

:100644 100644 13afbc6 f209b68 M	src/ncc/Objects/PackageLock/PackageEntry.php
 1 file changed, 125 insertions(+)

commit 06c8792c568ab0e1e4fb41fb854dcd39d36adca9
Author: Netkas
Date:   Fri Nov 11 08:33:19 2022 -0500

    Opt to use builtin base64_encode() and base64_decode() when available to improve performance.

:100644 100644 f1d7b5e 9c75af3 M	src/ncc/Utilities/Base64.php
 1 file changed, 7 insertions(+)

commit e16c3ebd746f6160fdc29f92b71664b85d9c40da
Author: Netkas
Date:   Fri Nov 11 05:53:01 2022 -0500

    Updated ID handler in \ncc\Objects\Package > PackageUnit

:100644 100644 bbdfa52 75940cc M	src/ncc/Objects/Package/ExecutionUnit.php
 1 file changed, 13 insertions(+), 6 deletions(-)

commit 04bc2eb99ed5c3ac1b047b5eb9b48d4af09c4a6d
Author: Netkas
Date:   Fri Nov 11 04:53:36 2022 -0500

    Updated Runner in \ncc\Classes\PhpExtension

:100644 100644 202e501 d77c5e1 M	src/ncc/Classes/PhpExtension/Runner.php
:100644 100644 8be9927 f52c6ad M	src/ncc/Interfaces/RunnerInterface.php
 2 files changed, 6 insertions(+), 9 deletions(-)

commit d78dd984a700f652d4c325b70eec1beb8f1d5c8b
Author: Netkas
Date:   Fri Nov 11 04:29:13 2022 -0500

    Added checks for the results in \ncc\Objects > ProjectConfiguration > getRequiredExecutionPolicies()

:100644 100644 370181c f361a3e M	src/ncc/Objects/ProjectConfiguration.php
 1 file changed, 58 insertions(+)

commit cd1d9407d6ce8ca46d16af52212870ef9685aa87
Author: Netkas
Date:   Fri Nov 11 04:12:37 2022 -0500

    Added properties preBuild() and postBuild() to \ncc\Objects\ProjectConfiguration > Build

:100644 100644 60101eb 71caa85 M	src/ncc/Objects/ProjectConfiguration/Build.php
 1 file changed, 18 insertions(+)

commit 8cdddf60a42aba2edfce4e7cd881f695cc7eec56
Author: Netkas
Date:   Fri Nov 11 04:12:07 2022 -0500

    Added Installer to \ncc\Objects\ProjectConfiguration

:000000 100644 0000000 30dda88 A	src/ncc/Objects/ProjectConfiguration/Installer.php
 1 file changed, 88 insertions(+)

commit eddb59ed47831fa71f8a10e5df0ee961b63d4ba0
Author: Netkas
Date:   Fri Nov 11 04:11:46 2022 -0500

    Added PackageLock.php (\ncc\Objects > PackageLock)

:000000 100644 0000000 10bc0de A	src/ncc/Objects/PackageLock.php
 1 file changed, 157 insertions(+)

commit eae1ea7b25ca083e40869cf2777d9f51a5cf4a31
Author: Netkas
Date:   Fri Nov 11 04:10:20 2022 -0500

    Implemented Execution Policy reference validation in \ncc\Objects > ProjectConfiguration
    
    added method getRequiredExecutionPolicies() to \ncc\Objects > ProjectConfiguration to return required execution policies for the selected build configuration
    
    Added method processBuildPolicies() to \ncc\Objects > ProjectConfiguration to return required execution policies for the given build configuration

:100644 100644 c987271 370181c M	src/ncc/Objects/ProjectConfiguration.php
 1 file changed, 161 insertions(+), 2 deletions(-)

commit 8d9a6e49f89fb078cb4e8aabd4e39e060deaa7c2
Author: Netkas
Date:   Fri Nov 11 04:03:19 2022 -0500

    Added Public Constructor to \ncc\Objects\ProjectConfiguration\ExecutionPolicy > Execute

:100644 100644 7e31ce8 0cc164a M	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php
 1 file changed, 11 insertions(+)

commit dbcd231358bf0f520921fd71d6a8db80f5b89429
Author: Netkas
Date:   Fri Nov 11 04:01:40 2022 -0500

    Added PreBuild and PostBuild to \ncc\Objects\ProjectConfiguration > BuildConfiguration

:100644 100644 cc80ef6 45a8bf5 M	src/ncc/Objects/ProjectConfiguration/BuildConfiguration.php
 1 file changed, 23 insertions(+), 12 deletions(-)

commit a204788ecfa0cec7bbc8802eefc2b08a1b976143
Author: Netkas
Date:   Fri Nov 11 03:59:51 2022 -0500

    Added exception InvalidExecutionPolicyName.php

:100644 100644 eb82f32 e12d9f9 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 2699960 A	src/ncc/Exceptions/InvalidExecutionPolicyName.php
 2 files changed, 22 insertions(+), 1 deletion(-)

commit 3190426e4faf724006ab738d0cc3e3719f366258
Author: Netkas
Date:   Fri Nov 11 03:56:55 2022 -0500

    Validate execution policy names
    
     - Added method executionPolicyName() to \ncc\Utilities > Validate
     - Added ExecutionPolicy to \ncc\Abstracts > RegexPatterns

:100644 100644 7fef226 335af46 M	src/ncc/Abstracts/RegexPatterns.php
:100644 100644 3cb7600 77362be M	src/ncc/Utilities/Validate.php
 2 files changed, 23 insertions(+)

commit 80dfc2796775fdf7d7ee307d38adea7552d28a36
Author: Netkas
Date:   Fri Nov 11 02:34:37 2022 -0500

    Added UndefinedExecutionPolicyException.php to \ncc\Exception

:100644 100644 b414bd4 eb82f32 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 8797b5e A	src/ncc/Exceptions/UndefinedExecutionPolicyException.php
 2 files changed, 36 insertions(+), 1 deletion(-)

commit 1896c99840dfb758b1a0e1e12adc805667adb62c
Author: Netkas
Date:   Fri Nov 11 01:56:39 2022 -0500

    Added RuntimeConstants.php

:000000 100644 0000000 751d28c A	src/ncc/Abstracts/SpecialConstants/RuntimeConstants.php
 1 file changed, 8 insertions(+)

commit c83aff610ea3ecaa968e66f40e81612e52b7c466
Author: Netkas
Date:   Fri Nov 11 01:54:35 2022 -0500

    Added property 'Tty' to \ncc\Objects\ProjectConfiguration > ExecutionPolicy

:100644 100644 d8c3624 7e31ce8 M	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php
 1 file changed, 9 insertions(+)

commit bbd77ddf702572e8615b9d2c9edff70985f90596
Author: Netkas
Date:   Fri Nov 11 00:24:36 2022 -0500

    Added Default Value to public constructor to \ncc\Objects\PackageLock > DependencyEntry

:100644 100644 d84e6cd df4071b M	src/ncc/Objects/PackageLock/DependencyEntry.php
 1 file changed, 1 insertion(+), 1 deletion(-)

commit dce75b9df4f7ad0bafe0664f4cf5f21f0750f557
Author: Netkas
Date:   Thu Nov 10 22:10:32 2022 -0500

    Deleted Unused MainExecutionPolicy.php

:100644 000000 c005578 0000000 D	src/ncc/Objects/Package/MainExecutionPolicy.php
 1 file changed, 30 deletions(-)

commit d4145283801c9705ac5ca807f088ac4963752758
Author: Netkas
Date:   Thu Nov 10 22:10:13 2022 -0500

    Corrected method fromArray() in \ncc\Objects\Package > Header to construct Compiler object

:100644 100644 e090bc5 16a627e M	src/ncc/Objects/Package/Header.php
 1 file changed, 3 insertions(+)

commit 1803e228cc060ef9aedbd7bca1060eb960ebeff2
Author: Netkas
Date:   Thu Nov 10 21:43:49 2022 -0500

    Added VersionNotFoundException

:100644 100644 e7db756 b414bd4 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 b7b4acc A	src/ncc/Exceptions/VersionNotFoundException.php
 2 files changed, 36 insertions(+), 1 deletion(-)

commit 491c065342fbb02c2998552f77264660bcf3b7c7
Author: Netkas
Date:   Thu Nov 10 21:36:59 2022 -0500

    Added method getVersion() to \ncc\Objects\PackageLock > PackageEntry and moved Compiler property to \ncc\Objects\PackageLock > VersionEntry

:100644 100644 6247cce 13afbc6 M	src/ncc/Objects/PackageLock/PackageEntry.php
:100644 100644 b0e925a 0387937 M	src/ncc/Objects/PackageLock/VersionEntry.php
 2 files changed, 57 insertions(+), 30 deletions(-)

commit 04b13b3a64e7223e765d4cd6808a0165996ea7cb
Author: Netkas
Date:   Thu Nov 10 19:43:04 2022 -0500

    Added Installer.php to \ncc\Classes\PhpExtension to handle the installation process of PHP packages

:000000 100644 0000000 aa63562 A	src/ncc/Classes/PhpExtension/Installer.php
 1 file changed, 362 insertions(+)

commit 19bf40fcf4a8e23a145eb71c6d30766b016d0348
Author: Netkas
Date:   Thu Nov 10 19:39:04 2022 -0500

    Added method installUnit() to \ncc\Interfaces > RunnerInterface and updated \ncc\Classes\PhpExtension > Runner to reflect the change

:100644 100644 459c4e9 202e501 M	src/ncc/Classes/PhpExtension/Runner.php
:100644 100644 7899998 8be9927 M	src/ncc/Interfaces/RunnerInterface.php
 2 files changed, 30 insertions(+)

commit 8b0ddf39a04b6c0b4b191ca45e0f0a8a059d14a6
Author: Netkas
Date:   Thu Nov 10 19:21:10 2022 -0500

    Minor Correction in src/ncc/CLI/BuildMenu.php
    Deleted ConstantCompiler.php
    Replaced file_get_contents() with IO::fread() in Component.php
    Replaced file_get_contents() with IO::fread() in Functions.php
    Code Cleanup in Functions.php (\ncc\Utilities > Functions)
    Improved CLI Exception handling, added parameter to dump exception to json file

:100644 100644 98b69ac 32d9731 M	src/ncc/CLI/BuildMenu.php
:100644 100644 c8fe242 74151af M	src/ncc/CLI/Main.php
:100644 100644 68b7568 33292ad M	src/ncc/Objects/NccVersionInformation/Component.php
:100644 100644 870eeb9 f08f5fa M	src/ncc/Utilities/Console.php
:100644 000000 7f1e298 0000000 D	src/ncc/Utilities/ConstantCompiler.php
:100644 100644 b1ed843 bd23434 M	src/ncc/Utilities/Functions.php
 6 files changed, 118 insertions(+), 103 deletions(-)

commit 754f09c96d70d88645d508f4956e982ca21ef1f0
Author: Netkas
Date:   Tue Nov 8 16:08:22 2022 -0500

    Added method build() to the CompilerInterface and updated \ncc\Classes\PhpExtension > Compiler & \ncc\CLI > BuildMenu to reflect these changes

:100644 100644 f7a4a84 98b69ac M	src/ncc/CLI/BuildMenu.php
:100644 100644 aaef4ca dbf710c M	src/ncc/Classes/PhpExtension/Compiler.php
:100644 100644 ee86c57 c098abf M	src/ncc/Interfaces/CompilerInterface.php
 3 files changed, 36 insertions(+), 5 deletions(-)

commit b1af6841d0f0cec1cf4f23802a37017a6a1f4a9a
Author: Netkas
Date:   Tue Nov 8 16:06:41 2022 -0500

    Moved methods compileRuntimeConstants(), compilePackageConstants() and regularConstants() from \ncc\Classes\NccExtension > ConstantCompiler to \ncc\Classes\NccExtension > PackageCompiler

:100644 100644 9f6f434 b561239 M	src/ncc/Classes/NccExtension/ConstantCompiler.php
:100644 100644 ca88d63 d03964a M	src/ncc/Classes/NccExtension/PackageCompiler.php
 2 files changed, 64 insertions(+), 57 deletions(-)

commit 3dd754ae8eddf3bd2f8cd800551d08f5943878d9
Author: Netkas
Date:   Mon Nov 7 22:41:17 2022 -0500

    Minor change in IO.php
    Added method compileRunner() to \ncc\Utilities > Functions
    Updated \ncc\Objects > Package
    Added Exec and ExitHandlers to array converters in \ncc\Objects\ProjectConfiguration > ExecutionPolicy
    Made \ncc\Objects\ProjectConfiguration > Build > getBuildConfiguration() accept default values
    Updated Checksum handler in \ncc\Objects\Package > Resource
    Added ExecutionUnit to \ncc\Objects\Package
    Changed Checksum handler in \ncc\Objects\Package > Component
    Updated BuildMenu.php
    Added DateTimeConstants.php
    Added PackageLockVersion to \ncc\Abstracts > Versions
    Added Abstract Class Runners to \ncc\Abstracts
    Added NccExtension
    Added Runner.php to PhpExtension
    Updated Compiler.php for PhpExtension
    Added RunnerInterface.php
    Added UnsupportedRunnerException.php

:100644 100644 9e74821 e7db756 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 5a0e052 A	src/ncc/Abstracts/Runners.php
:000000 100644 0000000 479346d A	src/ncc/Abstracts/SpecialConstants/DateTimeConstants.php
:100644 100644 98825ac 8676dba M	src/ncc/Abstracts/Versions.php
:100644 100644 e936406 f7a4a84 M	src/ncc/CLI/BuildMenu.php
:000000 100644 0000000 9f6f434 A	src/ncc/Classes/NccExtension/ConstantCompiler.php
:000000 100644 0000000 ca88d63 A	src/ncc/Classes/NccExtension/PackageCompiler.php
:100644 100644 0ce15f9 aaef4ca M	src/ncc/Classes/PhpExtension/Compiler.php
:000000 100644 0000000 459c4e9 A	src/ncc/Classes/PhpExtension/Runner.php
:000000 100644 0000000 830a7a1 A	src/ncc/Exceptions/UnsupportedRunnerException.php
:100644 100644 409ea5e ee86c57 M	src/ncc/Interfaces/CompilerInterface.php
:000000 100644 0000000 7899998 A	src/ncc/Interfaces/RunnerInterface.php
:100644 100644 0189a0d 5da50a1 M	src/ncc/Objects/Package.php
:100644 100644 75406f7 b48708b M	src/ncc/Objects/Package/Component.php
:000000 100644 0000000 bbdfa52 A	src/ncc/Objects/Package/ExecutionUnit.php
:100644 100644 87c44a0 14d77dd M	src/ncc/Objects/Package/Resource.php
:100644 100644 b27e917 60101eb M	src/ncc/Objects/ProjectConfiguration/Build.php
:100644 100644 8a68586 151909c M	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php
:100644 100644 8e0fcaf b1ed843 M	src/ncc/Utilities/Functions.php
:100644 100644 b05f7ee c886bb2 M	src/ncc/Utilities/IO.php
 20 files changed, 896 insertions(+), 191 deletions(-)

commit f46289a8083a2c3f396c238de2bdcd8129bc255f
Author: Netkas
Date:   Mon Nov 7 22:38:40 2022 -0500

    Added Intellij scopes
     - NCC_Source_files.xml
     - Third_Party_Source_Files.xml

:000000 100644 0000000 6e38ebb A	.idea/scopes/NCC_Source_files.xml
:000000 100644 0000000 73f6682 A	.idea/scopes/Third_Party_Source_Files.xml
 2 files changed, 6 insertions(+)

commit 7f36877919283a036d98590bc439910647029426
Author: Netkas
Date:   Mon Nov 7 14:51:17 2022 -0500

    Corrected compileInstallConstants() in \ncc\Utilities

:100644 100644 2b00bb6 7f1e298 M	src/ncc/Utilities/ConstantCompiler.php
 1 file changed, 4 insertions(+), 4 deletions(-)

commit 2b820db54dd63ff5ce650de5c8002a76d4815c76
Author: Netkas
Date:   Mon Nov 7 13:14:21 2022 -0500

    Reworked Constant Compiler to be accessible for different stages

:000000 100644 0000000 0d4e857 A	src/ncc/Abstracts/SpecialConstants/BuildConstants.php
:000000 100644 0000000 93ba75a A	src/ncc/Abstracts/SpecialConstants/InstallConstants.php
:100644 100644 7d826c5 b3facbb R064	src/ncc/Abstracts/SpecialFormat.php	src/ncc/Abstracts/SpecialConstants/ProjectConstants.php
:000000 100644 0000000 2b00bb6 A	src/ncc/Utilities/ConstantCompiler.php
:100644 100644 79d40aa 8e0fcaf M	src/ncc/Utilities/Functions.php
 5 files changed, 128 insertions(+), 40 deletions(-)

commit bdf083d1fcc03b77887cb872508a45acdca8d1d1
Author: Netkas
Date:   Mon Nov 7 12:38:01 2022 -0500

    Updated ProjectConfiguration.php

:100644 100644 293101c c987271 M	src/ncc/Objects/ProjectConfiguration.php
 1 file changed, 1 insertion(+)

commit 7cac73e748e14212b7de13183e7e1a68126ece0e
Author: Netkas
Date:   Mon Nov 7 12:35:06 2022 -0500

    Updated Build.php to contain new property `main`

:100644 100644 cf45987 b27e917 M	src/ncc/Objects/ProjectConfiguration/Build.php
 1 file changed, 10 insertions(+)

commit a81fbd3bf70f09124308583b9c6087614fb30a92
Merge: baac4e4 ca76f8c
Author: Netkas
Date:   Mon Nov 7 12:13:37 2022 -0500

    Merge remote-tracking branch 'origin/pkgmngr' into pkgmngr

commit baac4e42612c78f638c053f34fb5ec6eb411e86f
Author: Netkas
Date:   Sun Nov 6 17:40:47 2022 -0500

    Added PackageEntry.php
    Added DependencyEntry.php
    Added VersionEntry.php
    Added MainExecutionPolicy
    Updated CompilerInterface.php
    Added InstallerInterface.php
    Added InstallationPaths.php
    Added MainExecutionPolicy and sub-objects to ProjectConfiguration.php

:100644 100644 4fa160d 409ea5e M	src/ncc/Interfaces/CompilerInterface.php
:000000 100644 0000000 75049ce A	src/ncc/Interfaces/InstallerInterface.php
:000000 100644 0000000 d7c745a A	src/ncc/Objects/InstallationPaths.php
:100644 100644 2869f8a 0189a0d M	src/ncc/Objects/Package.php
:100644 100644 8b66ae3 d84e6cd R077	src/ncc/Objects/PackageLock/Dependency.php	src/ncc/Objects/PackageLock/DependencyEntry.php
:000000 100644 0000000 6247cce A	src/ncc/Objects/PackageLock/PackageEntry.php
:100644 100644 2d002d9 b0e925a R069	src/ncc/Objects/PackageLock/Package.php	src/ncc/Objects/PackageLock/VersionEntry.php
:100644 100644 f2980b1 293101c M	src/ncc/Objects/ProjectConfiguration.php
:000000 100644 0000000 8a68586 A	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy.php
:000000 100644 0000000 d8c3624 A	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/Execute.php
:000000 100644 0000000 8d78bcc A	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/ExitHandle.php
:000000 100644 0000000 28a73b2 A	src/ncc/Objects/ProjectConfiguration/ExecutionPolicy/ExitHandlers.php
 12 files changed, 601 insertions(+), 27 deletions(-)

commit 1871f384e08fa5e110c309d0c6b770179775bd0b
Author: Netkas
Date:   Sun Nov 6 14:10:49 2022 -0500

    Deleted unused PackageParser.php

:100644 000000 1d54da1 0000000 D	src/ncc/Classes/PackageParser.php
 1 file changed, 42 deletions(-)

commit 77b257d57c2858651f91c42a1802abc4700f3269
Author: Netkas
Date:   Sun Nov 6 12:25:29 2022 -0500

    IO Correction & Escaped shell arguments (https://git.n64.cc/nosial/ncc/-/issues/5)
    Check if parent object is directory
    Improved IO handling in CredentialManager.php
    Improved IO handling in installer
    Added method fread() to \ncc\Utilities > IO
    Added method fwrite() to \ncc\Utilities > IO
    Updated installer to have better IO handling
    Updated installer with improvements and bug fix for Composer's automatic installation method
    [Issue #22](https://git.n64.cc/nosial/ncc/-/issues/22)
    Added IOException.php
    Added IO.php

:100644 100644 2121c4b 6f9ae9c M	src/installer/installer
:100644 100644 c68a1ea 9e74821 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 e733d0c A	src/ncc/Exceptions/IOException.php
:100644 100644 543e537 4a9b2c2 M	src/ncc/Managers/CredentialManager.php
:000000 100644 0000000 b05f7ee A	src/ncc/Utilities/IO.php
 5 files changed, 286 insertions(+), 76 deletions(-)

commit ca76f8c9713b7825441ee5102b646e82baa532c9
Author: Netkas
Date:   Sun Nov 6 15:22:23 2022 -0500

    IO Correction & Escaped shell arguments (https://git.n64.cc/nosial/ncc/-/issues/5)

:100644 100644 32955ab 6f9ae9c M	src/installer/installer
 1 file changed, 5 insertions(+), 5 deletions(-)

commit 56af17f6e51928d898a6a0eff5dd570cd4d64294
Author: Netkas
Date:   Sun Nov 6 15:21:06 2022 -0500

    Check if parent object is directory

:100644 100644 72c72e6 b05f7ee M	src/ncc/Utilities/IO.php
 1 file changed, 2 insertions(+), 2 deletions(-)

commit 225596dd0720c8d5141fd2a9b7d21949bbeb1974
Author: Netkas
Date:   Sun Nov 6 15:20:20 2022 -0500

    Improved IO handling in CredentialManager.php

:100644 100644 543e537 4a9b2c2 M	src/ncc/Managers/CredentialManager.php
 1 file changed, 16 insertions(+), 16 deletions(-)

commit 7e9d1cf98d5eca70882d5c290c3e78112c58f5d9
Author: Netkas
Date:   Sun Nov 6 14:44:13 2022 -0500

    Improved IO handling in installer

:100644 100644 ace496f 32955ab M	src/installer/installer
 1 file changed, 71 insertions(+), 29 deletions(-)

commit 265d42d75de2313d7672b1485b3ecf45610aee63
Author: Netkas
Date:   Sun Nov 6 14:34:56 2022 -0500

    Added method fread() to \ncc\Utilities > IO

:100644 100644 8c38584 72c72e6 M	src/ncc/Utilities/IO.php
 1 file changed, 44 insertions(+), 1 deletion(-)

commit 77bf4b77af22e56be75cd2d5c0c3239c5e14b6b7
Author: Netkas
Date:   Sun Nov 6 14:25:44 2022 -0500

    Updated installer to have better IO handling

:100644 100644 9d919ce ace496f M	src/installer/installer
 1 file changed, 31 insertions(+), 7 deletions(-)

commit bc07921d199d5a7e83983c6a138049eefc9a5268
Author: Netkas
Date:   Sun Nov 6 14:10:49 2022 -0500

    Deleted unused PackageParser.php

:100644 000000 1d54da1 0000000 D	src/ncc/Classes/PackageParser.php
 1 file changed, 42 deletions(-)

commit 60af4da72d379f02da72c9732c025151890bfa7b
Author: Netkas
Date:   Sun Nov 6 12:31:14 2022 -0500

    Updated installer with improvements and bug fix for Composer's automatic installation method
    
    [Issue #22](https://git.n64.cc/nosial/ncc/-/issues/22)

:100644 100644 2121c4b 9d919ce M	src/installer/installer
 1 file changed, 40 insertions(+), 23 deletions(-)

commit 1aa5cf8c52e3db381f3e70f14208a3079592a2b3
Author: Netkas
Date:   Sun Nov 6 12:25:54 2022 -0500

    Added IOException.php

:100644 100644 c68a1ea 9e74821 M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 e733d0c A	src/ncc/Exceptions/IOException.php
 2 files changed, 36 insertions(+), 1 deletion(-)

commit 47b240bfcae5ad87ca368c9d5e14692bcf7e2a38
Author: Netkas
Date:   Sun Nov 6 12:25:29 2022 -0500

    Added IO.php

:000000 100644 0000000 8c38584 A	src/ncc/Utilities/IO.php
 1 file changed, 49 insertions(+)

commit 70f88ccaf702aad3ff86a7cce4366237675686b5
Author: Netkas
Date:   Sun Nov 6 09:11:25 2022 -0500

    Deleted unused AutoloaderGenerator.php

:100644 000000 2f94c89 0000000 D	src/ncc/Classes/PhpExtension/AutoloaderGenerator.php
 1 file changed, 120 deletions(-)

commit 88abe9d79abe308fe5cc198c7cab5171503038fa
Author: Netkas
Date:   Sat Nov 5 07:16:04 2022 -0400

    Updated ExceptionCodes.php
    Added ComponentChecksumException.php
    Added ComponentDecodeException.php
    Added InstallationException.php
    Added PackageLockException.php
    Added ResourceChecksumException.php
    Added UnsupportedComponentTypeException.php

:100644 100644 0e0dfca c68a1ea M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 68bb520 A	src/ncc/Exceptions/ComponentChecksumException.php
:000000 100644 0000000 593255f A	src/ncc/Exceptions/ComponentDecodeException.php
:000000 100644 0000000 1b99c67 A	src/ncc/Exceptions/InstallationException.php
:000000 100644 0000000 b86c20c A	src/ncc/Exceptions/PackageLockException.php
:000000 100644 0000000 911a885 A	src/ncc/Exceptions/ResourceChecksumException.php
:000000 100644 0000000 ecd4c79 A	src/ncc/Exceptions/UnsupportedComponentTypeException.php
 7 files changed, 211 insertions(+), 1 deletion(-)

commit aac8f8b769be51b47be1fa70e6bd03e62bf85ab1
Author: Netkas
Date:   Tue Nov 1 18:55:25 2022 -0400

    Added method load() to \ncc\Objects > Package

:100644 100644 78bf4dc 2869f8a M	src/ncc/Objects/Package.php
 1 file changed, 114 insertions(+), 3 deletions(-)

commit 41e2b736394cc29f9a71ab7fca6642b1e8c297f9
Author: Netkas
Date:   Tue Nov 1 18:53:41 2022 -0400

    Add default state for package type

:100644 100644 df54f71 3e86446 M	src/ncc/Objects/Package/MagicBytes.php
 1 file changed, 6 insertions(+)

commit 99ceabb7f9f78b68cebef124e10ff3eb0f3c5601
Author: Netkas
Date:   Tue Nov 1 18:53:14 2022 -0400

    Removed CLI checks from Compiler.php

:100644 100644 77fa4fc 0ce15f9 M	src/ncc/Classes/PhpExtension/Compiler.php
 1 file changed, 24 insertions(+), 43 deletions(-)

commit 5d6200608366ec8b5af86f9345578662fd90bb27
Author: Netkas
Date:   Tue Nov 1 18:29:45 2022 -0400

    Added comments to SpecialFormat.php

:100644 100644 ab80064 7d826c5 M	src/ncc/Abstracts/SpecialFormat.php
 1 file changed, 40 insertions(+), 1 deletion(-)

commit 38046d81019471e8ccdfaaf9f4e6b43f67d6928b
Author: Netkas
Date:   Tue Nov 1 18:27:09 2022 -0400

    Added the functionality to compile constants

:100644 100644 4257002 77fa4fc M	src/ncc/Classes/PhpExtension/Compiler.php
:100644 100644 9d85b37 79d40aa M	src/ncc/Utilities/Functions.php
 2 files changed, 37 insertions(+)

commit 98ccc60f82b33bf11a49382ca12216f5f81cc11c
Author: Netkas
Date:   Tue Nov 1 17:43:30 2022 -0400

    Removed unused byteEncode() and byteDecode() functions from \ncc\Utilities > Functions

:100644 100644 8be1667 9d85b37 M	src/ncc/Utilities/Functions.php
 1 file changed, 24 deletions(-)

commit 4b2d320f48ac2426fcb159fc8ab50525a32a7569
Author: Netkas
Date:   Tue Nov 1 17:31:35 2022 -0400

    Added Dependency.php and Package.php

:000000 100644 0000000 8b66ae3 A	src/ncc/Objects/PackageLock/Dependency.php
:000000 100644 0000000 2d002d9 A	src/ncc/Objects/PackageLock/Package.php
 2 files changed, 149 insertions(+)

commit 6cfa358b887115a9eeefc41011ede29b1efd8e12
Author: Netkas
Date:   Sun Oct 30 17:48:49 2022 -0400

    Updated \ncc\Utilities > Functions > cbc() to return a binary string representation instead of an integer

:100644 100644 e0b74d9 8be1667 M	src/ncc/Utilities/Functions.php
 1 file changed, 3 insertions(+), 3 deletions(-)

commit ef1871989934cf05be823f05a954751d7919fa19
Author: Netkas
Date:   Sun Oct 30 13:25:35 2022 -0400

    Added PackageManagerMenu.php

:000000 100644 0000000 6abd7e5 A	src/ncc/CLI/PackageManagerMenu.php
 1 file changed, 57 insertions(+)

commit 843289e239c9e4b19e1d623b5b0881ec5f5da76b
Author: Netkas
Date:   Sat Oct 29 09:27:27 2022 -0400

    Added PackageStructureVersions.php

:000000 100644 0000000 fd11063 A	src/ncc/Abstracts/PackageStructureVersions.php
 1 file changed, 12 insertions(+)

commit 4b74ffe8f74fe81f72e67175d5f3bd53dec93b01
Author: Netkas
Date:   Fri Oct 28 03:45:48 2022 -0400

    Added PackageParsingException.php

:100644 100644 9ae32a2 0e0dfca M	src/ncc/Abstracts/ExceptionCodes.php
:000000 100644 0000000 70c1be7 A	src/ncc/Exceptions/PackageParsingException.php
 2 files changed, 36 insertions(+), 1 deletion(-)
This commit is contained in:
Zi Xing 2022-11-25 06:50:47 +00:00
parent e5491d4ca2
commit 78399c4710
90 changed files with 6796 additions and 847 deletions

3
.idea/scopes/NCC_Source_files.xml generated Normal file
View file

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="NCC Source files" pattern="file[ncc]:src/ncc/Managers//*||file[ncc]:src/ncc/Abstracts//*||file[ncc]:src/ncc/Exceptions//*||file[ncc]:src/ncc/Runtime//*||file[ncc]:src/ncc/Extensions//*||file[ncc]:src/ncc/CLI//*||file[ncc]:src/ncc/Classes//*||file[ncc]:src/ncc/Objects//*||file[ncc]:src/ncc/Interfaces//*||file[ncc]:src/ncc/Utilities//*||file:src/ncc/ncc.php||file:src/ncc/ncc||file:src/ncc/banner_basic||file:src/ncc/autoload_spl.php||file:src/ncc/autoload.php" />
</component>

View file

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Third Party Source Files" pattern="file[ncc]:src/ncc/ThirdParty//*" />
</component>

BIN
assets/pkg_struct_1.0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View file

@ -0,0 +1,151 @@
# Execution Policies
**Updated on Sunday, November 20, 2022**
An execution policy is a policy defined in the Project
configuration file (`project.json`) that can be used
to execute a script or program in any stage of the package
For instance, you can have a script that is executed before
the build process starts, or in different installation stages
when the user is installing your package you can have a unit
run before or after the installation/uninstallation process
starts.#
Use cases such as this allows you to properly implement
and control your program's files & assets that are not
handled by NCC's compiler extensions.
## Table of Contents
<!-- TOC -->
* [Execution Policies](#execution-policies)
* [Table of Contents](#table-of-contents)
* [JSON Example](#json-example)
* [ExecutionPolicy Object](#executionpolicy-object)
* [Object Properties](#object-properties)
* [JSON Example](#json-example)
* [ExecutionConfiguration Object](#executionconfiguration-object)
* [Object Properties](#object-properties)
* [JSON Example](#json-example)
* [ExitHandler Object](#exithandler-object)
* [Object Properties](#object-properties)
* [JSON Example](#json-example)
<!-- TOC -->
## JSON Example
```json
{
"execution_policies": {
"main": {
"runner": "php",
"message": "Running main %ASSEMBLY.PACKAGE%",
"exec": {
"target": "scripts/main.php",
"working_directory": "%INSTALL_PATH.SRC%",
"silent": false
}
},
"hello_world": {
"runner": "shell",
"message": "Running HTOP",
"options": {
"htop": null
},
"exec": {
"tty": true
}
}
}
}
```
------------------------------------------------------------
## ExecutionPolicy Object
Execution Policies for your project **must** have unique
names, because they way you tell NCC to execute these
policies is by referencing their name in the configuration.
Invalid names/undefined policies will raise errors when
building the project
### Object Properties
| Property Name | Value Type | Example Value | Description |
|-----------------|---------------------------------|----------------------|--------------------------------------------------------------------------------------------|
| `runner` | string | bash | The name of a supported runner instance, see runners in this document |
| `message` | string, null | Starting foo_bar ... | *Optional* the message to display before running the execution policy |
| `exec` | ExecutionConfiguration | N/A | The configuration object that tells how the runner should execute the process |
| `exit_handlers` | ExitHandlersConfiguration, null | N/A | *Optional* Exit Handler Configurations that tells NCC how to handle exits from the process |
### JSON Example
```json
{
"name": "foo_bar",
"runner": "bash",
"message": "Running foo_bar ...",
"exec": null,
"exit_handlers": null
}
```
------------------------------------------------------------
## ExecutionConfiguration Object
### Object Properties
| Property Name | Value Type | Example Value | Description |
|---------------------|-------------------|---------------------------------|------------------------------------------------------------------------|
| `target` | `string` | scripts/foo_bar.bash | The target file to execute |
| `working_directory` | `string`, `null` | %INSTALL_PATH.SRC% | *optional* The working directory to execute the process in |
| `options` | `array`, `null` | {"run": null, "log": "verbose"} | Commandline Parameters to pass on to the target or process |
| `silent` | `boolean`, `null` | False | Indicates if the target should run silently, by default this is false. |
| `tty` | `boolean`, `null` | False | Indicates if the target should run in TTY mode |
| `timeout` | `integer`, `null` | 60 | The amount of seconds to wait before the process is killed |
### JSON Example
```json
{
"target": "scripts/foo_bar.bash",
"working_directory": "%INSTALL_PATH.SRC%",
"options": {"run": null, "log": "verbose"},
"silent": false,
"tty": false,
"timeout": 10
}
```
------------------------------------------------------------
## ExitHandler Object
An exit handler is executed once the specified exit code is
returned or the process exits with an error or normally, if
an exit handler is specified it will be executed.
### Object Properties
| Property Name | Value Type | Example Value | Description |
|---------------|--------------------|---------------|------------------------------------------------------------------------------|
| `message` | `string` | Hello World! | The message to display when the exit handler is triggered |
| `end_process` | `boolean`, `null` | False | *optional* Kills the process after this exit handler is triggered |
| `run` | `string`, `null` | `null` | *optional* A execution policy to execute once this exit handler is triggered |
| `exit_code` | `int`, `null` | 1 | The exit code that triggers this exit handler |
### JSON Example
```json
{
"message": "Hello World",
"end_process": false,
"run": null,
"exit_code": 1
}
```

View file

@ -12,12 +12,8 @@
<?PHP <?PHP
use ncc\Abstracts\Scopes; use ncc\Abstracts\ConsoleColors;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\ComponentVersionNotFoundException;
use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Managers\CredentialManager;
use ncc\ncc; use ncc\ncc;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException; use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
@ -29,7 +25,7 @@
use ncc\ThirdParty\Symfony\Yaml\Yaml; use ncc\ThirdParty\Symfony\Yaml\Yaml;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\PathFinder; use ncc\Utilities\IO;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\Utilities\Validate; use ncc\Utilities\Validate;
use ncc\ZiProto\ZiProto; use ncc\ZiProto\ZiProto;
@ -82,6 +78,7 @@
// Initialize NCC // Initialize NCC
try try
{ {
define('NCC_CLI_MODE', 1);
ncc::initialize(); ncc::initialize();
} }
catch (FileNotFoundException|\ncc\Exceptions\RuntimeException $e) catch (FileNotFoundException|\ncc\Exceptions\RuntimeException $e)
@ -192,7 +189,7 @@
]; ];
foreach($required_files as $path) foreach($required_files as $path)
{ {
if(!file_exists($path)) if(!$NCC_FILESYSTEM->exists($path))
{ {
Console::outError('Missing file \'' . $path . '\', installation failed.', true, 1); Console::outError('Missing file \'' . $path . '\', installation failed.', true, 1);
exit(1); exit(1);
@ -202,7 +199,7 @@
// Preform the checksum validation // Preform the checksum validation
if(!$NCC_BYPASS_CHECKSUM) if(!$NCC_BYPASS_CHECKSUM)
{ {
if(!file_exists($NCC_CHECKSUM)) if(!$NCC_FILESYSTEM->exists($NCC_CHECKSUM))
{ {
Console::outWarning('The file \'checksum.bin\' was not found, the contents of the program cannot be verified to be safe'); Console::outWarning('The file \'checksum.bin\' was not found, the contents of the program cannot be verified to be safe');
} }
@ -210,7 +207,16 @@
{ {
Console::out('Running checksum'); Console::out('Running checksum');
$checksum = ZiProto::decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin')); try
{
$checksum = ZiProto::decode(IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin'));
}
catch(Exception $e)
{
Console::outError($e->getMessage(), true, 1);
return;
}
$checksum_failed = false; $checksum_failed = false;
foreach($checksum as $path => $hash) foreach($checksum as $path => $hash)
@ -239,24 +245,33 @@
} }
} }
// Check for required extensions // Check the installed extensions and report
$curl_available = true; Console::out('Checking installed extensions...');
foreach(Validate::requiredExtensions() as $ext => $installed) $extensions = Validate::requiredExtensions();
foreach($extensions as $ext => $installed)
{ {
if(!$installed) if($installed)
{ {
switch($ext) Console::out("$ext ... " . Console::formatColor("installed", ConsoleColors::LightGreen));
}
else
{ {
case 'curl': Console::out("$ext ... " . Console::formatColor("missing", ConsoleColors::LightRed));
Console::outWarning('This installer requires the \'curl\' extension to install composer'); }
$curl_available = false; }
break;
default: // Check for curl if the installer requires it
Console::outWarning('The extension \'' . $ext . '\' is not installed, compatibility without it is not guaranteed'); $curl_available = true;
break; if(!$extensions['curl'])
} {
if(getParameter($NCC_ARGS, 'install-composer') !== null)
{
Console::outError('This installer requires the \'curl\' extension to install composer', true, 1);
return;
} }
$curl_available = false;
Console::outWarning('The extension \'curl\' is not installed, the installer will not be able to install composer');
} }
// Attempt to load version information // Attempt to load version information
@ -283,14 +298,16 @@
try try
{ {
Console::out($full_name . ' Version: ' . $component->getVersion()); Console::out(Console::formatColor($full_name, ConsoleColors::Green) . ' Version: ' . Console::formatColor($component->getVersion(), ConsoleColors::LightMagenta));
} }
catch (ComponentVersionNotFoundException $e) catch (Exception $e)
{ {
Console::outWarning('Cannot determine component version of ' . $full_name); Console::outWarning('Cannot determine component version of ' . Console::formatColor($full_name, ConsoleColors::Green));
} }
} }
Console::out('Starting installation');
// Determine the installation path // Determine the installation path
$skip_prompt = false; $skip_prompt = false;
$install_dir_arg = getParameter($NCC_ARGS, 'install-dir'); $install_dir_arg = getParameter($NCC_ARGS, 'install-dir');
@ -304,7 +321,7 @@
exit(1); exit(1);
} }
if(file_exists($install_dir_arg . DIRECTORY_SEPARATOR . 'ncc')) if($NCC_FILESYSTEM->exists($install_dir_arg . DIRECTORY_SEPARATOR . 'ncc'))
{ {
Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install'); Console::out('NCC Seems to already be installed, the installer will repair/upgrade your current install');
$NCC_INSTALL_PATH = $install_dir_arg; $NCC_INSTALL_PATH = $install_dir_arg;
@ -323,9 +340,9 @@
{ {
$user_input = null; $user_input = null;
$user_input = Console::getInput("Installation Path (Default: $NCC_INSTALL_PATH): "); $user_input = Console::getInput("Installation Path (Default: $NCC_INSTALL_PATH): ");
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input)) if(strlen($user_input) > 0 && $NCC_FILESYSTEM->exists($user_input) && Validate::unixFilepath($user_input))
{ {
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'ncc')) if($NCC_FILESYSTEM->exists($user_input . DIRECTORY_SEPARATOR . 'ncc'))
{ {
$NCC_INSTALL_PATH = $user_input; $NCC_INSTALL_PATH = $user_input;
break; break;
@ -346,7 +363,6 @@
} }
} }
// Determine the data path // Determine the data path
$skip_prompt = false; $skip_prompt = false;
$data_dir_arg = getParameter($NCC_ARGS, 'data-dir'); $data_dir_arg = getParameter($NCC_ARGS, 'data-dir');
@ -360,7 +376,7 @@
exit(1); exit(1);
} }
if(file_exists($data_dir_arg . DIRECTORY_SEPARATOR . 'package.lck')) if($NCC_FILESYSTEM->exists($data_dir_arg . DIRECTORY_SEPARATOR . 'package.lck'))
{ {
$NCC_DATA_PATH = $data_dir_arg; $NCC_DATA_PATH = $data_dir_arg;
$skip_prompt = true; $skip_prompt = true;
@ -379,9 +395,9 @@
{ {
$user_input = null; $user_input = null;
$user_input = Console::getInput("Data Path (Default: $NCC_DATA_PATH): "); $user_input = Console::getInput("Data Path (Default: $NCC_DATA_PATH): ");
if(strlen($user_input) > 0 && file_exists($user_input) && Validate::unixFilepath($user_input)) if(strlen($user_input) > 0 && $NCC_FILESYSTEM->exists($user_input) && Validate::unixFilepath($user_input))
{ {
if(file_exists($user_input . DIRECTORY_SEPARATOR . 'package.lck')) if($NCC_FILESYSTEM->exists($user_input . DIRECTORY_SEPARATOR . 'package.lck'))
{ {
$NCC_DATA_PATH = $user_input; $NCC_DATA_PATH = $user_input;
break; break;
@ -409,21 +425,25 @@
{ {
$update_composer = true; $update_composer = true;
} }
elseif(getParameter($NCC_ARGS, 'install-composer') !== null)
{
$update_composer = true;
}
else else
{
if(!$NCC_AUTO_MODE)
{ {
Console::out("Note: This doesn't affect your current install of composer (if you have composer installed)"); Console::out("Note: This doesn't affect your current install of composer (if you have composer installed)");
$update_composer = Console::getBooleanInput('Do you want to install composer for NCC? (Recommended)'); $update_composer = Console::getBooleanInput('Do you want to install composer for NCC? (Recommended)');
} }
else
{
$update_composer = false;
}
}
} }
else else
{ {
$update_composer = false; $update_composer = false;
} }
if(!$NCC_AUTO_MODE) if(!$NCC_AUTO_MODE)
{ {
if(!Console::getBooleanInput('Do you want install NCC?')) if(!Console::getBooleanInput('Do you want install NCC?'))
@ -435,14 +455,22 @@
// Backup the configuration file // Backup the configuration file
$config_backup = null; $config_backup = null;
if(file_exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml')) if($NCC_FILESYSTEM->exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml'))
{ {
Console::out('ncc.yaml will be updated'); Console::out('ncc.yaml will be updated');
$config_backup = file_get_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml'); try
{
$config_backup = IO::fread($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml');
}
catch(Exception $e)
{
Console::outError($e->getMessage(), true, 1);
return;
}
} }
// Prepare installation // Prepare installation
if(file_exists($NCC_INSTALL_PATH)) if($NCC_FILESYSTEM->exists($NCC_INSTALL_PATH))
{ {
try try
{ {
@ -455,35 +483,20 @@
} }
} }
// Create the required directories $NCC_FILESYSTEM->mkdir($NCC_INSTALL_PATH, 0755);
$required_dirs = [
$NCC_INSTALL_PATH,
$NCC_DATA_PATH,
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'packages',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'repos',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'downloads',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'data',
$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'ext',
];
$NCC_FILESYSTEM->mkdir($required_dirs, 0755); try
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'config'], 0777);
$NCC_FILESYSTEM->chmod([$NCC_DATA_PATH . DIRECTORY_SEPARATOR . 'cache'], 0777);
// Verify directories exist
foreach($required_dirs as $dir)
{ {
if(!file_exists($dir)) Functions::initializeFiles();
{
Console::outError("Cannot create directory '$dir', please verify if you have write permissions to the directory.");
exit(1);
} }
catch(Exception $e)
{
Console::outError('Cannot initialize NCC files, ' . $e->getMessage());
exit(1);
} }
// Install composer // Install composer
if($curl_available && $update_composer) if($update_composer)
{ {
Console::out('Installing composer for NCC'); Console::out('Installing composer for NCC');
@ -501,11 +514,10 @@
fclose($fp); fclose($fp);
Console::out('Running composer installer'); Console::out('Running composer installer');
// TODO: Unescaped shell arguments are a security issue
$Process = Process::fromShellCommandline(implode(' ', [ $Process = Process::fromShellCommandline(implode(' ', [
$NCC_PHP_EXECUTABLE, $NCC_PHP_EXECUTABLE,
$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer-setup.php', escapeshellcmd($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'composer-setup.php'),
'--install-dir=' . $NCC_INSTALL_PATH, '--install-dir=' . escapeshellcmd($NCC_INSTALL_PATH),
'--filename=composer.phar' '--filename=composer.phar'
])); ]));
$Process->setWorkingDirectory($NCC_INSTALL_PATH); $Process->setWorkingDirectory($NCC_INSTALL_PATH);
@ -536,7 +548,15 @@
// Install NCC // Install NCC
Console::out('Copying files to \'' . $NCC_INSTALL_PATH . '\''); Console::out('Copying files to \'' . $NCC_INSTALL_PATH . '\'');
$build_files = explode("\n", file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'build_files')); try
{
$build_files = explode("\n", IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'build_files'));
}
catch(Exception $e)
{
Console::outError($e->getMessage(), true, 1);
return;
}
$total_items = count($build_files); $total_items = count($build_files);
$processed_items = 0; $processed_items = 0;
@ -561,7 +581,7 @@
$NCC_FILESYSTEM->copy(__DIR__ . DIRECTORY_SEPARATOR . $file, $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file); $NCC_FILESYSTEM->copy(__DIR__ . DIRECTORY_SEPARATOR . $file, $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file);
$NCC_FILESYSTEM->chmod([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file], 0755); $NCC_FILESYSTEM->chmod([$NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file], 0755);
if(!file_exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file)) if(!$NCC_FILESYSTEM->exists($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file))
{ {
Console::outError('Cannot create file \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file . '\', installation failed.'); Console::outError('Cannot create file \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . $file . '\', installation failed.');
exit(1); exit(1);
@ -573,32 +593,19 @@
Console::inlineProgressBar($processed_items, $total_items); Console::inlineProgressBar($processed_items, $total_items);
} }
// Create credential store if needed
Console::out('Processing Credential Store');
$credential_manager = new CredentialManager();
try
{
$credential_manager->constructStore();
}
catch (AccessDeniedException|\ncc\Exceptions\RuntimeException $e)
{
Console::outError('Cannot construct credential store, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
}
try
{
$NCC_FILESYSTEM->touch([PathFinder::getPackageLock(Scopes::System)]);
}
catch (InvalidScopeException $e)
{
Console::outError('Cannot create package lock, ' . $e->getMessage());
exit(0);
}
// Generate executable shortcut // Generate executable shortcut
Console::out('Creating shortcut'); Console::out('Creating shortcut');
$executable_shortcut = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'ncc.sh');
try
{
$executable_shortcut = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'ncc.sh');
}
catch(Exception $e)
{
Console::outError($e->getMessage(), true, 1);
return;
}
$executable_shortcut = str_ireplace('%php_exec', $NCC_PHP_EXECUTABLE, $executable_shortcut); $executable_shortcut = str_ireplace('%php_exec', $NCC_PHP_EXECUTABLE, $executable_shortcut);
$executable_shortcut = str_ireplace('%ncc_exec', $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut); $executable_shortcut = str_ireplace('%ncc_exec', $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut);
@ -611,41 +618,65 @@
foreach($bin_paths as $path) foreach($bin_paths as $path)
{ {
// Delete old versions of the executable shortcuts. // Delete old versions of the executable shortcuts.
if(file_exists($path . DIRECTORY_SEPARATOR . 'ncc')) if($NCC_FILESYSTEM->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
{ {
$NCC_FILESYSTEM->remove($path . DIRECTORY_SEPARATOR . 'ncc'); $NCC_FILESYSTEM->remove($path . DIRECTORY_SEPARATOR . 'ncc');
} }
if($NCC_FILESYSTEM->exists([$path])) if($NCC_FILESYSTEM->exists($path))
{ {
file_put_contents($path . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut); try
$NCC_FILESYSTEM->chmod([$path . DIRECTORY_SEPARATOR . 'ncc'], 0755); {
IO::fwrite($path . DIRECTORY_SEPARATOR . 'ncc', $executable_shortcut);
break;
}
catch (Exception $e)
{
Console::outException($e->getMessage(), $e, 1);
return;
}
} }
} }
// Register the ncc extension // Register the ncc extension
Console::out('Registering extension'); Console::out('Registering extension');
$extension_shortcut = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'extension'); try
{
$extension_shortcut = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'extension');
}
catch(Exception $e)
{
Console::outError($e->getMessage(), true, 1);
return;
}
$extension_shortcut = str_ireplace('%ncc_install', $NCC_INSTALL_PATH, $extension_shortcut); $extension_shortcut = str_ireplace('%ncc_install', $NCC_INSTALL_PATH, $extension_shortcut);
// Remove all the old extensions first. // Remove all the old extensions first.
/** /**
* @param string $path * @param string $path
* @param Filesystem $NCC_FILESYSTEM * @param Filesystem $filesystem
* @param string $extension_shortcut * @param string $extension_shortcut
* @return bool * @return bool
*/ */
function install_extension(string $path, Filesystem $NCC_FILESYSTEM, string $extension_shortcut): bool function install_extension(string $path, Filesystem $filesystem, string $extension_shortcut): bool
{ {
if (file_exists($path . DIRECTORY_SEPARATOR . 'ncc')) if ($filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
{ {
$NCC_FILESYSTEM->remove($path . DIRECTORY_SEPARATOR . 'ncc'); $filesystem->remove($path . DIRECTORY_SEPARATOR . 'ncc');
} }
file_put_contents($path . DIRECTORY_SEPARATOR . 'ncc', $extension_shortcut); try
$NCC_FILESYSTEM->chmod([$path . DIRECTORY_SEPARATOR . 'ncc'], 0755); {
IO::fwrite($path . DIRECTORY_SEPARATOR . 'ncc', $extension_shortcut);
}
catch (\ncc\Exceptions\IOException $e)
{
Console::outException($e->getMessage(), $e, 1);
return false;
}
if (file_exists($path . DIRECTORY_SEPARATOR . 'ncc')) { if ($filesystem->exists($path . DIRECTORY_SEPARATOR . 'ncc'))
{
return true; return true;
} }
@ -745,7 +776,15 @@
Console::out('Updating ncc.yaml'); Console::out('Updating ncc.yaml');
} }
file_put_contents($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml', Yaml::dump($config_obj)); try
{
IO::fwrite($NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'ncc.yaml', Yaml::dump($config_obj));
}
catch (\ncc\Exceptions\IOException $e)
{
Console::outException($e->getMessage(), $e, 1);
return;
}
Console::out('NCC version: ' . NCC_VERSION_NUMBER . ' has been successfully installed'); Console::out('NCC version: ' . NCC_VERSION_NUMBER . ' has been successfully installed');
Console::out('For licensing information see \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'LICENSE\' or run \'ncc help --license\''); Console::out('For licensing information see \'' . $NCC_INSTALL_PATH . DIRECTORY_SEPARATOR . 'LICENSE\' or run \'ncc help --license\'');

View file

@ -0,0 +1,14 @@
<?php
namespace ncc\Abstracts;
abstract class ConstantReferences
{
const Assembly = 'assembly';
const Build = 'build';
const DateTime = 'date_time';
const Install = 'install';
}

View file

@ -6,12 +6,17 @@
use ncc\Exceptions\AutoloadGeneratorException; use ncc\Exceptions\AutoloadGeneratorException;
use ncc\Exceptions\BuildConfigurationNotFoundException; use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException; use ncc\Exceptions\BuildException;
use ncc\Exceptions\ComponentChecksumException;
use ncc\Exceptions\ComponentDecodeException;
use ncc\Exceptions\ComponentVersionNotFoundException; use ncc\Exceptions\ComponentVersionNotFoundException;
use ncc\Exceptions\ConstantReadonlyException; use ncc\Exceptions\ConstantReadonlyException;
use ncc\Exceptions\DirectoryNotFoundException; use ncc\Exceptions\DirectoryNotFoundException;
use ncc\Exceptions\ExecutionUnitNotFoundException;
use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InstallationException;
use ncc\Exceptions\InvalidConstantNameException; use ncc\Exceptions\InvalidConstantNameException;
use ncc\Exceptions\InvalidCredentialsEntryException; use ncc\Exceptions\InvalidCredentialsEntryException;
use ncc\Exceptions\InvalidExecutionPolicyName;
use ncc\Exceptions\InvalidPackageException; use ncc\Exceptions\InvalidPackageException;
use ncc\Exceptions\InvalidPackageNameException; use ncc\Exceptions\InvalidPackageNameException;
use ncc\Exceptions\InvalidProjectBuildConfiguration; use ncc\Exceptions\InvalidProjectBuildConfiguration;
@ -21,12 +26,25 @@
use ncc\Exceptions\InvalidScopeException; use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\InvalidVersionConfigurationException; use ncc\Exceptions\InvalidVersionConfigurationException;
use ncc\Exceptions\InvalidVersionNumberException; use ncc\Exceptions\InvalidVersionNumberException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\MalformedJsonException; use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\NoAvailableUnitsException;
use ncc\Exceptions\NoUnitsFoundException; use ncc\Exceptions\NoUnitsFoundException;
use ncc\Exceptions\PackageAlreadyInstalledException;
use ncc\Exceptions\PackageLockException;
use ncc\Exceptions\PackageNotFoundException;
use ncc\Exceptions\PackageParsingException;
use ncc\Exceptions\ProjectAlreadyExistsException; use ncc\Exceptions\ProjectAlreadyExistsException;
use ncc\Exceptions\ProjectConfigurationNotFoundException;
use ncc\Exceptions\ResourceChecksumException;
use ncc\Exceptions\RunnerExecutionException;
use ncc\Exceptions\RuntimeException; use ncc\Exceptions\RuntimeException;
use ncc\Exceptions\UndefinedExecutionPolicyException;
use ncc\Exceptions\UnsupportedComponentTypeException;
use ncc\Exceptions\UnsupportedCompilerExtensionException; use ncc\Exceptions\UnsupportedCompilerExtensionException;
use ncc\Exceptions\UnsupportedPackageException; use ncc\Exceptions\UnsupportedPackageException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Exceptions\VersionNotFoundException;
/** /**
* @author Zi Xing Narrakas * @author Zi Xing Narrakas
@ -174,6 +192,96 @@
*/ */
const BuildException = -1727; const BuildException = -1727;
/**
* @see PackageParsingException
*/
const PackageParsingException = -1728;
/**
* @see PackageLockException
*/
const PackageLockException = -1729;
/**
* @see InstallationException
*/
const InstallationException = -1730;
/**
* @see UnsupportedComponentTypeException
*/
const UnsupportedComponentTypeException = -1731;
/**
* @see ComponentDecodeException
*/
const ComponentDecodeException = -1732;
/**
* @see ComponentChecksumException
*/
const ComponentChecksumException = -1733;
/**
* @see ResourceChecksumException
*/
const ResourceChecksumException = -1734;
/**
* @see IOException
*/
const IOException = -1735;
/**
* @see UnsupportedRunnerException
*/
const UnsupportedRunnerException = -1736;
/**
* @see VersionNotFoundException
*/
const VersionNotFoundException = -1737;
/**
* @see UndefinedExecutionPolicyException
*/
const UndefinedExecutionPolicyException = -1738;
/**
* @see InvalidExecutionPolicyName
*/
const InvalidExecutionPolicyName = -1739;
/**
* @see ProjectConfigurationNotFoundException
*/
const ProjectConfigurationNotFoundException = -1740;
/**
* @see RunnerExecutionException
*/
const RunnerExecutionException = -1741;
/**
* @see NoAvailableUnitsException
*/
const NoAvailableUnitsException = -1742;
/**
* @see ExecutionUnitNotFoundException
*/
const ExecutionUnitNotFoundException = -1743;
/**
* @see PackageAlreadyInstalledException
*/
const PackageAlreadyInstalledException = -1744;
/**
* @see PackageNotFoundException
*/
const PackageNotFoundException = -1745;
/** /**
* All the exception codes from NCC * All the exception codes from NCC
*/ */
@ -205,6 +313,23 @@
self::InvalidPropertyValueException, self::InvalidPropertyValueException,
self::InvalidVersionConfigurationException, self::InvalidVersionConfigurationException,
self::UnsupportedExtensionVersionException, self::UnsupportedExtensionVersionException,
self::BuildException self::BuildException,
self::PackageParsingException,
self::PackageLockException,
self::InstallationException,
self::UnsupportedComponentTypeException,
self::ComponentDecodeException,
self::ResourceChecksumException,
self::IOException,
self::UnsupportedRunnerException,
self::VersionNotFoundException,
self::UndefinedExecutionPolicyException,
self::InvalidExecutionPolicyName,
self::ProjectConfigurationNotFoundException,
self::RunnerExecutionException,
self::NoAvailableUnitsException,
self::ExecutionUnitNotFoundException,
self::PackageAlreadyInstalledException,
self::PackageNotFoundException
]; ];
} }

View file

@ -0,0 +1,30 @@
<?php
namespace ncc\Abstracts;
abstract class LogLevel
{
const Silent = 'silent';
const Verbose = 'verbose';
const Debug = 'debug';
const Info = 'info';
const Warning = 'warn';
const Error = 'error';
const Fatal = 'fatal';
const All = [
self::Silent,
self::Verbose,
self::Debug,
self::Info,
self::Warning,
self::Error,
self::Fatal,
];
}

View file

@ -5,4 +5,6 @@
abstract class BuildConfigurationValues abstract class BuildConfigurationValues
{ {
const DefaultConfiguration = 'default'; const DefaultConfiguration = 'default';
const AllConfigurations = 'all';
} }

View file

@ -0,0 +1,12 @@
<?php
namespace ncc\Abstracts;
abstract class PackageStructureVersions
{
const _1_0 = '1.0';
const ALL = [
self::_1_0
];
}

View file

@ -23,4 +23,6 @@
const WindowsPath = '/^(([%][^\/:*?<>""|]*[%])|([a-zA-Z][:])|(\\\\))((\\\\{1})|((\\\\{1})[^\\\\]([^\/:*?<>""|]*))+)$/m'; const WindowsPath = '/^(([%][^\/:*?<>""|]*[%])|([a-zA-Z][:])|(\\\\))((\\\\{1})|((\\\\{1})[^\\\\]([^\/:*?<>""|]*))+)$/m';
const ConstantName = '/^([^\x00-\x7F]|[\w_\ \.\+\-]){2,64}$/'; const ConstantName = '/^([^\x00-\x7F]|[\w_\ \.\+\-]){2,64}$/';
const ExecutionPolicyName = '/^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/m';
} }

View file

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

View file

@ -0,0 +1,51 @@
<?php
namespace ncc\Abstracts\SpecialConstants;
abstract class AssemblyConstants
{
/**
* Assembly's Name Property
*/
const AssemblyName = '%ASSEMBLY.NAME%';
/**
* Assembly's Package Property
*/
const AssemblyPackage = '%ASSEMBLY.PACKAGE%';
/**
* Assembly's Description Property
*/
const AssemblyDescription = '%ASSEMBLY.DESCRIPTION%';
/**
* Assembly's Company Property
*/
const AssemblyCompany = '%ASSEMBLY.COMPANY%';
/**
* Assembly's Product Property
*/
const AssemblyProduct = '%ASSEMBLY.PRODUCT%';
/**
* Assembly's Copyright Property
*/
const AssemblyCopyright = '%ASSEMBLY.COPYRIGHT%';
/**
* Assembly's Trademark Property
*/
const AssemblyTrademark = '%ASSEMBLY.TRADEMARK%';
/**
* Assembly's Version Property
*/
const AssemblyVersion = '%ASSEMBLY.VERSION%';
/**
* Assembly's UUID property
*/
const AssemblyUid = '%ASSEMBLY.UID%';
}

View file

@ -0,0 +1,26 @@
<?php
namespace ncc\Abstracts\SpecialConstants;
abstract class BuildConstants
{
/**
* The Unix Timestamp for when the package was compiled
*/
const CompileTimestamp = '%COMPILE_TIMESTAMP%';
/**
* The version of NCC that was used to compile the package
*/
const NccBuildVersion = '%NCC_BUILD_VERSION%';
/**
* NCC Build Flags exploded into spaces
*/
const NccBuildFlags = '%NCC_BUILD_FLAGS%';
/**
* NCC Build Branch
*/
const NccBuildBranch = '%NCC_BUILD_BRANCH%';
}

View file

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

View file

@ -0,0 +1,14 @@
<?php
namespace ncc\Abstracts\SpecialConstants;
abstract class InstallConstants
{
const InstallationPath = '%INSTALL_PATH%';
const BinPath = '%INSTALL_PATH.BIN%';
const SourcePath = '%INSTALL_PATH.SRC%';
const DataPath = '%INSTALL_PATH.DATA%';
}

View file

@ -0,0 +1,8 @@
<?php
namespace ncc\Abstracts\SpecialConstants;
abstract class RuntimeConstants
{
const CWD = '%CWD%';
}

View file

@ -1,32 +0,0 @@
<?php
namespace ncc\Abstracts;
abstract class SpecialFormat
{
const AssemblyName = '%ASSEMBLY.NAME%';
const AssemblyPackage = '%ASSEMBLY.PACKAGE%';
const AssemblyDescription = '%ASSEMBLY.DESCRIPTION%';
const AssemblyCompany = '%ASSEMBLY.COMPANY%';
const AssemblyProduct = '%ASSEMBLY.PRODUCT%';
const AssemblyCopyright = '%ASSEMBLY.COPYRIGHT%';
const AssemblyTrademark = '%ASSEMBLY.TRADEMARK%';
const AssemblyVersion = '%ASSEMBLY.VERSION%';
const AssemblyUid = '%ASSEMBLY.UID%';
const CompileTimestamp = '%COMPILE_TIMESTAMP%';
const NccBuildVersion = '%NCC_BUILD_VERSION%';
const NccBuildArgs = '%NCC_BUILD_FLAGS%';
const NccBuildBranch = '%NCC_BUILD_BRANCH%';
}

View file

@ -13,4 +13,9 @@
* The current version of the package structure file format * The current version of the package structure file format
*/ */
const PackageStructureVersion = '1.0'; const PackageStructureVersion = '1.0';
/**
* The current version of the package lock structure file format
*/
const PackageLockVersion = '1.0.0';
} }

View file

@ -3,16 +3,9 @@
namespace ncc\CLI; namespace ncc\CLI;
use Exception; use Exception;
use JetBrains\PhpStorm\NoReturn;
use ncc\Abstracts\CompilerExtensions;
use ncc\Abstracts\Options\BuildConfigurationValues; use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Classes\PhpExtension\Compiler; use ncc\Managers\ProjectManager;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\MalformedJsonException;
use ncc\Interfaces\CompilerInterface;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Objects\ProjectConfiguration;
use ncc\Utilities\Console; use ncc\Utilities\Console;
class BuildMenu class BuildMenu
@ -22,8 +15,9 @@
* *
* @param $args * @param $args
* @return void * @return void
* @noinspection PhpNoReturnAttributeCanBeAddedInspection
*/ */
#[NoReturn] public static function start($args): void public static function start($args): void
{ {
if(isset($args['help'])) if(isset($args['help']))
{ {
@ -48,12 +42,6 @@
{ {
$path_arg = ($args['path'] ?? $args['p']); $path_arg = ($args['path'] ?? $args['p']);
// Append trailing slash
if(substr($path_arg, -1) !== DIRECTORY_SEPARATOR)
{
$path_arg .= DIRECTORY_SEPARATOR;
}
// Check if the path exists // Check if the path exists
if(!file_exists($path_arg) || !is_dir($path_arg)) if(!file_exists($path_arg) || !is_dir($path_arg))
{ {
@ -67,93 +55,39 @@
$project_path = getcwd(); $project_path = getcwd();
} }
// Load the project
try try
{ {
$ProjectConfiguration = ProjectConfiguration::fromFile($project_path . DIRECTORY_SEPARATOR . 'project.json'); $ProjectManager = new ProjectManager($project_path);
$ProjectManager->load();
} }
catch (FileNotFoundException $e) catch (Exception $e)
{ {
Console::outException('Cannot find the file \'project.json\'', $e, 1); Console::outException('Failed to load Project Configuration (project.json)', $e, 1);
return;
}
catch (MalformedJsonException $e)
{
Console::outException('The file \'project.json\' contains malformed json data, please verify the syntax of the file', $e, 1);
return; return;
} }
// Build the project
// Select the correct compiler for the specified extension try
switch(strtolower($ProjectConfiguration->Project->Compiler->Extension))
{ {
case CompilerExtensions::PHP:
/** @var CompilerInterface $Compiler */
$Compiler = new Compiler($ProjectConfiguration);
break;
default:
Console::outError('The extension '. $ProjectConfiguration->Project->Compiler->Extension . ' is not supported', true, 1);
return;
}
$build_configuration = BuildConfigurationValues::DefaultConfiguration; $build_configuration = BuildConfigurationValues::DefaultConfiguration;
if(isset($args['config'])) if(isset($args['config']))
{ {
$build_configuration = $args['config']; $build_configuration = $args['config'];
} }
// Auto-resolve to the default configuration if `default` is used or not specified $output = $ProjectManager->build($build_configuration);
if($build_configuration == BuildConfigurationValues::DefaultConfiguration)
{
$build_configuration = $ProjectConfiguration->Build->DefaultConfiguration;
}
try
{
$ProjectConfiguration->Build->getBuildConfiguration($build_configuration);
}
catch (BuildConfigurationNotFoundException $e)
{
Console::outException('The build configuration \'' . $build_configuration . '\' does not exist in the project configuration', $e, 1);
return;
}
Console::out(
' ===== BUILD INFO ===== ' . PHP_EOL .
' Package Name: ' . $ProjectConfiguration->Assembly->Package . PHP_EOL .
' Version: ' . $ProjectConfiguration->Assembly->Version . PHP_EOL .
' Compiler Extension: ' . $ProjectConfiguration->Project->Compiler->Extension . PHP_EOL .
' Compiler Version: ' . $ProjectConfiguration->Project->Compiler->MaximumVersion . ' - ' . $ProjectConfiguration->Project->Compiler->MinimumVersion . PHP_EOL .
' Build Configuration: ' . $build_configuration . PHP_EOL
);
Console::out('Preparing package');
try
{
$Compiler->prepare($project_path, $build_configuration);
}
catch (Exception $e)
{
Console::outException('The package preparation process failed', $e, 1);
return;
}
Console::out('Compiling package');
try
{
$Compiler->build($project_path);
}
catch (Exception $e)
{
Console::outException('Build Failed', $e, 1);
return;
}
Console::out('Successfully built ' . $output);
exit(0); exit(0);
} }
catch (Exception $e)
{
Console::outException('Failed to build project', $e, 1);
return;
}
}
/** /**
* Displays the main options section * Displays the main options section

View file

@ -1,31 +0,0 @@
<?php
namespace ncc\CLI;
class Functions
{
/**
* Simple print function with builtin EOL terminator
*
* @param string $out
* @param bool $eol
* @param int $padding
* @param int $pad_type
* @param string $pad_string
* @return void
*/
public static function print(string $out, bool $eol=true, int $padding=0, int $pad_type=0, string $pad_string=' ')
{
if($padding > 0)
{
$out = str_pad($out, $padding, $pad_string, $pad_type);
}
if($eol)
{
$out = $out . PHP_EOL;
}
print($out);
}
}

View file

@ -1,8 +1,11 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\CLI; namespace ncc\CLI;
use Exception; use Exception;
use ncc\Abstracts\LogLevel;
use ncc\Abstracts\NccBuildFlags; use ncc\Abstracts\NccBuildFlags;
use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\RuntimeException; use ncc\Exceptions\RuntimeException;
@ -12,6 +15,16 @@
class Main class Main
{ {
/**
* @var array
*/
private static $args;
/**
* @var string|null
*/
private static $log_level;
/** /**
* Executes the main CLI process * Executes the main CLI process
* *
@ -20,9 +33,9 @@
*/ */
public static function start($argv): void public static function start($argv): void
{ {
$args = Resolver::parseArguments(implode(' ', $argv)); self::$args = Resolver::parseArguments(implode(' ', $argv));
if(isset($args['ncc-cli'])) if(isset(self::$args['ncc-cli']))
{ {
// Initialize NCC // Initialize NCC
try try
@ -41,6 +54,38 @@
// Define CLI stuff // Define CLI stuff
define('NCC_CLI_MODE', 1); define('NCC_CLI_MODE', 1);
if(isset(self::$args['l']) || isset(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
{
self::$log_level = LogLevel::Info;
}
if(Resolver::checkLogLevel(self::$log_level, LogLevel::Debug))
{
Console::outDebug('Debug logging enabled');
Console::outDebug(sprintf('consts: %s', json_encode(ncc::getConstants(), JSON_UNESCAPED_SLASHES)));
Console::outDebug(sprintf('args: %s', json_encode(self::$args, JSON_UNESCAPED_SLASHES)));
}
if(in_array(NccBuildFlags::Unstable, NCC_VERSION_FLAGS)) if(in_array(NccBuildFlags::Unstable, NCC_VERSION_FLAGS))
{ {
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');
@ -48,37 +93,59 @@
try try
{ {
switch(strtolower($args['ncc-cli'])) switch(strtolower(self::$args['ncc-cli']))
{ {
default: default:
Console::out('Unknown command ' . strtolower($args['ncc-cli'])); Console::out('Unknown command ' . strtolower(self::$args['ncc-cli']));
exit(1); exit(1);
case 'project': case 'project':
ProjectMenu::start($args); ProjectMenu::start(self::$args);
exit(0); exit(0);
case 'build': case 'build':
BuildMenu::start($args); BuildMenu::start(self::$args);
exit(0); exit(0);
case 'credential': case 'credential':
CredentialMenu::start($args); CredentialMenu::start(self::$args);
exit(0);
case 'package':
PackageManagerMenu::start(self::$args);
exit(0); exit(0);
case '1': case '1':
case 'help': case 'help':
HelpMenu::start($args); HelpMenu::start(self::$args);
exit(0); exit(0);
} }
} }
catch(Exception $e) catch(Exception $e)
{ {
Console::outException('Error: ' . $e->getMessage() . ' (Code: ' . $e->getCode() . ')', $e, 1); Console::outException($e->getMessage() . ' (Code: ' . $e->getCode() . ')', $e, 1);
exit(1); exit(1);
} }
} }
} }
/**
* @return mixed
*/
public static function getArgs()
{
return self::$args;
}
/**
* @return string
*/
public static function getLogLevel(): string
{
if(self::$log_level == null)
self::$log_level = LogLevel::Info;
return self::$log_level;
}
} }

View file

@ -0,0 +1,345 @@
<?php
namespace ncc\CLI;
use Exception;
use ncc\Abstracts\ConsoleColors;
use ncc\Abstracts\Scopes;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\PackageLockException;
use ncc\Exceptions\VersionNotFoundException;
use ncc\Managers\PackageManager;
use ncc\Objects\CliHelpSection;
use ncc\Objects\Package;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\Utilities\Resolver;
class PackageManagerMenu
{
/**
* Displays the main help menu
*
* @param $args
* @return void
*/
public static function start($args): void
{
if(isset($args['install']))
{
try
{
self::installPackage($args);
return;
}
catch (Exception $e)
{
Console::outException('Installation Failed', $e, 1);
return;
}
}
if(isset($args['uninstall']))
{
try
{
self::uninstallPackage($args);
return;
}
catch (Exception $e)
{
Console::outException('Uninstallation Failed', $e, 1);
return;
}
}
if(isset($args['list']))
{
try
{
self::getInstallPackages();
return;
}
catch(Exception $e)
{
Console::outException('List Failed', $e, 1);
return;
}
}
self::displayOptions();
exit(0);
}
/**
* Displays all installed packages
*
* @return void
*/
private static function getInstallPackages(): void
{
$package_manager = new PackageManager();
try
{
$installed_packages = $package_manager->getInstalledPackages();
}
catch (Exception $e)
{
unset($e);
Console::out('No packages installed');
exit(0);
}
foreach($installed_packages as $package => $versions)
{
if(count($versions) == 0)
{
continue;
}
foreach($versions as $version)
{
try
{
$package_version = $package_manager->getPackageVersion($package, $version);
if($package_version == null)
throw new Exception();
Console::out(sprintf('%s==%s (%s)',
Console::formatColor($package, ConsoleColors::LightGreen),
Console::formatColor($version, ConsoleColors::LightMagenta),
$package_manager->getPackageVersion($package, $version)->Compiler->Extension
));
}
catch(Exception $e)
{
unset($e);
Console::out(sprintf('%s==%s',
Console::formatColor($package, ConsoleColors::LightGreen),
Console::formatColor($version, ConsoleColors::LightMagenta)
));
}
}
}
}
/**
* @param $args
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
*/
private static function installPackage($args): void
{
$path = ($args['path'] ?? $args['p']);
$package_manager = new PackageManager();
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Insufficient permission to install packages');
if(!file_exists($path) || !is_file($path) || !is_readable($path))
throw new FileNotFoundException('The specified file \'' . $path .' \' does not exist or is not readable.');
$user_confirmation = false;
if(isset($args['y']) || isset($args['Y']))
{
$user_confirmation = (bool)($args['y'] ?? $args['Y']);
}
try
{
$package = Package::load($path);
}
catch(Exception $e)
{
Console::outException('Error while loading package', $e, 1);
return;
}
Console::out('Package installation details' . PHP_EOL);
if(!is_null($package->Assembly->UUID))
Console::out(' UUID: ' . Console::formatColor($package->Assembly->UUID, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Package))
Console::out(' Package: ' . Console::formatColor($package->Assembly->Package, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Name))
Console::out(' Name: ' . Console::formatColor($package->Assembly->Name, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Version))
Console::out(' Version: ' . Console::formatColor($package->Assembly->Version, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Description))
Console::out(' Description: ' . Console::formatColor($package->Assembly->Description, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Product))
Console::out(' Product: ' . Console::formatColor($package->Assembly->Product, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Company))
Console::out(' Company: ' . Console::formatColor($package->Assembly->Company, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Copyright))
Console::out(' Copyright: ' . Console::formatColor($package->Assembly->Copyright, ConsoleColors::LightGreen));
if(!is_null($package->Assembly->Trademark))
Console::out(' Trademark: ' . Console::formatColor($package->Assembly->Trademark, ConsoleColors::LightGreen));
Console::out((string)null);
if(count($package->Dependencies) > 0)
{
$dependencies = [];
foreach($package->Dependencies as $dependency)
{
$dependencies[] = sprintf('%s v%s',
Console::formatColor($dependency->Name, ConsoleColors::Green),
Console::formatColor($dependency->Version, ConsoleColors::LightMagenta)
);
}
Console::out('The following dependencies will be installed:');
Console::out(sprintf(' %s', implode(', ', $dependencies)) . PHP_EOL);
}
Console::out(sprintf('Extension: %s',
Console::formatColor($package->Header->CompilerExtension->Extension, ConsoleColors::Green)
));
if($package->Header->CompilerExtension->MaximumVersion !== null)
Console::out(sprintf('Maximum Version: %s',
Console::formatColor($package->Header->CompilerExtension->MaximumVersion, ConsoleColors::LightMagenta)
));
if($package->Header->CompilerExtension->MinimumVersion !== null)
Console::out(sprintf('Minimum Version: %s',
Console::formatColor($package->Header->CompilerExtension->MinimumVersion, ConsoleColors::LightMagenta)
));
if(!$user_confirmation)
$user_confirmation = Console::getBooleanInput(sprintf('Do you want to install %s', $package->Assembly->Package));
if($user_confirmation)
{
try
{
$package_manager->install($path);
}
catch(Exception $e)
{
Console::outException('Installation Failed', $e, 1);
}
return;
}
Console::outError('User cancelled installation', true, 1);
}
/**
* Uninstalls a version of a package or all versions of a package
*
* @param $args
* @return void
* @throws VersionNotFoundException
*/
private static function uninstallPackage($args): void
{
$selected_package = ($args['package'] ?? $args['pkg']);
$selected_version = null;
if(isset($args['v']))
$selected_version = $args['v'];
if(isset($args['version']))
$selected_version = $args['version'];
$user_confirmation = null;
// For undefined array key warnings
if(isset($args['y']) || isset($args['Y']))
$user_confirmation = (bool)($args['y'] ?? $args['Y']);
if($selected_package == null)
Console::outError('Missing argument \'package\'', true, 1);
$package_manager = new PackageManager();
try
{
$package_entry = $package_manager->getPackage($selected_package);
}
catch (PackageLockException $e)
{
Console::outException('PackageLock error', $e, 1);
return;
}
$version_entry = null;
if($version_entry !== null && $package_entry !== null)
/** @noinspection PhpUnhandledExceptionInspection */
/** @noinspection PhpRedundantOptionalArgumentInspection */
$version_entry = $package_entry->getVersion($version_entry, false);
if($package_entry == null)
{
Console::outError(sprintf('Package "%s" is not installed', $selected_package), true, 1);
return;
}
if($version_entry == null & $selected_version !== null)
{
Console::outError(sprintf('Package "%s==%s" is not installed', $selected_package, $selected_version), true, 1);
return;
}
if($user_confirmation == null)
{
if($selected_version !== null)
{
if(!Console::getBooleanInput(sprintf('Do you want to uninstall %s==%s', $selected_package, $selected_version)))
{
Console::outError('User cancelled operation', true, 1);
return;
}
}
else
{
if(!Console::getBooleanInput(sprintf('Do you want to uninstall all versions of %s', $selected_package)))
{
Console::outError('User cancelled operation', true, 1);
return;
}
}
}
try
{
if($selected_version !== null)
{
$package_manager->uninstallPackageVersion($selected_package, $selected_version);
}
else
{
$package_manager->uninstallPackage($selected_package);
}
}
catch(Exception $e)
{
Console::outException('Uninstallation failed', $e, 1);
return;
}
}
/**
* Displays the main options section
*
* @return void
*/
private static function displayOptions(): void
{
$options = [
new CliHelpSection(['help'], 'Displays this help menu about the value command'),
new CliHelpSection(['install', '--path', '-p'], 'Installs a specified NCC package file'),
new CliHelpSection(['list'], 'Lists all installed packages on the system'),
];
$options_padding = Functions::detectParametersPadding($options) + 4;
Console::out('Usage: ncc install {command} [options]');
Console::out('Options:' . PHP_EOL);
foreach($options as $option)
{
Console::out(' ' . $option->toString($options_padding));
}
}
}

View file

@ -0,0 +1,129 @@
<?php
namespace ncc\Classes\NccExtension;
use ncc\Abstracts\SpecialConstants\BuildConstants;
use ncc\Abstracts\SpecialConstants\DateTimeConstants;
use ncc\Abstracts\SpecialConstants\InstallConstants;
use ncc\Abstracts\SpecialConstants\AssemblyConstants;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration;
use ncc\Objects\ProjectConfiguration\Assembly;
class ConstantCompiler
{
/**
* Compiles assembly constants about the project (Usually used during compiling time)
*
* @param string|null $input
* @param Assembly $assembly
* @return string|null
* @noinspection PhpUnnecessaryLocalVariableInspection
*/
public static function compileAssemblyConstants(?string $input, Assembly $assembly): ?string
{
if($input == null)
return null;
$input = str_replace(AssemblyConstants::AssemblyName, $assembly->Name, $input);
$input = str_replace(AssemblyConstants::AssemblyPackage, $assembly->Package, $input);
$input = str_replace(AssemblyConstants::AssemblyDescription, $assembly->Description, $input);
$input = str_replace(AssemblyConstants::AssemblyCompany, $assembly->Company, $input);
$input = str_replace(AssemblyConstants::AssemblyProduct, $assembly->Product, $input);
$input = str_replace(AssemblyConstants::AssemblyCopyright, $assembly->Copyright, $input);
$input = str_replace(AssemblyConstants::AssemblyTrademark, $assembly->Trademark, $input);
$input = str_replace(AssemblyConstants::AssemblyVersion, $assembly->Version, $input);
$input = str_replace(AssemblyConstants::AssemblyUid, $assembly->UUID, $input);
return $input;
}
/**
* Compiles build constants about the NCC build (Usually used during compiling time)
*
* @param string|null $input
* @return string|null
* @noinspection PhpUnnecessaryLocalVariableInspection
*/
public static function compileBuildConstants(?string $input): ?string
{
if($input == null)
return null;
$input = str_replace(BuildConstants::CompileTimestamp, time(), $input);
$input = str_replace(BuildConstants::NccBuildVersion, NCC_VERSION_NUMBER, $input);
$input = str_replace(BuildConstants::NccBuildFlags, implode(' ', NCC_VERSION_FLAGS), $input);
$input = str_replace(BuildConstants::NccBuildBranch, NCC_VERSION_BRANCH, $input);
return $input;
}
/**
* Compiles installation constants (Usually used during compiling time)
*
* @param string|null $input
* @param InstallationPaths $installationPaths
* @return string|null
* @noinspection PhpUnnecessaryLocalVariableInspection
*/
public static function compileInstallConstants(?string $input, InstallationPaths $installationPaths): ?string
{
if($input == null)
return null;
$input = str_replace(InstallConstants::InstallationPath, $installationPaths->getInstallationPath(), $input);
$input = str_replace(InstallConstants::BinPath, $installationPaths->getBinPath(), $input);
$input = str_replace(InstallConstants::SourcePath, $installationPaths->getSourcePath(), $input);
$input = str_replace(InstallConstants::DataPath, $installationPaths->getDataPath(), $input);
return $input;
}
/**
* Compiles DateTime constants from a Unix Timestamp
*
* @param string|null $input
* @param int $timestamp
* @return string|null
* @noinspection PhpUnnecessaryLocalVariableInspection
*/
public static function compileDateTimeConstants(?string $input, int $timestamp): ?string
{
if($input == null)
return null;
$input = str_replace(DateTimeConstants::d, date('d', $timestamp), $input);
$input = str_replace(DateTimeConstants::D, date('D', $timestamp), $input);
$input = str_replace(DateTimeConstants::j, date('j', $timestamp), $input);
$input = str_replace(DateTimeConstants::l, date('l', $timestamp), $input);
$input = str_replace(DateTimeConstants::N, date('N', $timestamp), $input);
$input = str_replace(DateTimeConstants::S, date('S', $timestamp), $input);
$input = str_replace(DateTimeConstants::w, date('w', $timestamp), $input);
$input = str_replace(DateTimeConstants::z, date('z', $timestamp), $input);
$input = str_replace(DateTimeConstants::W, date('W', $timestamp), $input);
$input = str_replace(DateTimeConstants::F, date('F', $timestamp), $input);
$input = str_replace(DateTimeConstants::m, date('m', $timestamp), $input);
$input = str_replace(DateTimeConstants::M, date('M', $timestamp), $input);
$input = str_replace(DateTimeConstants::n, date('n', $timestamp), $input);
$input = str_replace(DateTimeConstants::t, date('t', $timestamp), $input);
$input = str_replace(DateTimeConstants::L, date('L', $timestamp), $input);
$input = str_replace(DateTimeConstants::o, date('o', $timestamp), $input);
$input = str_replace(DateTimeConstants::Y, date('Y', $timestamp), $input);
$input = str_replace(DateTimeConstants::y, date('y', $timestamp), $input);
$input = str_replace(DateTimeConstants::a, date('a', $timestamp), $input);
$input = str_replace(DateTimeConstants::A, date('A', $timestamp), $input);
$input = str_replace(DateTimeConstants::B, date('B', $timestamp), $input);
$input = str_replace(DateTimeConstants::g, date('g', $timestamp), $input);
$input = str_replace(DateTimeConstants::G, date('G', $timestamp), $input);
$input = str_replace(DateTimeConstants::h, date('h', $timestamp), $input);
$input = str_replace(DateTimeConstants::H, date('H', $timestamp), $input);
$input = str_replace(DateTimeConstants::i, date('i', $timestamp), $input);
$input = str_replace(DateTimeConstants::s, date('s', $timestamp), $input);
$input = str_replace(DateTimeConstants::c, date('c', $timestamp), $input);
$input = str_replace(DateTimeConstants::r, date('r', $timestamp), $input);
$input = str_replace(DateTimeConstants::u, date('u', $timestamp), $input);
return $input;
}
}

View file

@ -0,0 +1,307 @@
<?php
namespace ncc\Classes\NccExtension;
use Exception;
use ncc\Abstracts\CompilerExtensions;
use ncc\Abstracts\ConstantReferences;
use ncc\Abstracts\LogLevel;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Classes\PhpExtension\Compiler;
use ncc\CLI\Main;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\PackagePreparationFailedException;
use ncc\Exceptions\ProjectConfigurationNotFoundException;
use ncc\Exceptions\UnsupportedCompilerExtensionException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Interfaces\CompilerInterface;
use ncc\Managers\ProjectManager;
use ncc\ncc;
use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration;
use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\Utilities\Resolver;
class PackageCompiler
{
/**
* Compiles the project into a package
*
* @param ProjectManager $manager
* @param string $build_configuration
* @return string
* @throws AccessDeniedException
* @throws BuildConfigurationNotFoundException
* @throws BuildException
* @throws FileNotFoundException
* @throws IOException
* @throws MalformedJsonException
* @throws PackagePreparationFailedException
* @throws ProjectConfigurationNotFoundException
* @throws UnsupportedCompilerExtensionException
* @throws UnsupportedRunnerException
*/
public static function compile(ProjectManager $manager, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
{
$configuration = $manager->getProjectConfiguration();
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
{
foreach($configuration->Assembly->toArray() as $prop => $value)
Console::outDebug(sprintf('assembly.%s: %s', $prop, ($value ?? 'n/a')));
foreach($configuration->Project->Compiler->toArray() as $prop => $value)
Console::outDebug(sprintf('compiler.%s: %s', $prop, ($value ?? 'n/a')));
}
// Select the correct compiler for the specified extension
/** @noinspection PhpSwitchCanBeReplacedWithMatchExpressionInspection */
switch(strtolower($configuration->Project->Compiler->Extension))
{
case CompilerExtensions::PHP:
/** @var CompilerInterface $Compiler */
$Compiler = new Compiler($configuration, $manager->getProjectPath());
break;
default:
throw new UnsupportedCompilerExtensionException('The compiler extension \'' . $configuration->Project->Compiler->Extension . '\' is not supported');
}
$build_configuration = $configuration->Build->getBuildConfiguration($build_configuration)->Name;
$Compiler->prepare($build_configuration);
$Compiler->build();
return PackageCompiler::writePackage(
$manager->getProjectPath(), $Compiler->getPackage(), $configuration, $build_configuration
);
}
/**
* Compiles the execution policies of the package
*
* @param string $path
* @param ProjectConfiguration $configuration
* @return array
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
*/
public static function compileExecutionPolicies(string $path, ProjectConfiguration $configuration): array
{
if(count($configuration->ExecutionPolicies) == 0)
return [];
Console::out('Compiling Execution Policies');
$total_items = count($configuration->ExecutionPolicies);
$execution_units = [];
$processed_items = 0;
/** @var ProjectConfiguration\ExecutionPolicy $policy */
foreach($configuration->ExecutionPolicies as $policy)
{
if($total_items > 5)
{
Console::inlineProgressBar($processed_items, $total_items);
}
$unit_path = Functions::correctDirectorySeparator($path . $policy->Execute->Target);
$execution_units[] = Functions::compileRunner($unit_path, $policy);
}
if(ncc::cliMode() && $total_items > 5)
print(PHP_EOL);
return $execution_units;
}
/**
* Writes the finished package to disk, returns the output path
*
* @param string $path
* @param Package $package
* @param ProjectConfiguration $configuration
* @param string $build_configuration
* @return string
* @throws BuildConfigurationNotFoundException
* @throws BuildException
* @throws IOException
*/
public static function writePackage(string $path, Package $package, ProjectConfiguration $configuration, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
{
// Write the package to disk
$FileSystem = new Filesystem();
$BuildConfiguration = $configuration->Build->getBuildConfiguration($build_configuration);
if($FileSystem->exists($path . $BuildConfiguration->OutputPath))
{
try
{
$FileSystem->remove($path . $BuildConfiguration->OutputPath);
}
catch(\ncc\ThirdParty\Symfony\Filesystem\Exception\IOException $e)
{
throw new BuildException('Cannot delete directory \'' . $path . $BuildConfiguration->OutputPath . '\', ' . $e->getMessage(), $e);
}
}
// Finally write the package to the disk
$FileSystem->mkdir($path . $BuildConfiguration->OutputPath);
$output_file = $path . $BuildConfiguration->OutputPath . DIRECTORY_SEPARATOR . $package->Assembly->Package . '.ncc';
$FileSystem->touch($output_file);
try
{
$package->save($output_file);
}
catch(Exception $e)
{
throw new IOException('Cannot write to output file', $e);
}
return $output_file;
}
/**
* Compiles the special formatted constants
*
* @param Package $package
* @param int $timestamp
* @return array
*/
public static function compileRuntimeConstants(Package $package, int $timestamp): array
{
$compiled_constants = [];
foreach($package->Header->RuntimeConstants as $name => $value)
{
$compiled_constants[$name] = self::compileConstants($value, [
ConstantReferences::Assembly => $package->Assembly,
ConstantReferences::DateTime => $timestamp,
ConstantReferences::Build => null
]);
}
return $compiled_constants;
}
/**
* Compiles the constants in the package object
*
* @param Package $package
* @param array $refs
* @return void
*/
public static function compilePackageConstants(Package &$package, array $refs): void
{
if($package->Assembly !== null)
{
$assembly = [];
foreach($package->Assembly->toArray() as $key => $value)
{
$assembly[$key] = self::compileConstants($value, $refs);
}
$package->Assembly = Assembly::fromArray($assembly);
unset($assembly);
}
if($package->ExecutionUnits !== null && count($package->ExecutionUnits) > 0)
{
$units = [];
foreach($package->ExecutionUnits as $executionUnit)
{
$units[] = self::compileExecutionUnitConstants($executionUnit, $refs);
}
$package->ExecutionUnits = $units;
unset($units);
}
}
/**
* Compiles the constants in a given execution unit
*
* @param Package\ExecutionUnit $unit
* @param array $refs
* @return Package\ExecutionUnit
*/
public static function compileExecutionUnitConstants(Package\ExecutionUnit $unit, array $refs): Package\ExecutionUnit
{
$unit->ExecutionPolicy->Message = self::compileConstants($unit->ExecutionPolicy->Message, $refs);
if($unit->ExecutionPolicy->ExitHandlers !== null)
{
if($unit->ExecutionPolicy->ExitHandlers->Success !== null)
{
$unit->ExecutionPolicy->ExitHandlers->Success->Message = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Success->Message, $refs);
}
if($unit->ExecutionPolicy->ExitHandlers->Error !== null)
{
$unit->ExecutionPolicy->ExitHandlers->Error->Message = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Error->Message, $refs);
}
if($unit->ExecutionPolicy->ExitHandlers->Warning !== null)
{
$unit->ExecutionPolicy->ExitHandlers->Warning->Error = self::compileConstants($unit->ExecutionPolicy->ExitHandlers->Warning->Message, $refs);
}
}
if($unit->ExecutionPolicy->Execute !== null)
{
if($unit->ExecutionPolicy->Execute->Target !== null)
{
$unit->ExecutionPolicy->Execute->Target = self::compileConstants($unit->ExecutionPolicy->Execute->Target, $refs);
}
if($unit->ExecutionPolicy->Execute->WorkingDirectory !== null)
{
$unit->ExecutionPolicy->Execute->WorkingDirectory = self::compileConstants($unit->ExecutionPolicy->Execute->WorkingDirectory, $refs);
}
if($unit->ExecutionPolicy->Execute->Options !== null && count($unit->ExecutionPolicy->Execute->Options) > 0)
{
$options = [];
foreach($unit->ExecutionPolicy->Execute->Options as $key=>$value)
{
$options[self::compileConstants($key, $refs)] = self::compileConstants($value, $refs);
}
$unit->ExecutionPolicy->Execute->Options = $options;
}
}
return $unit;
}
/**
* Compiles multiple types of constants
*
* @param string|null $value
* @param array $refs
* @return string|null
*/
public static function compileConstants(?string $value, array $refs): ?string
{
if($value == null)
return null;
if(isset($refs[ConstantReferences::Assembly]))
$value = ConstantCompiler::compileAssemblyConstants($value, $refs[ConstantReferences::Assembly]);
if(isset($refs[ConstantReferences::Build]))
$value = ConstantCompiler::compileBuildConstants($value);
if(isset($refs[ConstantReferences::DateTime]))
$value = ConstantCompiler::compileDateTimeConstants($value, $refs[ConstantReferences::DateTime]);
if(isset($refs[ConstantReferences::Install]))
$value = ConstantCompiler::compileInstallConstants($value, $refs[ConstantReferences::Install]);
return $value;
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace ncc\Classes\NccExtension;
use ncc\Abstracts\Runners;
use ncc\Abstracts\Scopes;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\ExecutionUnitNotFoundException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NoAvailableUnitsException;
use ncc\Exceptions\RunnerExecutionException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Managers\ExecutionPointerManager;
use ncc\Objects\ExecutionPointers\ExecutionPointer;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver;
class Runner
{
/**
* Temporarily executes an execution unit, removes it once it is executed
*
* @param string $package
* @param string $version
* @param ExecutionUnit $unit
* @return void
* @throws AccessDeniedException
* @throws UnsupportedRunnerException
* @throws ExecutionUnitNotFoundException
* @throws FileNotFoundException
* @throws IOException
* @throws NoAvailableUnitsException
* @throws RunnerExecutionException
*/
public static function temporaryExecute(string $package, string $version, ExecutionUnit $unit)
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Cannot temporarily execute a unit with insufficent permissions');
$ExecutionPointerManager = new ExecutionPointerManager();
$ExecutionPointerManager->addUnit($package, $version, $unit, true);
$ExecutionPointerManager->executeUnit($package, $version, $unit->ExecutionPolicy->Name);
$ExecutionPointerManager->cleanTemporaryUnits();;
}
}

View file

@ -1,42 +0,0 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Classes;
use ncc\Exceptions\FileNotFoundException;
class PackageParser
{
/**
* @var string
*/
private $PackagePath;
/**
* Package Parser public constructor.
*
* @param string $path
*/
public function __construct(string $path)
{
$this->PackagePath = $path;
$this->parseFile();
}
private function parseFile()
{
if(file_exists($this->PackagePath) == false)
{
throw new FileNotFoundException('The given package path \'' . $this->PackagePath . '\' does not exist');
}
if(is_file($this->PackagePath) == false)
{
throw new FileNotFoundException('The given package path \'' . $this->PackagePath . '\' is not a file');
}
$file_handler = fopen($this->PackagePath, 'rb');
$header = fread($file_handler, 14);
}
}

View file

@ -1,120 +0,0 @@
<?php
namespace ncc\Classes\PhpExtension;
use ArrayIterator;
use ncc\Abstracts\ComponentFileExtensions;
use ncc\Exceptions\AutoloadGeneratorException;
use ncc\Exceptions\NoUnitsFoundException;
use ncc\Objects\ProjectConfiguration;
use ncc\ThirdParty\theseer\Autoload\CollectorException;
use ncc\ThirdParty\theseer\Autoload\CollectorResult;
use ncc\ThirdParty\theseer\Autoload\Config;
use ncc\ThirdParty\theseer\Autoload\Factory;
use ncc\ThirdParty\theseer\DirectoryScanner\Exception;
use ncc\Utilities\Console;
use SplFileInfo;
class AutoloaderGenerator
{
/**
* @var ProjectConfiguration
*/
private ProjectConfiguration $project;
/**
* @param ProjectConfiguration $project
*/
public function __construct(ProjectConfiguration $project)
{
$this->project = $project;
}
/**
* Processes the project and generates the autoloader source code.
*
* @param string $src
* @param string $output
* @param bool $static
* @return string
* @throws AutoloadGeneratorException
* @throws CollectorException
* @throws Exception
* @throws NoUnitsFoundException
*/
public function generateAutoload(string $src, string $output, bool $static=false): string
{
// Construct configuration
$configuration = new Config([$src]);
$configuration->setFollowSymlinks(false); // Don't follow symlinks, it won't work on some systems.
$configuration->setOutputFile($output);
$configuration->setTrusting(false); // Paranoid
// Official PHP file extensions that are missing from the default configuration (whatever)
$configuration->setInclude(ComponentFileExtensions::Php);
// Construct factory
$factory = new Factory();
$factory->setConfig($configuration);
// Create Collector
$result = self::runCollector($factory, $configuration);
// Exception raises when there are no files in the project that can be processed by the autoloader
if(!$result->hasUnits())
{
throw new NoUnitsFoundException('No units were found in the project');
}
if(!$result->hasDuplicates())
{
foreach($result->getDuplicates() as $unit => $files)
{
Console::outWarning((count($files) -1). ' duplicate unit(s) detected in the project: ' . $unit);
}
}
$template = @file_get_contents($configuration->getTemplate());
if ($template === false)
{
throw new AutoloadGeneratorException("Failed to read the template file '" . $configuration->getTemplate() . "'");
}
$builder = $factory->getRenderer($result);
return $builder->render($template);
}
/**
* Iterates through the target directories through the collector and returns the collector results.
*
* @param Factory $factory
* @param Config $config
* @return CollectorResult
* @throws CollectorException
* @throws Exception
*/
private static function runCollector(Factory $factory, Config $config): CollectorResult
{
$collector = $factory->getCollector();
foreach($config->getDirectories() as $directory)
{
if(is_dir($directory))
{
$scanner = $factory->getScanner()->getIterator($directory);
$collector->processDirectory($scanner);
unset($scanner);
}
else
{
$file = new SplFileInfo($directory);
$filter = $factory->getFilter(new ArrayIterator(array($file)));
foreach($filter as $file)
{
$collector->processFile($file);
}
}
}
return $collector->getResult();
}
}

View file

@ -8,22 +8,26 @@
use FilesystemIterator; use FilesystemIterator;
use ncc\Abstracts\ComponentFileExtensions; use ncc\Abstracts\ComponentFileExtensions;
use ncc\Abstracts\ComponentDataType; use ncc\Abstracts\ComponentDataType;
use ncc\Abstracts\ConstantReferences;
use ncc\Abstracts\Options\BuildConfigurationValues; use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Classes\NccExtension\PackageCompiler;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\BuildConfigurationNotFoundException; use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException; use ncc\Exceptions\BuildException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PackagePreparationFailedException; use ncc\Exceptions\PackagePreparationFailedException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Interfaces\CompilerInterface; use ncc\Interfaces\CompilerInterface;
use ncc\ncc; use ncc\ncc;
use ncc\Objects\Package; use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration; use ncc\Objects\ProjectConfiguration;
use ncc\ThirdParty\nikic\PhpParser\Error;
use ncc\ThirdParty\nikic\PhpParser\ParserFactory; use ncc\ThirdParty\nikic\PhpParser\ParserFactory;
use ncc\ThirdParty\Symfony\Filesystem\Exception\IOException;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner; use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
use ncc\Utilities\Base64; use ncc\Utilities\Base64;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO;
use SplFileInfo; use SplFileInfo;
class Compiler implements CompilerInterface class Compiler implements CompilerInterface
@ -39,28 +43,30 @@
private $package; private $package;
/** /**
* @var ProjectConfiguration\BuildConfiguration|null * @var string
*/ */
private $selected_build_configuration; private $path;
/** /**
* @param ProjectConfiguration $project * @param ProjectConfiguration $project
* @param string $path
*/ */
public function __construct(ProjectConfiguration $project) public function __construct(ProjectConfiguration $project, string $path)
{ {
$this->project = $project; $this->project = $project;
$this->path = $path;
} }
/** /**
* Prepares the PHP package by generating the Autoloader and detecting all components & resources * Prepares the PHP package by generating the Autoloader and detecting all components & resources
* This function must be called before calling the build function, otherwise the operation will fail * This function must be called before calling the build function, otherwise the operation will fail
* *
* @param string $path
* @param string $build_configuration * @param string $build_configuration
* @return void * @return void
* @throws PackagePreparationFailedException * @throws PackagePreparationFailedException
* @throws BuildConfigurationNotFoundException
*/ */
public function prepare(string $path, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void public function prepare(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void
{ {
try try
{ {
@ -72,40 +78,29 @@
throw new PackagePreparationFailedException($e->getMessage(), $e); throw new PackagePreparationFailedException($e->getMessage(), $e);
} }
// Auto-select the default build configuration
if($build_configuration == BuildConfigurationValues::DefaultConfiguration)
{
$build_configuration = $this->project->Build->DefaultConfiguration;
}
// Select the build configuration // Select the build configuration
try $selected_build_configuration = $this->project->Build->getBuildConfiguration($build_configuration);
{
$this->selected_build_configuration = $this->project->Build->getBuildConfiguration($build_configuration);
}
catch (BuildConfigurationNotFoundException $e)
{
throw new PackagePreparationFailedException($e->getMessage(), $e);
}
// Create the package object // Create the package object
$this->package = new Package(); $this->package = new Package();
$this->package->Assembly = $this->project->Assembly; $this->package->Assembly = $this->project->Assembly;
$this->package->Dependencies = $this->project->Build->Dependencies; $this->package->Dependencies = $this->project->Build->Dependencies;
$this->package->MainExecutionPolicy = $this->project->Build->Main;
// Add both the defined constants from the build configuration and the global constants. // Add both the defined constants from the build configuration and the global constants.
// Global constants are overridden // Global constants are overridden
$this->package->Header->RuntimeConstants = array_merge($this->selected_build_configuration->DefineConstants, $this->package->Header->RuntimeConstants); $this->package->Header->RuntimeConstants = [];
$this->package->Header->RuntimeConstants = array_merge($this->project->Build->DefineConstants, $this->package->Header->RuntimeConstants); $this->package->Header->RuntimeConstants = array_merge(
$selected_build_configuration->DefineConstants,
$this->project->Build->DefineConstants,
$this->package->Header->RuntimeConstants
);
$this->package->Header->CompilerExtension = $this->project->Project->Compiler; $this->package->Header->CompilerExtension = $this->project->Project->Compiler;
$this->package->Header->CompilerVersion = NCC_VERSION_NUMBER; $this->package->Header->CompilerVersion = NCC_VERSION_NUMBER;
if(ncc::cliMode())
{
Console::out('Scanning project files'); Console::out('Scanning project files');
Console::out('theseer\DirectoryScanner - Copyright (c) 2009-2014 Arne Blankerts <arne@blankerts.de> All rights reserved.'); Console::out('theseer\DirectoryScanner - Copyright (c) 2009-2014 Arne Blankerts <arne@blankerts.de> All rights reserved.');
}
// First scan the project files and create a file struct. // First scan the project files and create a file struct.
$DirectoryScanner = new DirectoryScanner(); $DirectoryScanner = new DirectoryScanner();
@ -121,18 +116,12 @@
// Include file components that can be compiled // Include file components that can be compiled
$DirectoryScanner->setIncludes(ComponentFileExtensions::Php); $DirectoryScanner->setIncludes(ComponentFileExtensions::Php);
$DirectoryScanner->setExcludes($this->selected_build_configuration->ExcludeFiles); $DirectoryScanner->setExcludes($selected_build_configuration->ExcludeFiles);
$source_path = $this->path . $this->project->Build->SourcePath;
// Append trailing slash to the end of the path if it's not already there
if(substr($path, -1) !== DIRECTORY_SEPARATOR)
{
$path .= DIRECTORY_SEPARATOR;
}
$source_path = $path . $this->project->Build->SourcePath;
// TODO: Re-implement the scanning process outside the compiler, as this is will be redundant
// Scan for components first. // Scan for components first.
Console::out('Scanning for components... ', false); Console::out('Scanning for components... ');
/** @var SplFileInfo $item */ /** @var SplFileInfo $item */
/** @noinspection PhpRedundantOptionalArgumentInspection */ /** @noinspection PhpRedundantOptionalArgumentInspection */
foreach($DirectoryScanner($source_path, True) as $item) foreach($DirectoryScanner($source_path, True) as $item)
@ -142,12 +131,12 @@
continue; continue;
$Component = new Package\Component(); $Component = new Package\Component();
$Component->Name = Functions::removeBasename($item->getPathname(), $path); $Component->Name = Functions::removeBasename($item->getPathname(), $this->path);
$this->package->Components[] = $Component; $this->package->Components[] = $Component;
Console::outVerbose(sprintf('found component %s', $Component->Name));
} }
if(ncc::cliMode())
{
if(count($this->package->Components) > 0) if(count($this->package->Components) > 0)
{ {
Console::out(count($this->package->Components) . ' component(s) found'); Console::out(count($this->package->Components) . ' component(s) found');
@ -156,8 +145,6 @@
{ {
Console::out('No components found'); Console::out('No components found');
} }
}
// Clear previous excludes and includes // Clear previous excludes and includes
$DirectoryScanner->setExcludes([]); $DirectoryScanner->setExcludes([]);
@ -165,10 +152,10 @@
// Ignore component files // Ignore component files
$DirectoryScanner->setExcludes(array_merge( $DirectoryScanner->setExcludes(array_merge(
$this->selected_build_configuration->ExcludeFiles, ComponentFileExtensions::Php $selected_build_configuration->ExcludeFiles, ComponentFileExtensions::Php
)); ));
Console::out('Scanning for resources... ', false); Console::out('Scanning for resources... ');
/** @var SplFileInfo $item */ /** @var SplFileInfo $item */
foreach($DirectoryScanner($source_path) as $item) foreach($DirectoryScanner($source_path) as $item)
{ {
@ -177,13 +164,12 @@
continue; continue;
$Resource = new Package\Resource(); $Resource = new Package\Resource();
$Resource->Name = Functions::removeBasename($item->getPathname(), $path); $Resource->Name = Functions::removeBasename($item->getPathname(), $this->path);
$this->package->Resources[] = $Resource; $this->package->Resources[] = $Resource;
Console::outVerbose(sprintf('found resource %s', $Resource->Name));
} }
if(ncc::cliMode())
{
if(count($this->package->Resources) > 0) if(count($this->package->Resources) > 0)
{ {
Console::out(count($this->package->Resources) . ' resources(s) found'); Console::out(count($this->package->Resources) . ' resources(s) found');
@ -193,82 +179,141 @@
Console::out('No resources found'); Console::out('No resources found');
} }
} }
/**
* Executes the compile process in the correct order and returns the finalized Package object
*
* @return Package|null
* @throws AccessDeniedException
* @throws BuildException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
*/
public function build(): ?Package
{
$this->compileExecutionPolicies();
$this->compileComponents();
$this->compileResources();
PackageCompiler::compilePackageConstants($this->package, [
ConstantReferences::Assembly => $this->project->Assembly,
ConstantReferences::Build => null,
ConstantReferences::DateTime => time()
]);
return $this->getPackage();
} }
/** /**
* Builds the package by parsing the AST contents of the components and resources * Compiles the resources of the package
* *
* @param string $path * @return void
* @return string * @throws AccessDeniedException
* @throws BuildException * @throws BuildException
* @throws FileNotFoundException
* @throws IOException
*/ */
public function build(string $path): string public function compileResources(): void
{ {
if($this->package == null) if($this->package == null)
{
throw new BuildException('The prepare() method must be called before building the package'); throw new BuildException('The prepare() method must be called before building the package');
}
// Append trailing slash to the end of the path if it's not already there if(count($this->package->Resources) == 0)
if(substr($path, -1) !== DIRECTORY_SEPARATOR) return;
{
$path .= DIRECTORY_SEPARATOR;
}
// Runtime variables // Process the resources
$components = []; Console::out('Processing resources');
$resources = []; $total_items = count($this->package->Resources);
$processed_items = 0; $processed_items = 0;
$total_items = 0; $resources = [];
if(count($this->package->Components) > 0) foreach($this->package->Resources as $resource)
{ {
if(ncc::cliMode()) if($total_items > 5)
{
Console::out('Compiling components');
$total_items = count($this->package->Components);
}
// Process the components and attempt to create an AST representation of the source
foreach($this->package->Components as $component)
{
if(ncc::cliMode() && $total_items > 5)
{ {
Console::inlineProgressBar($processed_items, $total_items); Console::inlineProgressBar($processed_items, $total_items);
} }
$content = file_get_contents(Functions::correctDirectorySeparator($path . $component->Name)); // Get the data and
$resource->Data = IO::fread(Functions::correctDirectorySeparator($this->path . $resource->Name));
$resource->Data = Base64::encode($resource->Data);
$resource->Name = str_replace($this->project->Build->SourcePath, (string)null, $resource->Name);
$resource->updateChecksum();
$resources[] = $resource;
Console::outDebug(sprintf('processed resource %s', $resource->Name));
}
// Update the resources
$this->package->Resources = $resources;
}
/**
* Compiles the components of the package
*
* @return void
* @throws AccessDeniedException
* @throws BuildException
* @throws FileNotFoundException
* @throws IOException
*/
public function compileComponents(): void
{
if($this->package == null)
throw new BuildException('The prepare() method must be called before building the package');
if(count($this->package->Components) == 0)
return;
Console::out('Compiling components');
$total_items = count($this->package->Components);
$processed_items = 0;
$components = [];
// Process the components and attempt to create an AST representation of the source
foreach($this->package->Components as $component)
{
if($total_items > 5)
{
Console::inlineProgressBar($processed_items, $total_items);
}
$content = IO::fread(Functions::correctDirectorySeparator($this->path . $component->Name));
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7); $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
try try
{ {
$stmts = $parser->parse($content); $stmts = $parser->parse($content);
$encoded = json_encode($stmts); $encoded = json_encode($stmts);
unset($stmts);
if($encoded === false) if($encoded === false)
{ {
$component->DataType = ComponentDataType::b64encoded; $component->DataType = ComponentDataType::b64encoded;
$component->Data = Base64::encode($content); $component->Data = Base64::encode($content);
$component->Checksum = hash('sha1', $component->Data);
} }
else else
{ {
$component->DataType = ComponentDataType::AST; $component->DataType = ComponentDataType::AST;
$component->Data = json_decode($encoded, true); $component->Data = json_decode($encoded, true);
$component->Checksum = null;
} }
} }
catch(Error $e) catch(Exception $e)
{ {
$component->DataType = ComponentDataType::b64encoded; $component->DataType = ComponentDataType::b64encoded;
$component->Data = Base64::encode($content); $component->Data = Base64::encode($content);
$component->Checksum = hash('sha1', $component->Data);
unset($e); unset($e);
} }
unset($parser);
$component->Name = str_replace($this->project->Build->SourcePath, (string)null, $component->Name); $component->Name = str_replace($this->project->Build->SourcePath, (string)null, $component->Name);
$component->updateChecksum();
$components[] = $component; $components[] = $component;
$processed_items += 1; $processed_items += 1;
Console::outDebug(sprintf('processed component %s (%s)', $component->Name, $component->DataType));
} }
if(ncc::cliMode() && $total_items > 5) if(ncc::cliMode() && $total_items > 5)
@ -280,71 +325,24 @@
$this->package->Components = $components; $this->package->Components = $components;
} }
if(count($this->package->Resources) > 0) /**
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
*/
public function compileExecutionPolicies(): void
{ {
// Process the resources PackageCompiler::compileExecutionPolicies($this->path, $this->project);
if(ncc::cliMode())
{
Console::out('Processing resources');
$processed_items = 0;
$total_items = count($this->package->Resources);
} }
foreach($this->package->Resources as $resource) /**
* @inheritDoc
*/
public function getPackage(): ?Package
{ {
if(ncc::cliMode() && $total_items > 5) return $this->package;
{
Console::inlineProgressBar($processed_items, $total_items);
} }
// Get the data and
$resource->Data = file_get_contents(Functions::correctDirectorySeparator($path . $resource->Name));
$resource->Data = Base64::encode($resource->Data);
$resource->Checksum = hash('sha1', $resource->Data);
$resource->Name = str_replace($this->project->Build->SourcePath, (string)null, $resource->Name);
$resources[] = $resource;
}
// Update the resources
$this->package->Resources = $resources;
}
if(ncc::cliMode())
{
if($total_items > 5)
print(PHP_EOL);
Console::out($this->package->Assembly->Package . ' compiled successfully');
}
// Write the package to disk
$FileSystem = new Filesystem();
if($FileSystem->exists($path . $this->selected_build_configuration->OutputPath))
{
try
{
$FileSystem->remove($path . $this->selected_build_configuration->OutputPath);
}
catch(IOException $e)
{
throw new BuildException('Cannot delete directory \'' . $path . $this->selected_build_configuration->OutputPath . '\', ' . $e->getMessage(), $e);
}
}
// Finally write the package to the disk
$FileSystem->mkdir($path . $this->selected_build_configuration->OutputPath);
$output_file = $path . $this->selected_build_configuration->OutputPath . DIRECTORY_SEPARATOR . $this->package->Assembly->Package . '.ncc';
$FileSystem->touch($output_file);
try
{
$this->package->save($output_file);
}
catch(Exception $e)
{
throw new BuildException('Cannot write to output file', $e);
}
return $output_file;
}
} }

View file

@ -0,0 +1,342 @@
<?php
/** @noinspection PhpPropertyOnlyWrittenInspection */
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Classes\PhpExtension;
use ArrayIterator;
use Exception;
use ncc\Abstracts\ComponentDataType;
use ncc\Abstracts\ComponentFileExtensions;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\ComponentChecksumException;
use ncc\Exceptions\ComponentDecodeException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NoUnitsFoundException;
use ncc\Exceptions\ResourceChecksumException;
use ncc\Exceptions\UnsupportedComponentTypeException;
use ncc\Interfaces\InstallerInterface;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package;
use ncc\Objects\Package\Component;
use ncc\ThirdParty\nikic\PhpParser\Comment;
use ncc\ThirdParty\nikic\PhpParser\Node;
use ncc\ThirdParty\nikic\PhpParser\PrettyPrinter\Standard;
use ncc\ThirdParty\theseer\Autoload\CollectorException;
use ncc\ThirdParty\theseer\Autoload\CollectorResult;
use ncc\ThirdParty\theseer\Autoload\Config;
use ncc\ThirdParty\theseer\Autoload\Factory;
use ncc\Utilities\Base64;
use ncc\Utilities\IO;
use ReflectionClass;
use ReflectionException;
use RuntimeException;
use SplFileInfo;
use function is_array;
use function is_string;
class Installer implements InstallerInterface
{
/**
* @var ReflectionClass[] Node type to reflection class map
*/
private $reflectionClassCache;
/**
* @var Package
*/
private $package;
/**
* @inheritDoc
*/
public function __construct(Package $package)
{
$this->package = $package;
}
/**
* Processes the given component and returns the decoded component as a string representation
* If the processed component does not result in a string representation, none will be returned.
*
* @param Component $component
* @return string|null
* @throws ComponentChecksumException
* @throws ComponentDecodeException
* @throws UnsupportedComponentTypeException
*/
public function processComponent(Package\Component $component): ?string
{
if($component->Data == null)
return null;
if(!$component->validateChecksum())
throw new ComponentChecksumException('Checksum validation failed for component ' . $component->Name . ', the package may be corrupted.');
switch($component->DataType)
{
case ComponentDataType::AST:
try
{
$stmts = $this->decodeRecursive($component->Data);
}
catch (Exception $e)
{
throw new ComponentDecodeException('Cannot decode component: ' . $component->Name . ', ' . $e->getMessage(), $e);
}
$prettyPrinter = new Standard();
return $prettyPrinter->prettyPrintFile($stmts);
case ComponentDataType::b64encoded:
return Base64::decode($component->Data);
case ComponentDataType::Plain:
return $component->Data;
default:
throw new UnsupportedComponentTypeException('Unsupported component type \'' . $component->DataType . '\'');
}
}
/**
* @inheritDoc
*/
public function preInstall(InstallationPaths $installationPaths): void
{
}
/**
* @inheritDoc
*/
public function postInstall(InstallationPaths $installationPaths): void
{
$autoload_path = $installationPaths->getBinPath() . DIRECTORY_SEPARATOR . 'autoload.php';
$autoload_src = $this->generateAutoload($installationPaths->getSourcePath(), $autoload_path);
IO::fwrite($autoload_path, $autoload_src);
}
/**
* Processes the given resource and returns the string representation of the resource
*
* @param Package\Resource $resource
* @return string|null
* @throws ResourceChecksumException
*/
public function processResource(Package\Resource $resource): ?string
{
if(!$resource->validateChecksum())
throw new ResourceChecksumException('Checksum validation failed for resource ' . $resource->Name . ', the package may be corrupted.');
return Base64::decode($resource->Data);
}
/**
* @param $value
* @return array|Comment|Node
* @throws ReflectionException
* @noinspection PhpMissingReturnTypeInspection
*/
private function decodeRecursive($value)
{
if (is_array($value))
{
if (isset($value['nodeType']))
{
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc')
{
return $this->decodeComment($value);
}
return $this->decodeNode($value);
}
return $this->decodeArray($value);
}
return $value;
}
/**
* @param array $array
* @return array
* @throws ReflectionException
*/
private function decodeArray(array $array) : array
{
$decodedArray = [];
foreach ($array as $key => $value)
{
$decodedArray[$key] = $this->decodeRecursive($value);
}
return $decodedArray;
}
/**
* @param array $value
* @return Node
* @throws ReflectionException
*/
private function decodeNode(array $value) : Node
{
$nodeType = $value['nodeType'];
if (!is_string($nodeType))
{
throw new RuntimeException('Node type must be a string');
}
$reflectionClass = $this->reflectionClassFromNodeType($nodeType);
/** @var Node $node */
$node = $reflectionClass->newInstanceWithoutConstructor();
if (isset($value['attributes'])) {
if (!is_array($value['attributes']))
{
throw new RuntimeException('Attributes must be an array');
}
$node->setAttributes($this->decodeArray($value['attributes']));
}
foreach ($value as $name => $subNode) {
if ($name === 'nodeType' || $name === 'attributes')
{
continue;
}
$node->$name = $this->decodeRecursive($subNode);
}
return $node;
}
/**
* @param array $value
* @return Comment
*/
private 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
);
}
/**
* @param string $nodeType
* @return ReflectionClass
* @throws ReflectionException
*/
private function reflectionClassFromNodeType(string $nodeType) : ReflectionClass
{
if (!isset($this->reflectionClassCache[$nodeType]))
{
$className = $this->classNameFromNodeType($nodeType);
$this->reflectionClassCache[$nodeType] = new ReflectionClass($className);
}
return $this->reflectionClassCache[$nodeType];
}
/**
* @param string $nodeType
* @return string
*/
private 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\"");
}
/**
* Processes the project and generates the autoloader source code.
*
* @param string $src
* @param string $output
* @return string
* @throws AccessDeniedException
* @throws CollectorException
* @throws FileNotFoundException
* @throws IOException
* @throws NoUnitsFoundException
*/
private function generateAutoload(string $src, string $output): string
{
// Construct configuration
$configuration = new Config([$src]);
$configuration->setFollowSymlinks(false); // Don't follow symlinks, it won't work on some systems.
$configuration->setTrusting(true); // Paranoid
$configuration->setOutputFile($output);
$configuration->setStaticMode(false);
// Official PHP file extensions that are missing from the default configuration (whatever)
$configuration->setInclude(ComponentFileExtensions::Php);
$configuration->setQuietMode(true);
// Construct factory
$factory = new Factory();
$factory->setConfig($configuration);
// Create Collector
$result = self::runCollector($factory, $configuration);
// Exception raises when there are no files in the project that can be processed by the autoloader
if(!$result->hasUnits())
{
throw new NoUnitsFoundException('No units were found in the project');
}
$template = IO::fread($configuration->getTemplate());
$builder = $factory->getRenderer($result);
return $builder->render($template);
}
/**
* Iterates through the target directories through the collector and returns the collector results.
*
* @param Factory $factory
* @param Config $config
* @return CollectorResult
* @throws CollectorException
* @throws Exception
*/
private static function runCollector(Factory $factory, Config $config): CollectorResult
{
$collector = $factory->getCollector();
foreach($config->getDirectories() as $directory)
{
if(is_dir($directory))
{
$scanner = $factory->getScanner()->getIterator($directory);
$collector->processDirectory($scanner);
unset($scanner);
}
else
{
$file = new SplFileInfo($directory);
$filter = $factory->getFilter(new ArrayIterator(array($file)));
foreach($filter as $file)
{
$collector->processFile($file);
}
}
}
return $collector->getResult();
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace ncc\Classes\PhpExtension;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\RunnerExecutionException;
use ncc\Interfaces\RunnerInterface;
use ncc\Objects\ExecutionPointers\ExecutionPointer;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\ThirdParty\Symfony\Process\Process;
use ncc\Utilities\Base64;
use ncc\Utilities\IO;
class Runner implements RunnerInterface
{
/**
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws FileNotFoundException
* @throws AccessDeniedException
* @throws IOException
*/
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit
{
$execution_unit = new ExecutionUnit();
$target_file = $path;
if(!file_exists($target_file) && !is_file($target_file))
throw new FileNotFoundException($target_file);
$policy->Execute->Target = null;
$execution_unit->ExecutionPolicy = $policy;
$execution_unit->Data = Base64::encode(IO::fread($target_file));
return $execution_unit;
}
/**
* Returns the file extension to use for the target file
*
* @return string
*/
public static function getFileExtension(): string
{
return '.php';
}
/**
* @param ExecutionPointer $pointer
* @return Process
* @throws RunnerExecutionException
*/
public static function prepareProcess(ExecutionPointer $pointer): Process
{
$php_bin = new ExecutableFinder();
$php_bin = $php_bin->find('php');
if($php_bin == null)
throw new RunnerExecutionException('Cannot locate PHP executable');
if($pointer->ExecutionPolicy->Execute->Options !== null && count($pointer->ExecutionPolicy->Execute->Options) > 0)
return new Process(array_merge([$php_bin, $pointer->FilePointer], $pointer->ExecutionPolicy->Execute->Options));
return new Process([$php_bin, $pointer->FilePointer]);
}
}

View file

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

View file

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

View file

@ -0,0 +1,8 @@
<?php
namespace ncc\Exceptions;
class ExecutionUnitNotFoundException extends \Exception
{
}

View file

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

View file

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

View file

@ -0,0 +1,14 @@
<?php
namespace ncc\Exceptions;
use Exception;
use Throwable;
class InvalidExecutionPolicyName extends Exception
{
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,13 @@
<?php
namespace ncc\Exceptions;
use Exception;
class ProjectConfigurationNotFoundException extends Exception
{
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, $previous);
}
}

View file

@ -0,0 +1,29 @@
<?php
/** @noinspection PhpPropertyOnlyWrittenInspection */
namespace ncc\Exceptions;
use Exception;
use Throwable;
class ResourceChecksumException extends Exception
{
/**
* @var Throwable|null
*/
private ?Throwable $previous;
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
$this->previous = $previous;
}
}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,11 @@
<?php
namespace ncc\Exceptions;
class UnsupportedRunnerException extends \Exception
{
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View file

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

View file

@ -3,23 +3,79 @@
namespace ncc\Interfaces; namespace ncc\Interfaces;
use ncc\Abstracts\Options\BuildConfigurationValues; use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\BuildException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration;
interface CompilerInterface interface CompilerInterface
{ {
/**
* Public constructor
*
* @param ProjectConfiguration $project
* @param string $path
*/
public function __construct(ProjectConfiguration $project, string $path);
/** /**
* Prepares the package for the build process, this method is called before build() * Prepares the package for the build process, this method is called before build()
* *
* @param string $path The path that the project file is located in (project.json)
* @param string $build_configuration The build configuration to use to build the project * @param string $build_configuration The build configuration to use to build the project
* @return void * @return void
*/ */
public function prepare(string $path, string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void; public function prepare(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): void;
/** /**
* Builds the package, returns the output path of the build * Executes the compile process in the correct order and returns the finalized Package object
* *
* @param string $path The path that the project file is located in (project.json) * @return Package|null
* @return string Returns the output path of the build * @throws AccessDeniedException
* @throws BuildException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
*/ */
public function build(string $path): string; public function build(): ?Package;
/**
* Compiles the components of the package
*
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/
public function compileComponents(): void;
/**
* Compiles the resources of the package
*
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/
public function compileResources(): void;
/**
* Compiles the execution policies of the package
*
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
*/
public function compileExecutionPolicies(): void;
/**
* Returns the current state of the package
*
* @return Package|null
*/
public function getPackage(): ?Package;
} }

View file

@ -0,0 +1,59 @@
<?php
namespace ncc\Interfaces;
use Exception;
use ncc\Exceptions\ComponentChecksumException;
use ncc\Exceptions\ComponentDecodeException;
use ncc\Exceptions\UnsupportedComponentTypeException;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package;
use ncc\Objects\Package\Component;
interface InstallerInterface
{
/**
* Public Constructor
*
* @param Package $package
*/
public function __construct(Package $package);
/**
* Processes the component and optionally returns a string of the final component
*
* @param Component $component
* @return string|null
* @throws ComponentChecksumException
* @throws ComponentDecodeException
* @throws UnsupportedComponentTypeException
*/
public function processComponent(Package\Component $component): ?string;
/**
* Processes the resource and optionally returns a string of the final resource
*
* @param Package\Resource $resource
* @return string|null
* @throws
*/
public function processResource(Package\Resource $resource): ?string;
/**
* Method called before the installation stage begins
*
* @param InstallationPaths $installationPaths
* @throws Exception
* @return void
*/
public function preInstall(InstallationPaths $installationPaths): void;
/**
* Method called after the installation stage is completed and all the files have been installed
*
* @param InstallationPaths $installationPaths
* @throws Exception
* @return void
*/
public function postInstall(InstallationPaths $installationPaths): void;
}

View file

@ -0,0 +1,44 @@
<?php
namespace ncc\Interfaces;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\RunnerExecutionException;
use ncc\Objects\ExecutionPointers\ExecutionPointer;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\ThirdParty\Symfony\Process\Process;
interface RunnerInterface
{
/**
* Processes the ExecutionPolicy
*
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws FileNotFoundException
* @throws AccessDeniedException
* @throws IOException
*/
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit;
/**
* Returns the file extension to use for the target file
*
* @return string
*/
public static function getFileExtension(): string;
/**
* Prepares a process object for the execution pointer
*
* @param ExecutionPointer $pointer
* @return Process
* @throws RunnerExecutionException
*/
public static function prepareProcess(ExecutionPointer $pointer): Process;
}

View file

@ -4,12 +4,15 @@
namespace ncc\Managers; namespace ncc\Managers;
use Exception;
use ncc\Abstracts\Scopes; use ncc\Abstracts\Scopes;
use ncc\Abstracts\Versions; use ncc\Abstracts\Versions;
use ncc\Exceptions\AccessDeniedException; use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\InvalidCredentialsEntryException; use ncc\Exceptions\InvalidCredentialsEntryException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\RuntimeException; use ncc\Exceptions\RuntimeException;
use ncc\Objects\Vault; use ncc\Objects\Vault;
use ncc\Utilities\IO;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto; use ncc\ZiProto\ZiProto;
@ -26,6 +29,7 @@
*/ */
public function __construct() public function __construct()
{ {
/** @noinspection PhpUnhandledExceptionInspection */
$this->CredentialsPath = PathFinder::getDataPath(Scopes::System) . DIRECTORY_SEPARATOR . 'credentials.store'; $this->CredentialsPath = PathFinder::getDataPath(Scopes::System) . DIRECTORY_SEPARATOR . 'credentials.store';
} }
@ -51,7 +55,7 @@
* *
* @return void * @return void
* @throws AccessDeniedException * @throws AccessDeniedException
* @throws RuntimeException * @throws IOException
*/ */
public function constructStore(): void public function constructStore(): void
{ {
@ -68,12 +72,7 @@
$VaultObject = new Vault(); $VaultObject = new Vault();
$VaultObject->Version = Versions::CredentialsStoreVersion; $VaultObject->Version = Versions::CredentialsStoreVersion;
if(!@file_put_contents($this->CredentialsPath, ZiProto::encode($VaultObject->toArray()))) IO::fwrite($this->CredentialsPath, ZiProto::encode($VaultObject->toArray()), 0600);
{
throw new RuntimeException('Cannot create file \'' . $this->CredentialsPath . '\'');
}
chmod($this->CredentialsPath, 0600);
} }
/** /**
@ -81,6 +80,7 @@
* *
* @return Vault * @return Vault
* @throws AccessDeniedException * @throws AccessDeniedException
* @throws IOException
* @throws RuntimeException * @throws RuntimeException
*/ */
public function getVault(): Vault public function getVault(): Vault
@ -94,17 +94,15 @@
try try
{ {
$Vault = ZiProto::decode(file_get_contents($this->CredentialsPath)); $Vault = ZiProto::decode(IO::fread($this->CredentialsPath));
} }
catch(\Exception $e) catch(Exception $e)
{ {
// TODO: Implement error-correction for corrupted credentials store. // TODO: Implement error-correction for corrupted credentials store.
throw new RuntimeException($e->getMessage(), $e); throw new RuntimeException($e->getMessage(), $e);
} }
$Vault = Vault::fromArray($Vault); return Vault::fromArray($Vault);
return $Vault;
} }
/** /**
@ -113,15 +111,16 @@
* @param Vault $vault * @param Vault $vault
* @return void * @return void
* @throws AccessDeniedException * @throws AccessDeniedException
* @throws IOException
*/ */
public function saveVault(Vault $vault) public function saveVault(Vault $vault): void
{ {
if(!$this->checkAccess()) if(!$this->checkAccess())
{ {
throw new AccessDeniedException('Cannot write to credentials store without system permissions'); throw new AccessDeniedException('Cannot write to credentials store without system permissions');
} }
file_put_contents($this->CredentialsPath, ZiProto::encode($vault->toArray())); IO::fwrite($this->CredentialsPath, ZiProto::encode($vault->toArray()), 0600);
} }
/** /**
@ -132,8 +131,9 @@
* @throws AccessDeniedException * @throws AccessDeniedException
* @throws InvalidCredentialsEntryException * @throws InvalidCredentialsEntryException
* @throws RuntimeException * @throws RuntimeException
* @throws IOException
*/ */
public function registerEntry(Vault\Entry $entry) public function registerEntry(Vault\Entry $entry): void
{ {
if(!preg_match('/^[\w-]+$/', $entry->Alias)) if(!preg_match('/^[\w-]+$/', $entry->Alias))
{ {
@ -152,7 +152,7 @@
/** /**
* @return null * @return null
*/ */
public function getCredentialsPath() public function getCredentialsPath(): ?string
{ {
return $this->CredentialsPath; return $this->CredentialsPath;
} }

View file

@ -0,0 +1,424 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Managers;
use Exception;
use ncc\Abstracts\Runners;
use ncc\Abstracts\Scopes;
use ncc\Classes\PhpExtension\Runner;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\ExecutionUnitNotFoundException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NoAvailableUnitsException;
use ncc\Exceptions\RunnerExecutionException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Objects\ExecutionPointers;
use ncc\Objects\Package;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\ExitHandle;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
use ncc\ThirdParty\Symfony\Process\Process;
use ncc\Utilities\Console;
use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto;
class ExecutionPointerManager
{
/**
* The path for where all the runners are located
*
* @var string
*/
private $RunnerPath;
/**
* An array of temporary unit names to destroy once the object is destroyed
*
* @var string[]
*/
private $TemporaryUnits;
/**
* Deletes all the temporary files on destruct
*/
public function __destruct()
{
try
{
$this->cleanTemporaryUnits();
}
catch(Exception $e)
{
unset($e);
}
}
/**
* @throws InvalidScopeException
*/
public function __construct()
{
$this->RunnerPath = PathFinder::getRunnerPath(Scopes::System);
$this->TemporaryUnits = [];
}
/**
* Deletes all temporary files and directories
*
* @return void
*/
public function cleanTemporaryUnits(): void
{
if(count($this->TemporaryUnits) == 0)
return;
try
{
foreach($this->TemporaryUnits as $datum)
{
$this->removeUnit($datum['package'], $datum['version'], $datum['name']);
}
}
catch(Exception $e)
{
unset($e);
}
}
/**
* Calculates the Package ID for the execution pointers
*
* @param string $package
* @param string $version
* @return string
*/
private function getPackageId(string $package, string $version): string
{
return hash('haval128,4', $package . $version);
}
/**
* Adds a new Execution Unit to the
*
* @param string $package
* @param string $version
* @param ExecutionUnit $unit
* @param bool $temporary
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws UnsupportedRunnerException
* @noinspection PhpUnused
*/
public function addUnit(string $package, string $version, ExecutionUnit $unit, bool $temporary=false): void
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Cannot add new ExecutionUnit \'' . $unit->ExecutionPolicy->Name .'\' for ' . $package . ', insufficient permissions');
$package_id = $this->getPackageId($package, $version);
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
$package_bin_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id;
$filesystem = new Filesystem();
// Either load or create the pointers file
if(!$filesystem->exists($package_config_path))
{
$execution_pointers = new ExecutionPointers($package, $version);
}
else
{
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
}
$bin_file = $package_bin_path . DIRECTORY_SEPARATOR . hash('haval128,4', $unit->ExecutionPolicy->Name);
$bin_file .= match ($unit->ExecutionPolicy->Runner) {
Runners::php => Runner::getFileExtension(),
default => throw new UnsupportedRunnerException('The runner \'' . $unit->ExecutionPolicy->Runner . '\' is not supported'),
};
if($filesystem->exists($bin_file) && $temporary)
return;
if(!$filesystem->exists($package_bin_path))
$filesystem->mkdir($package_bin_path);
if($filesystem->exists($bin_file))
$filesystem->remove($bin_file);
IO::fwrite($bin_file, $unit->Data);
$execution_pointers->addUnit($unit, $bin_file);
IO::fwrite($package_config_path, ZiProto::encode($execution_pointers->toArray(true)));
if($temporary)
{
$this->TemporaryUnits[] = [
'package' => $package,
'version' => $version,
'unit' => $unit->ExecutionPolicy->Name
];
}
}
/**
* Deletes and removes the installed unit
*
* @param string $package
* @param string $version
* @param string $name
* @return bool
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/
public function removeUnit(string $package, string $version, string $name): bool
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Cannot remove ExecutionUnit \'' . $name .'\' for ' . $package . ', insufficient permissions');
$package_id = $this->getPackageId($package, $version);
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
$package_bin_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id;
$filesystem = new Filesystem();
if(!$filesystem->exists($package_config_path))
return false;
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
$unit = $execution_pointers->getUnit($name);
if($unit == null)
return false;
$results = $execution_pointers->deleteUnit($name);
// Delete everything if there are no execution pointers configured
if(count($execution_pointers->getPointers()) == 0)
{
$filesystem->remove($package_config_path);
$filesystem->remove($package_bin_path);
return $results;
}
// Delete the single execution pointer file
if($filesystem->exists($unit->FilePointer))
$filesystem->remove($unit->FilePointer);
return $results;
}
/**
* Returns an array of configured units for a package version
*
* @param string $package
* @param string $version
* @return array
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @noinspection PhpUnused
*/
public function getUnits(string $package, string $version): array
{
$package_id = $this->getPackageId($package, $version);
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
if(!file_exists($package_config_path))
return [];
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
$results = [];
foreach($execution_pointers->getPointers() as $pointer)
{
$results[] = $pointer->ExecutionPolicy->Name;
}
return $results;
}
/**
* Executes a unit
*
* @param string $package
* @param string $version
* @param string $name
* @return void
* @throws AccessDeniedException
* @throws ExecutionUnitNotFoundException
* @throws FileNotFoundException
* @throws IOException
* @throws NoAvailableUnitsException
* @throws UnsupportedRunnerException
* @throws RunnerExecutionException
*/
public function executeUnit(string $package, string $version, string $name): void
{
$package_id = $this->getPackageId($package, $version);
$package_config_path = $this->RunnerPath . DIRECTORY_SEPARATOR . $package_id . '.inx';
if(!file_exists($package_config_path))
throw new NoAvailableUnitsException('There is no available units for \'' . $package . '=' .$version .'\'');
$execution_pointers = ExecutionPointers::fromArray(ZiProto::decode(IO::fread($package_config_path)));
$unit = $execution_pointers->getUnit($name);
if($unit == null)
throw new ExecutionUnitNotFoundException('The execution unit \'' . $name . '\' was not found for \'' . $package . '=' .$version .'\'');
$process = match (strtolower($unit->ExecutionPolicy->Runner))
{
Runners::php => Runner::prepareProcess($unit),
default => throw new UnsupportedRunnerException('The runner \'' . $unit->ExecutionPolicy->Runner . '\' is not supported'),
};
if($unit->ExecutionPolicy->Execute->WorkingDirectory !== null)
$process->setWorkingDirectory($unit->ExecutionPolicy->Execute->WorkingDirectory);
if($unit->ExecutionPolicy->Execute->Timeout !== null)
$process->setTimeout((float)$unit->ExecutionPolicy->Execute->Timeout);
if($unit->ExecutionPolicy->Execute->Silent)
{
$process->disableOutput();
$process->setTty(false);
}
elseif($unit->ExecutionPolicy->Execute->Tty)
{
$process->enableOutput();
$process->setTty(true);
}
else
{
$process->enableOutput();
}
try
{
if($unit->ExecutionPolicy->Message !== null)
Console::out($unit->ExecutionPolicy->Message);
$process->run(function ($type, $buffer) {
Console::out($buffer);
});
$process->wait();
}
catch(Exception $e)
{
unset($e);
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error);
}
if($unit->ExecutionPolicy->ExitHandlers !== null)
{
if($process->isSuccessful() && $unit->ExecutionPolicy->ExitHandlers->Success !== null)
{
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Success);
}
elseif($process->isSuccessful() && $unit->ExecutionPolicy->ExitHandlers->Error !== null)
{
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error);
}
else
{
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Success, $process);
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Warning, $process);
$this->handleExit($package, $version, $unit->ExecutionPolicy->ExitHandlers->Error, $process);
}
}
}
/**
* Temporarily executes a
*
* @param Package $package
* @param string $unit_name
* @return void
* @throws AccessDeniedException
* @throws ExecutionUnitNotFoundException
* @throws FileNotFoundException
* @throws IOException
* @throws NoAvailableUnitsException
* @throws RunnerExecutionException
* @throws UnsupportedRunnerException
*/
public function temporaryExecute(Package $package, string $unit_name): void
{
// First get the execution unit from the package.
$unit = $package->getExecutionUnit($unit_name);
// Get the required units
$required_units = [];
if($unit->ExecutionPolicy->ExitHandlers !== null)
{
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Success?->Run;
if($required_unit !== null)
$required_units[] = $required_unit;
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Warning?->Run;
if($required_unit !== null)
$required_units[] = $required_unit;
$required_unit = $unit->ExecutionPolicy?->ExitHandlers?->Error?->Run;
if($required_unit !== null)
$required_units = $required_unit;
}
// Install the units temporarily
$this->addUnit($package->Assembly->Package, $package->Assembly->Version, $unit, true);
foreach($required_units as $r_unit)
{
$this->addUnit($package->Assembly->Package, $package->Assembly->Version, $r_unit, true);
}
$this->executeUnit($package->Assembly->Package, $package->Assembly->Version, $unit_name);
$this->cleanTemporaryUnits();
}
/**
* Handles an exit handler object.
*
* If Process is Null and EndProcess is true, the method will end the process
* if Process is not Null the exit handler will only execute if the process' exit code is the same
*
* @param string $package
* @param string $version
* @param ExitHandle $exitHandle
* @param Process|null $process
* @return bool
* @throws AccessDeniedException
* @throws ExecutionUnitNotFoundException
* @throws FileNotFoundException
* @throws IOException
* @throws NoAvailableUnitsException
* @throws RunnerExecutionException
* @throws UnsupportedRunnerException
*/
public function handleExit(string $package, string $version, ExitHandle $exitHandle, ?Process $process=null): bool
{
if($exitHandle->Message !== null)
Console::out($exitHandle->Message);
if($process !== null && !$exitHandle->EndProcess)
{
if($exitHandle->ExitCode !== $process->getExitCode())
return false;
}
elseif($exitHandle->EndProcess)
{
exit($exitHandle->ExitCode);
}
if($exitHandle->Run !== null)
{
$this->executeUnit($package, $version, $exitHandle->Run);
}
return true;
}
}

View file

@ -0,0 +1,152 @@
<?php
/** @noinspection PhpPropertyOnlyWrittenInspection */
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Managers;
use Exception;
use ncc\Abstracts\Scopes;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PackageLockException;
use ncc\Objects\PackageLock;
use ncc\Utilities\Console;
use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache;
use ncc\ZiProto\ZiProto;
class PackageLockManager
{
/**
* @var PackageLock|null
*/
private $PackageLock;
/**
* @var string
*/
private $PackageLockPath;
/**
* Public Constructor
*/
public function __construct()
{
/** @noinspection PhpUnhandledExceptionInspection */
$this->PackageLockPath = PathFinder::getPackageLock(Scopes::System);
try
{
$this->load();
}
catch (PackageLockException $e)
{
unset($e);
}
}
/**
* Loads the PackageLock from the disk
*
* @return void
* @throws PackageLockException
*/
public function load(): void
{
if(RuntimeCache::get($this->PackageLockPath) !== null)
{
$this->PackageLock = RuntimeCache::get($this->PackageLockPath);
return;
}
if(file_exists($this->PackageLockPath) && is_file($this->PackageLockPath))
{
try
{
Console::outDebug('reading package lock file');
$data = IO::fread($this->PackageLockPath);
if(strlen($data) > 0)
{
$this->PackageLock = PackageLock::fromArray(ZiProto::decode($data));
}
else
{
$this->PackageLock = new PackageLock();
}
}
catch(Exception $e)
{
throw new PackageLockException('The PackageLock file cannot be parsed', $e);
}
}
else
{
$this->PackageLock = new PackageLock();
}
RuntimeCache::set($this->PackageLockPath, $this->PackageLock);
}
/**
* Saves the PackageLock to disk
*
* @return void
* @throws AccessDeniedException
* @throws PackageLockException
*/
public function save(): void
{
// Don't save something that isn't loaded lol
if($this->PackageLock == null)
return;
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Cannot write to PackageLock, insufficient permissions');
try
{
IO::fwrite($this->PackageLockPath, ZiProto::encode($this->PackageLock->toArray(true)), 0755);
RuntimeCache::set($this->PackageLockPath, $this->PackageLock);
}
catch(IOException $e)
{
throw new PackageLockException('Cannot save the package lock file to disk', $e);
}
}
/**
* Constructs the package lock file if it doesn't exist
*
* @return void
* @throws AccessDeniedException
* @throws PackageLockException
*/
public function constructLockFile(): void
{
try
{
$this->load();
}
catch (PackageLockException $e)
{
unset($e);
$this->PackageLock = new PackageLock();
}
$this->save();
}
/**
* @return PackageLock|null
* @throws PackageLockException
*/
public function getPackageLock(): ?PackageLock
{
if($this->PackageLock == null)
$this->load();
return $this->PackageLock;
}
}

View file

@ -0,0 +1,490 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Managers;
use Exception;
use ncc\Abstracts\CompilerExtensions;
use ncc\Abstracts\ConstantReferences;
use ncc\Abstracts\LogLevel;
use ncc\Abstracts\Scopes;
use ncc\Classes\NccExtension\PackageCompiler;
use ncc\Classes\PhpExtension\Installer;
use ncc\CLI\Main;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InstallationException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PackageAlreadyInstalledException;
use ncc\Exceptions\PackageLockException;
use ncc\Exceptions\PackageNotFoundException;
use ncc\Exceptions\PackageParsingException;
use ncc\Exceptions\UnsupportedCompilerExtensionException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Exceptions\VersionNotFoundException;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package;
use ncc\Objects\PackageLock\PackageEntry;
use ncc\Objects\PackageLock\VersionEntry;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
use ncc\Utilities\Console;
use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto;
use SplFileInfo;
class PackageManager
{
/**
* @var string
*/
private $PackagesPath;
/**
* @var PackageLockManager|null
*/
private $PackageLockManager;
/**
* @throws InvalidScopeException
* @throws PackageLockException
*/
public function __construct()
{
$this->PackagesPath = PathFinder::getPackagesPath(Scopes::System);
$this->PackageLockManager = new PackageLockManager();
$this->PackageLockManager->load();
}
/**
* Installs a local package onto the system
*
* @param string $input
* @return string
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws InstallationException
* @throws PackageAlreadyInstalledException
* @throws PackageLockException
* @throws PackageParsingException
* @throws UnsupportedCompilerExtensionException
* @throws UnsupportedRunnerException
* @throws VersionNotFoundException
*/
public function install(string $input): string
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Insufficient permission to install packages');
Console::outVerbose(sprintf('Installing %s', $input));
if(!file_exists($input) || !is_file($input) || !is_readable($input))
throw new FileNotFoundException('The specified file \'' . $input .' \' does not exist or is not readable.');
$package = Package::load($input);
if($this->getPackageVersion($package->Assembly->Package, $package->Assembly->Version) !== null)
throw new PackageAlreadyInstalledException('The package ' . $package->Assembly->Package . '==' . $package->Assembly->Version . ' is already installed');
$extension = $package->Header->CompilerExtension->Extension;
$installation_paths = new InstallationPaths($this->PackagesPath . DIRECTORY_SEPARATOR . $package->Assembly->Package . '==' . $package->Assembly->Version);
$installer = match ($extension) {
CompilerExtensions::PHP => new Installer($package),
default => throw new UnsupportedCompilerExtensionException('The compiler extension \'' . $extension . '\' is not supported'),
};
$execution_pointer_manager = new ExecutionPointerManager();
PackageCompiler::compilePackageConstants($package, [
ConstantReferences::Install => $installation_paths
]);
Console::outVerbose(sprintf('Successfully parsed %s', $package->Assembly->Package));
if(Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
{
Console::outDebug(sprintf('installer.install_path: %s', $installation_paths->getInstallationPath()));
Console::outDebug(sprintf('installer.data_path: %s', $installation_paths->getDataPath()));
Console::outDebug(sprintf('installer.bin_path: %s', $installation_paths->getBinPath()));
Console::outDebug(sprintf('installer.src_path: %s', $installation_paths->getSourcePath()));
foreach($package->Assembly->toArray() as $prop => $value)
Console::outDebug(sprintf('assembly.%s: %s', $prop, ($value ?? 'n/a')));
foreach($package->Header->CompilerExtension->toArray() as $prop => $value)
Console::outDebug(sprintf('header.compiler.%s: %s', $prop, ($value ?? 'n/a')));
}
Console::out('Installing ' . $package->Assembly->Package);
// 4 For Directory Creation, preInstall, postInstall & initData methods
$steps = (4 + count($package->Components) + count ($package->Resources) + count ($package->ExecutionUnits));
// Include the Execution units
if($package->Installer?->PreInstall !== null)
$steps += count($package->Installer->PreInstall);
if($package->Installer?->PostInstall!== null)
$steps += count($package->Installer->PostInstall);
$current_steps = 0;
$filesystem = new Filesystem();
try
{
$filesystem->mkdir($installation_paths->getInstallationPath(), 0755);
$filesystem->mkdir($installation_paths->getBinPath(), 0755);
$filesystem->mkdir($installation_paths->getDataPath(), 0755);
$filesystem->mkdir($installation_paths->getSourcePath(), 0755);
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
catch(Exception $e)
{
throw new InstallationException('Error while creating directory, ' . $e->getMessage(), $e);
}
try
{
self::initData($package, $installation_paths);
Console::outDebug(sprintf('saving shadow package to %s', $installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'pkg'));
$package->save($installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'pkg');
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
catch(Exception $e)
{
throw new InstallationException('Cannot initialize package install, ' . $e->getMessage(), $e);
}
// Execute the pre-installation stage before the installation stage
try
{
$installer->preInstall($installation_paths);
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
catch (Exception $e)
{
throw new InstallationException('Pre installation stage failed, ' . $e->getMessage(), $e);
}
if($package->Installer?->PreInstall !== null && count($package->Installer->PreInstall) > 0)
{
foreach($package->Installer->PreInstall as $unit_name)
{
try
{
$execution_pointer_manager->temporaryExecute($package, $unit_name);
}
catch(Exception $e)
{
Console::outWarning('Cannot execute unit ' . $unit_name . ', ' . $e->getMessage());
}
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
}
// Process & Install the components
foreach($package->Components as $component)
{
Console::outDebug(sprintf('processing component %s (%s)', $component->Name, $component->DataType));
try
{
$data = $installer->processComponent($component);
if($data !== null)
{
$component_path = $installation_paths->getSourcePath() . DIRECTORY_SEPARATOR . $component->Name;
$component_dir = dirname($component_path);
if(!$filesystem->exists($component_dir))
$filesystem->mkdir($component_dir);
IO::fwrite($component_path, $data);
}
}
catch(Exception $e)
{
throw new InstallationException('Cannot process one or more components, ' . $e->getMessage(), $e);
}
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
// Process & Install the resources
foreach($package->Resources as $resource)
{
Console::outDebug(sprintf('processing resource %s', $resource->Name));
try
{
$data = $installer->processResource($resource);
if($data !== null)
{
$resource_path = $installation_paths->getSourcePath() . DIRECTORY_SEPARATOR . $resource->Name;
$resource_dir = dirname($resource_path);
if(!$filesystem->exists($resource_dir))
$filesystem->mkdir($resource_dir);
IO::fwrite($resource_path, $data);
}
}
catch(Exception $e)
{
throw new InstallationException('Cannot process one or more resources, ' . $e->getMessage(), $e);
}
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
// Install execution units
// TODO: Implement symlink support
if(count($package->ExecutionUnits) > 0)
{
$execution_pointer_manager = new ExecutionPointerManager();
$unit_paths = [];
foreach($package->ExecutionUnits as $executionUnit)
{
$execution_pointer_manager->addUnit($package->Assembly->Package, $package->Assembly->Version, $executionUnit);
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
IO::fwrite($installation_paths->getDataPath() . DIRECTORY_SEPARATOR . 'exec', ZiProto::encode($unit_paths));
}
// Execute the post-installation stage after the installation is complete
try
{
$installer->postInstall($installation_paths);
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
catch (Exception $e)
{
throw new InstallationException('Post installation stage failed, ' . $e->getMessage(), $e);
}
if($package->Installer?->PostInstall !== null && count($package->Installer->PostInstall) > 0)
{
foreach($package->Installer->PostInstall as $unit_name)
{
try
{
$execution_pointer_manager->temporaryExecute($package, $unit_name);
}
catch(Exception $e)
{
Console::outWarning('Cannot execute unit ' . $unit_name . ', ' . $e->getMessage());
}
$current_steps += 1;
Console::inlineProgressBar($current_steps, $steps);
}
}
$this->getPackageLockManager()->getPackageLock()->addPackage($package, $installation_paths->getInstallationPath());
$this->getPackageLockManager()->save();
return $package->Assembly->Package;
}
/**
* Returns an existing package entry, returns null if no such entry exists
*
* @param string $package
* @return PackageEntry|null
* @throws PackageLockException
* @throws PackageLockException
*/
public function getPackage(string $package): ?PackageEntry
{
return $this->getPackageLockManager()->getPackageLock()->getPackage($package);
}
/**
* Returns an existing version entry, returns null if no such entry exists
*
* @param string $package
* @param string $version
* @return VersionEntry|null
* @throws VersionNotFoundException
* @throws PackageLockException
*/
public function getPackageVersion(string $package, string $version): ?VersionEntry
{
return $this->getPackage($package)?->getVersion($version);
}
/**
* Returns the latest version of the package, or null if there is no entry
*
* @param string $package
* @return VersionEntry|null
* @throws VersionNotFoundException
* @throws PackageLockException
*/
public function getLatestVersion(string $package): ?VersionEntry
{
return $this->getPackage($package)?->getVersion($this->getPackage($package)?->getLatestVersion());
}
/**
* Returns an array of all packages and their installed versions
*
* @return array
* @throws PackageLockException
* @throws PackageLockException
*/
public function getInstalledPackages(): array
{
return $this->getPackageLockManager()->getPackageLock()->getPackages();
}
/**
* Uninstalls a package version
*
* @param string $package
* @param string $version
* @return void
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws PackageLockException
* @throws PackageNotFoundException
* @throws VersionNotFoundException
*/
public function uninstallPackageVersion(string $package, string $version): void
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Insufficient permission to uninstall packages');
$version_entry = $this->getPackageVersion($package, $version);
if($version_entry == null)
throw new PackageNotFoundException(sprintf('The package %s==%s was not found', $package, $version));
Console::out(sprintf('Uninstalling %s==%s', $package, $version));
Console::outVerbose(sprintf('Removing package %s==%s from PackageLock', $package, $version));
if(!$this->getPackageLockManager()->getPackageLock()->removePackageVersion($package, $version))
Console::outDebug('warning: removing package from package lock failed');
$this->getPackageLockManager()->save();
Console::outVerbose('Removing package files');
$scanner = new DirectoryScanner();
$filesystem = new Filesystem();
/** @var SplFileInfo $item */
/** @noinspection PhpRedundantOptionalArgumentInspection */
foreach($scanner($version_entry->Location, true) as $item)
{
if(is_file($item->getPath()))
{
Console::outDebug(sprintf('deleting %s', $item->getPath()));
$filesystem->remove($item->getPath());
}
}
$filesystem->remove($version_entry->Location);
if($version_entry->ExecutionUnits !== null && count($version_entry->ExecutionUnits) > 0)
{
Console::outVerbose('Uninstalling execution units');
$execution_pointer_manager = new ExecutionPointerManager();
foreach($version_entry->ExecutionUnits as $executionUnit)
{
if(!$execution_pointer_manager->removeUnit($package, $version, $executionUnit->ExecutionPolicy->Name))
Console::outDebug(sprintf('warning: removing execution unit %s failed', $executionUnit->ExecutionPolicy->Name));
}
}
}
/**
* Uninstalls all versions of a package
*
* @param string $package
* @return void
* @throws AccessDeniedException
* @throws PackageLockException
* @throws PackageNotFoundException
* @throws VersionNotFoundException
*/
public function uninstallPackage(string $package): void
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Insufficient permission to uninstall packages');
$package_entry = $this->getPackage($package);
if($package_entry == null)
throw new PackageNotFoundException(sprintf('The package %s was not found', $package));
foreach($package_entry->getVersions() as $version)
{
$version_entry = $package_entry->getVersion($version);
try
{
$this->uninstallPackageVersion($package, $version_entry->Version);
}
catch(Exception $e)
{
Console::outDebug(sprintf('warning: unable to uninstall package %s==%s, %s (%s)', $package, $version_entry->Version, $e->getMessage(), $e->getCode()));
}
}
}
/**
* @param Package $package
* @param InstallationPaths $paths
* @throws InstallationException
*/
private static function initData(Package $package, InstallationPaths $paths): void
{
// Create data files
$dependencies = [];
foreach($package->Dependencies as $dependency)
{
$dependencies[] = $dependency->toArray(true);
}
$data_files = [
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'assembly' =>
ZiProto::encode($package->Assembly->toArray(true)),
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'ext' =>
ZiProto::encode($package->Header->CompilerExtension->toArray(true)),
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'const' =>
ZiProto::encode($package->Header->RuntimeConstants),
$paths->getDataPath() . DIRECTORY_SEPARATOR . 'dependencies' =>
ZiProto::encode($dependencies),
];
foreach($data_files as $file => $data)
{
try
{
IO::fwrite($file, $data);
}
catch (IOException $e)
{
throw new InstallationException('Cannot write to file \'' . $file . '\', ' . $e->getMessage(), $e);
}
}
}
/**
* @return PackageLockManager|null
*/
private function getPackageLockManager(): ?PackageLockManager
{
if($this->PackageLockManager == null)
{
$this->PackageLockManager = new PackageLockManager();
}
return $this->PackageLockManager;
}
}

View file

@ -1,12 +1,26 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Managers; namespace ncc\Managers;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Abstracts\Options\InitializeProjectOptions; use ncc\Abstracts\Options\InitializeProjectOptions;
use ncc\Classes\NccExtension\PackageCompiler;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\BuildException;
use ncc\Exceptions\DirectoryNotFoundException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidPackageNameException; use ncc\Exceptions\InvalidPackageNameException;
use ncc\Exceptions\InvalidProjectNameException; use ncc\Exceptions\InvalidProjectNameException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\MalformedJsonException; use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\PackagePreparationFailedException;
use ncc\Exceptions\ProjectAlreadyExistsException; use ncc\Exceptions\ProjectAlreadyExistsException;
use ncc\Exceptions\ProjectConfigurationNotFoundException;
use ncc\Exceptions\UnsupportedCompilerExtensionException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Objects\ProjectConfiguration; use ncc\Objects\ProjectConfiguration;
use ncc\Objects\ProjectConfiguration\Compiler; use ncc\Objects\ProjectConfiguration\Compiler;
use ncc\ThirdParty\Symfony\Uid\Uuid; use ncc\ThirdParty\Symfony\Uid\Uuid;
@ -14,84 +28,77 @@
class ProjectManager class ProjectManager
{ {
/**
* The selected directory for managing the project
*
* @var string|null
*/
private ?string $SelectedDirectory;
/** /**
* The path that points to the project's main project.json file * The path that points to the project's main project.json file
* *
* @var string|null * @var string
*/ */
private ?string $ProjectFilePath; private $ProjectFilePath;
/** /**
* The path that points the project's main directory * The path that points the project's main directory
* *
* @var string|null * @var string
*/ */
private ?string $ProjectPath; private $ProjectPath;
/**
* The loaded project configuration, null if no project file is loaded
*
* @var ProjectConfiguration|null
*/
private $ProjectConfiguration;
/** /**
* Public Constructor * Public Constructor
* *
* @param string $selected_directory * @param string $path
* @throws AccessDeniedException
* @throws DirectoryNotFoundException
* @throws FileNotFoundException
* @throws IOException
* @throws MalformedJsonException
* @throws ProjectConfigurationNotFoundException
*/ */
public function __construct(string $selected_directory) public function __construct(string $path)
{ {
$this->SelectedDirectory = $selected_directory;
$this->ProjectFilePath = null; $this->ProjectFilePath = null;
$this->ProjectPath = null; $this->ProjectPath = null;
$this->detectProjectPath();
}
/**
* Attempts to resolve the project path from the selected directory
* Returns false if the selected directory is not a proper project or an initialized project
*
* @return void
*/
private function detectProjectPath(): void
{
$selected_directory = $this->SelectedDirectory;
// Auto-resolve the trailing slash // Auto-resolve the trailing slash
/** @noinspection PhpStrFunctionsInspection */ /** @noinspection PhpStrFunctionsInspection */
if(substr($selected_directory, -1) !== '/') if(substr($path, -1) !== '/')
{ {
$selected_directory .= DIRECTORY_SEPARATOR; $path .= DIRECTORY_SEPARATOR;
} }
// Detect if the folder exists or not // Detect if the folder exists or not
if(!file_exists($selected_directory) || !is_dir($selected_directory)) if(!file_exists($path) || !is_dir($path))
{ {
return; throw new DirectoryNotFoundException('The given directory \'' . $path .'\' does not exist');
} }
$this->ProjectPath = $selected_directory; $this->ProjectPath = $path;
$this->ProjectFilePath = $selected_directory . 'project.json'; $this->ProjectFilePath = $path . 'project.json';
if(file_exists($this->ProjectFilePath))
$this->load();
} }
/** /**
* Initializes the project structure * Initializes the project structure
* *
* // TODO: Correct the unexpected path behavior issue when initializing a project
*
* @param Compiler $compiler * @param Compiler $compiler
* @param string $name * @param string $name
* @param string $package * @param string $package
* @param string $src * @param string|null $src
* @param array $options * @param array $options
* @throws InvalidPackageNameException * @throws InvalidPackageNameException
* @throws InvalidProjectNameException * @throws InvalidProjectNameException
* @throws MalformedJsonException * @throws MalformedJsonException
* @throws ProjectAlreadyExistsException * @throws ProjectAlreadyExistsException
*/ */
public function initializeProject(Compiler $compiler, string $name, string $package, string $src, array $options=[]): void public function initializeProject(Compiler $compiler, string $name, string $package, ?string $src=null, array $options=[]): void
{ {
// Validate the project information first // Validate the project information first
if(!Validate::packageName($package)) if(!Validate::packageName($package))
@ -109,41 +116,43 @@
throw new ProjectAlreadyExistsException('A project has already been initialized in \'' . $this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json' . '\''); throw new ProjectAlreadyExistsException('A project has already been initialized in \'' . $this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json' . '\'');
} }
$Project = new ProjectConfiguration(); $this->ProjectConfiguration = new ProjectConfiguration();
// Set the compiler information // Set the compiler information
$Project->Project->Compiler = $compiler; $this->ProjectConfiguration->Project->Compiler = $compiler;
// Set the assembly information // Set the assembly information
$Project->Assembly->Name = $name; $this->ProjectConfiguration->Assembly->Name = $name;
$Project->Assembly->Package = $package; $this->ProjectConfiguration->Assembly->Package = $package;
$Project->Assembly->Version = '1.0.0'; $this->ProjectConfiguration->Assembly->Version = '1.0.0';
$Project->Assembly->UUID = Uuid::v1()->toRfc4122(); $this->ProjectConfiguration->Assembly->UUID = Uuid::v1()->toRfc4122();
// Set the build information // Set the build information
$Project->Build->SourcePath = $src; $this->ProjectConfiguration->Build->SourcePath = $src;
$Project->Build->DefaultConfiguration = 'debug'; if($this->ProjectConfiguration->Build->SourcePath == null)
$this->ProjectConfiguration->Build->SourcePath = $this->ProjectPath;
$this->ProjectConfiguration->Build->DefaultConfiguration = 'debug';
// Assembly constants if the program wishes to check for this // Assembly constants if the program wishes to check for this
$Project->Build->DefineConstants['ASSEMBLY_NAME'] = '%ASSEMBLY.NAME%'; $this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_NAME'] = '%ASSEMBLY.NAME%';
$Project->Build->DefineConstants['ASSEMBLY_PACKAGE'] = '%ASSEMBLY.PACKAGE%'; $this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_PACKAGE'] = '%ASSEMBLY.PACKAGE%';
$Project->Build->DefineConstants['ASSEMBLY_VERSION'] = '%ASSEMBLY.VERSION%'; $this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_VERSION'] = '%ASSEMBLY.VERSION%';
$Project->Build->DefineConstants['ASSEMBLY_UID'] = '%ASSEMBLY.UID%'; $this->ProjectConfiguration->Build->DefineConstants['ASSEMBLY_UID'] = '%ASSEMBLY.UID%';
// Generate configurations // Generate configurations
$DebugConfiguration = new ProjectConfiguration\BuildConfiguration(); $DebugConfiguration = new ProjectConfiguration\BuildConfiguration();
$DebugConfiguration->Name = 'debug'; $DebugConfiguration->Name = 'debug';
$DebugConfiguration->OutputPath = 'build/debug'; $DebugConfiguration->OutputPath = 'build/debug';
$DebugConfiguration->DefineConstants["DEBUG"] = '1'; // Debugging constant if the program wishes to check for this $DebugConfiguration->DefineConstants["DEBUG"] = '1'; // Debugging constant if the program wishes to check for this
$Project->Build->Configurations[] = $DebugConfiguration; $this->ProjectConfiguration->Build->Configurations[] = $DebugConfiguration;
$ReleaseConfiguration = new ProjectConfiguration\BuildConfiguration(); $ReleaseConfiguration = new ProjectConfiguration\BuildConfiguration();
$ReleaseConfiguration->Name = 'release'; $ReleaseConfiguration->Name = 'release';
$ReleaseConfiguration->OutputPath = 'build/release'; $ReleaseConfiguration->OutputPath = 'build/release';
$ReleaseConfiguration->DefineConstants["DEBUG"] = '0'; // Debugging constant if the program wishes to check for this $ReleaseConfiguration->DefineConstants["DEBUG"] = '0'; // Debugging constant if the program wishes to check for this
$Project->Build->Configurations[] = $ReleaseConfiguration; $this->ProjectConfiguration->Build->Configurations[] = $ReleaseConfiguration;
// Finally create project.json // Finally create project.json
$Project->toFile($this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json'); $this->ProjectConfiguration->toFile($this->ProjectPath . DIRECTORY_SEPARATOR . 'project.json');
// And create the project directory for additional assets/resources // And create the project directory for additional assets/resources
$Folders = [ $Folders = [
@ -166,15 +175,59 @@
switch($option) switch($option)
{ {
case InitializeProjectOptions::CREATE_SOURCE_DIRECTORY: case InitializeProjectOptions::CREATE_SOURCE_DIRECTORY:
if(!file_exists($this->ProjectPath . DIRECTORY_SEPARATOR . 'src')) if(!file_exists($this->ProjectConfiguration->Build->SourcePath))
{ {
mkdir($this->ProjectPath . DIRECTORY_SEPARATOR . 'src'); mkdir($this->ProjectConfiguration->Build->SourcePath);
} }
break; break;
} }
} }
} }
/**
* Determines if a project configuration is loaded or not
*
* @return bool
*/
public function projectLoaded(): bool
{
if($this->ProjectConfiguration == null)
return false;
return true;
}
/**
* Attempts to load the project configuration
*
* @return void
* @throws MalformedJsonException
* @throws ProjectConfigurationNotFoundException
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/
public function load()
{
if(!file_exists($this->ProjectFilePath) && !is_file($this->ProjectFilePath))
throw new ProjectConfigurationNotFoundException('The project configuration file \'' . $this->ProjectFilePath . '\' was not found');
$this->ProjectConfiguration = ProjectConfiguration::fromFile($this->ProjectFilePath);
}
/**
* Saves the project configuration
*
* @return void
* @throws MalformedJsonException
*/
public function save()
{
if(!$this->projectLoaded())
return;
$this->ProjectConfiguration->toFile($this->ProjectFilePath);
}
/** /**
* @return string|null * @return string|null
*/ */
@ -182,4 +235,49 @@
{ {
return $this->ProjectFilePath; return $this->ProjectFilePath;
} }
/**
* @return ProjectConfiguration|null
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws MalformedJsonException
* @throws ProjectConfigurationNotFoundException
*/
public function getProjectConfiguration(): ?ProjectConfiguration
{
if($this->ProjectConfiguration == null)
$this->load();
return $this->ProjectConfiguration;
}
/**
* @return string|null
*/
public function getProjectPath(): ?string
{
return $this->ProjectPath;
}
/**
* Compiles the project into a package
*
* @param string $build_configuration
* @return string
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
* @throws MalformedJsonException
* @throws ProjectConfigurationNotFoundException
* @throws BuildConfigurationNotFoundException
* @throws BuildException
* @throws PackagePreparationFailedException
* @throws UnsupportedCompilerExtensionException
* @throws UnsupportedRunnerException
*/
public function build(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): string
{
return PackageCompiler::compile($this, $build_configuration);
}
} }

View file

@ -0,0 +1,171 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects;
use ncc\Exceptions\FileNotFoundException;
use ncc\Objects\ExecutionPointers\ExecutionPointer;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Utilities\Validate;
class ExecutionPointers
{
/**
* @var string
*/
private $Package;
/**
* @var string
*/
private $Version;
/**
* @var ExecutionPointer[]
*/
private $Pointers;
/**
* @param string|null $package
* @param string|null $version
*/
public function __construct(?string $package=null, ?string $version=null)
{
$this->Package = $package;
$this->Version = $version;
$this->Pointers = [];
}
/**
* Adds an Execution Unit as a pointer
*
* @param ExecutionUnit $unit
* @param bool $overwrite
* @return bool
*/
public function addUnit(ExecutionUnit $unit, string $bin_file, bool $overwrite=true): bool
{
if(Validate::exceedsPathLength($bin_file))
return false;
if(!file_exists($bin_file))
throw new FileNotFoundException('The file ' . $unit->Data . ' does not exist, cannot add unit \'' . $unit->ExecutionPolicy->Name . '\'');
if($overwrite)
{
$this->deleteUnit($unit->ExecutionPolicy->Name);
}
elseif($this->getUnit($unit->ExecutionPolicy->Name) !== null)
{
return false;
}
$this->Pointers[] = new ExecutionPointer($unit, $bin_file);
return true;
}
/**
* Deletes an existing unit from execution pointers
*
* @param string $name
* @return bool
*/
public function deleteUnit(string $name): bool
{
$unit = $this->getUnit($name);
if($unit == null)
return false;
$new_pointers = [];
foreach($this->Pointers as $pointer)
{
if($pointer->ExecutionPolicy->Name !== $name)
$new_pointers[] = $pointer;
}
$this->Pointers = $new_pointers;
return true;
}
/**
* Returns an existing unit from the pointers
*
* @param string $name
* @return ExecutionPointer|null
*/
public function getUnit(string $name): ?ExecutionPointer
{
foreach($this->Pointers as $pointer)
{
if($pointer->ExecutionPolicy->Name == $name)
return $pointer;
}
return null;
}
/**
* Returns an array of execution pointers that are currently configured
*
* @return array|ExecutionPointer[]
*/
public function getPointers(): array
{
return $this->Pointers;
}
/**
* Returns the version of the package that uses these execution policies.
*
* @return string
*/
public function getVersion(): string
{
return $this->Version;
}
/**
* Returns the name of the package that uses these execution policies
*
* @return string
*/
public function getPackage(): string
{
return $this->Package;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
$pointers = [];
foreach($this->Pointers as $pointer)
{
$pointers[] = $pointer->toArray($bytecode);
}
return $pointers;
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return ExecutionPointers
*/
public static function fromArray(array $data): self
{
$object = new self();
foreach($data as $datum)
{
$object->Pointers[] = ExecutionPointer::fromArray($datum);
}
return $object;
}
}

View file

@ -0,0 +1,78 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ExecutionPointers;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\Functions;
class ExecutionPointer
{
/**
* @var string
*/
public $ID;
/**
* The execution policy for this execution unit
*
* @var ExecutionPolicy
*/
public $ExecutionPolicy;
/**
* The file pointer for where the target script should be executed
*
* @var string
*/
public $FilePointer;
/**
* Public Constructor with optional ExecutionUnit parameter to construct object from
*
* @param ExecutionUnit|null $unit
*/
public function __construct(?ExecutionUnit $unit=null, ?string $bin_file=null)
{
if($unit == null)
return;
$this->ID = $unit->getID();
$this->ExecutionPolicy = $unit->ExecutionPolicy;
$this->FilePointer = $bin_file;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('id') : 'id') => $this->ID,
($bytecode ? Functions::cbc('execution_policy') : 'execution_policy') => $this->ExecutionPolicy->toArray($bytecode),
($bytecode ? Functions::cbc('file_pointer') : 'file_pointer') => $this->FilePointer,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return ExecutionPointer
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->ID = Functions::array_bc($data, 'id');
$object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy');
$object->FilePointer = Functions::array_bc($data, 'file_pointer');
return $object;
}
}

View file

@ -0,0 +1,61 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects;
class InstallationPaths
{
/**
* The path of where the package will be installed at
*
* @var string
*/
private $InstallationPath;
/**
* @param string $installation_path
*/
public function __construct(string $installation_path)
{
$this->InstallationPath = $installation_path;
}
/**
* Returns the data path where NCC's metadata & runtime information is stored
*
* @return string
*/
public function getDataPath(): string
{
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'ncc';
}
/**
* Returns the source path for where the package resides
*
* @return string
*/
public function getSourcePath(): string
{
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'src';
}
/**
* Returns the path for where executables are located
*
* @return string
*/
public function getBinPath(): string
{
return $this->InstallationPath . DIRECTORY_SEPARATOR . 'bin';
}
/**
* @return string
*/
public function getInstallationPath(): string
{
return $this->InstallationPath;
}
}

View file

@ -1,8 +1,14 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\NccVersionInformation; namespace ncc\Objects\NccVersionInformation;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\ComponentVersionNotFoundException; use ncc\Exceptions\ComponentVersionNotFoundException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use ncc\Utilities\IO;
class Component class Component
{ {
@ -25,18 +31,19 @@
* *
* @return string * @return string
* @throws ComponentVersionNotFoundException * @throws ComponentVersionNotFoundException
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/ */
public function getVersion(): string public function getVersion(): string
{ {
$third_party_path = NCC_EXEC_LOCATION . DIRECTORY_SEPARATOR . 'ThirdParty' . DIRECTORY_SEPARATOR; $third_party_path = NCC_EXEC_LOCATION . DIRECTORY_SEPARATOR . 'ThirdParty' . DIRECTORY_SEPARATOR;
$component_path = $third_party_path . $this->Vendor . DIRECTORY_SEPARATOR . $this->PackageName . DIRECTORY_SEPARATOR; $component_path = $third_party_path . $this->Vendor . DIRECTORY_SEPARATOR . $this->PackageName . DIRECTORY_SEPARATOR;
if(file_exists($component_path . 'VERSION') == false) if(!file_exists($component_path . 'VERSION'))
{
throw new ComponentVersionNotFoundException('The file \'' . $component_path . 'VERSION' . '\' does not exist'); throw new ComponentVersionNotFoundException('The file \'' . $component_path . 'VERSION' . '\' does not exist');
}
return file_get_contents($component_path . 'VERSION'); return IO::fread($component_path . 'VERSION');
} }
/** /**

View file

@ -4,17 +4,24 @@
namespace ncc\Objects; namespace ncc\Objects;
use Exception;
use ncc\Abstracts\EncoderType;
use ncc\Abstracts\PackageStructureVersions;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidPackageException; use ncc\Exceptions\InvalidPackageException;
use ncc\Exceptions\InvalidProjectConfigurationException; use ncc\Exceptions\InvalidProjectConfigurationException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PackageParsingException;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\Package\Header; use ncc\Objects\Package\Header;
use ncc\Objects\Package\Installer; use ncc\Objects\Package\Installer;
use ncc\Objects\Package\MagicBytes; use ncc\Objects\Package\MagicBytes;
use ncc\Objects\Package\MainExecutionPolicy;
use ncc\Objects\Package\Resource; use ncc\Objects\Package\Resource;
use ncc\Objects\ProjectConfiguration\Assembly; use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO;
use ncc\ZiProto\ZiProto; use ncc\ZiProto\ZiProto;
class Package class Package
@ -50,7 +57,7 @@
/** /**
* The Main Execution Policy object for the package if the package is an executable package. * The Main Execution Policy object for the package if the package is an executable package.
* *
* @var MainExecutionPolicy|null * @var string|null
*/ */
public $MainExecutionPolicy; public $MainExecutionPolicy;
@ -61,6 +68,13 @@
*/ */
public $Installer; public $Installer;
/**
* An array of execution units defined in the package
*
* @var ExecutionUnit[]
*/
public $ExecutionUnits;
/** /**
* An array of resources that the package depends on * An array of resources that the package depends on
* *
@ -83,6 +97,7 @@
$this->MagicBytes = new MagicBytes(); $this->MagicBytes = new MagicBytes();
$this->Header = new Header(); $this->Header = new Header();
$this->Assembly = new Assembly(); $this->Assembly = new Assembly();
$this->ExecutionUnits = [];
$this->Components = []; $this->Components = [];
$this->Dependencies = []; $this->Dependencies = [];
$this->Resources = []; $this->Resources = [];
@ -126,16 +141,141 @@
return true; return true;
} }
/**
* Attempts to find the execution unit with the given name
*
* @param string $name
* @return ExecutionUnit|null
*/
public function getExecutionUnit(string $name): ?ExecutionUnit
{
foreach($this->ExecutionUnits as $unit)
{
if($unit->ExecutionPolicy->Name == $name)
return $unit;
}
return null;
}
/** /**
* Writes the package contents to disk * Writes the package contents to disk
* *
* @param string $output_path * @param string $output_path
* @return void * @return void
* @throws IOException
*/ */
public function save(string $output_path): void public function save(string $output_path): void
{ {
$package_contents = $this->MagicBytes->toString() . ZiProto::encode($this->toArray(true)); $package_contents = $this->MagicBytes->toString() . ZiProto::encode($this->toArray(true));
file_put_contents($output_path, $package_contents); IO::fwrite($output_path, $package_contents, 0777);
}
/**
* Attempts to parse the specified package path and returns the object representation
* of the package, including with the MagicBytes representation that is in the
* file headers.
*
* @param string $path
* @return Package
* @throws FileNotFoundException
* @throws PackageParsingException
*/
public static function load(string $path): Package
{
if(!file_exists($path) || !is_file($path) || !is_readable($path))
{
throw new FileNotFoundException('The file ' . $path . ' does not exist or is not readable');
}
$handle = fopen($path, "rb");
$header = fread($handle, 256); // Read the first 256 bytes of the file
fclose($handle);
if(!strtoupper(substr($header, 0, 11)) == 'NCC_PACKAGE')
throw new PackageParsingException('The package \'' . $path . '\' does not appear to be a valid NCC Package (Missing Header)');
// Extract the package structure version
$package_structure_version = strtoupper(substr($header, 11, 3));
if(!in_array($package_structure_version, PackageStructureVersions::ALL))
throw new PackageParsingException('The package \'' . $path . '\' has a package structure version of ' . $package_structure_version . ' which is not supported by this version NCC');
// Extract the package encoding type and package type
$encoding_header = strtoupper(substr($header, 14, 5));
$encoding_type = substr($encoding_header, 0, 3);
$package_type = substr($encoding_header, 3, 2);
$magic_bytes = new MagicBytes();
$magic_bytes->PackageStructureVersion = $package_structure_version;
// Determine the encoding type
switch($encoding_type)
{
case '300':
$magic_bytes->Encoder = EncoderType::ZiProto;
$magic_bytes->IsCompressed = false;
$magic_bytes->IsEncrypted = false;
break;
case '301':
$magic_bytes->Encoder = EncoderType::ZiProto;
$magic_bytes->IsCompressed = true;
$magic_bytes->IsEncrypted = false;
break;
case '310':
$magic_bytes->Encoder = EncoderType::ZiProto;
$magic_bytes->IsCompressed = false;
$magic_bytes->IsEncrypted = true;
break;
case '311':
$magic_bytes->Encoder = EncoderType::ZiProto;
$magic_bytes->IsCompressed = true;
$magic_bytes->IsEncrypted = true;
break;
default:
throw new PackageParsingException('Cannot determine the encoding type for the package \'' . $path . '\' (Got ' . $encoding_type . ')');
}
// Determine the package type
switch($package_type)
{
case '40':
$magic_bytes->IsInstallable = true;
$magic_bytes->IsExecutable = false;
break;
case '41':
$magic_bytes->IsInstallable = false;
$magic_bytes->IsExecutable = true;
break;
case '42':
$magic_bytes->IsInstallable = true;
$magic_bytes->IsExecutable = true;
break;
default:
throw new PackageParsingException('Cannot determine the package type for the package \'' . $path . '\' (Got ' . $package_type . ')');
}
// TODO: Implement encryption and compression parsing
// Assuming all is good, load the entire fire into memory and parse its contents
try
{
$package = Package::fromArray(ZiProto::decode(substr(IO::fread($path), strlen($magic_bytes->toString()))));
}
catch(Exception $e)
{
throw new PackageParsingException('Cannot decode the contents of the package \'' . $path . '\', invalid encoding or the package is corrupted, ' . $e->getMessage(), $e);
}
$package->MagicBytes = $magic_bytes;
return $package;
} }
/** /**
@ -161,13 +301,17 @@
foreach($this->Resources as $resource) foreach($this->Resources as $resource)
$_resources[] = $resource->toArray($bytecode); $_resources[] = $resource->toArray($bytecode);
$_execution_units = [];
foreach($this->ExecutionUnits as $unit)
$_execution_units[] = $unit->toArray($bytecode);
return [ return [
($bytecode ? Functions::cbc('header') : 'header') => $this->Header?->toArray($bytecode), ($bytecode ? Functions::cbc('header') : 'header') => $this?->Header?->toArray($bytecode),
($bytecode ? Functions::cbc('assembly') : 'assembly') => $this->Assembly?->toArray($bytecode), ($bytecode ? Functions::cbc('assembly') : 'assembly') => $this?->Assembly?->toArray($bytecode),
($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $_dependencies, ($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $_dependencies,
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->MainExecutionPolicy?->toArray($bytecode), ($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this?->MainExecutionPolicy,
($bytecode ? Functions::cbc('installer') : 'installer') => $this->Installer?->toArray($bytecode), ($bytecode ? Functions::cbc('installer') : 'installer') => $this?->Installer?->toArray($bytecode),
($bytecode ? Functions::cbc('execution_units') : 'execution_units') => $_execution_units,
($bytecode ? Functions::cbc('resources') : 'resources') => $_resources, ($bytecode ? Functions::cbc('resources') : 'resources') => $_resources,
($bytecode ? Functions::cbc('components') : 'components') => $_components ($bytecode ? Functions::cbc('components') : 'components') => $_components
]; ];
@ -190,8 +334,6 @@
$object->Assembly = Assembly::fromArray($object->Assembly); $object->Assembly = Assembly::fromArray($object->Assembly);
$object->MainExecutionPolicy = Functions::array_bc($data, 'main_execution_policy'); $object->MainExecutionPolicy = Functions::array_bc($data, 'main_execution_policy');
if($object->MainExecutionPolicy !== null)
$object->MainExecutionPolicy = MainExecutionPolicy::fromArray($object->MainExecutionPolicy);
$object->Installer = Functions::array_bc($data, 'installer'); $object->Installer = Functions::array_bc($data, 'installer');
if($object->Installer !== null) if($object->Installer !== null)
@ -224,6 +366,15 @@
} }
} }
$_execution_units = Functions::array_bc($data, 'execution_units');
if($_execution_units !== null)
{
foreach($_execution_units as $unit)
{
$object->ExecutionUnits[] = ExecutionUnit::fromArray($unit);
}
}
return $object; return $object;
} }
} }

View file

@ -1,5 +1,7 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\Package; namespace ncc\Objects\Package;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
@ -33,12 +35,12 @@
* *
* @var string * @var string
*/ */
public $Checksum; private $Checksum;
/** /**
* The raw data of the component, this is to be processed by the compiler extension * The raw data of the component, this is to be processed by the compiler extension
* *
* @var string * @var mixed
*/ */
public $Data; public $Data;
@ -51,17 +53,32 @@
public function validateChecksum(): bool public function validateChecksum(): bool
{ {
if($this->Checksum === null) if($this->Checksum === null)
return false; return true; // Return true if the checksum is empty
if($this->Data === null) if($this->Data === null)
return false; return true; // Return true if the data is null
if(hash('sha1', $this->Data) !== $this->Checksum) if(hash('sha1', $this->Data, true) !== $this->Checksum)
return false; return false; // Return false if the checksum failed
return true; return true;
} }
/**
* Updates the checksum of the resource
*
* @return void
*/
public function updateChecksum(): void
{
$this->Checksum = null;
if(gettype($this->Data) == 'string')
{
$this->Checksum = hash('sha1', $this->Data, true);
}
}
/** /**
* Returns an array representation of the component. * Returns an array representation of the component.
* *

View file

@ -0,0 +1,71 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\Functions;
class ExecutionUnit
{
/**
* @var string|null
*/
private $ID;
/**
* The execution policy for this execution unit
*
* @var ExecutionPolicy
*/
public $ExecutionPolicy;
/**
* The data of the unit to execute
*
* @var string
*/
public $Data;
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('execution_policy') : 'execution_policy') => $this->ExecutionPolicy->toArray($bytecode),
($bytecode ? Functions::cbc('data') : 'data') => $this->Data,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return static
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->ExecutionPolicy = Functions::array_bc($data, 'execution_policy');
$object->Data = Functions::array_bc($data, 'data');
return $object;
}
/**
* @return string
*/
public function getID(): string
{
if($this->ID == null)
$this->ID = hash('sha1', $this->ExecutionPolicy->Name);
return $this->ID;
}
}

View file

@ -68,6 +68,9 @@
$object->RuntimeConstants = Functions::array_bc($data, 'runtime_constants'); $object->RuntimeConstants = Functions::array_bc($data, 'runtime_constants');
$object->CompilerVersion = Functions::array_bc($data, 'compiler_version'); $object->CompilerVersion = Functions::array_bc($data, 'compiler_version');
if($object->CompilerExtension !== null)
$object->CompilerExtension = Compiler::fromArray($object->CompilerExtension);
return $object; return $object;
} }
} }

View file

@ -1,18 +1,81 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\Package; namespace ncc\Objects\Package;
use ncc\Utilities\Functions;
class Installer class Installer
{ {
/**
* An array of execution policies to execute pre install
*
* @var string[]|null
*/
public $PreInstall;
/**
* An array of execution policies to execute post install
*
* @var string[]|null
*/
public $PostInstall;
/**
* An array of execution policies to execute pre uninstall
*
* @var string[]|null
*/
public $PreUninstall;
/**
* An array of execution policies to execute post uninstall
*
* @var string[]|null
*/
public $PostUninstall;
/**
* An array of execution policies to execute pre update
*
* @var string[]|null
*/
public $PreUpdate;
/**
* An array of execution policies to execute post update
*
* @var string[]|null
*/
public $PostUpdate;
/** /**
* Returns an array representation of the object * Returns an array representation of the object
* Returns null if all properties are not set
* *
* @param bool $bytecode * @param bool $bytecode
* @return array * @return array|null
*/ */
public function toArray(bool $bytecode=false): array public function toArray(bool $bytecode=false): ?array
{ {
return []; if(
$this->PreInstall == null && $this->PostInstall == null &&
$this->PreUninstall == null && $this->PostUninstall == null &&
$this->PreUpdate == null && $this->PostUpdate == null
)
{
return null;
}
return [
($bytecode ? Functions::cbc('pre_install') : 'pre_install') => ($this->PreInstall == null ? null : $this->PreInstall),
($bytecode ? Functions::cbc('post_install') : 'post_install') => ($this->PostInstall == null ? null : $this->PostInstall),
($bytecode ? Functions::cbc('pre_uninstall') : 'pre_uninstall') => ($this->PreUninstall == null ? null : $this->PreUninstall),
($bytecode? Functions::cbc('post_uninstall') : 'post_uninstall') => ($this->PostUninstall == null ? null : $this->PostUninstall),
($bytecode? Functions::cbc('pre_update') : 'pre_update') => ($this->PreUpdate == null ? null : $this->PreUpdate),
($bytecode? Functions::cbc('post_update') : 'post_update') => ($this->PostUpdate == null ? null : $this->PostUpdate)
];
} }
/** /**
@ -20,11 +83,19 @@
* *
* @param array $data * @param array $data
* @return Installer * @return Installer
* @noinspection DuplicatedCode
*/ */
public static function fromArray(array $data): self public static function fromArray(array $data): self
{ {
$object = new self(); $object = new self();
$object->PreInstall = Functions::array_bc($data, 'pre_install');
$object->PostInstall = Functions::array_bc($data, 'post_install');
$object->PreUninstall = Functions::array_bc($data, 'pre_uninstall');
$object->PostUninstall = Functions::array_bc($data, 'post_uninstall');
$object->PreUpdate = Functions::array_bc($data, 'pre_update');
$object->PostUpdate = Functions::array_bc($data, 'post_update');
return $object; return $object;
} }
} }

View file

@ -147,6 +147,12 @@
// NCC_PACKAGE1.030140 // NCC_PACKAGE1.030140
$magic_bytes .= '40'; $magic_bytes .= '40';
} }
else
{
// If no type is specified, default to installable only
// NCC_PACKAGE1.030140
$magic_bytes .= '40';
}
return $magic_bytes; return $magic_bytes;
} }

View file

@ -1,30 +0,0 @@
<?php
namespace ncc\Objects\Package;
class MainExecutionPolicy
{
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return MainExecutionPolicy
*/
public static function fromArray(array $data): self
{
$object = new self();
return $object;
}
}

View file

@ -21,7 +21,7 @@
* *
* @var string * @var string
*/ */
public $Checksum; private $Checksum;
/** /**
* The raw data of the resource * The raw data of the resource
@ -44,12 +44,27 @@
if($this->Data === null) if($this->Data === null)
return false; return false;
if(hash('sha1', $this->Data) !== $this->Checksum) if(hash('sha1', $this->Data, true) !== $this->Checksum)
return false; return false;
return true; return true;
} }
/**
* Updates the checksum of the resource
*
* @return void
*/
public function updateChecksum(): void
{
$this->Checksum = null;
if(gettype($this->Data) == 'string')
{
$this->Checksum = hash('sha1', $this->Data, true);
}
}
/** /**
* Returns an array representation of the resource. * Returns an array representation of the resource.
* *

View file

@ -0,0 +1,194 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects;
use ncc\Abstracts\Versions;
use ncc\Objects\PackageLock\PackageEntry;
use ncc\Utilities\Functions;
class PackageLock
{
/**
* The version of package lock file structure
*
* @var string
*/
public $PackageLockVersion;
/**
* The Unix Timestamp for when this package lock file was last updated
*
* @var int
*/
public $LastUpdatedTimestamp;
/**
* An array of installed packages in the PackageLock file
*
* @var PackageEntry[]
*/
public $Packages;
/**
* Public Constructor
*/
public function __construct()
{
$this->PackageLockVersion = Versions::PackageLockVersion;
$this->Packages = [];
}
/**
* Updates the version and timestamp
*
* @return void
*/
private function update(): void
{
$this->PackageLockVersion = Versions::PackageLockVersion;
$this->LastUpdatedTimestamp = time();
}
/**
* @param Package $package
* @param string $install_path
* @return void
*/
public function addPackage(Package $package, string $install_path): void
{
if(!isset($this->Packages[$package->Assembly->Package]))
{
$package_entry = new PackageEntry();
$package_entry->addVersion($package, $install_path, true);
$package_entry->Name = $package->Assembly->Package;
$this->Packages[$package->Assembly->Package] = $package_entry;
$this->update();
return;
}
$this->Packages[$package->Assembly->Package]->addVersion($package, true);
$this->update();
}
/**
* Removes a package version entry, removes the entire entry if there are no installed versions
*
* @param string $package
* @param string $version
* @return bool
*/
public function removePackageVersion(string $package, string $version): bool
{
if(isset($this->Packages[$package]))
{
$r = $this->Packages[$package]->removeVersion($version);
// Remove the entire package entry if there's no installed versions
if($this->Packages[$package]->getLatestVersion() == null && $r)
{
unset($this->Packages[$package]);
}
$this->update();
return $r;
}
return false;
}
/**
* Removes an entire package entry
*
* @param string $package
* @return bool
*/
public function removePackage(string $package): bool
{
if(isset($this->Packages[$package]))
{
unset($this->Packages[$package]);
return true;
}
return false;
}
/**
* Gets an existing package entry, returns null if no such entry exists
*
* @param string $package
* @return PackageEntry|null
*/
public function getPackage(string $package): ?PackageEntry
{
if(isset($this->Packages[$package]))
{
return $this->Packages[$package];
}
return null;
}
/**
* Returns an array of all packages and their installed versions
*
* @return array
*/
public function getPackages(): array
{
$results = [];
foreach($this->Packages as $package => $entry)
$results[$package] = $entry->getVersions();
return $results;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
$package_entries = [];
foreach($this->Packages as $entry)
{
$package_entries[] = $entry->toArray($bytecode);
}
return [
($bytecode ? Functions::cbc('package_lock_version') : 'package_lock_version') => $this->PackageLockVersion,
($bytecode ? Functions::cbc('last_updated_timestamp') : 'last_updated_timestamp') => $this->LastUpdatedTimestamp,
($bytecode ? Functions::cbc('packages') : 'packages') => $package_entries
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return static
*/
public static function fromArray(array $data): self
{
$object = new self();
$packages = Functions::array_bc($data, 'packages');
if($packages !== null)
{
foreach($packages as $_datum)
{
$entry = PackageEntry::fromArray($_datum);
$object->Packages[$entry->Name] = $entry;
}
}
$object->PackageLockVersion = Functions::array_bc($data, 'package_lock_version');
$object->LastUpdatedTimestamp = Functions::array_bc($data, 'last_updated_timestamp');
return $object;
}
}

View file

@ -0,0 +1,64 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\PackageLock;
use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Utilities\Functions;
class DependencyEntry
{
/**
* The name of the package dependency
*
* @var string
*/
public $PackageName;
/**
* The version of the package dependency
*
* @var string
*/
public $Version;
public function __construct(?Dependency $dependency=null)
{
if($dependency !== null)
{
$this->PackageName = $dependency->Name;
$this->Version = $dependency->Version;
}
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('package_name') : 'package_name') => $this->PackageName,
($bytecode ? Functions::cbc('version') : 'version') => $this->Version,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return DependencyEntry
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->PackageName = Functions::array_bc($data, 'package_name');
$object->Version = Functions::array_bc($data, 'version');
return $object;
}
}

View file

@ -0,0 +1,235 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\PackageLock;
use ncc\Exceptions\VersionNotFoundException;
use ncc\Objects\Package;
use ncc\ThirdParty\jelix\Version\VersionComparator;
use ncc\Utilities\Functions;
class PackageEntry
{
/**
* The name of the package that's installed
*
* @var string
*/
public $Name;
/**
* The latest version of the package entry, this is updated automatically
*
* @var string|null
*/
private $LatestVersion;
/**
* An array of installed versions for this package
*
* @var VersionEntry[]
*/
public $Versions;
/**
* Public Constructor
*/
public function __construct()
{
$this->Versions = [];
}
/**
* Searches and returns a version of the package
*
* @param string $version
* @param bool $throw_exception
* @return VersionEntry|null
* @throws VersionNotFoundException
*/
public function getVersion(string $version, bool $throw_exception=false): ?VersionEntry
{
foreach($this->Versions as $versionEntry)
{
if($versionEntry->Version == $version)
{
return $versionEntry;
}
}
if($throw_exception)
throw new VersionNotFoundException('The version entry is not found');
return null;
}
/**
* Removes version entry from the package
*
* @param string $version
* @return bool
* @noinspection PhpUnused
*/
public function removeVersion(string $version): bool
{
$count = 0;
$found_node = false;
foreach($this->Versions as $versionEntry)
{
if($versionEntry->Version == $version)
{
$found_node = true;
break;
}
$count += 1;
}
if($found_node)
{
unset($this->Versions[$count]);
$this->updateLatestVersion();
return true;
}
return false;
}
/**
* Adds a new version entry to the package, if overwrite is true then
* the entry will be overwritten if it exists, otherwise it will return
* false.
*
* @param Package $package
* @param string $install_path
* @param bool $overwrite
* @return bool
*/
public function addVersion(Package $package, string $install_path, bool $overwrite=false): bool
{
try
{
if ($this->getVersion($package->Assembly->Version) !== null)
{
if (!$overwrite) return false;
$this->removeVersion($package->Assembly->Version);
}
}
catch (VersionNotFoundException $e)
{
unset($e);
}
$version = new VersionEntry();
$version->Version = $package->Assembly->Version;
$version->Compiler = $package->Header->CompilerExtension;
$version->ExecutionUnits = $package->ExecutionUnits;
$version->MainExecutionPolicy = $package->MainExecutionPolicy;
$version->Location = $install_path;
foreach($package->Dependencies as $dependency)
{
$version->Dependencies[] = new DependencyEntry($dependency);
}
$this->Versions[] = $version;
$this->updateLatestVersion();
return true;
}
/**
* Updates and returns the latest version of this package entry
*
* @return void
*/
private function updateLatestVersion(): void
{
$latest_version = null;
foreach($this->Versions as $version)
{
$version = $version->Version;
if($latest_version == null)
{
$latest_version = $version;
continue;
}
if(VersionComparator::compareVersion($version, $latest_version))
$latest_version = $version;
}
$this->LatestVersion = $latest_version;
}
/**
* @return string|null
*/
public function getLatestVersion(): ?string
{
return $this->LatestVersion;
}
/**
* Returns an array of all versions installed
*
* @return array
*/
public function getVersions(): array
{
$r = [];
foreach($this->Versions as $version)
{
$r[] = $version->Version;
}
return $r;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
$versions = [];
foreach($this->Versions as $version)
{
$versions[] = $version->toArray($bytecode);
}
return [
($bytecode ? Functions::cbc('name') : 'name') => $this->Name,
($bytecode ? Functions::cbc('latest_version') : 'latest_version') => $this->LatestVersion,
($bytecode ? Functions::cbc('versions') : 'versions') => $versions,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return PackageEntry
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Name = Functions::array_bc($data, 'name');
$object->LatestVersion = Functions::array_bc($data, 'latest_version');
$versions = Functions::array_bc($data, 'versions');
if($versions !== null)
{
foreach($versions as $_datum)
{
$object->Versions[] = VersionEntry::fromArray($_datum);
}
}
return $object;
}
}

View file

@ -0,0 +1,126 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\PackageLock;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\Compiler;
use ncc\Utilities\Functions;
class VersionEntry
{
/**
* The version of the package that's installed
*
* @var string
*/
public $Version;
/**
* The compiler extension used for the package
*
* @var Compiler
*/
public $Compiler;
/**
* An array of packages that this package depends on
*
* @var DependencyEntry[]
*/
public $Dependencies;
/**
* @var ExecutionUnit[]
*/
public $ExecutionUnits;
/**
* The main execution policy for this version entry if applicable
*
* @var string|null
*/
public $MainExecutionPolicy;
/**
* The path where the package is located
*
* @var string
*/
public $Location;
/**
* Public Constructor
*/
public function __construct()
{
$this->Dependencies = [];
$this->ExecutionUnits = [];
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
$dependencies = [];
foreach($this->Dependencies as $dependency)
{
$dependencies[] = $dependency->toArray($bytecode);
}
$execution_units = [];
foreach($this->ExecutionUnits as $executionUnit)
{
$execution_units[] = $executionUnit->toArray($bytecode);
}
return [
($bytecode ? Functions::cbc('version') : 'version') => $this->Version,
($bytecode ? Functions::cbc('compiler') : 'compiler') => $this->Compiler->toArray($bytecode),
($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $dependencies,
($bytecode ? Functions::cbc('execution_units') : 'execution_units') => $execution_units,
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->MainExecutionPolicy,
($bytecode ? Functions::cbc('location') : 'location') => $this->Location,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return VersionEntry
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Version = Functions::array_bc($data, 'version');
$object->Compiler = Compiler::fromArray(Functions::array_bc($data, 'compiler'));
$object->MainExecutionPolicy = Functions::array_bc($data, 'main_execution_policy');
$object->Location = Functions::array_bc($data, 'location');
$dependencies = Functions::array_bc($data, 'dependencies');
if($dependencies !== null)
{
foreach($dependencies as $_datum)
{
$object->Dependencies[] = DependencyEntry::fromArray($_datum);
}
}
$execution_units = Functions::array_bc($data, 'execution_units');
if($execution_units !== null)
{
foreach($execution_units as $_datum)
{
$object->ExecutionUnits[] = ExecutionUnit::fromArray($_datum);
}
}
return $object;
}
}

View file

@ -1,18 +1,29 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects; namespace ncc\Objects;
use Exception;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidConstantNameException; use ncc\Exceptions\InvalidConstantNameException;
use ncc\Exceptions\InvalidProjectBuildConfiguration; use ncc\Exceptions\InvalidProjectBuildConfiguration;
use ncc\Exceptions\InvalidProjectConfigurationException; use ncc\Exceptions\InvalidProjectConfigurationException;
use ncc\Exceptions\InvalidPropertyValueException; use ncc\Exceptions\InvalidPropertyValueException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\MalformedJsonException; use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\RuntimeException; use ncc\Exceptions\RuntimeException;
use ncc\Exceptions\UndefinedExecutionPolicyException;
use ncc\Exceptions\UnsupportedCompilerExtensionException; use ncc\Exceptions\UnsupportedCompilerExtensionException;
use ncc\Exceptions\UnsupportedExtensionVersionException; use ncc\Exceptions\UnsupportedExtensionVersionException;
use ncc\Objects\ProjectConfiguration\Assembly; use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Objects\ProjectConfiguration\Build; use ncc\Objects\ProjectConfiguration\Build;
use ncc\Objects\ProjectConfiguration\BuildConfiguration;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Objects\ProjectConfiguration\Installer;
use ncc\Objects\ProjectConfiguration\Project; use ncc\Objects\ProjectConfiguration\Project;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
@ -36,6 +47,20 @@
*/ */
public $Assembly; public $Assembly;
/**
* An array of execution policies
*
* @var ExecutionPolicy[]
*/
public $ExecutionPolicies;
/**
* Execution Policies to execute by the NCC installer
*
* @var Installer|null
*/
public $Installer;
/** /**
* Build configuration for the project * Build configuration for the project
* *
@ -50,6 +75,7 @@
{ {
$this->Project = new Project(); $this->Project = new Project();
$this->Assembly = new Assembly(); $this->Assembly = new Assembly();
$this->ExecutionPolicies = [];
$this->Build = new Build(); $this->Build = new Build();
} }
@ -58,13 +84,15 @@
* *
* @param bool $throw_exception * @param bool $throw_exception
* @return bool * @return bool
* @throws BuildConfigurationNotFoundException
* @throws InvalidConstantNameException
* @throws InvalidProjectBuildConfiguration
* @throws InvalidProjectConfigurationException * @throws InvalidProjectConfigurationException
* @throws InvalidPropertyValueException * @throws InvalidPropertyValueException
* @throws RuntimeException * @throws RuntimeException
* @throws UndefinedExecutionPolicyException
* @throws UnsupportedCompilerExtensionException * @throws UnsupportedCompilerExtensionException
* @throws UnsupportedExtensionVersionException * @throws UnsupportedExtensionVersionException
* @throws InvalidProjectBuildConfiguration
* @throws InvalidConstantNameException
*/ */
public function validate(bool $throw_exception=True): bool public function validate(bool $throw_exception=True): bool
{ {
@ -77,9 +105,170 @@
if(!$this->Build->validate($throw_exception)) if(!$this->Build->validate($throw_exception))
return false; return false;
try
{
$this->getRequiredExecutionPolicies(BuildConfigurationValues::AllConfigurations);
}
catch(Exception $e)
{
if($throw_exception)
throw $e;
return false;
}
return true; return true;
} }
/**
* @param string $name
* @return ExecutionPolicy|null
*/
private function getExecutionPolicy(string $name): ?ExecutionPolicy
{
foreach($this->ExecutionPolicies as $executionPolicy)
{
if($executionPolicy->Name == $name)
return $executionPolicy;
}
return null;
}
/**
* Runs a check on the project configuration and determines what policies are required
*
* @param string $build_configuration
* @return array
* @throws BuildConfigurationNotFoundException
* @throws UndefinedExecutionPolicyException
*/
public function getRequiredExecutionPolicies(string $build_configuration=BuildConfigurationValues::DefaultConfiguration): array
{
if($this->ExecutionPolicies == null || count($this->ExecutionPolicies) == 0)
return [];
$defined_polices = [];
$required_policies = [];
/** @var ExecutionPolicy $execution_policy */
foreach($this->ExecutionPolicies as $execution_policy)
{
$defined_polices[] = $execution_policy->Name;
$execution_policy->validate();
}
// Check the installer by batch
if($this->Installer !== null)
{
$array_rep = $this->Installer->toArray();
/** @var string[] $value */
foreach($array_rep as $key => $value)
{
if($value == null || count($value) == 0)
continue;
foreach($value as $unit)
{
if(!in_array($unit, $defined_polices))
throw new UndefinedExecutionPolicyException('The property \'' . $key . '\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
if(!in_array($unit, $required_policies))
$required_policies[] = $unit;
}
}
}
if($this->Build->PreBuild !== null && count($this->Build->PostBuild) > 0)
{
foreach($this->Build->PostBuild as $unit)
{
if(!in_array($unit, $defined_polices))
throw new UndefinedExecutionPolicyException('The property \'build.pre_build\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
if(!in_array($unit, $required_policies))
$required_policies[] = $unit;
}
}
if($this->Build->PostBuild !== null && count($this->Build->PostBuild) > 0)
{
foreach($this->Build->PostBuild as $unit)
{
if(!in_array($unit, $defined_polices))
throw new UndefinedExecutionPolicyException('The property \'build.pre_build\' in the project configuration calls for an undefined execution policy \'' . $unit . '\'');
if(!in_array($unit, $required_policies))
$required_policies[] = $unit;
}
}
switch($build_configuration)
{
case BuildConfigurationValues::AllConfigurations:
/** @var BuildConfiguration $configuration */
foreach($this->Build->Configurations as $configuration)
{
foreach($this->processBuildPolicies($configuration, $defined_polices) as $policy)
{
if(!in_array($policy, $required_policies))
$required_policies[] = $policy;
}
}
break;
default:
$configuration = $this->Build->getBuildConfiguration($build_configuration);
foreach($this->processBuildPolicies($configuration, $defined_polices) as $policy)
{
if(!in_array($policy, $required_policies))
$required_policies[] = $policy;
}
break;
}
foreach($required_policies as $policy)
{
$execution_policy = $this->getExecutionPolicy($policy);
if($execution_policy->ExitHandlers !== null)
{
if(
$execution_policy->ExitHandlers->Success !== null &&
$execution_policy->ExitHandlers->Success->Run !== null
)
{
if(!in_array($execution_policy->ExitHandlers->Success->Run, $defined_polices))
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Success exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Success->Run . '\'');
if(!in_array($execution_policy->ExitHandlers->Success->Run, $required_policies))
$required_policies[] = $execution_policy->ExitHandlers->Success->Run;
}
if(
$execution_policy->ExitHandlers->Warning !== null &&
$execution_policy->ExitHandlers->Warning->Run !== null
)
{
if(!in_array($execution_policy->ExitHandlers->Warning->Run, $defined_polices))
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Warning exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Warning->Run . '\'');
if(!in_array($execution_policy->ExitHandlers->Warning->Run, $required_policies))
$required_policies[] = $execution_policy->ExitHandlers->Warning->Run;
}
if(
$execution_policy->ExitHandlers->Error !== null &&
$execution_policy->ExitHandlers->Error->Run !== null
)
{
if(!in_array($execution_policy->ExitHandlers->Error->Run, $defined_polices))
throw new UndefinedExecutionPolicyException('The execution policy \'' . $execution_policy->Name . '\' Error exit handler points to a undefined execution policy \'' . $execution_policy->ExitHandlers->Error->Run . '\'');
if(!in_array($execution_policy->ExitHandlers->Error->Run, $required_policies))
$required_policies[] = $execution_policy->ExitHandlers->Error->Run;
}
}
}
return $required_policies;
}
/** /**
* Returns an array representation of the object * Returns an array representation of the object
* *
@ -88,9 +277,15 @@
*/ */
public function toArray(bool $bytecode=false): array public function toArray(bool $bytecode=false): array
{ {
$execution_policies = [];
foreach($this->ExecutionPolicies as $executionPolicy)
{
$execution_policies[$executionPolicy->Name] = $executionPolicy->toArray($bytecode);
}
return [ return [
($bytecode ? Functions::cbc('project') : 'project') => $this->Project->toArray($bytecode), ($bytecode ? Functions::cbc('project') : 'project') => $this->Project->toArray($bytecode),
($bytecode ? Functions::cbc('assembly') : 'assembly') => $this->Assembly->toArray($bytecode), ($bytecode ? Functions::cbc('assembly') : 'assembly') => $this->Assembly->toArray($bytecode),
($bytecode ? Functions::cbc('execution_policies') : 'execution_policies') => $execution_policies,
($bytecode ? Functions::cbc('build') : 'build') => $this->Build->toArray($bytecode), ($bytecode ? Functions::cbc('build') : 'build') => $this->Build->toArray($bytecode),
]; ];
} }
@ -128,7 +323,26 @@
$ProjectConfigurationObject->Project = Project::fromArray(Functions::array_bc($data, 'project')); $ProjectConfigurationObject->Project = Project::fromArray(Functions::array_bc($data, 'project'));
$ProjectConfigurationObject->Assembly = Assembly::fromArray(Functions::array_bc($data, 'assembly')); $ProjectConfigurationObject->Assembly = Assembly::fromArray(Functions::array_bc($data, 'assembly'));
$ProjectConfigurationObject->ExecutionPolicies = Functions::array_bc($data, 'execution_policies');
$ProjectConfigurationObject->Build = Build::fromArray(Functions::array_bc($data, 'build')); $ProjectConfigurationObject->Build = Build::fromArray(Functions::array_bc($data, 'build'));
$ProjectConfigurationObject->Installer = Functions::array_bc($data, 'installer');
if($ProjectConfigurationObject->Installer !== null)
$ProjectConfigurationObject->Installer = Installer::fromArray($ProjectConfigurationObject->Installer);
if($ProjectConfigurationObject->ExecutionPolicies == null)
{
$ProjectConfigurationObject->ExecutionPolicies = [];
}
else
{
$policies = [];
foreach($ProjectConfigurationObject->ExecutionPolicies as $policy)
{
$policies[] = ExecutionPolicy::fromArray($policy);
}
$ProjectConfigurationObject->ExecutionPolicies = $policies;
}
return $ProjectConfigurationObject; return $ProjectConfigurationObject;
} }
@ -140,10 +354,45 @@
* @return ProjectConfiguration * @return ProjectConfiguration
* @throws FileNotFoundException * @throws FileNotFoundException
* @throws MalformedJsonException * @throws MalformedJsonException
* @throws AccessDeniedException
* @throws IOException
* @noinspection PhpUnused * @noinspection PhpUnused
*/ */
public static function fromFile(string $path): ProjectConfiguration public static function fromFile(string $path): ProjectConfiguration
{ {
return ProjectConfiguration::fromArray(Functions::loadJsonFile($path, Functions::FORCE_ARRAY)); return ProjectConfiguration::fromArray(Functions::loadJsonFile($path, Functions::FORCE_ARRAY));
} }
/**
* @param BuildConfiguration $configuration
* @param array $defined_polices
* @return array
* @throws UndefinedExecutionPolicyException
*/
private function processBuildPolicies(BuildConfiguration $configuration, array $defined_polices): array
{
$required_policies = [];
if ($configuration->PreBuild !== null && count($configuration->PreBuild) > 0)
{
foreach ($configuration->PreBuild as $unit)
{
if (!in_array($unit, $defined_polices))
throw new UndefinedExecutionPolicyException('The property \'pre_build\' in the build configuration \'' . $configuration->Name . '\' calls for an undefined execution policy \'' . $unit . '\'');
$required_policies[] = $unit;
}
}
if ($configuration->PostBuild !== null && count($configuration->PostBuild) > 0)
{
foreach ($configuration->PostBuild as $unit)
{
if (!in_array($unit, $defined_polices))
throw new UndefinedExecutionPolicyException('The property \'pre_build\' in the build configuration \'' . $configuration->Name . '\' calls for an undefined execution policy \'' . $unit . '\'');
$required_policies[] = $unit;
}
}
return $required_policies;
}
} }

View file

@ -4,6 +4,7 @@
namespace ncc\Objects\ProjectConfiguration; namespace ncc\Objects\ProjectConfiguration;
use ncc\Abstracts\Options\BuildConfigurationValues;
use ncc\Exceptions\BuildConfigurationNotFoundException; use ncc\Exceptions\BuildConfigurationNotFoundException;
use ncc\Exceptions\InvalidConstantNameException; use ncc\Exceptions\InvalidConstantNameException;
use ncc\Exceptions\InvalidProjectBuildConfiguration; use ncc\Exceptions\InvalidProjectBuildConfiguration;
@ -51,6 +52,13 @@
*/ */
public $Scope; public $Scope;
/**
* The execution policy to use as the main execution point
*
* @var string|null
*/
public $Main;
/** /**
* An array of constants to define by default * An array of constants to define by default
* *
@ -58,6 +66,20 @@
*/ */
public $DefineConstants; public $DefineConstants;
/**
* An array of execution policies to execute pre build
*
* @var string[]
*/
public $PreBuild;
/**
* An array of execution policies to execute post build
*
* @var string[]
*/
public $PostBuild;
/** /**
* An array of dependencies that are required by default * An array of dependencies that are required by default
* *
@ -125,6 +147,7 @@
* Returns an array of all the build configurations defined in the project configuration * Returns an array of all the build configurations defined in the project configuration
* *
* @return array * @return array
* @noinspection PhpUnused
*/ */
public function getBuildConfigurations(): array public function getBuildConfigurations(): array
{ {
@ -148,6 +171,9 @@
*/ */
public function getBuildConfiguration(string $name): BuildConfiguration public function getBuildConfiguration(string $name): BuildConfiguration
{ {
if($name == BuildConfigurationValues::DefaultConfiguration)
$name = $this->DefaultConfiguration;
foreach($this->Configurations as $configuration) foreach($this->Configurations as $configuration)
{ {
if($configuration->Name == $name) if($configuration->Name == $name)
@ -174,7 +200,10 @@
$ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles; $ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles;
$ReturnResults[($bytecode ? Functions::cbc('options') : 'options')] = $this->Options; $ReturnResults[($bytecode ? Functions::cbc('options') : 'options')] = $this->Options;
$ReturnResults[($bytecode ? Functions::cbc('scope') : 'scope')] = $this->Scope; $ReturnResults[($bytecode ? Functions::cbc('scope') : 'scope')] = $this->Scope;
$ReturnResults[($bytecode ? Functions::cbc('main') : 'main')] = $this->Main;
$ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants; $ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants;
$ReturnResults[($bytecode ? Functions::cbc('pre_build') : 'pre_build')] = $this->PreBuild;
$ReturnResults[($bytecode ? Functions::cbc('post_build') : 'post_build')] = $this->PostBuild;
$ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = []; $ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = [];
foreach($this->Dependencies as $dependency) foreach($this->Dependencies as $dependency)
@ -207,7 +236,10 @@
$BuildObject->ExcludeFiles = (Functions::array_bc($data, 'exclude_files') ?? []); $BuildObject->ExcludeFiles = (Functions::array_bc($data, 'exclude_files') ?? []);
$BuildObject->Options = (Functions::array_bc($data, 'options') ?? []); $BuildObject->Options = (Functions::array_bc($data, 'options') ?? []);
$BuildObject->Scope = Functions::array_bc($data, 'scope'); $BuildObject->Scope = Functions::array_bc($data, 'scope');
$BuildObject->Main = Functions::array_bc($data, 'main');
$BuildObject->DefineConstants = (Functions::array_bc($data, 'define_constants') ?? []); $BuildObject->DefineConstants = (Functions::array_bc($data, 'define_constants') ?? []);
$BuildObject->PreBuild = (Functions::array_bc($data, 'pre_build') ?? []);
$BuildObject->PostBuild = (Functions::array_bc($data, 'post_build') ?? []);
if(Functions::array_bc($data, 'dependencies') !== null) if(Functions::array_bc($data, 'dependencies') !== null)
{ {

View file

@ -47,6 +47,20 @@
*/ */
public $ExcludeFiles; public $ExcludeFiles;
/**
* An array of policies to execute pre-building the package
*
* @var string[]|string
*/
public $PreBuild;
/**
* An array of policies to execute post-building the package
*
* @var string
*/
public $PostBuild;
/** /**
* Dependencies required for the build configuration, cannot conflict with the * Dependencies required for the build configuration, cannot conflict with the
* default dependencies * default dependencies
@ -64,6 +78,8 @@
$this->OutputPath = 'build'; $this->OutputPath = 'build';
$this->DefineConstants = []; $this->DefineConstants = [];
$this->ExcludeFiles = []; $this->ExcludeFiles = [];
$this->PreBuild = [];
$this->PostBuild = [];
$this->Dependencies = []; $this->Dependencies = [];
} }
@ -84,6 +100,7 @@
$ReturnResults[($bytecode ? Functions::cbc('output_path') : 'output_path')] = $this->OutputPath; $ReturnResults[($bytecode ? Functions::cbc('output_path') : 'output_path')] = $this->OutputPath;
$ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants; $ReturnResults[($bytecode ? Functions::cbc('define_constants') : 'define_constants')] = $this->DefineConstants;
$ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles; $ReturnResults[($bytecode ? Functions::cbc('exclude_files') : 'exclude_files')] = $this->ExcludeFiles;
$ReturnResults[($bytecode ? Functions::cbc('pre_build') : 'pre_build')] = $this->PreBuild;
$ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = []; $ReturnResults[($bytecode ? Functions::cbc('dependencies') : 'dependencies')] = [];
foreach($this->Dependencies as $dependency) foreach($this->Dependencies as $dependency)
@ -105,37 +122,31 @@
$BuildConfigurationObject = new BuildConfiguration(); $BuildConfigurationObject = new BuildConfiguration();
if(Functions::array_bc($data, 'name') !== null) if(Functions::array_bc($data, 'name') !== null)
{
$BuildConfigurationObject->Name = Functions::array_bc($data, 'name'); $BuildConfigurationObject->Name = Functions::array_bc($data, 'name');
}
if(Functions::array_bc($data, 'options') !== null) if(Functions::array_bc($data, 'options') !== null)
{
$BuildConfigurationObject->Options = Functions::array_bc($data, 'options'); $BuildConfigurationObject->Options = Functions::array_bc($data, 'options');
}
if(Functions::array_bc($data, 'output_path') !== null) if(Functions::array_bc($data, 'output_path') !== null)
{
$BuildConfigurationObject->OutputPath = Functions::array_bc($data, 'output_path'); $BuildConfigurationObject->OutputPath = Functions::array_bc($data, 'output_path');
}
if(Functions::array_bc($data, 'define_constants') !== null) if(Functions::array_bc($data, 'define_constants') !== null)
{
$BuildConfigurationObject->DefineConstants = Functions::array_bc($data, 'define_constants'); $BuildConfigurationObject->DefineConstants = Functions::array_bc($data, 'define_constants');
}
if(Functions::array_bc($data, 'exclude_files') !== null) if(Functions::array_bc($data, 'exclude_files') !== null)
{
$BuildConfigurationObject->ExcludeFiles = Functions::array_bc($data, 'exclude_files'); $BuildConfigurationObject->ExcludeFiles = Functions::array_bc($data, 'exclude_files');
}
if(Functions::array_bc($data, 'pre_build') !== null)
$BuildConfigurationObject->PreBuild = Functions::array_bc($data, 'pre_build');
if(Functions::array_bc($data, 'post_build') !== null)
$BuildConfigurationObject->PostBuild = Functions::array_bc($data, 'post_build');
if(Functions::array_bc($data, 'dependencies') !== null) if(Functions::array_bc($data, 'dependencies') !== null)
{ {
foreach(Functions::array_bc($data, 'dependencies') as $item) foreach(Functions::array_bc($data, 'dependencies') as $item)
{
$BuildConfigurationObject->Dependencies[] = Dependency::fromArray($item); $BuildConfigurationObject->Dependencies[] = Dependency::fromArray($item);
} }
}
return $BuildConfigurationObject; return $BuildConfigurationObject;
} }

View file

@ -0,0 +1,98 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ProjectConfiguration;
use ncc\Objects\InstallationPaths;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\Execute;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy\ExitHandlers;
use ncc\Utilities\Functions;
class ExecutionPolicy
{
/**
* The unique name of the execution policy
*
* @var string
*/
public $Name;
/**
* The name of a supported runner instance
*
* @var string
*/
public $Runner;
/**
* The message to display when the policy is invoked
*
* @var string|null
*/
public $Message;
/**
* The execution process of the policy
*
* @var Execute
*/
public $Execute;
/**
* The configuration for exit handling
*
* @var ExitHandlers
*/
public $ExitHandlers;
/**
* @param bool $throw_exception
* @return bool
*/
public function validate(bool $throw_exception=True): bool
{
// TODO: Implement validation method
return true;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('name') : 'name') => $this->Name,
($bytecode ? Functions::cbc('runner') : 'runner') => $this->Runner,
($bytecode ? Functions::cbc('message') : 'message') => $this->Message,
($bytecode ? Functions::cbc('exec') : 'exec') => $this->Execute?->toArray($bytecode),
($bytecode ? Functions::cbc('exit_handlers') : 'exit_handlers') => $this->ExitHandlers?->toArray($bytecode),
];
}
/**
* @param array $data
* @return ExecutionPolicy
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Name = Functions::array_bc($data, 'name');
$object->Runner = Functions::array_bc($data, 'runner');
$object->Message = Functions::array_bc($data, 'message');
$object->Execute = Functions::array_bc($data, 'exec');
$object->ExitHandlers = Functions::array_bc($data, 'exit_handlers');
if($object->Execute !== null)
$object->Execute = Execute::fromArray($object->Execute);
if($object->ExitHandlers !== null)
$object->ExitHandlers = ExitHandlers::fromArray($object->ExitHandlers);
return $object;
}
}

View file

@ -0,0 +1,103 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\Functions;
class Execute
{
/**
* The target file to execute
*
* @var string
*/
public $Target;
/**
* The working directory to execute the policy in, if not specified the
* value "%CWD%" will be used as the default
*
* @var string|null
*/
public $WorkingDirectory;
/**
* An array of options to pass on to the process
*
* @var array|null
*/
public $Options;
/**
* Indicates if the output should be displayed or suppressed
*
* @var bool|null
*/
public $Silent;
/**
* Indicates if the process should run in Tty mode (Overrides Silent mode)
*
* @var bool|null
*/
public $Tty;
/**
* The number of seconds to wait before giving up on the process, will automatically execute the error handler
* if one is set.
*
* @var int
*/
public $Timeout;
/**
* Public Constructor
*/
public function __construct()
{
$this->Tty = false;
$this->Silent = false;
$this->Timeout = null;
$this->WorkingDirectory = "%CWD%";
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('target') : 'target') => $this->Target,
($bytecode ? Functions::cbc('working_directory') : 'working_directory') => $this->WorkingDirectory,
($bytecode ? Functions::cbc('options') : 'options') => $this->Options,
($bytecode ? Functions::cbc('silent') : 'silent') => $this->Silent,
($bytecode ? Functions::cbc('tty') : 'tty') => $this->Tty,
($bytecode ? Functions::cbc('timeout') : 'timeout') => $this->Timeout
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return Execute
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Target = Functions::array_bc($data, 'target');
$object->WorkingDirectory = Functions::array_bc($data, 'working_directory');
$object->Options = Functions::array_bc($data, 'options');
$object->Silent = Functions::array_bc($data, 'silent');
$object->Tty = Functions::array_bc($data, 'tty');
$object->Timeout = Functions::array_bc($data, 'timeout');
return $object;
}
}

View file

@ -0,0 +1,76 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\Functions;
class ExitHandle
{
/**
* The message to display when the handle is triggered
*
* @var string|null
*/
public $Message;
/**
* Indicates if the process should exit if the handle is triggered,
* by default NCC will choose the applicable value for this property,
* for instance; if the exit handle is registered for "error", the
* property will be set to true, otherwise for "success" and "warning"
* the property will be false.
*
* @var bool|null
*/
public $EndProcess;
/**
* The name of another execution policy to execute (optionally) when this exit handle is triggered
*
* @var string|null
*/
public $Run;
/**
* The exit code that needs to be returned from the process to trigger this handle
*
* @var int
*/
public $ExitCode;
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('message') : 'message') => $this->Message,
($bytecode ? Functions::cbc('end_process') : 'end_process') => $this->EndProcess,
($bytecode ? Functions::cbc('run') : 'run') => $this->Run,
($bytecode ? Functions::cbc('exit_code') : 'exit_code') => $this->ExitCode,
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return ExitHandle
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Message = Functions::array_bc($data, 'message');
$object->EndProcess = Functions::array_bc($data, 'end_process');
$object->Run = Functions::array_bc($data, 'run');
$object->ExitCode = Functions::array_bc($data, 'exit_code');
return $object;
}
}

View file

@ -0,0 +1,71 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\Functions;
class ExitHandlers
{
/**
* The handle to execute when the process exits with a success exit code
*
* @var ExitHandle
*/
public $Success;
/**
* The handle to execute when the process exits with a warning exit code
*
* @var ExitHandle
*/
public $Warning;
/**
* The handle to execute when the process exits with a error exit code
*
* @var ExitHandle
*/
public $Error;
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('success') : 'success') => $this->Success?->toArray($bytecode),
($bytecode ? Functions::cbc('warning') : 'warning') => $this->Warning?->toArray($bytecode),
($bytecode ? Functions::cbc('error') : 'error') => $this->Error?->toArray($bytecode),
];
}
/**
* Constructs object from an array representation
*
* @param array $data
* @return ExitHandlers
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->Success = Functions::array_bc($data, 'success');
if($object->Success !== null)
$object->Success = ExitHandle::fromArray($object->Success);
$object->Warning = Functions::array_bc($data, 'warning');
if($object->Warning !== null)
$object->Warning = ExitHandle::fromArray($object->Warning);
$object->Error = Functions::array_bc($data, 'error');
if($object->Error !== null)
$object->Error = ExitHandle::fromArray($object->Error);
return $object;
}
}

View file

@ -0,0 +1,88 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects\ProjectConfiguration;
use ncc\Utilities\Functions;
class Installer
{
/**
* An array of execution policies to execute pre-installation
*
* @var string[]|null
*/
public $PreInstall;
/**
* An array of execution policies to execute post-installation
*
* @var string[]|null
*/
public $PostInstall;
/**
* An array of execution policies to execute pre-uninstallation
*
* @var string[]|null
*/
public $PreUninstall;
/**
* An array of execution policies to execute post-uninstallation
*
* @var string[]|null
*/
public $PostUninstall;
/**
* An array of execution policies to execute pre-update
*
* @var string[]|null
*/
public $PreUpdate;
/**
* An array of execution policies to execute post-update
*
* @var string[]|null
*/
public $PostUpdate;
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/
public function toArray(bool $bytecode=false): array
{
return [
($bytecode ? Functions::cbc('pre_install') : 'pre_install') => $this->PreInstall,
($bytecode? Functions::cbc('post_install') : 'post_install') => $this->PostInstall,
($bytecode? Functions::cbc('pre_uninstall') : 'pre_uninstall') => $this->PostUninstall,
($bytecode? Functions::cbc('post_uninstall') : 'post_uninstall') => $this->PostUninstall,
($bytecode? Functions::cbc('pre_update') : 'pre_update') => $this->PreUpdate,
($bytecode? Functions::cbc('post_update') : 'post_update') => $this->PostUpdate
];
}
/**
* @param array $data
* @return Installer
*/
public static function fromArray(array $data): self
{
$object = new self();
$object->PreInstall = Functions::array_bc($data, 'pre_install');
$object->PostInstall = Functions::array_bc($data, 'post_install');
$object->PreUninstall = Functions::array_bc($data, 'pre_uninstall');
$object->PostUninstall = Functions::array_bc($data, 'post_uninstall');
$object->PreUpdate = Functions::array_bc($data, 'pre_update');
$object->PostUpdate = Functions::array_bc($data, 'post_update');
return $object;
}
}

View file

@ -17,6 +17,10 @@
*/ */
public static function encode(string $string): string public static function encode(string $string): string
{ {
// Builtin function is faster than raw implementation
if(function_exists('base64_encode'))
return base64_encode($string);
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); $base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
$bit_pattern = ''; $bit_pattern = '';
$padding = 0; $padding = 0;
@ -54,6 +58,9 @@
*/ */
public static function decode(string $string): string public static function decode(string $string): string
{ {
if(function_exists('base64_decode'))
return base64_encode($string);
$base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); $base64 = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
$bit_pattern = ''; $bit_pattern = '';
$padding = substr_count(substr(strrev($string), 0, 2), '='); $padding = substr_count(substr(strrev($string), 0, 2), '=');

View file

@ -4,10 +4,17 @@
use Exception; use Exception;
use ncc\Abstracts\ConsoleColors; use ncc\Abstracts\ConsoleColors;
use ncc\Abstracts\LogLevel;
use ncc\CLI\Main;
use ncc\ncc; use ncc\ncc;
class Console class Console
{ {
/**
* @var int
*/
private static $largestTickLength = 0;
/** /**
* Inline Progress bar, created by dealnews.com. * Inline Progress bar, created by dealnews.com.
* *
@ -23,6 +30,20 @@
if(!ncc::cliMode()) if(!ncc::cliMode())
return; return;
if(Main::getLogLevel() !== null)
{
switch(Main::getLogLevel())
{
case LogLevel::Verbose:
case LogLevel::Debug:
case LogLevel::Silent:
return;
default:
break;
}
}
static $start_time; static $start_time;
// if we go over our bound, just ignore it // if we go over our bound, just ignore it
@ -44,6 +65,7 @@
$status_bar.="="; $status_bar.="=";
} }
/** @noinspection PhpRedundantOptionalArgumentInspection */
$disp=number_format($perc*100, 0); $disp=number_format($perc*100, 0);
$status_bar.=" ] $disp% $value/$total"; $status_bar.=" ] $disp% $value/$total";
@ -74,18 +96,54 @@
} }
} }
/**
* Appends a verbose prefix to the message
*
* @param string $log_level
* @param string $input
* @return string
*/
private static function setPrefix(string $log_level, string $input): string
{
$input = match ($log_level) {
LogLevel::Verbose => self::formatColor('VRB:', ConsoleColors::LightCyan) . " $input",
LogLevel::Debug => self::formatColor('DBG:', ConsoleColors::LightMagenta) . " $input",
LogLevel::Info => self::formatColor('INF:', ConsoleColors::White) . " $input",
LogLevel::Warning => self::formatColor('WRN:', ConsoleColors::Yellow) . " $input",
LogLevel::Error => self::formatColor('ERR:', ConsoleColors::LightRed) . " $input",
LogLevel::Fatal => self::formatColor('FTL:', ConsoleColors::LightRed) . " $input",
default => self::formatColor('MSG:', ConsoleColors::Default) . " $input",
};
$tick_time = (string)microtime(true);
if(strlen($tick_time) > self::$largestTickLength)
self::$largestTickLength = strlen($tick_time);
if(strlen($tick_time) < self::$largestTickLength)
/** @noinspection PhpRedundantOptionalArgumentInspection */
$tick_time = str_pad($tick_time, (strlen($tick_time) + (self::$largestTickLength - strlen($tick_time))), ' ', STR_PAD_RIGHT);
return '[' . $tick_time . ' - ' . date('TH:i:sP') . '] ' . $input;
}
/** /**
* Simple output function * Simple output function
* *
* @param string $message * @param string $message
* @param bool $newline * @param bool $newline
* @param bool $no_prefix
* @return void * @return void
*/ */
public static function out(string $message, bool $newline=true): void public static function out(string $message, bool $newline=true, bool $no_prefix=false): void
{ {
if(!ncc::cliMode()) if(!ncc::cliMode())
return; return;
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Info, Main::getLogLevel()))
return;
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()) && !$no_prefix)
$message = self::setPrefix(LogLevel::Info, $message);
if($newline) if($newline)
{ {
print($message . PHP_EOL); print($message . PHP_EOL);
@ -95,6 +153,58 @@
print($message); print($message);
} }
/**
* Output debug message
*
* @param string $message
* @param bool $newline
* @return void
*/
public static function outDebug(string $message, bool $newline=true): void
{
if(!ncc::cliMode())
return;
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Debug, Main::getLogLevel()))
return;
$backtrace = null;
if(function_exists('debug_backtrace'))
$backtrace = debug_backtrace();
$trace_msg = null;
if($backtrace !== null && isset($backtrace[1]))
{
$trace_msg = Console::formatColor($backtrace[1]['class'], ConsoleColors::LightGray);
$trace_msg .= $backtrace[1]['type'];
$trace_msg .= Console::formatColor($backtrace[1]['function'] . '()', ConsoleColors::LightGreen);
$trace_msg .= ' > ';
}
/** @noinspection PhpUnnecessaryStringCastInspection */
$message = self::setPrefix(LogLevel::Debug, (string)$trace_msg . $message);
self::out($message, $newline, true);
}
/**
* Output debug message
*
* @param string $message
* @param bool $newline
* @return void
*/
public static function outVerbose(string $message, bool $newline=true): void
{
if(!ncc::cliMode())
return;
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
return;
self::out(self::setPrefix(LogLevel::Verbose, $message), $newline, true);
}
/** /**
* Formats the text to have a different color and returns the formatted value * Formats the text to have a different color and returns the formatted value
* *
@ -105,6 +215,11 @@
*/ */
public static function formatColor(string $input, string $color_code, bool $persist=true): string public static function formatColor(string $input, string $color_code, bool $persist=true): string
{ {
if(Main::getArgs() !== null && isset(Main::getArgs()['no-color']))
{
return $input;
}
if($persist) if($persist)
{ {
return $color_code . $input . ConsoleColors::Default; return $color_code . $input . ConsoleColors::Default;
@ -125,6 +240,15 @@
if(!ncc::cliMode()) if(!ncc::cliMode())
return; return;
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Warning, Main::getLogLevel()))
return;
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
{
self::out(self::setPrefix(LogLevel::Warning, $message), $newline, true);
return;
}
self::out(self::formatColor('Warning: ', ConsoleColors::Yellow) . $message, $newline); self::out(self::formatColor('Warning: ', ConsoleColors::Yellow) . $message, $newline);
} }
@ -141,7 +265,17 @@
if(!ncc::cliMode()) if(!ncc::cliMode())
return; return;
if(Main::getLogLevel() !== null && !Resolver::checkLogLevel(LogLevel::Error, Main::getLogLevel()))
return;
if(Main::getLogLevel() !== null && Resolver::checkLogLevel(LogLevel::Verbose, Main::getLogLevel()))
{
self::out(self::setPrefix(LogLevel::Error, $message), $newline, true);
}
else
{
self::out(self::formatColor(ConsoleColors::Red, 'Error: ') . $message, $newline); self::out(self::formatColor(ConsoleColors::Red, 'Error: ') . $message, $newline);
}
if($exit_code !== null) if($exit_code !== null)
{ {
@ -162,11 +296,12 @@
if(!ncc::cliMode()) if(!ncc::cliMode())
return; return;
if(strlen($message) > 0) if(strlen($message) > 0 && Resolver::checkLogLevel(LogLevel::Error, Main::getLogLevel()))
{ {
self::out(self::formatColor('Error: ' . $message, ConsoleColors::Red)); self::out(PHP_EOL . self::formatColor('Error: ', ConsoleColors::Red) . $message);
} }
Console::out(PHP_EOL . '===== Exception Details =====');
self::outExceptionDetails($e); self::outExceptionDetails($e);
if($exit_code !== null) if($exit_code !== null)
@ -189,6 +324,39 @@
$trace_header = self::formatColor($e->getFile() . ':' . $e->getLine(), ConsoleColors::Magenta); $trace_header = self::formatColor($e->getFile() . ':' . $e->getLine(), ConsoleColors::Magenta);
$trace_error = self::formatColor('error: ', ConsoleColors::Red); $trace_error = self::formatColor('error: ', ConsoleColors::Red);
self::out($trace_header . ' ' . $trace_error . $e->getMessage()); self::out($trace_header . ' ' . $trace_error . $e->getMessage());
self::out(sprintf('Error code: %s', $e->getCode()));
$trace = $e->getTrace();
if(count($trace) > 1)
{
self::out('Stack Trace:');
foreach($trace as $item)
{
self::out( ' - ' . self::formatColor($item['file'], ConsoleColors::Red) . ':' . $item['line']);
}
}
if(Main::getArgs() !== null)
{
if(isset(Main::getArgs()['dbg-ex']))
{
try
{
$dump = [
'constants' => ncc::getConstants(),
'exception' => Functions::exceptionToArray($e)
];
IO::fwrite(getcwd() . DIRECTORY_SEPARATOR . time() . '.json', json_encode($dump, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), 0777);
}
catch (Exception $e)
{
self::outWarning('Cannot dump exception details, ' . $e->getMessage());
}
}
else
{
self::out('You can pass on \'--dbg-ex\' option to dump the exception details to a json file');
}
}
} }
/** /**

View file

@ -2,9 +2,22 @@
namespace ncc\Utilities; namespace ncc\Utilities;
use Exception;
use ncc\Abstracts\Runners;
use ncc\Abstracts\Scopes;
use ncc\Classes\PhpExtension\Runner;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException; use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\MalformedJsonException; use ncc\Exceptions\MalformedJsonException;
use ncc\Exceptions\UnsupportedRunnerException;
use ncc\Managers\CredentialManager;
use ncc\Managers\PackageLockManager;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
/** /**
* @author Zi Xing Narrakas * @author Zi Xing Narrakas
@ -22,11 +35,15 @@
* Calculates a byte-code representation of the input using CRC32 * Calculates a byte-code representation of the input using CRC32
* *
* @param string $input * @param string $input
* @return int * @return string
*/ */
public static function cbc(string $input): int public static function cbc(string $input): string
{ {
return hexdec(hash('crc32', $input, true)); $cache = RuntimeCache::get("cbc_$input");
if($cache !== null)
return $cache;
return RuntimeCache::set("cbc_$input", hash('crc32', $input, true));
} }
/** /**
@ -36,6 +53,7 @@
* @param array $data * @param array $data
* @param string $select * @param string $select
* @return mixed|null * @return mixed|null
* @noinspection PhpMissingReturnTypeInspection
*/ */
public static function array_bc(array $data, string $select) public static function array_bc(array $data, string $select)
{ {
@ -54,7 +72,9 @@
* @param string $path * @param string $path
* @param int $flags * @param int $flags
* @return mixed * @return mixed
* @throws AccessDeniedException
* @throws FileNotFoundException * @throws FileNotFoundException
* @throws IOException
* @throws MalformedJsonException * @throws MalformedJsonException
* @noinspection PhpMissingReturnTypeInspection * @noinspection PhpMissingReturnTypeInspection
*/ */
@ -65,7 +85,7 @@
throw new FileNotFoundException($path); throw new FileNotFoundException($path);
} }
return self::loadJson(file_get_contents($path), $flags); return self::loadJson(IO::fread($path), $flags);
} }
/** /**
@ -98,6 +118,7 @@
* @return string * @return string
* @throws MalformedJsonException * @throws MalformedJsonException
* @noinspection PhpMissingParamTypeInspection * @noinspection PhpMissingParamTypeInspection
* @noinspection PhpUnusedLocalVariableInspection
*/ */
public static function encodeJson($value, int $flags=0): string public static function encodeJson($value, int $flags=0): string
{ {
@ -123,7 +144,7 @@
* @return void * @return void
* @throws MalformedJsonException * @throws MalformedJsonException
*/ */
public static function encodeJsonFile($value, string $path, int $flags=0) public static function encodeJsonFile($value, string $path, int $flags=0): void
{ {
file_put_contents($path, self::encodeJson($value, $flags)); file_put_contents($path, self::encodeJson($value, $flags));
} }
@ -160,16 +181,19 @@
* @param string $copyright * @param string $copyright
* @param bool $basic_ascii * @param bool $basic_ascii
* @return string * @return string
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/ */
public static function getBanner(string $version, string $copyright, bool $basic_ascii=false): string public static function getBanner(string $version, string $copyright, bool $basic_ascii=false): string
{ {
if($basic_ascii) if($basic_ascii)
{ {
$banner = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_basic'); $banner = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_basic');
} }
else else
{ {
$banner = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_extended'); $banner = IO::fread(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'banner_extended');
} }
$banner_version = str_pad($version, 21); $banner_version = str_pad($version, 21);
@ -219,26 +243,125 @@
} }
/** /**
* Converts the input string into a Bas64 encoding before returning it as a * @param string $path
* byte representation * @param ExecutionPolicy $policy
* * @return ExecutionUnit
* @param string $string * @throws UnsupportedRunnerException
* @return string * @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/ */
public static function byteEncode(string $string): string public static function compileRunner(string $path, ExecutionPolicy $policy): ExecutionUnit
{ {
return convert_uuencode(Base64::encode($string)); return match (strtolower($policy->Runner)) {
Runners::php => Runner::processUnit($path, $policy),
default => throw new UnsupportedRunnerException('The runner \'' . $policy->Runner . '\' is not supported'),
};
} }
/** /**
* Decodes the input string back into the normal string representation that was encoded * Returns an array representation of the exception
* by the byteEncode() function
* *
* @param string $string * @param Exception $e
* @return array
*/
public static function exceptionToArray(Exception $e): array
{
$exception = [
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => null,
'trace_string' => $e->getTraceAsString(),
];
if($e->getPrevious() !== null)
{
$exception['trace'] = self::exceptionToArray($e);
}
return $exception;
}
/**
* Takes the input bytes and converts it to a readable unit representation
*
* @param int $bytes
* @param int $decimals
* @return string * @return string
*/ */
public static function byteDecode(string $string): string public static function b2u(int $bytes, int $decimals=2): string
{ {
return base64_decode(convert_uudecode($string)); $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor];
}
/**
* Initializes NCC files
*
* @return void
* @throws AccessDeniedException
* @throws InvalidScopeException
*/
public static function initializeFiles(): void
{
if(Resolver::resolveScope() !== Scopes::System)
throw new AccessDeniedException('Cannot initialize NCC files, insufficient permissions');
Console::outVerbose('Initializing NCC files');
$filesystem = new Filesystem();
if(!$filesystem->exists(PathFinder::getDataPath(Scopes::System)))
{
Console::outDebug(sprintf('Initializing %s', PathFinder::getDataPath(Scopes::System)));
$filesystem->mkdir(PathFinder::getDataPath(Scopes::System), 0755);
}
if(!$filesystem->exists(PathFinder::getCachePath(Scopes::System)))
{
Console::outDebug(sprintf('Initializing %s', PathFinder::getCachePath(Scopes::System)));
/** @noinspection PhpRedundantOptionalArgumentInspection */
$filesystem->mkdir(PathFinder::getCachePath(Scopes::System), 0777);
}
if(!$filesystem->exists(PathFinder::getRunnerPath(Scopes::System)))
{
Console::outDebug(sprintf('Initializing %s', PathFinder::getRunnerPath(Scopes::System)));
/** @noinspection PhpRedundantOptionalArgumentInspection */
$filesystem->mkdir(PathFinder::getRunnerPath(Scopes::System), 0755);
}
if(!$filesystem->exists(PathFinder::getPackagesPath(Scopes::System)))
{
Console::outDebug(sprintf('Initializing %s', PathFinder::getPackagesPath(Scopes::System)));
/** @noinspection PhpRedundantOptionalArgumentInspection */
$filesystem->mkdir(PathFinder::getPackagesPath(Scopes::System), 0755);
}
// Create credential store if needed
try
{
Console::outVerbose('Processing Credential Store');
$credential_manager = new CredentialManager();
$credential_manager->constructStore();
}
catch (Exception $e)
{
Console::outError('Cannot construct credential store, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
}
// Create package lock if needed
try
{
Console::outVerbose('Processing Package Lock');
$package_manager = new PackageLockManager();
$package_manager->constructLockFile();
}
catch (Exception $e)
{
Console::outError('Cannot construct Package Lock, ' . $e->getMessage() . ' (Error Code: ' . $e->getCode() . ')');
}
} }
} }

97
src/ncc/Utilities/IO.php Normal file
View file

@ -0,0 +1,97 @@
<?php
namespace ncc\Utilities;
use ncc\Exceptions\AccessDeniedException;
use ncc\Exceptions\FileNotFoundException;
use ncc\Exceptions\IOException;
use SplFileInfo;
use SplFileObject;
class IO
{
/**
* Attempts to write the specified file, with proper error handling
*
* @param string $uri
* @param string $data
* @param int $perms
* @param string $mode
* @return void
* @throws IOException
*/
public static function fwrite(string $uri, string $data, int $perms=0644, string $mode='w'): void
{
$fileInfo = new SplFileInfo($uri);
if(!is_dir($fileInfo->getPath()))
{
throw new IOException(sprintf('Attempted to write data to a directory instead of a file: (%s)', $uri));
}
Console::outDebug(sprintf('writing %s of data to %s', Functions::b2u(strlen($data)), $uri));
$file = new SplFileObject($uri, $mode);
if (!$file->flock(LOCK_EX | LOCK_NB))
{
throw new IOException(sprintf('Unable to obtain lock on file: (%s)', $uri));
}
elseif (!$file->fwrite($data))
{
throw new IOException(sprintf('Unable to write content to file: (%s)... to (%s)', substr($data,0,25), $uri));
}
elseif (!$file->flock(LOCK_UN))
{
throw new IOException(sprintf('Unable to remove lock on file: (%s)', $uri));
}
elseif (!@chmod($uri, $perms))
{
throw new IOException(sprintf('Unable to chmod: (%s) to (%s)', $uri, $perms));
}
}
/**
* Attempts to read the specified file
*
* @param string $uri
* @param string $mode
* @param int|null $length
* @return string
* @throws AccessDeniedException
* @throws FileNotFoundException
* @throws IOException
*/
public static function fread(string $uri, string $mode='r', ?int $length=null): string
{
$fileInfo = new SplFileInfo($uri);
if(!is_dir($fileInfo->getPath()))
{
throw new IOException(sprintf('Attempted to read data from a directory instead of a file: (%s)', $uri));
}
if(!file_exists($uri))
{
throw new FileNotFoundException(sprintf('Cannot find file %s', $uri));
}
if(!is_readable($uri))
{
throw new AccessDeniedException(sprintf('Insufficient permissions to read %s', $uri));
}
$file = new SplFileObject($uri, $mode);
if($length == null)
{
$length = $file->getSize();
}
if($length == 0)
{
return (string)null;
}
Console::outDebug(sprintf('reading %s', $uri));
return $file->fread($length);
}
}

View file

@ -145,49 +145,16 @@
} }
/** /**
* Returns the path where temporary files are stored * Returns the path where Runner bin files are located and installed
* *
* @param string $scope * @param string $scope
* @param bool $win32 * @param bool $win32
* @return string * @return string
* @throws InvalidScopeException * @throws InvalidScopeException
*/ */
public static function getTmpPath(string $scope=Scopes::Auto, bool $win32=false): string public static function getRunnerPath(string $scope=Scopes::Auto, bool $win32=false): string
{ {
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'tmp'; return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'runners';
}
/**
* Returns the configuration file
*
* @param string $scope
* @param bool $win32
* @return string
* @throws InvalidScopeException
*/
public static function getConfigurationFile(string $scope=Scopes::Auto, bool $win32=false): string
{
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'config';
}
/**
* Returns an array of all the configuration files the current user can access (For global-cross referencing)
*
* @param bool $win32
* @return array
* @throws InvalidScopeException
*/
public static function getConfigurationFiles(bool $win32=false): array
{
$results = [];
$results[] = self::getConfigurationFile(Scopes::System, $win32);
if(!in_array(self::getConfigurationFile(Scopes::User, $win32), $results))
{
$results[] = self::getConfigurationFile(Scopes::User, $win32);
}
return $results;
} }
/** /**
@ -235,18 +202,4 @@
{ {
return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'ext'; return self::getDataPath($scope, $win32) . DIRECTORY_SEPARATOR . 'ext';
} }
/**
* Returns the file path where files for the given extension is stored
*
* @param string $extension_name
* @param string $scope
* @param bool $win32
* @return string
* @throws InvalidScopeException
*/
public static function getNamedExtensionPath(string $extension_name, string $scope=Scopes::Auto, bool $win32=false): string
{
return self::getExtensionPath($scope, $win32) . DIRECTORY_SEPARATOR . Security::sanitizeFilename($extension_name);
}
} }

View file

@ -1,11 +1,21 @@
<?php <?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Utilities; namespace ncc\Utilities;
use ncc\Abstracts\LogLevel;
use ncc\Abstracts\Scopes; use ncc\Abstracts\Scopes;
class Resolver class Resolver
{ {
/**
* The cache value of the User ID
*
* @var string|null
*/
private static $UserIdCache;
/** /**
* @param string|null $input * @param string|null $input
* @return string * @return string
@ -20,10 +30,13 @@
$input = strtoupper($input); $input = strtoupper($input);
if(self::$UserIdCache == null)
self::$UserIdCache = posix_getuid();
// Resolve the scope if it's set to automatic // Resolve the scope if it's set to automatic
if($input == Scopes::Auto) if($input == Scopes::Auto)
{ {
if(posix_getuid() == 0) if(self::$UserIdCache == 0)
{ {
$input = Scopes::System; $input = Scopes::System;
} }
@ -34,7 +47,7 @@
} }
// Auto-Correct the scope if the current user ID is 0 // Auto-Correct the scope if the current user ID is 0
if($input == Scopes::User && posix_getuid() == 0) if($input == Scopes::User && self::$UserIdCache == 0)
{ {
$input = Scopes::System; $input = Scopes::System;
} }
@ -45,9 +58,12 @@
/** /**
* Parse arguments * Parse arguments
* *
* @param array|string [$message] input arguments * @param array|string $message [$message] input arguments
* @param int $max_arguments * @param int $max_arguments
* @return array Configs Key/Value * @return array Configs Key/Value
* @noinspection RegExpRedundantEscape
* @noinspection RegExpSimplifiable
* @noinspection PhpMissingParamTypeInspection
*/ */
public static function parseArguments($message=null, int $max_arguments=1000): array public static function parseArguments($message=null, int $max_arguments=1000): array
{ {
@ -135,4 +151,94 @@
{ {
return hash('haval128,3', self::resolveFullConstantName($scope, $name)); return hash('haval128,3', self::resolveFullConstantName($scope, $name));
} }
/**
* Checks if the input level matches the current level
*
* @param string|null $input
* @param string|null $current_level
* @return bool
*/
public static function checkLogLevel(?string $input, ?string $current_level): bool
{
if($input == null)
return false;
if($current_level == null)
return false;
$input = strtolower($input);
if(!Validate::checkLogLevel($input))
return false;
$current_level = strtolower($current_level);
if(!Validate::checkLogLevel($current_level))
return false;
switch($current_level)
{
case LogLevel::Debug:
$levels = [
LogLevel::Debug,
LogLevel::Verbose,
LogLevel::Info,
LogLevel::Warning,
LogLevel::Fatal,
LogLevel::Error
];
if(in_array($input, $levels))
return true;
return false;
case LogLevel::Verbose:
$levels = [
LogLevel::Verbose,
LogLevel::Info,
LogLevel::Warning,
LogLevel::Fatal,
LogLevel::Error
];
if(in_array($input, $levels))
return true;
return false;
case LogLevel::Info:
$levels = [
LogLevel::Info,
LogLevel::Warning,
LogLevel::Fatal,
LogLevel::Error
];
if(in_array($input, $levels))
return true;
return false;
case LogLevel::Warning:
$levels = [
LogLevel::Warning,
LogLevel::Fatal,
LogLevel::Error
];
if(in_array($input, $levels))
return true;
return false;
case LogLevel::Error:
$levels = [
LogLevel::Fatal,
LogLevel::Error
];
if(in_array($input, $levels))
return true;
return false;
case LogLevel::Fatal:
if($input == LogLevel::Fatal)
return true;
return false;
default:
case LogLevel::Silent:
return false;
}
}
} }

View file

@ -0,0 +1,40 @@
<?php
namespace ncc\Utilities;
class RuntimeCache
{
/**
* An array of cache entries
*
* @var array
*/
private static $cache = [];
/**
* Sets a value, returns the value
*
* @param $key
* @param $value
* @return mixed
*/
public static function set($key, $value)
{
self::$cache[$key] = $value;
return $value;
}
/**
* Gets an existing value, null if it doesn't exist
*
* @param $key
* @return mixed|null
*/
public static function get($key)
{
if(isset(self::$cache[$key]))
return self::$cache[$key];
return null;
}
}

View file

@ -2,6 +2,7 @@
namespace ncc\Utilities; namespace ncc\Utilities;
use ncc\Abstracts\LogLevel;
use ncc\Abstracts\RegexPatterns; use ncc\Abstracts\RegexPatterns;
use ncc\Abstracts\Scopes; use ncc\Abstracts\Scopes;
@ -208,4 +209,53 @@
return true; return true;
} }
/**
* Validates the execution policy name
*
* @param string $input
* @return bool
*/
public static function executionPolicyName(string $input): bool
{
if($input == null)
{
return false;
}
if(!preg_match(RegexPatterns::ExecutionPolicyName, $input))
{
return false;
}
return true;
}
/**
* Determines if the given log level is valid or not
*
* @param string $input
* @return bool
*/
public static function checkLogLevel(string $input): bool
{
if(!in_array(strtolower($input), LogLevel::All))
return false;
return true;
}
/**
* Determines if given input exceeds the path length limit
*
* @param string $input
* @return bool
*/
public static function exceedsPathLength(string $input): bool
{
if(strlen($input) > 4096)
return true;
return false;
}
} }

View file

@ -0,0 +1,9 @@
<?php
require(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'autoload.php');
\ncc\ncc::initialize();
$package_lock_manager = new \ncc\Managers\PackageLockManager();
$package_lock_manager->load();
var_dump($package_lock_manager->getPackageLock());