Skip to content

Commit

Permalink
Allow to exclude Composer files (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry authored May 23, 2018
1 parent d0d15ea commit 6915801
Show file tree
Hide file tree
Showing 9 changed files with 424 additions and 58 deletions.
17 changes: 16 additions & 1 deletion doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
1. [Banner (`banner`)][banner]
1. [Banner file (`banner-file`)][banner-file]
1. [Dumping the Composer autoloader (`dump-autoload`)][dump-autoload]
1. [Excluding the Composer files (`exclude-composer-files`)][exclude-composer-files]
1. [Compactors (`compactors`)][compactors]
1. [Compression algorithm (`compression`)][compression]
1. [Signing algorithm (`algorithm`)][algorithm]
Expand All @@ -34,7 +35,8 @@ specified through the `--configuration|-c option`, one of the following files wi
`box.json.dist`. If no configuration file is found, Box will proceed with the default settings.

The configuration file is a JSON object saved to a file. Note that all settings are optional.
//TODO: update this last bit of information as this is not true
// TODO: update this last bit of information as this is not true
// TODO: add a test to ensure this schema is always up to date with the actual schema file

```json
{
Expand All @@ -53,6 +55,7 @@ The configuration file is a JSON object saved to a file. Note that all settings
"directories": "?",
"directories-bin": "?",
"dump-autoload": "?",
"exclude-composer-files": "?",
"files": "?",
"files-bin": "?",
"finder": "?",
Expand Down Expand Up @@ -461,6 +464,18 @@ The autoloader is dumped at the end of the process to ensure it will take into a
by the [compactors][compactors] process.


## Excluding the Composer files (`exclude-composer-files`)

The `dump-autoload` (`boolean`|`null`, default `true`) setting will result in Box dump the Composer autoload with the
[classmap authoritative mode][composer-classmap-authoritative] and the [`--no-dev` option][composer-no-dev-option] which
disables the `autoload-dev` rules. This is however done only if a `composer.json` file could be found.

The dumping of the autoloader will be _ignored_ if the `composer.json` file could be found.

The autoloader is dumped at the end of the process to ensure it will take into account the eventual modifications done
by the [compactors][compactors] process.


## Compactors (`compactors`)

The compactors (`string[]`) setting is a list of file contents compacting classes that must be registered. A file
Expand Down
4 changes: 4 additions & 0 deletions res/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
"description": "Will dump the optimized Composer autoloader.",
"type": ["boolean", "null"]
},
"exclude-composer-files": {
"description": "Will remove the composer.json, composer.lock and installed.json files from the PHAR",
"type": ["boolean", "null"]
},
"files": {
"description": "A list of file paths to include.",
"items": {
Expand Down
28 changes: 28 additions & 0 deletions src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,34 @@ public function endBuffering(bool $dumpAutoload): void
$this->phar->stopBuffering();
}

public function removeComposerArtefacts(string $vendorDir): void
{
Assertion::false($this->buffering, 'The buffering must have ended before removing the Composer artefacts');

$composerFiles = [
'composer.json',
'composer.lock',
$vendorDir.'/composer/installed.json',
];

$this->phar->startBuffering();

foreach ($composerFiles as $composerFile) {
// TODO: the file map could return the unchanged path when no mapping is found...
$localComposerFile = ($this->mapFile)($composerFile);

if (null === $localComposerFile) {
$localComposerFile = $composerFile;
}

if (file_exists('phar://'.$this->phar->getPath().'/'.$localComposerFile)) {
$this->phar->delete($localComposerFile);
}
}

$this->phar->stopBuffering();
}

/**
* @return null|string The required extension to execute the PHAR now that it is compressed
*/
Expand Down
8 changes: 4 additions & 4 deletions src/Composer/ComposerConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ function (string $packageName) use ($vendorDir): ?string {
);
}

private static function retrieveVendorDir(array $composerJsonDecodedContents): string
public static function retrieveVendorDir(array $composerJsonDecodedContents): string
{
if (!array_key_exists('config', $composerJsonDecodedContents)) {
if (false === array_key_exists('config', $composerJsonDecodedContents)) {
return 'vendor';
}

if (!array_key_exists('vendor-dir', $composerJsonDecodedContents['config'])) {
if (false === array_key_exists('vendor-dir', $composerJsonDecodedContents['config'])) {
return 'vendor';
}

Expand All @@ -85,7 +85,7 @@ private static function retrieveVendorDir(array $composerJsonDecodedContents): s
*/
private static function retrieveDevPackageNames(array $composerLockDecodedContents): array
{
if (!array_key_exists('packages-dev', $composerLockDecodedContents)) {
if (false === array_key_exists('packages-dev', $composerLockDecodedContents)) {
return [];
}

Expand Down
25 changes: 23 additions & 2 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ final class Configuration
private $files;
private $binaryFiles;
private $dumpAutoload;
private $excludeComposerFiles;
private $compactors;
private $compressionAlgorithm;
private $mainScriptPath;
Expand All @@ -116,11 +117,15 @@ final class Configuration
/**
* @param null|string $file
* @param null|string $alias
* @param string $basePath Utility to private the base path used and be able to retrieve a path relative to it (the base path)
* @param string $basePath Utility to private the base path used and be able to retrieve a
* path relative to it (the base path)
* @param null[]|string[] $composerJson
* @param null[]|string[] $composerLock
* @param SplFileInfo[] $files List of files
* @param SplFileInfo[] $binaryFiles List of binary files
* @param bool $dumpAutoload Whether or not the Composer autoloader should be dumped
* @param bool $excludeComposerFiles Whether or not the Composer files composer.json, composer.lock and
* installed.json should be removed from the PHAR
* @param Compactor[] $compactors List of file contents compactors
* @param null|int $compressionAlgorithm Compression algorithm constant value. See the \Phar class constants
* @param null|int $fileMode File mode in octal form
Expand All @@ -137,7 +142,8 @@ final class Configuration
* @param null|string $stubPath The PHAR stub file path
* @param bool $isInterceptFileFuncs Whether or not Phar::interceptFileFuncs() should be used
* @param bool $isStubGenerated Whether or not if the PHAR stub should be generated
* @param bool $checkRequirements Whether the PHAR will check the application requirements before running
* @param bool $checkRequirements Whether the PHAR will check the application requirements before
* running
*/
private function __construct(
?string $file,
Expand All @@ -148,6 +154,7 @@ private function __construct(
array $files,
array $binaryFiles,
bool $dumpAutoload,
bool $excludeComposerFiles,
array $compactors,
?int $compressionAlgorithm,
?int $fileMode,
Expand Down Expand Up @@ -193,6 +200,7 @@ private function __construct(
$this->files = $files;
$this->binaryFiles = $binaryFiles;
$this->dumpAutoload = $dumpAutoload;
$this->excludeComposerFiles = $excludeComposerFiles;
$this->compactors = $compactors;
$this->compressionAlgorithm = $compressionAlgorithm;
$this->fileMode = $fileMode;
Expand Down Expand Up @@ -276,6 +284,8 @@ public static function create(?string $file, stdClass $raw): self

$dumpAutoload = self::retrieveDumpAutoload($raw, null !== $composerJson[0]);

$excludeComposerFiles = self::retrieveExcludeComposerFiles($raw);

$compactors = self::retrieveCompactors($raw, $basePath);
$compressionAlgorithm = self::retrieveCompressionAlgorithm($raw);

Expand Down Expand Up @@ -327,6 +337,7 @@ public static function create(?string $file, stdClass $raw): self
$filesAggregate,
$binaryFilesAggregate,
$dumpAutoload,
$excludeComposerFiles,
$compactors,
$compressionAlgorithm,
$fileMode,
Expand Down Expand Up @@ -407,6 +418,11 @@ public function dumpAutoload(): bool
return $this->dumpAutoload;
}

public function excludeComposerFiles(): bool
{
return $this->excludeComposerFiles;
}

/**
* @return Compactor[] the list of compactors
*/
Expand Down Expand Up @@ -1262,6 +1278,11 @@ private static function retrieveDumpAutoload(stdClass $raw, bool $composerJson):
return $composerJson ? $dumpAutoload : false;
}

private static function retrieveExcludeComposerFiles(stdClass $raw): bool
{
return $raw->{'exclude-composer-files'} ?? true;
}

/**
* @return Compactor[]
*/
Expand Down
21 changes: 21 additions & 0 deletions src/Console/Command/Compile.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use DateTimeZone;
use KevinGH\Box\Box;
use KevinGH\Box\Compactor;
use KevinGH\Box\Composer\ComposerConfiguration;
use KevinGH\Box\Configuration;
use KevinGH\Box\Console\Logger\BuildLogger;
use KevinGH\Box\MapFile;
Expand Down Expand Up @@ -219,6 +220,8 @@ private function createPhar(

$this->commit($box, $config, $logger);

$this->checkComposerFiles($box, $config, $logger);

$this->configureCompressionAlgorithm($config, $box, $input->getOption(self::DEV_OPTION), $io, $logger);

if ($debug) {
Expand Down Expand Up @@ -537,6 +540,24 @@ private function commit(Box $box, Configuration $config, BuildLogger $logger): v
$box->endBuffering($config->dumpAutoload());
}

private function checkComposerFiles(Box $box, Configuration $config, BuildLogger $logger): void
{
$message = $config->excludeComposerFiles()
? 'Removing the Composer dump artefacts'
: 'Keep the Composer dump artefacts'
;

$logger->log(BuildLogger::QUESTION_MARK_PREFIX, $message);

if ($config->excludeComposerFiles()) {
$box->removeComposerArtefacts(
ComposerConfiguration::retrieveVendorDir(
$config->getComposerJsonDecodedContents() ?? []
)
);
}
}

private function configureCompressionAlgorithm(Configuration $config, Box $box, bool $dev, SymfonyStyle $io, BuildLogger $logger): void
{
if (null === ($algorithm = $config->getCompressionAlgorithm())) {
Expand Down
111 changes: 111 additions & 0 deletions tests/BoxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use Exception;
use InvalidArgumentException;
use function iterator_to_array;
use KevinGH\Box\Compactor\FakeCompactor;
use KevinGH\Box\Console\DisplayNormalizer;
use KevinGH\Box\Test\FileSystemTestCase;
Expand Down Expand Up @@ -730,6 +731,116 @@ public function test_it_cannot_dump_the_autoloader_when_adding_files_to_the_phar
}
}

public function test_it_can_remove_the_composer_files(): void
{
$files = [
'composer.json' => '{}',
'composer.lock' => '{}',
'vendor/composer/installed.json' => '{}',
];

foreach ($files as $file => $contents) {
dump_file($file, $contents);
}

$this->box->startBuffering();
$this->box->addFiles(array_keys($files), true);
$this->box->endBuffering(true);

foreach ($files as $file => $contents) {
$this->assertFileExists('phar://test.phar/'.$file);
}

$this->box->removeComposerArtefacts('vendor');

foreach ($files as $file => $contents) {
$this->assertFileNotExists('phar://test.phar/'.$file);
}
}

public function test_it_can_remove_the_composer_files_with_a_custom_vendor_directory(): void
{
$files = [
'composer.json' => <<<'JSON'
{
"config": {
"vendor-dir": "my-vendor"
}
}
JSON
,
'composer.lock' => '{}',
'my-vendor/composer/installed.json' => '{}',
];

foreach ($files as $file => $contents) {
dump_file($file, $contents);
}

$this->box->startBuffering();
$this->box->addFiles(array_keys($files), true);
$this->box->endBuffering(true);

foreach ($files as $file => $contents) {
$this->assertFileExists('phar://test.phar/'.$file);
}

$this->box->removeComposerArtefacts('my-vendor');

foreach ($files as $file => $contents) {
$this->assertFileNotExists('phar://test.phar/'.$file);
}
}

public function test_it_can_remove_the_composer_files_mapped_with_a_different_path(): void
{
$files = [
'composer.json' => '{}',
'composer.lock' => '{}',
'vendor/composer/installed.json' => '{}',
];

foreach ($files as $file => $contents) {
dump_file($file, $contents);
}

$map = new MapFile([
['' => 'lib'],
]);

$this->box->registerFileMapping($this->tmp, $map);

$this->box->startBuffering();
$this->box->addFiles(array_keys($files), true);
$this->box->endBuffering(false);

foreach ($files as $file => $contents) {
$this->assertFileExists('phar://test.phar/lib/'.$file);
}

$this->box->removeComposerArtefacts('vendor');

foreach ($files as $file => $contents) {
$this->assertFileNotExists('phar://test.phar/lib/'.$file);
}
}

public function test_it_cannot_remove_the_composer_files_when_buffering(): void
{
$this->box->startBuffering();

try {
$this->box->removeComposerArtefacts('vendor');

$this->fail('Expected exception to be thrown.');
} catch (InvalidArgumentException $exception) {
$this->assertSame(
'The buffering must have ended before removing the Composer artefacts',
$exception->getMessage()
);
}
}

public function test_it_fails_gracefully_when_the_autoloader_failed_to_be_dumped(): void
{
$this->box->startBuffering();
Expand Down
Loading

0 comments on commit 6915801

Please sign in to comment.