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

Breadcrumb

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

function Application::doRun

Same name in this branch
  1. 11.1.x vendor/symfony/console/Application.php \Symfony\Component\Console\Application::doRun()

Overrides Application::doRun

File

vendor/composer/composer/src/Composer/Console/Application.php, line 139

Class

Application
The console application that handles the commands

Namespace

Composer\Console

Code

public function doRun(InputInterface $input, OutputInterface $output) : int {
    $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins');
    $this->disableScriptsByDefault = $input->hasParameterOption('--no-scripts');
    static $stdin = null;
    if (null === $stdin) {
        $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r');
    }
    if (Platform::getEnv('COMPOSER_TESTS_ARE_RUNNING') !== '1' && (Platform::getEnv('COMPOSER_NO_INTERACTION') || $stdin === false || !Platform::isTty($stdin))) {
        $input->setInteractive(false);
    }
    $io = $this->io = new ConsoleIO($input, $output, new HelperSet([
        new QuestionHelper(),
    ]));
    // Register error handler again to pass it the IO instance
    ErrorHandler::register($io);
    if ($input->hasParameterOption('--no-cache')) {
        $io->writeError('Disabling cache usage', true, IOInterface::DEBUG);
        Platform::putEnv('COMPOSER_CACHE_DIR', Platform::isWindows() ? 'nul' : '/dev/null');
    }
    // switch working dir
    $newWorkDir = $this->getNewWorkingDir($input);
    if (null !== $newWorkDir) {
        $oldWorkingDir = Platform::getCwd(true);
        chdir($newWorkDir);
        $this->initialWorkingDirectory = $newWorkDir;
        $cwd = Platform::getCwd(true);
        $io->writeError('Changed CWD to ' . ($cwd !== '' ? $cwd : $newWorkDir), true, IOInterface::DEBUG);
    }
    // determine command name to be executed without including plugin commands
    $commandName = '';
    if ($name = $this->getCommandName($input)) {
        try {
            $commandName = $this->find($name)
                ->getName();
        } catch (CommandNotFoundException $e) {
            // we'll check command validity again later after plugins are loaded
            $commandName = false;
        } catch (\InvalidArgumentException $e) {
        }
    }
    // prompt user for dir change if no composer.json is present in current dir
    if (null === $newWorkDir && !in_array($commandName, [
        '',
        'list',
        'init',
        'about',
        'help',
        'diagnose',
        'self-update',
        'global',
        'create-project',
        'outdated',
    ], true) && !file_exists(Factory::getComposerFile()) && ($useParentDirIfNoJsonAvailable = $this->getUseParentDirConfigValue()) !== false && ($commandName !== 'config' || $input->hasParameterOption('--file', true) === false && $input->hasParameterOption('-f', true) === false) && $input->hasParameterOption('--help', true) === false && $input->hasParameterOption('-h', true) === false) {
        $dir = dirname(Platform::getCwd(true));
        $home = realpath((Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE')) ?: '/');
        // abort when we reach the home dir or top of the filesystem
        while (dirname($dir) !== $dir && $dir !== $home) {
            if (file_exists($dir . '/' . Factory::getComposerFile())) {
                if ($useParentDirIfNoJsonAvailable !== true && !$io->isInteractive()) {
                    $io->writeError('<info>No composer.json in current directory, to use the one at ' . $dir . ' run interactively or set config.use-parent-dir to true</info>');
                    break;
                }
                if ($useParentDirIfNoJsonAvailable === true || $io->askConfirmation('<info>No composer.json in current directory, do you want to use the one at ' . $dir . '?</info> [<comment>Y,n</comment>]? ')) {
                    if ($useParentDirIfNoJsonAvailable === true) {
                        $io->writeError('<info>No composer.json in current directory, changing working directory to ' . $dir . '</info>');
                    }
                    else {
                        $io->writeError('<info>Always want to use the parent dir? Use "composer config --global use-parent-dir true" to change the default.</info>');
                    }
                    $oldWorkingDir = Platform::getCwd(true);
                    chdir($dir);
                }
                break;
            }
            $dir = dirname($dir);
        }
        unset($dir, $home);
    }
    $needsSudoCheck = !Platform::isWindows() && function_exists('exec') && !Platform::getEnv('COMPOSER_ALLOW_SUPERUSER') && !Platform::isDocker();
    $isNonAllowedRoot = false;
    // Clobber sudo credentials if COMPOSER_ALLOW_SUPERUSER is not set before loading plugins
    if ($needsSudoCheck) {
        $isNonAllowedRoot = $this->isRunningAsRoot();
        if ($isNonAllowedRoot) {
            if ($uid = (int) Platform::getEnv('SUDO_UID')) {
                // Silently clobber any sudo credentials on the invoking user to avoid privilege escalations later on
                // ref. https://github.com/composer/composer/issues/5119
                Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1");
            }
        }
        // Silently clobber any remaining sudo leases on the current user as well to avoid privilege escalations
        Silencer::call('exec', 'sudo -K > /dev/null 2>&1');
    }
    // avoid loading plugins/initializing the Composer instance earlier than necessary if no plugin command is needed
    // if showing the version, we never need plugin commands
    $mayNeedPluginCommand = false === $input->hasParameterOption([
        '--version',
        '-V',
    ]) && (false === $commandName || in_array($commandName, [
        '',
        'list',
        'help',
    ], true) || $commandName === '_complete' && !$isNonAllowedRoot);
    if ($mayNeedPluginCommand && !$this->disablePluginsByDefault && !$this->hasPluginCommands) {
        // at this point plugins are needed, so if we are running as root and it is not allowed we need to prompt
        // if interactive, and abort otherwise
        if ($isNonAllowedRoot) {
            $io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>');
            if ($io->isInteractive() && $io->askConfirmation('<info>Continue as root/super user</info> [<comment>yes</comment>]? ')) {
                // avoid a second prompt later
                $isNonAllowedRoot = false;
            }
            else {
                $io->writeError('<warning>Aborting as no plugin should be loaded if running as super user is not explicitly allowed</warning>');
                return 1;
            }
        }
        try {
            foreach ($this->getPluginCommands() as $command) {
                if ($this->has($command->getName())) {
                    $io->writeError('<warning>Plugin command ' . $command->getName() . ' (' . get_class($command) . ') would override a Composer command and has been skipped</warning>');
                }
                else {
                    $this->add($command);
                }
            }
        } catch (NoSslException $e) {
            // suppress these as they are not relevant at this point
        } catch (ParsingException $e) {
            $details = $e->getDetails();
            $file = realpath(Factory::getComposerFile());
            $line = null;
            if ($details && isset($details['line'])) {
                $line = $details['line'];
            }
            $ghe = new GithubActionError($this->io);
            $ghe->emit($e->getMessage(), $file, $line);
            throw $e;
        }
        $this->hasPluginCommands = true;
    }
    if (!$this->disablePluginsByDefault && $isNonAllowedRoot && !$io->isInteractive()) {
        $io->writeError('<error>Composer plugins have been disabled for safety in this non-interactive session.</error>');
        $io->writeError('<error>Set COMPOSER_ALLOW_SUPERUSER=1 if you want to allow plugins to run as root/super user.</error>');
        $this->disablePluginsByDefault = true;
    }
    // determine command name to be executed incl plugin commands, and check if it's a proxy command
    $isProxyCommand = false;
    if ($name = $this->getCommandName($input)) {
        try {
            $command = $this->find($name);
            $commandName = $command->getName();
            $isProxyCommand = $command instanceof Command\BaseCommand && $command->isProxyCommand();
        } catch (\InvalidArgumentException $e) {
        }
    }
    if (!$isProxyCommand) {
        $io->writeError(sprintf('Running %s (%s) with %s on %s', Composer::getVersion(), Composer::RELEASE_DATE, defined('HHVM_VERSION') ? 'HHVM ' . HHVM_VERSION : 'PHP ' . PHP_VERSION, function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS'), true, IOInterface::DEBUG);
        if (\PHP_VERSION_ID < 70205) {
            $io->writeError('<warning>Composer supports PHP 7.2.5 and above, you will most likely encounter problems with your PHP ' . PHP_VERSION . '. Upgrading is strongly recommended but you can use Composer 2.2.x LTS as a fallback.</warning>');
        }
        if (XdebugHandler::isXdebugActive() && !Platform::getEnv('COMPOSER_DISABLE_XDEBUG_WARN')) {
            $io->writeError('<warning>Composer is operating slower than normal because you have Xdebug enabled. See https://getcomposer.org/xdebug</warning>');
        }
        if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) {
            $io->writeError(sprintf('<warning>Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
        }
        if ($isNonAllowedRoot) {
            if ($commandName !== 'self-update' && $commandName !== 'selfupdate' && $commandName !== '_complete') {
                $io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>');
                if ($io->isInteractive()) {
                    if (!$io->askConfirmation('<info>Continue as root/super user</info> [<comment>yes</comment>]? ')) {
                        return 1;
                    }
                }
            }
        }
        // Check system temp folder for usability as it can cause weird runtime issues otherwise
        Silencer::call(static function () use ($io) : void {
            $pid = function_exists('getmypid') ? getmypid() . '-' : '';
            $tempfile = sys_get_temp_dir() . '/temp-' . $pid . bin2hex(random_bytes(5));
            if (!(file_put_contents($tempfile, __FILE__) && file_get_contents($tempfile) === __FILE__ && unlink($tempfile) && !file_exists($tempfile))) {
                $io->writeError(sprintf('<error>PHP temp directory (%s) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini</error>', sys_get_temp_dir()));
            }
        });
        // add non-standard scripts as own commands
        $file = Factory::getComposerFile();
        if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
            if (isset($composer['scripts']) && is_array($composer['scripts'])) {
                foreach ($composer['scripts'] as $script => $dummy) {
                    if (!defined('Composer\\Script\\ScriptEvents::' . str_replace('-', '_', strtoupper($script)))) {
                        if ($this->has($script)) {
                            $io->writeError('<warning>A script named ' . $script . ' would override a Composer command and has been skipped</warning>');
                        }
                        else {
                            $description = null;
                            if (isset($composer['scripts-descriptions'][$script])) {
                                $description = $composer['scripts-descriptions'][$script];
                            }
                            $aliases = $composer['scripts-aliases'][$script] ?? [];
                            $this->add(new Command\ScriptAliasCommand($script, $description, $aliases));
                        }
                    }
                }
            }
        }
    }
    try {
        if ($input->hasParameterOption('--profile')) {
            $startTime = microtime(true);
            $this->io
                ->enableDebugging($startTime);
        }
        $result = parent::doRun($input, $output);
        if (true === $input->hasParameterOption([
            '--version',
            '-V',
        ], true)) {
            $io->writeError(sprintf('<info>PHP</info> version <comment>%s</comment> (%s)', \PHP_VERSION, \PHP_BINARY));
            $io->writeError('Run the "diagnose" command to get more detailed diagnostics output.');
        }
        // chdir back to $oldWorkingDir if set
        if (isset($oldWorkingDir) && '' !== $oldWorkingDir) {
            Silencer::call('chdir', $oldWorkingDir);
        }
        if (isset($startTime)) {
            $io->writeError('<info>Memory usage: ' . round(memory_get_usage() / 1024 / 1024, 2) . 'MiB (peak: ' . round(memory_get_peak_usage() / 1024 / 1024, 2) . 'MiB), time: ' . round(microtime(true) - $startTime, 2) . 's</info>');
        }
        return $result;
    } catch (ScriptExecutionException $e) {
        if ($this->getDisablePluginsByDefault() && $this->isRunningAsRoot() && !$this->io
            ->isInteractive()) {
            $io->writeError('<error>Plugins have been disabled automatically as you are running as root, this may be the cause of the script failure.</error>', true, IOInterface::QUIET);
            $io->writeError('<error>See also https://getcomposer.org/root</error>', true, IOInterface::QUIET);
        }
        return $e->getCode();
    } catch (\Throwable $e) {
        $ghe = new GithubActionError($this->io);
        $ghe->emit($e->getMessage());
        $this->hintCommonErrors($e, $output);
        // symfony/console <6.4 does not handle \Error subtypes so we have to renderThrowable ourselves
        // instead of rethrowing those for consumption by the parent class
        // can be removed when Composer supports PHP 8.1+
        if (!method_exists($this, 'setCatchErrors') && !$e instanceof \Exception) {
            if ($output instanceof ConsoleOutputInterface) {
                $this->renderThrowable($e, $output->getErrorOutput());
            }
            else {
                $this->renderThrowable($e, $output);
            }
            return max(1, $e->getCode());
        }
        // override TransportException's code for the purpose of parent::run() using it as process exit code
        // as http error codes are all beyond the 255 range of permitted exit codes
        if ($e instanceof TransportException) {
            $reflProp = new \ReflectionProperty($e, 'code');
            $reflProp->setAccessible(true);
            $reflProp->setValue($e, Installer::ERROR_TRANSPORT_EXCEPTION);
        }
        throw $e;
    } finally {
        restore_error_handler();
    }
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal