function RequireCommand::execute
Throws
\Seld\JsonLint\ParsingException
Overrides Command::execute
File
-
vendor/
composer/ composer/ src/ Composer/ Command/ RequireCommand.php, line 133
Class
- RequireCommand
- @author Jérémy Romey <jeremy@free-agent.fr> @author Jordi Boggiano <j.boggiano@seld.be>
Namespace
Composer\CommandCode
protected function execute(InputInterface $input, OutputInterface $output) : int {
$this->file = Factory::getComposerFile();
$io = $this->getIO();
if ($input->getOption('no-suggest')) {
$io->writeError('<warning>You are using the deprecated option "--no-suggest". It has no effect and will break in Composer 3.</warning>');
}
$this->newlyCreated = !file_exists($this->file);
if ($this->newlyCreated && !file_put_contents($this->file, "{\n}\n")) {
$io->writeError('<error>' . $this->file . ' could not be created.</error>');
return 1;
}
if (!Filesystem::isReadable($this->file)) {
$io->writeError('<error>' . $this->file . ' is not readable.</error>');
return 1;
}
if (filesize($this->file) === 0) {
file_put_contents($this->file, "{\n}\n");
}
$this->json = new JsonFile($this->file);
$this->lock = Factory::getLockFile($this->file);
$this->composerBackup = file_get_contents($this->json
->getPath());
$this->lockBackup = file_exists($this->lock) ? file_get_contents($this->lock) : null;
$signalHandler = SignalHandler::create([
SignalHandler::SIGINT,
SignalHandler::SIGTERM,
SignalHandler::SIGHUP,
], function (string $signal, SignalHandler $handler) {
$this->getIO()
->writeError('Received ' . $signal . ', aborting', true, IOInterface::DEBUG);
$this->revertComposerFile();
$handler->exitWithLastSignal();
});
// check for writability by writing to the file as is_writable can not be trusted on network-mounts
// see https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
if (!is_writable($this->file) && false === Silencer::call('file_put_contents', $this->file, $this->composerBackup)) {
$io->writeError('<error>' . $this->file . ' is not writable.</error>');
return 1;
}
if ($input->getOption('fixed') === true) {
$config = $this->json
->read();
$packageType = empty($config['type']) ? 'library' : $config['type'];
/**
* @see https://github.com/composer/composer/pull/8313#issuecomment-532637955
*/
if ($packageType !== 'project' && !$input->getOption('dev')) {
$io->writeError('<error>The "--fixed" option is only allowed for packages with a "project" type or for dev dependencies to prevent possible misuses.</error>');
if (!isset($config['type'])) {
$io->writeError('<error>If your package is not a library, you can explicitly specify the "type" by using "composer config type project".</error>');
}
return 1;
}
}
$composer = $this->requireComposer();
$repos = $composer->getRepositoryManager()
->getRepositories();
$platformOverrides = $composer->getConfig()
->get('platform');
// initialize $this->repos as it is used by the PackageDiscoveryTrait
$this->repos = new CompositeRepository(array_merge([
$platformRepo = new PlatformRepository([], $platformOverrides),
], $repos));
if ($composer->getPackage()
->getPreferStable()) {
$preferredStability = 'stable';
}
else {
$preferredStability = $composer->getPackage()
->getMinimumStability();
}
try {
$requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'), $platformRepo, $preferredStability, $input->getOption('no-update'), $input->getOption('fixed'));
} catch (\Exception $e) {
if ($this->newlyCreated) {
$this->revertComposerFile();
throw new \RuntimeException('No composer.json present in the current directory (' . $this->file . '), this may be the cause of the following exception.', 0, $e);
}
throw $e;
}
$requirements = $this->formatRequirements($requirements);
if (!$input->getOption('dev') && $io->isInteractive()) {
$devPackages = [];
$devTags = [
'dev',
'testing',
'static analysis',
];
$currentRequiresByKey = $this->getPackagesByRequireKey();
foreach ($requirements as $name => $version) {
// skip packages which are already in the composer.json as those have already been decided
if (isset($currentRequiresByKey[$name])) {
continue;
}
$pkg = PackageSorter::getMostCurrentVersion($this->getRepos()
->findPackages($name));
if ($pkg instanceof CompletePackageInterface) {
$pkgDevTags = array_intersect($devTags, array_map('strtolower', $pkg->getKeywords()));
if (count($pkgDevTags) > 0) {
$devPackages[] = $pkgDevTags;
}
}
}
if (count($devPackages) === count($requirements)) {
$plural = count($requirements) > 1 ? 's' : '';
$plural2 = count($requirements) > 1 ? 'are' : 'is';
$plural3 = count($requirements) > 1 ? 'they are' : 'it is';
$pkgDevTags = array_unique(array_merge(...$devPackages));
$io->warning('The package' . $plural . ' you required ' . $plural2 . ' recommended to be placed in require-dev (because ' . $plural3 . ' tagged as "' . implode('", "', $pkgDevTags) . '") but you did not use --dev.');
if ($io->askConfirmation('<info>Do you want to re-run the command with --dev?</> [<comment>yes</>]? ')) {
$input->setOption('dev', true);
}
}
unset($devPackages, $pkgDevTags);
}
$requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
$removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
// check which requirements need the version guessed
$requirementsToGuess = [];
foreach ($requirements as $package => $constraint) {
if ($constraint === 'guess') {
$requirements[$package] = '*';
$requirementsToGuess[] = $package;
}
}
// validate requirements format
$versionParser = new VersionParser();
foreach ($requirements as $package => $constraint) {
if (strtolower($package) === $composer->getPackage()
->getName()) {
$io->writeError(sprintf('<error>Root package \'%s\' cannot require itself in its composer.json</error>', $package));
return 1;
}
if ($constraint === 'self.version') {
continue;
}
$versionParser->parseConstraints($constraint);
}
$inconsistentRequireKeys = $this->getInconsistentRequireKeys($requirements, $requireKey);
if (count($inconsistentRequireKeys) > 0) {
foreach ($inconsistentRequireKeys as $package) {
$io->warning(sprintf('%s is currently present in the %s key and you ran the command %s the --dev flag, which will move it to the %s key.', $package, $removeKey, $input->getOption('dev') ? 'with' : 'without', $requireKey));
}
if ($io->isInteractive()) {
if (!$io->askConfirmation(sprintf('<info>Do you want to move %s?</info> [<comment>no</comment>]? ', count($inconsistentRequireKeys) > 1 ? 'these requirements' : 'this requirement'), false)) {
if (!$io->askConfirmation(sprintf('<info>Do you want to re-run the command %s --dev?</info> [<comment>yes</comment>]? ', $input->getOption('dev') ? 'without' : 'with'), true)) {
return 0;
}
$input->setOption('dev', true);
[
$requireKey,
$removeKey,
] = [
$removeKey,
$requireKey,
];
}
}
}
$sortPackages = $input->getOption('sort-packages') || $composer->getConfig()
->get('sort-packages');
$this->firstRequire = $this->newlyCreated;
if (!$this->firstRequire) {
$composerDefinition = $this->json
->read();
if (count($composerDefinition['require'] ?? []) === 0 && count($composerDefinition['require-dev'] ?? []) === 0) {
$this->firstRequire = true;
}
}
if (!$input->getOption('dry-run')) {
$this->updateFile($this->json, $requirements, $requireKey, $removeKey, $sortPackages);
}
$io->writeError('<info>' . $this->file . ' has been ' . ($this->newlyCreated ? 'created' : 'updated') . '</info>');
if ($input->getOption('no-update')) {
return 0;
}
$composer->getPluginManager()
->deactivateInstalledPlugins();
try {
$result = $this->doUpdate($input, $output, $io, $requirements, $requireKey, $removeKey);
if ($result === 0 && count($requirementsToGuess) > 0) {
$result = $this->updateRequirementsAfterResolution($requirementsToGuess, $requireKey, $removeKey, $sortPackages, $input->getOption('dry-run'), $input->getOption('fixed'));
}
return $result;
} catch (\Exception $e) {
if (!$this->dependencyResolutionCompleted) {
$this->revertComposerFile();
}
throw $e;
} finally {
if ($input->getOption('dry-run') && $this->newlyCreated) {
@unlink($this->json
->getPath());
}
$signalHandler->unregister();
}
}