2012-03-03 05:35:40 +00:00
< ? 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 ;
use Composer\Autoload\AutoloadGenerator ;
use Composer\DependencyResolver\DefaultPolicy ;
2018-09-13 13:23:05 +00:00
use Composer\DependencyResolver\LocalRepoTransaction ;
2019-09-07 06:52:10 +00:00
use Composer\DependencyResolver\LockTransaction ;
2012-03-03 05:35:40 +00:00
use Composer\DependencyResolver\Operation\UpdateOperation ;
2013-08-11 22:28:33 +00:00
use Composer\DependencyResolver\Operation\InstallOperation ;
2013-03-03 00:55:10 +00:00
use Composer\DependencyResolver\Operation\UninstallOperation ;
2018-05-03 15:30:19 +00:00
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation ;
2013-08-11 22:28:33 +00:00
use Composer\DependencyResolver\Operation\OperationInterface ;
2015-07-07 14:53:33 +00:00
use Composer\DependencyResolver\PolicyInterface ;
2018-09-11 13:49:08 +00:00
use Composer\DependencyResolver\Pool ;
2012-03-03 05:35:40 +00:00
use Composer\DependencyResolver\Request ;
2013-04-26 22:11:06 +00:00
use Composer\DependencyResolver\Rule ;
2012-03-03 05:35:40 +00:00
use Composer\DependencyResolver\Solver ;
2012-03-18 21:43:07 +00:00
use Composer\DependencyResolver\SolverProblemsException ;
2012-03-05 23:48:07 +00:00
use Composer\Downloader\DownloadManager ;
2013-08-14 15:42:11 +00:00
use Composer\EventDispatcher\EventDispatcher ;
2012-03-05 23:48:07 +00:00
use Composer\Installer\InstallationManager ;
2014-07-29 13:25:16 +00:00
use Composer\Installer\InstallerEvents ;
2012-05-23 13:39:33 +00:00
use Composer\Installer\NoopInstaller ;
2016-03-02 21:13:06 +00:00
use Composer\Installer\SuggestedPackagesReporter ;
2012-03-03 05:35:40 +00:00
use Composer\IO\IOInterface ;
use Composer\Package\AliasPackage ;
2018-11-26 19:09:26 +00:00
use Composer\Package\BasePackage ;
2014-10-03 12:48:28 +00:00
use Composer\Package\CompletePackage ;
2012-03-03 05:35:40 +00:00
use Composer\Package\Link ;
2019-11-07 16:35:44 +00:00
use Composer\Package\LinkConstraint\VersionConstraint ;
2016-04-20 11:34:04 +00:00
use Composer\Package\Loader\ArrayLoader ;
use Composer\Package\Dumper\ArrayDumper ;
2019-09-06 23:58:12 +00:00
use Composer\Package\Package ;
2019-09-07 06:52:10 +00:00
use Composer\Repository\ArrayRepository ;
2018-09-10 13:23:40 +00:00
use Composer\Repository\RepositorySet ;
2015-09-24 14:32:36 +00:00
use Composer\Semver\Constraint\Constraint ;
2012-03-05 23:48:07 +00:00
use Composer\Package\Locker ;
2012-03-03 05:35:40 +00:00
use Composer\Package\PackageInterface ;
2012-08-23 13:52:40 +00:00
use Composer\Package\RootPackageInterface ;
2012-03-03 05:35:40 +00:00
use Composer\Repository\CompositeRepository ;
2012-05-09 18:03:19 +00:00
use Composer\Repository\InstalledArrayRepository ;
2012-03-03 05:35:40 +00:00
use Composer\Repository\PlatformRepository ;
use Composer\Repository\RepositoryInterface ;
2012-03-05 23:48:07 +00:00
use Composer\Repository\RepositoryManager ;
2015-07-07 14:53:33 +00:00
use Composer\Repository\WritableRepositoryInterface ;
2012-03-03 05:35:40 +00:00
use Composer\Script\ScriptEvents ;
2012-03-10 00:16:37 +00:00
/**
* @ author Jordi Boggiano < j . boggiano @ seld . be >
* @ author Beau Simensen < beau @ dflydev . com >
* @ author Konstantin Kudryashov < ever . zet @ gmail . com >
2013-08-15 15:14:48 +00:00
* @ author Nils Adermann < naderman @ naderman . de >
2012-03-10 00:16:37 +00:00
*/
2012-03-06 23:30:18 +00:00
class Installer
2012-03-03 05:35:40 +00:00
{
/**
2012-03-05 23:48:07 +00:00
* @ var IOInterface
*/
protected $io ;
2012-06-24 19:58:51 +00:00
/**
* @ var Config
*/
protected $config ;
2012-03-05 23:48:07 +00:00
/**
2012-08-23 13:52:40 +00:00
* @ var RootPackageInterface
2012-03-05 23:48:07 +00:00
*/
protected $package ;
2018-09-13 13:23:05 +00:00
// TODO can we get rid of the below and just use the package itself?
/**
* @ var RootPackageInterface
*/
protected $fixedRootPackage ;
2012-03-05 23:48:07 +00:00
/**
* @ var DownloadManager
*/
protected $downloadManager ;
/**
* @ var RepositoryManager
*/
protected $repositoryManager ;
/**
* @ var Locker
*/
protected $locker ;
/**
* @ var InstallationManager
*/
protected $installationManager ;
/**
* @ var EventDispatcher
*/
protected $eventDispatcher ;
2012-04-27 09:42:58 +00:00
/**
* @ var AutoloadGenerator
*/
protected $autoloadGenerator ;
2012-03-10 18:56:15 +00:00
protected $preferSource = false ;
2012-08-31 20:25:17 +00:00
protected $preferDist = false ;
2012-10-24 15:33:31 +00:00
protected $optimizeAutoloader = false ;
2015-08-16 19:56:52 +00:00
protected $classMapAuthoritative = false ;
2016-07-28 08:23:39 +00:00
protected $apcuAutoloader = false ;
2012-04-14 09:55:57 +00:00
protected $devMode = false ;
2012-03-10 18:56:15 +00:00
protected $dryRun = false ;
protected $verbose = false ;
protected $update = false ;
2014-12-29 20:29:13 +00:00
protected $dumpAutoloader = true ;
2012-05-13 11:25:02 +00:00
protected $runScripts = true ;
2014-10-17 14:26:00 +00:00
protected $ignorePlatformReqs = false ;
2014-12-02 08:18:44 +00:00
protected $preferStable = false ;
protected $preferLowest = false ;
2016-05-31 22:48:26 +00:00
protected $skipSuggest = false ;
2019-10-19 19:46:29 +00:00
protected $writeLock ;
2016-12-06 21:40:47 +00:00
protected $executeOperations = true ;
2014-02-24 11:28:08 +00:00
/**
* Array of package names / globs flagged for update
*
* @ var array | null
*/
2019-11-07 16:35:44 +00:00
protected $updateMirrors = false ;
2012-05-26 13:20:27 +00:00
protected $updateWhitelist = null ;
2018-09-11 13:59:02 +00:00
protected $whitelistTransitiveDependencies = false ;
2017-09-11 15:16:15 +00:00
protected $whitelistAllDependencies = false ;
2012-03-10 17:08:36 +00:00
2012-04-15 15:44:47 +00:00
/**
2016-03-02 21:13:06 +00:00
* @ var SuggestedPackagesReporter
2012-04-15 15:44:47 +00:00
*/
2016-03-02 21:13:06 +00:00
protected $suggestedPackagesReporter ;
2012-04-15 15:44:47 +00:00
2012-03-10 17:08:36 +00:00
/**
* @ var RepositoryInterface
*/
2018-09-13 13:23:05 +00:00
protected $additionalFixedRepository ;
2012-03-10 17:08:36 +00:00
2012-03-05 23:48:07 +00:00
/**
* Constructor
2012-03-10 00:16:37 +00:00
*
2012-10-18 08:35:06 +00:00
* @ param IOInterface $io
* @ param Config $config
* @ param RootPackageInterface $package
* @ param DownloadManager $downloadManager
* @ param RepositoryManager $repositoryManager
* @ param Locker $locker
* @ param InstallationManager $installationManager
* @ param EventDispatcher $eventDispatcher
* @ param AutoloadGenerator $autoloadGenerator
2012-03-05 23:48:07 +00:00
*/
2012-08-23 13:52:40 +00:00
public function __construct ( IOInterface $io , Config $config , RootPackageInterface $package , DownloadManager $downloadManager , RepositoryManager $repositoryManager , Locker $locker , InstallationManager $installationManager , EventDispatcher $eventDispatcher , AutoloadGenerator $autoloadGenerator )
2012-03-05 23:48:07 +00:00
{
$this -> io = $io ;
2012-06-24 19:58:51 +00:00
$this -> config = $config ;
2012-03-05 23:48:07 +00:00
$this -> package = $package ;
$this -> downloadManager = $downloadManager ;
$this -> repositoryManager = $repositoryManager ;
$this -> locker = $locker ;
$this -> installationManager = $installationManager ;
$this -> eventDispatcher = $eventDispatcher ;
2012-04-27 09:42:58 +00:00
$this -> autoloadGenerator = $autoloadGenerator ;
2019-10-19 19:46:29 +00:00
$this -> writeLock = $config -> get ( 'lock' );
2012-03-05 23:48:07 +00:00
}
/**
* Run installation ( or update )
2013-11-22 15:17:02 +00:00
*
2014-07-16 13:17:38 +00:00
* @ throws \Exception
2015-09-28 09:51:14 +00:00
* @ return int 0 on success or a positive error code on failure
2012-03-03 05:35:40 +00:00
*/
2012-03-10 17:08:36 +00:00
public function run ()
2012-03-03 05:35:40 +00:00
{
2016-02-29 15:04:39 +00:00
// 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.
2014-12-02 14:02:20 +00:00
gc_collect_cycles ();
2014-12-02 10:23:21 +00:00
gc_disable ();
2019-11-07 16:35:44 +00:00
if ( $this -> updateWhitelist && $this -> updateMirrors ) {
throw new \RuntimeException ( " The installer options updateMirrors and updateWhitelist are mutually exclusive. " );
}
2016-03-10 18:36:58 +00:00
// Force update if there is no lock file present
if ( ! $this -> update && ! $this -> locker -> isLocked ()) {
2019-11-08 11:26:46 +00:00
$this -> io -> writeError ( '<warning>No lock file found. Updating dependencies instead of installing from lock file. Use composer update over composer install if you do not have a lock file.</warning>' );
2016-03-10 18:36:58 +00:00
$this -> update = true ;
}
2012-03-10 17:08:36 +00:00
if ( $this -> dryRun ) {
$this -> verbose = true ;
2012-05-23 13:16:24 +00:00
$this -> runScripts = false ;
2016-12-06 21:40:47 +00:00
$this -> executeOperations = false ;
$this -> writeLock = false ;
$this -> dumpAutoloader = false ;
2012-10-22 13:50:40 +00:00
$this -> mockLocalRepositories ( $this -> repositoryManager );
2012-03-03 05:35:40 +00:00
}
2013-12-26 15:35:20 +00:00
if ( $this -> runScripts ) {
2017-11-28 15:04:50 +00:00
$devMode = ( int ) $this -> devMode ;
putenv ( " COMPOSER_DEV_MODE= $devMode " );
2013-12-26 15:35:20 +00:00
// dispatch pre event
2018-09-13 13:23:05 +00:00
// should we treat this more strictly as running an update and then running an install, triggering events multiple times?
2013-12-26 15:35:20 +00:00
$eventName = $this -> update ? ScriptEvents :: PRE_UPDATE_CMD : ScriptEvents :: PRE_INSTALL_CMD ;
2015-02-23 15:31:54 +00:00
$this -> eventDispatcher -> dispatchScript ( $eventName , $this -> devMode );
2013-12-26 15:35:20 +00:00
}
2013-11-11 16:43:11 +00:00
$this -> downloadManager -> setPreferSource ( $this -> preferSource );
$this -> downloadManager -> setPreferDist ( $this -> preferDist );
2012-03-03 05:35:40 +00:00
2013-03-02 23:41:12 +00:00
$localRepo = $this -> repositoryManager -> getLocalRepository ();
2012-03-03 05:35:40 +00:00
2016-03-02 21:13:06 +00:00
if ( ! $this -> suggestedPackagesReporter ) {
$this -> suggestedPackagesReporter = new SuggestedPackagesReporter ( $this -> io );
}
2012-11-28 17:44:49 +00:00
try {
2018-09-13 13:23:05 +00:00
if ( $this -> update ) {
2019-02-14 16:57:29 +00:00
// TODO introduce option to set doInstall to false (update lock file without vendor install)
$res = $this -> doUpdate ( $localRepo , true );
2018-09-13 13:23:05 +00:00
} else {
2019-02-14 16:57:29 +00:00
$res = $this -> doInstall ( $localRepo );
2018-09-13 13:23:05 +00:00
}
2013-11-22 15:17:02 +00:00
if ( $res !== 0 ) {
return $res ;
2012-04-15 15:44:47 +00:00
}
2012-11-28 17:44:49 +00:00
} catch ( \Exception $e ) {
2016-12-06 21:40:47 +00:00
if ( $this -> executeOperations ) {
2015-10-26 15:01:06 +00:00
$this -> installationManager -> notifyInstalls ( $this -> io );
}
2012-11-28 17:44:49 +00:00
throw $e ;
2012-04-14 13:45:25 +00:00
}
2016-12-06 21:40:47 +00:00
if ( $this -> executeOperations ) {
2015-10-26 15:01:06 +00:00
$this -> installationManager -> notifyInstalls ( $this -> io );
}
2012-04-14 13:45:25 +00:00
2014-04-05 22:07:20 +00:00
// output suggestions if we're in dev mode
2018-09-13 13:23:05 +00:00
if ( $this -> update && $this -> devMode && ! $this -> skipSuggest ) {
$this -> suggestedPackagesReporter -> output ( $this -> locker -> getLockedRepository ( $this -> devMode ));
2012-04-14 13:45:25 +00:00
}
2018-09-13 13:23:05 +00:00
// TODO probably makes more sense to do this on the lock file only?
2014-10-03 12:48:28 +00:00
# Find abandoned packages and warn user
foreach ( $localRepo -> getPackages () as $package ) {
if ( ! $package instanceof CompletePackage || ! $package -> isAbandoned ()) {
continue ;
}
2018-07-05 00:52:04 +00:00
$replacement = is_string ( $package -> getReplacementPackage ())
2014-10-03 12:48:28 +00:00
? 'Use ' . $package -> getReplacementPackage () . ' instead'
: 'No replacement was suggested' ;
2015-02-06 12:52:44 +00:00
$this -> io -> writeError (
2014-10-03 12:48:28 +00:00
sprintf (
2015-04-30 21:34:26 +00:00
" <warning>Package %s is abandoned, you should avoid using it. %s.</warning> " ,
2014-10-03 12:48:28 +00:00
$package -> getPrettyName (),
$replacement
)
);
}
2016-12-06 21:40:47 +00:00
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>' );
2014-01-17 14:04:10 +00:00
}
2016-12-06 21:40:47 +00:00
$this -> autoloadGenerator -> setDevMode ( $this -> devMode );
$this -> autoloadGenerator -> setClassMapAuthoritative ( $this -> classMapAuthoritative );
2016-12-06 23:21:13 +00:00
$this -> autoloadGenerator -> setApcu ( $this -> apcuAutoloader );
2016-12-06 21:40:47 +00:00
$this -> autoloadGenerator -> setRunScripts ( $this -> runScripts );
$this -> autoloadGenerator -> dump ( $this -> config , $localRepo , $this -> package , $this -> installationManager , 'composer' , $this -> optimizeAutoloader );
}
if ( $this -> executeOperations ) {
2016-07-02 15:35:09 +00:00
// force binaries re-generation in case they are missing
2016-03-28 21:15:13 +00:00
foreach ( $localRepo -> getPackages () as $package ) {
2016-07-02 15:35:09 +00:00
$this -> installationManager -> ensureBinariesPresence ( $package );
2016-03-28 21:15:13 +00:00
}
2014-02-26 09:43:26 +00:00
$vendorDir = $this -> config -> get ( 'vendor-dir' );
if ( is_dir ( $vendorDir )) {
2015-08-11 10:20:15 +00:00
// suppress errors as this fails sometimes on OSX for no apparent reason
// see https://github.com/composer/composer/issues/4070#issuecomment-129792748
@ touch ( $vendorDir );
2014-02-26 09:43:26 +00:00
}
2012-04-14 13:45:25 +00:00
}
2017-11-28 15:07:28 +00:00
if ( $this -> runScripts ) {
// dispatch post event
$eventName = $this -> update ? ScriptEvents :: POST_UPDATE_CMD : ScriptEvents :: POST_INSTALL_CMD ;
$this -> eventDispatcher -> dispatchScript ( $eventName , $this -> devMode );
}
2016-02-29 15:04:39 +00:00
// re-enable GC except on HHVM which triggers a warning here
if ( ! defined ( 'HHVM_VERSION' )) {
gc_enable ();
}
2013-11-22 15:17:02 +00:00
return 0 ;
2012-04-14 13:45:25 +00:00
}
2019-02-14 16:57:29 +00:00
protected function doUpdate ( RepositoryInterface $localRepo , $doInstall )
2012-04-14 13:45:25 +00:00
{
2019-02-14 16:57:29 +00:00
$platformRepo = $this -> createPlatformRepo ( true );
$aliases = $this -> getRootAliases ( true );
2012-11-22 21:47:19 +00:00
$lockedRepository = null ;
2018-09-13 13:23:05 +00:00
if ( $this -> locker -> isLocked ()) {
$lockedRepository = $this -> locker -> getLockedRepository ( true );
2012-04-24 08:49:49 +00:00
}
2018-09-13 13:23:05 +00:00
if ( $this -> updateWhitelist ) {
if ( ! $lockedRepository ) {
$this -> io -> writeError ( '<error>Cannot update only a partial set of packages without a lock file present.</error>' , true , IOInterface :: QUIET );
return 1 ;
}
$this -> whitelistUpdateDependencies (
$lockedRepository ,
$this -> package -> getRequires (),
$this -> package -> getDevRequires ()
);
}
2012-05-27 23:58:54 +00:00
2015-02-06 12:52:44 +00:00
$this -> io -> writeError ( '<info>Loading composer repositories with package information</info>' );
2012-08-16 23:42:05 +00:00
2018-09-10 13:23:40 +00:00
// creating repository set
2018-09-13 13:23:05 +00:00
$policy = $this -> createPolicy ( true );
$repositorySet = $this -> createRepositorySet ( $platformRepo , $aliases );
$repositories = $this -> repositoryManager -> getRepositories ();
foreach ( $repositories as $repository ) {
$repositorySet -> addRepository ( $repository );
2012-04-15 17:05:16 +00:00
}
2015-04-30 14:14:20 +00:00
if ( $lockedRepository ) {
2018-09-11 11:33:29 +00:00
$repositorySet -> addRepository ( $lockedRepository );
2015-04-30 14:14:20 +00:00
}
2018-09-13 13:23:05 +00:00
// TODO can we drop any locked packages that we have matching remote versions for?
2012-04-15 17:05:16 +00:00
2019-09-07 00:28:40 +00:00
$request = $this -> createRequest ( $this -> fixedRootPackage , $platformRepo , $lockedRepository );
2012-04-27 09:42:58 +00:00
2018-09-13 13:23:05 +00:00
if ( $lockedRepository ) {
// TODO do we really always need this? Maybe only to skip fix() in updateWhitelist case cause these packages get removed on full update automatically?
foreach ( $lockedRepository -> getPackages () as $lockedPackage ) {
if ( ! $repositorySet -> isPackageAcceptable ( $lockedPackage -> getNames (), $lockedPackage -> getStability ())) {
$constraint = new Constraint ( '=' , $lockedPackage -> getVersion ());
$constraint -> setPrettyString ( '(stability not acceptable)' );
2019-11-07 20:51:53 +00:00
// if we can get rid of this remove() here, we can generally get rid of remove support in the request
2018-09-13 13:23:05 +00:00
$request -> remove ( $lockedPackage -> getName (), $constraint );
2013-03-10 18:55:26 +00:00
}
}
2018-09-13 13:23:05 +00:00
}
2013-03-10 18:55:26 +00:00
2018-09-13 13:23:05 +00:00
$this -> io -> writeError ( '<info>Updating dependencies</info>' );
2013-03-10 18:55:26 +00:00
2018-09-13 13:23:05 +00:00
$links = array_merge ( $this -> package -> getRequires (), $this -> package -> getDevRequires ());
2012-03-03 05:35:40 +00:00
2019-11-07 16:35:44 +00:00
// 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 ) {
foreach ( $lockedRepository -> getPackages () as $lockedPackage ) {
$request -> install ( $lockedPackage -> getName (), new Constraint ( '==' , $lockedPackage -> getVersion ()));
}
} else {
foreach ( $links as $link ) {
$request -> install ( $link -> getTarget (), $link -> getConstraint ());
}
2018-09-13 13:23:05 +00:00
}
2012-03-03 05:35:40 +00:00
2018-09-13 13:23:05 +00:00
// if the updateWhitelist is enabled, packages not in it are also fixed
// to the version specified in the lock
if ( $this -> updateWhitelist ) {
foreach ( $lockedRepository -> getPackages () as $lockedPackage ) {
2019-09-06 23:58:12 +00:00
// TODO should this really be checking acceptability here?
2018-09-13 13:23:05 +00:00
if ( ! $this -> isUpdateable ( $lockedPackage ) && $repositorySet -> isPackageAcceptable ( $lockedPackage -> getNames (), $lockedPackage -> getStability ())) {
// TODO add reason for fix?
$request -> fixPackage ( $lockedPackage );
2012-03-03 05:35:40 +00:00
}
2013-03-03 19:05:46 +00:00
}
2012-03-03 05:35:40 +00:00
}
2019-09-06 23:58:12 +00:00
// TODO reenable events
2018-09-13 13:23:05 +00:00
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $installedRepo, $request);
2018-09-11 13:49:08 +00:00
2018-09-12 09:49:09 +00:00
$pool = $repositorySet -> createPool ( $request );
2018-09-11 11:33:29 +00:00
2018-09-13 13:23:05 +00:00
// TODO ensure that the solver always picks most recent reference for dev packages, so they get updated even when just a new commit is pushed but version is unchanged
2019-09-06 23:58:12 +00:00
// should already be solved by using the remote package in all cases in the pool
2012-03-03 05:35:40 +00:00
// solve dependencies
2018-09-13 13:23:05 +00:00
$solver = new Solver ( $policy , $pool , $this -> io );
2012-03-18 21:43:07 +00:00
try {
2018-09-13 13:23:05 +00:00
$lockTransaction = $solver -> solve ( $request , $this -> ignorePlatformReqs );
2019-06-21 16:34:16 +00:00
$ruleSetSize = $solver -> getRuleSetSize ();
$solver = null ;
2012-03-18 21:43:07 +00:00
} catch ( SolverProblemsException $e ) {
2016-03-03 12:21:49 +00:00
$this -> io -> writeError ( '<error>Your requirements could not be resolved to an installable set of packages.</error>' , true , IOInterface :: QUIET );
2015-02-06 12:52:44 +00:00
$this -> io -> writeError ( $e -> getMessage ());
2018-09-13 13:23:05 +00:00
if ( ! $this -> devMode ) {
2017-08-07 14:32:04 +00:00
$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 );
}
2012-03-18 21:43:07 +00:00
2018-09-13 13:23:05 +00:00
return max ( 1 , $e -> getCode ());
2012-03-18 21:43:07 +00:00
}
2012-03-03 05:35:40 +00:00
2018-09-13 13:23:05 +00:00
// TODO should we warn people / error if plugins in vendor folder do not match contents of lock file before update?
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $lockedRepository, $request, $lockTransaction);
2016-10-30 20:35:13 +00:00
2018-09-14 12:39:24 +00:00
$this -> io -> writeError ( " Analyzed " . count ( $pool ) . " packages to resolve dependencies " , true , IOInterface :: VERBOSE );
2019-06-21 16:34:16 +00:00
$this -> io -> writeError ( " Analyzed " . $ruleSetSize . " rules to resolve dependencies " , true , IOInterface :: VERBOSE );
2016-10-30 20:35:13 +00:00
2018-09-13 13:23:05 +00:00
if ( ! $lockTransaction -> getOperations ()) {
$this -> io -> writeError ( 'Nothing to modify in lock file' );
2012-11-22 21:47:19 +00:00
}
2019-09-07 06:52:10 +00:00
$this -> extractDevPackages ( $lockTransaction , $platformRepo , $aliases , $policy );
2018-09-13 13:23:05 +00:00
// write lock
$platformReqs = $this -> extractPlatformRequirements ( $this -> package -> getRequires ());
$platformDevReqs = $this -> extractPlatformRequirements ( $this -> package -> getDevRequires ());
if ( $lockTransaction -> getOperations ()) {
2016-10-29 15:03:08 +00:00
$installs = $updates = $uninstalls = array ();
2018-09-13 13:23:05 +00:00
foreach ( $lockTransaction -> getOperations () as $operation ) {
2016-10-29 15:03:08 +00:00
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 ();
}
}
2018-07-24 12:32:52 +00:00
$this -> io -> writeError ( sprintf (
2018-09-13 13:23:05 +00:00
" <info>Lock file operations: %d install%s, %d update%s, %d removal%s</info> " ,
2016-10-29 15:03:08 +00:00
count ( $installs ),
1 === count ( $installs ) ? '' : 's' ,
count ( $updates ),
1 === count ( $updates ) ? '' : 's' ,
count ( $uninstalls ),
2018-07-24 12:32:52 +00:00
1 === count ( $uninstalls ) ? '' : 's'
));
2016-10-29 15:03:08 +00:00
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 );
}
}
2018-09-13 13:23:05 +00:00
foreach ( $lockTransaction -> getOperations () as $operation ) {
2012-11-22 21:47:19 +00:00
// collect suggestions
2018-07-14 18:55:26 +00:00
$jobType = $operation -> getJobType ();
2018-09-13 13:23:05 +00:00
if ( $operation instanceof InstallOperation ) {
2016-03-02 21:13:06 +00:00
$this -> suggestedPackagesReporter -> addSuggestionsFromPackage ( $operation -> getPackage ());
2012-11-22 21:47:19 +00:00
}
2018-09-13 13:23:05 +00:00
// output op, but alias op only in debug verbosity
if ( false === strpos ( $operation -> getJobType (), 'Alias' ) || $this -> io -> isDebug ()) {
2019-11-08 15:48:35 +00:00
$this -> io -> writeError ( ' - ' . $operation -> show ( true ));
2012-11-22 21:47:19 +00:00
}
}
2019-09-07 00:28:40 +00:00
$updatedLock = $this -> locker -> setLockData (
2019-11-07 16:35:44 +00:00
$lockTransaction -> getNewLockPackages ( false , $this -> updateMirrors ),
$lockTransaction -> getNewLockPackages ( true , $this -> updateMirrors ),
2019-09-07 00:28:40 +00:00
$platformReqs ,
$platformDevReqs ,
$aliases ,
$this -> package -> getMinimumStability (),
$this -> package -> getStabilityFlags (),
$this -> preferStable || $this -> package -> getPreferStable (),
$this -> preferLowest ,
$this -> config -> get ( 'platform' ) ? : array (),
$this -> writeLock && $this -> executeOperations
);
if ( $updatedLock && $this -> writeLock && $this -> executeOperations ) {
$this -> io -> writeError ( '<info>Writing lock file</info>' );
}
2019-09-06 23:58:12 +00:00
2018-09-13 13:23:05 +00:00
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
2019-02-14 16:57:29 +00:00
return $this -> doInstall ( $localRepo , true );
2015-04-30 15:41:28 +00:00
}
2018-09-13 13:23:05 +00:00
return 0 ;
2016-04-20 11:34:04 +00:00
}
2019-09-07 06:52:10 +00:00
/**
* 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
*/
protected function extractDevPackages ( LockTransaction $lockTransaction , $platformRepo , $aliases , $policy )
{
if ( ! $this -> package -> getDevRequires ()) {
return array ();
}
$resultRepo = new ArrayRepository ( array ());
$loader = new ArrayLoader ( null , true );
$dumper = new ArrayDumper ();
foreach ( $lockTransaction -> getNewLockPackages ( false ) as $pkg ) {
$resultRepo -> addPackage ( $loader -> load ( $dumper -> dump ( $pkg )));
}
$repositorySet = $this -> createRepositorySet ( $platformRepo , $aliases , null );
$repositorySet -> addRepository ( $resultRepo );
$request = $this -> createRequest ( $this -> fixedRootPackage , $platformRepo , null );
$links = $this -> package -> getRequires ();
foreach ( $links as $link ) {
$request -> install ( $link -> getTarget (), $link -> getConstraint ());
}
$pool = $repositorySet -> createPool ( $request );
2019-11-08 11:13:23 +00:00
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request);
2019-09-07 06:52:10 +00:00
$solver = new Solver ( $policy , $pool , $this -> io );
try {
$nonDevLockTransaction = $solver -> solve ( $request , $this -> ignorePlatformReqs );
2019-11-08 11:13:23 +00:00
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops);
2019-09-07 06:52:10 +00:00
$solver = null ;
} catch ( SolverProblemsException $e ) {
2019-11-08 11:13:23 +00:00
$this -> io -> writeError ( '<error>Unable to find a compatible set of packages based on your non-dev requirements alone.</error>' , true , IOInterface :: QUIET );
2019-09-07 06:52:10 +00:00
$this -> io -> writeError ( $e -> getMessage ());
return max ( 1 , $e -> getCode ());
}
$lockTransaction -> setNonDevPackages ( $nonDevLockTransaction );
}
2016-04-20 11:34:04 +00:00
/**
2019-11-08 11:26:46 +00:00
* @ param RepositoryInterface $localRepo
* @ param bool $alreadySolved Whether the function is called as part of an update command or independently
* @ return int exit code
2016-04-20 11:34:04 +00:00
*/
2019-02-14 16:57:29 +00:00
protected function doInstall ( RepositoryInterface $localRepo , $alreadySolved = false )
2016-04-20 11:34:04 +00:00
{
2019-02-14 16:57:29 +00:00
$platformRepo = $this -> createPlatformRepo ( false );
$aliases = $this -> getRootAliases ( false );
2018-09-13 13:23:05 +00:00
$lockedRepository = $this -> locker -> getLockedRepository ( $this -> devMode );
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
// creating repository set
$policy = $this -> createPolicy ( false );
2019-11-07 19:40:28 +00:00
// use aliases from lock file only, so empty root aliases here
$repositorySet = $this -> createRepositorySet ( $platformRepo , array (), $lockedRepository );
2018-09-13 13:23:05 +00:00
$repositorySet -> addRepository ( $lockedRepository );
2016-04-20 11:34:04 +00:00
2019-09-07 00:28:40 +00:00
$this -> io -> writeError ( '<info>Installing dependencies from lock file' . ( $this -> devMode ? ' (including require-dev)' : '' ) . '</info>' );
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
// 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>' );
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
// creating requirements request
2019-09-07 00:28:40 +00:00
$request = $this -> createRequest ( $this -> fixedRootPackage , $platformRepo , $lockedRepository );
2018-09-13 13:23:05 +00:00
if ( ! $this -> locker -> isFresh ()) {
2020-01-14 14:39:35 +00:00
$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 );
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
foreach ( $lockedRepository -> getPackages () as $package ) {
$request -> fixPackage ( $package );
}
foreach ( $this -> locker -> getPlatformRequirements ( $this -> devMode ) as $link ) {
$request -> install ( $link -> getTarget (), $link -> getConstraint ());
}
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $installedRepo, $request);
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
$pool = $repositorySet -> createPool ( $request );
2016-04-20 11:34:04 +00:00
2018-09-13 13:23:05 +00:00
// solve dependencies
$solver = new Solver ( $policy , $pool , $this -> io );
try {
$lockTransaction = $solver -> solve ( $request , $this -> ignorePlatformReqs );
2019-06-27 12:35:36 +00:00
$solver = null ;
2016-04-20 11:34:04 +00:00
2019-11-08 11:26:46 +00:00
// 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
2018-09-13 13:23:05 +00:00
if ( 0 !== count ( $lockTransaction -> getOperations ())) {
2019-11-08 11:26:46 +00:00
$this -> io -> writeError ( '<error>Your lock file cannot be installed on this system without changes. Please run composer update.</error>' , true , IOInterface :: QUIET );
2018-09-13 13:23:05 +00:00
// TODO actually display operations to explain what happened?
return 1 ;
}
} catch ( SolverProblemsException $e ) {
2019-11-08 11:26:46 +00:00
$this -> io -> writeError ( '<error>Your lock file does not contain a compatible set of packages. Please run composer update.</error>' , true , IOInterface :: QUIET );
2018-09-13 13:23:05 +00:00
$this -> io -> writeError ( $e -> getMessage ());
return max ( 1 , $e -> getCode ());
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
// TODO should we warn people / error if plugins in vendor folder do not match contents of lock file before update?
//$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $repositorySet, $installedRepo, $request, $lockTransaction);
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
// 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 );
if ( ! $localRepoTransaction -> getOperations ()) {
$this -> io -> writeError ( 'Nothing to install, update or remove' );
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
if ( $localRepoTransaction -> getOperations ()) {
$installs = $updates = $uninstalls = array ();
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 ();
}
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
$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 );
}
2016-04-20 11:34:04 +00:00
}
2019-11-14 14:20:50 +00:00
if ( $this -> executeOperations ) {
$this -> installationManager -> execute ( $localRepo , $localRepoTransaction -> getOperations (), $this -> devMode );
} else {
foreach ( $localRepoTransaction -> getOperations () as $operation ) {
// output op, but alias op only in debug verbosity
if ( false === strpos ( $operation -> getJobType (), 'Alias' ) || $this -> io -> isDebug ()) {
$this -> io -> writeError ( ' - ' . $operation -> show ( false ));
}
2014-04-07 09:10:26 +00:00
}
}
2018-09-13 13:23:05 +00:00
return 0 ;
2014-04-07 09:10:26 +00:00
}
2018-09-13 13:23:05 +00:00
private function createPlatformRepo ( $forUpdate )
2016-04-20 11:34:04 +00:00
{
2018-09-13 13:23:05 +00:00
if ( $forUpdate ) {
$platformOverrides = $this -> config -> get ( 'platform' ) ? : array ();
} else {
$platformOverrides = $this -> locker -> getPlatformOverrides ();
2016-04-20 11:34:04 +00:00
}
2018-09-13 13:23:05 +00:00
return new PlatformRepository ( array (), $platformOverrides );
2016-04-20 11:34:04 +00:00
}
/**
2018-09-11 11:33:29 +00:00
* @ param array $rootAliases
* @ param RepositoryInterface | null $lockedRepository
* @ return RepositorySet
2015-07-07 14:53:33 +00:00
*/
2018-09-13 13:23:05 +00:00
private function createRepositorySet ( PlatformRepository $platformRepo , array $rootAliases = array (), $lockedRepository = null )
2013-03-02 23:41:12 +00:00
{
2019-02-14 16:57:29 +00:00
$this -> aliasPlatformPackages ( $platformRepo , $rootAliases );
2018-09-13 13:23:05 +00:00
// TODO what's the point of rootConstraints at all, we generate the package pool taking them into account anyway?
// TODO maybe we can drop the lockedRepository here
2019-09-07 06:52:10 +00:00
// TODO if this gets called in doInstall, this->update is still true?!
2016-03-10 18:36:58 +00:00
if ( $this -> update ) {
$minimumStability = $this -> package -> getMinimumStability ();
$stabilityFlags = $this -> package -> getStabilityFlags ();
2016-04-20 11:34:04 +00:00
$requires = array_merge ( $this -> package -> getRequires (), $this -> package -> getDevRequires ());
2016-03-10 18:36:58 +00:00
} else {
2013-03-02 23:41:12 +00:00
$minimumStability = $this -> locker -> getMinimumStability ();
$stabilityFlags = $this -> locker -> getStabilityFlags ();
2015-02-17 14:37:33 +00:00
$requires = array ();
foreach ( $lockedRepository -> getPackages () as $package ) {
2015-09-24 14:32:36 +00:00
$constraint = new Constraint ( '=' , $package -> getVersion ());
2015-02-17 14:37:33 +00:00
$constraint -> setPrettyString ( $package -> getPrettyVersion ());
$requires [ $package -> getName ()] = $constraint ;
}
2013-10-14 02:01:26 +00:00
}
2015-02-17 14:37:33 +00:00
2019-11-23 13:43:22 +00:00
$rootRequires = array ();
2013-10-14 02:01:26 +00:00
foreach ( $requires as $req => $constraint ) {
2014-10-17 14:26:00 +00:00
// skip platform requirements from the root package to avoid filtering out existing platform packages
if ( $this -> ignorePlatformReqs && preg_match ( PlatformRepository :: PLATFORM_PACKAGE_REGEX , $req )) {
continue ;
}
2015-02-17 14:37:33 +00:00
if ( $constraint instanceof Link ) {
2019-11-23 13:43:22 +00:00
$rootRequires [ $req ] = $constraint -> getConstraint ();
2015-02-17 14:37:33 +00:00
} else {
2019-11-23 13:43:22 +00:00
$rootRequires [ $req ] = $constraint ;
2015-02-17 14:37:33 +00:00
}
2013-10-14 02:01:26 +00:00
}
2018-09-13 13:23:05 +00:00
$this -> fixedRootPackage = clone $this -> package ;
$this -> fixedRootPackage -> setRequires ( array ());
$this -> fixedRootPackage -> setDevRequires ( array ());
2019-11-23 13:43:22 +00:00
$repositorySet = new RepositorySet ( $rootAliases , $this -> package -> getReferences (), $minimumStability , $stabilityFlags , $rootRequires );
2018-09-13 13:23:05 +00:00
$repositorySet -> addRepository ( new InstalledArrayRepository ( array ( $this -> fixedRootPackage )));
$repositorySet -> addRepository ( $platformRepo );
if ( $this -> additionalFixedRepository ) {
$repositorySet -> addRepository ( $this -> additionalFixedRepository );
}
return $repositorySet ;
2013-03-28 20:02:55 +00:00
}
2015-07-07 14:53:33 +00:00
/**
* @ return DefaultPolicy
*/
2018-09-13 13:23:05 +00:00
private function createPolicy ( $forUpdate )
2013-03-28 20:02:55 +00:00
{
2014-07-19 17:43:59 +00:00
$preferStable = null ;
2014-12-13 22:56:15 +00:00
$preferLowest = null ;
2018-09-13 13:23:05 +00:00
if ( ! $forUpdate ) {
2014-07-19 17:43:59 +00:00
$preferStable = $this -> locker -> getPreferStable ();
2014-12-13 22:56:15 +00:00
$preferLowest = $this -> locker -> getPreferLowest ();
2014-07-19 17:43:59 +00:00
}
2014-12-13 22:56:15 +00:00
// old lock file without prefer stable/lowest will return null
2014-07-19 17:43:59 +00:00
// so in this case we use the composer.json info
if ( null === $preferStable ) {
2014-12-02 08:18:44 +00:00
$preferStable = $this -> preferStable || $this -> package -> getPreferStable ();
2014-12-13 22:56:15 +00:00
}
if ( null === $preferLowest ) {
2014-12-02 08:18:44 +00:00
$preferLowest = $this -> preferLowest ;
2014-07-19 17:43:59 +00:00
}
2014-11-21 13:01:01 +00:00
return new DefaultPolicy ( $preferStable , $preferLowest );
2013-03-02 23:41:12 +00:00
}
2015-07-07 14:53:33 +00:00
/**
2019-09-07 00:28:40 +00:00
* @ param RootPackageInterface $rootPackage
* @ param PlatformRepository $platformRepo
* @ param RepositoryInterface | null $lockedRepository
2015-07-07 14:53:33 +00:00
* @ return Request
*/
2019-09-07 00:28:40 +00:00
private function createRequest ( RootPackageInterface $rootPackage , PlatformRepository $platformRepo , $lockedRepository = null )
2013-03-02 23:41:12 +00:00
{
2019-09-07 00:28:40 +00:00
$request = new Request ( $lockedRepository );
2013-03-02 23:41:12 +00:00
2018-09-13 13:23:05 +00:00
$request -> fixPackage ( $rootPackage , false );
2013-03-02 23:41:12 +00:00
2013-05-11 11:01:08 +00:00
$fixedPackages = $platformRepo -> getPackages ();
2018-09-13 13:23:05 +00:00
if ( $this -> additionalFixedRepository ) {
$fixedPackages = array_merge ( $fixedPackages , $this -> additionalFixedRepository -> getPackages ());
2013-05-10 17:25:23 +00:00
}
2013-05-11 11:01:08 +00:00
// fix the version of all platform packages + additionally installed packages
// to prevent the solver trying to remove or update those
2018-09-13 13:23:05 +00:00
// TODO why not replaces?
2013-05-11 11:01:08 +00:00
$provided = $rootPackage -> getProvides ();
foreach ( $fixedPackages as $package ) {
// skip platform packages that are provided by the root package
if ( $package -> getRepository () !== $platformRepo
2013-03-02 23:41:12 +00:00
|| ! isset ( $provided [ $package -> getName ()])
2018-09-13 13:23:05 +00:00
|| ! $provided [ $package -> getName ()] -> getConstraint () -> matches ( new Constraint ( '=' , $package -> getVersion ()))
2013-03-02 23:41:12 +00:00
) {
2018-09-13 13:23:05 +00:00
$request -> fixPackage ( $package , false );
2013-03-02 23:41:12 +00:00
}
}
return $request ;
}
2015-07-07 14:53:33 +00:00
/**
2019-02-14 16:57:29 +00:00
* @ param bool $forUpdate
2015-07-07 14:53:33 +00:00
* @ return array
*/
2019-02-14 16:57:29 +00:00
private function getRootAliases ( $forUpdate )
2012-04-14 13:45:25 +00:00
{
2019-02-14 16:57:29 +00:00
if ( $forUpdate ) {
2012-04-14 13:45:25 +00:00
$aliases = $this -> package -> getAliases ();
2016-03-10 18:36:58 +00:00
} else {
$aliases = $this -> locker -> getAliases ();
2012-04-14 10:07:49 +00:00
}
2012-08-22 12:20:43 +00:00
$normalizedAliases = array ();
2012-04-14 13:45:25 +00:00
foreach ( $aliases as $alias ) {
2012-08-22 13:39:16 +00:00
$normalizedAliases [ $alias [ 'package' ]][ $alias [ 'version' ]] = array (
'alias' => $alias [ 'alias' ],
2015-09-28 09:51:14 +00:00
'alias_normalized' => $alias [ 'alias_normalized' ],
2012-08-22 13:39:16 +00:00
);
2012-03-03 05:35:40 +00:00
}
2012-03-18 21:43:07 +00:00
2012-08-22 12:20:43 +00:00
return $normalizedAliases ;
2012-03-03 05:35:40 +00:00
}
2012-03-05 23:48:07 +00:00
2015-07-07 14:53:33 +00:00
/**
* @ param PlatformRepository $platformRepo
* @ param array $aliases
*/
2012-08-22 13:39:16 +00:00
private function aliasPlatformPackages ( PlatformRepository $platformRepo , $aliases )
{
2019-02-14 16:57:29 +00:00
// TODO should the repository set do this?
foreach ( $aliases as $packageName => $versions ) {
2012-08-22 13:39:16 +00:00
foreach ( $versions as $version => $alias ) {
2019-02-14 16:57:29 +00:00
$packages = $platformRepo -> findPackages ( $packageName , $version );
2012-08-22 13:39:16 +00:00
foreach ( $packages as $package ) {
$aliasPackage = new AliasPackage ( $package , $alias [ 'alias_normalized' ], $alias [ 'alias' ]);
$aliasPackage -> setRootPackageAlias ( true );
$platformRepo -> addPackage ( $aliasPackage );
}
}
}
}
2015-07-07 14:53:33 +00:00
/**
2015-09-28 09:51:14 +00:00
* @ param PackageInterface $package
2015-07-07 14:53:33 +00:00
* @ return bool
*/
2012-05-27 22:11:47 +00:00
private function isUpdateable ( PackageInterface $package )
{
if ( ! $this -> updateWhitelist ) {
throw new \LogicException ( 'isUpdateable should only be called when a whitelist is present' );
}
2012-12-13 14:37:11 +00:00
foreach ( $this -> updateWhitelist as $whiteListedPattern => $void ) {
2018-11-26 19:09:26 +00:00
$patternRegexp = BasePackage :: packageNameToRegexp ( $whiteListedPattern );
2014-02-24 11:28:08 +00:00
if ( preg_match ( $patternRegexp , $package -> getName ())) {
2012-12-13 09:08:04 +00:00
return true ;
}
}
return false ;
2012-05-27 23:58:54 +00:00
}
2015-07-07 14:53:33 +00:00
/**
2015-09-28 09:51:14 +00:00
* @ param array $links
2015-07-07 14:53:33 +00:00
* @ return array
*/
2013-06-13 11:28:24 +00:00
private function extractPlatformRequirements ( $links )
{
2013-03-03 19:05:46 +00:00
$platformReqs = array ();
foreach ( $links as $link ) {
2013-04-06 20:26:10 +00:00
if ( preg_match ( PlatformRepository :: PLATFORM_PACKAGE_REGEX , $link -> getTarget ())) {
2013-03-03 19:05:46 +00:00
$platformReqs [ $link -> getTarget ()] = $link -> getPrettyConstraint ();
}
}
return $platformReqs ;
}
2012-05-27 23:58:54 +00:00
/**
* Adds all dependencies of the update whitelist to the whitelist , too .
*
2012-05-28 10:02:15 +00:00
* Packages which are listed as requirements in the root package will be
* skipped including their dependencies , unless they are listed in the
2017-09-11 16:56:51 +00:00
* update whitelist themselves or $whitelistAllDependencies is true .
2012-05-28 10:02:15 +00:00
*
2018-09-13 13:23:05 +00:00
* @ param RepositoryInterface $lockRepo Use the locked repo
2017-05-16 19:59:19 +00:00
* As we want the most accurate package list to work with , and installed
* repo might be empty but locked repo will always be current .
2012-05-28 14:38:52 +00:00
* @ param array $rootRequires An array of links to packages in require of the root package
* @ param array $rootDevRequires An array of links to packages in require - dev of the root package
2012-05-27 23:58:54 +00:00
*/
2018-09-13 13:23:05 +00:00
private function whitelistUpdateDependencies ( $lockRepo , array $rootRequires , array $rootDevRequires )
2012-05-27 23:58:54 +00:00
{
2016-04-20 11:34:04 +00:00
$rootRequires = array_merge ( $rootRequires , $rootDevRequires );
2012-05-28 10:02:15 +00:00
$skipPackages = array ();
2017-09-11 16:30:48 +00:00
if ( ! $this -> whitelistAllDependencies ) {
2017-11-03 13:35:04 +00:00
foreach ( $rootRequires as $require ) {
$skipPackages [ $require -> getTarget ()] = true ;
}
2012-05-28 10:02:15 +00:00
}
2019-09-06 23:58:12 +00:00
$repositorySet = new RepositorySet ( array (), array (), 'dev' );
2018-09-13 13:23:05 +00:00
$repositorySet -> addRepository ( $lockRepo );
2012-05-27 23:58:54 +00:00
$seen = array ();
2014-02-24 11:28:08 +00:00
$rootRequiredPackageNames = array_keys ( $rootRequires );
2012-05-27 23:58:54 +00:00
foreach ( $this -> updateWhitelist as $packageName => $void ) {
$packageQueue = new \SplQueue ;
2019-01-29 16:18:58 +00:00
$nameMatchesRequiredPackage = false ;
2012-05-27 23:58:54 +00:00
2018-09-11 13:59:02 +00:00
$depPackages = $repositorySet -> findPackages ( $packageName , null , false );
2018-12-17 14:21:03 +00:00
$matchesByPattern = array ();
2014-02-24 11:28:08 +00:00
2014-02-24 11:49:09 +00:00
// check if the name is a glob pattern that did not match directly
2018-12-13 12:54:22 +00:00
if ( empty ( $depPackages )) {
2019-01-28 16:54:32 +00:00
// add any installed package matching the whitelisted name/pattern
2018-12-13 12:54:22 +00:00
$whitelistPatternSearchRegexp = BasePackage :: packageNameToRegexp ( $packageName , '^%s$' );
2018-09-13 13:23:05 +00:00
foreach ( $lockRepo -> search ( $whitelistPatternSearchRegexp ) as $installedPackage ) {
2019-01-28 17:00:52 +00:00
$matchesByPattern [] = $repositorySet -> findPackages ( $installedPackage [ 'name' ], null , false );
2018-12-13 12:54:22 +00:00
}
2019-01-28 16:54:32 +00:00
// add root requirements which match the whitelisted name/pattern
2018-11-26 19:09:26 +00:00
$whitelistPatternRegexp = BasePackage :: packageNameToRegexp ( $packageName );
2014-02-24 11:28:08 +00:00
foreach ( $rootRequiredPackageNames as $rootRequiredPackageName ) {
if ( preg_match ( $whitelistPatternRegexp , $rootRequiredPackageName )) {
$nameMatchesRequiredPackage = true ;
break ;
}
}
}
2018-12-13 12:54:22 +00:00
if ( ! empty ( $matchesByPattern )) {
2018-12-17 14:21:03 +00:00
$depPackages = array_merge ( $depPackages , call_user_func_array ( 'array_merge' , $matchesByPattern ));
2018-12-13 12:54:22 +00:00
}
2018-12-12 16:27:26 +00:00
2019-11-07 16:35:44 +00:00
if ( count ( $depPackages ) == 0 && ! $nameMatchesRequiredPackage ) {
2015-02-06 12:52:44 +00:00
$this -> io -> writeError ( '<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>' );
2013-03-01 13:35:32 +00:00
}
foreach ( $depPackages as $depPackage ) {
2012-05-27 23:58:54 +00:00
$packageQueue -> enqueue ( $depPackage );
2012-05-27 22:11:47 +00:00
}
2012-05-27 23:58:54 +00:00
while ( ! $packageQueue -> isEmpty ()) {
$package = $packageQueue -> dequeue ();
2018-09-11 11:33:29 +00:00
if ( isset ( $seen [ spl_object_hash ( $package )])) {
2012-05-27 23:58:54 +00:00
continue ;
}
2018-09-11 11:33:29 +00:00
$seen [ spl_object_hash ( $package )] = true ;
2012-05-27 23:58:54 +00:00
$this -> updateWhitelist [ $package -> getName ()] = true ;
2018-09-11 13:59:02 +00:00
if ( ! $this -> whitelistTransitiveDependencies && ! $this -> whitelistAllDependencies ) {
2013-10-14 08:49:34 +00:00
continue ;
}
2012-05-27 23:58:54 +00:00
$requires = $package -> getRequires ();
foreach ( $requires as $require ) {
2018-09-11 13:59:02 +00:00
$requirePackages = $repositorySet -> findPackages ( $require -> getTarget (), null , false );
2012-05-27 23:58:54 +00:00
foreach ( $requirePackages as $requirePackage ) {
2017-09-11 16:27:20 +00:00
if ( isset ( $this -> updateWhitelist [ $requirePackage -> getName ()])) {
2016-03-15 10:17:58 +00:00
continue ;
}
2018-12-13 12:54:22 +00:00
if ( isset ( $skipPackages [ $requirePackage -> getName ()]) && ! preg_match ( BasePackage :: packageNameToRegexp ( $packageName ), $requirePackage -> getName ())) {
2016-02-02 09:45:57 +00:00
$this -> io -> writeError ( '<warning>Dependency "' . $requirePackage -> getName () . '" is also a root requirement, but is not explicitly whitelisted. Ignoring.</warning>' );
2012-05-28 10:02:15 +00:00
continue ;
}
2016-03-15 10:17:58 +00:00
2012-05-27 23:58:54 +00:00
$packageQueue -> enqueue ( $requirePackage );
}
}
}
}
2012-05-27 22:11:47 +00:00
}
2012-10-22 13:50:40 +00:00
/**
* Replace local repositories with InstalledArrayRepository instances
*
* This is to prevent any accidental modification of the existing repos on disk
*
* @ param RepositoryManager $rm
*/
private function mockLocalRepositories ( RepositoryManager $rm )
{
2013-03-21 11:08:58 +00:00
$packages = array ();
foreach ( $rm -> getLocalRepository () -> getPackages () as $package ) {
$packages [( string ) $package ] = clone $package ;
}
2012-10-22 13:50:40 +00:00
foreach ( $packages as $key => $package ) {
if ( $package instanceof AliasPackage ) {
2013-03-21 11:08:58 +00:00
$alias = ( string ) $package -> getAliasOf ();
$packages [ $key ] = new AliasPackage ( $packages [ $alias ], $package -> getVersion (), $package -> getPrettyVersion ());
2012-10-22 13:50:40 +00:00
}
}
$rm -> setLocalRepository (
new InstalledArrayRepository ( $packages )
);
}
2012-03-05 23:48:07 +00:00
/**
2012-03-06 23:30:18 +00:00
* Create Installer
2012-03-10 00:16:37 +00:00
*
2013-06-13 11:28:24 +00:00
* @ param IOInterface $io
* @ param Composer $composer
2012-03-06 23:30:18 +00:00
* @ return Installer
2012-03-05 23:48:07 +00:00
*/
2013-01-06 19:34:52 +00:00
public static function create ( IOInterface $io , Composer $composer )
2012-03-05 23:48:07 +00:00
{
return new static (
$io ,
2012-06-24 19:58:51 +00:00
$composer -> getConfig (),
2012-03-05 23:48:07 +00:00
$composer -> getPackage (),
$composer -> getDownloadManager (),
$composer -> getRepositoryManager (),
$composer -> getLocker (),
$composer -> getInstallationManager (),
2013-01-06 19:34:52 +00:00
$composer -> getEventDispatcher (),
$composer -> getAutoloadGenerator ()
2012-03-05 23:48:07 +00:00
);
}
2012-03-10 17:08:36 +00:00
2015-07-07 14:53:33 +00:00
/**
2018-09-13 13:23:05 +00:00
* @ param RepositoryInterface $additionalFixedRepository
2015-07-07 14:53:33 +00:00
* @ return $this
*/
2018-09-13 13:23:05 +00:00
public function setAdditionalFixedRepository ( RepositoryInterface $additionalFixedRepository )
2012-03-10 17:08:36 +00:00
{
2018-09-13 13:23:05 +00:00
$this -> additionalFixedRepository = $additionalFixedRepository ;
2012-03-10 17:08:36 +00:00
return $this ;
}
/**
2012-10-24 23:14:04 +00:00
* Whether to run in drymode or not
2012-03-10 17:08:36 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $dryRun
2012-03-10 17:08:36 +00:00
* @ return Installer
*/
2012-04-14 09:55:57 +00:00
public function setDryRun ( $dryRun = true )
2012-03-10 17:08:36 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> dryRun = ( bool ) $dryRun ;
2012-03-10 17:08:36 +00:00
return $this ;
}
2014-10-11 17:30:19 +00:00
/**
* Checks , if this is a dry run ( simulation mode ) .
*
* @ return bool
*/
public function isDryRun ()
{
return $this -> dryRun ;
}
2012-03-10 17:08:36 +00:00
/**
2012-04-14 09:55:57 +00:00
* prefer source installation
2012-03-10 17:08:36 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $preferSource
2012-03-10 17:08:36 +00:00
* @ return Installer
*/
2012-04-14 09:55:57 +00:00
public function setPreferSource ( $preferSource = true )
2012-03-10 17:08:36 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> preferSource = ( bool ) $preferSource ;
2012-03-10 17:08:36 +00:00
return $this ;
}
2012-08-31 20:25:17 +00:00
/**
* prefer dist installation
*
2015-09-28 09:51:14 +00:00
* @ param bool $preferDist
2012-08-31 20:25:17 +00:00
* @ return Installer
*/
public function setPreferDist ( $preferDist = true )
{
2017-03-08 14:07:29 +00:00
$this -> preferDist = ( bool ) $preferDist ;
2012-08-31 20:25:17 +00:00
return $this ;
}
2012-10-23 11:41:17 +00:00
/**
2012-10-24 23:14:04 +00:00
* Whether or not generated autoloader are optimized
2012-10-23 11:41:17 +00:00
*
2013-01-05 19:01:58 +00:00
* @ param bool $optimizeAutoloader
2012-10-23 11:41:17 +00:00
* @ return Installer
*/
2012-10-24 15:33:31 +00:00
public function setOptimizeAutoloader ( $optimizeAutoloader = false )
2012-10-23 11:41:17 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> optimizeAutoloader = ( bool ) $optimizeAutoloader ;
2015-08-16 19:56:52 +00:00
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 .
*
* @ param bool $classMapAuthoritative
* @ return Installer
*/
public function setClassMapAuthoritative ( $classMapAuthoritative = false )
{
2017-03-08 14:07:29 +00:00
$this -> classMapAuthoritative = ( bool ) $classMapAuthoritative ;
2015-08-16 19:56:52 +00:00
if ( $this -> classMapAuthoritative ) {
// Force optimizeAutoloader when classmap is authoritative
$this -> setOptimizeAutoloader ( true );
}
2012-10-23 11:41:17 +00:00
return $this ;
}
2016-07-28 08:23:39 +00:00
/**
* Whether or not generated autoloader considers APCu caching .
*
* @ param bool $apcuAutoloader
* @ return Installer
*/
public function setApcuAutoloader ( $apcuAutoloader = false )
{
2017-03-08 14:07:29 +00:00
$this -> apcuAutoloader = ( bool ) $apcuAutoloader ;
2016-07-28 08:23:39 +00:00
return $this ;
}
2012-03-10 17:08:36 +00:00
/**
2012-04-14 09:55:57 +00:00
* update packages
2012-03-10 17:08:36 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $update
2012-03-10 17:08:36 +00:00
* @ return Installer
*/
2012-04-14 09:55:57 +00:00
public function setUpdate ( $update = true )
2012-03-10 17:08:36 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> update = ( bool ) $update ;
2012-03-10 17:08:36 +00:00
return $this ;
}
/**
2012-04-14 09:55:57 +00:00
* enables dev packages
2012-03-10 17:08:36 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $devMode
2012-03-10 17:08:36 +00:00
* @ return Installer
*/
2012-04-14 09:55:57 +00:00
public function setDevMode ( $devMode = true )
2012-03-10 17:08:36 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> devMode = ( bool ) $devMode ;
2012-03-10 17:08:36 +00:00
return $this ;
}
2014-11-21 21:16:19 +00:00
/**
* set whether to run autoloader or not
2014-12-29 20:29:13 +00:00
*
2016-12-06 21:40:47 +00:00
* This is disabled implicitly when enabling dryRun
*
2015-09-28 09:51:14 +00:00
* @ param bool $dumpAutoloader
2014-11-21 21:16:19 +00:00
* @ return Installer
*/
2014-12-29 20:29:13 +00:00
public function setDumpAutoloader ( $dumpAutoloader = true )
2014-11-21 21:16:19 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> dumpAutoloader = ( bool ) $dumpAutoloader ;
2014-12-29 20:29:13 +00:00
2014-11-21 21:16:19 +00:00
return $this ;
}
2012-04-16 17:45:06 +00:00
/**
2012-05-13 11:25:02 +00:00
* set whether to run scripts or not
2012-04-16 17:45:06 +00:00
*
2016-12-06 21:40:47 +00:00
* This is disabled implicitly when enabling dryRun
*
2015-09-28 09:51:14 +00:00
* @ param bool $runScripts
2012-04-16 17:45:06 +00:00
* @ return Installer
*/
2012-05-13 11:25:02 +00:00
public function setRunScripts ( $runScripts = true )
2012-04-16 17:45:06 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> runScripts = ( bool ) $runScripts ;
2012-04-16 17:45:06 +00:00
return $this ;
}
2012-06-24 19:58:51 +00:00
/**
* set the config instance
*
* @ param Config $config
* @ return Installer
*/
public function setConfig ( Config $config )
{
$this -> config = $config ;
return $this ;
}
2012-03-10 17:08:36 +00:00
/**
* run in verbose mode
*
2015-09-28 09:51:14 +00:00
* @ param bool $verbose
2012-03-10 17:08:36 +00:00
* @ return Installer
*/
2012-04-14 09:55:57 +00:00
public function setVerbose ( $verbose = true )
2012-03-10 17:08:36 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> verbose = ( bool ) $verbose ;
2012-03-10 17:08:36 +00:00
return $this ;
}
2012-05-26 13:20:27 +00:00
2014-10-11 17:46:37 +00:00
/**
* Checks , if running in verbose mode .
*
* @ return bool
*/
public function isVerbose ()
{
return $this -> verbose ;
}
2014-10-02 05:01:15 +00:00
/**
* set ignore Platform Package requirements
*
2015-09-28 09:51:14 +00:00
* @ param bool $ignorePlatformReqs
2014-10-02 05:01:15 +00:00
* @ return Installer
*/
2014-10-17 14:26:00 +00:00
public function setIgnorePlatformRequirements ( $ignorePlatformReqs = false )
2014-10-15 13:42:07 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> ignorePlatformReqs = ( bool ) $ignorePlatformReqs ;
2014-10-02 05:01:15 +00:00
return $this ;
}
2019-11-07 16:35:44 +00:00
/**
* Update the lock file to the exact same versions and references but use current remote metadata like URLs and mirror info
*
* @ param bool $updateMirrors
* @ return Installer
*/
public function setUpdateMirrors ( $updateMirrors )
{
$this -> updateMirrors = $updateMirrors ;
return $this ;
}
2012-05-26 13:20:27 +00:00
/**
* restrict the update operation to a few packages , all other packages
* that are already installed will be kept at their current version
*
* @ param array $packages
* @ return Installer
*/
public function setUpdateWhitelist ( array $packages )
{
2012-05-27 23:58:54 +00:00
$this -> updateWhitelist = array_flip ( array_map ( 'strtolower' , $packages ));
2012-05-26 13:20:27 +00:00
return $this ;
}
2012-07-21 14:51:40 +00:00
2017-11-03 13:35:04 +00:00
/**
* Should dependencies of whitelisted packages ( but not direct dependencies ) be updated ?
2017-09-11 15:16:15 +00:00
*
* This will NOT whitelist any dependencies that are also directly defined
* in the root package .
2013-10-14 08:49:34 +00:00
*
2017-11-03 13:35:04 +00:00
* @ param bool $updateTransitiveDependencies
2013-10-14 08:49:34 +00:00
* @ return Installer
*/
2017-11-03 13:35:04 +00:00
public function setWhitelistTransitiveDependencies ( $updateTransitiveDependencies = true )
2013-10-14 08:49:34 +00:00
{
2018-09-11 13:59:02 +00:00
$this -> whitelistTransitiveDependencies = ( bool ) $updateTransitiveDependencies ;
2013-10-14 08:49:34 +00:00
return $this ;
}
2017-09-11 15:16:15 +00:00
/**
* Should all dependencies of whitelisted packages be updated recursively ?
*
2017-11-03 13:35:04 +00:00
* This will whitelist any dependencies of the whitelisted packages , including
* those defined in the root package .
2017-09-11 15:16:15 +00:00
*
* @ param bool $updateAllDependencies
* @ return Installer
*/
2017-09-11 17:53:56 +00:00
public function setWhitelistAllDependencies ( $updateAllDependencies = true )
2017-09-11 15:16:15 +00:00
{
$this -> whitelistAllDependencies = ( bool ) $updateAllDependencies ;
return $this ;
}
2014-11-21 13:01:01 +00:00
/**
2015-03-20 14:23:24 +00:00
* Should packages be preferred in a stable version when updating ?
2014-12-02 08:18:44 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $preferStable
2014-12-02 08:18:44 +00:00
* @ return Installer
*/
public function setPreferStable ( $preferStable = true )
{
2017-03-08 14:07:29 +00:00
$this -> preferStable = ( bool ) $preferStable ;
2014-12-02 08:18:44 +00:00
return $this ;
}
/**
2015-03-20 14:23:24 +00:00
* Should packages be preferred in a lowest version when updating ?
2014-11-21 13:01:01 +00:00
*
2015-09-28 09:51:14 +00:00
* @ param bool $preferLowest
2014-11-21 13:01:01 +00:00
* @ return Installer
*/
2014-12-02 08:18:44 +00:00
public function setPreferLowest ( $preferLowest = true )
2014-11-21 13:01:01 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> preferLowest = ( bool ) $preferLowest ;
2014-11-21 13:01:01 +00:00
return $this ;
}
2016-12-06 21:40:47 +00:00
/**
* Should the lock file be updated when updating ?
*
* This is disabled implicitly when enabling dryRun
*
* @ param bool $writeLock
* @ return Installer
*/
public function setWriteLock ( $writeLock = true )
{
2017-03-08 14:07:29 +00:00
$this -> writeLock = ( bool ) $writeLock ;
2016-12-06 21:40:47 +00:00
return $this ;
}
/**
2018-06-05 13:55:14 +00:00
* Should the operations ( package install , update and removal ) be executed on disk ?
2016-12-06 21:40:47 +00:00
*
* This is disabled implicitly when enabling dryRun
*
* @ param bool $executeOperations
* @ return Installer
*/
public function setExecuteOperations ( $executeOperations = true )
{
2017-03-08 14:07:29 +00:00
$this -> executeOperations = ( bool ) $executeOperations ;
2016-12-06 21:40:47 +00:00
return $this ;
}
2016-05-31 22:48:26 +00:00
/**
* Should suggestions be skipped ?
*
* @ param bool $skipSuggest
* @ return Installer
*/
2016-06-06 10:22:06 +00:00
public function setSkipSuggest ( $skipSuggest = true )
2016-05-31 22:48:26 +00:00
{
2017-03-08 14:07:29 +00:00
$this -> skipSuggest = ( bool ) $skipSuggest ;
2016-05-31 22:48:26 +00:00
return $this ;
}
2012-07-21 14:51:40 +00:00
/**
2013-08-13 11:25:21 +00:00
* Disables plugins .
2012-07-21 14:51:40 +00:00
*
* 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 .
2012-11-01 15:22:37 +00:00
*
* @ return Installer
2012-07-21 14:51:40 +00:00
*/
2013-08-13 11:25:21 +00:00
public function disablePlugins ()
2012-07-21 14:51:40 +00:00
{
2013-08-13 11:25:21 +00:00
$this -> installationManager -> disablePlugins ();
2012-11-01 15:22:37 +00:00
return $this ;
2012-07-21 14:51:40 +00:00
}
2016-03-02 21:13:06 +00:00
/**
2016-04-11 14:06:57 +00:00
* @ param SuggestedPackagesReporter $suggestedPackagesReporter
2016-03-02 21:13:06 +00:00
* @ return Installer
*/
public function setSuggestedPackagesReporter ( SuggestedPackagesReporter $suggestedPackagesReporter )
{
$this -> suggestedPackagesReporter = $suggestedPackagesReporter ;
return $this ;
}
2012-03-03 05:35:40 +00:00
}