diff --git a/.github/actions/phar/action.yaml b/.github/actions/phar/action.yaml index eb3966c9..d4543ea0 100644 --- a/.github/actions/phar/action.yaml +++ b/.github/actions/phar/action.yaml @@ -18,19 +18,19 @@ runs: shell: bash working-directory: tools/phar - - name: Build Castor PHAR Archive for Linux + - name: Build Castor phar for Linux run: bin/castor castor:phar:linux shell: bash - - name: Build Castor PHAR Archive for Darwin + - name: Build Castor phar for Darwin run: bin/castor castor:phar:darwin shell: bash - - name: Build Castor PHAR Archive for Windows + - name: Build Castor phar for Windows run: bin/castor castor:phar:windows shell: bash - - name: Ensure PHAR is OK + - name: Ensure phar is OK run: build/castor.linux-amd64.phar --version shell: bash working-directory: tools/phar diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75715e14..f22b2213 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: - php: "8.1" castor: bin: 'bin/castor' - method: 'vendor' + method: 'bin/castor' - php: "8.1" castor: bin: 'tools/phar/build/castor.linux-amd64.phar' @@ -53,16 +53,14 @@ jobs: castor: bin: 'castor' method: 'binary' - build-options: '--php-extensions=mbstring,phar,posix,tokenizer,pcntl' - php-bin: 'none' - php: "8.2" castor: bin: 'bin/castor' - method: 'vendor' + method: 'bin/castor' - php: "8.3" castor: bin: 'bin/castor' - method: 'vendor' + method: 'bin/castor' steps: - name: Checkout @@ -81,7 +79,7 @@ jobs: run: composer install --prefer-dist --no-progress --optimize-autoloader --classmap-authoritative working-directory: tools/phar - - name: Build Castor PHAR Archive for Linux + - name: Build Castor phar for Linux run: bin/castor castor:phar:linux shell: bash if: matrix.castor.method == 'phar' || matrix.castor.method == 'binary' @@ -93,8 +91,8 @@ jobs: # /tmp/castor-php-static-compiler # key: php-static-build-cache-${{ hashFiles('src/Console/Command/CompileCommand.php', 'tests/CompileCommandTest.php') }} - - name: Compile Custom Built PHP along Castor PHAR Archive for Linux - run: bin/castor compile tools/phar/build/castor.linux-amd64.phar ${{ matrix.castor.build-options }} + - name: Compile Custom Built PHP along Castor phar for Linux + run: bin/castor compile tools/phar/build/castor.linux-amd64.phar --php-extensions=mbstring,phar,posix,tokenizer,pcntl shell: bash if: matrix.castor.method == 'binary' @@ -108,10 +106,9 @@ jobs: run: vendor/bin/simple-phpunit env: CASTOR_BIN: ${{ github.workspace }}/${{ matrix.castor.bin }} - PHP_BIN: ${{ matrix.castor.php-bin }} phar: - name: Ensure PHAR is OK + name: Ensure phar is OK runs-on: ubuntu-latest steps: diff --git a/bin/generate-tests.php b/bin/generate-tests.php index 9e655895..45a3d947 100755 --- a/bin/generate-tests.php +++ b/bin/generate-tests.php @@ -63,6 +63,7 @@ 'log:with-context', 'parallel:sleep', 'repack', + 'compile', 'run:ls', 'run:run-parallel', ]; diff --git a/doc/going-further/compile.md b/doc/going-further/compile.md index 1a79173e..a5233f87 100644 --- a/doc/going-further/compile.md +++ b/doc/going-further/compile.md @@ -1,17 +1,21 @@ # Compiling your application into a standalone binary -[Putting your Castor application into a PHAR archive](repack.md) can be a good way to easily share and use it in various environments. +[Packing your Castor application as a phar](repack.md) can be a good way to easily +share and use it in various environments. -However, you need to ensure that PHP is installed and configured correctly in all the environments where you want to use your Castor app. +However, you need to ensure that PHP is installed and configured correctly in all +the environments where you want to use your Castor app. This can be a hassle, especially if you don't have control over the environments. -To make things simpler, Castor's `compile` command can help by creating a customizable PHP binary with a PHAR archive, making one executable file that can be used in any setting. +To make things simpler, Castor's `compile` command can help by creating a +customizable PHP binary with a phar, making one executable file that can be used in any setting. -Just pass your repacked Castor app PHAR as an argument of this command. +Just pass your repacked Castor app phar as an argument of this command. ## Pre-requisites -Follow the [`repack` documentation](repack.md) to output a PHAR archive of your Castor app. +Follow the [`repack` documentation](repack.md) to produce a phar of your +Castor app. ## Running the Compile Command @@ -28,19 +32,20 @@ vendor/bin/castor compile my-custom-castor-app.phar Make sure to take a look at the command description to see all the available options: ```bash -vendor/bin/castor compile -h -`````` +vendor/bin/castor compile --help +``` + ### Behavior The `compile` command performs several steps: -1. Downloads or uses an existing Static PHP CLI tool to compile PHP and the PHAR archive into a binary. +1. Downloads or uses an existing [Static PHP CLI tool](https://github.com/crazywhalecc/static-php-cli) to compile PHP and the phar into a binary. 2. If required, it automatically installs dependencies and compiles PHP with the specified extensions. -3. Combines the compiled PHP and your PHAR file into a single executable. +3. Combines the compiled PHP and your phar file into a single executable. ## Post-Compilation -Once the compilation is finished, your Castor application is transformed into a standalone binary named `compiled-castor` by default (you can use the `--output=` option to change it). +Once the compilation is finished, your Castor application is transformed into a standalone binary named `castor` by default (you can use the `--output` option to change it). This binary is now ready to be distributed and run in environments that do not have PHP installed. diff --git a/doc/going-further/repack.md b/doc/going-further/repack.md index 67842cb8..6ed8b2a6 100644 --- a/doc/going-further/repack.md +++ b/doc/going-further/repack.md @@ -41,6 +41,6 @@ vendor/bin/castor repack --help ## Going further -Packaging your Castor app as a PHAR archive simplifies distribution but requires PHP setup on target systems. +Packaging your Castor app as a phar simplifies distribution but requires PHP setup on target systems. -[Castor's `compile` command](compile.md) streamlines this by embedding the PHAR in a PHP binary, creating a standalone executable for diverse environments +[Castor's `compile` command](compile.md) streamlines this by embedding the phar in a PHP binary, creating a standalone executable for diverse environments. diff --git a/examples/failure.php b/examples/failure.php index f238fda4..4073c714 100644 --- a/examples/failure.php +++ b/examples/failure.php @@ -9,7 +9,7 @@ #[AsTask(description: 'A failing task not authorized to fail')] function failure(): void { - run('i_do_not_exist', path: '/tmp'); + run('i_do_not_exist', path: '/tmp', pty: false); } #[AsTask(description: 'A failing task authorized to fail')] diff --git a/src/Console/Command/CompileCommand.php b/src/Console/Command/CompileCommand.php index 2e2afcdc..d9ccaac7 100644 --- a/src/Console/Command/CompileCommand.php +++ b/src/Console/Command/CompileCommand.php @@ -5,7 +5,6 @@ use Castor\PathHelper; use Castor\PlatformUtil; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -31,11 +30,11 @@ protected function configure(): void { $this ->setName('compile') - ->addArgument('phar-path', InputArgument::REQUIRED, 'Path to PHAR archived compiled along PHP') + ->addArgument('phar-path', InputArgument::REQUIRED, 'Path to phar to compile along PHP') ->addOption('output', null, InputOption::VALUE_REQUIRED, 'Compiled standalone binary output filepath', PathHelper::getRoot() . '/castor') ->addOption('os', null, InputOption::VALUE_REQUIRED, 'Target OS for PHP compilation', 'linux', ['linux', 'macos']) ->addOption('arch', null, InputOption::VALUE_REQUIRED, 'Target architecture for PHP compilation', 'x86_64', ['x86_64', 'aarch64']) - ->addOption('php-version', null, InputOption::VALUE_REQUIRED, 'PHP version in major.minor format', '8.2') + ->addOption('php-version', null, InputOption::VALUE_REQUIRED, 'PHP version in major.minor format', '8.3') ->addOption('php-extensions', null, InputOption::VALUE_REQUIRED, 'PHP extensions required, in a comma-separated format. Defaults are the minimum required to run a basic "Hello World" task in Castor.', 'mbstring,phar,posix,tokenizer') ->addOption('php-rebuild', null, InputOption::VALUE_NONE, 'Ignore cache and force PHP build compilation.') ->setHidden(true) @@ -55,7 +54,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $io = new SymfonyStyle($input, $output); - $io->section('Compiling PHP and your Castor app PHAR archive into a standalone binary'); + $io->section('Compiling PHP and your Castor app phar into a standalone binary'); $spcBinaryPath = PlatformUtil::getCacheDirectory() . '/castor-php-static-compiler/spc'; $spcBinaryDir = \dirname($spcBinaryPath); @@ -102,16 +101,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } - private function downloadSPC(string $spcSourceUrl, string $spcBinaryDestination, OutputInterface $output): void + private function downloadSPC(string $spcSourceUrl, string $spcBinaryDestination, SymfonyStyle $io): void { $response = $this->httpClient->request('GET', $spcSourceUrl); $contentLength = $response->getHeaders()['content-length'][0] ?? 0; $outputStream = fopen($spcBinaryDestination, 'w'); - $progressBar = new ProgressBar($output, (int) $contentLength); + $progressBar = $io->createProgressBar((int) $contentLength); if (false === $outputStream) { - throw new \RuntimeException(sprintf('Failed to open file "%s" for writing', $spcBinaryDestination)); + throw new \RuntimeException(sprintf('Failed to open file "%s" for writing.', $spcBinaryDestination)); } foreach ($this->httpClient->stream($response) as $chunk) { @@ -128,15 +127,12 @@ private function downloadSPC(string $spcSourceUrl, string $spcBinaryDestination, private function installPHPBuildTools(string $spcBinaryPath, string $spcBinaryDir, SymfonyStyle $io): void { $installSPCDepsProcess = new Process( - command: [ - $spcBinaryPath, 'doctor', - '--auto-fix', - ], + command: [$spcBinaryPath, 'doctor', '--auto-fix'], cwd: $spcBinaryDir, - timeout: 5 * 60 + timeout: null, ); $io->text('Running command: ' . $installSPCDepsProcess->getCommandLine()); - $installSPCDepsProcess->mustRun(fn ($type, $buffer) => print ($buffer)); + $installSPCDepsProcess->mustRun(fn ($type, $buffer) => print $buffer); } private function downloadPHPSourceDeps(string $spcBinaryPath, mixed $phpExtensions, mixed $phpVersion, string $spcBinaryDir, SymfonyStyle $io): void @@ -148,10 +144,10 @@ private function downloadPHPSourceDeps(string $spcBinaryPath, mixed $phpExtensio '--with-php=' . $phpVersion, ], cwd: $spcBinaryDir, - timeout: 5 * 60 + timeout: null, ); $io->text('Running command: ' . $downloadProcess->getCommandLine()); - $downloadProcess->mustRun(fn ($type, $buffer) => print ($buffer)); + $downloadProcess->mustRun(fn ($type, $buffer) => print $buffer); } private function buildPHP(string $spcBinaryPath, mixed $phpExtensions, mixed $arch, string $spcBinaryDir, SymfonyStyle $io): void @@ -161,13 +157,12 @@ private function buildPHP(string $spcBinaryPath, mixed $phpExtensions, mixed $ar $spcBinaryPath, 'build', $phpExtensions, '--build-micro', '--arch=' . $arch, - '-r', ], cwd: $spcBinaryDir, - timeout: 60 * 60 + timeout: null, ); $io->text('Running command: ' . $buildProcess->getCommandLine()); - $buildProcess->mustRun(fn ($type, $buffer) => print ($buffer)); + $buildProcess->mustRun(fn ($type, $buffer) => print $buffer); } private function mergePHPandPHARIntoSingleExecutable(string $spcBinaryPath, string $pharFilePath, string $appBinaryFilePath, string $spcBinaryDir, SymfonyStyle $io): void @@ -182,11 +177,12 @@ private function mergePHPandPHARIntoSingleExecutable(string $spcBinaryPath, stri 'micro:combine', $pharFilePath, '--output=' . $appBinaryFilePath, ], - cwd: $spcBinaryDir + cwd: $spcBinaryDir, + timeout: null, ); $io->text('Running command: ' . $mergePHPandPHARProcess->getCommandLine()); - $mergePHPandPHARProcess->mustRun(fn ($type, $buffer) => print ($buffer)); + $mergePHPandPHARProcess->mustRun(fn ($type, $buffer) => print $buffer); } private function setupSPC(string $spcBinaryDir, string $spcBinaryPath, SymfonyStyle $io, mixed $os, mixed $arch, OutputInterface $output): void @@ -198,7 +194,7 @@ private function setupSPC(string $spcBinaryDir, string $spcBinaryPath, SymfonySt } else { $spcSourceUrl = sprintf('https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-%s-%s', $os, $arch); $io->text(sprintf('Downloading the static-php-cli (spc) tool from "%s" to "%s"', $spcSourceUrl, $spcBinaryPath)); - $this->downloadSPC($spcSourceUrl, $spcBinaryPath, $output); + $this->downloadSPC($spcSourceUrl, $spcBinaryPath, $io); $io->newLine(2); } } diff --git a/src/Console/Command/RepackCommand.php b/src/Console/Command/RepackCommand.php index 1eb6d004..e55adb4c 100644 --- a/src/Console/Command/RepackCommand.php +++ b/src/Console/Command/RepackCommand.php @@ -106,7 +106,7 @@ class RepackedApplication extends Application $process = new Process([$box, 'compile', '--config=.box.json']); try { - $process->mustRun(fn ($type, $buffer) => print ($buffer)); + $process->mustRun(fn ($type, $buffer) => print $buffer); } finally { unlink('.box.json'); unlink('.main.php'); diff --git a/tests/Examples/Generated/FailureFailureTest.php.err.txt b/tests/Examples/Generated/FailureFailureTest.php.err.txt index 29775049..86a74933 100644 --- a/tests/Examples/Generated/FailureFailureTest.php.err.txt +++ b/tests/Examples/Generated/FailureFailureTest.php.err.txt @@ -1,3 +1,4 @@ +sh: 1: i_do_not_exist: not found In failure.php line 12: diff --git a/tests/Examples/Generated/FailureFailureTest.php.output.txt b/tests/Examples/Generated/FailureFailureTest.php.output.txt index e5b48ae6..e69de29b 100644 --- a/tests/Examples/Generated/FailureFailureTest.php.output.txt +++ b/tests/Examples/Generated/FailureFailureTest.php.output.txt @@ -1 +0,0 @@ -sh: 1: i_do_not_exist: not found diff --git a/tests/TaskTestCase.php b/tests/TaskTestCase.php index 39ef44de..ac238a09 100644 --- a/tests/TaskTestCase.php +++ b/tests/TaskTestCase.php @@ -18,7 +18,6 @@ public function runTask(array $args, ?string $cwd = null): Process $coverage = $this->getTestResultObject()?->getCodeCoverage(); $castorBin = $_SERVER['CASTOR_BIN'] ?? __DIR__ . '/../bin/castor'; - $phpBin = !isset($_SERVER['PHP_BIN']) || '' === $_SERVER['PHP_BIN'] ? \PHP_BINARY : $_SERVER['PHP_BIN']; $extraEnv = [ 'ENDPOINT' => $_SERVER['ENDPOINT'], @@ -34,14 +33,8 @@ public function runTask(array $args, ?string $cwd = null): Process ]; } - $commandLine = [$castorBin, '--no-ansi', ...$args]; - - if ('none' !== $phpBin) { - array_unshift($commandLine, $phpBin); - } - $process = new Process( - $commandLine, + [$castorBin, '--no-ansi', ...$args], cwd: $cwd ?? __DIR__ . '/..', env: [ 'COLUMNS' => 120, diff --git a/tools/php-cs-fixer/composer.json b/tools/php-cs-fixer/composer.json index b7376b6a..b0ac7ffc 100644 --- a/tools/php-cs-fixer/composer.json +++ b/tools/php-cs-fixer/composer.json @@ -1,5 +1,5 @@ { "require": { - "friendsofphp/php-cs-fixer": "3.48.*" + "friendsofphp/php-cs-fixer": "^3.46" } }