Make installer classes forward promises from downloaders to InstallationManager
parent
816d8e9d1b
commit
5761228068
|
@ -26,6 +26,7 @@ use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
|
|||
use Composer\EventDispatcher\EventDispatcher;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
use Composer\Util\Loop;
|
||||
use React\Promise\PromiseInterface;
|
||||
|
||||
/**
|
||||
* Package operation manager.
|
||||
|
@ -296,8 +297,8 @@ class InstallationManager
|
|||
$io = $this->io;
|
||||
|
||||
$promise = $installer->prepare($opType, $package, $initialPackage);
|
||||
if (null === $promise) {
|
||||
$promise = new \React\Promise\Promise(function ($resolve, $reject) { $resolve(); });
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$promise = $promise->then(function () use ($opType, $installManager, $repo, $operation) {
|
||||
|
|
|
@ -19,6 +19,7 @@ use Composer\Package\PackageInterface;
|
|||
use Composer\Util\Filesystem;
|
||||
use Composer\Util\Silencer;
|
||||
use Composer\Util\Platform;
|
||||
use React\Promise\PromiseInterface;
|
||||
|
||||
/**
|
||||
* Package installation manager.
|
||||
|
@ -131,11 +132,19 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
$this->binaryInstaller->removeBinaries($package);
|
||||
}
|
||||
|
||||
$this->installCode($package);
|
||||
$this->binaryInstaller->installBinaries($package, $this->getInstallPath($package));
|
||||
if (!$repo->hasPackage($package)) {
|
||||
$repo->addPackage(clone $package);
|
||||
$promise = $this->installCode($package);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$binaryInstaller = $this->binaryInstaller;
|
||||
$installPath = $this->getInstallPath($package);
|
||||
return $promise->then(function () use ($binaryInstaller, $installPath, $package, $repo) {
|
||||
$binaryInstaller->installBinaries($package, $installPath);
|
||||
if (!$repo->hasPackage($package)) {
|
||||
$repo->addPackage(clone $package);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,12 +159,20 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
$this->initializeVendorDir();
|
||||
|
||||
$this->binaryInstaller->removeBinaries($initial);
|
||||
$this->updateCode($initial, $target);
|
||||
$this->binaryInstaller->installBinaries($target, $this->getInstallPath($target));
|
||||
$repo->removePackage($initial);
|
||||
if (!$repo->hasPackage($target)) {
|
||||
$repo->addPackage(clone $target);
|
||||
$promise = $this->updateCode($initial, $target);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$binaryInstaller = $this->binaryInstaller;
|
||||
$installPath = $this->getInstallPath($target);
|
||||
return $promise->then(function () use ($binaryInstaller, $installPath, $target, $initial, $repo) {
|
||||
$binaryInstaller->installBinaries($target, $installPath);
|
||||
$repo->removePackage($initial);
|
||||
if (!$repo->hasPackage($target)) {
|
||||
$repo->addPackage(clone $target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,17 +184,25 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
throw new \InvalidArgumentException('Package is not installed: '.$package);
|
||||
}
|
||||
|
||||
$this->removeCode($package);
|
||||
$this->binaryInstaller->removeBinaries($package);
|
||||
$repo->removePackage($package);
|
||||
|
||||
$downloadPath = $this->getPackageBasePath($package);
|
||||
if (strpos($package->getName(), '/')) {
|
||||
$packageVendorDir = dirname($downloadPath);
|
||||
if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
|
||||
Silencer::call('rmdir', $packageVendorDir);
|
||||
}
|
||||
$promise = $this->removeCode($package);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$binaryInstaller = $this->binaryInstaller;
|
||||
$downloadPath = $this->getPackageBasePath($package);
|
||||
$filesystem = $this->filesystem;
|
||||
return $promise->then(function () use ($binaryInstaller, $filesystem, $downloadPath, $package, $repo) {
|
||||
$binaryInstaller->removeBinaries($package);
|
||||
$repo->removePackage($package);
|
||||
|
||||
if (strpos($package->getName(), '/')) {
|
||||
$packageVendorDir = dirname($downloadPath);
|
||||
if (is_dir($packageVendorDir) && $filesystem->isDirEmpty($packageVendorDir)) {
|
||||
Silencer::call('rmdir', $packageVendorDir);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,7 +252,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
protected function installCode(PackageInterface $package)
|
||||
{
|
||||
$downloadPath = $this->getInstallPath($package);
|
||||
$this->downloadManager->install($package, $downloadPath);
|
||||
return $this->downloadManager->install($package, $downloadPath);
|
||||
}
|
||||
|
||||
protected function updateCode(PackageInterface $initial, PackageInterface $target)
|
||||
|
@ -240,21 +265,31 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
|
|||
if (substr($initialDownloadPath, 0, strlen($targetDownloadPath)) === $targetDownloadPath
|
||||
|| substr($targetDownloadPath, 0, strlen($initialDownloadPath)) === $initialDownloadPath
|
||||
) {
|
||||
$this->removeCode($initial);
|
||||
$this->installCode($target);
|
||||
$promise = $this->removeCode($initial);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
return;
|
||||
$self = $this;
|
||||
return $promise->then(function () use ($self, $target) {
|
||||
$reflMethod = new \ReflectionMethod($self, 'installCode');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
// equivalent of $this->installCode($target) with php 5.3 support
|
||||
// TODO remove this once 5.3 support is dropped
|
||||
return $reflMethod->invoke($self, $target);
|
||||
});
|
||||
}
|
||||
|
||||
$this->filesystem->rename($initialDownloadPath, $targetDownloadPath);
|
||||
}
|
||||
$this->downloadManager->update($initial, $target, $targetDownloadPath);
|
||||
return $this->downloadManager->update($initial, $target, $targetDownloadPath);
|
||||
}
|
||||
|
||||
protected function removeCode(PackageInterface $package)
|
||||
{
|
||||
$downloadPath = $this->getPackageBasePath($package);
|
||||
$this->downloadManager->remove($package, $downloadPath);
|
||||
return $this->downloadManager->remove($package, $downloadPath);
|
||||
}
|
||||
|
||||
protected function initializeVendorDir()
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Composer;
|
|||
use Composer\IO\IOInterface;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use React\Promise\PromiseInterface;
|
||||
|
||||
/**
|
||||
* Installer for plugin packages
|
||||
|
@ -65,15 +66,20 @@ class PluginInstaller extends LibraryInstaller
|
|||
*/
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||
{
|
||||
parent::install($repo, $package);
|
||||
try {
|
||||
$this->composer->getPluginManager()->registerPackage($package, true);
|
||||
} catch (\Exception $e) {
|
||||
// Rollback installation
|
||||
$this->io->writeError('Plugin initialization failed ('.$e->getMessage().'), uninstalling plugin');
|
||||
parent::uninstall($repo, $package);
|
||||
throw $e;
|
||||
$promise = parent::install($repo, $package);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$pluginManager = $this->composer->getPluginManager();
|
||||
$self = $this;
|
||||
return $promise->then(function () use ($self, $pluginManager, $package, $repo) {
|
||||
try {
|
||||
$pluginManager->registerPackage($package, true);
|
||||
} catch (\Exception $e) {
|
||||
$self->rollbackInstall($e, $repo, $package);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,22 +87,38 @@ class PluginInstaller extends LibraryInstaller
|
|||
*/
|
||||
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
|
||||
{
|
||||
parent::update($repo, $initial, $target);
|
||||
|
||||
try {
|
||||
$this->composer->getPluginManager()->deactivatePackage($initial, true);
|
||||
$this->composer->getPluginManager()->registerPackage($target, true);
|
||||
} catch (\Exception $e) {
|
||||
// Rollback installation
|
||||
$this->io->writeError('Plugin initialization failed, uninstalling plugin');
|
||||
parent::uninstall($repo, $target);
|
||||
throw $e;
|
||||
$promise = parent::update($repo, $initial, $target);
|
||||
if (!$promise instanceof PromiseInterface) {
|
||||
$promise = \React\Promise\resolve();
|
||||
}
|
||||
|
||||
$pluginManager = $this->composer->getPluginManager();
|
||||
$self = $this;
|
||||
return $promise->then(function () use ($self, $pluginManager, $initial, $target, $repo) {
|
||||
try {
|
||||
$pluginManager->deactivatePackage($initial, true);
|
||||
$pluginManager->registerPackage($target, true);
|
||||
} catch (\Exception $e) {
|
||||
$self->rollbackInstall($e, $repo, $target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||
{
|
||||
$this->composer->getPluginManager()->uninstallPackage($package, true);
|
||||
|
||||
return parent::uninstall($repo, $package);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO v3 should make this private once we can drop PHP 5.3 support
|
||||
* @private
|
||||
*/
|
||||
public function rollbackInstall(\Exception $e, InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||
{
|
||||
$this->io->writeError('Plugin initialization failed ('.$e->getMessage().'), uninstalling plugin');
|
||||
parent::uninstall($repo, $package);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class ProjectInstaller implements InstallerInterface
|
|||
*/
|
||||
public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null)
|
||||
{
|
||||
$this->downloadManager->prepare($type, $package, $this->installPath, $prevPackage);
|
||||
return $this->downloadManager->prepare($type, $package, $this->installPath, $prevPackage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +84,7 @@ class ProjectInstaller implements InstallerInterface
|
|||
*/
|
||||
public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null)
|
||||
{
|
||||
$this->downloadManager->cleanup($type, $package, $this->installPath, $prevPackage);
|
||||
return $this->downloadManager->cleanup($type, $package, $this->installPath, $prevPackage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +92,7 @@ class ProjectInstaller implements InstallerInterface
|
|||
*/
|
||||
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
|
||||
{
|
||||
$this->downloadManager->install($package, $this->installPath);
|
||||
return $this->downloadManager->install($package, $this->installPath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue