Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. RequireCommand.php

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\Command

Code

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();
    }
}
RSS feed
Powered by Drupal