diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php new file mode 100644 index 000000000..5b15f54cf --- /dev/null +++ b/src/Composer/Downloader/DownloadManager.php @@ -0,0 +1,153 @@ + + * 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\Package\PackageInterface; +use Composer\Downloader\DownloaderInterface; + +/** + * Downloaders manager. + * + * @author Konstantin Kudryashov + */ +class DownloadManager +{ + private $preferSource = false; + private $downloaders = array(); + + /** + * Initializes download manager. + * + * @param Boolean $preferSource prefer downloading from source + */ + public function __construct($preferSource = false) + { + $this->preferSource = $preferSource; + } + + /** + * Makes downloader prefer source installation over the dist. + * + * @param Boolean $preferSource prefer downloading from source + */ + public function preferSource($preferSource = true) + { + $this->preferSource = $preferSource; + } + + /** + * Sets installer downloader for a specific installation type. + * + * @param string $type installation type + * @param DownloaderInterface $downloader downloader instance + */ + public function setDownloader($type, DownloaderInterface $downloader) + { + $this->downloaders[$type] = $downloader; + } + + /** + * Returns downloader for a specific installation type. + * + * @param string $type installation type + * + * @return DownloaderInterface + * + * @throws UnexpectedValueException if downloader for provided type is not registeterd + */ + public function getDownloader($type) + { + if (!isset($this->downloaders[$type])) { + throw new \UnexpectedValueException('Unknown source type: '.$type); + } + + return $this->downloaders[$type]; + } + + /** + * Downloads package into target dir. + * + * @param PackageInterface $package package instance + * @param string $targetDir target dir + * + * @return string downloader type (source/dist) + * + * @throws InvalidArgumentException if package have no urls to download from + */ + public function download(PackageInterface $package, $targetDir) + { + $sourceType = $package->getSourceType(); + $distType = $package->getDistType(); + + if (!($this->preferSource && $sourceType) && $distType) { + $downloader = $this->getDownloader($distType); + $downloader->download( + $package, $targetDir, $package->getDistUrl(), $package->getDistSha1Checksum() + ); + + return 'dist'; + } + + if ($sourceType) { + $downloader = $this->getDownloader($sourceType); + $downloader->download($package, $targetDir, $package->getSourceUrl()); + + return 'source'; + } + + throw new \InvalidArgumentException('Package should have dist or source specified'); + } + + /** + * Updates package from initial to target version. + * + * @param PackageInterface $initial initial package version + * @param PackageInterface $target target package version + * @param string $targetDir target dir + * @param string $type downloader type (source/dist) + * + * @throws InvalidArgumentException if initial package is not installed + */ + public function update(PackageInterface $initial, PackageInterface $target, $targetDir, $type) + { + if ('dist' === $type) { + $downloader = $this->getDownloader($initial->getDistType()); + $downloader->update($initial, $target, $targetDir); + } elseif ('source' === $type) { + $downloader = $this->getDownloader($initial->getSourceType()); + $downloader->update($initial, $target, $targetDir); + } else { + throw new \InvalidArgumentException('Package should have dist or source specified'); + } + } + + /** + * Removes package from target dir. + * + * @param PackageInterface $package package instance + * @param string $targetDir target dir + * @param string $type downloader type (source/dist) + */ + public function remove(PackageInterface $package, $targetDir, $type) + { + if ('dist' === $type) { + $downloader = $this->getDownloader($package->getDistType()); + $downloader->remove($package, $targetDir); + } elseif ('source' === $type) { + $downloader = $this->getDownloader($package->getSourceType()); + $downloader->remove($package, $targetDir); + } else { + throw new \InvalidArgumentException('Package should have dist or source specified'); + } + } +} diff --git a/tests/Composer/Test/Downloader/DownloadManagerTest.php b/tests/Composer/Test/Downloader/DownloadManagerTest.php new file mode 100644 index 000000000..efac5f0ba --- /dev/null +++ b/tests/Composer/Test/Downloader/DownloadManagerTest.php @@ -0,0 +1,352 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Downloader; + +use Composer\Downloader\DownloadManager; + +class DownloadManagerTest extends \PHPUnit_Framework_TestCase +{ + public function testSetGetDownloader() + { + $downloader = $this->createDownloaderMock(); + $manager = new DownloadManager(); + + $manager->setDownloader('test', $downloader); + $this->assertSame($downloader, $manager->getDownloader('test')); + + $this->setExpectedException('UnexpectedValueException'); + $manager->getDownloader('unregistered'); + } + + public function testFullPackageDownload() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('git')); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $package + ->expects($this->once()) + ->method('getDistUrl') + ->will($this->returnValue('dist_url')); + $package + ->expects($this->once()) + ->method('getDistSha1Checksum') + ->will($this->returnValue('sha1')); + + $pearDownloader = $this->createDownloaderMock(); + $pearDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'target_dir', 'dist_url', 'sha1'); + + $manager = new DownloadManager(); + $manager->setDownloader('pear', $pearDownloader); + + $manager->download($package, 'target_dir'); + } + + public function testBadPackageDownload() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue(null)); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue(null)); + + $manager = new DownloadManager(); + + $this->setExpectedException('InvalidArgumentException'); + $manager->download($package, 'target_dir'); + } + + public function testDistOnlyPackageDownload() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue(null)); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $package + ->expects($this->once()) + ->method('getDistUrl') + ->will($this->returnValue('dist_url')); + $package + ->expects($this->once()) + ->method('getDistSha1Checksum') + ->will($this->returnValue('sha1')); + + $pearDownloader = $this->createDownloaderMock(); + $pearDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'target_dir', 'dist_url', 'sha1'); + + $manager = new DownloadManager(); + $manager->setDownloader('pear', $pearDownloader); + + $manager->download($package, 'target_dir'); + } + + public function testSourceOnlyPackageDownload() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('git')); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue(null)); + + $package + ->expects($this->once()) + ->method('getSourceUrl') + ->will($this->returnValue('source_url')); + + $gitDownloader = $this->createDownloaderMock(); + $gitDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'vendor/pkg', 'source_url'); + + $manager = new DownloadManager(); + $manager->setDownloader('git', $gitDownloader); + + $manager->download($package, 'vendor/pkg'); + } + + public function testFullPackageDownloadWithSourcePreferred() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('git')); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $package + ->expects($this->once()) + ->method('getSourceUrl') + ->will($this->returnValue('source_url')); + + $gitDownloader = $this->createDownloaderMock(); + $gitDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'vendor/pkg', 'source_url'); + + $manager = new DownloadManager(); + $manager->setDownloader('git', $gitDownloader); + $manager->preferSource(); + + $manager->download($package, 'vendor/pkg'); + } + + public function testDistOnlyPackageDownloadWithSourcePreferred() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue(null)); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $package + ->expects($this->once()) + ->method('getDistUrl') + ->will($this->returnValue('dist_url')); + $package + ->expects($this->once()) + ->method('getDistSha1Checksum') + ->will($this->returnValue('sha1')); + + $pearDownloader = $this->createDownloaderMock(); + $pearDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'target_dir', 'dist_url', 'sha1'); + + $manager = new DownloadManager(); + $manager->setDownloader('pear', $pearDownloader); + $manager->preferSource(); + + $manager->download($package, 'target_dir'); + } + + public function testSourceOnlyPackageDownloadWithSourcePreferred() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('git')); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue(null)); + + $package + ->expects($this->once()) + ->method('getSourceUrl') + ->will($this->returnValue('source_url')); + + $gitDownloader = $this->createDownloaderMock(); + $gitDownloader + ->expects($this->once()) + ->method('download') + ->with($package, 'vendor/pkg', 'source_url'); + + $manager = new DownloadManager(); + $manager->setDownloader('git', $gitDownloader); + $manager->preferSource(); + + $manager->download($package, 'vendor/pkg'); + } + + public function testBadPackageDownloadWithSourcePreferred() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue(null)); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue(null)); + + $manager = new DownloadManager(); + $manager->preferSource(); + + $this->setExpectedException('InvalidArgumentException'); + $manager->download($package, 'target_dir'); + } + + public function testUpdateDist() + { + $initial = $this->createPackageMock(); + $initial + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $target = $this->createPackageMock(); + + $pearDownloader = $this->createDownloaderMock(); + $pearDownloader + ->expects($this->once()) + ->method('update') + ->with($initial, $target, 'vendor/bundles/FOS/UserBundle'); + + $manager = new DownloadManager(); + $manager->setDownloader('pear', $pearDownloader); + + $manager->update($initial, $target, 'vendor/bundles/FOS/UserBundle', 'dist'); + } + + public function testUpdateSource() + { + $initial = $this->createPackageMock(); + $initial + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('svn')); + + $target = $this->createPackageMock(); + + $svnDownloader = $this->createDownloaderMock(); + $svnDownloader + ->expects($this->once()) + ->method('update') + ->with($initial, $target, 'vendor/pkg'); + + $manager = new DownloadManager(); + $manager->setDownloader('svn', $svnDownloader); + + $manager->update($initial, $target, 'vendor/pkg', 'source'); + } + + public function testRemoveDist() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getDistType') + ->will($this->returnValue('pear')); + + $pearDownloader = $this->createDownloaderMock(); + $pearDownloader + ->expects($this->once()) + ->method('remove') + ->with($package, 'vendor/bundles/FOS/UserBundle'); + + $manager = new DownloadManager(); + $manager->setDownloader('pear', $pearDownloader); + + $manager->remove($package, 'vendor/bundles/FOS/UserBundle', 'dist'); + } + + public function testRemoveSource() + { + $package = $this->createPackageMock(); + $package + ->expects($this->once()) + ->method('getSourceType') + ->will($this->returnValue('svn')); + + $svnDownloader = $this->createDownloaderMock(); + $svnDownloader + ->expects($this->once()) + ->method('remove') + ->with($package, 'vendor/pkg'); + + $manager = new DownloadManager(); + $manager->setDownloader('svn', $svnDownloader); + + $manager->remove($package, 'vendor/pkg', 'source'); + } + + private function createDownloaderMock() + { + return $this->getMockBuilder('Composer\Downloader\DownloaderInterface') + ->getMock(); + } + + private function createPackageMock() + { + return $this->getMockBuilder('Composer\Package\PackageInterface') + ->getMock(); + } +}