Skip to content

Commit

Permalink
Fix the parallel processing in a renamed PHAR (#160)
Browse files Browse the repository at this point in the history
When the PHAR was renamed, the autoload files could no longer be found.

Closes #152
  • Loading branch information
theofidry authored Apr 24, 2018
1 parent 1f5430f commit 6b7dc4a
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/.box_dump
/box
/*.phar
/*.phar.sig
/box.json
Expand Down
27 changes: 11 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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


##
Expand Down Expand Up @@ -68,17 +68,17 @@ 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
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/

Expand Down Expand Up @@ -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


#
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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
20 changes: 20 additions & 0 deletions bin/box
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
14 changes: 14 additions & 0 deletions scoper.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
66 changes: 43 additions & 23 deletions src/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 6b7dc4a

Please sign in to comment.