Browse Source

DownloadManager implemented

everzet 13 years ago
parent
commit
cde9531e4d

+ 153 - 0
src/Composer/Downloader/DownloadManager.php

@@ -0,0 +1,153 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * 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 <ever.zet@gmail.com>
+ */
+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');
+        }
+    }
+}

+ 352 - 0
tests/Composer/Test/Downloader/DownloadManagerTest.php

@@ -0,0 +1,352 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * 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();
+    }
+}