Skip to content
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
6 changes: 0 additions & 6 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,9 @@ jobs:
libbz2-dev \
libzip-dev
- name: "Set php-src download URL"
if: ${{ !startsWith(matrix.php-versions, '8.5') }}
run: |
DIST_URL=`curl -fsSL "https://www.php.net/releases/index.php?json&max=1&version=${{ matrix.php-versions }}" | jq -r '.[].source[]|select(.filename|endswith(".gz")).filename'`
echo "php_src_download_url=https://www.php.net/distributions/$DIST_URL" >> $GITHUB_ENV
- name: "Set php-src download URL (8.5 pre-release)"
if: ${{ startsWith(matrix.php-versions, '8.5') }}
run: |
RC_URL=`curl -fsSL "https://www.php.net/release-candidates.php?format=json" | jq -r '.releases[]|select(.version|startswith("${{ matrix.php-versions }}")).files.gz.path'`
echo "php_src_download_url=$RC_URL" >> $GITHUB_ENV
- name: "Install PHP ${{ matrix.php-versions }}"
run: |
mkdir -p /tmp/php
Expand Down
17 changes: 17 additions & 0 deletions features/build-extensions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Feature: Extensions can be built with PIE

# pie build <ext>
Example: An extension can be built
When I run a command to build an extension
Then the extension should have been built

# pie build <ext>
Example: An extension can be built with warnings at PHP startup
Given I have an invalid extension installed
When I run a command to build an extension
Then the extension should have been built

# pie build <ext> --with-some-options=foo
Example: An extension can be built with configure options
When I run a command to build an extension with configure options
Then the extension should have been built with options
22 changes: 22 additions & 0 deletions features/download-extensions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Feature: Extensions can be downloaded with PIE

# pie download <ext>
Example: The latest version of an extension can be downloaded
When I run a command to download the latest version of an extension
Then the latest version should have been downloaded

# pie download <ext>:<version>
Scenario Outline: A version matching the requested constraint can be downloaded
When I run a command to download version "<constraint>" of an extension
Then version "<version>" should have been downloaded

Examples:
| constraint | version |
| 2.0.5 | 2.0.5 |
| ^2.0 | 2.0.5 |

# pie download <ext>:dev-main
@non-windows
Example: An in-development version can be downloaded on non-Windows systems
When I run a command to download version "dev-main" of an extension
Then version "dev-main" should have been downloaded
36 changes: 0 additions & 36 deletions features/install-extensions.feature
Original file line number Diff line number Diff line change
@@ -1,41 +1,5 @@
Feature: Extensions can be installed with PIE

# pie download <ext>
Example: The latest version of an extension can be downloaded
When I run a command to download the latest version of an extension
Then the latest version should have been downloaded

# pie download <ext>:<version>
Scenario Outline: A version matching the requested constraint can be downloaded
When I run a command to download version "<constraint>" of an extension
Then version "<version>" should have been downloaded

Examples:
| constraint | version |
| 2.0.5 | 2.0.5 |
| ^2.0 | 2.0.5 |

# pie download <ext>:dev-main
@non-windows
Example: An in-development version can be downloaded on non-Windows systems
When I run a command to download version "dev-main" of an extension
Then version "dev-main" should have been downloaded

# pie build <ext>
Example: An extension can be built
When I run a command to build an extension
Then the extension should have been built

Example: An extension can be built with warnings at PHP startup
Given I have an invalid extension installed
When I run a command to build an extension
Then the extension should have been built

# pie build <ext> --with-some-options=foo
Example: An extension can be built with configure options
When I run a command to build an extension with configure options
Then the extension should have been built with options

# pie install <ext> --skip-enable-extension
Example: An extension can be installed without enabling
When I run a command to install an extension without enabling it
Expand Down
55 changes: 55 additions & 0 deletions src/Command/ArgvInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Php\Pie\Command;

use Throwable;

class ArgvInput extends \Symfony\Component\Console\Input\ArgvInput
{
private Throwable|null $exceptionThrown = null;

/**
* Wrap parent token parsing to collect and ignore exceptions during
* parsing. This ensures that errors we meet mid-way through parsing don't
* short-circuit processing the rest of the arguments. Without this, whilst
* the following example works:
*
* pie build asgrim/example-pie-extension --with-hello-name=sup
*
* This does not:
*
* pie build --with-hello-name=sup asgrim/example-pie-extension
*
* This is because when Symfony tries to parse the `--with-hello-name`, it
* hasn't loaded in the configure options for the package yet, and so
* throws an exception and does not process the package name argument.
*
* Note, however, there is still a limitation, as this will not work:
*
* pie build --with-hello-name sup asgrim/example-pie-extension
*/
protected function parse(): void
{
$this->exceptionThrown = null;

parent::parse();

if ($this->exceptionThrown !== null) {
throw $this->exceptionThrown;
}
}

protected function parseToken(string $token, bool $parseOptions): bool
{
try {
return parent::parseToken($token, $parseOptions);
} catch (Throwable $caught) {
$this->exceptionThrown = $caught;

// Ignore the error intentionally
return $parseOptions;
}
}
}
2 changes: 1 addition & 1 deletion src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Php\Pie\Building\Build;
use Php\Pie\Building\UnixBuild;
use Php\Pie\Building\WindowsBuild;
use Php\Pie\Command\ArgvInput;
use Php\Pie\Command\BuildCommand;
use Php\Pie\Command\DownloadCommand;
use Php\Pie\Command\InfoCommand;
Expand Down Expand Up @@ -43,7 +44,6 @@
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down
49 changes: 49 additions & 0 deletions test/unit/Command/ArgvInputTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Php\PieUnitTest\Command;

use Php\Pie\Command\ArgvInput;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Throwable;

#[CoversClass(ArgvInput::class)]
final class ArgvInputTest extends TestCase
{
/** @return array<string, list<list<string>>> */
public static function argvWithInvalidInputProvider(): array
{
return [
'simple-option' => [['myapp', '--invalid-option', 'myvalue']],
'value-option' => [['myapp', '--invalid-option=foo', 'myvalue']],
'short-option' => [['myapp', '-i', 'myvalue']],
// explicitly not supported for now; we can't tell which is the argument here
// 'split-option' => [['myapp', '--invalid-option', 'foo', 'myvalue']],
];
}

/** @param list<string> $argv */
#[DataProvider('argvWithInvalidInputProvider')]
public function testInvalidOptionsDoNotCauseArgumentsToBeMissed(array $argv): void
{
$definition = new InputDefinition();
$definition->addArgument(new InputArgument('myarg', InputArgument::OPTIONAL));

$argvInput = new ArgvInput($argv);
try {
$argvInput->bind($definition);
self::fail('Expected an exception to be thrown because `--invalid-option` is not defined');
} catch (Throwable) {
// An exception is expected here, because `--invalid-option` was not defined
self::addToAssertionCount(1);
}

// But, crucially, we should have captured the following argument
self::assertSame('myvalue', $argvInput->getArgument('myarg'));
}
}
Loading