Add parallel download capability to FileDownloader and derivatives
parent
0f2f950cb6
commit
3dfcae99a9
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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(' <warning>Now trying to download from ' . $source . '</warning>');
|
||||
}
|
||||
$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(
|
||||
' <warning>Failed to download '.
|
||||
$package->getPrettyName().
|
||||
' from ' . $source . ': '.
|
||||
$e->getMessage().'</warning>'
|
||||
);
|
||||
|
||||
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(' <warning>Now trying to download from ' . $source . '</warning>');
|
||||
}
|
||||
$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(
|
||||
' <warning>Failed to download '.
|
||||
$package->getPrettyName().
|
||||
' from ' . $source . ': '.
|
||||
$e->getMessage().'</warning>'
|
||||
);
|
||||
}
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>): ", 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 <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>) 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 <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
|
||||
}
|
||||
|
||||
// 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(' (<comment>100%</comment>)', 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 <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
|
||||
}
|
||||
|
||||
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 . " <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>): ", 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');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -38,6 +38,14 @@ class MetapackageInstaller implements InstallerInterface
|
|||
return $repo->hasPackage($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function download(PackageInterface $package, PackageInterface $prevPackage = null)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -40,6 +40,13 @@ class NoopInstaller implements InstallerInterface
|
|||
return $repo->hasPackage($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function download(PackageInterface $package, PackageInterface $prevPackage = null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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')) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Util;
|
||||
|
||||
use Composer\Util\HttpDownloader;
|
||||
use React\Promise\Promise;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 '';
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue