1
0
Fork 0

Split Composer into PartialComposer & Composer classes to avoid nullable properties on Composer for non-fully-loaded instances, add types to Composer\Factory

pull/10547/head
Jordi Boggiano 2022-02-18 14:45:08 +01:00
parent eda9014bef
commit 84f0f19112
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
11 changed files with 264 additions and 289 deletions

View File

@ -98,7 +98,7 @@ EOT
$composer = $this->requireComposer();
if ((!$composer->getLocker() || !$composer->getLocker()->isLocked()) && !HttpDownloader::isCurlEnabled()) {
if (!$composer->getLocker()->isLocked() && !HttpDownloader::isCurlEnabled()) {
$io->writeError('<warning>Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.</warning>');
}

View File

@ -12,15 +12,10 @@
namespace Composer;
use Composer\Package\RootPackageInterface;
use Composer\Package\Locker;
use Composer\Pcre\Preg;
use Composer\Util\Loop;
use Composer\Repository\RepositoryManager;
use Composer\Installer\InstallationManager;
use Composer\Plugin\PluginManager;
use Composer\Downloader\DownloadManager;
use Composer\EventDispatcher\EventDispatcher;
use Composer\Autoload\AutoloadGenerator;
use Composer\Package\Archiver\ArchiveManager;
@ -29,7 +24,7 @@ use Composer\Package\Archiver\ArchiveManager;
* @author Konstantin Kudryashiv <ever.zet@gmail.com>
* @author Nils Adermann <naderman@naderman.de>
*/
class Composer
class Composer extends PartialComposer
{
/*
* Examples of the following constants in the various configurations they can be in
@ -87,220 +82,76 @@ class Composer
}
/**
* @var RootPackageInterface
* @var Locker
*/
private $package;
private $locker;
/**
* @var Locker|null
* @var Downloader\DownloadManager
*/
private $locker = null;
private $downloadManager;
/**
* @var Loop
* @var Plugin\PluginManager
*/
private $loop;
private $pluginManager;
/**
* @var Repository\RepositoryManager
* @var Autoload\AutoloadGenerator
*/
private $repositoryManager;
private $autoloadGenerator;
/**
* @var Downloader\DownloadManager|null
* @var ArchiveManager
*/
private $downloadManager = null;
private $archiveManager;
/**
* @var Installer\InstallationManager
*/
private $installationManager;
/**
* @var Plugin\PluginManager|null
*/
private $pluginManager = null;
/**
* @var Config
*/
private $config;
/**
* @var EventDispatcher
*/
private $eventDispatcher;
/**
* @var Autoload\AutoloadGenerator|null
*/
private $autoloadGenerator = null;
/**
* @var ArchiveManager|null
*/
private $archiveManager = null;
/**
* @return void
*/
public function setPackage(RootPackageInterface $package): void
{
$this->package = $package;
}
/**
* @return RootPackageInterface
*/
public function getPackage(): RootPackageInterface
{
return $this->package;
}
/**
* @return void
*/
public function setConfig(Config $config): void
{
$this->config = $config;
}
/**
* @return Config
*/
public function getConfig(): Config
{
return $this->config;
}
/**
* @return void
*/
public function setLocker(Locker $locker): void
{
$this->locker = $locker;
}
/**
* @return ?Locker
*/
public function getLocker(): ?Locker
public function getLocker(): Locker
{
return $this->locker;
}
/**
* @return void
*/
public function setLoop(Loop $loop): void
{
$this->loop = $loop;
}
/**
* @return Loop
*/
public function getLoop(): Loop
{
return $this->loop;
}
/**
* @return void
*/
public function setRepositoryManager(RepositoryManager $manager): void
{
$this->repositoryManager = $manager;
}
/**
* @return RepositoryManager
*/
public function getRepositoryManager(): RepositoryManager
{
return $this->repositoryManager;
}
/**
* @return void
*/
public function setDownloadManager(DownloadManager $manager): void
{
$this->downloadManager = $manager;
}
public function getDownloadManager(): ?DownloadManager
public function getDownloadManager(): DownloadManager
{
return $this->downloadManager;
}
/**
* @return void
*/
public function setArchiveManager(ArchiveManager $manager): void
{
$this->archiveManager = $manager;
}
public function getArchiveManager(): ?ArchiveManager
public function getArchiveManager(): ArchiveManager
{
return $this->archiveManager;
}
/**
* @return void
*/
public function setInstallationManager(InstallationManager $manager): void
{
$this->installationManager = $manager;
}
/**
* @return InstallationManager
*/
public function getInstallationManager(): InstallationManager
{
return $this->installationManager;
}
/**
* @return void
*/
public function setPluginManager(PluginManager $manager): void
{
$this->pluginManager = $manager;
}
public function getPluginManager(): ?PluginManager
public function getPluginManager(): PluginManager
{
return $this->pluginManager;
}
/**
* @return void
*/
public function setEventDispatcher(EventDispatcher $eventDispatcher): void
{
$this->eventDispatcher = $eventDispatcher;
}
/**
* @return EventDispatcher
*/
public function getEventDispatcher(): EventDispatcher
{
return $this->eventDispatcher;
}
/**
* @return void
*/
public function setAutoloadGenerator(AutoloadGenerator $autoloadGenerator): void
{
$this->autoloadGenerator = $autoloadGenerator;
}
public function getAutoloadGenerator(): ?AutoloadGenerator
public function getAutoloadGenerator(): AutoloadGenerator
{
return $this->autoloadGenerator;
}

View File

@ -560,7 +560,7 @@ class Application extends BaseApplication
$composer = $this->getComposer(false, false);
if (null === $composer) {
$composer = Factory::createGlobal($this->io);
$composer = Factory::createGlobal($this->io, $this->disablePluginsByDefault, $this->disableScriptsByDefault);
}
if (null !== $composer) {

View File

@ -12,10 +12,12 @@
namespace Composer\EventDispatcher;
use Composer\Autoload\AutoloadGenerator;
use Composer\DependencyResolver\Transaction;
use Composer\Installer\InstallerEvent;
use Composer\IO\IOInterface;
use Composer\Composer;
use Composer\PartialComposer;
use Composer\Pcre\Preg;
use Composer\Util\Platform;
use Composer\DependencyResolver\Operation\OperationInterface;
@ -44,7 +46,7 @@ use Symfony\Component\Process\ExecutableFinder;
*/
class EventDispatcher
{
/** @var Composer */
/** @var PartialComposer */
protected $composer;
/** @var IOInterface */
protected $io;
@ -62,11 +64,11 @@ class EventDispatcher
/**
* Constructor.
*
* @param Composer $composer The composer instance
* @param PartialComposer $composer The composer instance
* @param IOInterface $io The IOInterface instance
* @param ProcessExecutor $process
*/
public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
public function __construct(PartialComposer $composer, IOInterface $io, ProcessExecutor $process = null)
{
$this->composer = $composer;
$this->io = $io;
@ -116,6 +118,8 @@ class EventDispatcher
*/
public function dispatchScript($eventName, $devMode = false, $additionalArgs = array(), $flags = array())
{
assert($this->composer instanceof Composer, new \LogicException('This should only be reached with a fully loaded Composer'));
return $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
}
@ -133,6 +137,8 @@ class EventDispatcher
*/
public function dispatchPackageEvent($eventName, $devMode, RepositoryInterface $localRepo, array $operations, OperationInterface $operation)
{
assert($this->composer instanceof Composer, new \LogicException('This should only be reached with a fully loaded Composer'));
return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $localRepo, $operations, $operation));
}
@ -149,6 +155,8 @@ class EventDispatcher
*/
public function dispatchInstallerEvent($eventName, $devMode, $executeOperations, Transaction $transaction)
{
assert($this->composer instanceof Composer, new \LogicException('This should only be reached with a fully loaded Composer'));
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $executeOperations, $transaction));
}
@ -486,6 +494,8 @@ class EventDispatcher
return array();
}
assert($this->composer instanceof Composer, new \LogicException('This should only be reached with a fully loaded Composer'));
if ($this->loader) {
$this->loader->unregister();
}

View File

@ -28,6 +28,7 @@ use Composer\Util\Loop;
use Composer\Util\Silencer;
use Composer\Plugin\PluginEvents;
use Composer\EventDispatcher\Event;
use Phar;
use Seld\JsonLint\DuplicateKeyException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
@ -39,6 +40,7 @@ use Composer\Downloader\TransportException;
use Composer\Json\JsonValidationException;
use Composer\Repository\InstalledRepositoryInterface;
use Seld\JsonLint\JsonParser;
use ZipArchive;
/**
* Creates a configured instance of composer.
@ -52,9 +54,8 @@ class Factory
{
/**
* @throws \RuntimeException
* @return string
*/
protected static function getHomeDir()
protected static function getHomeDir(): string
{
$home = Platform::getEnv('COMPOSER_HOME');
if ($home) {
@ -95,11 +96,7 @@ class Factory
return $dirs[0];
}
/**
* @param string $home
* @return string
*/
protected static function getCacheDir($home)
protected static function getCacheDir(string $home): string
{
$cacheDir = Platform::getEnv('COMPOSER_CACHE_DIR');
if ($cacheDir) {
@ -144,11 +141,7 @@ class Factory
return $home . '/cache';
}
/**
* @param string $home
* @return string
*/
protected static function getDataDir($home)
protected static function getDataDir(string $home): string
{
$homeEnv = Platform::getEnv('COMPOSER_HOME');
if ($homeEnv) {
@ -169,12 +162,7 @@ class Factory
return $home;
}
/**
* @param string|null $cwd
*
* @return Config
*/
public static function createConfig(IOInterface $io = null, $cwd = null)
public static function createConfig(IOInterface $io = null, ?string $cwd = null): Config
{
$cwd = $cwd ?: (string) getcwd();
@ -243,20 +231,12 @@ class Factory
return $config;
}
/**
* @return string
*/
public static function getComposerFile()
public static function getComposerFile(): string
{
return trim((string) Platform::getEnv('COMPOSER')) ?: './composer.json';
}
/**
* @param string $composerFile
*
* @return string
*/
public static function getLockFile($composerFile)
public static function getLockFile(string $composerFile): string
{
return "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
? substr($composerFile, 0, -4).'lock'
@ -266,7 +246,7 @@ class Factory
/**
* @return array{highlight: OutputFormatterStyle, warning: OutputFormatterStyle}
*/
public static function createAdditionalStyles()
public static function createAdditionalStyles(): array
{
return array(
'highlight' => new OutputFormatterStyle('red'),
@ -274,12 +254,7 @@ class Factory
);
}
/**
* Creates a ConsoleOutput instance
*
* @return ConsoleOutput
*/
public static function createOutput()
public static function createOutput(): ConsoleOutput
{
$styles = self::createAdditionalStyles();
$formatter = new OutputFormatter(false, $styles);
@ -299,9 +274,9 @@ class Factory
* @param bool $fullLoad Whether to initialize everything or only main project stuff (used when loading the global composer)
* @throws \InvalidArgumentException
* @throws \UnexpectedValueException
* @return Composer
* @return Composer|PartialComposer Composer if $fullLoad is true, otherwise PartialComposer
*/
public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true, $disableScripts = false)
public function createComposer(IOInterface $io, $localConfig = null, bool $disablePlugins = false, ?string $cwd = null, bool $fullLoad = true, bool $disableScripts = false)
{
$cwd = $cwd ?: (string) getcwd();
@ -363,7 +338,7 @@ class Factory
$vendorDir = $config->get('vendor-dir');
// initialize composer
$composer = new Composer();
$composer = $fullLoad ? new Composer() : new PartialComposer();
$composer->setConfig($config);
if ($fullLoad) {
@ -410,7 +385,7 @@ class Factory
$im = $this->createInstallationManager($loop, $io, $dispatcher);
$composer->setInstallationManager($im);
if ($fullLoad) {
if ($composer instanceof Composer) {
// initialize download manager
$dm = $this->createDownloadManager($io, $config, $httpDownloader, $process, $dispatcher);
$composer->setDownloadManager($dm);
@ -427,7 +402,7 @@ class Factory
// add installers to the manager (must happen after download manager is created since they read it out of $composer)
$this->createDefaultInstallers($im, $composer, $io, $process);
if ($fullLoad) {
if ($composer instanceof Composer) {
$globalComposer = null;
if (realpath($config->get('home')) !== $cwd) {
$globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins, $disableScripts);
@ -440,7 +415,7 @@ class Factory
}
// init locker if possible
if ($fullLoad && isset($composerFile)) {
if ($composer instanceof Composer && isset($composerFile)) {
$lockFile = self::getLockFile($composerFile);
$locker = new Package\Locker($io, new JsonFile($lockFile, null, $io), $im, file_get_contents($composerFile), $process);
@ -460,16 +435,17 @@ class Factory
}
/**
* @param IOInterface $io IO instance
* @param bool $disablePlugins Whether plugins should not be loaded
* @param bool $disableScripts Whether scripts should not be executed
* @return Composer|null
*/
public static function createGlobal(IOInterface $io, $disablePlugins = false, $disableScripts = false)
public static function createGlobal(IOInterface $io, bool $disablePlugins = false, bool $disableScripts = false): ?Composer
{
$factory = new static();
return $factory->createGlobalComposer($io, static::createConfig($io), $disablePlugins, $disableScripts, true);
$composer = $factory->createGlobalComposer($io, static::createConfig($io), $disablePlugins, $disableScripts, true);
assert(null === $composer || $composer instanceof Composer);
return $composer;
}
/**
@ -478,7 +454,7 @@ class Factory
*
* @return void
*/
protected function addLocalRepository(IOInterface $io, RepositoryManager $rm, $vendorDir, RootPackageInterface $rootPackage, ProcessExecutor $process = null)
protected function addLocalRepository(IOInterface $io, RepositoryManager $rm, $vendorDir, RootPackageInterface $rootPackage, ProcessExecutor $process = null): void
{
$fs = null;
if ($process) {
@ -489,13 +465,9 @@ class Factory
}
/**
* @param bool $disablePlugins
* @param bool $disableScripts
* @param bool $fullLoad
*
* @return Composer|null
* @return PartialComposer|Composer|null By default PartialComposer, but Composer if $fullLoad is set to true
*/
protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins, $disableScripts, $fullLoad = false)
protected function createGlobalComposer(IOInterface $io, Config $config, bool $disablePlugins, bool $disableScripts, bool $fullLoad = false): ?PartialComposer
{
$composer = null;
try {
@ -513,7 +485,7 @@ class Factory
* @param EventDispatcher $eventDispatcher
* @return Downloader\DownloadManager
*/
public function createDownloadManager(IOInterface $io, Config $config, HttpDownloader $httpDownloader, ProcessExecutor $process, EventDispatcher $eventDispatcher = null)
public function createDownloadManager(IOInterface $io, Config $config, HttpDownloader $httpDownloader, ProcessExecutor $process, EventDispatcher $eventDispatcher = null): Downloader\DownloadManager
{
$cache = null;
if ($config->get('cache-files-ttl') > 0) {
@ -566,20 +538,20 @@ class Factory
public function createArchiveManager(Config $config, Downloader\DownloadManager $dm, Loop $loop)
{
$am = new Archiver\ArchiveManager($dm, $loop);
$am->addArchiver(new Archiver\ZipArchiver);
$am->addArchiver(new Archiver\PharArchiver);
if (class_exists(ZipArchive::class)) {
$am->addArchiver(new Archiver\ZipArchiver);
}
if (class_exists(Phar::class)) {
$am->addArchiver(new Archiver\PharArchiver);
}
return $am;
}
/**
* @param IOInterface $io
* @param Composer $composer
* @param Composer $globalComposer
* @param bool $disablePlugins
* @return Plugin\PluginManager
*/
protected function createPluginManager(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
protected function createPluginManager(IOInterface $io, Composer $composer, PartialComposer $globalComposer = null, bool $disablePlugins = false): Plugin\PluginManager
{
return new Plugin\PluginManager($io, $composer, $globalComposer, $disablePlugins);
}
@ -587,7 +559,7 @@ class Factory
/**
* @return Installer\InstallationManager
*/
public function createInstallationManager(Loop $loop, IOInterface $io, EventDispatcher $eventDispatcher = null)
public function createInstallationManager(Loop $loop, IOInterface $io, EventDispatcher $eventDispatcher = null): Installer\InstallationManager
{
return new Installer\InstallationManager($loop, $io, $eventDispatcher);
}
@ -595,7 +567,7 @@ class Factory
/**
* @return void
*/
protected function createDefaultInstallers(Installer\InstallationManager $im, Composer $composer, IOInterface $io, ProcessExecutor $process = null)
protected function createDefaultInstallers(Installer\InstallationManager $im, PartialComposer $composer, IOInterface $io, ProcessExecutor $process = null): void
{
$fs = new Filesystem($process);
$binaryInstaller = new Installer\BinaryInstaller($io, rtrim($composer->getConfig()->get('bin-dir'), '/'), $composer->getConfig()->get('bin-compat'), $fs, rtrim($composer->getConfig()->get('vendor-dir'), '/'));
@ -608,10 +580,8 @@ class Factory
/**
* @param InstalledRepositoryInterface $repo repository to purge packages from
* @param Installer\InstallationManager $im manager to check whether packages are still installed
*
* @return void
*/
protected function purgePackages(InstalledRepositoryInterface $repo, Installer\InstallationManager $im)
protected function purgePackages(InstalledRepositoryInterface $repo, Installer\InstallationManager $im): void
{
foreach ($repo->getPackages() as $package) {
if (!$im->isPackageInstalled($repo, $package)) {
@ -620,10 +590,7 @@ class Factory
}
}
/**
* @return Package\Loader\RootPackageLoader
*/
protected function loadRootPackage(RepositoryManager $rm, Config $config, VersionParser $parser, VersionGuesser $guesser, IOInterface $io)
protected function loadRootPackage(RepositoryManager $rm, Config $config, VersionParser $parser, VersionGuesser $guesser, IOInterface $io): Package\Loader\RootPackageLoader
{
return new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser, $io);
}
@ -636,11 +603,14 @@ class Factory
* @param bool $disableScripts Whether scripts should not be run
* @return Composer
*/
public static function create(IOInterface $io, $config = null, $disablePlugins = false, $disableScripts = false)
public static function create(IOInterface $io, $config = null, bool $disablePlugins = false, bool $disableScripts = false): Composer
{
$factory = new static();
return $factory->createComposer($io, $config, $disablePlugins, null, true, $disableScripts);
$composer = $factory->createComposer($io, $config, $disablePlugins, null, true, $disableScripts);
assert($composer instanceof Composer);
return $composer;
}
/**
@ -651,7 +621,7 @@ class Factory
* @param mixed[] $options Array of options passed directly to HttpDownloader constructor
* @return HttpDownloader
*/
public static function createHttpDownloader(IOInterface $io, Config $config, $options = array())
public static function createHttpDownloader(IOInterface $io, Config $config, $options = array()): HttpDownloader
{
static $warned = false;
$disableTls = false;
@ -693,9 +663,6 @@ class Factory
return $httpDownloader;
}
/**
* @return bool
*/
private static function useXdg(): bool
{
foreach (array_keys($_SERVER) as $key) {
@ -713,7 +680,6 @@ class Factory
/**
* @throws \RuntimeException
* @return string
*/
private static function getUserDir(): string
{

View File

@ -14,6 +14,7 @@ namespace Composer\Installer;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\PartialComposer;
use Composer\Pcre\Preg;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
@ -31,11 +32,11 @@ use Composer\Downloader\DownloadManager;
*/
class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
{
/** @var Composer */
/** @var PartialComposer */
protected $composer;
/** @var string */
protected $vendorDir;
/** @var DownloadManager */
/** @var DownloadManager|null */
protected $downloadManager;
/** @var IOInterface */
protected $io;
@ -50,15 +51,15 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
* Initializes library installer.
*
* @param IOInterface $io
* @param Composer $composer
* @param PartialComposer $composer
* @param string|null $type
* @param Filesystem $filesystem
* @param BinaryInstaller $binaryInstaller
*/
public function __construct(IOInterface $io, Composer $composer, $type = 'library', Filesystem $filesystem = null, BinaryInstaller $binaryInstaller = null)
public function __construct(IOInterface $io, PartialComposer $composer, $type = 'library', Filesystem $filesystem = null, BinaryInstaller $binaryInstaller = null)
{
$this->composer = $composer;
$this->downloadManager = $composer->getDownloadManager();
$this->downloadManager = $composer instanceof Composer ? $composer->getDownloadManager() : null;
$this->io = $io;
$this->type = $type;
@ -101,7 +102,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$this->initializeVendorDir();
$downloadPath = $this->getInstallPath($package);
return $this->downloadManager->download($package, $downloadPath, $prevPackage);
return $this->getDownloadManager()->download($package, $downloadPath, $prevPackage);
}
/**
@ -112,7 +113,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$this->initializeVendorDir();
$downloadPath = $this->getInstallPath($package);
return $this->downloadManager->prepare($type, $package, $downloadPath, $prevPackage);
return $this->getDownloadManager()->prepare($type, $package, $downloadPath, $prevPackage);
}
/**
@ -123,7 +124,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$this->initializeVendorDir();
$downloadPath = $this->getInstallPath($package);
return $this->downloadManager->cleanup($type, $package, $downloadPath, $prevPackage);
return $this->getDownloadManager()->cleanup($type, $package, $downloadPath, $prevPackage);
}
/**
@ -266,7 +267,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
{
$downloadPath = $this->getInstallPath($package);
return $this->downloadManager->install($package, $downloadPath);
return $this->getDownloadManager()->install($package, $downloadPath);
}
/**
@ -295,7 +296,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$this->filesystem->rename($initialDownloadPath, $targetDownloadPath);
}
return $this->downloadManager->update($initial, $target, $targetDownloadPath);
return $this->getDownloadManager()->update($initial, $target, $targetDownloadPath);
}
/**
@ -305,7 +306,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
{
$downloadPath = $this->getPackageBasePath($package);
return $this->downloadManager->remove($package, $downloadPath);
return $this->getDownloadManager()->remove($package, $downloadPath);
}
/**
@ -316,4 +317,11 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$this->filesystem->ensureDirectoryExists($this->vendorDir);
$this->vendorDir = realpath($this->vendorDir);
}
protected function getDownloadManager(): DownloadManager
{
assert($this->downloadManager instanceof DownloadManager, new \LogicException(self::class.' should be initialized with a fully loaded Composer instance to be able to install/... packages'));
return $this->downloadManager;
}
}

View File

@ -14,8 +14,10 @@ namespace Composer\Installer;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\PartialComposer;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
use Composer\Plugin\PluginManager;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
use React\Promise\PromiseInterface;
@ -28,13 +30,7 @@ use React\Promise\PromiseInterface;
*/
class PluginInstaller extends LibraryInstaller
{
/**
* Initializes Plugin installer.
*
* @param IOInterface $io
* @param Composer $composer
*/
public function __construct(IOInterface $io, Composer $composer, Filesystem $fs = null, BinaryInstaller $binaryInstaller = null)
public function __construct(IOInterface $io, PartialComposer $composer, Filesystem $fs = null, BinaryInstaller $binaryInstaller = null)
{
parent::__construct($io, $composer, 'composer-plugin', $fs, $binaryInstaller);
}
@ -73,7 +69,7 @@ class PluginInstaller extends LibraryInstaller
return $promise->then(function () use ($package, $repo) {
try {
Platform::workaroundFilesystemIssues();
$this->composer->getPluginManager()->registerPackage($package, true);
$this->getPluginManager()->registerPackage($package, true);
} catch (\Exception $e) {
$this->rollbackInstall($e, $repo, $package);
}
@ -93,8 +89,8 @@ class PluginInstaller extends LibraryInstaller
return $promise->then(function () use ($initial, $target, $repo) {
try {
Platform::workaroundFilesystemIssues();
$this->composer->getPluginManager()->deactivatePackage($initial);
$this->composer->getPluginManager()->registerPackage($target, true);
$this->getPluginManager()->deactivatePackage($initial);
$this->getPluginManager()->registerPackage($target, true);
} catch (\Exception $e) {
$this->rollbackInstall($e, $repo, $target);
}
@ -103,7 +99,7 @@ class PluginInstaller extends LibraryInstaller
public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$this->composer->getPluginManager()->uninstallPackage($package);
$this->getPluginManager()->uninstallPackage($package);
return parent::uninstall($repo, $package);
}
@ -114,4 +110,12 @@ class PluginInstaller extends LibraryInstaller
parent::uninstall($repo, $package);
throw $e;
}
protected function getPluginManager(): PluginManager
{
assert($this->composer instanceof Composer, new \LogicException(self::class.' should be initialized with a fully loaded Composer instance.'));
$pluginManager = $this->composer->getPluginManager();
return $pluginManager;
}
}

View File

@ -1,8 +1,151 @@
<?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\Package\RootPackageInterface;
use Composer\Util\Loop;
use Composer\Repository\RepositoryManager;
use Composer\Installer\InstallationManager;
use Composer\EventDispatcher\EventDispatcher;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class PartialComposer
{
/**
* @var RootPackageInterface
*/
private $package;
/**
* @var Loop
*/
private $loop;
/**
* @var Repository\RepositoryManager
*/
private $repositoryManager;
/**
* @var Installer\InstallationManager
*/
private $installationManager;
/**
* @var Config
*/
private $config;
/**
* @var EventDispatcher
*/
private $eventDispatcher;
/**
* @return void
*/
public function setPackage(RootPackageInterface $package): void
{
$this->package = $package;
}
/**
* @return RootPackageInterface
*/
public function getPackage(): RootPackageInterface
{
return $this->package;
}
/**
* @return void
*/
public function setConfig(Config $config): void
{
$this->config = $config;
}
/**
* @return Config
*/
public function getConfig(): Config
{
return $this->config;
}
/**
* @return void
*/
public function setLoop(Loop $loop): void
{
$this->loop = $loop;
}
/**
* @return Loop
*/
public function getLoop(): Loop
{
return $this->loop;
}
/**
* @return void
*/
public function setRepositoryManager(RepositoryManager $manager): void
{
$this->repositoryManager = $manager;
}
/**
* @return RepositoryManager
*/
public function getRepositoryManager(): RepositoryManager
{
return $this->repositoryManager;
}
/**
* @return void
*/
public function setInstallationManager(InstallationManager $manager): void
{
$this->installationManager = $manager;
}
/**
* @return InstallationManager
*/
public function getInstallationManager(): InstallationManager
{
return $this->installationManager;
}
/**
* @return void
*/
public function setEventDispatcher(EventDispatcher $eventDispatcher): void
{
$this->eventDispatcher = $eventDispatcher;
}
/**
* @return EventDispatcher
*/
public function getEventDispatcher(): EventDispatcher
{
return $this->eventDispatcher;
}
}

View File

@ -13,6 +13,7 @@
namespace Composer\Plugin;
use Composer\Composer;
use Composer\Autoload\AutoloadGenerator;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Installer\InstallerInterface;
use Composer\IO\IOInterface;
@ -20,6 +21,7 @@ use Composer\Package\BasePackage;
use Composer\Package\CompletePackage;
use Composer\Package\Package;
use Composer\Package\Version\VersionParser;
use Composer\PartialComposer;
use Composer\Pcre\Preg;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\InstalledRepository;
@ -42,7 +44,7 @@ class PluginManager
protected $composer;
/** @var IOInterface */
protected $io;
/** @var ?Composer */
/** @var PartialComposer|null */
protected $globalComposer;
/** @var VersionParser */
protected $versionParser;
@ -67,15 +69,7 @@ class PluginManager
/** @var int */
private static $classCounter = 0;
/**
* Initializes plugin manager
*
* @param IOInterface $io
* @param Composer $composer
* @param Composer $globalComposer
* @param bool $disablePlugins
*/
public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null, $disablePlugins = false)
public function __construct(IOInterface $io, Composer $composer, PartialComposer $globalComposer = null, bool $disablePlugins = false)
{
$this->io = $io;
$this->composer = $composer;
@ -118,10 +112,9 @@ class PluginManager
}
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
$this->deactivateRepository($repo, false);
if ($globalRepo) {
$this->deactivateRepository($globalRepo, true);
if ($this->globalComposer !== null) {
$this->deactivateRepository($this->globalComposer->getRepositoryManager()->getLocalRepository(), true);
}
}
@ -137,10 +130,8 @@ class PluginManager
/**
* Gets global composer or null when main composer is not fully loaded
*
* @return Composer|null
*/
public function getGlobalComposer(): ?Composer
public function getGlobalComposer(): ?PartialComposer
{
return $this->globalComposer;
}
@ -558,6 +549,7 @@ class PluginManager
return $this->composer->getInstallationManager()->getInstallPath($package);
}
assert(null !== $this->globalComposer);
return $this->globalComposer->getInstallationManager()->getInstallPath($package);
}

View File

@ -19,10 +19,10 @@ class JsonValidationExceptionTest extends TestCase
{
/**
* @dataProvider errorProvider
* @param string|null $message
* @param string[]|null $errors
* @param string[] $errors
* @param string[] $expectedErrors
*/
public function testGetErrors($message, $errors, $expectedMessage, $expectedErrors): void
public function testGetErrors(?string $message, array $errors, string $expectedMessage, array $expectedErrors): void
{
$object = new JsonValidationException($message, $errors);
$this->assertSame($expectedMessage, $object->getMessage());

View File

@ -17,6 +17,7 @@ use Composer\Package\Loader\RootPackageLoader;
use Composer\Composer;
use Composer\Config;
use Composer\Factory;
use Composer\PartialComposer;
use Composer\Repository\RepositoryManager;
use Composer\Package\Version\VersionGuesser;
use Composer\Package\Version\VersionParser;
@ -32,7 +33,7 @@ use Composer\Util\ProcessExecutor;
class FactoryMock extends Factory
{
public static function createConfig(IOInterface $io = null, $cwd = null): Config
public static function createConfig(IOInterface $io = null, ?string $cwd = null): Config
{
$config = new Config(true, $cwd);
@ -59,7 +60,7 @@ class FactoryMock extends Factory
return new InstallationManagerMock();
}
protected function createDefaultInstallers(InstallationManager $im, Composer $composer, IOInterface $io, ProcessExecutor $process = null): void
protected function createDefaultInstallers(InstallationManager $im, PartialComposer $composer, IOInterface $io, ProcessExecutor $process = null): void
{
}