function Installer::run
Run installation (or update)
@phpstan-return self::ERROR_*
Return value
int 0 on success or a positive error code on failure
Throws
\Exception
File
-
vendor/
composer/ composer/ src/ Composer/ Installer.php, line 244
Class
- Installer
- @author Jordi Boggiano <j.boggiano@seld.be> @author Beau Simensen <beau@dflydev.com> @author Konstantin Kudryashov <ever.zet@gmail.com> @author Nils Adermann <naderman@naderman.de>
Namespace
ComposerCode
public function run() : int {
// Disable GC to save CPU cycles, as the dependency solver can create hundreds of thousands
// of PHP objects, the GC can spend quite some time walking the tree of references looking
// for stuff to collect while there is nothing to collect. This slows things down dramatically
// and turning it off results in much better performance. Do not try this at home however.
gc_collect_cycles();
gc_disable();
if ($this->updateAllowList !== null && $this->updateMirrors) {
throw new \RuntimeException("The installer options updateMirrors and updateAllowList are mutually exclusive.");
}
$isFreshInstall = $this->repositoryManager
->getLocalRepository()
->isFresh();
// Force update if there is no lock file present
if (!$this->update && !$this->locker
->isLocked()) {
$this->io
->writeError('<warning>No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.</warning>');
$this->update = true;
}
if ($this->dryRun) {
$this->verbose = true;
$this->runScripts = false;
$this->executeOperations = false;
$this->writeLock = false;
$this->dumpAutoloader = false;
$this->mockLocalRepositories($this->repositoryManager);
}
if ($this->downloadOnly) {
$this->dumpAutoloader = false;
}
if ($this->update && !$this->install) {
$this->dumpAutoloader = false;
}
if ($this->runScripts) {
Platform::putEnv('COMPOSER_DEV_MODE', $this->devMode ? '1' : '0');
// dispatch pre event
// should we treat this more strictly as running an update and then running an install, triggering events multiple times?
$eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
$this->eventDispatcher
->dispatchScript($eventName, $this->devMode);
}
$this->downloadManager
->setPreferSource($this->preferSource);
$this->downloadManager
->setPreferDist($this->preferDist);
$localRepo = $this->repositoryManager
->getLocalRepository();
try {
if ($this->update) {
$res = $this->doUpdate($localRepo, $this->install);
}
else {
$res = $this->doInstall($localRepo);
}
if ($res !== 0) {
return $res;
}
} catch (\Exception $e) {
if ($this->executeOperations && $this->install && $this->config
->get('notify-on-install')) {
$this->installationManager
->notifyInstalls($this->io);
}
throw $e;
}
if ($this->executeOperations && $this->install && $this->config
->get('notify-on-install')) {
$this->installationManager
->notifyInstalls($this->io);
}
if ($this->update) {
$installedRepo = new InstalledRepository([
$this->locker
->getLockedRepository($this->devMode),
$this->createPlatformRepo(false),
new RootPackageRepository(clone $this->package),
]);
if ($isFreshInstall) {
$this->suggestedPackagesReporter
->addSuggestionsFromPackage($this->package);
}
$this->suggestedPackagesReporter
->outputMinimalistic($installedRepo);
}
// Find abandoned packages and warn user
$lockedRepository = $this->locker
->getLockedRepository(true);
foreach ($lockedRepository->getPackages() as $package) {
if (!$package instanceof CompletePackage || !$package->isAbandoned()) {
continue;
}
$replacement = is_string($package->getReplacementPackage()) ? 'Use ' . $package->getReplacementPackage() . ' instead' : 'No replacement was suggested';
$this->io
->writeError(sprintf("<warning>Package %s is abandoned, you should avoid using it. %s.</warning>", $package->getPrettyName(), $replacement));
}
if ($this->dumpAutoloader) {
// write autoloader
if ($this->optimizeAutoloader) {
$this->io
->writeError('<info>Generating optimized autoload files</info>');
}
else {
$this->io
->writeError('<info>Generating autoload files</info>');
}
$this->autoloadGenerator
->setClassMapAuthoritative($this->classMapAuthoritative);
$this->autoloadGenerator
->setApcu($this->apcuAutoloader, $this->apcuAutoloaderPrefix);
$this->autoloadGenerator
->setRunScripts($this->runScripts);
$this->autoloadGenerator
->setPlatformRequirementFilter($this->platformRequirementFilter);
$this->autoloadGenerator
->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader, null, $this->locker);
}
if ($this->install && $this->executeOperations) {
// force binaries re-generation in case they are missing
foreach ($localRepo->getPackages() as $package) {
$this->installationManager
->ensureBinariesPresence($package);
}
}
$fundEnv = Platform::getEnv('COMPOSER_FUND');
$showFunding = true;
if (is_numeric($fundEnv)) {
$showFunding = intval($fundEnv) !== 0;
}
if ($showFunding) {
$fundingCount = 0;
foreach ($localRepo->getPackages() as $package) {
if ($package instanceof CompletePackageInterface && !$package instanceof AliasPackage && $package->getFunding()) {
$fundingCount++;
}
}
if ($fundingCount > 0) {
$this->io
->writeError([
sprintf("<info>%d package%s you are using %s looking for funding.</info>", $fundingCount, 1 === $fundingCount ? '' : 's', 1 === $fundingCount ? 'is' : 'are'),
'<info>Use the `composer fund` command to find out more!</info>',
]);
}
}
if ($this->runScripts) {
// dispatch post event
$eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
$this->eventDispatcher
->dispatchScript($eventName, $this->devMode);
}
// re-enable GC except on HHVM which triggers a warning here
if (!defined('HHVM_VERSION')) {
gc_enable();
}
if ($this->audit) {
if ($this->update && !$this->install) {
$packages = $lockedRepository->getCanonicalPackages();
$target = 'locked';
}
else {
$packages = $localRepo->getCanonicalPackages();
$target = 'installed';
}
if (count($packages) > 0) {
try {
$auditor = new Auditor();
$repoSet = new RepositorySet();
foreach ($this->repositoryManager
->getRepositories() as $repo) {
$repoSet->addRepository($repo);
}
$auditConfig = $this->config
->get('audit');
return $auditor->audit($this->io, $repoSet, $packages, $this->auditFormat, true, $auditConfig['ignore'] ?? [], $auditConfig['abandoned'] ?? Auditor::ABANDONED_FAIL) > 0 && $this->errorOnAudit ? self::ERROR_AUDIT_FAILED : 0;
} catch (TransportException $e) {
$this->io
->error('Failed to audit ' . $target . ' packages.');
if ($this->io
->isVerbose()) {
$this->io
->error('[' . get_class($e) . '] ' . $e->getMessage());
}
}
}
else {
$this->io
->writeError('No ' . $target . ' packages - skipping audit.');
}
}
return 0;
}