*/ class GlobalCommand extends BaseCommand { public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $application = $this->getApplication(); if ($input->mustSuggestArgumentValuesFor('command-name')) { $suggestions->suggestValues(array_values(array_filter(array_map(static function (Command $command) { return $command->isHidden() ? null : $command->getName(); }, $application->all())))); return; } if ($application->has($commandName = $input->getArgument('command-name'))) { $input = $this->prepareSubcommandInput($input, true); $input = CompletionInput::fromString($input->__toString(), 2); $command = $application->find($commandName); $command->mergeApplicationDefinition(); $input->bind($command->getDefinition()); $command->complete($input, $suggestions); } } protected function configure(): void { $this ->setName('global') ->setDescription('Allows running commands in the global composer dir ($COMPOSER_HOME)') ->setDefinition([ new InputArgument('command-name', InputArgument::REQUIRED, ''), new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''), ]) ->setHelp( "Use this command as a wrapper to run other Composer commands\nwithin the global context of COMPOSER_HOME.\n\nYou can use this to install CLI utilities globally, all you need\nis to add the COMPOSER_HOME/vendor/bin dir to your PATH env var.\n\nCOMPOSER_HOME is c:\Users\\AppData\Roaming\Composer on Windows\nand /home//.composer on unix systems.\n\nIf your system uses freedesktop.org standards, then it will first check\nXDG_CONFIG_HOME or default to /home//.config/composer\n\nNote: This path may vary depending on customizations to bin-dir in\ncomposer.json or the environmental variable COMPOSER_BIN_DIR.\n\nRead more at https://getcomposer.org/doc/03-cli.md#global" ) ; } /** * @throws \Symfony\Component\Console\Exception\ExceptionInterface */ public function run(InputInterface $input, OutputInterface $output): int { // TODO remove for Symfony 6+ as it is then in the interface if (!method_exists($input, '__toString')) { // @phpstan-ignore-line throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input)); } // extract real command name $tokens = Preg::split('{\s+}', $input->__toString()); $args = []; foreach ($tokens as $token) { if ($token && $token[0] !== '-') { $args[] = $token; if (count($args) >= 2) { break; } } } // show help for this command if no command was found if (count($args) < 2) { return parent::run($input, $output); } $input = $this->prepareSubcommandInput($input); return $this->getApplication()->run($input, $output); } private function prepareSubcommandInput(InputInterface $input, bool $quiet = false): StringInput { // TODO remove for Symfony 6+ as it is then in the interface if (!method_exists($input, '__toString')) { // @phpstan-ignore-line throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input)); } // The COMPOSER env var should not apply to the global execution scope if (Platform::getEnv('COMPOSER')) { Platform::clearEnv('COMPOSER'); } // change to global dir $config = Factory::createConfig(); $home = $config->get('home'); if (!is_dir($home)) { $fs = new Filesystem(); $fs->ensureDirectoryExists($home); if (!is_dir($home)) { throw new \RuntimeException('Could not create home directory'); } } try { chdir($home); } catch (\Exception $e) { throw new \RuntimeException('Could not switch to home directory "'.$home.'"', 0, $e); } if (!$quiet) { $this->getIO()->writeError('Changed current directory to '.$home.''); } // create new input without "global" command prefix $input = new StringInput(Preg::replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1)); $this->getApplication()->resetComposer(); return $input; } /** * @inheritDoc */ public function isProxyCommand(): bool { return true; } } __halt_compiler();----SIGNATURE:----F30Qn8HrqPOa6s44v27QHBERAXfj6vMJk9CJe5FAQN/p9iU7O/GiAVYNC74kR0fh6ZYMaAOTkyZ+A0AnwBn3r/03mx8DAVrngDBF/1WdR6yQ1X3sy/v6gwBNKEvnjhMvHKrvSBcSVJMUebf2CU1ktJKtYuYiRLBXfEFCPPJnjAJfb+9TlF1p+Xfr9bVj0Z/ESpvfX4rKDztn2qnRMkWVJs4EkwbC8KNicrkK5c9phVrA77/npHoINIvk57N9Rp0erAZtBGicTvXVsFRSVfWqwivgGXshfiOR2jThTloXKaTWYC4X6I3QbhCQ4eVCCYxV4CfOdbjNF2zcTKfDQJ7kTdcUaUzEmnMR/Qr5auMQ+VqHbZvRe3wJpvRzZVmUEzt9YSZ1z1Yrqr6ur80JeASWLkBqceNMy9hvZfY0honunPrbR3dTafGj9TdsTh69M4xaJIkHLFoWd8Ggk72S7gzK7scd6mecrDgMmBZ/B3cLgplD66MwkzWaizMp0/Gj+v3yFPwX9fJPlX0ucCnazZKUTzdSgGQrhjjraV6xziBE+terTpdVQfCy/NJMlC+5UXJHrqQyXqTBFZKxEY32KSkz2VuL3s3UlzxwfnehiADUt3lOv0hTzn6QjIttfG4e8npl3qlM6sMxx0T+61rA6PNrEUWAnBlnRKUmchZ9m6vwozs=----ATTACHMENT:----MTcxODM0NDMwMTQyMTIwNiAyMDA2MzUyNTg2NTIxNTUzIDE4MTU0NDU2MzQ2NzI4Nzc=