Skip to content

Commit

Permalink
fix: Fix the autoloading of the excluded files (#1323)
Browse files Browse the repository at this point in the history
This fixes the integration of
humbug/php-scoper#864 within Box which was done in #1142.

The issue was that the relative file paths was passed instead of hashes. Note that we create the file hasher in a different way than in PHP-Scoper, since PHP-Scoper has to deal with the vendor directory from the source and the scoped one, and deals with absolute paths. In Box however, this is not the case, we directly get relative file paths (relative to the working directory)
  • Loading branch information
theofidry authored Apr 7, 2024
1 parent 9f89e02 commit d83ec37
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public function startBuffering(): void
}

/**
* @param callable(SymbolsRegistry, string): void $dumpAutoload
* @param callable(SymbolsRegistry, string, string[]): void $dumpAutoload
*/
public function endBuffering(?callable $dumpAutoload): void
{
Expand Down
34 changes: 33 additions & 1 deletion src/Composer/AutoloadDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

namespace KevinGH\Box\Composer;

use Humbug\PhpScoper\Autoload\ComposerFileHasher;
use Humbug\PhpScoper\Autoload\ScoperAutoloadGenerator;
use Humbug\PhpScoper\Symbol\SymbolsRegistry;
use KevinGH\Box\NotInstantiable;
Expand All @@ -23,22 +24,34 @@
use function implode;
use function preg_match;
use function preg_replace;
use function sprintf;
use function str_replace;
use const PHP_EOL;

final class AutoloadDumper
{
use NotInstantiable;

private const PACKAGE_PATH_REGEX = '~^%s/(?<vendor>[^/]+?/[^/]+?)/(?<path>.+?)$~';

/**
* @param string[] $excludedComposerAutoloadFiles
*/
public static function generateAutoloadStatements(
SymbolsRegistry $symbolsRegistry,
array $excludedComposerAutoloadFileHashes,
string $vendorDir,
array $excludedComposerAutoloadFiles,
string $autoloadContents,
): string {
if (0 === $symbolsRegistry->count()) {
return $autoloadContents;
}

$excludedComposerAutoloadFileHashes = self::getExcludedComposerAutoloadFileHashes(
$vendorDir,
$excludedComposerAutoloadFiles,
);

$autoloadContents = self::extractInlinedAutoloadContents($autoloadContents);
$scoperStatements = self::getOriginalScoperAutoloaderContents(
$symbolsRegistry,
Expand All @@ -59,6 +72,25 @@ public static function generateAutoloadStatements(
return self::cleanupDuplicateLineReturns($mergedAutoloadContents);
}

/**
* @param string[] $excludedComposerAutoloadFiles
*/
private static function getExcludedComposerAutoloadFileHashes(
string $vendorDir,
array $excludedComposerAutoloadFiles,
): array {
$fileHashGenerator = new ComposerFileHasher(
'',
$excludedComposerAutoloadFiles,
sprintf(
self::PACKAGE_PATH_REGEX,
$vendorDir,
),
);

return $fileHashGenerator->generateHashes();
}

private static function extractInlinedAutoloadContents(string $autoloadContents): string
{
$autoloadContents = str_replace('<?php', '', $autoloadContents);
Expand Down
16 changes: 13 additions & 3 deletions src/Composer/ComposerOrchestrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,39 @@ public function checkVersion(): void
}
}

/**
* @param string[] $excludedComposerAutoloadFiles Relative paths of the files that were not scoped hence which need
* to be configured as loaded to Composer as otherwise they would be
* autoloaded twice.
*/
public function dumpAutoload(
SymbolsRegistry $symbolsRegistry,
string $prefix,
bool $excludeDevFiles,
array $excludedComposerAutoloadFileHashes,
array $excludedComposerAutoloadFiles,
): void {
$this->dumpAutoloader(true === $excludeDevFiles);

if ('' === $prefix) {
return;
}

$autoloadFile = $this->getVendorDir().'/autoload.php';
$vendorDir = $this->getVendorDir();
$autoloadFile = $vendorDir.'/autoload.php';

$autoloadContents = AutoloadDumper::generateAutoloadStatements(
$symbolsRegistry,
$excludedComposerAutoloadFileHashes,
$vendorDir,
$excludedComposerAutoloadFiles,
$this->fileSystem->getFileContents($autoloadFile),
);

$this->fileSystem->dumpFile($autoloadFile, $autoloadContents);
}

/**
* @return string The vendor-dir directory path relative to its composer.json.
*/
public function getVendorDir(): string
{
$vendorDirProcess = $this->processFactory->getVendorDirProcess();
Expand Down
50 changes: 32 additions & 18 deletions tests/Composer/AutoloadDumperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function md5;

/**
* @internal
Expand All @@ -29,12 +30,14 @@ final class AutoloadDumperTest extends TestCase
#[DataProvider('autoloadProvider')]
public function test_it_can_generate_the_autoload(
SymbolsRegistry $symbolsRegistry,
string $vendorDir,
array $excludedComposerAutoloadFileHashes,
string $autoloadContents,
string $expected,
): void {
$actual = AutoloadDumper::generateAutoloadStatements(
$symbolsRegistry,
$vendorDir,
$excludedComposerAutoloadFileHashes,
$autoloadContents,
);
Expand All @@ -44,8 +47,16 @@ public function test_it_can_generate_the_autoload(

public static function autoloadProvider(): iterable
{
$defaultVendorDir = 'vendor';

$excludedFile1 = 'vendor/phpstorm/stubs/stub1.php';
$excludedFile1Hash = md5('phpstorm/stubs:stub1.php');
$excludedFile2 = 'vendor/phpstorm/stubs/stub2.php';
$excludedFile2Hash = md5('phpstorm/stubs:stub2.php');

yield 'no symbols' => [
new SymbolsRegistry(),
$defaultVendorDir,
[],
<<<'PHP'
<?php
Expand Down Expand Up @@ -113,6 +124,7 @@ public static function autoloadProvider(): iterable
],
[],
),
$defaultVendorDir,
[],
<<<'PHP'
<?php
Expand Down Expand Up @@ -210,7 +222,8 @@ public static function autoloadProvider(): iterable
],
[],
),
['a610a8e036135f992c6edfb10ca9f4e9', 'e252736c6babb7c097ab6692dbcb2a5a'],
$defaultVendorDir,
[$excludedFile1, $excludedFile2],
<<<'PHP'
<?php
Expand Down Expand Up @@ -241,14 +254,14 @@ public static function autoloadProvider(): iterable
return ComposerAutoloaderInit2b848b33b146391fe6393b67efd7cd6f::getLoader();

PHP,
<<<'PHP'
<<<PHP
<?php
// @generated by Humbug Box
$loader = (static function () {
\$loader = (static function () {
// Backup the autoloaded Composer files
$existingComposerAutoloadFiles = $GLOBALS['__composer_autoload_files'] ?? [];
\$existingComposerAutoloadFiles = \$GLOBALS['__composer_autoload_files'] ?? [];
// @generated by Humbug Box
Expand All @@ -258,43 +271,43 @@ public static function autoloadProvider(): iterable
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
\$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
fwrite(STDERR, \$err);
} elseif (!headers_sent()) {
echo $err;
echo \$err;
}
}
trigger_error(
$err,
\$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
$loader = ComposerAutoloaderInit2b848b33b146391fe6393b67efd7cd6f::getLoader();
\$loader = ComposerAutoloaderInit2b848b33b146391fe6393b67efd7cd6f::getLoader();
// Ensure InstalledVersions is available
$installedVersionsPath = __DIR__.'/composer/InstalledVersions.php';
if (file_exists($installedVersionsPath)) require_once $installedVersionsPath;
\$installedVersionsPath = __DIR__.'/composer/InstalledVersions.php';
if (file_exists(\$installedVersionsPath)) require_once \$installedVersionsPath;
// Restore the backup and ensure the excluded files are properly marked as loaded
$GLOBALS['__composer_autoload_files'] = \array_merge(
$existingComposerAutoloadFiles,
\array_fill_keys(['a610a8e036135f992c6edfb10ca9f4e9', 'e252736c6babb7c097ab6692dbcb2a5a'], true)
\$GLOBALS['__composer_autoload_files'] = \\array_merge(
\$existingComposerAutoloadFiles,
\\array_fill_keys(['{$excludedFile1Hash}', '{$excludedFile2Hash}'], true)
);
return $loader;
return \$loader;
})();
// Function aliases. For more information see:
// https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md#function-aliases
if (!function_exists('bar')) { function bar() { return \Humbug\bar(...func_get_args()); } }
if (!function_exists('foo')) { function foo() { return \Humbug\foo(...func_get_args()); } }
if (!function_exists('bar')) { function bar() { return \\Humbug\\bar(...func_get_args()); } }
if (!function_exists('foo')) { function foo() { return \\Humbug\\foo(...func_get_args()); } }
return $loader;
return \$loader;
PHP,
];
Expand All @@ -308,6 +321,7 @@ public static function autoloadProvider(): iterable
],
[],
),
$defaultVendorDir,
[],
<<<'PHP'
<?php
Expand Down

0 comments on commit d83ec37

Please sign in to comment.