/vendor/composer/composer/src/Composer/Repository/ArtifactRepository.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 150 lines · 112 code · 22 blank · 16 comment · 11 complexity · 5053b3a674e9dedf314ebd2d5b389817 MD5 · raw file

  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\Repository;
  12. use Composer\IO\IOInterface;
  13. use Composer\Json\JsonFile;
  14. use Composer\Package\Loader\ArrayLoader;
  15. /**
  16. * @author Serge Smertin <serg.smertin@gmail.com>
  17. */
  18. class ArtifactRepository extends ArrayRepository
  19. {
  20. /** @var LoaderInterface */
  21. protected $loader;
  22. protected $lookup;
  23. public function __construct(array $repoConfig, IOInterface $io)
  24. {
  25. if (!extension_loaded('zip')) {
  26. throw new \RuntimeException('The artifact repository requires PHP\'s zip extension');
  27. }
  28. $this->loader = new ArrayLoader();
  29. $this->lookup = $repoConfig['url'];
  30. $this->io = $io;
  31. }
  32. protected function initialize()
  33. {
  34. parent::initialize();
  35. $this->scanDirectory($this->lookup);
  36. }
  37. private function scanDirectory($path)
  38. {
  39. $io = $this->io;
  40. $directory = new \RecursiveDirectoryIterator($path);
  41. $iterator = new \RecursiveIteratorIterator($directory);
  42. $regex = new \RegexIterator($iterator, '/^.+\.(zip|phar)$/i');
  43. foreach ($regex as $file) {
  44. /* @var $file \SplFileInfo */
  45. if (!$file->isFile()) {
  46. continue;
  47. }
  48. $package = $this->getComposerInformation($file);
  49. if (!$package) {
  50. if ($io->isVerbose()) {
  51. $io->writeError("File <comment>{$file->getBasename()}</comment> doesn't seem to hold a package");
  52. }
  53. continue;
  54. }
  55. if ($io->isVerbose()) {
  56. $template = 'Found package <info>%s</info> (<comment>%s</comment>) in file <info>%s</info>';
  57. $io->writeError(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename()));
  58. }
  59. $this->addPackage($package);
  60. }
  61. }
  62. /**
  63. * Find a file by name, returning the one that has the shortest path.
  64. *
  65. * @param \ZipArchive $zip
  66. * @param $filename
  67. * @return bool|int
  68. */
  69. private function locateFile(\ZipArchive $zip, $filename)
  70. {
  71. $indexOfShortestMatch = false;
  72. $lengthOfShortestMatch = -1;
  73. for ($i = 0; $i < $zip->numFiles; $i++) {
  74. $stat = $zip->statIndex($i);
  75. if (strcmp(basename($stat['name']), $filename) === 0) {
  76. $directoryName = dirname($stat['name']);
  77. if ($directoryName == '.') {
  78. //if composer.json is in root directory
  79. //it has to be the one to use.
  80. return $i;
  81. }
  82. if (strpos($directoryName, '\\') !== false ||
  83. strpos($directoryName, '/') !== false) {
  84. //composer.json files below first directory are rejected
  85. continue;
  86. }
  87. $length = strlen($stat['name']);
  88. if ($indexOfShortestMatch == false || $length < $lengthOfShortestMatch) {
  89. //Check it's not a directory.
  90. $contents = $zip->getFromIndex($i);
  91. if ($contents !== false) {
  92. $indexOfShortestMatch = $i;
  93. $lengthOfShortestMatch = $length;
  94. }
  95. }
  96. }
  97. }
  98. return $indexOfShortestMatch;
  99. }
  100. private function getComposerInformation(\SplFileInfo $file)
  101. {
  102. $zip = new \ZipArchive();
  103. $zip->open($file->getPathname());
  104. if (0 == $zip->numFiles) {
  105. return false;
  106. }
  107. $foundFileIndex = $this->locateFile($zip, 'composer.json');
  108. if (false === $foundFileIndex) {
  109. return false;
  110. }
  111. $configurationFileName = $zip->getNameIndex($foundFileIndex);
  112. $composerFile = "zip://{$file->getPathname()}#$configurationFileName";
  113. $json = file_get_contents($composerFile);
  114. $package = JsonFile::parseJson($json, $composerFile);
  115. $package['dist'] = array(
  116. 'type' => 'zip',
  117. 'url' => $file->getPathname(),
  118. 'shasum' => sha1_file($file->getRealPath())
  119. );
  120. $package = $this->loader->load($package);
  121. return $package;
  122. }
  123. }