Skip to content

Commit

Permalink
Cleaner: improved matchMask()
Browse files Browse the repository at this point in the history
  • Loading branch information
janpecha committed Sep 3, 2018
1 parent 185f21d commit 9be5fbd
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 15 deletions.
104 changes: 89 additions & 15 deletions src/ComposerCleaner/Cleaner.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Cleaner
private static $allowedComposerTypes = [null, 'library', 'composer-plugin'];

/** @var string[] */
private static $alwaysIgnore = ['composer.json', 'license*', 'LICENSE*'];
private static $alwaysIgnore = ['/composer.json', '/license*', '/LICENSE*'];


public function __construct(IOInterface $io, Filesystem $fileSystem)
Expand Down Expand Up @@ -87,25 +87,73 @@ private function processPackage($packageDir, array $ignoreFiles)
}
}

$toIgnore = [];

foreach ($this->getSources($data) as $source) {
$dir = strstr(ltrim(ltrim($source, '.'), '/') . '/', '/', true);
$ignoreFiles[] = $dir;
$dir = '/' . strstr(ltrim(ltrim($source, '.'), '/') . '/', '/', true);

if (is_dir($packageDir . $dir)) {
$dir .= '/*';
}

$toIgnore[] = $dir;
}

if (!$ignoreFiles || self::matchMask('', $ignoreFiles)) {
$toIgnore = array_merge($toIgnore, $ignoreFiles);

if (!$toIgnore || self::matchMask('', $toIgnore)) {
return;
}

$ignoreFiles = array_merge($ignoreFiles, self::$alwaysIgnore);
$toIgnore = array_merge($toIgnore, self::$alwaysIgnore);

foreach (new FilesystemIterator($packageDir) as $path) {
$fileName = $path->getFileName();
if (!self::matchMask($fileName, $ignoreFiles)) {
$this->io->write("Composer cleaner: Removing $path", true, IOInterface::VERBOSE);
$this->fileSystem->remove($path);
$this->removedCount++;
foreach ($this->collectPaths($packageDir, $toIgnore) as $path) {
$this->io->write("Composer cleaner: Removing $path", true, IOInterface::VERBOSE);
$this->fileSystem->remove($path);
$this->removedCount++;
}
}


/**
* @param string
* @param string[]
* @param string
* @return string[]|bool
*/
private function collectPaths($directory, $ignorePaths, $subdir = '')
{
$list = [];
$iterator = dir($directory . $subdir);
$removeAll = true;
while (($entry = $iterator->read()) !== false) {
$path = "$directory$subdir/$entry";
$short = "$subdir/$entry";

if ($entry == '.' || $entry == '..') {
continue;

} elseif (self::matchMask($short, $ignorePaths, is_dir($path))) {
$removeAll = false;
continue;

} elseif (is_dir($path)) {
$removeChildren = $this->collectPaths($directory, $ignorePaths, $short);

if ($removeChildren === true) {
$list[$short . '/'] = $path;

} else {
$list += $removeChildren;
$removeAll = false;
}

} elseif (is_file($path)) {
$list[$short] = $path;
}
}
$iterator->close();
return ($subdir !== '' && $removeAll) ? true : $list;
}


Expand All @@ -114,14 +162,40 @@ private function processPackage($packageDir, array $ignoreFiles)
* @param string[]
* @return bool
*/
public static function matchMask($fileName, array $patterns)
public static function matchMask($fileName, array $patterns, $isDir = false)
{
$res = false;
$path = explode('/', ltrim($fileName, '/'));
foreach ($patterns as $pattern) {
if (fnmatch($pattern, $fileName)) {
return true;
$pattern = strtr($pattern, '\\', '/');
if ($neg = substr($pattern, 0, 1) === '!') {
$pattern = substr($pattern, 1);
}

if (strpos($pattern, '/') === false) { // no slash means base name
if (fnmatch($pattern, end($path), FNM_CASEFOLD)) {
$res = !$neg;
}
continue;

} elseif (substr($pattern, -1) === '/') { // trailing slash means directory
$pattern = trim($pattern, '/');
if (!$isDir && count($path) <= count(explode('/', $pattern))) {
continue;
}
}

$parts = explode('/', ltrim($pattern, '/'));

if (fnmatch(
implode('/', $neg && $isDir ? array_slice($parts, 0, count($path)) : $parts),
implode('/', array_slice($path, 0, count($parts))),
FNM_CASEFOLD | FNM_PATHNAME
)) {
$res = !$neg;
}
}
return false;
return $res;
}


Expand Down
36 changes: 36 additions & 0 deletions tests/Cleaner.clean.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

require __DIR__ . '/bootstrap.php';

use Tester\Assert;

$io = new IOInterface;
$cleaner = new DG\ComposerCleaner\Cleaner($io, new Filesystem);
$vendorDir = __DIR__ . '/fixtures/vendor';

$cleaner->clean($vendorDir, [
'mpdf/mpdf' => [
'data/mpdf.css',
'!src/QrCode/data/',
'ttfonts/DejaVuSans.txt',
],
]);

$toRemove = [];

foreach ($io->getLog() as $log) {
if (isset($log[1][0]) && substr($log[1][0], 18, 8) === 'Removing') {
$toRemove[] = $log[1][0];
}
}

sort($toRemove, SORT_STRING);

Assert::same([
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/.github',
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/CHANGELOG.md',
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/data/lang2fonts.css',
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/src/QrCode/data',
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/ttfonts/Arial.txt',
'Composer cleaner: Removing ' . $vendorDir . '/mpdf/mpdf/ttfonts/license.txt',
], $toRemove);
Empty file.
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions tests/fixtures/vendor/mpdf/mpdf/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "mpdf/mpdf",
"type": "library",
"autoload": {
"psr-4": {
"Mpdf\\": "src/"
}
}
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
2 changes: 2 additions & 0 deletions tests/php-unix.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[PHP]
extension=json.so

0 comments on commit 9be5fbd

Please sign in to comment.