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

Fix the blacklist usage #106

Merged
merged 1 commit into from
Apr 7, 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
42 changes: 42 additions & 0 deletions doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ will be used in order to collect the files instead to collect all the files avai
or directory from a dev dependency, you can do so by adding it via one of the following setting: [`files`][files],
[`files-bin`][files], [`directories`][directories] or [`directories-bin`][directories].


### Files (`files` and `files-bin`)

The `files` (`string[]`) setting is a list of files paths relative to [`base-path`][base-path] unless absolute. Each
Expand Down Expand Up @@ -194,6 +195,47 @@ The `blacklist` (`string[]`) setting is a list of files that must not be added.
using the other available configuration settings: [`files`][files], [`files-bin`][files], [`directories`][directories],
[`directories-bin`][directories], [`finder`][finder], [`finder-bin`][finder].

Note that all the blacklisted paths are relative to the settings configured above. For example if you have the following
file structure:

```
project/
├── box.json.dist
├── A/
| ├── A00
| └── A01
└── B/
├── B00
├── B01
└── A/
└── BA00
```

With:

```json
{
# other non file related settings

"blacklist": [
"A"
]
}
```

Box will try to collect all the files found in `project` (cf. [Including files][including-files]) but will exclude `A/`
and 'B/A' resulting in the following files being collected:

```
project/
├── box.json.dist
└── B/
├── B00
└── B01
```

You you want a more granular blacklist leverage the [Finders configuration][finder] instead.


## Stub

Expand Down
102 changes: 76 additions & 26 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,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_quote;
use function uniqid;

final class Configuration
Expand Down Expand Up @@ -187,21 +188,21 @@ public static function create(?string $file, stdClass $raw): self

$devPackages = ComposerConfiguration::retrieveDevPackages($basePath);

$blacklistFilter = self::retrieveBlacklistFilter($raw, $basePath);
[$excludedPaths, $blacklistFilter] = self::retrieveBlacklistFilter($raw, $basePath);

if (self::shouldRetrieveAllFiles($file, $raw)) {
$filesAggregate = self::retrieveAllFiles($basePath, $mainScriptPath, $blacklistFilter, $devPackages);
$filesAggregate = self::retrieveAllFiles($basePath, $mainScriptPath, $blacklistFilter, $excludedPaths, $devPackages);
$binaryFilesAggregate = [];
} else {
$files = self::retrieveFiles($raw, 'files', $basePath);
$directories = self::retrieveDirectories($raw, 'directories', $basePath, $blacklistFilter);
$filesFromFinders = self::retrieveFilesFromFinders($raw, 'finder', $basePath, $blacklistFilter, $devPackages);
$directories = self::retrieveDirectories($raw, 'directories', $basePath, $blacklistFilter, $excludedPaths);
$filesFromFinders = self::retrieveFilesFromFinders($raw, 'finder', $basePath, $blacklistFilter, $excludedPaths, $devPackages);

$filesAggregate = array_unique(iterator_to_array(chain($files, $directories, ...$filesFromFinders)));

$binaryFiles = self::retrieveFiles($raw, 'files-bin', $basePath);
$binaryDirectories = self::retrieveDirectories($raw, 'directories-bin', $basePath, $blacklistFilter);
$binaryFilesFromFinders = self::retrieveFilesFromFinders($raw, 'finder-bin', $basePath, $blacklistFilter, $devPackages);
$binaryDirectories = self::retrieveDirectories($raw, 'directories-bin', $basePath, $blacklistFilter, $excludedPaths);
$binaryFilesFromFinders = self::retrieveFilesFromFinders($raw, 'finder-bin', $basePath, $blacklistFilter, $excludedPaths, $devPackages);

$binaryFilesAggregate = array_unique(iterator_to_array(chain($binaryFiles, $binaryDirectories, ...$binaryFilesFromFinders)));
}
Expand Down Expand Up @@ -463,23 +464,19 @@ private static function shouldRetrieveAllFiles(?string $file, stdClass $raw): bo
return true;
}

