Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow to configure the parser PHP version #1044

Merged
merged 5 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ potentially very difficult to debug due to dissimilar or unsupported package ver
- [Usage](#usage)
- [Configuration](docs/configuration.md#configuration)
- [Prefix](docs/configuration.md#prefix)
- [PHP Version](docs/configuration.md#php-version)
- [Output directory](docs/configuration.md#output-directory)
- [Finders and paths](docs/configuration.md#finders-and-paths)
- [Patchers](docs/configuration.md#patchers)
Expand Down
12 changes: 12 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Configuration

- [Prefix](#prefix)
- [PHP-Version](#php-version)
- [Output directory](#output-directory)
- [Finders and paths](#finders-and-paths)
- [Patchers](#patchers)
Expand Down Expand Up @@ -28,6 +29,7 @@ use Isolated\Symfony\Component\Finder\Finder;

return [
'prefix' => null, // string|null
'php-version' => null, // string|null
'output-dir' => null, // string|null
'finders' => [], // list<Finder>
'patchers' => [], // list<callable(string $filePath, string $prefix, string $contents): string>
Expand Down Expand Up @@ -56,6 +58,15 @@ The prefix to be used to isolate the code. If `null` or `''` (empty string) is g
then a random prefix will be automatically generated.


### PHP Version

The PHP version provided is used to configure the underlying [PHP-Parser] Parser and Printer. This will not affect
the PHP internal symbols used by PHP-Scoper but may affect what code can be parsed and how the code will be printed.

If `null` or `''` (empty string) is given, then the host version will be used, i.e. executing it with PHP 8.4 will
result in PHP 8.4 being used as the PHP version.


### Output directory

The base output directory where the prefixed files will be generated. If `null`
Expand Down Expand Up @@ -476,5 +487,6 @@ namespace Humbug\Acme;

[box]: https://github.com/box-project/box
[php-scoper-integration]: https://github.com/humbug/box#isolating-the-phar
[PHP-Parser]: https://github.com/nikic/PHP-Parser
[phpstorm-stubs]: https://github.com/JetBrains/phpstorm-stubs
[symfony_finder]: https://symfony.com/doc/current/components/finder.html
10 changes: 10 additions & 0 deletions src/Configuration/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use Humbug\PhpScoper\Configuration\Throwable\InvalidConfigurationValue;
use Humbug\PhpScoper\Patcher\Patcher;
use PhpParser\PhpVersion;

final class Configuration
{
Expand All @@ -38,6 +39,7 @@ public function __construct(
private ?string $path,
private ?string $outputDir,
string|Prefix $prefix,
private ?PhpVersion $phpVersion,
private array $filesWithContents,
private array $excludedFilesWithContents,
private Patcher $patcher,
Expand Down Expand Up @@ -75,6 +77,7 @@ public function withPrefix(string $prefix): self
$this->path,
$this->outputDir,
$prefix,
$this->phpVersion,
$this->filesWithContents,
$this->excludedFilesWithContents,
$this->patcher,
Expand All @@ -99,6 +102,7 @@ public function withFilesWithContents(array $filesWithContents): self
$this->path,
$this->outputDir,
$this->prefix,
$this->phpVersion,
$filesWithContents,
$this->excludedFilesWithContents,
$this->patcher,
Expand Down Expand Up @@ -128,6 +132,7 @@ public function withPatcher(Patcher $patcher): self
$this->path,
$this->outputDir,
$this->prefix,
$this->phpVersion,
$this->filesWithContents,
$this->excludedFilesWithContents,
$patcher,
Expand All @@ -144,4 +149,9 @@ public function getSymbolsConfiguration(): SymbolsConfiguration
{
return $this->symbolsConfiguration;
}

public function getPhpVersion(): ?PhpVersion
{
return $this->phpVersion;
}
}
25 changes: 25 additions & 0 deletions src/Configuration/ConfigurationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

namespace Humbug\PhpScoper\Configuration;

use Exception;
use Humbug\PhpScoper\Configuration\Throwable\InvalidConfiguration;
use Humbug\PhpScoper\Configuration\Throwable\InvalidConfigurationFile;
use Humbug\PhpScoper\Configuration\Throwable\InvalidConfigurationValue;
Expand All @@ -22,6 +23,7 @@
use Humbug\PhpScoper\Patcher\PatcherChain;
use Humbug\PhpScoper\Patcher\SymfonyParentTraitPatcher;
use Humbug\PhpScoper\Patcher\SymfonyPatcher;
use PhpParser\PhpVersion;
use SplFileInfo;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
Expand Down Expand Up @@ -97,6 +99,7 @@ public function create(?string $path = null, array $paths = []): Configuration
$path,
$outputDir,
$prefix,
self::retrievePhpVersion($config),
$filesWithContents,
self::retrieveFilesWithContents($excludedFiles),
new PatcherChain($patchers),
Expand Down Expand Up @@ -178,6 +181,28 @@ private static function retrievePrefix(array $config): string
return '' === $prefix ? self::generateRandomPrefix() : $prefix;
}

/**
* @throws InvalidConfigurationValue
*/
private static function retrievePhpVersion(array $config): ?PhpVersion
{
$stringVersion = $config[ConfigurationKeys::PHP_VERSION_KEYWORD] ?? null;

if (null === $stringVersion || '' === $stringVersion) {
return null;
}

if (!is_string($stringVersion)) {
throw InvalidConfigurationValue::forInvalidPhpVersionType($stringVersion);
}

try {
return PhpVersion::fromString($stringVersion);
} catch (Exception $exception) {
throw InvalidConfigurationValue::forInvalidPhpVersion($stringVersion, $exception);
}
}

/**
* @return non-empty-string|null
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Configuration/ConfigurationKeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ final class ConfigurationKeys
use NotInstantiable;

public const PREFIX_KEYWORD = 'prefix';
public const PHP_VERSION_KEYWORD = 'php-version';
public const OUTPUT_DIR_KEYWORD = 'output-dir';
public const EXCLUDED_FILES_KEYWORD = 'exclude-files';
public const FINDER_KEYWORD = 'finders';
Expand All @@ -43,6 +44,7 @@ final class ConfigurationKeys

public const KEYWORDS = [
self::PREFIX_KEYWORD,
self::PHP_VERSION_KEYWORD,
self::OUTPUT_DIR_KEYWORD,
self::EXCLUDED_FILES_KEYWORD,
self::FINDER_KEYWORD,
Expand Down
23 changes: 23 additions & 0 deletions src/Configuration/Throwable/InvalidConfigurationValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

namespace Humbug\PhpScoper\Configuration\Throwable;

use Exception;
use Symfony\Component\Finder\Finder;
use UnexpectedValueException;
use function gettype;
use function sprintf;

final class InvalidConfigurationValue extends UnexpectedValueException implements InvalidConfiguration
{
Expand Down Expand Up @@ -115,6 +117,27 @@ public static function forInvalidPrefixPattern(string $prefix): self
);
}

public static function forInvalidPhpVersionType(mixed $phpVersion): self
{
return new self(
sprintf(
'Expected the PHP version to be a string, got "%s" instead.',
gettype($phpVersion),
),
);
}

public static function forInvalidPhpVersion(string $stringVersion, Exception $previous): self
{
return new self(
sprintf(
'Expected the PHP version to of the format "<major>.<minor>", e.g. "7.2", got "%s".',
$stringVersion,
),
previous: $previous,
);
}

public static function forInvalidNamespaceSeparator(string $prefix): self
{
return new self(
Expand Down
23 changes: 22 additions & 1 deletion src/Console/Command/AddPrefixCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Humbug\PhpScoper\Console\ConsoleScoper;
use Humbug\PhpScoper\Scoper\Factory\ScoperFactory;
use InvalidArgumentException;
use PhpParser\PhpVersion;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -56,6 +57,7 @@ final class AddPrefixCommand implements Command, CommandAware
private const CONTINUE_ON_FAILURE_OPT = 'continue-on-failure';
private const CONFIG_FILE_OPT = 'config';
private const NO_CONFIG_OPT = 'no-config';
private const PHP_VERSION_OPT = 'php-version';

private const DEFAULT_OUTPUT_DIR = 'build';

Expand Down Expand Up @@ -96,7 +98,7 @@ public function getConfiguration(): CommandConfiguration
'o',
InputOption::VALUE_REQUIRED,
'The output directory in which the prefixed code will be dumped.',
''
'',
),
new InputOption(
self::FORCE_OPT,
Expand Down Expand Up @@ -131,6 +133,12 @@ public function getConfiguration(): CommandConfiguration
InputOption::VALUE_NONE,
'Do not look for a configuration file.',
),
new InputOption(
self::PHP_VERSION_OPT,
null,
InputOption::VALUE_REQUIRED,
'PHP version in which the PHP parser and printer will be configured, e.g. "7.2".',
),
],
);
}
Expand All @@ -147,6 +155,7 @@ public function execute(IO $io): int

$paths = $this->getPathArguments($io, $cwd);
$config = $this->retrieveConfig($io, $paths, $cwd);
$phpVersion = self::getPhpVersion($io);

$outputDir = $this->canonicalizePath(
$this->getOutputDir($io, $config),
Expand All @@ -157,6 +166,7 @@ public function execute(IO $io): int
$this->getScoper()->scope(
$io,
$config,
$phpVersion,
$paths,
$outputDir,
self::getStopOnFailure($io),
Expand All @@ -165,6 +175,17 @@ public function execute(IO $io): int
return ExitCode::SUCCESS;
}

private static function getPhpVersion(IO $io): ?PhpVersion
{
$version = $io
->getTypedOption(self::PHP_VERSION_OPT)
->asNullableString();

return null === $version
? $version
: PhpVersion::fromString($version);
}

private static function getStopOnFailure(IO $io): bool
{
$stopOnFailure = $io->getTypedOption(self::STOP_ON_FAILURE_OPT)->asBoolean();
Expand Down
30 changes: 29 additions & 1 deletion src/Console/Command/InspectCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Humbug\PhpScoper\Scoper\Factory\ScoperFactory;
use Humbug\PhpScoper\Symbol\SymbolsRegistry;
use InvalidArgumentException;
use PhpParser\PhpVersion;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -49,6 +50,7 @@ final class InspectCommand implements Command, CommandAware
private const PREFIX_OPT = 'prefix';
private const CONFIG_FILE_OPT = 'config';
private const NO_CONFIG_OPT = 'no-config';
private const PHP_VERSION_OPT = 'php-version';

public function __construct(
private readonly Filesystem $fileSystem,
Expand Down Expand Up @@ -94,6 +96,12 @@ public function getConfiguration(): CommandConfiguration
InputOption::VALUE_NONE,
'Do not look for a configuration file.',
),
new InputOption(
self::PHP_VERSION_OPT,
null,
InputOption::VALUE_REQUIRED,
'PHP version in which the PHP parser and printer will be configured, e.g. "7.2".',
),
],
);
}
Expand All @@ -108,6 +116,7 @@ public function execute(IO $io): int
// working directory
$cwd = getcwd();

$phpversion = self::getPhpVersion($io);
$filePath = $this->getFilePath($io, $cwd);
$config = $this->retrieveConfig($io, [$filePath], $cwd);

Expand All @@ -120,7 +129,13 @@ public function execute(IO $io): int
$symbolsRegistry = new SymbolsRegistry();
$fileContents = $config->getFilesWithContents()[$filePath][1];

$scopedContents = $this->scopeFile($config, $symbolsRegistry, $filePath, $fileContents);
$scopedContents = $this->scopeFile(
$config,
$symbolsRegistry,
$phpversion,
$filePath,
$fileContents,
);

$this->printScopedContents($io, $scopedContents, $symbolsRegistry);

Expand Down Expand Up @@ -192,12 +207,14 @@ private function canonicalizePath(string $path, string $cwd): string
private function scopeFile(
Configuration $config,
SymbolsRegistry $symbolsRegistry,
?PhpVersion $phpversion,
string $filePath,
string $fileContents,
): string {
$scoper = $this->scoperFactory->createScoper(
$config,
$symbolsRegistry,
$phpversion,
);

return $scoper->scope(
Expand Down Expand Up @@ -249,4 +266,15 @@ private static function exportSymbolsRegistry(SymbolsRegistry $symbolsRegistry,
true,
);
}

private static function getPhpVersion(IO $io): ?PhpVersion
{
$version = $io
->getTypedOption(self::PHP_VERSION_OPT)
->asNullableString();

return null === $version
? $version
: PhpVersion::fromString($version);
}
}
Loading
Loading