ArchiveManager.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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\Package\Archiver;
  12. use Composer\Downloader\DownloadManager;
  13. use Composer\Package\PackageInterface;
  14. use Composer\Package\RootPackage;
  15. use Composer\Util\Filesystem;
  16. /**
  17. * @author Matthieu Moquet <matthieu@moquet.net>
  18. * @author Till Klampaeckel <till@php.net>
  19. */
  20. class ArchiveManager
  21. {
  22. protected $downloadManager;
  23. protected $archivers = array();
  24. /**
  25. * @var bool
  26. */
  27. protected $overwriteFiles = true;
  28. /**
  29. * @param DownloadManager $downloadManager A manager used to download package sources
  30. */
  31. public function __construct(DownloadManager $downloadManager)
  32. {
  33. $this->downloadManager = $downloadManager;
  34. }
  35. /**
  36. * @param ArchiverInterface $archiver
  37. */
  38. public function addArchiver(ArchiverInterface $archiver)
  39. {
  40. $this->archivers[] = $archiver;
  41. }
  42. /**
  43. * Set whether existing archives should be overwritten
  44. *
  45. * @param bool $overwriteFiles New setting
  46. *
  47. * @return $this
  48. */
  49. public function setOverwriteFiles($overwriteFiles)
  50. {
  51. $this->overwriteFiles = $overwriteFiles;
  52. return $this;
  53. }
  54. /**
  55. * Generate a distinct filename for a particular version of a package.
  56. *
  57. * @param PackageInterface $package The package to get a name for
  58. *
  59. * @return string A filename without an extension
  60. */
  61. public function getPackageFilename(PackageInterface $package)
  62. {
  63. $nameParts = array(preg_replace('#[^a-z0-9-_.]#i', '-', $package->getName()));
  64. if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) {
  65. $nameParts = array_merge($nameParts, array($package->getDistReference(), $package->getDistType()));
  66. } else {
  67. $nameParts = array_merge($nameParts, array($package->getPrettyVersion(), $package->getDistReference()));
  68. }
  69. if ($package->getSourceReference()) {
  70. $nameParts[] = substr(sha1($package->getSourceReference()), 0, 6);
  71. }
  72. return implode('-', array_filter($nameParts, function ($p) {
  73. return !empty($p);
  74. }));
  75. }
  76. /**
  77. * Create an archive of the specified package.
  78. *
  79. * @param PackageInterface $package The package to archive
  80. * @param string $format The format of the archive (zip, tar, ...)
  81. * @param string $targetDir The diretory where to build the archive
  82. * @throws \InvalidArgumentException
  83. * @throws \RuntimeException
  84. * @return string The path of the created archive
  85. */
  86. public function archive(PackageInterface $package, $format, $targetDir)
  87. {
  88. if (empty($format)) {
  89. throw new \InvalidArgumentException('Format must be specified');
  90. }
  91. // Search for the most appropriate archiver
  92. $usableArchiver = null;
  93. foreach ($this->archivers as $archiver) {
  94. if ($archiver->supports($format, $package->getSourceType())) {
  95. $usableArchiver = $archiver;
  96. break;
  97. }
  98. }
  99. // Checks the format/source type are supported before downloading the package
  100. if (null === $usableArchiver) {
  101. throw new \RuntimeException(sprintf('No archiver found to support %s format', $format));
  102. }
  103. $filesystem = new Filesystem();
  104. $packageName = $this->getPackageFilename($package);
  105. // Archive filename
  106. $filesystem->ensureDirectoryExists($targetDir);
  107. $target = realpath($targetDir).'/'.$packageName.'.'.$format;
  108. $filesystem->ensureDirectoryExists(dirname($target));
  109. if (!$this->overwriteFiles && file_exists($target)) {
  110. return $target;
  111. }
  112. if ($package instanceof RootPackage) {
  113. $sourcePath = realpath('.');
  114. } else {
  115. // Directory used to download the sources
  116. $sourcePath = sys_get_temp_dir().'/composer_archiver/'.$packageName;
  117. $filesystem->ensureDirectoryExists($sourcePath);
  118. // Download sources
  119. $this->downloadManager->download($package, $sourcePath);
  120. }
  121. // Create the archive
  122. $archivePath = $usableArchiver->archive($sourcePath, $target, $format, $package->getArchiveExcludes());
  123. // cleanup temporary download
  124. if (!$package instanceof RootPackage) {
  125. $filesystem->removeDirectory($sourcePath);
  126. }
  127. return $archivePath;
  128. }
  129. }