/**
* @param stdClass $raw
* @param string $basePath
*
* @return Closure
*/
private static function retrieveBlacklistFilter(stdClass $raw, string $basePath): Closure
private static function retrieveBlacklistFilter(stdClass $raw, string $basePath): array
{
$blacklist = self::retrieveBlacklist($raw, $basePath);

return function (SplFileInfo $file) use ($blacklist): ?bool {
$blacklistFilter = function (SplFileInfo $file) use ($blacklist): ?bool {
if (in_array($file->getRealPath(), $blacklist, true)) {
return false;
}

return null;
};

return [$blacklist, $blacklistFilter];
}

/**
Expand All @@ -494,13 +491,39 @@ private static function retrieveBlacklist(stdClass $raw, string $basePath): arra
return [];
}

/** @var string[] $blacklist */
$blacklist = $raw->blacklist;

$normalizePath = function ($file) use ($basePath): string {
$normalizePath = function (string $file) use ($basePath): string {
return self::normalizePath($file, $basePath);
};

return array_unique(array_map($normalizePath, $blacklist));
$normalizedBlacklist = [];

foreach ($blacklist as $file) {
$normalizedBlacklist[] = self::normalizePath($file, $basePath);
$normalizedBlacklist[] = canonicalize(make_path_relative(trim($file), $basePath));
}

return array_unique($normalizedBlacklist);
}

/**
* @return string[]
*/
private static function retrieveExcludes(stdClass $raw, string $basePath): array
{
if (false === isset($raw->exclude)) {
return [];
}

$exclude = $raw->exclude;

$normalizePath = function (string $file) use ($basePath): string {
return canonicalize(make_path_relative(trim($file), $basePath));
};

return array_unique(array_map($normalizePath, $exclude));
}

/**
Expand Down Expand Up @@ -552,33 +575,43 @@ private static function retrieveFiles(stdClass $raw, string $key, string $basePa
* @param string $key Config property name
* @param string $basePath
* @param Closure $blacklistFilter
* @param string[] $excludedPaths
*
* @return iterable|SplFileInfo[]
*/
private static function retrieveDirectories(
stdClass $raw,
string $key,
string $basePath,
Closure $blacklistFilter
Closure $blacklistFilter,
array $excludedPaths
): iterable {
$directories = self::retrieveDirectoryPaths($raw, $key, $basePath);

if ([] !== $directories) {
return Finder::create()
$finder = Finder::create()
->files()
->filter($blacklistFilter)
->ignoreVCS(true)
->in($directories)
;

foreach ($excludedPaths as $excludedPath) {
$finder->notPath(preg_quote($excludedPath, '/'));
}

return $finder;
}

return [];
}

/**
* @param stdClass $raw
* @param string $key
* @param string $basePath
* @param Closure $blacklistFilter
* @param string[] $excludedPaths
* @param string[] $devPackages
*
* @return iterable[]|SplFileInfo[][]
Expand All @@ -588,10 +621,11 @@ private static function retrieveFilesFromFinders(
string $key,
string $basePath,
Closure $blacklistFilter,
array $excludedPaths,
array $devPackages
): array {
if (isset($raw->{$key})) {
return self::processFinders($raw->{$key}, $basePath, $blacklistFilter, $devPackages);
return self::processFinders($raw->{$key}, $basePath, $blacklistFilter, $excludedPaths, $devPackages);
}

return [];
Expand All @@ -601,6 +635,7 @@ private static function retrieveFilesFromFinders(
* @param array $findersConfig
* @param string $basePath
* @param Closure $blacklistFilter
* @param string[] $excludedPaths
* @param string[] $devPackages
*
* @return Finder[]|SplFileInfo[][]
Expand All @@ -609,10 +644,11 @@ private static function processFinders(
array $findersConfig,
string $basePath,
Closure $blacklistFilter,
array $excludedPaths,
array $devPackages
): array {
$processFinderConfig = function (stdClass $config) use ($basePath, $blacklistFilter, $devPackages) {
return self::processFinder($config, $basePath, $blacklistFilter, $devPackages);
$processFinderConfig = function (stdClass $config) use ($basePath, $blacklistFilter, $excludedPaths, $devPackages) {
return self::processFinder($config, $basePath, $blacklistFilter, $excludedPaths, $devPackages);
};

return array_map($processFinderConfig, $findersConfig);
Expand All @@ -622,12 +658,18 @@ private static function processFinders(
* @param stdClass $config
* @param string $basePath
* @param Closure $blacklistFilter
* @param string[] $excludedPaths
* @param string[] $devPackages
*
* @return Finder|SplFileInfo[]
*/
private static function processFinder(stdClass $config, string $basePath, Closure $blacklistFilter, array $devPackages): Finder
{
private static function processFinder(
stdClass $config,
string $basePath,
Closure $blacklistFilter,
array $excludedPaths,
array $devPackages
): Finder {
$finder = Finder::create()
->files()
->filter($blacklistFilter)
Expand All @@ -646,6 +688,10 @@ function (SplFileInfo $fileInfo) use ($devPackages): bool {
->ignoreVCS(true)
;

foreach ($excludedPaths as $excludedPath) {
$finder->notPath(preg_quote($excludedPath, '/'));
}

$normalizedConfig = (function (array $config, Finder $finder): array {
$normalizedConfig = [];

Expand Down Expand Up @@ -743,6 +789,7 @@ function (SplFileInfo $fileInfo) use ($devPackages): bool {
* @param string $basePath
* @param string $mainScriptPath
* @param Closure $blacklistFilter
* @param string[] $excludedPaths
* @param string[] $devPackages
*
* @return SplFileInfo[]
Expand All @@ -751,6 +798,7 @@ private static function retrieveAllFiles(
string $basePath,
string $mainScriptPath,
Closure $blacklistFilter,
array $excludedPaths,
array $devPackages
): array {
$relativeDevPackages = array_map(
Expand All @@ -769,6 +817,10 @@ function (string $packagePath) use ($basePath): string {
->ignoreVCS(true)
;

foreach ($excludedPaths as $excludedPath) {
$finder->notPath(preg_quote($excludedPath, '/'));
}

return array_filter(
array_unique(
array_map(
Expand All @@ -779,9 +831,7 @@ function (SplFileInfo $fileInfo): ?string {

return false !== $fileInfo->getRealPath() ? $fileInfo->getRealPath() : null;
},
iterator_to_array(
$finder
)
iterator_to_array($finder)
)
)
);
Expand Down
21 changes: 19 additions & 2 deletions tests/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ public function test_the_files_can_be_configured(): void
touch('file1');

mkdir('B');
touch('B/file1');
touch('B/fileB0');
touch('B/fileB1');

Expand Down Expand Up @@ -1256,6 +1257,23 @@ public function test_the_blacklist_input_is_normalized(): void
$this->assertSame($expected, $actual);
}

public function test_the_blacklist_input_may_refer_to_non_existent_paths(): void
{
$this->setConfig([
'blacklist' => [
'/nowhere',
],
]);

// Relative to the current working directory for readability
$expected = [
'box.json',
];
$actual = $this->normalizeConfigPaths($this->config->getFiles());

$this->assertSame($expected, $actual);
}

/**
* @dataProvider provideJsonValidNonStringArray
*
Expand Down Expand Up @@ -1705,15 +1723,14 @@ public function test_the_blacklist_setting_is_applied_to_all_the_files_found_in_
'B/fileB1',
'C/fileC0',
'C/fileC1',
'D/fileD0',
'D/fileD1',
'E/fileE0',
'E/fileE1',
];

$this->setConfig([
'blacklist' => [
'box.json',
'D',
'D/finder_excluded_file',
'E/finder_excluded_file',
],
Expand Down