diff --git a/CHANGELOG.md b/CHANGELOG.md index 76dbaaf7..693f8a7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,12 @@ ## Not released yet +* Add support for importing remote functions and tasks +* Add a bash installer to ease installation * Distribute static binaries `castor.darwin-arm64` automatically with the release * Add support for running Castor on Linux arm64 and distribute the binary `castor.linux-arm64.phar` automatically with the release -* Add a bash installer to ease installation -* Add support for importing remote functions and tasks * Add an option `ignoreValidationErrors` on `AsTask` attribute to ignore parameters & options validation errors * Add support for dynamic autocomplete task arguments/options @@ -15,12 +15,15 @@ `castor:repack` command * Find root directory by looking for a `.castor/castor.php` file * Allow stub file to be in `.castor/.castor.stub.php` + * Deprecate loading all PHP files from `[ROOT_DIR]/castor` * Deprecate `Context::withPath()` in favor of `Context::withWorkingDirectory()` * Deprecate `path` argument in `capture()`, `exit_code()`, `run()`, `with()` in favor of `workingDirectory` * Deprecate `Castor\TaskDescriptorCollection` in favor of `Castor\Descriptor\TaskDescriptorCollection` +* Deprecate `Castor\HasherHelper` in favor of `Castor\Castor\HasherHelper` +* Deprecate `Castor\PathHelper` in favor of `Castor\Castor\PathHelper` ## 0.14.0 (2024-03-08) diff --git a/bin/generate-tests.php b/bin/generate-tests.php index c40ddb55..6787c47f 100755 --- a/bin/generate-tests.php +++ b/bin/generate-tests.php @@ -4,7 +4,7 @@ require __DIR__ . '/../vendor/autoload.php'; use Castor\Console\ApplicationFactory; -use Castor\PlatformHelper; +use Castor\Helper\PlatformHelper; use Castor\Tests\Helper\OutputCleaner; use Castor\Tests\Helper\WebServerHelper; use Symfony\Component\Console\Input\ArrayInput; diff --git a/composer.json b/composer.json index fa6359fb..5ef241f9 100644 --- a/composer.json +++ b/composer.json @@ -33,22 +33,22 @@ "jolicode/jolinotif": "^2.6.0", "jolicode/php-os-helper": "^0.1.0", "monolog/monolog": "^3.5", - "nikic/php-parser": "^4.18", - "spatie/ssh": "^1.9.2", - "symfony/cache": "^6.4.3", - "symfony/console": "^6.4.2", + "nikic/php-parser": "^4.19.1", + "spatie/ssh": "^1.10.0", + "symfony/cache": "^6.4.4", + "symfony/console": "^6.4.4", "symfony/deprecation-contracts": "^3.4", - "symfony/dotenv": "^6.4.3", - "symfony/error-handler": "^6.4.3", + "symfony/dotenv": "^6.4.4", + "symfony/error-handler": "^6.4.4", "symfony/expression-language": "^6.4.3", "symfony/filesystem": "^6.4.3", "symfony/finder": "^6.4", - "symfony/http-client": "^6.4.3", - "symfony/monolog-bridge": "^6.4.3", - "symfony/process": "^6.4.3", - "symfony/string": "^6.4.3", + "symfony/http-client": "^6.4.5", + "symfony/monolog-bridge": "^6.4.4", + "symfony/process": "^6.4.4", + "symfony/string": "^6.4.4", "symfony/translation-contracts": "^3.4.1", - "symfony/var-dumper": "^6.4.3", + "symfony/var-dumper": "^6.4.4", "symfony/yaml": "^6.4.3" }, "conflict": { @@ -64,7 +64,7 @@ } }, "require-dev": { - "phpunit/php-code-coverage": "^9.2.30", - "symfony/phpunit-bridge": "^6.4.3" + "phpunit/php-code-coverage": "^9.2.31", + "symfony/phpunit-bridge": "^6.4.4" } } diff --git a/composer.lock b/composer.lock index daf5484e..d37af41a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f70459a71db521523c0b9a12ed2ee14d", + "content-hash": "500b6664d5def41726e798f182816a0e", "packages": [ { "name": "jolicode/jolinotif", @@ -222,21 +222,21 @@ }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v4.19.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", @@ -272,9 +272,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-03-17T08:10:35+00:00" }, { "name": "psr/cache", @@ -480,26 +480,26 @@ }, { "name": "spatie/ssh", - "version": "1.9.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/spatie/ssh.git", - "reference": "c28a187f961c1039e205f291417f74e3d4c83b71" + "reference": "46af35be178a664a49384778557f424b0265db7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ssh/zipball/c28a187f961c1039e205f291417f74e3d4c83b71", - "reference": "c28a187f961c1039e205f291417f74e3d4c83b71", + "url": "https://api.github.com/repos/spatie/ssh/zipball/46af35be178a664a49384778557f424b0265db7a", + "reference": "46af35be178a664a49384778557f424b0265db7a", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "symfony/process": "^4.4|^5.3|^6.0" + "symfony/process": "^4.4|^5.3|^6.0|^7.0" }, "require-dev": { "pestphp/pest": "^1.22", "spatie/pest-plugin-snapshots": "^1.1", - "symfony/var-dumper": "^5.3|6.0" + "symfony/var-dumper": "^5.3|6.0|^7.0" }, "type": "library", "autoload": { @@ -527,7 +527,7 @@ ], "support": { "issues": "https://github.com/spatie/ssh/issues", - "source": "https://github.com/spatie/ssh/tree/1.9.2" + "source": "https://github.com/spatie/ssh/tree/1.10.0" }, "funding": [ { @@ -535,20 +535,20 @@ "type": "custom" } ], - "time": "2023-06-19T22:01:59+00:00" + "time": "2023-12-18T14:27:04+00:00" }, { "name": "symfony/cache", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "49f8cdee544a621a621cd21b6cda32a38926d310" + "reference": "0ef36534694c572ff526d91c7181f3edede176e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/49f8cdee544a621a621cd21b6cda32a38926d310", - "reference": "49f8cdee544a621a621cd21b6cda32a38926d310", + "url": "https://api.github.com/repos/symfony/cache/zipball/0ef36534694c572ff526d91c7181f3edede176e7", + "reference": "0ef36534694c572ff526d91c7181f3edede176e7", "shasum": "" }, "require": { @@ -615,7 +615,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.3" + "source": "https://github.com/symfony/cache/tree/v6.4.4" }, "funding": [ { @@ -631,7 +631,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-22T20:27:10+00:00" }, { "name": "symfony/cache-contracts", @@ -711,16 +711,16 @@ }, { "name": "symfony/console", - "version": "v6.4.2", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625" + "reference": "0d9e4eb5ad413075624378f474c4167ea202de78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0254811a143e6bc6c8deea08b589a7e68a37f625", - "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625", + "url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78", + "reference": "0d9e4eb5ad413075624378f474c4167ea202de78", "shasum": "" }, "require": { @@ -785,7 +785,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.2" + "source": "https://github.com/symfony/console/tree/v6.4.4" }, "funding": [ { @@ -801,7 +801,7 @@ "type": "tidelift" } ], - "time": "2023-12-10T16:15:48+00:00" + "time": "2024-02-22T20:27:10+00:00" }, { "name": "symfony/deprecation-contracts", @@ -872,16 +872,16 @@ }, { "name": "symfony/dotenv", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "3cb7ca997124760ed1389d5341806247670f4ef8" + "reference": "f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/3cb7ca997124760ed1389d5341806247670f4ef8", - "reference": "3cb7ca997124760ed1389d5341806247670f4ef8", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0", + "reference": "f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0", "shasum": "" }, "require": { @@ -926,7 +926,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.3" + "source": "https://github.com/symfony/dotenv/tree/v6.4.4" }, "funding": [ { @@ -942,20 +942,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-08T17:53:17+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "6dc3c76a278b77f01d864a6005d640822c6f26a6" + "reference": "c725219bdf2afc59423c32793d5019d2a904e13a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/6dc3c76a278b77f01d864a6005d640822c6f26a6", - "reference": "6dc3c76a278b77f01d864a6005d640822c6f26a6", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c725219bdf2afc59423c32793d5019d2a904e13a", + "reference": "c725219bdf2afc59423c32793d5019d2a904e13a", "shasum": "" }, "require": { @@ -1001,7 +1001,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.3" + "source": "https://github.com/symfony/error-handler/tree/v6.4.4" }, "funding": [ { @@ -1017,7 +1017,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:40:36+00:00" + "time": "2024-02-22T20:27:10+00:00" }, { "name": "symfony/event-dispatcher", @@ -1368,16 +1368,16 @@ }, { "name": "symfony/http-client", - "version": "v6.4.3", + "version": "v6.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "a9034bc119fab8238f76cf49c770f3135f3ead86" + "reference": "f3c86a60a3615f466333a11fd42010d4382a82c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/a9034bc119fab8238f76cf49c770f3135f3ead86", - "reference": "a9034bc119fab8238f76cf49c770f3135f3ead86", + "url": "https://api.github.com/repos/symfony/http-client/zipball/f3c86a60a3615f466333a11fd42010d4382a82c7", + "reference": "f3c86a60a3615f466333a11fd42010d4382a82c7", "shasum": "" }, "require": { @@ -1441,7 +1441,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.3" + "source": "https://github.com/symfony/http-client/tree/v6.4.5" }, "funding": [ { @@ -1457,7 +1457,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:01:07+00:00" + "time": "2024-03-02T12:45:30+00:00" }, { "name": "symfony/http-client-contracts", @@ -1539,16 +1539,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5677bdf7cade4619cb17fc9e1e7b31ec392244a9" + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5677bdf7cade4619cb17fc9e1e7b31ec392244a9", - "reference": "5677bdf7cade4619cb17fc9e1e7b31ec392244a9", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", "shasum": "" }, "require": { @@ -1596,7 +1596,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.3" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.4" }, "funding": [ { @@ -1612,20 +1612,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-08T15:01:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.3", + "version": "v6.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "9c6ec4e543044f7568a53a76ab1484ecd30637a2" + "reference": "f6947cb939d8efee137797382cb4db1af653ef75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9c6ec4e543044f7568a53a76ab1484ecd30637a2", - "reference": "9c6ec4e543044f7568a53a76ab1484ecd30637a2", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6947cb939d8efee137797382cb4db1af653ef75", + "reference": "f6947cb939d8efee137797382cb4db1af653ef75", "shasum": "" }, "require": { @@ -1674,7 +1674,7 @@ "symfony/process": "^5.4|^6.0|^7.0", "symfony/property-access": "^5.4.5|^6.0.5|^7.0", "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.3|^7.0", + "symfony/serializer": "^6.4.4|^7.0.4", "symfony/stopwatch": "^5.4|^6.0|^7.0", "symfony/translation": "^5.4|^6.0|^7.0", "symfony/translation-contracts": "^2.5|^3", @@ -1709,7 +1709,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.3" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.5" }, "funding": [ { @@ -1725,20 +1725,20 @@ "type": "tidelift" } ], - "time": "2024-01-31T07:21:29+00:00" + "time": "2024-03-04T21:00:47+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "1e1ec293f15dcc815146637ee9ee8a7f43642fa1" + "reference": "db7468152b27242f1a4d10fabe278a2cfaa4eac0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/1e1ec293f15dcc815146637ee9ee8a7f43642fa1", - "reference": "1e1ec293f15dcc815146637ee9ee8a7f43642fa1", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/db7468152b27242f1a4d10fabe278a2cfaa4eac0", + "reference": "db7468152b27242f1a4d10fabe278a2cfaa4eac0", "shasum": "" }, "require": { @@ -1751,7 +1751,7 @@ "conflict": { "symfony/console": "<5.4", "symfony/http-foundation": "<5.4", - "symfony/security-core": "<6.0" + "symfony/security-core": "<5.4" }, "require-dev": { "symfony/console": "^5.4|^6.0|^7.0", @@ -1759,7 +1759,7 @@ "symfony/mailer": "^5.4|^6.0|^7.0", "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "symfony-bridge", @@ -1788,7 +1788,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.3" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.4" }, "funding": [ { @@ -1804,7 +1804,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:01:07+00:00" + "time": "2024-02-01T11:49:25+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2283,16 +2283,16 @@ }, { "name": "symfony/process", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "31642b0818bfcff85930344ef93193f8c607e0a3" + "reference": "710e27879e9be3395de2b98da3f52a946039f297" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/31642b0818bfcff85930344ef93193f8c607e0a3", - "reference": "31642b0818bfcff85930344ef93193f8c607e0a3", + "url": "https://api.github.com/repos/symfony/process/zipball/710e27879e9be3395de2b98da3f52a946039f297", + "reference": "710e27879e9be3395de2b98da3f52a946039f297", "shasum": "" }, "require": { @@ -2324,7 +2324,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.3" + "source": "https://github.com/symfony/process/tree/v6.4.4" }, "funding": [ { @@ -2340,7 +2340,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-20T12:31:00+00:00" }, { "name": "symfony/service-contracts", @@ -2426,16 +2426,16 @@ }, { "name": "symfony/string", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7a14736fb179876575464e4658fce0c304e8c15b" + "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7a14736fb179876575464e4658fce0c304e8c15b", - "reference": "7a14736fb179876575464e4658fce0c304e8c15b", + "url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", + "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", "shasum": "" }, "require": { @@ -2492,7 +2492,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.3" + "source": "https://github.com/symfony/string/tree/v6.4.4" }, "funding": [ { @@ -2508,7 +2508,7 @@ "type": "tidelift" } ], - "time": "2024-01-25T09:26:29+00:00" + "time": "2024-02-01T13:16:41+00:00" }, { "name": "symfony/translation-contracts", @@ -2590,16 +2590,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0435a08f69125535336177c29d56af3abc1f69da" + "reference": "b439823f04c98b84d4366c79507e9da6230944b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0435a08f69125535336177c29d56af3abc1f69da", - "reference": "0435a08f69125535336177c29d56af3abc1f69da", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b439823f04c98b84d4366c79507e9da6230944b1", + "reference": "b439823f04c98b84d4366c79507e9da6230944b1", "shasum": "" }, "require": { @@ -2655,7 +2655,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.3" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.4" }, "funding": [ { @@ -2671,20 +2671,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:53:30+00:00" + "time": "2024-02-15T11:23:52+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "a8c12b5448a5ac685347f5eeb2abf6a571ec16b8" + "reference": "0bd342e24aef49fc82a21bd4eedd3e665d177e5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/a8c12b5448a5ac685347f5eeb2abf6a571ec16b8", - "reference": "a8c12b5448a5ac685347f5eeb2abf6a571ec16b8", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0bd342e24aef49fc82a21bd4eedd3e665d177e5b", + "reference": "0bd342e24aef49fc82a21bd4eedd3e665d177e5b", "shasum": "" }, "require": { @@ -2730,7 +2730,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.3" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.4" }, "funding": [ { @@ -2746,7 +2746,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-26T08:37:45+00:00" }, { "name": "symfony/yaml", @@ -2824,16 +2824,16 @@ "packages-dev": [ { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", "shasum": "" }, "require": { @@ -2890,7 +2890,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" }, "funding": [ { @@ -2898,7 +2898,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-03-02T06:37:42+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3306,16 +3306,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v6.4.3", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "d49b4f6dc4690cf2c194311bb498abf0cf4f7485" + "reference": "16ed5bdfd18e14fc7de347c8688e8ac479284222" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d49b4f6dc4690cf2c194311bb498abf0cf4f7485", - "reference": "d49b4f6dc4690cf2c194311bb498abf0cf4f7485", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/16ed5bdfd18e14fc7de347c8688e8ac479284222", + "reference": "16ed5bdfd18e14fc7de347c8688e8ac479284222", "shasum": "" }, "require": { @@ -3367,7 +3367,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.3" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.4" }, "funding": [ { @@ -3383,20 +3383,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-02-08T14:08:19+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -3425,7 +3425,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -3433,7 +3433,7 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], diff --git a/doc/going-further/helpers/fingerprint.md b/doc/going-further/helpers/fingerprint.md index b3639281..39ef5117 100644 --- a/doc/going-further/helpers/fingerprint.md +++ b/doc/going-further/helpers/fingerprint.md @@ -36,7 +36,7 @@ function task_with_a_fingerprint(): void Most of the time, you will want your fingerprint hash to be based on the content of a file, to scope it to a specific task or something else. To help you compute this hash, Castor provides a `hasher()` function. It returns an instance of -`Castor\HasherHelper` with various helper methods: +`Castor\Helper\HasherHelper` with various helper methods: - `write()`: Writes a hash of a specific (string) value. - `writeFile()`: Writes a hash of a file content or its modification time. diff --git a/doc/going-further/interacting-with-castor/log.md b/doc/going-further/interacting-with-castor/log.md index 2e045ec9..0722aa5d 100644 --- a/doc/going-further/interacting-with-castor/log.md +++ b/doc/going-further/interacting-with-castor/log.md @@ -67,7 +67,7 @@ If you need to access the raw logger instance, you can get it with the ```php use Castor\Attribute\AsContext; use Castor\Context; -use Castor\PathHelper; +use Castor\Helper\PathHelper; use Monolog\Handler\StreamHandler; use function Castor\logger; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3126631b..8f58a791 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,11 +5,6 @@ parameters: count: 1 path: examples/args.php - - - message: "#^Function pyrech\\\\.* not found\\.$#" - count: 2 - path: examples/ - - message: "#^Default value of the parameter \\#1 \\$data \\(array\\{\\}\\) of method Castor\\\\Context\\:\\:__construct\\(\\) is incompatible with type array\\{name\\: string, production\\: bool, foo\\?\\: string\\}\\.$#" count: 1 @@ -20,6 +15,16 @@ parameters: count: 1 path: src/Context.php + - + message: "#^Class Castor\\\\HasherHelper extends @final class Castor\\\\Helper\\\\HasherHelper\\.$#" + count: 1 + path: src/HasherHelper.php + + - + message: "#^Class Castor\\\\PathHelper extends @final class Castor\\\\Helper\\\\PathHelper\\.$#" + count: 1 + path: src/PathHelper.php + - message: "#^Function Castor\\\\get_exit_code\\(\\) has parameter \\$args with no type specified\\.$#" count: 1 diff --git a/phpstan.neon b/phpstan.neon index a3e1c0a1..32e08fb5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -26,3 +26,8 @@ parameters: reference?: string, } ''' + ignoreErrors: + - + message: "#^Function pyrech\\\\.* not found\\.$#" + count: 2 + path: examples/ diff --git a/src/Console/Application.php b/src/Console/Application.php index 2637ca12..b975369e 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -20,9 +20,9 @@ use Castor\Fingerprint\FingerprintHelper; use Castor\FunctionFinder; use Castor\GlobalHelper; +use Castor\Helper\PlatformHelper; +use Castor\Helper\WaitForHelper; use Castor\Import\Importer; -use Castor\PlatformHelper; -use Castor\WaitForHelper; use Monolog\Logger; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LogLevel; diff --git a/src/Console/ApplicationFactory.php b/src/Console/ApplicationFactory.php index 1b64cac9..222202bf 100644 --- a/src/Console/ApplicationFactory.php +++ b/src/Console/ApplicationFactory.php @@ -10,6 +10,9 @@ use Castor\ExpressionLanguage; use Castor\Fingerprint\FingerprintHelper; use Castor\FunctionFinder; +use Castor\Helper\PathHelper; +use Castor\Helper\PlatformHelper; +use Castor\Helper\WaitForHelper; use Castor\Import\Importer; use Castor\Import\Listener\RemoteImportListener; use Castor\Import\Remote\Composer; @@ -17,10 +20,7 @@ use Castor\Listener\GenerateStubsListener; use Castor\Listener\UpdateCastorListener; use Castor\Monolog\Processor\ProcessProcessor; -use Castor\PathHelper; -use Castor\PlatformHelper; use Castor\Stub\StubsGenerator; -use Castor\WaitForHelper; use Monolog\Logger; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Console\Application as SymfonyApplication; diff --git a/src/Console/Command/CompileCommand.php b/src/Console/Command/CompileCommand.php index 48df44c0..7f2e45ef 100644 --- a/src/Console/Command/CompileCommand.php +++ b/src/Console/Command/CompileCommand.php @@ -2,8 +2,8 @@ namespace Castor\Console\Command; -use Castor\PathHelper; -use Castor\PlatformHelper; +use Castor\Helper\PathHelper; +use Castor\Helper\PlatformHelper; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -15,9 +15,7 @@ use Symfony\Component\Process\Process; use Symfony\Contracts\HttpClient\HttpClientInterface; -/** - * @internal - */ +/** @internal */ class CompileCommand extends Command { // When something **important** related to the compilation changed, increase diff --git a/src/Console/Command/RepackCommand.php b/src/Console/Command/RepackCommand.php index 13d3538f..9ba1d578 100644 --- a/src/Console/Command/RepackCommand.php +++ b/src/Console/Command/RepackCommand.php @@ -3,7 +3,7 @@ namespace Castor\Console\Command; use Castor\FunctionFinder; -use Castor\PathHelper; +use Castor\Helper\PathHelper; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -11,9 +11,7 @@ use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\Process; -/** - * @internal - */ +/** @internal */ class RepackCommand extends Command { protected function configure(): void diff --git a/src/Console/Command/TaskCommand.php b/src/Console/Command/TaskCommand.php index 5c59c85f..ed3a06a7 100644 --- a/src/Console/Command/TaskCommand.php +++ b/src/Console/Command/TaskCommand.php @@ -14,7 +14,7 @@ use Castor\EventDispatcher; use Castor\Exception\FunctionConfigurationException; use Castor\ExpressionLanguage; -use Castor\SluggerHelper; +use Castor\Helper\SluggerHelper; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\SignalableCommandInterface; use Symfony\Component\Console\Exception\LogicException; diff --git a/src/Context.php b/src/Context.php index affa7892..6befc68c 100644 --- a/src/Context.php +++ b/src/Context.php @@ -3,6 +3,7 @@ namespace Castor; use Castor\Console\Output\VerbosityLevel; +use Castor\Helper\PathHelper; use Castor\VerbosityLevel as LegacyVerbosityLevel; class Context implements \ArrayAccess diff --git a/src/ContextRegistry.php b/src/ContextRegistry.php index a0aaa82b..f092cd29 100644 --- a/src/ContextRegistry.php +++ b/src/ContextRegistry.php @@ -4,6 +4,7 @@ use Castor\Descriptor\ContextDescriptor; use Castor\Exception\FunctionConfigurationException; +use Castor\Helper\PathHelper; /** @internal */ class ContextRegistry diff --git a/src/Exception/FunctionConfigurationException.php b/src/Exception/FunctionConfigurationException.php index 1757eb0e..61f05a65 100644 --- a/src/Exception/FunctionConfigurationException.php +++ b/src/Exception/FunctionConfigurationException.php @@ -2,7 +2,7 @@ namespace Castor\Exception; -use Castor\PathHelper; +use Castor\Helper\PathHelper; class FunctionConfigurationException extends \InvalidArgumentException { diff --git a/src/FunctionFinder.php b/src/FunctionFinder.php index 8ec72b5c..3f75e441 100644 --- a/src/FunctionFinder.php +++ b/src/FunctionFinder.php @@ -13,6 +13,7 @@ use Castor\Descriptor\SymfonyTaskDescriptor; use Castor\Descriptor\TaskDescriptor; use Castor\Exception\FunctionConfigurationException; +use Castor\Helper\SluggerHelper; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Finder\Finder; use Symfony\Component\Process\Process; diff --git a/src/HasherHelper.php b/src/HasherHelper.php index d70564b9..8654a55b 100644 --- a/src/HasherHelper.php +++ b/src/HasherHelper.php @@ -2,161 +2,13 @@ namespace Castor; -use Castor\Console\Application; -use Castor\Fingerprint\FileHashStrategy; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; -use Symfony\Component\Finder\Finder; +use Castor\Helper\HasherHelper as BaseHasherHelper; -class HasherHelper -{ - private readonly \HashContext $hashContext; - - /** - * @see https://www.php.net/manual/en/function.hash-algos.php - */ - public function __construct( - private readonly Application $application, - private readonly LoggerInterface $logger = new NullLogger(), - string $algo = 'xxh128', - ) { - $this->hashContext = hash_init($algo); - } - - public function write(string $value): self - { - $this->logger->debug('Hashing value "{value}".', ['value' => $value]); - - hash_update($this->hashContext, $value); - - return $this; - } - - public function writeFile(string $path, FileHashStrategy $strategy = FileHashStrategy::MTimes): self - { - if (!str_starts_with($path, '/')) { - $path = getcwd() . '/' . $path; - } - - if (!is_file($path)) { - throw new \InvalidArgumentException(sprintf('The path "%s" is not a file.', $path)); - } - - if (!is_readable($path)) { - throw new \InvalidArgumentException(sprintf('The file "%s" is not readable.', $path)); - } - - $this->logger->debug('Hashing file "{path}" with strategy "{strategy}".', [ - 'path' => $path, - 'strategy' => $strategy->name, - ]); - - switch ($strategy) { - case FileHashStrategy::Content: - hash_update_file($this->hashContext, $path); - - break; - case FileHashStrategy::MTimes: - hash_update($this->hashContext, sprintf('%s:%s', $path, filemtime($path))); - - break; - } - - return $this; - } - - public function writeWithFinder(Finder $finder, FileHashStrategy $strategy = FileHashStrategy::MTimes): self - { - $this->logger->debug('Hashing files with Finder with strategy "{strategy}".', [ - 'strategy' => $strategy->name, - ]); - - foreach ($finder as $file) { - switch ($strategy) { - case FileHashStrategy::Content: - hash_update_file($this->hashContext, $file->getPathname()); - - break; - case FileHashStrategy::MTimes: - hash_update($this->hashContext, "{$file->getPathname()}:{$file->getMTime()}"); - - break; - } - } - - return $this; - } +trigger_deprecation('castor', '0.15', 'The "%s" class is deprecated, use "%s" instead.', HasherHelper::class, BaseHasherHelper::class); - public function writeGlob(string $pattern, FileHashStrategy $strategy = FileHashStrategy::MTimes): self - { - $this->logger->debug('Hashing files {pattern} with strategy "{strategy}".', [ - 'pattern' => $pattern, - 'strategy' => $strategy->name, - ]); - - $files = glob($pattern); - - if (false === $files) { - throw new \InvalidArgumentException(sprintf('The pattern "%s" is invalid.', $pattern)); - } - - foreach ($files as $file) { - switch ($strategy) { - case FileHashStrategy::Content: - hash_update_file($this->hashContext, $file); - - break; - case FileHashStrategy::MTimes: - $modifiedTime = filemtime($file); - hash_update($this->hashContext, "{$file}:{$modifiedTime}"); - - break; - } - } - - return $this; - } - - public function writeTaskName(): self - { - $taskName = $this->application->getCommand()->getName() ?? 'n/a'; - - $this->logger->debug('Hashing task name "{name}".', [ - 'name' => $taskName, - ]); - - hash_update($this->hashContext, $taskName); - - return $this; - } - - public function writeTaskArgs(string ...$args): self - { - $this->logger->debug('Hashing task args "{args}".', [ - 'args' => implode(', ', $args), - ]); - - $input = $this->application->getInput(); - - foreach ($args as $arg) { - if ($input->hasArgument($arg)) { - $this->write($input->getArgument($arg)); - } - } - - return $this; - } - - public function writeTask(string ...$args): self - { - $this->writeTaskName(); - $this->writeTaskArgs(...$args); - - return $this; - } - - public function finish(): string - { - return hash_final($this->hashContext); - } +/** + * @deprecated since castor/castor 0.15, use Castor\Helper\HasherHelper instead. + */ +class HasherHelper extends BaseHasherHelper +{ } diff --git a/src/Helper/HasherHelper.php b/src/Helper/HasherHelper.php new file mode 100644 index 00000000..63b8eba0 --- /dev/null +++ b/src/Helper/HasherHelper.php @@ -0,0 +1,165 @@ +hashContext = hash_init($algo); + } + + public function write(string $value): self + { + $this->logger->debug('Hashing value "{value}".', ['value' => $value]); + + hash_update($this->hashContext, $value); + + return $this; + } + + public function writeFile(string $path, FileHashStrategy $strategy = FileHashStrategy::MTimes): self + { + if (!str_starts_with($path, '/')) { + $path = getcwd() . '/' . $path; + } + + if (!is_file($path)) { + throw new \InvalidArgumentException(sprintf('The path "%s" is not a file.', $path)); + } + + if (!is_readable($path)) { + throw new \InvalidArgumentException(sprintf('The file "%s" is not readable.', $path)); + } + + $this->logger->debug('Hashing file "{path}" with strategy "{strategy}".', [ + 'path' => $path, + 'strategy' => $strategy->name, + ]); + + switch ($strategy) { + case FileHashStrategy::Content: + hash_update_file($this->hashContext, $path); + + break; + case FileHashStrategy::MTimes: + hash_update($this->hashContext, sprintf('%s:%s', $path, filemtime($path))); + + break; + } + + return $this; + } + + public function writeWithFinder(Finder $finder, FileHashStrategy $strategy = FileHashStrategy::MTimes): self + { + $this->logger->debug('Hashing files with Finder with strategy "{strategy}".', [ + 'strategy' => $strategy->name, + ]); + + foreach ($finder as $file) { + switch ($strategy) { + case FileHashStrategy::Content: + hash_update_file($this->hashContext, $file->getPathname()); + + break; + case FileHashStrategy::MTimes: + hash_update($this->hashContext, "{$file->getPathname()}:{$file->getMTime()}"); + + break; + } + } + + return $this; + } + + public function writeGlob(string $pattern, FileHashStrategy $strategy = FileHashStrategy::MTimes): self + { + $this->logger->debug('Hashing files {pattern} with strategy "{strategy}".', [ + 'pattern' => $pattern, + 'strategy' => $strategy->name, + ]); + + $files = glob($pattern); + + if (false === $files) { + throw new \InvalidArgumentException(sprintf('The pattern "%s" is invalid.', $pattern)); + } + + foreach ($files as $file) { + switch ($strategy) { + case FileHashStrategy::Content: + hash_update_file($this->hashContext, $file); + + break; + case FileHashStrategy::MTimes: + $modifiedTime = filemtime($file); + hash_update($this->hashContext, "{$file}:{$modifiedTime}"); + + break; + } + } + + return $this; + } + + public function writeTaskName(): self + { + $taskName = $this->application->getCommand()->getName() ?? 'n/a'; + + $this->logger->debug('Hashing task name "{name}".', [ + 'name' => $taskName, + ]); + + hash_update($this->hashContext, $taskName); + + return $this; + } + + public function writeTaskArgs(string ...$args): self + { + $this->logger->debug('Hashing task args "{args}".', [ + 'args' => implode(', ', $args), + ]); + + $input = $this->application->getInput(); + + foreach ($args as $arg) { + if ($input->hasArgument($arg)) { + $this->write($input->getArgument($arg)); + } + } + + return $this; + } + + public function writeTask(string ...$args): self + { + $this->writeTaskName(); + $this->writeTaskArgs(...$args); + + return $this; + } + + public function finish(): string + { + return hash_final($this->hashContext); + } +} diff --git a/src/Helper/ParallelHelper.php b/src/Helper/ParallelHelper.php new file mode 100644 index 00000000..5f32add2 --- /dev/null +++ b/src/Helper/ParallelHelper.php @@ -0,0 +1,74 @@ + + */ + public static function parallel(Application $app, OutputInterface $output, callable ...$callbacks): array + { + /** @var \Fiber[] $fibers */ + $fibers = []; + $exceptions = []; + + foreach ($callbacks as $callback) { + $fiber = new \Fiber($callback); + + try { + $fiber->start(); + } catch (\Throwable $e) { + if ($output instanceof ConsoleOutput) { + $output = $output->getErrorOutput(); + } + + $app->renderThrowable($e, $output); + + $exceptions[] = $e; + } + + $fibers[] = $fiber; + } + + $isRunning = true; + + while ($isRunning) { + $isRunning = false; + + foreach ($fibers as $fiber) { + $isRunning = $isRunning || !$fiber->isTerminated(); + + if (!$fiber->isTerminated() && $fiber->isSuspended()) { + try { + $fiber->resume(); + } catch (\Throwable $e) { + if ($output instanceof ConsoleOutput) { + $output = $output->getErrorOutput(); + } + + $app->renderThrowable($e, $output); + + $exceptions[] = $e; + } + } + } + + if (\Fiber::getCurrent()) { + \Fiber::suspend(); + usleep(1_000); + } + } + + if ($exceptions) { + throw new \RuntimeException('One or more exceptions were thrown in parallel.'); + } + + return array_map(fn ($fiber) => $fiber->getReturn(), $fibers); + } +} diff --git a/src/Helper/PathHelper.php b/src/Helper/PathHelper.php new file mode 100644 index 00000000..d12c1ead --- /dev/null +++ b/src/Helper/PathHelper.php @@ -0,0 +1,56 @@ + $path + * @param (callable(string, string) : (false|void|null)) $function + */ + public static function watch(Application $app, SectionOutput $sectionOutput, string|array $path, callable $function, Context $context): void + { + $output = $sectionOutput->getConsoleOutput(); + + if (\is_array($path)) { + $parallelCallbacks = []; + + foreach ($path as $p) { + $parallelCallbacks[] = fn () => self::watch($app, $sectionOutput, $p, $function, $context); + } + + ParallelHelper::parallel($app, $output, ...$parallelCallbacks); + + return; + } + + $binary = match (true) { + OsHelper::isMacOS() => match (php_uname('m')) { + 'arm64' => 'watcher-darwin-arm64', + default => 'watcher-darwin-amd64', + }, + OsHelper::isWindows() => 'watcher-windows.exe', + default => match (php_uname('m')) { + 'arm64' => 'watcher-linux-arm64', + default => 'watcher-linux-amd64', + }, + }; + + $binaryPath = __DIR__ . '/../../tools/watcher/bin/' . $binary; + + if (str_starts_with(__FILE__, 'phar:')) { + static $tmpPath; + + if (null === $tmpPath) { + $tmpPath = sys_get_temp_dir() . '/' . $binary; + copy($binaryPath, $tmpPath); + chmod($tmpPath, 0o755); + } + + $binaryPath = $tmpPath; + } + + $watchContext = $context->withTty(false)->withPty(false)->withTimeout(null); + + $command = [$binaryPath, $path]; + $buffer = ''; + + run($command, callback: static function ($type, $bytes, $process) use ($function, $sectionOutput, &$buffer) { + if (Process::OUT === $type) { + $data = $buffer . $bytes; + $lines = explode("\n", $data); + + while (!empty($lines)) { + $line = trim($lines[0]); + + if ('' === $line) { + array_shift($lines); + + continue; + } + + try { + $eventLine = json_decode($line, true, 512, \JSON_THROW_ON_ERROR); + } catch (\JsonException) { + $buffer = implode("\n", $lines); + + break; + } + + $result = $function($eventLine['name'], $eventLine['operation']); + + if (false === $result) { + $process->stop(); + } + + array_shift($lines); + } + } else { + $sectionOutput->writeProcessOutput($type, $bytes, $process); + } + }, context: $watchContext); + } +} diff --git a/src/Import/Remote/Composer.php b/src/Import/Remote/Composer.php index 8db27855..e3179ef2 100644 --- a/src/Import/Remote/Composer.php +++ b/src/Import/Remote/Composer.php @@ -5,8 +5,8 @@ use Castor\Console\Application; use Castor\Fingerprint\FingerprintHelper; use Castor\GlobalHelper; +use Castor\Helper\PathHelper; use Castor\Import\Exception\ComposerError; -use Castor\PathHelper; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Helper\ProgressIndicator; use Symfony\Component\Filesystem\Filesystem; diff --git a/src/Import/Remote/PackageImporter.php b/src/Import/Remote/PackageImporter.php index e35a4a47..a2fdb0e4 100644 --- a/src/Import/Remote/PackageImporter.php +++ b/src/Import/Remote/PackageImporter.php @@ -3,10 +3,10 @@ namespace Castor\Import\Remote; use Castor\Console\Application; +use Castor\Helper\PathHelper; use Castor\Import\Exception\ImportError; use Castor\Import\Exception\InvalidImportFormat; use Castor\Import\Exception\RemoteNotAllowed; -use Castor\PathHelper; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputInterface; @@ -111,7 +111,7 @@ public function fetchPackages(InputInterface $input): void */ private function importPackageWithComposer(string $package, string $version, ?string $repositoryUrl = null, ?array $source = null, ?string $file = null): void { - $this->logger->notice('Importing remote package with Composer.', [ + $this->logger->info('Importing remote package with Composer.', [ 'package' => $package, 'version' => $version, ]); diff --git a/src/Listener/UpdateCastorListener.php b/src/Listener/UpdateCastorListener.php index 142d2d9f..a03a8ad8 100644 --- a/src/Listener/UpdateCastorListener.php +++ b/src/Listener/UpdateCastorListener.php @@ -3,7 +3,7 @@ namespace Castor\Listener; use Castor\Console\Application; -use Castor\PlatformHelper; +use Castor\Helper\PlatformHelper; use JoliCode\PhpOsHelper\OsHelper; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; diff --git a/src/PathHelper.php b/src/PathHelper.php index 5dcb7034..6147cd3a 100644 --- a/src/PathHelper.php +++ b/src/PathHelper.php @@ -2,52 +2,13 @@ namespace Castor; -use Symfony\Component\Filesystem\Path; +use Castor\Helper\PathHelper as BasePathHelper; -class PathHelper -{ - public static function getRoot(): string - { - static $root; - - if (null === $root) { - if (class_exists(\RepackedApplication::class)) { - return $root = Path::getDirectory(getcwd() ?: '.'); - } - - $path = getcwd() ?: '/'; - - while (!(file_exists($path . '/castor.php') || file_exists($path . '/.castor/castor.php'))) { - if ('/' === $path) { - throw new \RuntimeException('Could not find root "castor.php" file.'); - } - - $path = Path::getDirectory($path); - } - - $root = $path; - } +trigger_deprecation('castor', '0.15', 'The "%s" class is deprecated, use "%s" instead.', PathHelper::class, BasePathHelper::class); - return $root; - } - - public static function realpath(string $path): string - { - $realpath = realpath($path); - - if (false === $realpath) { - throw new \RuntimeException(sprintf('Directory "%s" not found.', $path)); - } - - return $realpath; - } - - public static function makeRelative(string $path): string - { - if (!Path::isAbsolute($path)) { - throw new \RuntimeException(sprintf('Path "%s" is not absolute.', $path)); - } - - return Path::makeRelative($path, self::getRoot()); - } +/** + * @deprecated since castor/castor 0.15, use Castor\Helper\PathHelper instead. + */ +class PathHelper extends BasePathHelper +{ } diff --git a/src/functions.php b/src/functions.php index 71b94a1f..e5437ac9 100644 --- a/src/functions.php +++ b/src/functions.php @@ -8,6 +8,10 @@ use Castor\Exception\MinimumVersionRequirementNotMetException; use Castor\Exception\WaitFor\ExitedBeforeTimeoutException; use Castor\Exception\WaitFor\TimeoutReachedException; +use Castor\Helper\HasherHelper; +use Castor\Helper\ParallelHelper; +use Castor\Helper\PathHelper; +use Castor\Helper\WatchHelper; use Joli\JoliNotif\Notification; use Joli\JoliNotif\NotifierFactory; use JoliCode\PhpOsHelper\OsHelper; @@ -17,7 +21,6 @@ use Spatie\Ssh\Ssh; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Dotenv\Dotenv; @@ -40,68 +43,7 @@ */ function parallel(callable ...$callbacks): array { - /** @var \Fiber[] $fibers */ - $fibers = []; - $exceptions = []; - - foreach ($callbacks as $callback) { - $fiber = new \Fiber($callback); - - try { - $fiber->start(); - } catch (\Throwable $e) { - $app = app(); - $output = output(); - - if ($output instanceof ConsoleOutput) { - $output = $output->getErrorOutput(); - } - - $app->renderThrowable($e, $output); - - $exceptions[] = $e; - } - - $fibers[] = $fiber; - } - - $isRunning = true; - - while ($isRunning) { - $isRunning = false; - - foreach ($fibers as $fiber) { - $isRunning = $isRunning || !$fiber->isTerminated(); - - if (!$fiber->isTerminated() && $fiber->isSuspended()) { - try { - $fiber->resume(); - } catch (\Throwable $e) { - $app = app(); - $output = output(); - - if ($output instanceof ConsoleOutput) { - $output = $output->getErrorOutput(); - } - - $app->renderThrowable($e, $output); - - $exceptions[] = $e; - } - } - } - - if (\Fiber::getCurrent()) { - \Fiber::suspend(); - usleep(1_000); - } - } - - if ($exceptions) { - throw new \RuntimeException('One or more exceptions were thrown in parallel.'); - } - - return array_map(fn ($fiber) => $fiber->getReturn(), $fibers); + return ParallelHelper::parallel(GlobalHelper::getApplication(), GlobalHelper::getOutput(), ...$callbacks); } /** @@ -526,85 +468,9 @@ function notify(string $message): void */ function watch(string|array $path, callable $function, ?Context $context = null): void { - if (\is_array($path)) { - $parallelCallbacks = []; - - foreach ($path as $p) { - $parallelCallbacks[] = fn () => watch($p, $function, $context); - } - - parallel(...$parallelCallbacks); - - return; - } - $context ??= GlobalHelper::getContext(); - $binary = match (true) { - OsHelper::isMacOS() => match (php_uname('m')) { - 'arm64' => 'watcher-darwin-arm64', - default => 'watcher-darwin-amd64', - }, - OsHelper::isWindows() => 'watcher-windows.exe', - default => match (php_uname('m')) { - 'arm64' => 'watcher-linux-arm64', - default => 'watcher-linux-amd64', - }, - }; - - $binaryPath = __DIR__ . '/../tools/watcher/bin/' . $binary; - - if (str_starts_with(__FILE__, 'phar:')) { - static $tmpPath; - - if (null === $tmpPath) { - $tmpPath = sys_get_temp_dir() . '/' . $binary; - copy($binaryPath, $tmpPath); - chmod($tmpPath, 0o755); - } - - $binaryPath = $tmpPath; - } - - $watchContext = $context->withTty(false)->withPty(false)->withTimeout(null); - - $command = [$binaryPath, $path]; - $buffer = ''; - - run($command, callback: static function ($type, $bytes, $process) use ($function, &$buffer) { - if (Process::OUT === $type) { - $data = $buffer . $bytes; - $lines = explode("\n", $data); - - while (!empty($lines)) { - $line = trim($lines[0]); - - if ('' === $line) { - array_shift($lines); - - continue; - } - - try { - $eventLine = json_decode($line, true, 512, \JSON_THROW_ON_ERROR); - } catch (\JsonException) { - $buffer = implode("\n", $lines); - - break; - } - - $result = $function($eventLine['name'], $eventLine['operation']); - - if (false === $result) { - $process->stop(); - } - - array_shift($lines); - } - } else { - GlobalHelper::getSectionOutput()->writeProcessOutput($type, $bytes, $process); - } - }, context: $watchContext); + WatchHelper::watch(GlobalHelper::getApplication(), GlobalHelper::getSectionOutput(), $path, $function, $context); } /** diff --git a/tests/Examples/Fingerprint/FingerprintedTestCase.php b/tests/Examples/Fingerprint/FingerprintedTestCase.php index c8660d9c..9fa129fd 100644 --- a/tests/Examples/Fingerprint/FingerprintedTestCase.php +++ b/tests/Examples/Fingerprint/FingerprintedTestCase.php @@ -2,7 +2,7 @@ namespace Castor\Tests\Examples\Fingerprint; -use Castor\PlatformHelper; +use Castor\Helper\PlatformHelper; use Castor\Tests\TaskTestCase; use Symfony\Component\Finder\Finder; diff --git a/tests/Examples/Generated/LayoutWithFolder.php.output.txt b/tests/Examples/Generated/LayoutWithFolder.php.output.txt index ea8e47ee..e571ce6d 100644 --- a/tests/Examples/Generated/LayoutWithFolder.php.output.txt +++ b/tests/Examples/Generated/LayoutWithFolder.php.output.txt @@ -9,6 +9,8 @@ Options: -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question + --no-remote Skip the import of all remote remote packages + --update-remotes Force the update of remote packages -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: diff --git a/tests/Examples/Generated/LayoutWithOldFolder.php.output.txt b/tests/Examples/Generated/LayoutWithOldFolder.php.output.txt index 9774f101..2842f343 100644 --- a/tests/Examples/Generated/LayoutWithOldFolder.php.output.txt +++ b/tests/Examples/Generated/LayoutWithOldFolder.php.output.txt @@ -10,6 +10,8 @@ Options: -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question + --no-remote Skip the import of all remote remote packages + --update-remotes Force the update of remote packages -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: diff --git a/tests/Examples/Generated/ParallelExceptionTest.php.err.txt b/tests/Examples/Generated/ParallelExceptionTest.php.err.txt index ffa867bc..998e7ba0 100644 --- a/tests/Examples/Generated/ParallelExceptionTest.php.err.txt +++ b/tests/Examples/Generated/ParallelExceptionTest.php.err.txt @@ -14,7 +14,7 @@ In parallel.php line 72: parallel:exception -In functions.php line XXXX: +In ParallelHelper.php line XXXX: One or more exceptions were thrown in parallel. diff --git a/tests/Helper/OutputCleaner.php b/tests/Helper/OutputCleaner.php index 725ff4d0..040719a6 100644 --- a/tests/Helper/OutputCleaner.php +++ b/tests/Helper/OutputCleaner.php @@ -12,6 +12,7 @@ public static function cleanOutput(string $string): string $string = str_replace('castor.linux-amd64.phar', 'castor', $string); $string = preg_replace('{In functions.php line \d+:}m', 'In functions.php line XXXX:', $string); $string = preg_replace('{In FunctionFinder.php line \d+:}m', 'In FunctionFinder.php line XXXX:', $string); + $string = preg_replace('{In ParallelHelper.php line \d+:}m', 'In ParallelHelper.php line XXXX:', $string); $string = preg_replace('{In Process.php line \d+:}m', 'In Process.php line XXXX:', $string); $string = preg_replace('{In ContextRegistry.php line \d+:}m', 'In ContextRegistry.php line XXXX:', $string); $string = preg_replace('{you are using v\d+.\d+.\d+.}m', 'you are using vX.Y.Z.', $string); diff --git a/tests/bin/compile-get-cache-key b/tests/bin/compile-get-cache-key index 84909ea4..6ad9b0ce 100755 --- a/tests/bin/compile-get-cache-key +++ b/tests/bin/compile-get-cache-key @@ -4,7 +4,7 @@ require __DIR__ . '/../../vendor/autoload.php'; use Castor\Console\Command\CompileCommand; -use Castor\PlatformHelper; +use Castor\Helper\PlatformHelper; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command;