1
0
Fork 0

Fail over from source to dist and vice versa when downloads fail

Any RuntimeException descendent will be caught and cause another
download attempt using either source or dist depending on what was
attempted first.
pull/2753/head
Nils Adermann 2014-02-24 18:40:33 +01:00
parent aa74818fe0
commit 5ed18d9aa2
5 changed files with 123 additions and 35 deletions

View File

@ -14,6 +14,7 @@ namespace Composer\Downloader;
use Composer\Package\PackageInterface; use Composer\Package\PackageInterface;
use Composer\Downloader\DownloaderInterface; use Composer\Downloader\DownloaderInterface;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem; use Composer\Util\Filesystem;
/** /**
@ -23,6 +24,7 @@ use Composer\Util\Filesystem;
*/ */
class DownloadManager class DownloadManager
{ {
private $io;
private $preferDist = false; private $preferDist = false;
private $preferSource = false; private $preferSource = false;
private $filesystem; private $filesystem;
@ -31,11 +33,13 @@ class DownloadManager
/** /**
* Initializes download manager. * Initializes download manager.
* *
* @param IOInterface $io The Input Output Interface
* @param bool $preferSource prefer downloading from source * @param bool $preferSource prefer downloading from source
* @param Filesystem|null $filesystem custom Filesystem object * @param Filesystem|null $filesystem custom Filesystem object
*/ */
public function __construct($preferSource = false, Filesystem $filesystem = null) public function __construct(IOInterface $io, $preferSource = false, Filesystem $filesystem = null)
{ {
$this->io = $io;
$this->preferSource = $preferSource; $this->preferSource = $preferSource;
$this->filesystem = $filesystem ?: new Filesystem(); $this->filesystem = $filesystem ?: new Filesystem();
} }
@ -168,20 +172,45 @@ class DownloadManager
$sourceType = $package->getSourceType(); $sourceType = $package->getSourceType();
$distType = $package->getDistType(); $distType = $package->getDistType();
if ((!$package->isDev() || $this->preferDist || !$sourceType) && !($preferSource && $sourceType) && $distType) { $wantDist = !$package->isDev() || $this->preferDist || !$sourceType;
$package->setInstallationSource('dist'); $wantSource = $preferSource && $sourceType;
} elseif ($sourceType) {
$package->setInstallationSource('source'); $types = array();
} else { if ($sourceType) {
$types[] = 'source';
}
if ($distType) {
$types[] = 'dist';
}
if (empty($types)) {
throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified'); throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
} }
if ($wantDist && !$wantSource) {
$types = array_reverse($types);
}
$this->filesystem->ensureDirectoryExists($targetDir); $this->filesystem->ensureDirectoryExists($targetDir);
foreach ($types as $source) {
$package->setInstallationSource($source);
try {
$downloader = $this->getDownloaderForInstalledPackage($package); $downloader = $this->getDownloaderForInstalledPackage($package);
if ($downloader) { if ($downloader) {
$downloader->download($package, $targetDir); $downloader->download($package, $targetDir);
} }
break;
} catch (\RuntimeException $e) {
$this->io->write(
'<warning>Caught an exception while trying to download '.
$package->getPrettyString().
': '.
$e->getMessage().'</warning>'
);
continue;
}
}
} }
/** /**

View File

@ -344,7 +344,7 @@ class Factory
$cache = new Cache($io, $config->get('cache-files-dir'), 'a-z0-9_./'); $cache = new Cache($io, $config->get('cache-files-dir'), 'a-z0-9_./');
} }
$dm = new Downloader\DownloadManager(); $dm = new Downloader\DownloadManager($io);
switch ($config->get('preferred-install')) { switch ($config->get('preferred-install')) {
case 'dist': case 'dist':
$dm->setPreferDist(true); $dm->setPreferDist(true);

View File

@ -47,7 +47,8 @@ class ComposerTest extends TestCase
public function testSetGetDownloadManager() public function testSetGetDownloadManager()
{ {
$composer = new Composer(); $composer = new Composer();
$manager = $this->getMock('Composer\Downloader\DownloadManager'); $io = $this->getMock('Composer\IO\IOInterface');
$manager = $this->getMock('Composer\Downloader\DownloadManager', array(), array($io));
$composer->setDownloadManager($manager); $composer->setDownloadManager($manager);
$this->assertSame($manager, $composer->getDownloadManager()); $this->assertSame($manager, $composer->getDownloadManager());

View File

@ -17,16 +17,18 @@ use Composer\Downloader\DownloadManager;
class DownloadManagerTest extends \PHPUnit_Framework_TestCase class DownloadManagerTest extends \PHPUnit_Framework_TestCase
{ {
protected $filesystem; protected $filesystem;
protected $io;
public function setUp() public function setUp()
{ {
$this->filesystem = $this->getMock('Composer\Util\Filesystem'); $this->filesystem = $this->getMock('Composer\Util\Filesystem');
$this->io = $this->getMock('Composer\IO\IOInterface');
} }
public function testSetGetDownloader() public function testSetGetDownloader()
{ {
$downloader = $this->createDownloaderMock(); $downloader = $this->createDownloaderMock();
$manager = new DownloadManager(false, $this->filesystem); $manager = new DownloadManager($this->io, false, $this->filesystem);
$manager->setDownloader('test', $downloader); $manager->setDownloader('test', $downloader);
$this->assertSame($downloader, $manager->getDownloader('test')); $this->assertSame($downloader, $manager->getDownloader('test'));
@ -43,7 +45,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getInstallationSource') ->method('getInstallationSource')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$manager = new DownloadManager(false, $this->filesystem); $manager = new DownloadManager($this->io, false, $this->filesystem);
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
@ -69,7 +71,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('dist')); ->will($this->returnValue('dist'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloader')) ->setMethods(array('getDownloader'))
->getMock(); ->getMock();
@ -101,7 +103,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('source')); ->will($this->returnValue('source'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloader')) ->setMethods(array('getDownloader'))
->getMock(); ->getMock();
@ -135,7 +137,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('source')); ->will($this->returnValue('source'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloader')) ->setMethods(array('getDownloader'))
->getMock(); ->getMock();
@ -167,7 +169,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue('dist')); ->will($this->returnValue('dist'));
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloader')) ->setMethods(array('getDownloader'))
->getMock(); ->getMock();
@ -190,7 +192,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getType') ->method('getType')
->will($this->returnValue('metapackage')); ->will($this->returnValue('metapackage'));
$manager = new DownloadManager(false, $this->filesystem); $manager = new DownloadManager($this->io, false, $this->filesystem);
$this->assertNull($manager->getDownloaderForInstalledPackage($package)); $this->assertNull($manager->getDownloaderForInstalledPackage($package));
} }
@ -219,7 +221,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -231,6 +233,62 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
$manager->download($package, 'target_dir'); $manager->download($package, 'target_dir');
} }
public function testFullPackageDownloadFailover()
{
$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->any())
->method('getPrettyString')
->will($this->returnValue('prettyPackage'));
$package
->expects($this->at(3))
->method('setInstallationSource')
->with('dist');
$package
->expects($this->at(5))
->method('setInstallationSource')
->with('source');
$downloaderFail = $this->createDownloaderMock();
$downloaderFail
->expects($this->once())
->method('download')
->with($package, 'target_dir')
->will($this->throwException(new \RuntimeException("Foo")));
$downloaderSuccess = $this->createDownloaderMock();
$downloaderSuccess
->expects($this->once())
->method('download')
->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage'))
->getMock();
$manager
->expects($this->at(0))
->method('getDownloaderForInstalledPackage')
->with($package)
->will($this->returnValue($downloaderFail));
$manager
->expects($this->at(1))
->method('getDownloaderForInstalledPackage')
->with($package)
->will($this->returnValue($downloaderSuccess));
$manager->download($package, 'target_dir');
}
public function testBadPackageDownload() public function testBadPackageDownload()
{ {
$package = $this->createPackageMock(); $package = $this->createPackageMock();
@ -243,7 +301,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getDistType') ->method('getDistType')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$manager = new DownloadManager(false, $this->filesystem); $manager = new DownloadManager($this->io, false, $this->filesystem);
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
$manager->download($package, 'target_dir'); $manager->download($package, 'target_dir');
@ -273,7 +331,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -309,7 +367,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -339,7 +397,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with('source'); ->with('source');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -375,7 +433,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -412,7 +470,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -449,7 +507,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'target_dir'); ->with($package, 'target_dir');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -474,7 +532,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->method('getDistType') ->method('getDistType')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$manager = new DownloadManager(false, $this->filesystem); $manager = new DownloadManager($this->io, false, $this->filesystem);
$manager->setPreferSource(true); $manager->setPreferSource(true);
$this->setExpectedException('InvalidArgumentException'); $this->setExpectedException('InvalidArgumentException');
@ -510,7 +568,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, $target, 'vendor/bundles/FOS/UserBundle'); ->with($initial, $target, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -547,7 +605,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, 'vendor/bundles/FOS/UserBundle'); ->with($initial, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download')) ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock(); ->getMock();
$manager $manager
@ -588,7 +646,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, $target, 'vendor/pkg'); ->with($initial, $target, 'vendor/pkg');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download')) ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock(); ->getMock();
$manager $manager
@ -625,7 +683,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($initial, 'vendor/pkg'); ->with($initial, 'vendor/pkg');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage', 'download')) ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
->getMock(); ->getMock();
$manager $manager
@ -647,7 +705,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
$target = $this->createPackageMock(); $target = $this->createPackageMock();
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -670,7 +728,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
->with($package, 'vendor/bundles/FOS/UserBundle'); ->with($package, 'vendor/bundles/FOS/UserBundle');
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager
@ -687,7 +745,7 @@ class DownloadManagerTest extends \PHPUnit_Framework_TestCase
$package = $this->createPackageMock(); $package = $this->createPackageMock();
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager') $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array(false, $this->filesystem)) ->setConstructorArgs(array($this->io, false, $this->filesystem))
->setMethods(array('getDownloaderForInstalledPackage')) ->setMethods(array('getDownloaderForInstalledPackage'))
->getMock(); ->getMock();
$manager $manager

View File

@ -51,7 +51,7 @@ class InstallerTest extends TestCase
{ {
$io = $this->getMock('Composer\IO\IOInterface'); $io = $this->getMock('Composer\IO\IOInterface');
$downloadManager = $this->getMock('Composer\Downloader\DownloadManager'); $downloadManager = $this->getMock('Composer\Downloader\DownloadManager', array(), array($io));
$config = $this->getMock('Composer\Config'); $config = $this->getMock('Composer\Config');
$repositoryManager = new RepositoryManager($io, $config); $repositoryManager = new RepositoryManager($io, $config);