From 6b7dc4a883c199c93403adbc7dfaefdd52fc9336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Tue, 24 Apr 2018 10:24:12 +0100 Subject: [PATCH] Fix the parallel processing in a renamed PHAR (#160) When the PHAR was renamed, the autoload files could no longer be found. Closes #152 --- .gitignore | 1 + Makefile | 27 ++++++++----------- bin/box | 20 ++++++++++++++ scoper.inc.php | 14 ++++++++++ src/Box.php | 2 +- src/bootstrap.php | 66 ++++++++++++++++++++++++++++++----------------- 6 files changed, 90 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index f9e09f7c5..30b86ae17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.box_dump +/box /*.phar /*.phar.sig /box.json diff --git a/Makefile b/Makefile index 64e9157a1..0db23ca75 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ cs: vendor-bin/php-cs-fixer/vendor/bin/php-cs-fixer $(PHPNOGC) $(PHPCSFIXER) fix --config .php_cs_53.dist compile: ## Compile the application into the PHAR -compile: box.phar - cp -f box.phar bin/box.phar +compile: box + cp -f box bin/box.phar ## @@ -68,8 +68,8 @@ e2e: e2e_scoper_alias e2e_check_requirements .PHONY: e2e_scoper_alias e2e_scoper_alias: ## Runs the end-to-end tests to check that the PHP-Scoper config API is working -e2e_scoper_alias: box.phar - php box.phar compile --working-dir fixtures/build/dir010 +e2e_scoper_alias: box + ./box compile --working-dir fixtures/build/dir010 .PHONY: e2e_check_requirements @@ -77,8 +77,8 @@ DOCKER=docker run -i --rm -w /opt/box PHP7PHAR=box_php72 php index.phar -vvv --no-ansi PHP5PHAR=box_php53 php index.phar -vvv --no-ansi e2e_check_requirements: ## Runs the end-to-end tests for the check requirements feature -e2e_check_requirements: box.phar - .docker/build +e2e_check_requirements: box + ./.docker/build bin/box compile --working-dir fixtures/check-requirements/pass-no-config/ @@ -113,13 +113,12 @@ e2e_check_requirements: box.phar .PHONY: blackfire blackfire: ## Profiles the compile step -blackfire: box.phar +blackfire: box # Profile compiling the PHAR from the source code blackfire --reference=1 --samples=5 run $(PHPNOGC) -d bin/box compile --quiet # Profile compiling the PHAR from the PHAR - mv -fv bin/box.phar . - blackfire --reference=2 --samples=5 run $(PHPNOGC) -d box.phar compile --quiet + blackfire --reference=2 --samples=5 run $(PHPNOGC) -d box compile --quiet # @@ -150,9 +149,6 @@ requirement-checker/vendor: vendor-bin/php-cs-fixer/vendor/bin/php-cs-fixer: vendor/bamarni composer bin php-cs-fixer install -bin/box.phar: bin/box src vendor - $(MAKE) compile - .PHONY: fixtures/default_stub.php fixtures/default_stub.php: bin/generate_default_stub @@ -170,7 +166,7 @@ requirement-checker/actual_terminal_diff: requirement-checker/src/Terminal.php v vendor/symfony/console/Terminal.php: vendor -box.phar: bin src res vendor box.json.dist scoper.inc.php .requirement-checker +box: bin src res vendor box.json.dist scoper.inc.php .requirement-checker # Compile Box bin/box compile @@ -180,10 +176,9 @@ box.phar: bin src res vendor box.json.dist scoper.inc.php .requirement-checker # Compile Box with the isolated Box PHAR php bin/_box.phar compile - rm box.phar || true - mv -v bin/box.phar . + mv -fv bin/box.phar box # Test the PHAR which has been created by the isolated PHAR - php box.phar compile + ./box compile rm bin/_box.phar diff --git a/bin/box b/bin/box index b1c30b085..f5cd805a0 100755 --- a/bin/box +++ b/bin/box @@ -15,7 +15,27 @@ declare(strict_types=1); namespace KevinGH\Box; +use function file_exists; use KevinGH\Box\Console\Application; +use RuntimeException; + +(function (): void { + if (file_exists($autoload = __DIR__.'/../../../autoload.php')) { + // Is installed via Composer + include_once $autoload; + + return; + } + + if (file_exists($autoload = __DIR__.'/../vendor/autoload.php')) { + // Is installed locally + include_once $autoload; + + return; + } + + throw new RuntimeException('Unable to find the Composer autoloader.'); +})(); require __DIR__.'/../src/bootstrap.php'; diff --git a/scoper.inc.php b/scoper.inc.php index 75faf984c..a540a190a 100644 --- a/scoper.inc.php +++ b/scoper.inc.php @@ -84,6 +84,20 @@ function (string $filePath, string $prefix, string $contents): string { function (string $filePath, string $prefix, string $contents) use ($classLoaderContents): string { return 'vendor/composer/composer/src/Composer/Autoload/ClassLoader.php' === $filePath ? $classLoaderContents : $contents; }, + function (string $filePath, string $prefix, string $contents): string { + if ('src/bootstrap.php' !== $filePath) { + return $contents; + } + + return preg_replace( + sprintf( + '/\\\\%s\\\\PHAR_COPY/', + $prefix + ), + '\\PHAR_COPY', + $contents + ); + }, ], 'whitelist' => [ \Composer\Autoload\ClassLoader::class, diff --git a/src/Box.php b/src/Box.php index d5c4cdb03..800c176c8 100644 --- a/src/Box.php +++ b/src/Box.php @@ -314,7 +314,7 @@ private function processContents(array $files, string $cwd): array $mapFile = $this->mapFile; $placeholders = $this->placeholders; $compactors = $this->compactors; - $bootstrap = $GLOBALS['bootstrap'] ?? function (): void {}; + $bootstrap = $GLOBALS['_BOX_BOOTSTRAP'] ?? function (): void {}; $processFile = function (string $file) use ($cwd, $basePath, $mapFile, $placeholders, $compactors, $bootstrap): array { chdir($cwd); diff --git a/src/bootstrap.php b/src/bootstrap.php index b06cd9bb6..300c0a139 100755 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -14,47 +14,67 @@ namespace KevinGH\Box; +use function bin2hex; +use function copy; +use function defined; +use function dirname; use ErrorException; +use function random_bytes; +use function register_shutdown_function; use RuntimeException; - -$findAutoloader = function () { - if (file_exists($autoload = __DIR__.'/../../../autoload.php')) { - // Is installed via Composer - return $autoload; - } - - if (file_exists($autoload = __DIR__.'/../vendor/autoload.php')) { - // Is installed locally - return $autoload; - } - - throw new RuntimeException('Unable to find the Composer or PHP-Scoper autoloader.'); -}; +use function substr; +use function sys_get_temp_dir; +use function unlink; // TODO: update PHP-Scoper to get rid of this horrible hack at some point -$findPhpScoperFunctions = function () { +$findPhpScoperFunctions = function (): void { if (file_exists($autoload = __DIR__.'/../../php-scoper/src/functions.php')) { // Is installed via Composer - return $autoload; + require_once $autoload; + + return; } if (file_exists($autoload = __DIR__.'/../vendor/humbug/php-scoper/src/functions.php')) { // Is scoped (in PHAR or dumped directory) or is installed locally - return $autoload; + require_once $autoload; + + return; + } + + if ('phar://' === substr(__FILE__, 0, 7)) { + // Is in the PHAR but the PHAR has been renamed without the extension `.phar`. As a result the PHAR protocol + // `phar://path/to/file/in/PHAR` will not work. + // See https://github.com/amphp/parallel/commit/732694688461936bec02c0ccf020dfee10c4f7ee + if (defined('PHAR_COPY')) { + return; + } + + $pharPath = dirname(substr(__FILE__, 7), 2); + define('PHAR_COPY', sys_get_temp_dir().'/phar-'.bin2hex(random_bytes(10)). '.phar'); + + copy($pharPath, \PHAR_COPY); + + $autoload = 'phar://'.\PHAR_COPY. '/vendor/humbug/php-scoper/src/functions.php'; + + register_shutdown_function(static function () { + @unlink(\PHAR_COPY); + }); + + require_once $autoload; + + return; } throw new RuntimeException('Unable to find the PHP-Scoper functions.'); }; -$bootstrap = function () use ($findAutoloader, $findPhpScoperFunctions): void { - require_once $findAutoloader(); - require_once $findPhpScoperFunctions(); +$GLOBALS['_BOX_BOOTSTRAP'] = function () use ($findPhpScoperFunctions): void { + $findPhpScoperFunctions(); \KevinGH\Box\register_aliases(); }; -$bootstrap(); - -$GLOBALS['bootstrap'] = $bootstrap; +$GLOBALS['_BOX_BOOTSTRAP'](); // Convert errors to exceptions set_error_handler(