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

Infer main & output information from the composer.json #127

Merged
merged 3 commits into from
Apr 20, 2018
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ great things:
1. [Creating a PHAR](#creating-a-phar)
1. [Configuration](doc/configuration.md)
1. [Base path](doc/configuration.md#base-path-base-path)
1. [Output](doc/configuration.md#output-output)
1. [Main](doc/configuration.md#main-main)
1. [Output](doc/configuration.md#output-output)
1. [Permissions](doc/configuration.md#permissions-chmod)
1. [Including files](doc/configuration.md#including-files)
1. [Files (`files` and `files-bin`)](doc/configuration.md#files-files-and-files-bin)
Expand Down
9 changes: 9 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## From 3.0.0-alpha.1 to 3.0.0-alpha.2

- Change the default PHAR output from `default.phar` to `index.phar` (#127)
- When no configuration is provided or when the setting `main` is omitted, the value found in `composer.json#bin` will have the priority
over the default `index.php` (#127)
- When no configuraiton is provided or when the setting `output` is omitted, the default value will depend in the `input` value as opposed
to systematically `default.phar` (#127)


## From 3.0.0-alpha.0 to 3.0.0-alpha.1

### Backward-compatibility (BC) breaks
Expand Down
26 changes: 15 additions & 11 deletions doc/configuration.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Configuration

1. [Base path][base-path]
1. [Output][output]
1. [Main][main]
1. [Output][output]
1. [Permissions][permissions]
1. [Including files][including-files]
1. [Files (`files` and `files-bin`)][files]
Expand Down Expand Up @@ -76,27 +76,30 @@ If set to `null` or not specified, the base path used is the directory containin
configuration file is given or the current working directory otherwise.


## Output (`output`)

The output (`string`) setting specifies the file name and path of the newly built PHAR. If the value of the setting is
not an absolute path, the path will be relative to the base path.

If not provided, the default value used will be `default.phar`.


## Main (`main`)

The main (`string`) setting is used to specify the file (relative to [`base-path`][base-path]) that will be run when the
PHAR is executed from the command line (To not confuse with the [stub][stub] which is the PHAR bootstrapping file).

The default file used is `index.php`.
When the parameter is not given, Box tries to guess the binary of the application with the `composer.json` file. If the
[Composer `bin`][composer-bin] is set, Box will pick the first value provided. Otherwise it will fallback on the
[PHAR][phar class] default file used which is `index.php`.

The main file contents is processed by the [compactors][compactors] as the other files.

If the main file starts with a shebang line (`#!`), it will be automatically removed (the shebang line goes in the
[stub][stub] for a PHAR and is configured by the [shebang][shebang] setting).


## Output (`output`)

The output (`string`) setting specifies the file name and path of the newly built PHAR. If the value of the setting is
not an absolute path, the path will be relative to the base path.

If not provided, the default value used will based on the [`main`][main]. For example if the main file is `bin/acme.php`
or `bin/acme` then the output will be `bin/acme.phar`.


## Permissions (`chmod`)

The chmod (`string`|`null`) setting is used to change the file permissions of the newly built PHAR. The string contains
Expand Down Expand Up @@ -505,6 +508,7 @@ The metadata (`any`) setting can be any value. This value will be stored as meta
[shebang]: #shebang-shebang
[banner]: #banner-banner
[banner-file]: #banner-file-banner-file
[phar class]: https://secure.php.net/manual/en/class.phar.php
[phar.mapphar]: https://secure.php.net/manual/en/phar.mapphar.php
[phar.setalias]: https://secure.php.net/manual/en/phar.setalias.php
[phar.webphar]: https://secure.php.net/manual/en/phar.webphar.php
Expand All @@ -520,7 +524,7 @@ The metadata (`any`) setting can be any value. This value will be stored as meta
[compression]: #compression-algorithm-compression
[algorithm]: #signing-algorithm-algorithm
[metadata]: #metadata-metadata

[composer-bin]: https://getcomposer.org/doc/04-schema.md#bin



Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
namespace KevinGH\Box;

use Assert\Assertion;
use function file_exists;
use KevinGH\Box\Compactor\PhpScoper;
use KevinGH\Box\Composer\ComposerOrchestrator;
use KevinGH\Box\PhpScoper\NullScoper;
Expand All @@ -28,6 +27,7 @@
use function Amp\Promise\wait;
use function array_map;
use function chdir;
use function file_exists;
use function KevinGH\Box\FileSystem\dump_file;
use function KevinGH\Box\FileSystem\file_contents;
use function KevinGH\Box\FileSystem\make_path_relative;
Expand Down
32 changes: 24 additions & 8 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_merge;
use function array_unique;
Expand All @@ -51,6 +52,7 @@
use function KevinGH\Box\FileSystem\longest_common_base_path;
use function KevinGH\Box\FileSystem\make_path_absolute;
use function KevinGH\Box\FileSystem\make_path_relative;
use function preg_match;
use function substr;
use function uniqid;

Expand All @@ -59,7 +61,7 @@
*/
final class Configuration
{
private const DEFAULT_ALIAS = 'default.phar';
private const DEFAULT_ALIAS = 'test.phar';
private const DEFAULT_MAIN_SCRIPT = 'index.php';
private const DEFAULT_DATETIME_FORMAT = 'Y-m-d H:i:s';
private const DEFAULT_REPLACEMENT_SIGIL = '@';
Expand Down Expand Up @@ -210,12 +212,12 @@ public static function create(?string $file, stdClass $raw): self

$basePath = self::retrieveBasePath($file, $raw);

[$tmpOutputPath, $outputPath] = self::retrieveOutputPath($raw, $basePath);
$composerFiles = self::retrieveComposerFiles($basePath);

$mainScriptPath = self::retrieveMainScriptPath($raw, $basePath);
$mainScriptPath = self::retrieveMainScriptPath($raw, $basePath, $composerFiles[0][1]);
$mainScriptContents = self::retrieveMainScriptContents($mainScriptPath);

$composerFiles = self::retrieveComposerFiles($basePath);
[$tmpOutputPath, $outputPath] = self::retrieveOutputPath($raw, $basePath, $mainScriptPath);

$composerJson = $composerFiles[0];
$composerLock = $composerFiles[1];
Expand Down Expand Up @@ -1006,9 +1008,18 @@ private static function retrieveFileMode(stdClass $raw): ?int
return null;
}

private static function retrieveMainScriptPath(stdClass $raw, string $basePath): string
private static function retrieveMainScriptPath(stdClass $raw, string $basePath, ?array $decodedJsonContents): string
{
$main = isset($raw->main) ? $raw->main : self::DEFAULT_MAIN_SCRIPT;
if (isset($raw->main)) {
$main = $raw->main;
} else {
if (null === $decodedJsonContents
|| false === array_key_exists('bin', $decodedJsonContents)
|| false === $main = current($decodedJsonContents['bin'])
) {
$main = self::DEFAULT_MAIN_SCRIPT;
}
}

return self::normalizePath($main, $basePath);
}
Expand Down Expand Up @@ -1106,12 +1117,17 @@ private static function retrieveMetadata(stdClass $raw)
/**
* @return string[] The first element is the temporary output path and the second the real one
*/
private static function retrieveOutputPath(stdClass $raw, string $basePath): array
private static function retrieveOutputPath(stdClass $raw, string $basePath, string $mainScriptPath): array
{
if (isset($raw->output)) {
$path = $raw->output;
} else {
$path = self::DEFAULT_ALIAS;
if (1 === preg_match('/^(?<main>.*?)(?:\.[\p{L}\d]+)?$/', $mainScriptPath, $matches)) {
$path = $matches['main'].'.phar';
} else {
// Last resort, should not happen
$path = self::DEFAULT_ALIAS;
}
}

$tmp = $real = self::normalizePath($path, $basePath);
Expand Down
69 changes: 64 additions & 5 deletions tests/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
use Phar;
use Seld\JsonLint\ParsingException;
use stdClass;
use const DIRECTORY_SEPARATOR;
use function file_put_contents;
use function KevinGH\Box\FileSystem\dump_file;
use function KevinGH\Box\FileSystem\make_path_absolute;
use function KevinGH\Box\FileSystem\remove;
use function KevinGH\Box\FileSystem\rename;
use function KevinGH\Box\FileSystem\symlink;
use const DIRECTORY_SEPARATOR;

/**
* @covers \KevinGH\Box\Configuration
Expand Down Expand Up @@ -1873,7 +1874,7 @@ public function test_the_blacklist_setting_is_applied_to_all_the_files_found_in_

public function test_the_existing_phars_are_ignored_when_all_the_files_are_collected(): void
{
touch('default.phar');
touch('index.phar');

// Relative to the current working directory for readability
$expected = [
Expand All @@ -1887,6 +1888,7 @@ public function test_the_existing_phars_are_ignored_when_all_the_files_are_colle
$this->assertEquals($expected, $actual, '', .0, 10, true);
$this->assertCount(0, $this->config->getBinaryFiles());

remove('index.phar');
touch('default');

// Relative to the current working directory for readability
Expand Down Expand Up @@ -2097,12 +2099,55 @@ public function test_a_main_script_path_is_configured_by_default(): void
{
$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'index.php', $this->config->getMainScriptPath());
$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'index.php', $this->getNoFileConfig()->getMainScriptPath());

dump_file('composer.json', '{"bin": []}');

$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'index.php', $this->config->getMainScriptPath());
$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'index.php', $this->getNoFileConfig()->getMainScriptPath());
}

public function test_a_main_script_path_is_inferred_by_the_composer_json_by_default(): void
{
dump_file('bin/foo');
dump_file('bin/bar');

dump_file(
'composer.json',
<<<'JSON'
{
"bin": [
"bin/foo",
"bin/bar"
]
}
JSON
);

$this->reloadConfig();

$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'bin/foo', $this->config->getMainScriptPath());
$this->assertSame($this->tmp.DIRECTORY_SEPARATOR.'bin/foo', $this->getNoFileConfig()->getMainScriptPath());
}

public function test_main_script_can_be_configured(): void
{
touch('test.php');

dump_file('bin/foo');
dump_file('bin/bar');

dump_file(
'composer.json',
<<<'JSON'
{
"bin": [
"bin/foo",
"bin/bar"
]
}
JSON
);

$this->setConfig(['main' => 'test.php']);

$this->assertSame($this->tmp.'/test.php', $this->config->getMainScriptPath());
Expand Down Expand Up @@ -2223,11 +2268,11 @@ public function test_can_configure_metadata(): void
public function test_get_default_output_path(): void
{
$this->assertSame(
$this->tmp.DIRECTORY_SEPARATOR.'default.phar',
$this->tmp.DIRECTORY_SEPARATOR.'index.phar',
$this->config->getOutputPath()
);
$this->assertSame(
$this->tmp.DIRECTORY_SEPARATOR.'default.phar',
$this->tmp.DIRECTORY_SEPARATOR.'index.phar',
$this->config->getTmpOutputPath()
);
}
Expand Down Expand Up @@ -2306,7 +2351,7 @@ public function test_the_output_path_is_normalized(): void
);
}

public function test_the_output_path_can_not_have_a_PHAR_extension(): void
public function test_the_output_path_can_omit_the_PHAR_extension(): void
{
$this->setConfig([
'files' => [self::DEFAULT_FILE],
Expand All @@ -2323,6 +2368,20 @@ public function test_the_output_path_can_not_have_a_PHAR_extension(): void
);
}

public function test_get_default_output_path_depends_on_the_input(): void
{
dump_file('bin/acme');

$this->setConfig([
'main' => 'bin/acme',
]);

$this->assertSame(
$this->tmp.'/bin/acme.phar',
$this->config->getOutputPath()
);
}

public function testGetPrivateKeyPassphrase(): void
{
$this->assertNull($this->config->getPrivateKeyPassphrase());
Expand Down
Loading