4 * Contains \Drush\Psysh\DrushCommand.
6 * DrushCommand is a PsySH proxy command which accepts a Drush command config
7 * array and tries to build an appropriate PsySH command for it.
10 namespace Drush\Psysh;
12 use Psy\Command\Command as BaseCommand;
13 use Symfony\Component\Console\Formatter\OutputFormatter;
14 use Symfony\Component\Console\Input\InputArgument;
15 use Symfony\Component\Console\Input\InputOption;
16 use Symfony\Component\Console\Input\InputInterface;
17 use Symfony\Component\Console\Output\OutputInterface;
22 class DrushCommand extends BaseCommand {
32 private $category = '';
35 * DrushCommand constructor.
37 * This accepts the Drush command configuration array and does a pretty
38 * decent job of building a PsySH command proxy for it. Wheee!
40 * @param array $config
41 * Drush command configuration array.
43 public function __construct(array $config) {
44 $this->config = $config;
45 parent::__construct();
49 * Get Category of this command.
51 public function getCategory() {
52 return $this->category;
56 * Sets the category title.
58 * @param string $category_title
60 public function setCategory($category_title) {
61 $this->category = $category_title;
67 protected function configure() {
69 ->setName($this->config['command'])
70 ->setAliases($this->buildAliasesFromConfig())
71 ->setDefinition($this->buildDefinitionFromConfig())
72 ->setDescription($this->config['description'])
73 ->setHelp($this->buildHelpFromConfig());
79 protected function execute(InputInterface $input, OutputInterface $output) {
80 $args = $input->getArguments();
81 $first = array_shift($args);
83 // If the first argument is an alias, assign the next argument as the
85 if (strpos($first, '@') === 0) {
87 $command = array_shift($args);
89 // Otherwise, default the alias to '@self' and use the first argument as the
96 $options = $input->getOptions();
97 // Force the 'backend' option to TRUE.
98 $options['backend'] = TRUE;
100 $return = drush_invoke_process($alias, $command, array_values($args), $options, ['interactive' => TRUE]);
102 if ($return['error_status'] > 0) {
103 foreach ($return['error_log'] as $error_type => $errors) {
104 $output->write($errors);
106 // Add a newline after so the shell returns on a new line.
107 $output->writeln('');
110 $output->page(drush_backend_get_result());
115 * Extract Drush command aliases from config array.
118 * The command aliases.
120 protected function buildAliasesFromConfig() {
121 return !empty($this->config['aliases']) ? $this->config['aliases'] : [];
125 * Build a command definition from Drush command configuration array.
127 * Currently, adds all non-hidden arguments and options, and makes a decent
128 * effort to guess whether an option accepts a value or not. It isn't always
132 * the command definition.
134 protected function buildDefinitionFromConfig() {
137 if (isset($this->config['arguments']) && !empty($this->config['arguments'])) {
138 $required_args = $this->config['required-arguments'];
140 if ($required_args === FALSE) {
143 elseif ($required_args === TRUE) {
144 $required_args = count($this->config['arguments']);
147 foreach ($this->config['arguments'] as $name => $argument) {
148 if (!is_array($argument)) {
149 $argument = ['description' => $argument];
152 if (!empty($argument['hidden'])) {
156 $input_type = ($required_args-- > 0) ? InputArgument::REQUIRED : InputArgument::OPTIONAL;
158 $definitions[] = new InputArgument($name, $input_type, $argument['description'], NULL);
162 // First create all global options.
163 $options = $this->config['options'] + drush_get_global_options();
165 // Add command specific options.
166 $definitions = array_merge($definitions, $this->createInputOptionsFromConfig($options));
172 * Creates input definitions from command options.
174 * @param array $options_config
176 * @return \Symfony\Component\Console\Input\InputInterface[]
178 protected function createInputOptionsFromConfig(array $options_config) {
181 foreach ($options_config as $name => $option) {
182 // Some commands will conflict.
183 if (in_array($name, ['help', 'command'])) {
187 if (!is_array($option)) {
188 $option = ['description' => $option];
191 if (!empty($option['hidden'])) {
195 // @todo: Figure out if there's a way to detect InputOption::VALUE_NONE
196 // (i.e. flags) via the config array.
197 if (isset($option['value']) && $option['value'] === 'required') {
198 $input_type = InputOption::VALUE_REQUIRED;
201 $input_type = InputOption::VALUE_OPTIONAL;
204 $definitions[] = new InputOption($name, !empty($option['short-form']) ? $option['short-form'] : '', $input_type, $option['description']);
211 * Build a command help from the Drush configuration array.
213 * Currently it's a word-wrapped description, plus any examples provided.
218 protected function buildHelpFromConfig() {
219 $help = wordwrap($this->config['description']);
222 foreach ($this->config['examples'] as $ex => $def) {
223 // Skip empty examples and things with obvious pipes...
224 if (($ex === '') || (strpos($ex, '|') !== FALSE)) {
228 $ex = preg_replace('/^drush\s+/', '', $ex);
229 $examples[$ex] = $def;
232 if (!empty($examples)) {
235 foreach ($examples as $ex => $def) {
236 $help .= sprintf("\n<return>// %s</return>\n", wordwrap(OutputFormatter::escape($def), 75, "</return>\n<return>// "));
237 $help .= sprintf("<return>>>> %s</return>\n", OutputFormatter::escape($ex));