1
0
Fork 0

Get rid of gitignore/hgignore handling (fixes #7358), Add support for -export-ignore (fixes #9153)

pull/10309/head
Jordi Boggiano 2021-11-24 22:44:03 +01:00
parent cc3b53bc2e
commit 126f95a8d7
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
6 changed files with 30 additions and 242 deletions

View File

@ -49,7 +49,6 @@ class ArchivableFilesFinder extends \FilterIterator
$filters = array();
} else {
$filters = array(
new HgExcludeFilter($sources),
new GitExcludeFilter($sources),
new ComposerExcludeFilter($sources, $excludes),
);

View File

@ -13,7 +13,7 @@
namespace Composer\Package\Archiver;
/**
* An exclude filter that processes gitignore and gitattributes
* An exclude filter that processes gitattributes
*
* It respects export-ignore git attributes
*
@ -22,7 +22,7 @@ namespace Composer\Package\Archiver;
class GitExcludeFilter extends BaseExcludeFilter
{
/**
* Parses .gitignore and .gitattributes files if they exist
* Parses .gitattributes if it exists
*
* @param string $sourcePath
*/
@ -30,12 +30,6 @@ class GitExcludeFilter extends BaseExcludeFilter
{
parent::__construct($sourcePath);
if (file_exists($sourcePath.'/.gitignore')) {
$this->excludePatterns = $this->parseLines(
file($sourcePath.'/.gitignore'),
array($this, 'parseGitIgnoreLine')
);
}
if (file_exists($sourcePath.'/.gitattributes')) {
$this->excludePatterns = array_merge(
$this->excludePatterns,
@ -47,18 +41,6 @@ class GitExcludeFilter extends BaseExcludeFilter
}
}
/**
* Callback line parser which process gitignore lines
*
* @param string $line A line from .gitignore
*
* @return array{0: string, 1: bool, 2: bool} An exclude pattern for filter()
*/
public function parseGitIgnoreLine($line)
{
return $this->generatePattern($line);
}
/**
* Callback parser which finds export-ignore rules in git attribute lines
*
@ -74,6 +56,10 @@ class GitExcludeFilter extends BaseExcludeFilter
return $this->generatePattern($parts[0]);
}
if (count($parts) == 2 && $parts[1] === '-export-ignore') {
return $this->generatePattern('!'.$parts[0]);
}
return null;
}
}

View File

@ -1,107 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Package\Archiver;
use Symfony\Component\Finder;
/**
* An exclude filter that processes hgignore files
*
* @author Nils Adermann <naderman@naderman.de>
*/
class HgExcludeFilter extends BaseExcludeFilter
{
const HG_IGNORE_REGEX = 1;
const HG_IGNORE_GLOB = 2;
/**
* Either HG_IGNORE_REGEX or HG_IGNORE_GLOB
* @var int
*/
protected $patternMode;
/**
* Parses .hgignore file if it exist
*
* @param string $sourcePath
*/
public function __construct($sourcePath)
{
parent::__construct($sourcePath);
$this->patternMode = self::HG_IGNORE_REGEX;
if (file_exists($sourcePath.'/.hgignore')) {
$this->excludePatterns = $this->parseLines(
file($sourcePath.'/.hgignore'),
array($this, 'parseHgIgnoreLine')
);
}
}
/**
* Callback line parser which process hgignore lines
*
* @param string $line A line from .hgignore
*
* @return array{0: string, 1: bool, 2: bool}|null An exclude pattern for filter()
*/
public function parseHgIgnoreLine($line)
{
if (preg_match('#^syntax\s*:\s*(glob|regexp)$#', $line, $matches)) {
if ($matches[1] === 'glob') {
$this->patternMode = self::HG_IGNORE_GLOB;
} else {
$this->patternMode = self::HG_IGNORE_REGEX;
}
return null;
}
if ($this->patternMode == self::HG_IGNORE_GLOB) {
return $this->patternFromGlob($line);
}
return $this->patternFromRegex($line);
}
/**
* Generates an exclude pattern for filter() from a hg glob expression
*
* @param string $line A line from .hgignore in glob mode
*
* @return array{0: string, 1: bool, 2: bool} An exclude pattern for filter()
*/
protected function patternFromGlob($line)
{
$pattern = '#'.substr(Finder\Glob::toRegex($line), 2, -1).'#';
$pattern = str_replace('[^/]*', '.*', $pattern);
return array($pattern, false, true);
}
/**
* Generates an exclude pattern for filter() from a hg regexp expression
*
* @param string $line A line from .hgignore in regexp mode
*
* @return array{0: string, 1: bool, 2: bool} An exclude pattern for filter()
*/
public function patternFromRegex($line)
{
// WTF need to escape the delimiter safely
$pattern = '#'.preg_replace('/((?:\\\\\\\\)*)(\\\\?)#/', '\1\2\2\\#', $line).'#';
return array($pattern, false, true);
}
}

View File

@ -156,40 +156,33 @@ class ArchivableFilesFinderTest extends TestCase
{
$this->skipIfNotExecutable('git');
file_put_contents($this->sources.'/.gitignore', implode("\n", array(
'# gitignore rules with comments and blank lines',
'',
'prefixE.foo',
'# and more',
'# comments',
'',
'!/prefixE.foo',
'/prefixD.foo',
'prefixF.*',
'!/*/*/prefixF.foo',
'',
'refixD.foo',
'/C',
'D/prefixA',
'E',
'F/',
'G/*',
'H/**',
'J/',
'parameters.yml',
'\!important!.txt',
'\#*',
)));
// git does not currently support negative git attributes
file_put_contents($this->sources.'/.gitattributes', implode("\n", array(
'',
'# gitattributes rules with comments and blank lines',
'prefixB.foo export-ignore',
//'!/prefixB.foo export-ignore',
'/prefixA.foo export-ignore',
'prefixC.* export-ignore',
//'!/*/*/prefixC.foo export-ignore',
'',
'prefixE.foo export-ignore',
'# and more',
'# comments',
'',
'/prefixE.foo -export-ignore',
'/prefixD.foo export-ignore',
'prefixF.* export-ignore',
'/*/*/prefixF.foo -export-ignore',
'',
'refixD.foo export-ignore',
'/C export-ignore',
'D/prefixA export-ignore',
'E export-ignore',
'F/ export-ignore',
'G/* export-ignore',
'H/** export-ignore',
'J/ export-ignore',
'parameters.yml export-ignore',
'\!important!.txt export-ignore',
'\#* export-ignore',
)));
$this->finder = new ArchivableFilesFinder($this->sources, array());
@ -207,46 +200,6 @@ class ArchivableFilesFinderTest extends TestCase
));
}
public function testHgExcludes()
{
$this->skipIfNotExecutable('hg');
file_put_contents($this->sources.'/.hgignore', implode("\n", array(
'# hgignore rules with comments, blank lines and syntax changes',
'',
'pre*A.foo',
'prefixE.foo',
'# and more',
'# comments',
'',
'^prefixD.foo',
'D/prefixA',
'parameters.yml',
'\!important!.txt',
'E',
'F/',
'syntax: glob',
'prefixF.*',
'B/*',
'H/**',
)));
$this->finder = new ArchivableFilesFinder($this->sources, array());
$expectedFiles = $this->getArchivedFiles(
'hg init && '.
'hg add && '.
'hg commit -m "init" && '.
'hg archive archive.zip'
);
// Remove .hg_archival.txt from the expectedFiles
$archiveKey = array_search('/.hg_archival.txt', $expectedFiles);
array_splice($expectedFiles, $archiveKey, 1);
$this->assertArchivableFiles($expectedFiles);
}
public function testSkipExcludes()
{
$excludes = array(

View File

@ -27,14 +27,14 @@ class GitExcludeFilterTest extends TestCase
{
$filter = new GitExcludeFilter('/');
$this->assertEquals($expected, $filter->parseGitIgnoreLine($ignore));
$this->assertEquals($expected, $filter->parseGitAttributesLine($ignore));
}
public function providePatterns()
{
return array(
array('app/config/parameters.yml', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', false, false)),
array('!app/config/parameters.yml', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', true, false)),
array('app/config/parameters.yml export-ignore', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', false, false)),
array('app/config/parameters.yml -export-ignore', array('{(?=[^\.])app/(?=[^\.])config/(?=[^\.])parameters\.yml(?=$|/)}', true, false)),
);
}
}

View File

@ -1,43 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Test\Package\Archiver;
use Composer\Package\Archiver\HgExcludeFilter;
use Composer\Test\TestCase;
class HgExcludeFilterTest extends TestCase
{
/**
* @dataProvider providePatterns
*
* @param string $ignore
* @param mixed[] $expected
*/
public function testPatternEscape($ignore, $expected)
{
$filter = new HgExcludeFilter('/');
$this->assertEquals($expected, $filter->patternFromRegex($ignore));
}
public function providePatterns()
{
return array(
array('.#', array('#.\\##', false, true)),
array('.\\#', array('#.\\\\\\##', false, true)),
array('\\.#', array('#\\.\\##', false, true)),
array('\\\\.\\\\\\\\#', array('#\\\\.\\\\\\\\\\##', false, true)),
array('.\\\\\\\\\\#', array('#.\\\\\\\\\\\\\\##', false, true)),
);
}
}