diff --git a/bin/pie b/bin/pie
index cbff1ac..6d548bb 100755
--- a/bin/pie
+++ b/bin/pie
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Php\Pie;
+use Php\Pie\Command\BuildCommand;
use Php\Pie\Command\DownloadCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
@@ -21,6 +22,7 @@ $application->setCommandLoader(new ContainerCommandLoader(
$container,
[
'download' => DownloadCommand::class,
+ 'build' => BuildCommand::class,
]
));
$application->run($container->get(InputInterface::class), $container->get(OutputInterface::class));
diff --git a/src/Building/Build.php b/src/Building/Build.php
new file mode 100644
index 0000000..14fd88c
--- /dev/null
+++ b/src/Building/Build.php
@@ -0,0 +1,21 @@
+ $configureOptions */
+ public function __invoke(
+ DownloadedPackage $downloadedPackage,
+ TargetPlatform $targetPlatform,
+ array $configureOptions,
+ OutputInterface $output,
+ ): void;
+}
diff --git a/src/Building/UnixBuild.php b/src/Building/UnixBuild.php
new file mode 100644
index 0000000..61c42c5
--- /dev/null
+++ b/src/Building/UnixBuild.php
@@ -0,0 +1,76 @@
+phpize($downloadedPackage);
+ $output->writeln('phpize complete.');
+
+ $phpConfigPath = $targetPlatform->phpBinaryPath->phpConfigPath();
+ if ($phpConfigPath !== null) {
+ $configureOptions[] = '--with-php-config=' . $phpConfigPath;
+ }
+
+ $this->configure($downloadedPackage, $configureOptions);
+ $optionsOutput = count($configureOptions) ? ' with options: ' . implode(' ', $configureOptions) : '.';
+ $output->writeln('Configure complete' . $optionsOutput);
+
+ $this->make($downloadedPackage);
+
+ $expectedSoFile = $downloadedPackage->extractedSourcePath . '/modules/' . $downloadedPackage->package->extensionName->name() . '.so';
+
+ if (! file_exists($expectedSoFile)) {
+ $output->writeln(sprintf(
+ 'Build complete, but expected %s does not exist - however, this may be normal if this extension outputs the .so file in a different location.',
+ $expectedSoFile,
+ ));
+
+ return;
+ }
+
+ $output->writeln(sprintf(
+ 'Build complete: %s',
+ $expectedSoFile,
+ ));
+ }
+
+ private function phpize(DownloadedPackage $downloadedPackage): void
+ {
+ (new Process(['phpize'], $downloadedPackage->extractedSourcePath))
+ ->mustRun();
+ }
+
+ /** @param list $configureOptions */
+ private function configure(DownloadedPackage $downloadedPackage, array $configureOptions = []): void
+ {
+ (new Process(['./configure', ...$configureOptions], $downloadedPackage->extractedSourcePath))
+ ->mustRun();
+ }
+
+ private function make(DownloadedPackage $downloadedPackage): void
+ {
+ (new Process(['make'], $downloadedPackage->extractedSourcePath))
+ ->mustRun();
+ }
+}
diff --git a/src/Building/WindowsBuild.php b/src/Building/WindowsBuild.php
new file mode 100644
index 0000000..3e743e3
--- /dev/null
+++ b/src/Building/WindowsBuild.php
@@ -0,0 +1,23 @@
+writeln('Nothing to do on Windows.');
+ }
+}
diff --git a/src/Command/BuildCommand.php b/src/Command/BuildCommand.php
new file mode 100644
index 0000000..2cc0377
--- /dev/null
+++ b/src/Command/BuildCommand.php
@@ -0,0 +1,58 @@
+dependencyResolver,
+ $targetPlatform,
+ $requestedNameAndVersionPair,
+ $this->downloadAndExtract,
+ $output,
+ );
+
+ CommandHelper::bindConfigureOptionsFromPackage($this, $downloadedPackage->package, $input);
+
+ $configureOptionsValues = CommandHelper::processConfigureOptionsFromInput($downloadedPackage->package, $input);
+
+ ($this->build)($downloadedPackage, $targetPlatform, $configureOptionsValues, $output);
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php
new file mode 100644
index 0000000..9cdd83c
--- /dev/null
+++ b/src/Command/CommandHelper.php
@@ -0,0 +1,210 @@
+addArgument(
+ self::ARG_REQUESTED_PACKAGE_AND_VERSION,
+ InputArgument::REQUIRED,
+ 'The extension name and version constraint to use, in the format {ext-name}{?:{?version-constraint}{?@stability}}, for example `xdebug/xdebug:^3.4@alpha`, `xdebug/xdebug:@alpha`, `xdebug/xdebug:^3.4`, etc.',
+ );
+ $command->addOption(
+ self::OPTION_WITH_PHP_CONFIG,
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'The path to the `php-config` binary to find the target PHP platform on ' . OperatingSystem::NonWindows->asFriendlyName() . ', e.g. --' . self::OPTION_WITH_PHP_CONFIG . '=/usr/bin/php-config7.4',
+ );
+ $command->addOption(
+ self::OPTION_WITH_PHP_PATH,
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'The path to the `php` binary to use as the target PHP platform on ' . OperatingSystem::Windows->asFriendlyName() . ', e.g. --' . self::OPTION_WITH_PHP_PATH . '=C:\usr\php7.4.33\php.exe',
+ );
+
+ /**
+ * Allows additional options for the `./configure` command to be passed here.
+ * Note, this means you probably need to call {@see self::validateInput()} to validate the input manually...
+ */
+ $command->ignoreValidationErrors();
+ }
+
+ public static function validateInput(InputInterface $input, Command $command): void
+ {
+ $input->bind($command->getDefinition());
+ }
+
+ public static function determineTargetPlatformFromInputs(InputInterface $input, OutputInterface $output): TargetPlatform
+ {
+ $phpBinaryPath = PhpBinaryPath::fromCurrentProcess();
+
+ /** @var mixed $withPhpConfig */
+ $withPhpConfig = $input->getOption(self::OPTION_WITH_PHP_CONFIG);
+ $specifiedWithPhpConfig = is_string($withPhpConfig) && $withPhpConfig !== '';
+ /** @var mixed $withPhpPath */
+ $withPhpPath = $input->getOption(self::OPTION_WITH_PHP_PATH);
+ $specifiedWithPhpPath = is_string($withPhpPath) && $withPhpPath !== '';
+
+ if (Platform::isWindows() && $specifiedWithPhpConfig) {
+ throw new InvalidArgumentException('The --with-php-config=/path/to/php-config cannot be used on Windows, use --with-php-path=/path/to/php instead.');
+ }
+
+ if (! Platform::isWindows() && $specifiedWithPhpPath && ! $specifiedWithPhpConfig) {
+ throw new InvalidArgumentException('The --with-php-path=/path/to/php cannot be used on non-Windows, use --with-php-config=/path/to/php-config instead.');
+ }
+
+ if ($specifiedWithPhpConfig) {
+ $phpBinaryPath = PhpBinaryPath::fromPhpConfigExecutable($withPhpConfig);
+ }
+
+ if ($specifiedWithPhpPath) {
+ $phpBinaryPath = PhpBinaryPath::fromPhpBinaryPath($withPhpPath);
+ }
+
+ $targetPlatform = TargetPlatform::fromPhpBinaryPath($phpBinaryPath);
+
+ $output->writeln(sprintf('You are running PHP %s', PHP_VERSION));
+ $output->writeln(sprintf(
+ 'Target PHP installation: %s %s%s, on %s %s (from %s)',
+ $phpBinaryPath->version(),
+ $targetPlatform->threadSafety->asShort(),
+ strtolower($targetPlatform->windowsCompiler !== null ? ', ' . $targetPlatform->windowsCompiler->name : ''),
+ $targetPlatform->operatingSystem->asFriendlyName(),
+ $targetPlatform->architecture->name,
+ $phpBinaryPath->phpBinaryPath,
+ ));
+
+ return $targetPlatform;
+ }
+
+ /** @return RequestedNameAndVersionPair */
+ public static function requestedNameAndVersionPair(InputInterface $input): array
+ {
+ $requestedPackageString = $input->getArgument(self::ARG_REQUESTED_PACKAGE_AND_VERSION);
+
+ if (! is_string($requestedPackageString) || $requestedPackageString === '') {
+ throw new InvalidArgumentException('No package was requested for installation');
+ }
+
+ $nameAndVersionPairs = (new VersionParser())
+ ->parseNameVersionPairs([$requestedPackageString]);
+ $requestedNameAndVersionPair = reset($nameAndVersionPairs);
+
+ if (! is_array($requestedNameAndVersionPair)) {
+ throw new InvalidArgumentException('Failed to parse the name/version pair');
+ }
+
+ if (! array_key_exists('version', $requestedNameAndVersionPair)) {
+ $requestedNameAndVersionPair['version'] = null;
+ }
+
+ Assert::stringNotEmpty($requestedNameAndVersionPair['name']);
+ Assert::nullOrStringNotEmpty($requestedNameAndVersionPair['version']);
+
+ return $requestedNameAndVersionPair;
+ }
+
+ /** @param RequestedNameAndVersionPair $requestedNameAndVersionPair */
+ public static function downloadPackage(
+ DependencyResolver $dependencyResolver,
+ TargetPlatform $targetPlatform,
+ array $requestedNameAndVersionPair,
+ DownloadAndExtract $downloadAndExtract,
+ OutputInterface $output,
+ ): DownloadedPackage {
+ $package = ($dependencyResolver)(
+ $targetPlatform,
+ $requestedNameAndVersionPair['name'],
+ $requestedNameAndVersionPair['version'],
+ );
+
+ $output->writeln(sprintf('Found package: %s which provides %s', $package->prettyNameAndVersion(), $package->extensionName->nameWithExtPrefix()));
+
+ return ($downloadAndExtract)($targetPlatform, $package);
+ }
+
+ public static function bindConfigureOptionsFromPackage(Command $command, Package $package, InputInterface $input): void
+ {
+ foreach ($package->configureOptions as $configureOption) {
+ $command->addOption(
+ $configureOption->name,
+ null,
+ $configureOption->needsValue ? InputOption::VALUE_REQUIRED : InputOption::VALUE_NONE,
+ $configureOption->description,
+ );
+ }
+
+ self::validateInput($input, $command);
+ }
+
+ /** @return list */
+ public static function processConfigureOptionsFromInput(Package $package, InputInterface $input): array
+ {
+ $configureOptionsValues = [];
+ foreach ($package->configureOptions as $configureOption) {
+ if (! $input->hasOption($configureOption->name)) {
+ continue;
+ }
+
+ $value = $input->getOption($configureOption->name);
+
+ if ($configureOption->needsValue) {
+ if (is_string($value) && $value !== '') {
+ $configureOptionsValues[] = '--' . $configureOption->name . '=' . escapeshellarg($value);
+ }
+
+ continue;
+ }
+
+ Assert::boolean($value);
+ if ($value !== true) {
+ continue;
+ }
+
+ $configureOptionsValues[] = '--' . $configureOption->name;
+ }
+
+ return $configureOptionsValues;
+ }
+}
diff --git a/src/Command/DownloadCommand.php b/src/Command/DownloadCommand.php
index 9611d6a..9c28f60 100644
--- a/src/Command/DownloadCommand.php
+++ b/src/Command/DownloadCommand.php
@@ -4,29 +4,14 @@
namespace Php\Pie\Command;
-use Composer\Package\Version\VersionParser;
-use InvalidArgumentException;
use Php\Pie\DependencyResolver\DependencyResolver;
use Php\Pie\Downloading\DownloadAndExtract;
-use Php\Pie\Platform\OperatingSystem;
-use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
-use Php\Pie\Platform\TargetPlatform;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use Webmozart\Assert\Assert;
-use function array_key_exists;
-use function is_array;
-use function is_string;
-use function reset;
use function sprintf;
-use function strtolower;
-
-use const PHP_VERSION;
#[AsCommand(
name: 'download',
@@ -34,10 +19,6 @@
)]
final class DownloadCommand extends Command
{
- private const ARG_REQUESTED_PACKAGE_AND_VERSION = 'requested-package-and-version';
- private const OPTION_WITH_PHP_CONFIG = 'with-php-config';
- private const OPTION_WITH_PHP_PATH = 'with-php-path';
-
public function __construct(
private readonly DependencyResolver $dependencyResolver,
private readonly DownloadAndExtract $downloadAndExtract,
@@ -49,66 +30,25 @@ public function configure(): void
{
parent::configure();
- $this->addArgument(
- self::ARG_REQUESTED_PACKAGE_AND_VERSION,
- InputArgument::REQUIRED,
- 'The extension name and version constraint to use, in the format {ext-name}{?:{?version-constraint}{?@stability}}, for example `xdebug/xdebug:^3.4@alpha`, `xdebug/xdebug:@alpha`, `xdebug/xdebug:^3.4`, etc.',
- );
- $this->addOption(
- self::OPTION_WITH_PHP_CONFIG,
- null,
- InputOption::VALUE_OPTIONAL,
- 'The path to the `php-config` binary to find the target PHP platform on ' . OperatingSystem::NonWindows->asFriendlyName() . ', e.g. --' . self::OPTION_WITH_PHP_CONFIG . '=/usr/bin/php-config7.4',
- );
- $this->addOption(
- self::OPTION_WITH_PHP_PATH,
- null,
- InputOption::VALUE_OPTIONAL,
- 'The path to the `php` binary to use as the target PHP platform on ' . OperatingSystem::Windows->asFriendlyName() . ', e.g. --' . self::OPTION_WITH_PHP_PATH . '=C:\usr\php7.4.33\php.exe',
- );
+ CommandHelper::configureOptions($this);
}
public function execute(InputInterface $input, OutputInterface $output): int
{
- $phpBinaryPath = PhpBinaryPath::fromCurrentProcess();
-
- /** @var mixed $withPhpConfig */
- $withPhpConfig = $input->getOption(self::OPTION_WITH_PHP_CONFIG);
- if (is_string($withPhpConfig) && $withPhpConfig !== '') {
- $phpBinaryPath = PhpBinaryPath::fromPhpConfigExecutable($withPhpConfig);
- }
+ CommandHelper::validateInput($input, $this);
- /** @var mixed $withPhpPath */
- $withPhpPath = $input->getOption(self::OPTION_WITH_PHP_PATH);
- if (is_string($withPhpPath) && $withPhpPath !== '') {
- $phpBinaryPath = PhpBinaryPath::fromPhpBinaryPath($withPhpPath);
- }
+ $targetPlatform = CommandHelper::determineTargetPlatformFromInputs($input, $output);
- $targetPlatform = TargetPlatform::fromPhpBinaryPath($phpBinaryPath);
+ $requestedNameAndVersionPair = CommandHelper::requestedNameAndVersionPair($input);
- $output->writeln(sprintf('You are running PHP %s', PHP_VERSION));
- $output->writeln(sprintf(
- 'Target PHP installation: %s %s%s, on %s %s (from %s)',
- $phpBinaryPath->version(),
- $targetPlatform->threadSafety->asShort(),
- strtolower($targetPlatform->windowsCompiler !== null ? ', ' . $targetPlatform->windowsCompiler->name : ''),
- $targetPlatform->operatingSystem->asFriendlyName(),
- $targetPlatform->architecture->name,
- $phpBinaryPath->phpBinaryPath,
- ));
-
- $requestedNameAndVersionPair = $this->requestedNameAndVersionPair($input);
-
- $package = ($this->dependencyResolver)(
+ $downloadedPackage = CommandHelper::downloadPackage(
+ $this->dependencyResolver,
$targetPlatform,
- $requestedNameAndVersionPair['name'],
- $requestedNameAndVersionPair['version'],
+ $requestedNameAndVersionPair,
+ $this->downloadAndExtract,
+ $output,
);
- $output->writeln(sprintf('Found package: %s which provides %s', $package->prettyNameAndVersion(), $package->extensionName->nameWithExtPrefix()));
-
- $downloadedPackage = ($this->downloadAndExtract)($targetPlatform, $package);
-
$output->writeln(sprintf(
'Extracted %s source to: %s',
$downloadedPackage->package->prettyNameAndVersion(),
@@ -117,31 +57,4 @@ public function execute(InputInterface $input, OutputInterface $output): int
return Command::SUCCESS;
}
-
- /** @return array{name: non-empty-string, version: non-empty-string|null} */
- private function requestedNameAndVersionPair(InputInterface $input): array
- {
- $requestedPackageString = $input->getArgument(self::ARG_REQUESTED_PACKAGE_AND_VERSION);
-
- if (! is_string($requestedPackageString) || $requestedPackageString === '') {
- throw new InvalidArgumentException('No package was requested for installation');
- }
-
- $nameAndVersionPairs = (new VersionParser())
- ->parseNameVersionPairs([$requestedPackageString]);
- $requestedNameAndVersionPair = reset($nameAndVersionPairs);
-
- if (! is_array($requestedNameAndVersionPair)) {
- throw new InvalidArgumentException('Failed to parse the name/version pair');
- }
-
- if (! array_key_exists('version', $requestedNameAndVersionPair)) {
- $requestedNameAndVersionPair['version'] = null;
- }
-
- Assert::stringNotEmpty($requestedNameAndVersionPair['name']);
- Assert::nullOrStringNotEmpty($requestedNameAndVersionPair['version']);
-
- return $requestedNameAndVersionPair;
- }
}
diff --git a/src/ConfigureOption.php b/src/ConfigureOption.php
new file mode 100644
index 0000000..12657a5
--- /dev/null
+++ b/src/ConfigureOption.php
@@ -0,0 +1,50 @@
+ $configureOptionDefinition */
+ public static function fromComposerJsonDefinition(array $configureOptionDefinition): self
+ {
+ Assert::keyExists($configureOptionDefinition, 'name');
+ Assert::stringNotEmpty($configureOptionDefinition['name']);
+
+ $needsValue = false;
+ if (array_key_exists('needs-value', $configureOptionDefinition)) {
+ Assert::boolean($configureOptionDefinition['needs-value']);
+ $needsValue = $configureOptionDefinition['needs-value'];
+ }
+
+ $description = '';
+ if (array_key_exists('description', $configureOptionDefinition)) {
+ Assert::string($configureOptionDefinition['description']);
+ $description = $configureOptionDefinition['description'];
+ }
+
+ return new self(
+ $configureOptionDefinition['name'],
+ $needsValue,
+ $description,
+ );
+ }
+}
diff --git a/src/Container.php b/src/Container.php
index c8e8c8f..bf50bc4 100644
--- a/src/Container.php
+++ b/src/Container.php
@@ -16,6 +16,10 @@
use GuzzleHttp\ClientInterface;
use GuzzleHttp\RequestOptions;
use Illuminate\Container\Container as IlluminateContainer;
+use Php\Pie\Building\Build;
+use Php\Pie\Building\UnixBuild;
+use Php\Pie\Building\WindowsBuild;
+use Php\Pie\Command\BuildCommand;
use Php\Pie\Command\DownloadCommand;
use Php\Pie\DependencyResolver\DependencyResolver;
use Php\Pie\DependencyResolver\ResolveDependencyWithComposer;
@@ -44,6 +48,7 @@ public static function factory(): ContainerInterface
$container->instance(OutputInterface::class, new ConsoleOutput());
$container->singleton(DownloadCommand::class);
+ $container->singleton(BuildCommand::class);
$container->singleton(IOInterface::class, static function (ContainerInterface $container): IOInterface {
return new ConsoleIO(
@@ -110,6 +115,17 @@ static function (ContainerInterface $container): DownloadAndExtract {
},
);
+ $container->singleton(
+ Build::class,
+ static function (ContainerInterface $container): Build {
+ if (Platform::isWindows()) {
+ return $container->get(WindowsBuild::class);
+ }
+
+ return $container->get(UnixBuild::class);
+ },
+ );
+
return $container;
}
}
diff --git a/src/DependencyResolver/Package.php b/src/DependencyResolver/Package.php
index 80f5a6d..41446fb 100644
--- a/src/DependencyResolver/Package.php
+++ b/src/DependencyResolver/Package.php
@@ -5,8 +5,12 @@
namespace Php\Pie\DependencyResolver;
use Composer\Package\CompletePackageInterface;
+use Php\Pie\ConfigureOption;
use Php\Pie\ExtensionName;
+use function array_key_exists;
+use function array_map;
+
/**
* @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks
*
@@ -17,21 +21,33 @@ final class Package
public const TYPE_PHP_MODULE = 'php-ext';
public const TYPE_ZEND_EXTENSION = 'php-ext-zend';
+ /** @param list $configureOptions */
public function __construct(
public readonly ExtensionName $extensionName,
public readonly string $name,
public readonly string $version,
public readonly string|null $downloadUrl,
+ public readonly array $configureOptions,
) {
}
public static function fromComposerCompletePackage(CompletePackageInterface $completePackage): self
{
+ $phpExtOptions = $completePackage->getPhpExt();
+
+ $configureOptions = $phpExtOptions !== null && array_key_exists('configure-options', $phpExtOptions)
+ ? array_map(
+ static fn (array $configureOption): ConfigureOption => ConfigureOption::fromComposerJsonDefinition($configureOption),
+ $phpExtOptions['configure-options'],
+ )
+ : [];
+
return new self(
ExtensionName::determineFromComposerPackage($completePackage),
$completePackage->getPrettyName(),
$completePackage->getPrettyVersion(),
$completePackage->getDistUrl(),
+ $configureOptions,
);
}
diff --git a/src/Platform/TargetPhp/PhpBinaryPath.php b/src/Platform/TargetPhp/PhpBinaryPath.php
index 0c28d06..025cc8d 100644
--- a/src/Platform/TargetPhp/PhpBinaryPath.php
+++ b/src/Platform/TargetPhp/PhpBinaryPath.php
@@ -23,9 +23,14 @@
*/
class PhpBinaryPath
{
- /** @param non-empty-string $phpBinaryPath */
- private function __construct(readonly string $phpBinaryPath)
- {
+ /**
+ * @param non-empty-string $phpBinaryPath
+ * @param non-empty-string|null $phpConfigPath
+ */
+ private function __construct(
+ public readonly string $phpBinaryPath,
+ private readonly string|null $phpConfigPath,
+ ) {
// @todo https://github.com/php/pie/issues/12 - we could verify that the given $phpBinaryPath really is a PHP install
}
@@ -160,6 +165,18 @@ public function phpinfo(): string
return $phpInfo;
}
+ /**
+ * This will only be set if {@see self::fromPhpConfigExecutable()} is used to create this {@see self}, otherwise
+ * will return `null`.
+ *
+ * @return non-empty-string|null
+ */
+ public function phpConfigPath(): string|null
+ {
+ return $this->phpConfigPath;
+ }
+
+ /** @param non-empty-string $phpConfig */
public static function fromPhpConfigExecutable(string $phpConfig): self
{
$phpExecutable = trim((new Process([$phpConfig, '--php-binary']))
@@ -167,13 +184,13 @@ public static function fromPhpConfigExecutable(string $phpConfig): self
->getOutput());
Assert::stringNotEmpty($phpExecutable, 'Could not find path to PHP executable.');
- return new self($phpExecutable);
+ return new self($phpExecutable, $phpConfig);
}
/** @param non-empty-string $phpBinary */
public static function fromPhpBinaryPath(string $phpBinary): self
{
- return new self($phpBinary);
+ return new self($phpBinary, null);
}
public static function fromCurrentProcess(): self
@@ -181,6 +198,6 @@ public static function fromCurrentProcess(): self
$phpExecutable = trim((string) (new PhpExecutableFinder())->find());
Assert::stringNotEmpty($phpExecutable, 'Could not find path to PHP executable.');
- return new self($phpExecutable);
+ return new self($phpExecutable, null);
}
}
diff --git a/test/assets/pie_test_ext/.gitignore b/test/assets/pie_test_ext/.gitignore
new file mode 100644
index 0000000..c37d5e7
--- /dev/null
+++ b/test/assets/pie_test_ext/.gitignore
@@ -0,0 +1,44 @@
+*.lo
+*.la
+.libs
+acinclude.m4
+aclocal.m4
+autom4te.cache
+build
+config.guess
+config.h
+config.h.in
+config.h.in~
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure~
+configure.ac
+configure.in
+include
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+missing
+mkinstalldirs
+modules
+php_test_results_*.txt
+phpt.*
+run-test-info.php
+run-tests.php
+tests/**/*.diff
+tests/**/*.out
+tests/**/*.php
+tests/**/*.exp
+tests/**/*.log
+tests/**/*.sh
+tests/**/*.db
+tests/**/*.mem
+tmp-php.ini
+pie_test_ext.dep
diff --git a/test/assets/pie_test_ext/config.m4 b/test/assets/pie_test_ext/config.m4
new file mode 100644
index 0000000..3deaa4f
--- /dev/null
+++ b/test/assets/pie_test_ext/config.m4
@@ -0,0 +1,14 @@
+PHP_ARG_ENABLE([pie_test_ext],
+ [whether to enable pie_test_ext support],
+ [AS_HELP_STRING([--enable-pie_test_ext],
+ [Enable pie_test_ext support])],
+ [no])
+
+if test "$PHP_PIE_TEST_EXT" != "no"; then
+ AC_DEFINE(HAVE_PIE_TEST_EXT, 1, [ Have pie_test_ext support ])
+
+ PHP_NEW_EXTENSION([pie_test_ext],
+ [pie_test_ext.c],
+ [$ext_shared],,
+ [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
+fi
diff --git a/test/assets/pie_test_ext/php_pie_test_ext.h b/test/assets/pie_test_ext/php_pie_test_ext.h
new file mode 100644
index 0000000..40dae60
--- /dev/null
+++ b/test/assets/pie_test_ext/php_pie_test_ext.h
@@ -0,0 +1,15 @@
+/* pie_test_ext extension for PHP (c) 2024 PHP Foundation */
+
+#ifndef PHP_PIE_TEST_EXT_H
+# define PHP_PIE_TEST_EXT_H
+
+extern zend_module_entry pie_test_ext_module_entry;
+# define phpext_pie_test_ext_ptr &pie_test_ext_module_entry
+
+# define PHP_PIE_TEST_EXT_VERSION "0.1.0"
+
+# if defined(ZTS) && defined(COMPILE_DL_PIE_TEST_EXT)
+ZEND_TSRMLS_CACHE_EXTERN()
+# endif
+
+#endif /* PHP_PIE_TEST_EXT_H */
diff --git a/test/assets/pie_test_ext/pie_test_ext.c b/test/assets/pie_test_ext/pie_test_ext.c
new file mode 100644
index 0000000..c9ef788
--- /dev/null
+++ b/test/assets/pie_test_ext/pie_test_ext.c
@@ -0,0 +1,68 @@
+/* pie_test_ext extension for PHP (c) 2024 PHP Foundation */
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "php_pie_test_ext.h"
+#include "pie_test_ext_arginfo.h"
+
+/* For compatibility with older PHP versions */
+#ifndef ZEND_PARSE_PARAMETERS_NONE
+#define ZEND_PARSE_PARAMETERS_NONE() \
+ ZEND_PARSE_PARAMETERS_START(0, 0) \
+ ZEND_PARSE_PARAMETERS_END()
+#endif
+
+/* {{{ void test1() */
+PHP_FUNCTION(test1)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ php_printf("The extension %s is loaded and working!\r\n", "pie_test_ext");
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION */
+PHP_RINIT_FUNCTION(pie_test_ext)
+{
+#if defined(ZTS) && defined(COMPILE_DL_PIE_TEST_EXT)
+ ZEND_TSRMLS_CACHE_UPDATE();
+#endif
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION */
+PHP_MINFO_FUNCTION(pie_test_ext)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "pie_test_ext support", "enabled");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ pie_test_ext_module_entry */
+zend_module_entry pie_test_ext_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "pie_test_ext", /* Extension name */
+ ext_functions, /* zend_function_entry */
+ NULL, /* PHP_MINIT - Module initialization */
+ NULL, /* PHP_MSHUTDOWN - Module shutdown */
+ PHP_RINIT(pie_test_ext), /* PHP_RINIT - Request initialization */
+ NULL, /* PHP_RSHUTDOWN - Request shutdown */
+ PHP_MINFO(pie_test_ext), /* PHP_MINFO - Module info */
+ PHP_PIE_TEST_EXT_VERSION, /* Version */
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_PIE_TEST_EXT
+# ifdef ZTS
+ZEND_TSRMLS_CACHE_DEFINE()
+# endif
+ZEND_GET_MODULE(pie_test_ext)
+#endif
diff --git a/test/assets/pie_test_ext/pie_test_ext.stub.php b/test/assets/pie_test_ext/pie_test_ext.stub.php
new file mode 100644
index 0000000..fa91253
--- /dev/null
+++ b/test/assets/pie_test_ext/pie_test_ext.stub.php
@@ -0,0 +1,8 @@
+
+--EXPECT--
+The extension "pie_test_ext" is available
diff --git a/test/assets/pie_test_ext/tests/002.phpt b/test/assets/pie_test_ext/tests/002.phpt
new file mode 100644
index 0000000..4f037c4
--- /dev/null
+++ b/test/assets/pie_test_ext/tests/002.phpt
@@ -0,0 +1,13 @@
+--TEST--
+test1() Basic test
+--EXTENSIONS--
+pie_test_ext
+--FILE--
+
+--EXPECT--
+The extension pie_test_ext is loaded and working!
+NULL
diff --git a/test/integration/Building/UnixBuildTest.php b/test/integration/Building/UnixBuildTest.php
new file mode 100644
index 0000000..08fe182
--- /dev/null
+++ b/test/integration/Building/UnixBuildTest.php
@@ -0,0 +1,69 @@
+ 'enable-pie_test_ext'])],
+ ),
+ self::TEST_EXTENSION_PATH,
+ );
+
+ $unixBuilder = new UnixBuild();
+ $unixBuilder->__invoke(
+ $downloadedPackage,
+ TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromCurrentProcess()),
+ ['--enable-pie_test_ext'],
+ $output,
+ );
+
+ $outputString = $output->fetch();
+
+ self::assertStringContainsString('phpize complete.', $outputString);
+ self::assertStringContainsString('Configure complete with options: --enable-pie_test_ext', $outputString);
+ self::assertStringContainsString('Build complete:', $outputString);
+ self::assertStringContainsString('pie_test_ext.so', $outputString);
+
+ self::assertSame(
+ 0,
+ (new Process(['make', 'test'], $downloadedPackage->extractedSourcePath))
+ ->mustRun()
+ ->getExitCode(),
+ );
+
+ (new Process(['make', 'clean'], $downloadedPackage->extractedSourcePath))->mustRun();
+ (new Process(['phpize', '--clean'], $downloadedPackage->extractedSourcePath))->mustRun();
+ }
+}
diff --git a/test/integration/Command/BuildCommandTest.php b/test/integration/Command/BuildCommandTest.php
new file mode 100644
index 0000000..98a80d5
--- /dev/null
+++ b/test/integration/Command/BuildCommandTest.php
@@ -0,0 +1,53 @@
+commandTester = new CommandTester(Container::factory()->get(BuildCommand::class));
+ }
+
+ public function testBuildCommandWillBuildTheExtension(): void
+ {
+ if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
+ self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
+ }
+
+ $this->commandTester->execute(['requested-package-and-version' => self::TEST_PACKAGE]);
+
+ $this->commandTester->assertCommandIsSuccessful();
+
+ $outputString = $this->commandTester->getDisplay();
+
+ self::assertStringContainsString('Found package: asgrim/example-pie-extension:1.0.1 which provides ext-example_pie_extension', $outputString);
+
+ if (Platform::isWindows()) {
+ self::assertStringContainsString('Nothing to do on Windows.', $outputString);
+
+ return;
+ }
+
+ self::assertStringContainsString('phpize complete.', $outputString);
+ self::assertStringContainsString('Configure complete.', $outputString);
+ self::assertStringContainsString('Build complete:', $outputString);
+ }
+}
diff --git a/test/integration/Command/DownloadCommandTest.php b/test/integration/Command/DownloadCommandTest.php
index 7297ed4..80e8804 100644
--- a/test/integration/Command/DownloadCommandTest.php
+++ b/test/integration/Command/DownloadCommandTest.php
@@ -4,6 +4,7 @@
namespace Php\PieIntegrationTest\Command;
+use Composer\Util\Platform;
use Php\Pie\Command\DownloadCommand;
use Php\Pie\Container;
use Php\Pie\DependencyResolver\UnableToResolveRequirement;
@@ -45,7 +46,7 @@ public static function validVersionsList(): array
[self::TEST_PACKAGE . ':1.0.1-alpha.3@alpha', self::TEST_PACKAGE . ':1.0.1-alpha.3'],
[self::TEST_PACKAGE . ':*', self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE . ':~1.0.0@alpha', self::TEST_PACKAGE . ':1.0.1'],
- [self::TEST_PACKAGE . ':^1.1.0@alpha', self::TEST_PACKAGE . ':1.1.0-alpha.1'],
+ [self::TEST_PACKAGE . ':^1.1.0@alpha', self::TEST_PACKAGE . ':1.1.0-alpha.4'],
[self::TEST_PACKAGE . ':~1.0.0', self::TEST_PACKAGE . ':1.0.1'],
// @todo https://github.com/php/pie/issues/13 - in theory, these could work, on NonWindows at least
// [self::TEST_PACKAGE . ':dev-main', self::TEST_PACKAGE . ':???'],
@@ -77,6 +78,10 @@ public function testDownloadCommandWillDownloadCompatibleExtension(string $reque
#[DataProvider('validVersionsList')]
public function testDownloadingWithPhpConfig(string $requestedVersion, string $expectedVersion): void
{
+ if (! Platform::isWindows()) {
+ self::markTestSkipped('This test can only run on Windows');
+ }
+
// @todo This test makes an assumption you're using `ppa:ondrej/php` to have multiple PHP versions. This allows
// us to test scenarios where you run with PHP 8.1 but want to install to a PHP 8.3 instance, for example.
// However, this test isn't very portable, and won't run in CI, so we could do with improving this later.
@@ -101,10 +106,11 @@ public function testDownloadingWithPhpConfig(string $requestedVersion, string $e
#[DataProvider('validVersionsList')]
public function testDownloadingWithPhpPath(string $requestedVersion, string $expectedVersion): void
{
- // @todo This test makes an assumption you're using `ppa:ondrej/php` to have multiple PHP versions. This allows
- // us to test scenarios where you run with PHP 8.1 but want to install to a PHP 8.3 instance, for example.
- // However, this test isn't very portable, and won't run in CI, so we could do with improving this later.
- $phpBinaryPath = '/usr/bin/php8.3';
+ if (! Platform::isWindows()) {
+ self::markTestSkipped('This test can only run on Windows');
+ }
+
+ $phpBinaryPath = 'C:\php-8.3.6\php.exe';
if (! file_exists($phpBinaryPath) || ! is_executable($phpBinaryPath)) {
self::markTestSkipped('This test can only run where "' . $phpBinaryPath . '" exists and is executable, to target PHP 8.3');
diff --git a/test/unit/Command/CommandHelperTest.php b/test/unit/Command/CommandHelperTest.php
new file mode 100644
index 0000000..3bf0a2b
--- /dev/null
+++ b/test/unit/Command/CommandHelperTest.php
@@ -0,0 +1,206 @@
+
+ *
+ * @psalm-suppress PossiblyUnusedMethod https://github.com/psalm/psalm-plugin-phpunit/issues/131
+ */
+ public static function validPackageAndVersions(): array
+ {
+ $packages = [
+ ['php/test-pie-ext', 'php/test-pie-ext', null],
+ ['php/test-pie-ext:^1.2', 'php/test-pie-ext', '^1.2'],
+ ['php/test-pie-ext:@alpha', 'php/test-pie-ext', '@alpha'],
+ ['php/test-pie-ext:~1.2.1', 'php/test-pie-ext', '~1.2.1'],
+ ['php/test-pie-ext:*', 'php/test-pie-ext', '*'],
+ ['php/test-pie-ext:1.2.3', 'php/test-pie-ext', '1.2.3'],
+ ];
+
+ return array_combine(
+ array_map(static fn (array $data) => $data[0], $packages),
+ $packages,
+ );
+ }
+
+ #[DataProvider('validPackageAndVersions')]
+ public function testRequestedNameAndVersionPair(string $requestedPackageAndVersion, string $expectedPackage, string|null $expectedVersion): void
+ {
+ $input = $this->createMock(InputInterface::class);
+
+ $input->expects(self::once())
+ ->method('getArgument')
+ ->with('requested-package-and-version')
+ ->willReturn($requestedPackageAndVersion);
+
+ self::assertSame(
+ [
+ 'name' => $expectedPackage,
+ 'version' => $expectedVersion,
+ ],
+ CommandHelper::requestedNameAndVersionPair($input),
+ );
+ }
+
+ public function testInvalidRequestedNameAndVersionPairThrowsExceptionWhenNoPackageProvided(): void
+ {
+ $input = $this->createMock(InputInterface::class);
+
+ $input->expects(self::once())
+ ->method('getArgument')
+ ->with('requested-package-and-version')
+ ->willReturn(null);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('No package was requested for installation');
+ CommandHelper::requestedNameAndVersionPair($input);
+ }
+
+ public function testDownloadPackage(): void
+ {
+ $dependencyResolver = $this->createMock(DependencyResolver::class);
+ $targetPlatform = TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromCurrentProcess());
+ $requestedNameAndVersionPair = ['name' => 'php/test-pie-ext', 'version' => '^1.2'];
+ $downloadAndExtract = $this->createMock(DownloadAndExtract::class);
+ $output = $this->createMock(OutputInterface::class);
+
+ $dependencyResolver->expects(self::once())
+ ->method('__invoke')
+ ->with(
+ $targetPlatform,
+ )
+ ->willReturn($package = new Package(
+ ExtensionName::normaliseFromString('test_pie_ext'),
+ 'php/test-pie-ext',
+ '1.2.3',
+ 'https://test-uri/',
+ [],
+ ));
+
+ $downloadAndExtract->expects(self::once())
+ ->method('__invoke')
+ ->with(
+ $targetPlatform,
+ $package,
+ )
+ ->willReturn($downloadedPackage = DownloadedPackage::fromPackageAndExtractedPath(
+ $package,
+ '/foo/bar',
+ ));
+
+ $output->expects(self::once())
+ ->method('writeln')
+ ->with(self::stringContains('Found package: php/test-pie-ext:1.2.3 which provides ext-test_pie_ext'));
+
+ self::assertSame($downloadedPackage, CommandHelper::downloadPackage(
+ $dependencyResolver,
+ $targetPlatform,
+ $requestedNameAndVersionPair,
+ $downloadAndExtract,
+ $output,
+ ));
+ }
+
+ public function testBindingConfigurationOptionsFromPackage(): void
+ {
+ self::markTestIncomplete(__METHOD__);
+ }
+
+ public function testProcessingConfigureOptionsFromInput(): void
+ {
+ $package = new Package(
+ ExtensionName::normaliseFromString('lolz'),
+ 'foo/bar',
+ '1.0.0',
+ null,
+ [
+ ConfigureOption::fromComposerJsonDefinition([
+ 'name' => 'with-stuff',
+ 'needs-value' => true,
+ ]),
+ ConfigureOption::fromComposerJsonDefinition(['name' => 'enable-thing']),
+ ],
+ );
+ $inputDefinition = new InputDefinition();
+ $inputDefinition->addOption(new InputOption('with-stuff', null, InputOption::VALUE_REQUIRED));
+ $inputDefinition->addOption(new InputOption('enable-thing', null, InputOption::VALUE_NONE));
+
+ $input = new ArrayInput(['--with-stuff' => 'lolz', '--enable-thing' => true], $inputDefinition);
+
+ $options = CommandHelper::processConfigureOptionsFromInput($package, $input);
+
+ self::assertSame(
+ [
+ '--with-stuff=' . escapeshellarg('lolz'),
+ '--enable-thing',
+ ],
+ $options,
+ );
+ }
+
+ public function testWindowsMachinesCannotUseWithPhpConfigOption(): void
+ {
+ if (! Platform::isWindows()) {
+ self::markTestSkipped('This test can only run on Windows');
+ }
+
+ $command = new Command();
+ $input = new ArrayInput(['--with-php-config' => 'C:\path\to\php-config']);
+ $output = new NullOutput();
+ CommandHelper::configureOptions($command);
+ CommandHelper::validateInput($input, $command);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('The --with-php-config=/path/to/php-config cannot be used on Windows, use --with-php-path=/path/to/php instead.');
+ CommandHelper::determineTargetPlatformFromInputs($input, $output);
+ }
+
+ public function testNonWindowsMachinesCannotUseWithPhpPathOption(): void
+ {
+ if (Platform::isWindows()) {
+ self::markTestSkipped('This test can only run on non-Windows');
+ }
+
+ $command = new Command();
+ $input = new ArrayInput(['--with-php-path' => '/usr/bin/php']);
+ $output = new NullOutput();
+ CommandHelper::configureOptions($command);
+ CommandHelper::validateInput($input, $command);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('The --with-php-path=/path/to/php cannot be used on non-Windows, use --with-php-config=/path/to/php-config instead.');
+ CommandHelper::determineTargetPlatformFromInputs($input, $output);
+ }
+}
diff --git a/test/unit/ConfigureOptionTest.php b/test/unit/ConfigureOptionTest.php
new file mode 100644
index 0000000..b35c56c
--- /dev/null
+++ b/test/unit/ConfigureOptionTest.php
@@ -0,0 +1,117 @@
+,
+ * expectedName: string,
+ * expectedNeedsValue: bool,
+ * expectedDescription: string,
+ * }
+ * >
+ *
+ * @psalm-suppress PossiblyUnusedMethod https://github.com/psalm/psalm-plugin-phpunit/issues/131
+ */
+ public static function composerJsonDefinitions(): array
+ {
+ return [
+ 'minimal' => [
+ 'definition' => ['name' => 'foo'],
+ 'expectedName' => 'foo',
+ 'expectedNeedsValue' => false,
+ 'expectedDescription' => '',
+ ],
+ 'full' => [
+ 'definition' => [
+ 'name' => 'foo',
+ 'needs-value' => false,
+ 'description' => 'Some option',
+ ],
+ 'expectedName' => 'foo',
+ 'expectedNeedsValue' => false,
+ 'expectedDescription' => 'Some option',
+ ],
+ 'needs-value' => [
+ 'definition' => [
+ 'name' => 'foo',
+ 'needs-value' => true,
+ 'description' => 'Some option',
+ ],
+ 'expectedName' => 'foo',
+ 'expectedNeedsValue' => true,
+ 'expectedDescription' => 'Some option',
+ ],
+ 'empty-description-allowed' => [
+ 'definition' => [
+ 'name' => 'foo',
+ 'needs-value' => false,
+ 'description' => '',
+ ],
+ 'expectedName' => 'foo',
+ 'expectedNeedsValue' => false,
+ 'expectedDescription' => '',
+ ],
+ ];
+ }
+
+ /** @param array $definition */
+ #[DataProvider('composerJsonDefinitions')]
+ public function testCanBeConstructedFromValidComposerJsonDefinition(array $definition, string $expectedName, bool $expectedNeedsValue, string $expectedDescription): void
+ {
+ $configureOption = ConfigureOption::fromComposerJsonDefinition($definition);
+
+ self::assertSame($expectedName, $configureOption->name);
+ self::assertSame($expectedNeedsValue, $configureOption->needsValue);
+ self::assertSame($expectedDescription, $configureOption->description);
+ }
+
+ /**
+ * @return array<
+ * non-empty-string,
+ * array{
+ * definition: array
+ * }
+ * >
+ *
+ * @psalm-suppress PossiblyUnusedMethod https://github.com/psalm/psalm-plugin-phpunit/issues/131
+ */
+ public static function invalidComposerJsonDefinitions(): array
+ {
+ return [
+ 'no-keys' => [
+ 'definition' => [],
+ ],
+ 'empty-name' => [
+ 'definition' => ['name' => ''],
+ ],
+ 'needs-value-invalid-type' => [
+ 'definition' => ['name' => 'foo', 'needs-value' => 'true'],
+ ],
+ 'description-invalid-type' => [
+ 'definition' => ['name' => 'foo', 'description' => 123],
+ ],
+ ];
+ }
+
+ /** @param array $definition */
+ #[DataProvider('invalidComposerJsonDefinitions')]
+ public function testInvalidComposerJsonDefinitionsAreRejected(array $definition): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ ConfigureOption::fromComposerJsonDefinition($definition);
+ }
+}
diff --git a/test/unit/Downloading/AddAuthenticationHeaderTest.php b/test/unit/Downloading/AddAuthenticationHeaderTest.php
index 854773c..6465c31 100644
--- a/test/unit/Downloading/AddAuthenticationHeaderTest.php
+++ b/test/unit/Downloading/AddAuthenticationHeaderTest.php
@@ -32,7 +32,13 @@ public function testAuthorizationHeaderIsAdded(): void
$requestWithAuthHeader = (new AddAuthenticationHeader())->withAuthHeaderFromComposer(
$request,
- new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', $downloadUrl),
+ new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ $downloadUrl,
+ [],
+ ),
$authHelper,
);
@@ -48,7 +54,13 @@ public function testExceptionIsThrownWhenPackageDoesNotHaveDownloadUrl(): void
$authHelper = $this->createMock(AuthHelper::class);
$addAuthenticationHeader = new AddAuthenticationHeader();
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', null);
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ null,
+ [],
+ );
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('The package foo/bar does not have a download URL');
diff --git a/test/unit/Downloading/DownloadedPackageTest.php b/test/unit/Downloading/DownloadedPackageTest.php
index 5ead146..078dd17 100644
--- a/test/unit/Downloading/DownloadedPackageTest.php
+++ b/test/unit/Downloading/DownloadedPackageTest.php
@@ -17,7 +17,13 @@ final class DownloadedPackageTest extends TestCase
{
public function testFromPackageAndExtractedPath(): void
{
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', null);
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ null,
+ [],
+ );
$extractedSourcePath = uniqid('/path/to/downloaded/package', true);
diff --git a/test/unit/Downloading/Exception/CouldNotFindReleaseAssetTest.php b/test/unit/Downloading/Exception/CouldNotFindReleaseAssetTest.php
index b03a335..5e5e494 100644
--- a/test/unit/Downloading/Exception/CouldNotFindReleaseAssetTest.php
+++ b/test/unit/Downloading/Exception/CouldNotFindReleaseAssetTest.php
@@ -20,7 +20,13 @@ final class CouldNotFindReleaseAssetTest extends TestCase
{
public function testForPackage(): void
{
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', null);
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ null,
+ [],
+ );
$exception = CouldNotFindReleaseAsset::forPackage($package, ['something.zip', 'something2.zip']);
@@ -29,7 +35,13 @@ public function testForPackage(): void
public function testForPackageWithMissingTag(): void
{
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', null);
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ null,
+ [],
+ );
$exception = CouldNotFindReleaseAsset::forPackageWithMissingTag($package);
diff --git a/test/unit/Downloading/GithubPackageReleaseAssetsTest.php b/test/unit/Downloading/GithubPackageReleaseAssetsTest.php
index 7c7efd4..b37d1e5 100644
--- a/test/unit/Downloading/GithubPackageReleaseAssetsTest.php
+++ b/test/unit/Downloading/GithubPackageReleaseAssetsTest.php
@@ -66,7 +66,13 @@ public function testUrlIsReturnedWhenFindingWindowsDownloadUrl(): void
$guzzleMockClient = new Client(['handler' => HandlerStack::create($mockHandler)]);
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'asgrim/example-pie-extension', '1.2.3', 'https://test-uri/' . uniqid('downloadUrl', true));
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'asgrim/example-pie-extension',
+ '1.2.3',
+ 'https://test-uri/' . uniqid('downloadUrl', true),
+ [],
+ );
$releaseAssets = new GithubPackageReleaseAssets($authHelper, $guzzleMockClient, 'https://test-github-api-base-url.thephp.foundation');
@@ -111,7 +117,13 @@ public function testUrlIsReturnedWhenFindingWindowsDownloadUrlWithCompilerAndThr
$guzzleMockClient = new Client(['handler' => HandlerStack::create($mockHandler)]);
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'asgrim/example-pie-extension', '1.2.3', 'https://test-uri/' . uniqid('downloadUrl', true));
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'asgrim/example-pie-extension',
+ '1.2.3',
+ 'https://test-uri/' . uniqid('downloadUrl', true),
+ [],
+ );
$releaseAssets = new GithubPackageReleaseAssets($authHelper, $guzzleMockClient, 'https://test-github-api-base-url.thephp.foundation');
@@ -142,7 +154,13 @@ public function testFindWindowsDownloadUrlForPackageThrowsExceptionWhenAssetNotF
$guzzleMockClient = new Client(['handler' => HandlerStack::create($mockHandler)]);
- $package = new Package(ExtensionName::normaliseFromString('foo'), 'asgrim/example-pie-extension', '1.2.3', 'https://test-uri/' . uniqid('downloadUrl', true));
+ $package = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'asgrim/example-pie-extension',
+ '1.2.3',
+ 'https://test-uri/' . uniqid('downloadUrl', true),
+ [],
+ );
$releaseAssets = new GithubPackageReleaseAssets($authHelper, $guzzleMockClient, 'https://test-github-api-base-url.thephp.foundation');
diff --git a/test/unit/Downloading/UnixDownloadAndExtractTest.php b/test/unit/Downloading/UnixDownloadAndExtractTest.php
index f0bc4da..c75ab9c 100644
--- a/test/unit/Downloading/UnixDownloadAndExtractTest.php
+++ b/test/unit/Downloading/UnixDownloadAndExtractTest.php
@@ -59,7 +59,13 @@ public function testInvoke(): void
->willReturn($extractedPath);
$downloadUrl = 'https://test-uri/' . uniqid('downloadUrl', true);
- $requestedPackage = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', $downloadUrl);
+ $requestedPackage = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ $downloadUrl,
+ [],
+ );
$downloadedPackage = $unixDownloadAndExtract->__invoke($targetPlatform, $requestedPackage);
diff --git a/test/unit/Downloading/WindowsDownloadAndExtractTest.php b/test/unit/Downloading/WindowsDownloadAndExtractTest.php
index 448bdd5..e413204 100644
--- a/test/unit/Downloading/WindowsDownloadAndExtractTest.php
+++ b/test/unit/Downloading/WindowsDownloadAndExtractTest.php
@@ -74,7 +74,13 @@ public function testInvoke(): void
)
->willReturn($extractedPath);
- $requestedPackage = new Package(ExtensionName::normaliseFromString('foo'), 'foo/bar', '1.2.3', 'https://test-uri/' . uniqid('downloadUrl', true));
+ $requestedPackage = new Package(
+ ExtensionName::normaliseFromString('foo'),
+ 'foo/bar',
+ '1.2.3',
+ 'https://test-uri/' . uniqid('downloadUrl', true),
+ [],
+ );
$downloadedPackage = $windowsDownloadAndExtract->__invoke($targetPlatform, $requestedPackage);
diff --git a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
index 44ba903..03f8f62 100644
--- a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
+++ b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
@@ -33,10 +33,13 @@ final class PhpBinaryPathTest extends TestCase
{
public function testVersionFromCurrentProcess(): void
{
+ $phpBinary = PhpBinaryPath::fromCurrentProcess();
+
self::assertSame(
sprintf('%s.%s.%s', PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION),
- PhpBinaryPath::fromCurrentProcess()->version(),
+ $phpBinary->version(),
);
+ self::assertNull($phpBinary->phpConfigPath());
}
public function testFromPhpConfigExecutable(): void
@@ -45,7 +48,7 @@ public function testFromPhpConfigExecutable(): void
$exitCode = $process->run();
$phpConfigExecutable = trim($process->getOutput());
- if ($exitCode !== 0 || ! file_exists($phpConfigExecutable) || ! is_executable($phpConfigExecutable)) {
+ if ($exitCode !== 0 || ! file_exists($phpConfigExecutable) || ! is_executable($phpConfigExecutable) || $phpConfigExecutable === '') {
self::markTestSkipped('Needs php-config in path to run this test');
}
@@ -59,6 +62,8 @@ public function testFromPhpConfigExecutable(): void
sprintf('%s.%s.%s', PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION),
$phpBinary->version(),
);
+
+ self::assertSame($phpConfigExecutable, $phpBinary->phpConfigPath());
}
public function testExtensions(): void