diff --git a/src/Composer/Command/ArchiveCommand.php b/src/Composer/Command/ArchiveCommand.php
index f893ed679..e26aa59a1 100644
--- a/src/Composer/Command/ArchiveCommand.php
+++ b/src/Composer/Command/ArchiveCommand.php
@@ -22,6 +22,7 @@ use Composer\Script\ScriptEvents;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Util\Filesystem;
+use Composer\Util\Loop;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -104,8 +105,9 @@ EOT
$archiveManager = $composer->getArchiveManager();
} else {
$factory = new Factory;
- $downloadManager = $factory->createDownloadManager($io, $config, $factory->createHttpDownloader($io, $config));
- $archiveManager = $factory->createArchiveManager($config, $downloadManager);
+ $httpDownloader = $factory->createHttpDownloader($io, $config);
+ $downloadManager = $factory->createDownloadManager($io, $config, $httpDownloader);
+ $archiveManager = $factory->createArchiveManager($config, $downloadManager, new Loop($httpDownloader));
}
if ($packageName) {
diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php
index a1c364539..e165649a6 100644
--- a/src/Composer/Command/CreateProjectCommand.php
+++ b/src/Composer/Command/CreateProjectCommand.php
@@ -38,6 +38,7 @@ use Symfony\Component\Finder\Finder;
use Composer\Json\JsonFile;
use Composer\Config\JsonConfigSource;
use Composer\Util\Filesystem;
+use Composer\Util\Loop;
use Composer\Package\Version\VersionParser;
/**
@@ -345,15 +346,18 @@ EOT
$package = $package->getAliasOf();
}
- $dm = $this->createDownloadManager($io, $config);
+ $factory = new Factory();
+
+ $httpDownloader = $factory->createHttpDownloader($io, $config);
+ $dm = $factory->createDownloadManager($io, $config, $httpDownloader);
$dm->setPreferSource($preferSource)
->setPreferDist($preferDist)
->setOutputProgress(!$noProgress);
$projectInstaller = new ProjectInstaller($directory, $dm);
- $im = $this->createInstallationManager();
+ $im = $factory->createInstallationManager(new Loop($httpDownloader));
$im->addInstaller($projectInstaller);
- $im->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package));
+ $im->execute(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package));
$im->notifyInstalls($io);
// collect suggestions
@@ -369,16 +373,4 @@ EOT
return $installedFromVcs;
}
-
- protected function createDownloadManager(IOInterface $io, Config $config)
- {
- $factory = new Factory();
-
- return $factory->createDownloadManager($io, $config, $factory->createHttpDownloader($io, $config));
- }
-
- protected function createInstallationManager()
- {
- return new InstallationManager();
- }
}
diff --git a/src/Composer/Command/StatusCommand.php b/src/Composer/Command/StatusCommand.php
index 3e46b7fa0..06fc7638b 100644
--- a/src/Composer/Command/StatusCommand.php
+++ b/src/Composer/Command/StatusCommand.php
@@ -89,7 +89,7 @@ EOT
// list packages
foreach ($installedRepo->getCanonicalPackages() as $package) {
- $downloader = $dm->getDownloaderForInstalledPackage($package);
+ $downloader = $dm->getDownloaderForPackage($package);
$targetDir = $im->getInstallPath($package);
if ($downloader instanceof ChangeReportInterface) {
diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php
index d041a7f88..3c53a086e 100644
--- a/src/Composer/Downloader/ArchiveDownloader.php
+++ b/src/Composer/Downloader/ArchiveDownloader.php
@@ -30,33 +30,50 @@ abstract class ArchiveDownloader extends FileDownloader
* @throws \RuntimeException
* @throws \UnexpectedValueException
*/
- public function download(PackageInterface $package, $path, $output = true)
+ public function install(PackageInterface $package, $path, $output = true)
{
- $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
- $retries = 3;
- while ($retries--) {
- $fileName = parent::download($package, $path, $output);
+ if ($output) {
+ $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
+ }
- if ($output) {
- $this->io->writeError(' Extracting archive', false, IOInterface::VERBOSE);
+ $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
+ $fileName = $this->getFileName($package, $path);
+
+ if ($output) {
+ $this->io->writeError(' Extracting archive', true, IOInterface::VERBOSE);
+ }
+
+ try {
+ $this->filesystem->ensureDirectoryExists($temporaryDir);
+ try {
+ $this->extract($package, $fileName, $temporaryDir);
+ } catch (\Exception $e) {
+ // remove cache if the file was corrupted
+ parent::clearLastCacheWrite($package);
+ throw $e;
}
- try {
- $this->filesystem->ensureDirectoryExists($temporaryDir);
- try {
- $this->extract($fileName, $temporaryDir);
- } catch (\Exception $e) {
- // remove cache if the file was corrupted
- parent::clearLastCacheWrite($package);
- throw $e;
+ $this->filesystem->unlink($fileName);
+
+ $renameAsOne = false;
+ if (!file_exists($path) || ($this->filesystem->isDirEmpty($path) && $this->filesystem->removeDirectory($path))) {
+ $renameAsOne = true;
+ }
+
+ $contentDir = $this->getFolderContent($temporaryDir);
+ $singleDirAtTopLevel = 1 === count($contentDir) && is_dir(reset($contentDir));
+
+ if ($renameAsOne) {
+ // if the target $path is clear, we can rename the whole package in one go instead of looping over the contents
+ if ($singleDirAtTopLevel) {
+ $extractedDir = (string) reset($contentDir);
+ } else {
+ $extractedDir = $temporaryDir;
}
-
- $this->filesystem->unlink($fileName);
-
- $contentDir = $this->getFolderContent($temporaryDir);
-
+ $this->filesystem->rename($extractedDir, $path);
+ } else {
// only one dir in the archive, extract its contents out of it
- if (1 === count($contentDir) && is_dir(reset($contentDir))) {
+ if ($singleDirAtTopLevel) {
$contentDir = $this->getFolderContent((string) reset($contentDir));
}
@@ -65,35 +82,24 @@ abstract class ArchiveDownloader extends FileDownloader
$file = (string) $file;
$this->filesystem->rename($file, $path . '/' . basename($file));
}
-
- $this->filesystem->removeDirectory($temporaryDir);
- if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir').'/composer/')) {
- $this->filesystem->removeDirectory($this->config->get('vendor-dir').'/composer/');
- }
- if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir'))) {
- $this->filesystem->removeDirectory($this->config->get('vendor-dir'));
- }
- } catch (\Exception $e) {
- // clean up
- $this->filesystem->removeDirectory($path);
- $this->filesystem->removeDirectory($temporaryDir);
-
- // retry downloading if we have an invalid zip file
- if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) {
- $this->io->writeError('');
- if ($this->io->isDebug()) {
- $this->io->writeError(' Invalid zip file ('.$e->getMessage().'), retrying...');
- } else {
- $this->io->writeError(' Invalid zip file, retrying...');
- }
- usleep(500000);
- continue;
- }
-
- throw $e;
}
- break;
+ $this->filesystem->removeDirectory($temporaryDir);
+ if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir').'/composer/')) {
+ $this->filesystem->removeDirectory($this->config->get('vendor-dir').'/composer/');
+ }
+ if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir'))) {
+ $this->filesystem->removeDirectory($this->config->get('vendor-dir'));
+ }
+ } catch (\Exception $e) {
+ // clean up
+ $this->filesystem->removeDirectory($path);
+ $this->filesystem->removeDirectory($temporaryDir);
+ if (file_exists($fileName)) {
+ $this->filesystem->unlink($fileName);
+ }
+
+ throw $e;
}
}
@@ -102,7 +108,7 @@ abstract class ArchiveDownloader extends FileDownloader
*/
protected function getFileName(PackageInterface $package, $path)
{
- return rtrim($path.'/'.md5($path.spl_object_hash($package)).'.'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_EXTENSION), '.');
+ return rtrim($path.'_'.md5($path.spl_object_hash($package)).'.'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_EXTENSION), '.');
}
/**
@@ -113,7 +119,7 @@ abstract class ArchiveDownloader extends FileDownloader
*
* @throws \UnexpectedValueException If can not extract downloaded file to path
*/
- abstract protected function extract($file, $path);
+ abstract protected function extract(PackageInterface $package, $file, $path);
/**
* Returns the folder content, excluding dotfiles
diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php
index 15c00a6e6..4bc865827 100644
--- a/src/Composer/Downloader/DownloadManager.php
+++ b/src/Composer/Downloader/DownloadManager.php
@@ -15,6 +15,7 @@ namespace Composer\Downloader;
use Composer\Package\PackageInterface;
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
+use React\Promise\PromiseInterface;
/**
* Downloaders manager.
@@ -24,6 +25,7 @@ use Composer\Util\Filesystem;
class DownloadManager
{
private $io;
+ private $httpDownloader;
private $preferDist = false;
private $preferSource = false;
private $packagePreferences = array();
@@ -33,9 +35,9 @@ class DownloadManager
/**
* Initializes download manager.
*
- * @param IOInterface $io The Input Output Interface
- * @param bool $preferSource prefer downloading from source
- * @param Filesystem|null $filesystem custom Filesystem object
+ * @param IOInterface $io The Input Output Interface
+ * @param bool $preferSource prefer downloading from source
+ * @param Filesystem|null $filesystem custom Filesystem object
*/
public function __construct(IOInterface $io, $preferSource = false, Filesystem $filesystem = null)
{
@@ -140,7 +142,7 @@ class DownloadManager
* wrong type
* @return DownloaderInterface|null
*/
- public function getDownloaderForInstalledPackage(PackageInterface $package)
+ public function getDownloaderForPackage(PackageInterface $package)
{
$installationSource = $package->getInstallationSource();
@@ -154,7 +156,7 @@ class DownloadManager
$downloader = $this->getDownloader($package->getSourceType());
} else {
throw new \InvalidArgumentException(
- 'Package '.$package.' seems not been installed properly'
+ 'Package '.$package.' does not have an installation source set'
);
}
@@ -171,63 +173,95 @@ class DownloadManager
return $downloader;
}
+ public function getDownloaderType(DownloaderInterface $downloader)
+ {
+ return array_search($downloader, $this->downloaders);
+ }
+
/**
* Downloads package into target dir.
*
* @param PackageInterface $package package instance
* @param string $targetDir target dir
- * @param bool $preferSource prefer installation from source
+ * @param PackageInterface $prevPackage previous package instance in case of updates
+ *
+ * @return PromiseInterface
+ * @throws \InvalidArgumentException if package have no urls to download from
+ * @throws \RuntimeException
+ */
+ public function download(PackageInterface $package, $targetDir, PackageInterface $prevPackage = null)
+ {
+ $this->filesystem->ensureDirectoryExists(dirname($targetDir));
+
+ $sources = $this->getAvailableSources($package, $prevPackage);
+
+ $io = $this->io;
+ $self = $this;
+
+ $download = function ($retry = false) use (&$sources, $io, $package, $self, $targetDir, &$download) {
+ $source = array_shift($sources);
+ if ($retry) {
+ $io->writeError(' Now trying to download from ' . $source . '');
+ }
+ $package->setInstallationSource($source);
+
+ $downloader = $self->getDownloaderForPackage($package);
+ if (!$downloader) {
+ return \React\Promise\resolve();
+ }
+
+ $handleError = function ($e) use ($sources, $source, $package, $io, $download) {
+ if ($e instanceof \RuntimeException) {
+ if (!$sources) {
+ throw $e;
+ }
+
+ $io->writeError(
+ ' Failed to download '.
+ $package->getPrettyName().
+ ' from ' . $source . ': '.
+ $e->getMessage().''
+ );
+
+ return $download(true);
+ }
+
+ throw $e;
+ };
+
+ try {
+ $result = $downloader->download($package, $targetDir);
+ } catch (\Exception $e) {
+ return $handleError($e);
+ }
+ if (!$result instanceof PromiseInterface) {
+ return \React\Promise\resolve($result);
+ }
+
+ $res = $result->then(function ($res) {
+ return $res;
+ }, $handleError);
+
+ return $res;
+ };
+
+ return $download();
+ }
+
+ /**
+ * Installs package into target dir.
+ *
+ * @param PackageInterface $package package instance
+ * @param string $targetDir target dir
*
* @throws \InvalidArgumentException if package have no urls to download from
* @throws \RuntimeException
*/
- public function download(PackageInterface $package, $targetDir, $preferSource = null)
+ public function install(PackageInterface $package, $targetDir)
{
- $preferSource = null !== $preferSource ? $preferSource : $this->preferSource;
- $sourceType = $package->getSourceType();
- $distType = $package->getDistType();
-
- $sources = array();
- if ($sourceType) {
- $sources[] = 'source';
- }
- if ($distType) {
- $sources[] = 'dist';
- }
-
- if (empty($sources)) {
- throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
- }
-
- if (!$preferSource && ($this->preferDist || 'dist' === $this->resolvePackageInstallPreference($package))) {
- $sources = array_reverse($sources);
- }
-
- $this->filesystem->ensureDirectoryExists($targetDir);
-
- foreach ($sources as $i => $source) {
- if (isset($e)) {
- $this->io->writeError(' Now trying to download from ' . $source . '');
- }
- $package->setInstallationSource($source);
- try {
- $downloader = $this->getDownloaderForInstalledPackage($package);
- if ($downloader) {
- $downloader->download($package, $targetDir);
- }
- break;
- } catch (\RuntimeException $e) {
- if ($i === count($sources) - 1) {
- throw $e;
- }
-
- $this->io->writeError(
- ' Failed to download '.
- $package->getPrettyName().
- ' from ' . $source . ': '.
- $e->getMessage().''
- );
- }
+ $downloader = $this->getDownloaderForPackage($package);
+ if ($downloader) {
+ $downloader->install($package, $targetDir);
}
}
@@ -242,31 +276,23 @@ class DownloadManager
*/
public function update(PackageInterface $initial, PackageInterface $target, $targetDir)
{
- $downloader = $this->getDownloaderForInstalledPackage($initial);
+ $downloader = $this->getDownloaderForPackage($target);
+ $initialDownloader = $this->getDownloaderForPackage($initial);
+
+ // no downloaders present means update from metapackage to metapackage, nothing to do
+ if (!$initialDownloader && !$downloader) {
+ return;
+ }
+
+ // if we have a downloader present before, but not after, the package became a metapackage and its files should be removed
if (!$downloader) {
+ $initialDownloader->remove($initial, $targetDir);
return;
}
- $installationSource = $initial->getInstallationSource();
-
- if ('dist' === $installationSource) {
- $initialType = $initial->getDistType();
- $targetType = $target->getDistType();
- } else {
- $initialType = $initial->getSourceType();
- $targetType = $target->getSourceType();
- }
-
- // upgrading from a dist stable package to a dev package, force source reinstall
- if ($target->isDev() && 'dist' === $installationSource) {
- $downloader->remove($initial, $targetDir);
- $this->download($target, $targetDir);
-
- return;
- }
-
+ $initialType = $this->getDownloaderType($initialDownloader);
+ $targetType = $this->getDownloaderType($downloader);
if ($initialType === $targetType) {
- $target->setInstallationSource($installationSource);
try {
$downloader->update($initial, $target, $targetDir);
@@ -282,8 +308,12 @@ class DownloadManager
}
}
- $downloader->remove($initial, $targetDir);
- $this->download($target, $targetDir, 'source' === $installationSource);
+ // if downloader type changed, or update failed and user asks for reinstall,
+ // we wipe the dir and do a new install instead of updating it
+ if ($initialDownloader) {
+ $initialDownloader->remove($initial, $targetDir);
+ }
+ $this->install($target, $targetDir);
}
/**
@@ -294,7 +324,7 @@ class DownloadManager
*/
public function remove(PackageInterface $package, $targetDir)
{
- $downloader = $this->getDownloaderForInstalledPackage($package);
+ $downloader = $this->getDownloaderForPackage($package);
if ($downloader) {
$downloader->remove($package, $targetDir);
}
@@ -322,4 +352,48 @@ class DownloadManager
return $package->isDev() ? 'source' : 'dist';
}
+
+ /**
+ * @return string[]
+ */
+ private function getAvailableSources(PackageInterface $package, PackageInterface $prevPackage = null)
+ {
+ $sourceType = $package->getSourceType();
+ $distType = $package->getDistType();
+
+ // add source before dist by default
+ $sources = array();
+ if ($sourceType) {
+ $sources[] = 'source';
+ }
+ if ($distType) {
+ $sources[] = 'dist';
+ }
+
+ if (empty($sources)) {
+ throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
+ }
+
+ if (
+ $prevPackage
+ // if we are updating, we want to keep the same source as the previously installed package (if available in the new one)
+ && in_array($prevPackage->getInstallationSource(), $sources, true)
+ // unless the previous package was stable dist (by default) and the new package is dev, then we allow the new default to take over
+ && !(!$prevPackage->isDev() && $prevPackage->getInstallationSource() === 'dist' && $package->isDev())
+ ) {
+ $prevSource = $prevPackage->getInstallationSource();
+ usort($sources, function ($a, $b) use ($prevSource) {
+ return $a === $prevSource ? -1 : 1;
+ });
+
+ return $sources;
+ }
+
+ // reverse sources in case dist is the preferred source for this package
+ if (!$this->preferSource && ($this->preferDist || 'dist' === $this->resolvePackageInstallPreference($package))) {
+ $sources = array_reverse($sources);
+ }
+
+ return $sources;
+ }
}
diff --git a/src/Composer/Downloader/DownloaderInterface.php b/src/Composer/Downloader/DownloaderInterface.php
index 713bf36dc..ac56583c4 100644
--- a/src/Composer/Downloader/DownloaderInterface.php
+++ b/src/Composer/Downloader/DownloaderInterface.php
@@ -13,6 +13,7 @@
namespace Composer\Downloader;
use Composer\Package\PackageInterface;
+use React\Promise\PromiseInterface;
/**
* Downloader interface.
@@ -29,13 +30,20 @@ interface DownloaderInterface
*/
public function getInstallationSource();
+ /**
+ * This should do any network-related tasks to prepare for install/update
+ *
+ * @return PromiseInterface|null
+ */
+ public function download(PackageInterface $package, $path);
+
/**
* Downloads specific package into specific folder.
*
* @param PackageInterface $package package instance
* @param string $path download path
*/
- public function download(PackageInterface $package, $path);
+ public function install(PackageInterface $package, $path);
/**
* Updates specific package in specific folder from initial to target version.
diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php
index 8b196e60c..3418eef84 100644
--- a/src/Composer/Downloader/FileDownloader.php
+++ b/src/Composer/Downloader/FileDownloader.php
@@ -26,6 +26,7 @@ use Composer\EventDispatcher\EventDispatcher;
use Composer\Util\Filesystem;
use Composer\Util\HttpDownloader;
use Composer\Util\Url as UrlUtil;
+use Composer\Downloader\TransportException;
/**
* Base downloader for files
@@ -43,7 +44,10 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
protected $filesystem;
protected $cache;
protected $outputProgress = true;
- private $lastCacheWrites = array();
+ /**
+ * @private this is only public for php 5.3 support in closures
+ */
+ public $lastCacheWrites = array();
private $eventDispatcher;
/**
@@ -87,108 +91,149 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
throw new \InvalidArgumentException('The given package is missing url information');
}
- if ($output) {
- $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . "): ", false);
- }
-
+ $retries = 3;
$urls = $package->getDistUrls();
- while ($url = array_shift($urls)) {
- try {
- $fileName = $this->doDownload($package, $path, $url);
- break;
- } catch (\Exception $e) {
- if ($this->io->isDebug()) {
- $this->io->writeError('');
- $this->io->writeError('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage());
- } elseif (count($urls)) {
- $this->io->writeError('');
- $this->io->writeError(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')', false);
- }
-
- if (!count($urls)) {
- throw $e;
- }
- }
+ foreach ($urls as $index => $url) {
+ $processedUrl = $this->processUrl($package, $url);
+ $urls[$index] = array(
+ 'base' => $url,
+ 'processed' => $processedUrl,
+ 'cacheKey' => $this->getCacheKey($package, $processedUrl)
+ );
}
- if ($output) {
- $this->io->writeError('');
- }
-
- return $fileName;
- }
-
- protected function doDownload(PackageInterface $package, $path, $url)
- {
$this->filesystem->emptyDirectory($path);
-
$fileName = $this->getFileName($package, $path);
- $processedUrl = $this->processUrl($package, $url);
+ $io = $this->io;
+ $cache = $this->cache;
+ $originalHttpDownloader = $this->httpDownloader;
+ $eventDispatcher = $this->eventDispatcher;
+ $filesystem = $this->filesystem;
+ $self = $this;
- $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->httpDownloader, $processedUrl);
- if ($this->eventDispatcher) {
- $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
- }
- $httpDownloader = $preFileDownloadEvent->getHttpDownloader();
+ $accept = null;
+ $reject = null;
+ $download = function () use ($io, $output, $originalHttpDownloader, $cache, $eventDispatcher, $package, $fileName, $path, &$urls, &$accept, &$reject) {
+ $url = reset($urls);
+
+ $httpDownloader = $originalHttpDownloader;
+ if ($eventDispatcher) {
+ $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $httpDownloader, $url['processed']);
+ $eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
+ $httpDownloader = $preFileDownloadEvent->getHttpDownloader();
+ }
- try {
$checksum = $package->getDistSha1Checksum();
- $cacheKey = $this->getCacheKey($package, $processedUrl);
+ $cacheKey = $url['cacheKey'];
// use from cache if it is present and has a valid checksum or we have no checksum to check against
- if ($this->cache && (!$checksum || $checksum === $this->cache->sha1($cacheKey)) && $this->cache->copyTo($cacheKey, $fileName)) {
- $this->io->writeError('Loading from cache', false);
+ if ($cache && (!$checksum || $checksum === $cache->sha1($cacheKey)) && $cache->copyTo($cacheKey, $fileName)) {
+ if ($output) {
+ $io->writeError(" - Loading " . $package->getName() . " (" . $package->getFullPrettyVersion() . ") from cache");
+ }
+ $result = \React\Promise\resolve($fileName);
} else {
- // download if cache restore failed
- if (!$this->outputProgress) {
- $this->io->writeError('Downloading', false);
+ if ($output) {
+ $io->writeError(" - Downloading " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
}
- // try to download 3 times then fail hard
- $retries = 3;
- while ($retries--) {
- try {
- // TODO handle this->outputProgress
- $httpDownloader->copy($processedUrl, $fileName, $package->getTransportOptions());
- break;
- } catch (TransportException $e) {
- // if we got an http response with a proper code, then requesting again will probably not help, abort
- if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) {
- throw $e;
- }
- $this->io->writeError('');
- $this->io->writeError(' Download failed, retrying...', true, IOInterface::VERBOSE);
- usleep(500000);
- }
- }
-
- if (!$this->outputProgress) {
- $this->io->writeError(' (100%)', false);
- }
-
- if ($this->cache) {
- $this->lastCacheWrites[$package->getName()] = $cacheKey;
- $this->cache->copyFrom($cacheKey, $fileName);
- }
+ $result = $httpDownloader->addCopy($url['processed'], $fileName, $package->getTransportOptions())
+ ->then($accept, $reject);
}
- if (!file_exists($fileName)) {
- throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
- .' directory is writable and you have internet connectivity');
+ return $result->then(function ($result) use ($fileName, $checksum, $url) {
+ // in case of retry, the first call's Promise chain finally calls this twice at the end,
+ // once with $result being the returned $fileName from $accept, and then once for every
+ // failed request with a null result, which can be skipped.
+ if (null === $result) {
+ return $fileName;
+ }
+
+ if (!file_exists($fileName)) {
+ throw new \UnexpectedValueException($url['base'].' could not be saved to '.$fileName.', make sure the'
+ .' directory is writable and you have internet connectivity');
+ }
+
+ if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
+ throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url['base'].')');
+ }
+
+ return $fileName;
+ });
+ };
+
+ $accept = function ($response) use ($io, $cache, $package, $fileName, $path, $self, &$urls) {
+ $url = reset($urls);
+ $cacheKey = $url['cacheKey'];
+
+ if ($cache) {
+ $self->lastCacheWrites[$package->getName()] = $cacheKey;
+ $cache->copyFrom($cacheKey, $fileName);
}
- if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
- throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url.')');
- }
- } catch (\Exception $e) {
+ $response->collect();
+
+ return $fileName;
+ };
+
+ $reject = function ($e) use ($io, &$urls, $download, $fileName, $path, $package, &$retries, $filesystem, $self) {
// clean up
- $this->filesystem->removeDirectory($path);
- $this->clearLastCacheWrite($package);
+ $filesystem->removeDirectory($path);
+ $self->clearLastCacheWrite($package);
+
+ if ($e instanceof TransportException) {
+ // if we got an http response with a proper code, then requesting again will probably not help, abort
+ if ((0 !== $e->getCode() && !in_array($e->getCode(), array(500, 502, 503, 504))) || !$retries) {
+ $retries = 0;
+ }
+ }
+
+ // special error code returned when network is being artificially disabled
+ if ($e instanceof TransportException && $e->getStatusCode() === 499) {
+ $retries = 0;
+ $urls = array();
+ }
+
+ if ($retries) {
+ usleep(500000);
+ $retries--;
+
+ return $download();
+ }
+
+ array_shift($urls);
+ if ($urls) {
+ if ($io->isDebug()) {
+ $io->writeError(' Failed downloading '.$package->getName().': ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage());
+ $io->writeError(' Trying the next URL for '.$package->getName());
+ } elseif (count($urls)) {
+ $io->writeError(' Failed downloading '.$package->getName().', trying the next URL ('.$e->getCode().': '.$e->getMessage().')');
+ }
+
+ $retries = 3;
+ usleep(100000);
+
+ return $download();
+ }
+
throw $e;
+ };
+
+ return $download();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function install(PackageInterface $package, $path, $output = true)
+ {
+ if ($output) {
+ $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
}
- return $fileName;
+ $this->filesystem->ensureDirectoryExists($path);
+ $this->filesystem->rename($this->getFileName($package, $path), $path . pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME));
}
/**
@@ -201,7 +246,11 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
return $this;
}
- protected function clearLastCacheWrite(PackageInterface $package)
+ /**
+ * TODO mark private in v3
+ * @protected This is public due to PHP 5.3
+ */
+ public function clearLastCacheWrite(PackageInterface $package)
{
if ($this->cache && isset($this->lastCacheWrites[$package->getName()])) {
$this->cache->remove($this->lastCacheWrites[$package->getName()]);
@@ -222,7 +271,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$this->io->writeError(" - " . $actionName . " " . $name . " (" . $from . " => " . $to . "): ", false);
$this->remove($initial, $path, false);
- $this->download($target, $path, false);
+ $this->install($target, $path, false);
$this->io->writeError('');
}
@@ -249,7 +298,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
*/
protected function getFileName(PackageInterface $package, $path)
{
- return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
+ return $path.'_'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
}
/**
@@ -299,7 +348,9 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$e = null;
try {
- $this->download($package, $targetDir.'_compare', false);
+ $res = $this->download($package, $targetDir.'_compare', false);
+ $this->httpDownloader->wait();
+ $res = $this->install($package, $targetDir.'_compare', false);
$comparer = new Comparer();
$comparer->setSource($targetDir.'_compare');
diff --git a/src/Composer/Downloader/FossilDownloader.php b/src/Composer/Downloader/FossilDownloader.php
index 135e973e0..a814f89b7 100644
--- a/src/Composer/Downloader/FossilDownloader.php
+++ b/src/Composer/Downloader/FossilDownloader.php
@@ -23,7 +23,7 @@ class FossilDownloader extends VcsDownloader
/**
* {@inheritDoc}
*/
- public function doDownload(PackageInterface $package, $path, $url)
+ public function doInstall(PackageInterface $package, $path, $url)
{
// Ensure we are allowed to use this URL by config
$this->config->prohibitUrlByConfig($url, $this->io);
diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php
index 869d5330b..ff398f300 100644
--- a/src/Composer/Downloader/GitDownloader.php
+++ b/src/Composer/Downloader/GitDownloader.php
@@ -38,7 +38,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
/**
* {@inheritDoc}
*/
- public function doDownload(PackageInterface $package, $path, $url)
+ public function doInstall(PackageInterface $package, $path, $url)
{
GitUtil::cleanEnv();
$path = $this->normalizePath($path);
diff --git a/src/Composer/Downloader/GzipDownloader.php b/src/Composer/Downloader/GzipDownloader.php
index f65fcf27d..9748b91ac 100644
--- a/src/Composer/Downloader/GzipDownloader.php
+++ b/src/Composer/Downloader/GzipDownloader.php
@@ -36,9 +36,10 @@ class GzipDownloader extends ArchiveDownloader
parent::__construct($io, $config, $downloader, $eventDispatcher, $cache);
}
- protected function extract($file, $path)
+ protected function extract(PackageInterface $package, $file, $path)
{
- $targetFilepath = $path . DIRECTORY_SEPARATOR . basename(substr($file, 0, -3));
+ $filename = pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_FILENAME);
+ $targetFilepath = $path . DIRECTORY_SEPARATOR . $filename;
// Try to use gunzip on *nix
if (!Platform::isWindows()) {
@@ -63,14 +64,6 @@ class GzipDownloader extends ArchiveDownloader
$this->extractUsingExt($file, $targetFilepath);
}
- /**
- * {@inheritdoc}
- */
- protected function getFileName(PackageInterface $package, $path)
- {
- return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
- }
-
private function extractUsingExt($file, $targetFilepath)
{
$archiveFile = gzopen($file, 'rb');
diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php
index 2921cc4b7..add381a75 100644
--- a/src/Composer/Downloader/HgDownloader.php
+++ b/src/Composer/Downloader/HgDownloader.php
@@ -24,7 +24,7 @@ class HgDownloader extends VcsDownloader
/**
* {@inheritDoc}
*/
- public function doDownload(PackageInterface $package, $path, $url)
+ public function doInstall(PackageInterface $package, $path, $url)
{
$hgUtils = new HgUtils($this->io, $this->config, $this->process);
diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php
index e7084bd97..ea583cfc0 100644
--- a/src/Composer/Downloader/PathDownloader.php
+++ b/src/Composer/Downloader/PathDownloader.php
@@ -61,6 +61,15 @@ class PathDownloader extends FileDownloader implements VcsCapableDownloaderInter
$realUrl
));
}
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function install(PackageInterface $package, $path, $output = true)
+ {
+ $url = $package->getDistUrl();
+ $realUrl = realpath($url);
// Get the transport options with default values
$transportOptions = $package->getTransportOptions() + array('symlink' => null);
diff --git a/src/Composer/Downloader/PerforceDownloader.php b/src/Composer/Downloader/PerforceDownloader.php
index a472b84c6..df270417f 100644
--- a/src/Composer/Downloader/PerforceDownloader.php
+++ b/src/Composer/Downloader/PerforceDownloader.php
@@ -27,7 +27,7 @@ class PerforceDownloader extends VcsDownloader
/**
* {@inheritDoc}
*/
- public function doDownload(PackageInterface $package, $path, $url)
+ public function doInstall(PackageInterface $package, $path, $url)
{
$ref = $package->getSourceReference();
$label = $this->getLabelFromSourceReference($ref);
diff --git a/src/Composer/Downloader/PharDownloader.php b/src/Composer/Downloader/PharDownloader.php
index 13fec244b..62741ee0e 100644
--- a/src/Composer/Downloader/PharDownloader.php
+++ b/src/Composer/Downloader/PharDownloader.php
@@ -12,6 +12,8 @@
namespace Composer\Downloader;
+use Composer\Package\PackageInterface;
+
/**
* Downloader for phar files
*
@@ -22,7 +24,7 @@ class PharDownloader extends ArchiveDownloader
/**
* {@inheritDoc}
*/
- protected function extract($file, $path)
+ protected function extract(PackageInterface $package, $file, $path)
{
// Can throw an UnexpectedValueException
$archive = new \Phar($file);
diff --git a/src/Composer/Downloader/RarDownloader.php b/src/Composer/Downloader/RarDownloader.php
index 6fe4cf27c..2ebc3bf18 100644
--- a/src/Composer/Downloader/RarDownloader.php
+++ b/src/Composer/Downloader/RarDownloader.php
@@ -20,6 +20,7 @@ use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Composer\Util\HttpDownloader;
use Composer\IO\IOInterface;
+use Composer\Package\PackageInterface;
use RarArchive;
/**
@@ -39,7 +40,7 @@ class RarDownloader extends ArchiveDownloader
parent::__construct($io, $config, $downloader, $eventDispatcher, $cache);
}
- protected function extract($file, $path)
+ protected function extract(PackageInterface $package, $file, $path)
{
$processError = null;
diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php
index e23958164..0aae163c6 100644
--- a/src/Composer/Downloader/SvnDownloader.php
+++ b/src/Composer/Downloader/SvnDownloader.php
@@ -28,7 +28,7 @@ class SvnDownloader extends VcsDownloader
/**
* {@inheritDoc}
*/
- public function doDownload(PackageInterface $package, $path, $url)
+ public function doInstall(PackageInterface $package, $path, $url)
{
SvnUtil::cleanEnv();
$ref = $package->getSourceReference();
diff --git a/src/Composer/Downloader/TarDownloader.php b/src/Composer/Downloader/TarDownloader.php
index 34c43da5f..e48407230 100644
--- a/src/Composer/Downloader/TarDownloader.php
+++ b/src/Composer/Downloader/TarDownloader.php
@@ -12,6 +12,8 @@
namespace Composer\Downloader;
+use Composer\Package\PackageInterface;
+
/**
* Downloader for tar files: tar, tar.gz or tar.bz2
*
@@ -22,7 +24,7 @@ class TarDownloader extends ArchiveDownloader
/**
* {@inheritDoc}
*/
- protected function extract($file, $path)
+ protected function extract(PackageInterface $package, $file, $path)
{
// Can throw an UnexpectedValueException
$archive = new \PharData($file);
diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php
index aa666058e..237d7e49d 100644
--- a/src/Composer/Downloader/VcsDownloader.php
+++ b/src/Composer/Downloader/VcsDownloader.php
@@ -55,6 +55,14 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
* {@inheritDoc}
*/
public function download(PackageInterface $package, $path)
+ {
+ // noop for now, ideally we would do a git fetch already here, or make sure the cached git repo is synced, etc.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function install(PackageInterface $package, $path)
{
if (!$package->getSourceReference()) {
throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
@@ -87,7 +95,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
$url = $needle . $url;
}
}
- $this->doDownload($package, $path, $url);
+ $this->doInstall($package, $path, $url);
break;
} catch (\Exception $e) {
// rethrow phpunit exceptions to avoid hard to debug bug failures
@@ -260,7 +268,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
* @param string $path download path
* @param string $url package url
*/
- abstract protected function doDownload(PackageInterface $package, $path, $url);
+ abstract protected function doInstall(PackageInterface $package, $path, $url);
/**
* Updates specific package in specific folder from initial to target version.
diff --git a/src/Composer/Downloader/XzDownloader.php b/src/Composer/Downloader/XzDownloader.php
index bd7b028e2..19e51c321 100644
--- a/src/Composer/Downloader/XzDownloader.php
+++ b/src/Composer/Downloader/XzDownloader.php
@@ -37,7 +37,7 @@ class XzDownloader extends ArchiveDownloader
parent::__construct($io, $config, $downloader, $eventDispatcher, $cache);
}
- protected function extract($file, $path)
+ protected function extract(PackageInterface $package, $file, $path)
{
$command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path);
@@ -49,12 +49,4 @@ class XzDownloader extends ArchiveDownloader
throw new \RuntimeException($processError);
}
-
- /**
- * {@inheritdoc}
- */
- protected function getFileName(PackageInterface $package, $path)
- {
- return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
- }
}
diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php
index 9eceab250..efa9fc994 100644
--- a/src/Composer/Downloader/ZipDownloader.php
+++ b/src/Composer/Downloader/ZipDownloader.php
@@ -185,7 +185,7 @@ class ZipDownloader extends ArchiveDownloader
* @param string $file File to extract
* @param string $path Path where to extract file
*/
- public function extract($file, $path)
+ public function extract(PackageInterface $package, $file, $path)
{
// Each extract calls its alternative if not available or fails
if (self::$isWindows) {
diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php
index c96fd2188..e66e64ed1 100644
--- a/src/Composer/Factory.php
+++ b/src/Composer/Factory.php
@@ -24,6 +24,7 @@ use Composer\Util\Filesystem;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Composer\Util\HttpDownloader;
+use Composer\Util\Loop;
use Composer\Util\Silencer;
use Composer\Plugin\PluginEvents;
use Composer\EventDispatcher\Event;
@@ -326,6 +327,7 @@ class Factory
}
$httpDownloader = self::createHttpDownloader($io, $config);
+ $loop = new Loop($httpDownloader);
// initialize event dispatcher
$dispatcher = new EventDispatcher($composer, $io);
@@ -352,7 +354,7 @@ class Factory
$composer->setPackage($package);
// initialize installation manager
- $im = $this->createInstallationManager();
+ $im = $this->createInstallationManager($loop);
$composer->setInstallationManager($im);
if ($fullLoad) {
@@ -365,7 +367,7 @@ class Factory
$composer->setAutoloadGenerator($generator);
// initialize archive manager
- $am = $this->createArchiveManager($config, $dm);
+ $am = $this->createArchiveManager($config, $dm, $loop);
$composer->setArchiveManager($am);
}
@@ -501,9 +503,9 @@ class Factory
* @param Downloader\DownloadManager $dm Manager use to download sources
* @return Archiver\ArchiveManager
*/
- public function createArchiveManager(Config $config, Downloader\DownloadManager $dm)
+ public function createArchiveManager(Config $config, Downloader\DownloadManager $dm, Loop $loop)
{
- $am = new Archiver\ArchiveManager($dm);
+ $am = new Archiver\ArchiveManager($dm, $loop);
$am->addArchiver(new Archiver\ZipArchiver);
$am->addArchiver(new Archiver\PharArchiver);
@@ -525,9 +527,9 @@ class Factory
/**
* @return Installer\InstallationManager
*/
- protected function createInstallationManager()
+ public function createInstallationManager(Loop $loop)
{
- return new Installer\InstallationManager();
+ return new Installer\InstallationManager($loop);
}
/**
diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php
index 9f50b5980..ce10dc4da 100644
--- a/src/Composer/Installer/InstallationManager.php
+++ b/src/Composer/Installer/InstallationManager.php
@@ -24,6 +24,7 @@ use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
use Composer\Util\StreamContextFactory;
+use Composer\Util\Loop;
/**
* Package operation manager.
@@ -37,6 +38,12 @@ class InstallationManager
private $installers = array();
private $cache = array();
private $notifiablePackages = array();
+ private $loop;
+
+ public function __construct(Loop $loop)
+ {
+ $this->loop = $loop;
+ }
public function reset()
{
@@ -156,7 +163,24 @@ class InstallationManager
*/
public function execute(RepositoryInterface $repo, OperationInterface $operation)
{
+ // TODO this should take all operations in one go
$method = $operation->getJobType();
+
+ if ($method === 'install') {
+ $package = $operation->getPackage();
+ $installer = $this->getInstaller($package->getType());
+ $promise = $installer->download($package);
+ } elseif ($method === 'update') {
+ $target = $operation->getTargetPackage();
+ $targetType = $target->getType();
+ $installer = $this->getInstaller($targetType);
+ $promise = $installer->download($target, $operation->getInitialPackage());
+ }
+
+ if (isset($promise)) {
+ $this->loop->wait(array($promise));
+ }
+
$this->$method($repo, $operation);
}
@@ -194,7 +218,8 @@ class InstallationManager
$this->markForNotification($target);
} else {
$this->getInstaller($initialType)->uninstall($repo, $initial);
- $this->getInstaller($targetType)->install($repo, $target);
+ $installer = $this->getInstaller($targetType);
+ $installer->install($repo, $target);
}
}
diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php
index e64dfadd2..e00877ed9 100644
--- a/src/Composer/Installer/InstallerInterface.php
+++ b/src/Composer/Installer/InstallerInterface.php
@@ -15,6 +15,7 @@ namespace Composer\Installer;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use InvalidArgumentException;
+use React\Promise\PromiseInterface;
/**
* Interface for the package installation manager.
@@ -42,6 +43,15 @@ interface InstallerInterface
*/
public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package);
+ /**
+ * Downloads the files needed to later install the given package.
+ *
+ * @param PackageInterface $package package instance
+ * @param PackageInterface $prevPackage previous package instance in case of an update
+ * @return PromiseInterface
+ */
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null);
+
/**
* Installs specific package.
*
diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php
index 34fbbbee4..4c2f45601 100644
--- a/src/Composer/Installer/LibraryInstaller.php
+++ b/src/Composer/Installer/LibraryInstaller.php
@@ -85,6 +85,14 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
return (Platform::isWindows() && $this->filesystem->isJunction($installPath)) || is_link($installPath);
}
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null)
+ {
+ $this->initializeVendorDir();
+ $downloadPath = $this->getInstallPath($package);
+
+ return $this->downloadManager->download($package, $downloadPath, $prevPackage);
+ }
+
/**
* {@inheritDoc}
*/
@@ -194,7 +202,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
protected function installCode(PackageInterface $package)
{
$downloadPath = $this->getInstallPath($package);
- $this->downloadManager->download($package, $downloadPath);
+ $this->downloadManager->install($package, $downloadPath);
}
protected function updateCode(PackageInterface $initial, PackageInterface $target)
diff --git a/src/Composer/Installer/MetapackageInstaller.php b/src/Composer/Installer/MetapackageInstaller.php
index 3f99ec03c..7dbf4af67 100644
--- a/src/Composer/Installer/MetapackageInstaller.php
+++ b/src/Composer/Installer/MetapackageInstaller.php
@@ -38,6 +38,14 @@ class MetapackageInstaller implements InstallerInterface
return $repo->hasPackage($package);
}
+ /**
+ * {@inheritDoc}
+ */
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null)
+ {
+ // noop
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/Composer/Installer/NoopInstaller.php b/src/Composer/Installer/NoopInstaller.php
index 72cf17d22..51df3c305 100644
--- a/src/Composer/Installer/NoopInstaller.php
+++ b/src/Composer/Installer/NoopInstaller.php
@@ -40,6 +40,13 @@ class NoopInstaller implements InstallerInterface
return $repo->hasPackage($package);
}
+ /**
+ * {@inheritDoc}
+ */
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null)
+ {
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/Composer/Installer/PluginInstaller.php b/src/Composer/Installer/PluginInstaller.php
index c400ca4a6..62a16fc62 100644
--- a/src/Composer/Installer/PluginInstaller.php
+++ b/src/Composer/Installer/PluginInstaller.php
@@ -50,13 +50,21 @@ class PluginInstaller extends LibraryInstaller
/**
* {@inheritDoc}
*/
- public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null)
{
$extra = $package->getExtra();
if (empty($extra['class'])) {
throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
}
+ return parent::download($package, $prevPackage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
+ {
parent::install($repo, $package);
try {
$this->composer->getPluginManager()->registerPackage($package, true);
diff --git a/src/Composer/Installer/ProjectInstaller.php b/src/Composer/Installer/ProjectInstaller.php
index c79238b36..350b220f5 100644
--- a/src/Composer/Installer/ProjectInstaller.php
+++ b/src/Composer/Installer/ProjectInstaller.php
@@ -58,7 +58,7 @@ class ProjectInstaller implements InstallerInterface
/**
* {@inheritDoc}
*/
- public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
+ public function download(PackageInterface $package, PackageInterface $prevPackage = null)
{
$installPath = $this->installPath;
if (file_exists($installPath) && !$this->filesystem->isDirEmpty($installPath)) {
@@ -67,7 +67,16 @@ class ProjectInstaller implements InstallerInterface
if (!is_dir($installPath)) {
mkdir($installPath, 0777, true);
}
- $this->downloadManager->download($package, $installPath);
+
+ return $this->downloadManager->download($package, $installPath, $prevPackage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
+ {
+ $this->downloadManager->install($package, $this->installPath);
}
/**
diff --git a/src/Composer/Package/Archiver/ArchiveManager.php b/src/Composer/Package/Archiver/ArchiveManager.php
index 22f8eeafe..359d6b053 100644
--- a/src/Composer/Package/Archiver/ArchiveManager.php
+++ b/src/Composer/Package/Archiver/ArchiveManager.php
@@ -16,6 +16,7 @@ use Composer\Downloader\DownloadManager;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem;
+use Composer\Util\Loop;
use Composer\Json\JsonFile;
/**
@@ -25,6 +26,7 @@ use Composer\Json\JsonFile;
class ArchiveManager
{
protected $downloadManager;
+ protected $loop;
protected $archivers = array();
@@ -36,9 +38,10 @@ class ArchiveManager
/**
* @param DownloadManager $downloadManager A manager used to download package sources
*/
- public function __construct(DownloadManager $downloadManager)
+ public function __construct(DownloadManager $downloadManager, Loop $loop)
{
$this->downloadManager = $downloadManager;
+ $this->loop = $loop;
}
/**
@@ -148,7 +151,9 @@ class ArchiveManager
$filesystem->ensureDirectoryExists($sourcePath);
// Download sources
- $this->downloadManager->download($package, $sourcePath);
+ $promise = $this->downloadManager->download($package, $sourcePath);
+ $this->loop->wait(array($promise));
+ $this->downloadManager->install($package, $sourcePath);
// Check exclude from downloaded composer.json
if (file_exists($composerJsonPath = $sourcePath.'/composer.json')) {
diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php
index 8fe6a04ed..af627df73 100644
--- a/src/Composer/Repository/ComposerRepository.php
+++ b/src/Composer/Repository/ComposerRepository.php
@@ -22,6 +22,7 @@ use Composer\Config;
use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\Util\HttpDownloader;
+use Composer\Util\Loop;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\EventDispatcher\EventDispatcher;
@@ -42,6 +43,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private $baseUrl;
private $io;
private $httpDownloader;
+ private $loop;
protected $cache;
protected $notifyUrl;
protected $searchUrl;
@@ -107,6 +109,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$this->httpDownloader = $httpDownloader;
$this->eventDispatcher = $eventDispatcher;
$this->repoConfig = $repoConfig;
+ $this->loop = new Loop($this->httpDownloader);
}
public function getRepoConfig()
@@ -569,6 +572,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$this->loadRootServerFile();
$packages = array();
+ $promises = array();
$repo = $this;
if (!$this->lazyProvidersUrl) {
@@ -592,7 +596,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$lastModified = isset($contents['last-modified']) ? $contents['last-modified'] : null;
}
- $this->asyncFetchFile($url, $cacheKey, $lastModified)
+ $promises[] = $this->asyncFetchFile($url, $cacheKey, $lastModified)
->then(function ($response) use (&$packages, $contents, $name, $constraint, $repo, $isPackageAcceptableCallable) {
static $uniqKeys = array('version', 'version_normalized', 'source', 'dist', 'time');
@@ -637,13 +641,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$packages[spl_object_hash($package->getAliasOf())] = $package->getAliasOf();
}
}
- }, function ($e) {
- // TODO use ->done() above instead with react/promise 2.0
- throw $e;
});
}
- $this->httpDownloader->wait();
+ $this->loop->wait($promises);
return $packages;
// RepositorySet should call loadMetadata, getMetadata when all promises resolved, then metadataComplete when done so we can GC the loaded json and whatnot then as needed
@@ -1119,7 +1120,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
}
$degradedMode = true;
- return true;
+ throw $e;
};
return $httpDownloader->add($filename, $options)->then($accept, $reject);
diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php
index 3dc6710b6..ff31bf695 100644
--- a/src/Composer/Util/Http/CurlDownloader.php
+++ b/src/Composer/Util/Http/CurlDownloader.php
@@ -295,7 +295,7 @@ class CurlDownloader
// resolve promise
if ($job['filename']) {
rename($job['filename'].'~', $job['filename']);
- call_user_func($job['resolve'], true);
+ call_user_func($job['resolve'], $response);
} else {
call_user_func($job['resolve'], $response);
}
diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php
index f2308d75a..172ea875a 100644
--- a/src/Composer/Util/HttpDownloader.php
+++ b/src/Composer/Util/HttpDownloader.php
@@ -160,7 +160,10 @@ class HttpDownloader
if ($job['request']['copyTo']) {
$result = $rfs->copy($job['origin'], $url, $job['request']['copyTo'], false /* TODO progress */, $options);
- $resolve($result);
+ $headers = $rfs->getLastHeaders();
+ $response = new Http\Response($job['request'], $rfs->findStatusCode($headers), $headers, $job['request']['copyTo'].'~');
+
+ $resolve($response);
} else {
$body = $rfs->getContents($job['origin'], $url, false /* TODO progress */, $options);
$headers = $rfs->getLastHeaders();
@@ -191,6 +194,7 @@ class HttpDownloader
$job['exception'] = $e;
$downloader->markJobDone();
+ $downloader->scheduleNextJob();
throw $e;
});
diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php
new file mode 100644
index 000000000..1be7d478b
--- /dev/null
+++ b/src/Composer/Util/Loop.php
@@ -0,0 +1,47 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Util;
+
+use Composer\Util\HttpDownloader;
+use React\Promise\Promise;
+
+/**
+ * @author Jordi Boggiano
+ */
+class Loop
+{
+ private $io;
+
+ public function __construct(HttpDownloader $httpDownloader)
+ {
+ $this->httpDownloader = $httpDownloader;
+ }
+
+ public function wait(array $promises)
+ {
+ $uncaught = null;
+
+ \React\Promise\all($promises)->then(
+ function () { },
+ function ($e) use (&$uncaught) {
+ $uncaught = $e;
+ }
+ );
+
+ $this->httpDownloader->wait();
+
+ if ($uncaught) {
+ throw $uncaught;
+ }
+ }
+}
diff --git a/tests/Composer/Test/ComposerTest.php b/tests/Composer/Test/ComposerTest.php
index c2c425e76..87270baae 100644
--- a/tests/Composer/Test/ComposerTest.php
+++ b/tests/Composer/Test/ComposerTest.php
@@ -57,7 +57,7 @@ class ComposerTest extends TestCase
public function testSetGetInstallationManager()
{
$composer = new Composer();
- $manager = $this->getMockBuilder('Composer\Installer\InstallationManager')->getMock();
+ $manager = $this->getMockBuilder('Composer\Installer\InstallationManager')->disableOriginalConstructor()->getMock();
$composer->setInstallationManager($manager);
$this->assertSame($manager, $composer->getInstallationManager());
diff --git a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php
index ddf21c64b..d887ba103 100644
--- a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php
@@ -29,7 +29,7 @@ class ArchiveDownloaderTest extends TestCase
$method->setAccessible(true);
$first = $method->invoke($downloader, $packageMock, '/path');
- $this->assertRegExp('#/path/[a-z0-9]+\.js#', $first);
+ $this->assertRegExp('#/path_[a-z0-9]+\.js#', $first);
$this->assertSame($first, $method->invoke($downloader, $packageMock, '/path'));
}
diff --git a/tests/Composer/Test/Downloader/DownloadManagerTest.php b/tests/Composer/Test/Downloader/DownloadManagerTest.php
index 222e541d7..307b2294f 100644
--- a/tests/Composer/Test/Downloader/DownloadManagerTest.php
+++ b/tests/Composer/Test/Downloader/DownloadManagerTest.php
@@ -50,7 +50,7 @@ class DownloadManagerTest extends TestCase
$this->setExpectedException('InvalidArgumentException');
- $manager->getDownloaderForInstalledPackage($package);
+ $manager->getDownloaderForPackage($package);
}
public function testGetDownloaderForCorrectlyInstalledDistPackage()
@@ -82,7 +82,7 @@ class DownloadManagerTest extends TestCase
->with('pear')
->will($this->returnValue($downloader));
- $this->assertSame($downloader, $manager->getDownloaderForInstalledPackage($package));
+ $this->assertSame($downloader, $manager->getDownloaderForPackage($package));
}
public function testGetDownloaderForIncorrectlyInstalledDistPackage()
@@ -116,7 +116,7 @@ class DownloadManagerTest extends TestCase
$this->setExpectedException('LogicException');
- $manager->getDownloaderForInstalledPackage($package);
+ $manager->getDownloaderForPackage($package);
}
public function testGetDownloaderForCorrectlyInstalledSourcePackage()
@@ -148,7 +148,7 @@ class DownloadManagerTest extends TestCase
->with('git')
->will($this->returnValue($downloader));
- $this->assertSame($downloader, $manager->getDownloaderForInstalledPackage($package));
+ $this->assertSame($downloader, $manager->getDownloaderForPackage($package));
}
public function testGetDownloaderForIncorrectlyInstalledSourcePackage()
@@ -182,7 +182,7 @@ class DownloadManagerTest extends TestCase
$this->setExpectedException('LogicException');
- $manager->getDownloaderForInstalledPackage($package);
+ $manager->getDownloaderForPackage($package);
}
public function testGetDownloaderForMetapackage()
@@ -195,7 +195,7 @@ class DownloadManagerTest extends TestCase
$manager = new DownloadManager($this->io, false, $this->filesystem);
- $this->assertNull($manager->getDownloaderForInstalledPackage($package));
+ $this->assertNull($manager->getDownloaderForPackage($package));
}
public function testFullPackageDownload()
@@ -223,11 +223,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -274,16 +274,16 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->at(0))
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloaderFail));
$manager
->expects($this->at(1))
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloaderSuccess));
@@ -333,11 +333,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -369,11 +369,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -399,11 +399,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue(null)); // There is no downloader for Metapackages.
@@ -435,11 +435,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -472,11 +472,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -509,11 +509,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -550,33 +550,30 @@ class DownloadManagerTest extends TestCase
$initial
->expects($this->once())
->method('getDistType')
- ->will($this->returnValue('pear'));
+ ->will($this->returnValue('zip'));
$target = $this->createPackageMock();
$target
->expects($this->once())
- ->method('getDistType')
- ->will($this->returnValue('pear'));
+ ->method('getInstallationSource')
+ ->will($this->returnValue('dist'));
$target
->expects($this->once())
- ->method('setInstallationSource')
- ->with('dist');
+ ->method('getDistType')
+ ->will($this->returnValue('zip'));
- $pearDownloader = $this->createDownloaderMock();
- $pearDownloader
+ $zipDownloader = $this->createDownloaderMock();
+ $zipDownloader
->expects($this->once())
->method('update')
->with($initial, $target, 'vendor/bundles/FOS/UserBundle');
+ $zipDownloader
+ ->expects($this->any())
+ ->method('getInstallationSource')
+ ->will($this->returnValue('dist'));
- $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
- ->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
- ->getMock();
- $manager
- ->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
- ->with($initial)
- ->will($this->returnValue($pearDownloader));
+ $manager = new DownloadManager($this->io, false, $this->filesystem);
+ $manager->setDownloader('zip', $zipDownloader);
$manager->update($initial, $target, 'vendor/bundles/FOS/UserBundle');
}
@@ -591,113 +588,89 @@ class DownloadManagerTest extends TestCase
$initial
->expects($this->once())
->method('getDistType')
- ->will($this->returnValue('pear'));
+ ->will($this->returnValue('xz'));
$target = $this->createPackageMock();
$target
- ->expects($this->once())
+ ->expects($this->any())
+ ->method('getInstallationSource')
+ ->will($this->returnValue('dist'));
+ $target
+ ->expects($this->any())
->method('getDistType')
- ->will($this->returnValue('composer'));
+ ->will($this->returnValue('zip'));
- $pearDownloader = $this->createDownloaderMock();
- $pearDownloader
+ $xzDownloader = $this->createDownloaderMock();
+ $xzDownloader
->expects($this->once())
->method('remove')
->with($initial, 'vendor/bundles/FOS/UserBundle');
+ $xzDownloader
+ ->expects($this->any())
+ ->method('getInstallationSource')
+ ->will($this->returnValue('dist'));
- $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
- ->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
- ->getMock();
- $manager
+ $zipDownloader = $this->createDownloaderMock();
+ $zipDownloader
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
- ->with($initial)
- ->will($this->returnValue($pearDownloader));
- $manager
- ->expects($this->once())
- ->method('download')
- ->with($target, 'vendor/bundles/FOS/UserBundle', false);
+ ->method('install')
+ ->with($target, 'vendor/bundles/FOS/UserBundle');
+ $zipDownloader
+ ->expects($this->any())
+ ->method('getInstallationSource')
+ ->will($this->returnValue('dist'));
+
+ $manager = new DownloadManager($this->io, false, $this->filesystem);
+ $manager->setDownloader('xz', $xzDownloader);
+ $manager->setDownloader('zip', $zipDownloader);
$manager->update($initial, $target, 'vendor/bundles/FOS/UserBundle');
}
- public function testUpdateSourceWithEqualTypes()
+ /**
+ * @dataProvider updatesProvider
+ */
+ public function testGetAvailableSourcesUpdateSticksToSameSource($prevPkgSource, $prevPkgIsDev, $targetAvailable, $targetIsDev, $expected)
{
- $initial = $this->createPackageMock();
- $initial
- ->expects($this->once())
- ->method('getInstallationSource')
- ->will($this->returnValue('source'));
- $initial
- ->expects($this->once())
- ->method('getSourceType')
- ->will($this->returnValue('svn'));
+ $initial = null;
+ if ($prevPkgSource) {
+ $initial = $this->prophesize('Composer\Package\PackageInterface');
+ $initial->getInstallationSource()->willReturn($prevPkgSource);
+ $initial->isDev()->willReturn($prevPkgIsDev);
+ }
- $target = $this->createPackageMock();
- $target
- ->expects($this->once())
- ->method('getSourceType')
- ->will($this->returnValue('svn'));
+ $target = $this->prophesize('Composer\Package\PackageInterface');
+ $target->getSourceType()->willReturn(in_array('source', $targetAvailable, true) ? 'git' : null);
+ $target->getDistType()->willReturn(in_array('dist', $targetAvailable, true) ? 'zip' : null);
+ $target->isDev()->willReturn($targetIsDev);
- $svnDownloader = $this->createDownloaderMock();
- $svnDownloader
- ->expects($this->once())
- ->method('update')
- ->with($initial, $target, 'vendor/pkg');
-
- $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
- ->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
- ->getMock();
- $manager
- ->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
- ->with($initial)
- ->will($this->returnValue($svnDownloader));
-
- $manager->update($initial, $target, 'vendor/pkg');
+ $manager = new DownloadManager($this->io, false, $this->filesystem);
+ $method = new \ReflectionMethod($manager, 'getAvailableSources');
+ $method->setAccessible(true);
+ $this->assertEquals($expected, $method->invoke($manager, $target->reveal(), $initial ? $initial->reveal() : null));
}
- public function testUpdateSourceWithNotEqualTypes()
+ public static function updatesProvider()
{
- $initial = $this->createPackageMock();
- $initial
- ->expects($this->once())
- ->method('getInstallationSource')
- ->will($this->returnValue('source'));
- $initial
- ->expects($this->once())
- ->method('getSourceType')
- ->will($this->returnValue('svn'));
-
- $target = $this->createPackageMock();
- $target
- ->expects($this->once())
- ->method('getSourceType')
- ->will($this->returnValue('git'));
-
- $svnDownloader = $this->createDownloaderMock();
- $svnDownloader
- ->expects($this->once())
- ->method('remove')
- ->with($initial, 'vendor/pkg');
-
- $manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
- ->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage', 'download'))
- ->getMock();
- $manager
- ->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
- ->with($initial)
- ->will($this->returnValue($svnDownloader));
- $manager
- ->expects($this->once())
- ->method('download')
- ->with($target, 'vendor/pkg', true);
-
- $manager->update($initial, $target, 'vendor/pkg');
+ return array(
+ // prevPkg source, prevPkg isDev, pkg available, pkg isDev, expected
+ // updates keep previous source as preference
+ array('source', false, array('source', 'dist'), false, array('source', 'dist')),
+ array('dist', false, array('source', 'dist'), false, array('dist', 'source')),
+ // updates do not keep previous source if target package does not have it
+ array('source', false, array('dist'), false, array('dist')),
+ array('dist', false, array('source'), false, array('source')),
+ // updates do not keep previous source if target is dev and prev wasn't dev and installed from dist
+ array('source', false, array('source', 'dist'), true, array('source', 'dist')),
+ array('dist', false, array('source', 'dist'), true, array('source', 'dist')),
+ // install picks the right default
+ array(null, null, array('source', 'dist'), true, array('source', 'dist')),
+ array(null, null, array('dist'), true, array('dist')),
+ array(null, null, array('source'), true, array('source')),
+ array(null, null, array('source', 'dist'), false, array('dist', 'source')),
+ array(null, null, array('dist'), false, array('dist')),
+ array(null, null, array('source'), false, array('source')),
+ );
}
public function testUpdateMetapackage()
@@ -707,11 +680,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
- ->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->expects($this->exactly(2))
+ ->method('getDownloaderForPackage')
->with($initial)
->will($this->returnValue(null)); // There is no downloader for metapackages.
@@ -730,11 +703,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($pearDownloader));
@@ -747,11 +720,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue(null)); // There is no downloader for metapackages.
@@ -790,11 +763,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -833,11 +806,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
@@ -879,11 +852,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'source'));
@@ -926,11 +899,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'source'));
@@ -973,11 +946,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'auto'));
@@ -1020,11 +993,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'auto'));
@@ -1063,11 +1036,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'source'));
@@ -1106,11 +1079,11 @@ class DownloadManagerTest extends TestCase
$manager = $this->getMockBuilder('Composer\Downloader\DownloadManager')
->setConstructorArgs(array($this->io, false, $this->filesystem))
- ->setMethods(array('getDownloaderForInstalledPackage'))
+ ->setMethods(array('getDownloaderForPackage'))
->getMock();
$manager
->expects($this->once())
- ->method('getDownloaderForInstalledPackage')
+ ->method('getDownloaderForPackage')
->with($package)
->will($this->returnValue($downloader));
$manager->setPreferences(array('foo/*' => 'dist'));
diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php
index 12edfe19d..9ce536474 100644
--- a/tests/Composer/Test/Downloader/FileDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php
@@ -15,6 +15,8 @@ namespace Composer\Test\Downloader;
use Composer\Downloader\FileDownloader;
use Composer\Test\TestCase;
use Composer\Util\Filesystem;
+use Composer\Util\Http\Response;
+use Composer\Util\Loop;
class FileDownloaderTest extends TestCase
{
@@ -23,6 +25,11 @@ class FileDownloaderTest extends TestCase
$io = $io ?: $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$config = $config ?: $this->getMockBuilder('Composer\Config')->getMock();
$httpDownloader = $httpDownloader ?: $this->getMockBuilder('Composer\Util\HttpDownloader')->disableOriginalConstructor()->getMock();
+ $httpDownloader
+ ->expects($this->any())
+ ->method('addCopy')
+ ->will($this->returnValue(\React\Promise\resolve(new Response(array('url' => 'http://example.org/'), 200, array(), 'file~'))));
+ $this->httpDownloader = $httpDownloader;
return new FileDownloader($io, $config, $httpDownloader, $eventDispatcher, $cache, $filesystem);
}
@@ -84,7 +91,7 @@ class FileDownloaderTest extends TestCase
$method = new \ReflectionMethod($downloader, 'getFileName');
$method->setAccessible(true);
- $this->assertEquals('/path/script.js', $method->invoke($downloader, $packageMock, '/path'));
+ $this->assertEquals('/path_script.js', $method->invoke($downloader, $packageMock, '/path'));
}
public function testDownloadButFileIsUnsaved()
@@ -118,8 +125,11 @@ class FileDownloaderTest extends TestCase
$downloader = $this->getDownloader($ioMock);
try {
- $downloader->download($packageMock, $path);
- $this->fail();
+ $promise = $downloader->download($packageMock, $path);
+ $loop = new Loop($this->httpDownloader);
+ $loop->wait(array($promise));
+
+ $this->fail('Download was expected to throw');
} catch (\Exception $e) {
if (is_dir($path)) {
$fs = new Filesystem();
@@ -128,7 +138,7 @@ class FileDownloaderTest extends TestCase
unlink($path);
}
- $this->assertInstanceOf('UnexpectedValueException', $e);
+ $this->assertInstanceOf('UnexpectedValueException', $e, $e->getMessage());
$this->assertContains('could not be saved to', $e->getMessage());
}
}
@@ -188,11 +198,14 @@ class FileDownloaderTest extends TestCase
$path = $this->getUniqueTmpDirectory();
$downloader = $this->getDownloader(null, null, null, null, null, $filesystem);
// make sure the file expected to be downloaded is on disk already
- touch($path.'/script.js');
+ touch($path.'_script.js');
try {
- $downloader->download($packageMock, $path);
- $this->fail();
+ $promise = $downloader->download($packageMock, $path);
+ $loop = new Loop($this->httpDownloader);
+ $loop->wait(array($promise));
+
+ $this->fail('Download was expected to throw');
} catch (\Exception $e) {
if (is_dir($path)) {
$fs = new Filesystem();
@@ -201,7 +214,7 @@ class FileDownloaderTest extends TestCase
unlink($path);
}
- $this->assertInstanceOf('UnexpectedValueException', $e);
+ $this->assertInstanceOf('UnexpectedValueException', $e, $e->getMessage());
$this->assertContains('checksum verification', $e->getMessage());
}
}
@@ -232,17 +245,25 @@ class FileDownloaderTest extends TestCase
$ioMock = $this->getMock('Composer\IO\IOInterface');
$ioMock->expects($this->at(0))
+ ->method('writeError')
+ ->with($this->stringContains('Downloading'));
+
+ $ioMock->expects($this->at(1))
->method('writeError')
->with($this->stringContains('Downgrading'));
$path = $this->getUniqueTmpDirectory();
- touch($path.'/script.js');
+ touch($path.'_script.js');
$filesystem = $this->getMock('Composer\Util\Filesystem');
$filesystem->expects($this->once())
->method('removeDirectory')
->will($this->returnValue(true));
$downloader = $this->getDownloader($ioMock, null, null, null, null, $filesystem);
+ $promise = $downloader->download($newPackage, $path, $oldPackage);
+ $loop = new Loop($this->httpDownloader);
+ $loop->wait(array($promise));
+
$downloader->update($oldPackage, $newPackage, $path);
}
}
diff --git a/tests/Composer/Test/Downloader/FossilDownloaderTest.php b/tests/Composer/Test/Downloader/FossilDownloaderTest.php
index 623f7dec2..9ab7b6b84 100644
--- a/tests/Composer/Test/Downloader/FossilDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/FossilDownloaderTest.php
@@ -56,7 +56,7 @@ class FossilDownloaderTest extends TestCase
->will($this->returnValue(null));
$downloader = $this->getDownloaderMock();
- $downloader->download($packageMock, '/path');
+ $downloader->install($packageMock, '/path');
}
public function testDownload()
@@ -89,7 +89,7 @@ class FossilDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
- $downloader->download($packageMock, 'repo');
+ $downloader->install($packageMock, 'repo');
}
/**
diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php
index c3cd31a4a..b5d0054de 100644
--- a/tests/Composer/Test/Downloader/GitDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php
@@ -79,7 +79,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue(null));
$downloader = $this->getDownloaderMock();
- $downloader->download($packageMock, '/path');
+ $downloader->install($packageMock, '/path');
}
public function testDownload()
@@ -130,7 +130,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
}
public function testDownloadWithCache()
@@ -195,7 +195,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = $this->getDownloaderMock(null, $config, $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
@rmdir($cachePath);
}
@@ -265,7 +265,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
}
public function pushUrlProvider()
@@ -329,7 +329,7 @@ class GitDownloaderTest extends TestCase
$config->merge(array('config' => array('github-protocols' => $protocols)));
$downloader = $this->getDownloaderMock(null, $config, $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
}
/**
@@ -360,7 +360,7 @@ class GitDownloaderTest extends TestCase
->will($this->returnValue(1));
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
}
/**
diff --git a/tests/Composer/Test/Downloader/HgDownloaderTest.php b/tests/Composer/Test/Downloader/HgDownloaderTest.php
index c71d463cb..a4219d143 100644
--- a/tests/Composer/Test/Downloader/HgDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/HgDownloaderTest.php
@@ -56,7 +56,7 @@ class HgDownloaderTest extends TestCase
->will($this->returnValue(null));
$downloader = $this->getDownloaderMock();
- $downloader->download($packageMock, '/path');
+ $downloader->install($packageMock, '/path');
}
public function testDownload()
@@ -83,7 +83,7 @@ class HgDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = $this->getDownloaderMock(null, null, $processExecutor);
- $downloader->download($packageMock, 'composerPath');
+ $downloader->install($packageMock, 'composerPath');
}
/**
diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php
index 1b5041d9f..d2b8fb753 100644
--- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php
@@ -138,7 +138,7 @@ class PerforceDownloaderTest extends TestCase
$perforce->expects($this->at(5))->method('syncCodeBase')->with($label);
$perforce->expects($this->at(6))->method('cleanupClientSpec');
$this->downloader->setPerforce($perforce);
- $this->downloader->doDownload($this->package, $this->testPath, 'url');
+ $this->downloader->doInstall($this->package, $this->testPath, 'url');
}
/**
@@ -161,6 +161,6 @@ class PerforceDownloaderTest extends TestCase
$perforce->expects($this->at(5))->method('syncCodeBase')->with($label);
$perforce->expects($this->at(6))->method('cleanupClientSpec');
$this->downloader->setPerforce($perforce);
- $this->downloader->doDownload($this->package, $this->testPath, 'url');
+ $this->downloader->doInstall($this->package, $this->testPath, 'url');
}
}
diff --git a/tests/Composer/Test/Downloader/XzDownloaderTest.php b/tests/Composer/Test/Downloader/XzDownloaderTest.php
index 451592d37..4c2fdb2af 100644
--- a/tests/Composer/Test/Downloader/XzDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/XzDownloaderTest.php
@@ -16,6 +16,7 @@ use Composer\Downloader\XzDownloader;
use Composer\Test\TestCase;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
+use Composer\Util\Loop;
use Composer\Util\HttpDownloader;
class XzDownloaderTest extends TestCase
@@ -66,10 +67,14 @@ class XzDownloaderTest extends TestCase
->method('get')
->with('vendor-dir')
->will($this->returnValue($this->testDir));
- $downloader = new XzDownloader($io, $config, new HttpDownloader($io, $this->getMockBuilder('Composer\Config')->getMock()), null, null, null);
+ $downloader = new XzDownloader($io, $config, $httpDownloader = new HttpDownloader($io, $this->getMockBuilder('Composer\Config')->getMock()), null, null, null);
try {
- $downloader->download($packageMock, $this->getUniqueTmpDirectory());
+ $promise = $downloader->download($packageMock, $this->testDir);
+ $loop = new Loop($httpDownloader);
+ $loop->wait(array($promise));
+ $downloader->install($packageMock, $this->testDir);
+
$this->fail('Download of invalid tarball should throw an exception');
} catch (\RuntimeException $e) {
$this->assertRegexp('/(File format not recognized|Unrecognized archive format)/i', $e->getMessage());
diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php
index 0c1311427..b754af607 100644
--- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php
@@ -17,6 +17,7 @@ use Composer\Package\PackageInterface;
use Composer\Test\TestCase;
use Composer\Util\Filesystem;
use Composer\Util\HttpDownloader;
+use Composer\Util\Loop;
class ZipDownloaderTest extends TestCase
{
@@ -27,6 +28,7 @@ class ZipDownloaderTest extends TestCase
private $prophet;
private $io;
private $config;
+ private $package;
public function setUp()
{
@@ -35,6 +37,7 @@ class ZipDownloaderTest extends TestCase
$this->config = $this->getMockBuilder('Composer\Config')->getMock();
$dlConfig = $this->getMockBuilder('Composer\Config')->getMock();
$this->httpDownloader = new HttpDownloader($this->io, $dlConfig);
+ $this->package = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
}
public function tearDown()
@@ -71,16 +74,15 @@ class ZipDownloaderTest extends TestCase
->with('vendor-dir')
->will($this->returnValue($this->testDir));
- $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock();
- $packageMock->expects($this->any())
+ $this->package->expects($this->any())
->method('getDistUrl')
->will($this->returnValue($distUrl = 'file://'.__FILE__))
;
- $packageMock->expects($this->any())
+ $this->package->expects($this->any())
->method('getDistUrls')
->will($this->returnValue(array($distUrl)))
;
- $packageMock->expects($this->atLeastOnce())
+ $this->package->expects($this->atLeastOnce())
->method('getTransportOptions')
->will($this->returnValue(array()))
;
@@ -90,7 +92,11 @@ class ZipDownloaderTest extends TestCase
$this->setPrivateProperty('hasSystemUnzip', false);
try {
- $downloader->download($packageMock, sys_get_temp_dir().'/composer-zip-test');
+ $promise = $downloader->download($this->package, $path = sys_get_temp_dir().'/composer-zip-test');
+ $loop = new Loop($this->httpDownloader);
+ $loop->wait(array($promise));
+ $downloader->install($this->package, $path);
+
$this->fail('Download of invalid zip files should throw an exception');
} catch (\Exception $e) {
$this->assertContains('is not a zip archive', $e->getMessage());
@@ -119,7 +125,7 @@ class ZipDownloaderTest extends TestCase
->will($this->returnValue(false));
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
/**
@@ -144,7 +150,7 @@ class ZipDownloaderTest extends TestCase
->will($this->throwException(new \ErrorException('Not a directory')));
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
/**
@@ -168,7 +174,7 @@ class ZipDownloaderTest extends TestCase
->will($this->returnValue(true));
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
/**
@@ -189,7 +195,7 @@ class ZipDownloaderTest extends TestCase
->will($this->returnValue(1));
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
public function testSystemUnzipOnlyGood()
@@ -206,7 +212,7 @@ class ZipDownloaderTest extends TestCase
->will($this->returnValue(0));
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
public function testNonWindowsFallbackGood()
@@ -234,7 +240,7 @@ class ZipDownloaderTest extends TestCase
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
/**
@@ -266,7 +272,7 @@ class ZipDownloaderTest extends TestCase
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
public function testWindowsFallbackGood()
@@ -294,7 +300,7 @@ class ZipDownloaderTest extends TestCase
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
/**
@@ -326,7 +332,7 @@ class ZipDownloaderTest extends TestCase
$downloader = new MockedZipDownloader($this->io, $this->config, $this->httpDownloader, null, null, $processExecutor);
$this->setPrivateProperty('zipArchiveObject', $zipArchive, $downloader);
- $downloader->extract('testfile.zip', 'vendor/dir');
+ $downloader->extract($this->package, 'testfile.zip', 'vendor/dir');
}
}
@@ -337,8 +343,13 @@ class MockedZipDownloader extends ZipDownloader
return;
}
- public function extract($file, $path)
+ public function install(PackageInterface $package, $path, $output = true)
{
- parent::extract($file, $path);
+ return;
+ }
+
+ public function extract(PackageInterface $package, $file, $path)
+ {
+ parent::extract($package, $file, $path);
}
}
diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
index 7786e7807..6d812e20a 100644
--- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
+++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php
@@ -101,7 +101,7 @@ class EventDispatcherTest extends TestCase
$composer->setPackage($package);
$composer->setRepositoryManager($this->getRepositoryManagerMockForDevModePassingTest());
- $composer->setInstallationManager($this->getMockBuilder('Composer\Installer\InstallationManager')->getMock());
+ $composer->setInstallationManager($this->getMockBuilder('Composer\Installer\InstallationManager')->disableOriginalConstructor()->getMock());
$dispatcher = new EventDispatcher(
$composer,
diff --git a/tests/Composer/Test/Installer/InstallationManagerTest.php b/tests/Composer/Test/Installer/InstallationManagerTest.php
index 86e860bc2..407a5b10f 100644
--- a/tests/Composer/Test/Installer/InstallationManagerTest.php
+++ b/tests/Composer/Test/Installer/InstallationManagerTest.php
@@ -13,6 +13,7 @@
namespace Composer\Test\Installer;
use Composer\Installer\InstallationManager;
+use Composer\Installer\NoopInstaller;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
@@ -21,9 +22,11 @@ use PHPUnit\Framework\TestCase;
class InstallationManagerTest extends TestCase
{
protected $repository;
+ protected $loop;
public function setUp()
{
+ $this->loop = $this->getMockBuilder('Composer\Util\Loop')->disableOriginalConstructor()->getMock();
$this->repository = $this->getMockBuilder('Composer\Repository\InstalledRepositoryInterface')->getMock();
}
@@ -38,7 +41,7 @@ class InstallationManagerTest extends TestCase
return $arg === 'vendor';
}));
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$this->assertSame($installer, $manager->getInstaller('vendor'));
@@ -67,7 +70,7 @@ class InstallationManagerTest extends TestCase
return $arg === 'vendor';
}));
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$this->assertSame($installer, $manager->getInstaller('vendor'));
@@ -80,16 +83,21 @@ class InstallationManagerTest extends TestCase
public function testExecute()
{
$manager = $this->getMockBuilder('Composer\Installer\InstallationManager')
+ ->setConstructorArgs(array($this->loop))
->setMethods(array('install', 'update', 'uninstall'))
->getMock();
- $installOperation = new InstallOperation($this->createPackageMock());
- $removeOperation = new UninstallOperation($this->createPackageMock());
+ $installOperation = new InstallOperation($package = $this->createPackageMock());
+ $removeOperation = new UninstallOperation($package);
$updateOperation = new UpdateOperation(
- $this->createPackageMock(),
- $this->createPackageMock()
+ $package,
+ $package
);
+ $package->expects($this->any())
+ ->method('getType')
+ ->will($this->returnValue('library'));
+
$manager
->expects($this->once())
->method('install')
@@ -103,6 +111,7 @@ class InstallationManagerTest extends TestCase
->method('update')
->with($this->repository, $updateOperation);
+ $manager->addInstaller(new NoopInstaller());
$manager->execute($this->repository, $installOperation);
$manager->execute($this->repository, $removeOperation);
$manager->execute($this->repository, $updateOperation);
@@ -111,7 +120,7 @@ class InstallationManagerTest extends TestCase
public function testInstall()
{
$installer = $this->createInstallerMock();
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$package = $this->createPackageMock();
@@ -139,7 +148,7 @@ class InstallationManagerTest extends TestCase
public function testUpdateWithEqualTypes()
{
$installer = $this->createInstallerMock();
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$initial = $this->createPackageMock();
@@ -173,18 +182,17 @@ class InstallationManagerTest extends TestCase
{
$libInstaller = $this->createInstallerMock();
$bundleInstaller = $this->createInstallerMock();
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($libInstaller);
$manager->addInstaller($bundleInstaller);
$initial = $this->createPackageMock();
- $target = $this->createPackageMock();
- $operation = new UpdateOperation($initial, $target, 'test');
-
$initial
->expects($this->once())
->method('getType')
->will($this->returnValue('library'));
+
+ $target = $this->createPackageMock();
$target
->expects($this->once())
->method('getType')
@@ -213,13 +221,14 @@ class InstallationManagerTest extends TestCase
->method('install')
->with($this->repository, $target);
+ $operation = new UpdateOperation($initial, $target, 'test');
$manager->update($this->repository, $operation);
}
public function testUninstall()
{
$installer = $this->createInstallerMock();
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$package = $this->createPackageMock();
@@ -249,7 +258,7 @@ class InstallationManagerTest extends TestCase
$installer = $this->getMockBuilder('Composer\Installer\LibraryInstaller')
->disableOriginalConstructor()
->getMock();
- $manager = new InstallationManager();
+ $manager = new InstallationManager($this->loop);
$manager->addInstaller($installer);
$package = $this->createPackageMock();
@@ -281,7 +290,9 @@ class InstallationManagerTest extends TestCase
private function createPackageMock()
{
- return $this->getMockBuilder('Composer\Package\PackageInterface')
+ $mock = $this->getMockBuilder('Composer\Package\PackageInterface')
->getMock();
+
+ return $mock;
}
}
diff --git a/tests/Composer/Test/Installer/LibraryInstallerTest.php b/tests/Composer/Test/Installer/LibraryInstallerTest.php
index 772bb05c8..672f8eb0a 100644
--- a/tests/Composer/Test/Installer/LibraryInstallerTest.php
+++ b/tests/Composer/Test/Installer/LibraryInstallerTest.php
@@ -113,7 +113,7 @@ class LibraryInstallerTest extends TestCase
$this->dm
->expects($this->once())
- ->method('download')
+ ->method('install')
->with($package, $this->vendorDir.'/some/package');
$this->repository
diff --git a/tests/Composer/Test/Mock/FactoryMock.php b/tests/Composer/Test/Mock/FactoryMock.php
index 47683afcd..fcb93d2cc 100644
--- a/tests/Composer/Test/Mock/FactoryMock.php
+++ b/tests/Composer/Test/Mock/FactoryMock.php
@@ -20,6 +20,7 @@ use Composer\Repository\WritableRepositoryInterface;
use Composer\Installer;
use Composer\IO\IOInterface;
use Composer\Test\TestCase;
+use Composer\Util\Loop;
class FactoryMock extends Factory
{
@@ -39,9 +40,9 @@ class FactoryMock extends Factory
{
}
- protected function createInstallationManager()
+ public function createInstallationManager(Loop $loop)
{
- return new InstallationManagerMock;
+ return new InstallationManagerMock();
}
protected function createDefaultInstallers(Installer\InstallationManager $im, Composer $composer, IOInterface $io)
diff --git a/tests/Composer/Test/Mock/InstallationManagerMock.php b/tests/Composer/Test/Mock/InstallationManagerMock.php
index de1de514b..21e717224 100644
--- a/tests/Composer/Test/Mock/InstallationManagerMock.php
+++ b/tests/Composer/Test/Mock/InstallationManagerMock.php
@@ -17,6 +17,7 @@ use Composer\Repository\RepositoryInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
use Composer\DependencyResolver\Operation\InstallOperation;
+use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
@@ -29,6 +30,18 @@ class InstallationManagerMock extends InstallationManager
private $uninstalled = array();
private $trace = array();
+ public function __construct()
+ {
+
+ }
+
+ public function execute(RepositoryInterface $repo, OperationInterface $operation)
+ {
+ $method = $operation->getJobType();
+ // skipping download() step here for tests
+ $this->$method($repo, $operation);
+ }
+
public function getInstallPath(PackageInterface $package)
{
return '';
diff --git a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php
index b9f08e693..714c9b923 100644
--- a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php
+++ b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php
@@ -16,6 +16,7 @@ use Composer\IO\NullIO;
use Composer\Factory;
use Composer\Package\Archiver\ArchiveManager;
use Composer\Package\PackageInterface;
+use Composer\Util\Loop;
use Composer\Test\Mock\FactoryMock;
class ArchiveManagerTest extends ArchiverTest
@@ -35,9 +36,10 @@ class ArchiveManagerTest extends ArchiverTest
$dm = $factory->createDownloadManager(
$io = new NullIO,
$config = FactoryMock::createConfig(),
- $factory->createHttpDownloader($io, $config)
+ $httpDownloader = $factory->createHttpDownloader($io, $config)
);
- $this->manager = $factory->createArchiveManager($factory->createConfig(), $dm);
+ $loop = new Loop($httpDownloader);
+ $this->manager = $factory->createArchiveManager($factory->createConfig(), $dm, $loop);
$this->targetDir = $this->testDir.'/composer_archiver_tests';
}
diff --git a/tests/Composer/Test/Plugin/PluginInstallerTest.php b/tests/Composer/Test/Plugin/PluginInstallerTest.php
index 01832f94d..633c5ab18 100644
--- a/tests/Composer/Test/Plugin/PluginInstallerTest.php
+++ b/tests/Composer/Test/Plugin/PluginInstallerTest.php
@@ -89,7 +89,7 @@ class PluginInstallerTest extends TestCase
->method('getLocalRepository')
->will($this->returnValue($this->repository));
- $im = $this->getMockBuilder('Composer\Installer\InstallationManager')->getMock();
+ $im = $this->getMockBuilder('Composer\Installer\InstallationManager')->disableOriginalConstructor()->getMock();
$im->expects($this->any())
->method('getInstallPath')
->will($this->returnCallback(function ($package) {