* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Console; use Symfony\Component\Console\Application as BaseApplication; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Formatter\OutputFormatter; use Composer\Command; use Composer\Command\Helper\DialogHelper; use Composer\Composer; use Composer\Factory; use Composer\IO\IOInterface; use Composer\IO\ConsoleIO; use Composer\Json\JsonValidationException; use Composer\Json\JsonFile; use Composer\Util\ErrorHandler; /** * The console application that handles the commands * * @author Ryan Weaver * @author Jordi Boggiano * @author François Pluchino */ class Application extends BaseApplication { /** * @var Composer */ protected $composer; /** * @var IOInterface */ protected $io; private static $logo = ' ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ '; public function __construct() { if (function_exists('ini_set') && extension_loaded('xdebug')) { ini_set('xdebug.show_exception_trace', false); ini_set('xdebug.scream', false); } if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) { date_default_timezone_set(@date_default_timezone_get()); } ErrorHandler::register(); parent::__construct('Composer', Composer::VERSION); } /** * {@inheritDoc} */ public function run(InputInterface $input = null, OutputInterface $output = null) { if (null === $output) { $styles = Factory::createAdditionalStyles(); $formatter = new OutputFormatter(null, $styles); $output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, null, $formatter); } return parent::run($input, $output); } /** * {@inheritDoc} */ public function doRun(InputInterface $input, OutputInterface $output) { $this->io = new ConsoleIO($input, $output, $this->getHelperSet()); if (version_compare(PHP_VERSION, '5.3.2', '<')) { $output->writeln('Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.'); } if (defined('COMPOSER_DEV_WARNING_TIME') && $this->getCommandName($input) !== 'self-update' && $this->getCommandName($input) !== 'selfupdate') { if (time() > COMPOSER_DEV_WARNING_TIME) { $output->writeln(sprintf('Warning: This development build of composer is over 30 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF'])); } } if (getenv('COMPOSER_NO_INTERACTION')) { $input->setInteractive(false); } // switch working dir if ($newWorkDir = $this->getNewWorkingDir($input)) { $oldWorkingDir = getcwd(); chdir($newWorkDir); if ($output->getVerbosity() >= 4) { $output->writeln('Changed CWD to ' . getcwd()); } } // add non-standard scripts as own commands $file = Factory::getComposerFile(); if (is_file($file) && is_readable($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)) { $output->writeln('A script named '.$script.' would override a native Composer function and has been skipped'); } else { $this->add(new Command\ScriptAliasCommand($script)); } } } } } if ($input->hasParameterOption('--profile')) { $startTime = microtime(true); $this->io->enableDebugging($startTime); } $result = parent::doRun($input, $output); if (isset($oldWorkingDir)) { chdir($oldWorkingDir); } if (isset($startTime)) { $output->writeln('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s'); } return $result; } /** * @param InputInterface $input * @return string * @throws \RuntimeException */ private function getNewWorkingDir(InputInterface $input) { $workingDir = $input->getParameterOption(array('--working-dir', '-d')); if (false !== $workingDir && !is_dir($workingDir)) { throw new \RuntimeException('Invalid working directory specified.'); } return $workingDir; } /** * {@inheritDoc} */ public function renderException($exception, $output) { try { $composer = $this->getComposer(false); if ($composer) { $config = $composer->getConfig(); $minSpaceFree = 1024*1024; if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree) || (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree) ) { $output->writeln('The disk hosting '.$dir.' is full, this may be the cause of the following exception'); } } } catch (\Exception $e) {} return parent::renderException($exception, $output); } /** * @param bool $required * @param bool $disablePlugins * @throws JsonValidationException * @return \Composer\Composer */ public function getComposer($required = true, $disablePlugins = false) { if (null === $this->composer) { try { $this->composer = Factory::create($this->io, null, $disablePlugins); } catch (\InvalidArgumentException $e) { if ($required) { $this->io->write($e->getMessage()); exit(1); } } catch (JsonValidationException $e) { $errors = ' - ' . implode(PHP_EOL . ' - ', $e->getErrors()); $message = $e->getMessage() . ':' . PHP_EOL . $errors; throw new JsonValidationException($message); } } return $this->composer; } /** * @return IOInterface */ public function getIO() { return $this->io; } public function getHelp() { return self::$logo . parent::getHelp(); } /** * Initializes all the composer commands */ protected function getDefaultCommands() { $commands = parent::getDefaultCommands(); $commands[] = new Command\AboutCommand(); $commands[] = new Command\ConfigCommand(); $commands[] = new Command\DependsCommand(); $commands[] = new Command\InitCommand(); $commands[] = new Command\InstallCommand(); $commands[] = new Command\CreateProjectCommand(); $commands[] = new Command\UpdateCommand(); $commands[] = new Command\SearchCommand(); $commands[] = new Command\ValidateCommand(); $commands[] = new Command\ShowCommand(); $commands[] = new Command\RequireCommand(); $commands[] = new Command\DumpAutoloadCommand(); $commands[] = new Command\StatusCommand(); $commands[] = new Command\ArchiveCommand(); $commands[] = new Command\DiagnoseCommand(); $commands[] = new Command\RunScriptCommand(); $commands[] = new Command\LicensesCommand(); $commands[] = new Command\GlobalCommand(); $commands[] = new Command\ClearCacheCommand(); $commands[] = new Command\RemoveCommand(); $commands[] = new Command\HomeCommand(); if ('phar:' === substr(__FILE__, 0, 5)) { $commands[] = new Command\SelfUpdateCommand(); } return $commands; } /** * {@inheritDoc} */ public function getLongVersion() { return parent::getLongVersion() . ' ' . Composer::RELEASE_DATE; } /** * {@inheritDoc} */ protected function getDefaultInputDefinition() { $definition = parent::getDefaultInputDefinition(); $definition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Display timing and memory usage information')); $definition->addOption(new InputOption('--working-dir', '-d', InputOption::VALUE_REQUIRED, 'If specified, use the given directory as working directory.')); return $definition; } /** * {@inheritDoc} */ protected function getDefaultHelperSet() { $helperSet = parent::getDefaultHelperSet(); $helperSet->set(new DialogHelper()); return $helperSet; } }