diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php new file mode 100644 index 000000000..07d418bed --- /dev/null +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -0,0 +1,99 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Downloader; + +use Composer\IO\IOInterface; +use Composer\Package\PackageInterface; +use Composer\Util\Filesystem; +use Composer\Util\RemoteFilesystem; + +/** + * Base downloader for archives + * + * @author Kirill chEbba Chebunin + * @author Jordi Boggiano + * @author François Pluchino + */ +abstract class ArchiveDownloader extends FileDownloader +{ + /** + * {@inheritDoc} + */ + public function download(PackageInterface $package, $path) + { + parent::download($package, $path); + + $fileName = $this->getFileName($package, $path); + $this->io->write(' Unpacking archive'); + $this->extract($fileName, $path); + + $this->io->write(' Cleaning up'); + unlink($fileName); + + // If we have only a one dir inside it suppose to be a package itself + $contentDir = glob($path . '/*'); + if (1 === count($contentDir)) { + $contentDir = $contentDir[0]; + + // Rename the content directory to avoid error when moving up + // a child folder with the same name + $temporaryName = md5(time().rand()); + rename($contentDir, $temporaryName); + $contentDir = $temporaryName; + + foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) { + if (trim(basename($file), '.')) { + rename($file, $path . '/' . basename($file)); + } + } + rmdir($contentDir); + } + + $this->io->write(''); + } + + /** + * {@inheritdoc} + */ + protected function getFileName(PackageInterface $package, $path) + { + return rtrim($path.'/'.md5($path.spl_object_hash($package)).'.'.pathinfo($package->getDistUrl(), PATHINFO_EXTENSION), '.'); + } + + /** + * {@inheritdoc} + */ + protected function processUrl($url) + { + if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) { + // bypass https for github if openssl is disabled + if (preg_match('{^https?://(github.com/[^/]+/[^/]+/(zip|tar)ball/[^/]+)$}i', $url, $match)) { + $url = 'http://nodeload.'.$match[1]; + } else { + throw new \RuntimeException('You must enable the openssl extension to download files via https'); + } + } + + return $url; + } + + /** + * Extract file to directory + * + * @param string $file Extracted file + * @param string $path Directory + * + * @throws \UnexpectedValueException If can not extract downloaded file to path + */ + abstract protected function extract($file, $path); +} diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 6a4d68103..39a7c4913 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -18,13 +18,13 @@ use Composer\Util\Filesystem; use Composer\Util\RemoteFilesystem; /** - * Base downloader for file packages + * Base downloader for files * * @author Kirill chEbba Chebunin * @author Jordi Boggiano * @author François Pluchino */ -abstract class FileDownloader implements DownloaderInterface +class FileDownloader implements DownloaderInterface { protected $io; @@ -63,18 +63,11 @@ abstract class FileDownloader implements DownloaderInterface } } - $fileName = rtrim($path.'/'.md5(time().rand()).'.'.pathinfo($url, PATHINFO_EXTENSION), '.'); + $fileName = $this->getFileName($package, $path); $this->io->write(" - Package " . $package->getName() . " (" . $package->getPrettyVersion() . ")"); - if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) { - // bypass https for github if openssl is disabled - if (preg_match('{^https?://(github.com/[^/]+/[^/]+/(zip|tar)ball/[^/]+)$}i', $url, $match)) { - $url = 'http://nodeload.'.$match[1]; - } else { - throw new \RuntimeException('You must enable the openssl extension to download files via https'); - } - } + $url = $this->processUrl($url); $rfs = new RemoteFilesystem($this->io); $rfs->copy($package->getSourceUrl(), $url, $fileName); @@ -86,32 +79,7 @@ abstract class FileDownloader implements DownloaderInterface } if ($checksum && hash_file('sha1', $fileName) !== $checksum) { - throw new \UnexpectedValueException('The checksum verification of the archive failed (downloaded from '.$url.')'); - } - - $this->io->write(' Unpacking archive'); - $this->extract($fileName, $path); - - $this->io->write(' Cleaning up'); - unlink($fileName); - - // If we have only a one dir inside it suppose to be a package itself - $contentDir = glob($path . '/*'); - if (1 === count($contentDir)) { - $contentDir = $contentDir[0]; - - // Rename the content directory to avoid error when moving up - // a child folder with the same name - $temporaryName = md5(time().rand()); - rename($contentDir, $temporaryName); - $contentDir = $temporaryName; - - foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) { - if (trim(basename($file), '.')) { - rename($file, $path . '/' . basename($file)); - } - } - rmdir($contentDir); + throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url.')'); } $this->io->write(''); @@ -122,8 +90,7 @@ abstract class FileDownloader implements DownloaderInterface */ public function update(PackageInterface $initial, PackageInterface $target, $path) { - $fs = new Filesystem(); - $fs->removeDirectory($path); + $this->remove($initial, $path); $this->download($target, $path); } @@ -137,12 +104,31 @@ abstract class FileDownloader implements DownloaderInterface } /** - * Extract file to directory + * Gets file name for specific package * - * @param string $file Extracted file - * @param string $path Directory - * - * @throws \UnexpectedValueException If can not extract downloaded file to path + * @param PackageInterface $package package instance + * @param string $path download path + * @return string file name */ - protected abstract function extract($file, $path); + protected function getFileName(PackageInterface $package, $path) + { + return $path.'/'.pathinfo($package->getDistUrl(), PATHINFO_BASENAME); + } + + /** + * Process the download url + * + * @param string $url download url + * @return string url + * + * @throws \RuntimeException If any problem with the url + */ + protected function processUrl($url) + { + if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) { + throw new \RuntimeException('You must enable the openssl extension to download files via https'); + } + + return $url; + } } diff --git a/src/Composer/Downloader/PharDownloader.php b/src/Composer/Downloader/PharDownloader.php index 83a38a4a3..d7b1fae46 100644 --- a/src/Composer/Downloader/PharDownloader.php +++ b/src/Composer/Downloader/PharDownloader.php @@ -19,7 +19,7 @@ use Composer\Package\PackageInterface; * * @author Kirill chEbba Chebunin */ -class PharDownloader extends FileDownloader +class PharDownloader extends ArchiveDownloader { /** * {@inheritDoc} diff --git a/src/Composer/Downloader/TarDownloader.php b/src/Composer/Downloader/TarDownloader.php index c239475f7..0429a4232 100644 --- a/src/Composer/Downloader/TarDownloader.php +++ b/src/Composer/Downloader/TarDownloader.php @@ -19,7 +19,7 @@ use Composer\Package\PackageInterface; * * @author Kirill chEbba Chebunin */ -class TarDownloader extends FileDownloader +class TarDownloader extends ArchiveDownloader { /** * {@inheritDoc} diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 7ae23e04e..3618fc07b 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -19,7 +19,7 @@ use Composer\IO\IOInterface; /** * @author Jordi Boggiano */ -class ZipDownloader extends FileDownloader +class ZipDownloader extends ArchiveDownloader { protected $process; diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index cf70c4c74..44b97fcf2 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -141,13 +141,14 @@ class Factory protected function createDownloadManager(IOInterface $io) { $dm = new Downloader\DownloadManager(); - $dm->setDownloader('git', new Downloader\GitDownloader($io)); - $dm->setDownloader('svn', new Downloader\SvnDownloader($io)); + $dm->setDownloader('git', new Downloader\GitDownloader($io)); + $dm->setDownloader('svn', new Downloader\SvnDownloader($io)); $dm->setDownloader('hg', new Downloader\HgDownloader($io)); $dm->setDownloader('pear', new Downloader\PearDownloader($io)); - $dm->setDownloader('zip', new Downloader\ZipDownloader($io)); - $dm->setDownloader('tar', new Downloader\TarDownloader($io)); - $dm->setDownloader('phar', new Downloader\PharDownloader($io)); + $dm->setDownloader('zip', new Downloader\ZipDownloader($io)); + $dm->setDownloader('tar', new Downloader\TarDownloader($io)); + $dm->setDownloader('phar', new Downloader\PharDownloader($io)); + $dm->setDownloader('file', new Downloader\FileDownloader($io)); return $dm; }