ArchivableFilesFinderTest.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Test\Package\Archiver;
  12. use Composer\Package\Archiver\ArchivableFilesFinder;
  13. use Composer\Util\Filesystem;
  14. use Symfony\Component\Process\Process;
  15. class ArchivableFilesFinderTest extends \PHPUnit_Framework_TestCase
  16. {
  17. protected $sources;
  18. protected $finder;
  19. protected $fs;
  20. protected function setUp()
  21. {
  22. $fs = new Filesystem;
  23. $this->fs = $fs;
  24. $this->sources = $fs->normalizePath(
  25. realpath(sys_get_temp_dir()).'/composer_archiver_test'.uniqid(mt_rand(), true)
  26. );
  27. $fileTree = array(
  28. 'A/prefixA.foo',
  29. 'A/prefixB.foo',
  30. 'A/prefixC.foo',
  31. 'A/prefixD.foo',
  32. 'A/prefixE.foo',
  33. 'A/prefixF.foo',
  34. 'B/sub/prefixA.foo',
  35. 'B/sub/prefixB.foo',
  36. 'B/sub/prefixC.foo',
  37. 'B/sub/prefixD.foo',
  38. 'B/sub/prefixE.foo',
  39. 'B/sub/prefixF.foo',
  40. 'toplevelA.foo',
  41. 'toplevelB.foo',
  42. 'prefixA.foo',
  43. 'prefixB.foo',
  44. 'prefixC.foo',
  45. 'prefixD.foo',
  46. 'prefixE.foo',
  47. 'prefixF.foo',
  48. );
  49. foreach ($fileTree as $relativePath) {
  50. $path = $this->sources.'/'.$relativePath;
  51. $fs->ensureDirectoryExists(dirname($path));
  52. file_put_contents($path, '');
  53. }
  54. }
  55. protected function tearDown()
  56. {
  57. $fs = new Filesystem;
  58. $fs->removeDirectory($this->sources);
  59. }
  60. public function testManualExcludes()
  61. {
  62. $excludes = array(
  63. 'prefixB.foo',
  64. '!/prefixB.foo',
  65. '/prefixA.foo',
  66. 'prefixC.*',
  67. '!*/*/*/prefixC.foo'
  68. );
  69. $this->finder = new ArchivableFilesFinder($this->sources, $excludes);
  70. $this->assertArchivableFiles(array(
  71. '/A/prefixA.foo',
  72. '/A/prefixD.foo',
  73. '/A/prefixE.foo',
  74. '/A/prefixF.foo',
  75. '/B/sub/prefixA.foo',
  76. '/B/sub/prefixC.foo',
  77. '/B/sub/prefixD.foo',
  78. '/B/sub/prefixE.foo',
  79. '/B/sub/prefixF.foo',
  80. '/prefixB.foo',
  81. '/prefixD.foo',
  82. '/prefixE.foo',
  83. '/prefixF.foo',
  84. '/toplevelA.foo',
  85. '/toplevelB.foo',
  86. ));
  87. }
  88. public function testGitExcludes()
  89. {
  90. // Ensure that git is available for testing.
  91. if (!$this->getProcessAvailable('git')) {
  92. return $this->markTestSkipped('git is not available.');
  93. }
  94. file_put_contents($this->sources.'/.gitignore', implode("\n", array(
  95. '# gitignore rules with comments and blank lines',
  96. '',
  97. 'prefixE.foo',
  98. '# and more',
  99. '# comments',
  100. '',
  101. '!/prefixE.foo',
  102. '/prefixD.foo',
  103. 'prefixF.*',
  104. '!/*/*/prefixF.foo',
  105. '',
  106. 'refixD.foo',
  107. )));
  108. // git does not currently support negative git attributes
  109. file_put_contents($this->sources.'/.gitattributes', implode("\n", array(
  110. '',
  111. '# gitattributes rules with comments and blank lines',
  112. 'prefixB.foo export-ignore',
  113. //'!/prefixB.foo export-ignore',
  114. '/prefixA.foo export-ignore',
  115. 'prefixC.* export-ignore',
  116. //'!/*/*/prefixC.foo export-ignore'
  117. )));
  118. $this->finder = new ArchivableFilesFinder($this->sources, array());
  119. $this->assertArchivableFiles($this->getArchivedFiles('git init && '.
  120. 'git add .git* && '.
  121. 'git commit -m "ignore rules" && '.
  122. 'git add . && '.
  123. 'git commit -m "init" && '.
  124. 'git archive --format=zip --prefix=archive/ -o archive.zip HEAD'
  125. ));
  126. }
  127. public function testHgExcludes()
  128. {
  129. // Ensure that Mercurial is available for testing.
  130. if (!$this->getProcessAvailable('hg')) {
  131. return $this->markTestSkipped('Mercurial is not available.');
  132. }
  133. file_put_contents($this->sources.'/.hgignore', implode("\n", array(
  134. '# hgignore rules with comments, blank lines and syntax changes',
  135. '',
  136. 'pre*A.foo',
  137. 'prefixE.foo',
  138. '# and more',
  139. '# comments',
  140. '',
  141. '^prefixD.foo',
  142. 'syntax: glob',
  143. 'prefixF.*',
  144. 'B/*',
  145. )));
  146. $this->finder = new ArchivableFilesFinder($this->sources, array());
  147. $expectedFiles = $this->getArchivedFiles('hg init && '.
  148. 'hg add && '.
  149. 'hg commit -m "init" && '.
  150. 'hg archive archive.zip'
  151. );
  152. array_shift($expectedFiles); // remove .hg_archival.txt
  153. $this->assertArchivableFiles($expectedFiles);
  154. }
  155. protected function getArchivableFiles()
  156. {
  157. $files = array();
  158. foreach ($this->finder as $file) {
  159. if (!$file->isDir()) {
  160. $files[] = preg_replace('#^'.preg_quote($this->sources, '#').'#', '', $this->fs->normalizePath($file->getRealPath()));
  161. }
  162. }
  163. sort($files);
  164. return $files;
  165. }
  166. protected function getArchivedFiles($command)
  167. {
  168. $process = new Process($command, $this->sources);
  169. $process->run();
  170. $archive = new \PharData($this->sources.'/archive.zip');
  171. $iterator = new \RecursiveIteratorIterator($archive);
  172. $files = array();
  173. foreach ($iterator as $file) {
  174. $files[] = preg_replace('#^phar://'.preg_quote($this->sources, '#').'/archive\.zip/archive#', '', $this->fs->normalizePath($file));
  175. }
  176. unset($archive, $iterator, $file);
  177. unlink($this->sources.'/archive.zip');
  178. return $files;
  179. }
  180. protected function assertArchivableFiles($expectedFiles)
  181. {
  182. $actualFiles = $this->getArchivableFiles();
  183. $this->assertEquals($expectedFiles, $actualFiles);
  184. }
  185. /**
  186. * Check whether or not the given process is available.
  187. *
  188. * @param string $process The name of the binary to test.
  189. *
  190. * @return boolean True if the process is available, false otherwise.
  191. */
  192. protected function getProcessAvailable($process)
  193. {
  194. // Check if the command is found. The 127 exit code is returned when the
  195. // command is not found.
  196. $process = new Process($process);
  197. return $process->run() !== 127;
  198. }
  199. }