class Installer
Same name in this branch
- 11.1.x vendor/composer/installers/src/Composer/Installers/Installer.php \Composer\Installers\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>
Hierarchy
- class \Composer\Installer
Expanded class hierarchy of Installer
7 files declare their use of Installer
- Application.php in vendor/
composer/ composer/ src/ Composer/ Console/ Application.php - CreateProjectCommand.php in vendor/
composer/ composer/ src/ Composer/ Command/ CreateProjectCommand.php - InstallCommand.php in vendor/
composer/ composer/ src/ Composer/ Command/ InstallCommand.php - Plugin.php in vendor/
php-http/ discovery/ src/ Composer/ Plugin.php - RemoveCommand.php in vendor/
composer/ composer/ src/ Composer/ Command/ RemoveCommand.php
File
-
vendor/
composer/ composer/ src/ Composer/ Installer.php, line 74
Namespace
ComposerView source
class Installer {
public const ERROR_NONE = 0;
// no error/success state
public const ERROR_GENERIC_FAILURE = 1;
public const ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE = 3;
public const ERROR_LOCK_FILE_INVALID = 4;
// used/declared in SolverProblemsException, carried over here for completeness
public const ERROR_DEPENDENCY_RESOLUTION_FAILED = 2;
public const ERROR_AUDIT_FAILED = 5;
// technically exceptions are thrown with various status codes >400, but the process exit code is normalized to 100
public const ERROR_TRANSPORT_EXCEPTION = 100;
/**
* @var IOInterface
*/
protected $io;
/**
* @var Config
*/
protected $config;
/**
* @var RootPackageInterface&BasePackage
*/
protected $package;
// TODO can we get rid of the below and just use the package itself?
/**
* @var RootPackageInterface&BasePackage
*/
protected $fixedRootPackage;
/**
* @var DownloadManager
*/
protected $downloadManager;
/**
* @var RepositoryManager
*/
protected $repositoryManager;
/**
* @var Locker
*/
protected $locker;
/**
* @var InstallationManager
*/
protected $installationManager;
/**
* @var EventDispatcher
*/
protected $eventDispatcher;
/**
* @var AutoloadGenerator
*/
protected $autoloadGenerator;
/** @var bool */
protected $preferSource = false;
/** @var bool */
protected $preferDist = false;
/** @var bool */
protected $optimizeAutoloader = false;
/** @var bool */
protected $classMapAuthoritative = false;
/** @var bool */
protected $apcuAutoloader = false;
/** @var string|null */
protected $apcuAutoloaderPrefix = null;
/** @var bool */
protected $devMode = false;
/** @var bool */
protected $dryRun = false;
/** @var bool */
protected $downloadOnly = false;
/** @var bool */
protected $verbose = false;
/** @var bool */
protected $update = false;
/** @var bool */
protected $install = true;
/** @var bool */
protected $dumpAutoloader = true;
/** @var bool */
protected $runScripts = true;
/** @var bool */
protected $preferStable = false;
/** @var bool */
protected $preferLowest = false;
/** @var bool */
protected $minimalUpdate = false;
/** @var bool */
protected $writeLock;
/** @var bool */
protected $executeOperations = true;
/** @var bool */
protected $audit = true;
/** @var bool */
protected $errorOnAudit = false;
/** @var Auditor::FORMAT_* */
protected $auditFormat = Auditor::FORMAT_SUMMARY;
/** @var list<string> */
private $ignoredTypes = [
'php-ext',
'php-ext-zend',
];
/** @var list<string>|null */
private $allowedTypes = null;
/** @var bool */
protected $updateMirrors = false;
/**
* Array of package names/globs flagged for update
*
* @var non-empty-list<string>|null
*/
protected $updateAllowList = null;
/** @var Request::UPDATE_* */
protected $updateAllowTransitiveDependencies = Request::UPDATE_ONLY_LISTED;
/**
* @var SuggestedPackagesReporter
*/
protected $suggestedPackagesReporter;
/**
* @var PlatformRequirementFilterInterface
*/
protected $platformRequirementFilter;
/**
* @var ?RepositoryInterface
*/
protected $additionalFixedRepository;
/** @var array<string, ConstraintInterface> */
protected $temporaryConstraints = [];
/**
* Constructor
*
* @param RootPackageInterface&BasePackage $package
*/
public function __construct(IOInterface $io, Config $config, RootPackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher, AutoloadGenerator $autoloadGenerator) {
$this->io = $io;
$this->config = $config;
$this->package = $package;
$this->downloadManager = $downloadManager;
$this->repositoryManager = $repositoryManager;
$this->locker = $locker;
$this->installationManager = $installationManager;
$this->eventDispatcher = $eventDispatcher;
$this->autoloadGenerator = $autoloadGenerator;
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
$this->platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing();
$this->writeLock = $config->get('lock');
}
/**
* Run installation (or update)
*
* @throws \Exception
* @return int 0 on success or a positive error code on failure
* @phpstan-return self::ERROR_*
*/
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;
}
/**
* @phpstan-return self::ERROR_*
*/
protected function doUpdate(InstalledRepositoryInterface $localRepo, bool $doInstall) : int {
$platformRepo = $this->createPlatformRepo(true);
$aliases = $this->getRootAliases(true);
$lockedRepository = null;
try {
if ($this->locker
->isLocked()) {
$lockedRepository = $this->locker
->getLockedRepository(true);
}
} catch (\Seld\JsonLint\ParsingException $e) {
if ($this->updateAllowList !== null || $this->updateMirrors) {
// in case we are doing a partial update or updating mirrors, the lock file is needed so we error
throw $e;
}
// otherwise, ignoring parse errors as the lock file will be regenerated from scratch when
// doing a full update
}
if (($this->updateAllowList !== null || $this->updateMirrors) && !$lockedRepository) {
$this->io
->writeError('<error>Cannot update ' . ($this->updateMirrors ? 'lock file information' : 'only a partial set of packages') . ' without a lock file present. Run `composer update` to generate a lock file.</error>', true, IOInterface::QUIET);
return self::ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE;
}
$this->io
->writeError('<info>Loading composer repositories with package information</info>');
// creating repository set
$policy = $this->createPolicy(true, $lockedRepository);
$repositorySet = $this->createRepositorySet(true, $platformRepo, $aliases);
$repositories = $this->repositoryManager
->getRepositories();
foreach ($repositories as $repository) {
$repositorySet->addRepository($repository);
}
if ($lockedRepository) {
$repositorySet->addRepository($lockedRepository);
}
$request = $this->createRequest($this->fixedRootPackage, $platformRepo, $lockedRepository);
$this->requirePackagesForUpdate($request, $lockedRepository, true);
// pass the allow list into the request, so the pool builder can apply it
if ($this->updateAllowList !== null) {
$request->setUpdateAllowList($this->updateAllowList, $this->updateAllowTransitiveDependencies);
}
$pool = $repositorySet->createPool($request, $this->io, $this->eventDispatcher, $this->createPoolOptimizer($policy), $this->ignoredTypes, $this->allowedTypes);
$this->io
->writeError('<info>Updating dependencies</info>');
// solve dependencies
$solver = new Solver($policy, $pool, $this->io);
try {
$lockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$ruleSetSize = $solver->getRuleSetSize();
$solver = null;
} catch (SolverProblemsException $e) {
$err = 'Your requirements could not be resolved to an installable set of packages.';
$prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io
->isVerbose());
$this->io
->writeError('<error>' . $err . '</error>', true, IOInterface::QUIET);
$this->io
->writeError($prettyProblem);
if (!$this->devMode) {
$this->io
->writeError('<warning>Running update with --no-dev does not mean require-dev is ignored, it just means the packages will not be installed. If dev requirements are blocking the update you have to resolve those problems.</warning>', true, IOInterface::QUIET);
}
$ghe = new GithubActionError($this->io);
$ghe->emit($err . "\n" . $prettyProblem);
return max(self::ERROR_GENERIC_FAILURE, $e->getCode());
}
$this->io
->writeError("Analyzed " . count($pool) . " packages to resolve dependencies", true, IOInterface::VERBOSE);
$this->io
->writeError("Analyzed " . $ruleSetSize . " rules to resolve dependencies", true, IOInterface::VERBOSE);
$pool = null;
if (!$lockTransaction->getOperations()) {
$this->io
->writeError('Nothing to modify in lock file');
}
$exitCode = $this->extractDevPackages($lockTransaction, $platformRepo, $aliases, $policy, $lockedRepository);
if ($exitCode !== 0) {
return $exitCode;
}
\Composer\Semver\CompilingMatcher::clear();
// write lock
$platformReqs = $this->extractPlatformRequirements($this->package
->getRequires());
$platformDevReqs = $this->extractPlatformRequirements($this->package
->getDevRequires());
$installsUpdates = $uninstalls = [];
if ($lockTransaction->getOperations()) {
$installNames = $updateNames = $uninstallNames = [];
foreach ($lockTransaction->getOperations() as $operation) {
if ($operation instanceof InstallOperation) {
$installsUpdates[] = $operation;
$installNames[] = $operation->getPackage()
->getPrettyName() . ':' . $operation->getPackage()
->getFullPrettyVersion();
}
elseif ($operation instanceof UpdateOperation) {
// when mirrors/metadata from a package gets updated we do not want to list it as an
// update in the output as it is only an internal lock file metadata update
if ($this->updateMirrors && $operation->getInitialPackage()
->getName() === $operation->getTargetPackage()
->getName() && $operation->getInitialPackage()
->getVersion() === $operation->getTargetPackage()
->getVersion()) {
continue;
}
$installsUpdates[] = $operation;
$updateNames[] = $operation->getTargetPackage()
->getPrettyName() . ':' . $operation->getTargetPackage()
->getFullPrettyVersion();
}
elseif ($operation instanceof UninstallOperation) {
$uninstalls[] = $operation;
$uninstallNames[] = $operation->getPackage()
->getPrettyName();
}
}
if ($this->config
->get('lock')) {
$this->io
->writeError(sprintf("<info>Lock file operations: %d install%s, %d update%s, %d removal%s</info>", count($installNames), 1 === count($installNames) ? '' : 's', count($updateNames), 1 === count($updateNames) ? '' : 's', count($uninstalls), 1 === count($uninstalls) ? '' : 's'));
if ($installNames) {
$this->io
->writeError("Installs: " . implode(', ', $installNames), true, IOInterface::VERBOSE);
}
if ($updateNames) {
$this->io
->writeError("Updates: " . implode(', ', $updateNames), true, IOInterface::VERBOSE);
}
if ($uninstalls) {
$this->io
->writeError("Removals: " . implode(', ', $uninstallNames), true, IOInterface::VERBOSE);
}
}
}
$sortByName = static function ($a, $b) : int {
if ($a instanceof UpdateOperation) {
$a = $a->getTargetPackage()
->getName();
}
else {
$a = $a->getPackage()
->getName();
}
if ($b instanceof UpdateOperation) {
$b = $b->getTargetPackage()
->getName();
}
else {
$b = $b->getPackage()
->getName();
}
return strcmp($a, $b);
};
usort($uninstalls, $sortByName);
usort($installsUpdates, $sortByName);
foreach (array_merge($uninstalls, $installsUpdates) as $operation) {
// collect suggestions
if ($operation instanceof InstallOperation) {
$this->suggestedPackagesReporter
->addSuggestionsFromPackage($operation->getPackage());
}
// output op if lock file is enabled, but alias op only in debug verbosity
if ($this->config
->get('lock') && (false === strpos($operation->getOperationType(), 'Alias') || $this->io
->isDebug())) {
$sourceRepo = '';
if ($this->io
->isVeryVerbose() && false === strpos($operation->getOperationType(), 'Alias')) {
$operationPkg = $operation instanceof UpdateOperation ? $operation->getTargetPackage() : $operation->getPackage();
if ($operationPkg->getRepository() !== null) {
$sourceRepo = ' from ' . $operationPkg->getRepository()
->getRepoName();
}
}
$this->io
->writeError(' - ' . $operation->show(true) . $sourceRepo);
}
}
$updatedLock = $this->locker
->setLockData($lockTransaction->getNewLockPackages(false, $this->updateMirrors), $lockTransaction->getNewLockPackages(true, $this->updateMirrors), $platformReqs, $platformDevReqs, $lockTransaction->getAliases($aliases), $this->package
->getMinimumStability(), $this->package
->getStabilityFlags(), $this->preferStable || $this->package
->getPreferStable(), $this->preferLowest, $this->config
->get('platform') ?: [], $this->writeLock && $this->executeOperations);
if ($updatedLock && $this->writeLock && $this->executeOperations) {
$this->io
->writeError('<info>Writing lock file</info>');
}
if ($doInstall) {
// TODO ensure lock is used from locker as-is, since it may not have been written to disk in case of executeOperations == false
return $this->doInstall($localRepo, true);
}
return 0;
}
/**
* Run the solver a second time on top of the existing update result with only the current result set in the pool
* and see what packages would get removed if we only had the non-dev packages in the solver request
*
* @param array<int, array<string, string>> $aliases
*
* @phpstan-param list<array{package: string, version: string, alias: string, alias_normalized: string}> $aliases
* @phpstan-return self::ERROR_*
*/
protected function extractDevPackages(LockTransaction $lockTransaction, PlatformRepository $platformRepo, array $aliases, PolicyInterface $policy, ?LockArrayRepository $lockedRepository = null) : int {
if (!$this->package
->getDevRequires()) {
return 0;
}
$resultRepo = new ArrayRepository([]);
$loader = new ArrayLoader(null, true);
$dumper = new ArrayDumper();
foreach ($lockTransaction->getNewLockPackages(false) as $pkg) {
$resultRepo->addPackage($loader->load($dumper->dump($pkg)));
}
$repositorySet = $this->createRepositorySet(true, $platformRepo, $aliases);
$repositorySet->addRepository($resultRepo);
$request = $this->createRequest($this->fixedRootPackage, $platformRepo);
$this->requirePackagesForUpdate($request, $lockedRepository, false);
$pool = $repositorySet->createPoolWithAllPackages();
$solver = new Solver($policy, $pool, $this->io);
try {
$nonDevLockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$solver = null;
} catch (SolverProblemsException $e) {
$err = 'Unable to find a compatible set of packages based on your non-dev requirements alone.';
$prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io
->isVerbose(), true);
$this->io
->writeError('<error>' . $err . '</error>', true, IOInterface::QUIET);
$this->io
->writeError('Your requirements can be resolved successfully when require-dev packages are present.');
$this->io
->writeError('You may need to move packages from require-dev or some of their dependencies to require.');
$this->io
->writeError($prettyProblem);
$ghe = new GithubActionError($this->io);
$ghe->emit($err . "\n" . $prettyProblem);
return $e->getCode();
}
$lockTransaction->setNonDevPackages($nonDevLockTransaction);
return 0;
}
/**
* @param bool $alreadySolved Whether the function is called as part of an update command or independently
* @return int exit code
* @phpstan-return self::ERROR_*
*/
protected function doInstall(InstalledRepositoryInterface $localRepo, bool $alreadySolved = false) : int {
if ($this->config
->get('lock')) {
$this->io
->writeError('<info>Installing dependencies from lock file' . ($this->devMode ? ' (including require-dev)' : '') . '</info>');
}
$lockedRepository = $this->locker
->getLockedRepository($this->devMode);
// verify that the lock file works with the current platform repository
// we can skip this part if we're doing this as the second step after an update
if (!$alreadySolved) {
$this->io
->writeError('<info>Verifying lock file contents can be installed on current platform.</info>');
$platformRepo = $this->createPlatformRepo(false);
// creating repository set
$policy = $this->createPolicy(false);
// use aliases from lock file only, so empty root aliases here
$repositorySet = $this->createRepositorySet(false, $platformRepo, [], $lockedRepository);
$repositorySet->addRepository($lockedRepository);
// creating requirements request
$request = $this->createRequest($this->fixedRootPackage, $platformRepo, $lockedRepository);
if (!$this->locker
->isFresh()) {
$this->io
->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.</warning>', true, IOInterface::QUIET);
}
$missingRequirementInfo = $this->locker
->getMissingRequirementInfo($this->package, $this->devMode);
if ($missingRequirementInfo !== []) {
$this->io
->writeError($missingRequirementInfo);
if (!$this->config
->get('allow-missing-requirements')) {
return self::ERROR_LOCK_FILE_INVALID;
}
}
foreach ($lockedRepository->getPackages() as $package) {
$request->fixLockedPackage($package);
}
$rootRequires = $this->package
->getRequires();
if ($this->devMode) {
$rootRequires = array_merge($rootRequires, $this->package
->getDevRequires());
}
foreach ($rootRequires as $link) {
if (PlatformRepository::isPlatformPackage($link->getTarget())) {
$request->requireName($link->getTarget(), $link->getConstraint());
}
}
foreach ($this->locker
->getPlatformRequirements($this->devMode) as $link) {
if (!isset($rootRequires[$link->getTarget()])) {
$request->requireName($link->getTarget(), $link->getConstraint());
}
}
unset($rootRequires, $link);
$pool = $repositorySet->createPool($request, $this->io, $this->eventDispatcher, null, $this->ignoredTypes, $this->allowedTypes);
// solve dependencies
$solver = new Solver($policy, $pool, $this->io);
try {
$lockTransaction = $solver->solve($request, $this->platformRequirementFilter);
$solver = null;
// installing the locked packages on this platform resulted in lock modifying operations, there wasn't a conflict, but the lock file as-is seems to not work on this system
if (0 !== count($lockTransaction->getOperations())) {
$this->io
->writeError('<error>Your lock file cannot be installed on this system without changes. Please run composer update.</error>', true, IOInterface::QUIET);
return self::ERROR_LOCK_FILE_INVALID;
}
} catch (SolverProblemsException $e) {
$err = 'Your lock file does not contain a compatible set of packages. Please run composer update.';
$prettyProblem = $e->getPrettyString($repositorySet, $request, $pool, $this->io
->isVerbose());
$this->io
->writeError('<error>' . $err . '</error>', true, IOInterface::QUIET);
$this->io
->writeError($prettyProblem);
$ghe = new GithubActionError($this->io);
$ghe->emit($err . "\n" . $prettyProblem);
return max(self::ERROR_GENERIC_FAILURE, $e->getCode());
}
}
// TODO in how far do we need to do anything here to ensure dev packages being updated to latest in lock without version change are treated correctly?
$localRepoTransaction = new LocalRepoTransaction($lockedRepository, $localRepo);
$this->eventDispatcher
->dispatchInstallerEvent(InstallerEvents::PRE_OPERATIONS_EXEC, $this->devMode, $this->executeOperations, $localRepoTransaction);
$installs = $updates = $uninstalls = [];
foreach ($localRepoTransaction->getOperations() as $operation) {
if ($operation instanceof InstallOperation) {
$installs[] = $operation->getPackage()
->getPrettyName() . ':' . $operation->getPackage()
->getFullPrettyVersion();
}
elseif ($operation instanceof UpdateOperation) {
$updates[] = $operation->getTargetPackage()
->getPrettyName() . ':' . $operation->getTargetPackage()
->getFullPrettyVersion();
}
elseif ($operation instanceof UninstallOperation) {
$uninstalls[] = $operation->getPackage()
->getPrettyName();
}
}
if ($installs === [] && $updates === [] && $uninstalls === []) {
$this->io
->writeError('Nothing to install, update or remove');
}
else {
$this->io
->writeError(sprintf("<info>Package operations: %d install%s, %d update%s, %d removal%s</info>", count($installs), 1 === count($installs) ? '' : 's', count($updates), 1 === count($updates) ? '' : 's', count($uninstalls), 1 === count($uninstalls) ? '' : 's'));
if ($installs) {
$this->io
->writeError("Installs: " . implode(', ', $installs), true, IOInterface::VERBOSE);
}
if ($updates) {
$this->io
->writeError("Updates: " . implode(', ', $updates), true, IOInterface::VERBOSE);
}
if ($uninstalls) {
$this->io
->writeError("Removals: " . implode(', ', $uninstalls), true, IOInterface::VERBOSE);
}
}
if ($this->executeOperations) {
$localRepo->setDevPackageNames($this->locker
->getDevPackageNames());
$this->installationManager
->execute($localRepo, $localRepoTransaction->getOperations(), $this->devMode, $this->runScripts, $this->downloadOnly);
// see https://github.com/composer/composer/issues/2764
if (count($localRepoTransaction->getOperations()) > 0) {
$vendorDir = $this->config
->get('vendor-dir');
if (is_dir($vendorDir)) {
// suppress errors as this fails sometimes on OSX for no apparent reason
// see https://github.com/composer/composer/issues/4070#issuecomment-129792748
@touch($vendorDir);
}
}
}
else {
foreach ($localRepoTransaction->getOperations() as $operation) {
// output op, but alias op only in debug verbosity
if (false === strpos($operation->getOperationType(), 'Alias') || $this->io
->isDebug()) {
$this->io
->writeError(' - ' . $operation->show(false));
}
}
}
return 0;
}
protected function createPlatformRepo(bool $forUpdate) : PlatformRepository {
if ($forUpdate) {
$platformOverrides = $this->config
->get('platform') ?: [];
}
else {
$platformOverrides = $this->locker
->getPlatformOverrides();
}
return new PlatformRepository([], $platformOverrides);
}
/**
* @param array<int, array<string, string>> $rootAliases
*
* @phpstan-param list<array{package: string, version: string, alias: string, alias_normalized: string}> $rootAliases
*/
private function createRepositorySet(bool $forUpdate, PlatformRepository $platformRepo, array $rootAliases = [], ?RepositoryInterface $lockedRepository = null) : RepositorySet {
if ($forUpdate) {
$minimumStability = $this->package
->getMinimumStability();
$stabilityFlags = $this->package
->getStabilityFlags();
$requires = array_merge($this->package
->getRequires(), $this->package
->getDevRequires());
}
else {
$minimumStability = $this->locker
->getMinimumStability();
$stabilityFlags = $this->locker
->getStabilityFlags();
$requires = [];
foreach ($lockedRepository->getPackages() as $package) {
$constraint = new Constraint('=', $package->getVersion());
$constraint->setPrettyString($package->getPrettyVersion());
$requires[$package->getName()] = $constraint;
}
}
$rootRequires = [];
foreach ($requires as $req => $constraint) {
if ($constraint instanceof Link) {
$constraint = $constraint->getConstraint();
}
// skip platform requirements from the root package to avoid filtering out existing platform packages
if ($this->platformRequirementFilter
->isIgnored($req)) {
continue;
}
elseif ($this->platformRequirementFilter instanceof IgnoreListPlatformRequirementFilter) {
$constraint = $this->platformRequirementFilter
->filterConstraint($req, $constraint);
}
$rootRequires[$req] = $constraint;
}
$this->fixedRootPackage = clone $this->package;
$this->fixedRootPackage
->setRequires([]);
$this->fixedRootPackage
->setDevRequires([]);
$stabilityFlags[$this->package
->getName()] = BasePackage::STABILITIES[VersionParser::parseStability($this->package
->getVersion())];
$repositorySet = new RepositorySet($minimumStability, $stabilityFlags, $rootAliases, $this->package
->getReferences(), $rootRequires, $this->temporaryConstraints);
$repositorySet->addRepository(new RootPackageRepository($this->fixedRootPackage));
$repositorySet->addRepository($platformRepo);
if ($this->additionalFixedRepository) {
// allow using installed repos if needed to avoid warnings about installed repositories being used in the RepositorySet
// see https://github.com/composer/composer/pull/9574
$additionalFixedRepositories = $this->additionalFixedRepository;
if ($additionalFixedRepositories instanceof CompositeRepository) {
$additionalFixedRepositories = $additionalFixedRepositories->getRepositories();
}
else {
$additionalFixedRepositories = [
$additionalFixedRepositories,
];
}
foreach ($additionalFixedRepositories as $additionalFixedRepository) {
if ($additionalFixedRepository instanceof InstalledRepository || $additionalFixedRepository instanceof InstalledRepositoryInterface) {
$repositorySet->allowInstalledRepositories();
break;
}
}
$repositorySet->addRepository($this->additionalFixedRepository);
}
return $repositorySet;
}
private function createPolicy(bool $forUpdate, ?LockArrayRepository $lockedRepo = null) : DefaultPolicy {
$preferStable = null;
$preferLowest = null;
if (!$forUpdate) {
$preferStable = $this->locker
->getPreferStable();
$preferLowest = $this->locker
->getPreferLowest();
}
// old lock file without prefer stable/lowest will return null
// so in this case we use the composer.json info
if (null === $preferStable) {
$preferStable = $this->preferStable || $this->package
->getPreferStable();
}
if (null === $preferLowest) {
$preferLowest = $this->preferLowest;
}
$preferredVersions = null;
if ($forUpdate && $this->minimalUpdate && $this->updateAllowList !== null && $lockedRepo !== null) {
$preferredVersions = [];
foreach ($lockedRepo->getPackages() as $pkg) {
if ($pkg instanceof AliasPackage || in_array($pkg->getName(), $this->updateAllowList, true)) {
continue;
}
$preferredVersions[$pkg->getName()] = $pkg->getVersion();
}
}
return new DefaultPolicy($preferStable, $preferLowest, $preferredVersions);
}
/**
* @param RootPackageInterface&BasePackage $rootPackage
*/
private function createRequest(RootPackageInterface $rootPackage, PlatformRepository $platformRepo, ?LockArrayRepository $lockedRepository = null) : Request {
$request = new Request($lockedRepository);
$request->fixPackage($rootPackage);
if ($rootPackage instanceof RootAliasPackage) {
$request->fixPackage($rootPackage->getAliasOf());
}
$fixedPackages = $platformRepo->getPackages();
if ($this->additionalFixedRepository) {
$fixedPackages = array_merge($fixedPackages, $this->additionalFixedRepository
->getPackages());
}
// fix the version of all platform packages + additionally installed packages
// to prevent the solver trying to remove or update those
// TODO why not replaces?
$provided = $rootPackage->getProvides();
foreach ($fixedPackages as $package) {
// skip platform packages that are provided by the root package
if ($package->getRepository() !== $platformRepo || !isset($provided[$package->getName()]) || !$provided[$package->getName()]
->getConstraint()
->matches(new Constraint('=', $package->getVersion()))) {
$request->fixPackage($package);
}
}
return $request;
}
private function requirePackagesForUpdate(Request $request, ?LockArrayRepository $lockedRepository = null, bool $includeDevRequires = true) : void {
// if we're updating mirrors we want to keep exactly the same versions installed which are in the lock file, but we want current remote metadata
if ($this->updateMirrors) {
$excludedPackages = [];
if (!$includeDevRequires) {
$excludedPackages = array_flip($this->locker
->getDevPackageNames());
}
foreach ($lockedRepository->getPackages() as $lockedPackage) {
// exclude alias packages here as for root aliases, both alias and aliased are
// present in the lock repo and we only want to require the aliased version
if (!$lockedPackage instanceof AliasPackage && !isset($excludedPackages[$lockedPackage->getName()])) {
$request->requireName($lockedPackage->getName(), new Constraint('==', $lockedPackage->getVersion()));
}
}
}
else {
$links = $this->package
->getRequires();
if ($includeDevRequires) {
$links = array_merge($links, $this->package
->getDevRequires());
}
foreach ($links as $link) {
$request->requireName($link->getTarget(), $link->getConstraint());
}
}
}
/**
* @return array<int, array<string, string>>
*
* @phpstan-return list<array{package: string, version: string, alias: string, alias_normalized: string}>
*/
private function getRootAliases(bool $forUpdate) : array {
if ($forUpdate) {
$aliases = $this->package
->getAliases();
}
else {
$aliases = $this->locker
->getAliases();
}
return $aliases;
}
/**
* @param Link[] $links
*
* @return array<string, string>
*/
private function extractPlatformRequirements(array $links) : array {
$platformReqs = [];
foreach ($links as $link) {
if (PlatformRepository::isPlatformPackage($link->getTarget())) {
$platformReqs[$link->getTarget()] = $link->getPrettyConstraint();
}
}
return $platformReqs;
}
/**
* Replace local repositories with InstalledArrayRepository instances
*
* This is to prevent any accidental modification of the existing repos on disk
*/
private function mockLocalRepositories(RepositoryManager $rm) : void {
$packages = [];
foreach ($rm->getLocalRepository()
->getPackages() as $package) {
$packages[(string) $package] = clone $package;
}
foreach ($packages as $key => $package) {
if ($package instanceof AliasPackage) {
$alias = (string) $package->getAliasOf();
$className = get_class($package);
$packages[$key] = new $className($packages[$alias], $package->getVersion(), $package->getPrettyVersion());
}
}
$rm->setLocalRepository(new InstalledArrayRepository($packages));
}
private function createPoolOptimizer(PolicyInterface $policy) : ?PoolOptimizer {
// Not the best architectural decision here, would need to be able
// to configure from the outside of Installer but this is only
// a debugging tool and should never be required in any other use case
if ('0' === Platform::getEnv('COMPOSER_POOL_OPTIMIZER')) {
$this->io
->write('Pool Optimizer was disabled for debugging purposes.', true, IOInterface::DEBUG);
return null;
}
return new PoolOptimizer($policy);
}
/**
* Create Installer
*
* @return Installer
*/
public static function create(IOInterface $io, Composer $composer) : self {
return new static($io, $composer->getConfig(), $composer->getPackage(), $composer->getDownloadManager(), $composer->getRepositoryManager(), $composer->getLocker(), $composer->getInstallationManager(), $composer->getEventDispatcher(), $composer->getAutoloadGenerator());
}
/**
* Packages of those types are ignored, by default php-ext and php-ext-zend are ignored
*
* @param list<string> $types
* @return $this
*/
public function setIgnoredTypes(array $types) : self {
$this->ignoredTypes = $types;
return $this;
}
/**
* Only packages of those types are allowed if set to non-null
*
* @param list<string>|null $types
* @return $this
*/
public function setAllowedTypes(?array $types) : self {
$this->allowedTypes = $types;
return $this;
}
/**
* @return $this
*/
public function setAdditionalFixedRepository(RepositoryInterface $additionalFixedRepository) : self {
$this->additionalFixedRepository = $additionalFixedRepository;
return $this;
}
/**
* @param array<string, ConstraintInterface> $constraints
* @return Installer
*/
public function setTemporaryConstraints(array $constraints) : self {
$this->temporaryConstraints = $constraints;
return $this;
}
/**
* Whether to run in drymode or not
*
* @return Installer
*/
public function setDryRun(bool $dryRun = true) : self {
$this->dryRun = $dryRun;
return $this;
}
/**
* Checks, if this is a dry run (simulation mode).
*/
public function isDryRun() : bool {
return $this->dryRun;
}
/**
* Whether to download only or not.
*
* @return Installer
*/
public function setDownloadOnly(bool $downloadOnly = true) : self {
$this->downloadOnly = $downloadOnly;
return $this;
}
/**
* prefer source installation
*
* @return Installer
*/
public function setPreferSource(bool $preferSource = true) : self {
$this->preferSource = $preferSource;
return $this;
}
/**
* prefer dist installation
*
* @return Installer
*/
public function setPreferDist(bool $preferDist = true) : self {
$this->preferDist = $preferDist;
return $this;
}
/**
* Whether or not generated autoloader are optimized
*
* @return Installer
*/
public function setOptimizeAutoloader(bool $optimizeAutoloader) : self {
$this->optimizeAutoloader = $optimizeAutoloader;
if (!$this->optimizeAutoloader) {
// Force classMapAuthoritative off when not optimizing the
// autoloader
$this->setClassMapAuthoritative(false);
}
return $this;
}
/**
* Whether or not generated autoloader considers the class map
* authoritative.
*
* @return Installer
*/
public function setClassMapAuthoritative(bool $classMapAuthoritative) : self {
$this->classMapAuthoritative = $classMapAuthoritative;
if ($this->classMapAuthoritative) {
// Force optimizeAutoloader when classmap is authoritative
$this->setOptimizeAutoloader(true);
}
return $this;
}
/**
* Whether or not generated autoloader considers APCu caching.
*
* @return Installer
*/
public function setApcuAutoloader(bool $apcuAutoloader, ?string $apcuAutoloaderPrefix = null) : self {
$this->apcuAutoloader = $apcuAutoloader;
$this->apcuAutoloaderPrefix = $apcuAutoloaderPrefix;
return $this;
}
/**
* update packages
*
* @return Installer
*/
public function setUpdate(bool $update) : self {
$this->update = $update;
return $this;
}
/**
* Allows disabling the install step after an update
*
* @return Installer
*/
public function setInstall(bool $install) : self {
$this->install = $install;
return $this;
}
/**
* enables dev packages
*
* @return Installer
*/
public function setDevMode(bool $devMode = true) : self {
$this->devMode = $devMode;
return $this;
}
/**
* set whether to run autoloader or not
*
* This is disabled implicitly when enabling dryRun
*
* @return Installer
*/
public function setDumpAutoloader(bool $dumpAutoloader = true) : self {
$this->dumpAutoloader = $dumpAutoloader;
return $this;
}
/**
* set whether to run scripts or not
*
* This is disabled implicitly when enabling dryRun
*
* @return Installer
* @deprecated Use setRunScripts(false) on the EventDispatcher instance being injected instead
*/
public function setRunScripts(bool $runScripts = true) : self {
$this->runScripts = $runScripts;
return $this;
}
/**
* set the config instance
*
* @return Installer
*/
public function setConfig(Config $config) : self {
$this->config = $config;
return $this;
}
/**
* run in verbose mode
*
* @return Installer
*/
public function setVerbose(bool $verbose = true) : self {
$this->verbose = $verbose;
return $this;
}
/**
* Checks, if running in verbose mode.
*/
public function isVerbose() : bool {
return $this->verbose;
}
/**
* set ignore Platform Package requirements
*
* If this is set to true, all platform requirements are ignored
* If this is set to false, no platform requirements are ignored
* If this is set to string[], those packages will be ignored
*
* @param bool|string[] $ignorePlatformReqs
*
* @return Installer
*
* @deprecated use setPlatformRequirementFilter instead
*/
public function setIgnorePlatformRequirements($ignorePlatformReqs) : self {
trigger_error('Installer::setIgnorePlatformRequirements is deprecated since Composer 2.2, use setPlatformRequirementFilter instead.', E_USER_DEPRECATED);
return $this->setPlatformRequirementFilter(PlatformRequirementFilterFactory::fromBoolOrList($ignorePlatformReqs));
}
/**
* @return Installer
*/
public function setPlatformRequirementFilter(PlatformRequirementFilterInterface $platformRequirementFilter) : self {
$this->platformRequirementFilter = $platformRequirementFilter;
return $this;
}
/**
* Update the lock file to the exact same versions and references but use current remote metadata like URLs and mirror info
*
* @return Installer
*/
public function setUpdateMirrors(bool $updateMirrors) : self {
$this->updateMirrors = $updateMirrors;
return $this;
}
/**
* restrict the update operation to a few packages, all other packages
* that are already installed will be kept at their current version
*
* @param string[] $packages
*
* @return Installer
*/
public function setUpdateAllowList(array $packages) : self {
if (count($packages) === 0) {
$this->updateAllowList = null;
}
else {
$this->updateAllowList = array_values(array_unique(array_map('strtolower', $packages)));
}
return $this;
}
/**
* Should dependencies of packages marked for update be updated?
*
* Depending on the chosen constant this will either only update the directly named packages, all transitive
* dependencies which are not root requirement or all transitive dependencies including root requirements
*
* @param int $updateAllowTransitiveDependencies One of the UPDATE_ constants on the Request class
* @return Installer
*/
public function setUpdateAllowTransitiveDependencies(int $updateAllowTransitiveDependencies) : self {
if (!in_array($updateAllowTransitiveDependencies, [
Request::UPDATE_ONLY_LISTED,
Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS_NO_ROOT_REQUIRE,
Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS,
], true)) {
throw new \RuntimeException("Invalid value for updateAllowTransitiveDependencies supplied");
}
$this->updateAllowTransitiveDependencies = $updateAllowTransitiveDependencies;
return $this;
}
/**
* Should packages be preferred in a stable version when updating?
*
* @return Installer
*/
public function setPreferStable(bool $preferStable = true) : self {
$this->preferStable = $preferStable;
return $this;
}
/**
* Should packages be preferred in a lowest version when updating?
*
* @return Installer
*/
public function setPreferLowest(bool $preferLowest = true) : self {
$this->preferLowest = $preferLowest;
return $this;
}
/**
* Only relevant for partial updates (with setUpdateAllowList), if this is enabled currently locked versions will be preferred for packages which are not in the allowlist
*
* This reduces the update to
*
* @return Installer
*/
public function setMinimalUpdate(bool $minimalUpdate = true) : self {
$this->minimalUpdate = $minimalUpdate;
return $this;
}
/**
* Should the lock file be updated when updating?
*
* This is disabled implicitly when enabling dryRun
*
* @return Installer
*/
public function setWriteLock(bool $writeLock = true) : self {
$this->writeLock = $writeLock;
return $this;
}
/**
* Should the operations (package install, update and removal) be executed on disk?
*
* This is disabled implicitly when enabling dryRun
*
* @return Installer
*/
public function setExecuteOperations(bool $executeOperations = true) : self {
$this->executeOperations = $executeOperations;
return $this;
}
/**
* Should an audit be run after installation is complete?
*
* @return Installer
*/
public function setAudit(bool $audit) : self {
$this->audit = $audit;
return $this;
}
/**
* Should exit with status code 5 on audit error
*
* @param bool $errorOnAudit
* @return Installer
*/
public function setErrorOnAudit(bool $errorOnAudit) : self {
$this->errorOnAudit = $errorOnAudit;
return $this;
}
/**
* What format should be used for audit output?
*
* @param Auditor::FORMAT_* $auditFormat
* @return Installer
*/
public function setAuditFormat(string $auditFormat) : self {
$this->auditFormat = $auditFormat;
return $this;
}
/**
* Disables plugins.
*
* Call this if you want to ensure that third-party code never gets
* executed. The default is to automatically install, and execute
* custom third-party installers.
*
* @return Installer
*/
public function disablePlugins() : self {
$this->installationManager
->disablePlugins();
return $this;
}
/**
* @return Installer
*/
public function setSuggestedPackagesReporter(SuggestedPackagesReporter $suggestedPackagesReporter) : self {
$this->suggestedPackagesReporter = $suggestedPackagesReporter;
return $this;
}
}
Members
Title Sort descending | Deprecated | Modifiers | Object type | Summary |
---|---|---|---|---|
Installer::$additionalFixedRepository | protected | property | ||
Installer::$allowedTypes | private | property | @var list<string>|null | |
Installer::$apcuAutoloader | protected | property | @var bool | |
Installer::$apcuAutoloaderPrefix | protected | property | @var string|null | |
Installer::$audit | protected | property | @var bool | |
Installer::$auditFormat | protected | property | @var Auditor::FORMAT_* | |
Installer::$autoloadGenerator | protected | property | ||
Installer::$classMapAuthoritative | protected | property | @var bool | |
Installer::$config | protected | property | ||
Installer::$devMode | protected | property | @var bool | |
Installer::$downloadManager | protected | property | ||
Installer::$downloadOnly | protected | property | @var bool | |
Installer::$dryRun | protected | property | @var bool | |
Installer::$dumpAutoloader | protected | property | @var bool | |
Installer::$errorOnAudit | protected | property | @var bool | |
Installer::$eventDispatcher | protected | property | ||
Installer::$executeOperations | protected | property | @var bool | |
Installer::$fixedRootPackage | protected | property | ||
Installer::$ignoredTypes | private | property | @var list<string> | |
Installer::$install | protected | property | @var bool | |
Installer::$installationManager | protected | property | ||
Installer::$io | protected | property | ||
Installer::$locker | protected | property | ||
Installer::$minimalUpdate | protected | property | @var bool | |
Installer::$optimizeAutoloader | protected | property | @var bool | |
Installer::$package | protected | property | ||
Installer::$platformRequirementFilter | protected | property | ||
Installer::$preferDist | protected | property | @var bool | |
Installer::$preferLowest | protected | property | @var bool | |
Installer::$preferSource | protected | property | @var bool | |
Installer::$preferStable | protected | property | @var bool | |
Installer::$repositoryManager | protected | property | ||
Installer::$runScripts | protected | property | @var bool | |
Installer::$suggestedPackagesReporter | protected | property | ||
Installer::$temporaryConstraints | protected | property | @var array<string, ConstraintInterface> | |
Installer::$update | protected | property | @var bool | |
Installer::$updateAllowList | protected | property | Array of package names/globs flagged for update | |
Installer::$updateAllowTransitiveDependencies | protected | property | @var Request::UPDATE_* | |
Installer::$updateMirrors | protected | property | @var bool | |
Installer::$verbose | protected | property | @var bool | |
Installer::$writeLock | protected | property | @var bool | |
Installer::create | public static | function | Create Installer | |
Installer::createPlatformRepo | protected | function | ||
Installer::createPolicy | private | function | ||
Installer::createPoolOptimizer | private | function | ||
Installer::createRepositorySet | private | function | @phpstan-param list<array{package: string, version: string, alias: string, alias_normalized: string}> $rootAliases | |
Installer::createRequest | private | function | ||
Installer::disablePlugins | public | function | Disables plugins. | |
Installer::doInstall | protected | function | @phpstan-return self::ERROR_* | |
Installer::doUpdate | protected | function | @phpstan-return self::ERROR_* | |
Installer::ERROR_AUDIT_FAILED | public | constant | ||
Installer::ERROR_DEPENDENCY_RESOLUTION_FAILED | public | constant | ||
Installer::ERROR_GENERIC_FAILURE | public | constant | ||
Installer::ERROR_LOCK_FILE_INVALID | public | constant | ||
Installer::ERROR_NONE | public | constant | ||
Installer::ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE | public | constant | ||
Installer::ERROR_TRANSPORT_EXCEPTION | public | constant | ||
Installer::extractDevPackages | protected | function | Run the solver a second time on top of the existing update result with only the current result set in the pool and see what packages would get removed if we only had the non-dev packages in the solver request |
|
Installer::extractPlatformRequirements | private | function | ||
Installer::getRootAliases | private | function | @phpstan-return list<array{package: string, version: string, alias: string, alias_normalized: string}> | |
Installer::isDryRun | public | function | Checks, if this is a dry run (simulation mode). | |
Installer::isVerbose | public | function | Checks, if running in verbose mode. | |
Installer::mockLocalRepositories | private | function | Replace local repositories with InstalledArrayRepository instances | |
Installer::requirePackagesForUpdate | private | function | ||
Installer::run | public | function | Run installation (or update) | |
Installer::setAdditionalFixedRepository | public | function | ||
Installer::setAllowedTypes | public | function | Only packages of those types are allowed if set to non-null | |
Installer::setApcuAutoloader | public | function | Whether or not generated autoloader considers APCu caching. | |
Installer::setAudit | public | function | Should an audit be run after installation is complete? | |
Installer::setAuditFormat | public | function | What format should be used for audit output? | |
Installer::setClassMapAuthoritative | public | function | Whether or not generated autoloader considers the class map authoritative. |
|
Installer::setConfig | public | function | set the config instance | |
Installer::setDevMode | public | function | enables dev packages | |
Installer::setDownloadOnly | public | function | Whether to download only or not. | |
Installer::setDryRun | public | function | Whether to run in drymode or not | |
Installer::setDumpAutoloader | public | function | set whether to run autoloader or not | |
Installer::setErrorOnAudit | public | function | Should exit with status code 5 on audit error | |
Installer::setExecuteOperations | public | function | Should the operations (package install, update and removal) be executed on disk? | |
Installer::setIgnoredTypes | public | function | Packages of those types are ignored, by default php-ext and php-ext-zend are ignored | |
Installer::setIgnorePlatformRequirements | Deprecated | public | function | set ignore Platform Package requirements |
Installer::setInstall | public | function | Allows disabling the install step after an update | |
Installer::setMinimalUpdate | public | function | Only relevant for partial updates (with setUpdateAllowList), if this is enabled currently locked versions will be preferred for packages which are not in the allowlist | |
Installer::setOptimizeAutoloader | public | function | Whether or not generated autoloader are optimized | |
Installer::setPlatformRequirementFilter | public | function | ||
Installer::setPreferDist | public | function | prefer dist installation | |
Installer::setPreferLowest | public | function | Should packages be preferred in a lowest version when updating? | |
Installer::setPreferSource | public | function | prefer source installation | |
Installer::setPreferStable | public | function | Should packages be preferred in a stable version when updating? | |
Installer::setRunScripts | Deprecated | public | function | set whether to run scripts or not |
Installer::setSuggestedPackagesReporter | public | function | ||
Installer::setTemporaryConstraints | public | function | ||
Installer::setUpdate | public | function | update packages | |
Installer::setUpdateAllowList | public | function | restrict the update operation to a few packages, all other packages that are already installed will be kept at their current version |
|
Installer::setUpdateAllowTransitiveDependencies | public | function | Should dependencies of packages marked for update be updated? | |
Installer::setUpdateMirrors | public | function | Update the lock file to the exact same versions and references but use current remote metadata like URLs and mirror info | |
Installer::setVerbose | public | function | run in verbose mode | |
Installer::setWriteLock | public | function | Should the lock file be updated when updating? | |
Installer::__construct | public | function | Constructor |