setName('bin') ->setDescription('Run a command inside a bin namespace') ->setDefinition(array( new InputArgument('namespace', InputArgument::REQUIRED), new InputArgument('args', InputArgument::REQUIRED | InputArgument::IS_ARRAY), )) ->ignoreValidationErrors() ; } /** * {@inheritDoc} */ public function execute(InputInterface $input, OutputInterface $output) { $config = new Config($this->getComposer()); $this->resetComposers($application = $this->getApplication()); /** @var ComposerApplication $application */ if ($config->binLinksAreEnabled()) { putenv('COMPOSER_BIN_DIR='.$this->createConfig()->get('bin-dir')); } $vendorRoot = $config->getTargetDirectory(); $namespace = $input->getArgument('namespace'); $input = new StringInput(preg_replace( sprintf('/bin\s+(--ansi\s)?%s(\s.+)/', preg_quote($namespace, '/')), '$1$2', (string) $input, 1 )); return ('all' !== $namespace) ? $this->executeInNamespace($application, $vendorRoot.'/'.$namespace, $input, $output) : $this->executeAllNamespaces($application, $vendorRoot, $input, $output) ; } /** * @param ComposerApplication $application * @param string $binVendorRoot * @param InputInterface $input * @param OutputInterface $output * * @return int Exit code */ private function executeAllNamespaces(ComposerApplication $application, $binVendorRoot, InputInterface $input, OutputInterface $output) { $binRoots = glob($binVendorRoot.'/*', GLOB_ONLYDIR); if (empty($binRoots)) { $this->getIO()->writeError('Couldn\'t find any bin namespace.'); return 0; // Is a valid scenario: the user may not have setup any bin namespace yet } $originalWorkingDir = getcwd(); $exitCode = 0; foreach ($binRoots as $binRoot) { $exitCode += $this->executeInNamespace($application, $binRoot, $input, $output); chdir($originalWorkingDir); $this->resetComposers($application); } return min($exitCode, 255); } /** * @param ComposerApplication $application * @param string $namespace * @param InputInterface $input * @param OutputInterface $output * * @return int Exit code */ private function executeInNamespace(ComposerApplication $application, $namespace, InputInterface $input, OutputInterface $output) { if (!file_exists($namespace)) { mkdir($namespace, 0777, true); } $this->chdir($namespace); $input = new StringInput((string) $input . ' --working-dir=.'); return $application->doRun($input, $output); } /** * {@inheritDoc} */ public function isProxyCommand() { return true; } /** * Resets all Composer references in the application. * * @param ComposerApplication $application */ private function resetComposers(ComposerApplication $application) { $application->resetComposer(); foreach ($this->getApplication()->all() as $command) { if ($command instanceof BaseCommand) { $command->resetComposer(); } } } private function chdir($dir) { chdir($dir); $this->getIO()->writeError('Changed current directory to ' . $dir . ''); } private function createConfig() { $config = Factory::createConfig(); $file = new JsonFile(Factory::getComposerFile()); if (!$file->exists()) { return $config; } $file->validateSchema(JsonFile::LAX_SCHEMA); $config->merge($file->read()); return $config; } }