Execute operations in batches to make sure plugins install in the expected order
parent
9f380d606c
commit
87a0fc5506
|
@ -62,6 +62,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
||||||
} while (is_dir($temporaryDir));
|
} while (is_dir($temporaryDir));
|
||||||
|
|
||||||
$this->addCleanupPath($package, $temporaryDir);
|
$this->addCleanupPath($package, $temporaryDir);
|
||||||
|
$this->addCleanupPath($package, $path);
|
||||||
|
|
||||||
$this->filesystem->ensureDirectoryExists($temporaryDir);
|
$this->filesystem->ensureDirectoryExists($temporaryDir);
|
||||||
$fileName = $this->getFileName($package, $path);
|
$fileName = $this->getFileName($package, $path);
|
||||||
|
@ -77,6 +78,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
||||||
$filesystem->removeDirectory($path);
|
$filesystem->removeDirectory($path);
|
||||||
$filesystem->removeDirectory($temporaryDir);
|
$filesystem->removeDirectory($temporaryDir);
|
||||||
$self->removeCleanupPath($package, $temporaryDir);
|
$self->removeCleanupPath($package, $temporaryDir);
|
||||||
|
$self->removeCleanupPath($package, $path);
|
||||||
};
|
};
|
||||||
|
|
||||||
$promise = null;
|
$promise = null;
|
||||||
|
@ -142,6 +144,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
||||||
|
|
||||||
$filesystem->removeDirectory($temporaryDir);
|
$filesystem->removeDirectory($temporaryDir);
|
||||||
$self->removeCleanupPath($package, $temporaryDir);
|
$self->removeCleanupPath($package, $temporaryDir);
|
||||||
|
$self->removeCleanupPath($package, $path);
|
||||||
}, function ($e) use ($cleanup) {
|
}, function ($e) use ($cleanup) {
|
||||||
$cleanup();
|
$cleanup();
|
||||||
|
|
||||||
|
|
|
@ -272,73 +272,23 @@ class InstallationManager
|
||||||
$this->loop->wait($promises);
|
$this->loop->wait($promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($operations as $index => $operation) {
|
// execute operations in batches to make sure every plugin is installed in the
|
||||||
$opType = $operation->getOperationType();
|
// right order and activated before the packages depending on it are installed
|
||||||
|
while ($operations) {
|
||||||
|
$batch = array();
|
||||||
|
|
||||||
// ignoring alias ops as they don't need to execute anything
|
foreach ($operations as $index => $operation) {
|
||||||
if (!in_array($opType, array('update', 'install', 'uninstall'))) {
|
unset($operations[$index]);
|
||||||
// output alias ops in debug verbosity as they have no output otherwise
|
$batch[$index] = $operation;
|
||||||
if ($this->io->isDebug()) {
|
if (in_array($operation->getOperationType(), array('update', 'install'), true)) {
|
||||||
$this->io->writeError(' - ' . $operation->show(false));
|
$package = $operation->getOperationType() === 'update' ? $operation->getTargetPackage() : $operation->getPackage();
|
||||||
|
if ($package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$this->$opType($repo, $operation);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($opType === 'update') {
|
$this->executeBatch($repo, $batch, $cleanupPromises, $devMode, $runScripts);
|
||||||
$package = $operation->getTargetPackage();
|
|
||||||
$initialPackage = $operation->getInitialPackage();
|
|
||||||
} else {
|
|
||||||
$package = $operation->getPackage();
|
|
||||||
$initialPackage = null;
|
|
||||||
}
|
|
||||||
$installer = $this->getInstaller($package->getType());
|
|
||||||
|
|
||||||
$event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($opType);
|
|
||||||
if (defined($event) && $runScripts && $this->eventDispatcher) {
|
|
||||||
$this->eventDispatcher->dispatchPackageEvent(constant($event), $devMode, $repo, $operations, $operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dispatcher = $this->eventDispatcher;
|
|
||||||
$installManager = $this;
|
|
||||||
$loop = $this->loop;
|
|
||||||
$io = $this->io;
|
|
||||||
|
|
||||||
$promise = $installer->prepare($opType, $package, $initialPackage);
|
|
||||||
if (!$promise instanceof PromiseInterface) {
|
|
||||||
$promise = \React\Promise\resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
$promise = $promise->then(function () use ($opType, $installManager, $repo, $operation) {
|
|
||||||
return $installManager->$opType($repo, $operation);
|
|
||||||
})->then($cleanupPromises[$index])
|
|
||||||
->then(function () use ($opType, $runScripts, $dispatcher, $installManager, $devMode, $repo, $operations, $operation) {
|
|
||||||
$repo->write($devMode, $installManager);
|
|
||||||
|
|
||||||
$event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($opType);
|
|
||||||
if (defined($event) && $runScripts && $dispatcher) {
|
|
||||||
$dispatcher->dispatchPackageEvent(constant($event), $devMode, $repo, $operations, $operation);
|
|
||||||
}
|
|
||||||
}, function ($e) use ($opType, $package, $io) {
|
|
||||||
$io->writeError(' <error>' . ucfirst($opType) .' of '.$package->getPrettyName().' failed</error>');
|
|
||||||
|
|
||||||
throw $e;
|
|
||||||
});
|
|
||||||
|
|
||||||
$promises[] = $promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute all prepare => installs/updates/removes => cleanup steps
|
|
||||||
if (!empty($promises)) {
|
|
||||||
$progress = null;
|
|
||||||
if ($io instanceof ConsoleIO && !$io->isDebug()) {
|
|
||||||
$progress = $io->getProgressBar();
|
|
||||||
}
|
|
||||||
$this->loop->wait($promises, $progress);
|
|
||||||
if ($progress) {
|
|
||||||
$progress->clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$runCleanup();
|
$runCleanup();
|
||||||
|
@ -366,6 +316,77 @@ class InstallationManager
|
||||||
$repo->write($devMode, $this);
|
$repo->write($devMode, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executeBatch(RepositoryInterface $repo, array $operations, array $cleanupPromises, $devMode, $runScripts)
|
||||||
|
{
|
||||||
|
foreach ($operations as $index => $operation) {
|
||||||
|
$opType = $operation->getOperationType();
|
||||||
|
|
||||||
|
// ignoring alias ops as they don't need to execute anything
|
||||||
|
if (!in_array($opType, array('update', 'install', 'uninstall'))) {
|
||||||
|
// output alias ops in debug verbosity as they have no output otherwise
|
||||||
|
if ($this->io->isDebug()) {
|
||||||
|
$this->io->writeError(' - ' . $operation->show(false));
|
||||||
|
}
|
||||||
|
$this->$opType($repo, $operation);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opType === 'update') {
|
||||||
|
$package = $operation->getTargetPackage();
|
||||||
|
$initialPackage = $operation->getInitialPackage();
|
||||||
|
} else {
|
||||||
|
$package = $operation->getPackage();
|
||||||
|
$initialPackage = null;
|
||||||
|
}
|
||||||
|
$installer = $this->getInstaller($package->getType());
|
||||||
|
|
||||||
|
$event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($opType);
|
||||||
|
if (defined($event) && $runScripts && $this->eventDispatcher) {
|
||||||
|
$this->eventDispatcher->dispatchPackageEvent(constant($event), $devMode, $repo, $operations, $operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dispatcher = $this->eventDispatcher;
|
||||||
|
$installManager = $this;
|
||||||
|
$io = $this->io;
|
||||||
|
|
||||||
|
$promise = $installer->prepare($opType, $package, $initialPackage);
|
||||||
|
if (!$promise instanceof PromiseInterface) {
|
||||||
|
$promise = \React\Promise\resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
$promise = $promise->then(function () use ($opType, $installManager, $repo, $operation) {
|
||||||
|
return $installManager->$opType($repo, $operation);
|
||||||
|
})->then($cleanupPromises[$index])
|
||||||
|
->then(function () use ($opType, $runScripts, $dispatcher, $installManager, $devMode, $repo, $operations, $operation) {
|
||||||
|
$repo->write($devMode, $installManager);
|
||||||
|
|
||||||
|
$event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($opType);
|
||||||
|
if (defined($event) && $runScripts && $dispatcher) {
|
||||||
|
$dispatcher->dispatchPackageEvent(constant($event), $devMode, $repo, $operations, $operation);
|
||||||
|
}
|
||||||
|
}, function ($e) use ($opType, $package, $io) {
|
||||||
|
$io->writeError(' <error>' . ucfirst($opType) .' of '.$package->getPrettyName().' failed</error>');
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
});
|
||||||
|
|
||||||
|
$promises[] = $promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute all prepare => installs/updates/removes => cleanup steps
|
||||||
|
if (!empty($promises)) {
|
||||||
|
$progress = null;
|
||||||
|
if ($io instanceof ConsoleIO && !$io->isDebug() && count($promises) > 1) {
|
||||||
|
$progress = $io->getProgressBar();
|
||||||
|
}
|
||||||
|
$this->loop->wait($promises, $progress);
|
||||||
|
if ($progress) {
|
||||||
|
$progress->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes install operation.
|
* Executes install operation.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue