3 namespace Drush\Commands\generate\Generators\Drush;
5 use DrupalCodeGenerator\Command\BaseGenerator;
6 use DrupalCodeGenerator\Utils;
7 use Symfony\Component\Console\Input\InputInterface;
8 use Symfony\Component\Console\Output\OutputInterface;
9 use Symfony\Component\Console\Question\Question;
12 * Implements drush-command-file command.
14 class DrushCommandFile extends BaseGenerator
17 protected $name = 'drush-command-file';
18 protected $description = 'Generates a Drush command file.';
19 protected $alias = 'dcf';
20 protected $templatePath = __DIR__;
25 protected function interact(InputInterface $input, OutputInterface $output)
27 $questions = Utils::defaultQuestions();
28 $questions['source'] = new Question('Absolute path to legacy Drush command file (optional - for porting)');
29 $questions['source']->setValidator(function ($path) {
30 if ($path && !is_file($path)) {
31 throw new \UnexpectedValueException(sprintf('Could not open file "%s".', $path));
36 $vars = &$this->collectVars($input, $output, $questions);
37 $vars['class'] = Utils::camelize($vars['machine_name'] . 'Commands');
38 if ($vars['source']) {
39 require_once $vars['source'];
40 $filename = str_replace(['.drush.inc', '.drush8.inc'], '', basename($vars['source']));
41 $command_hook = $filename . '_drush_command';
42 if (!function_exists($command_hook)) {
43 throw new \InvalidArgumentException('Drush command hook "' . $command_hook . '" does not exist.');
45 $commands = call_user_func($filename . '_drush_command');
46 $vars['commands'] = $this->adjustCommands($commands);
50 ->path('src/Commands/{class}.php')
51 ->template('drush-command-file.twig');
53 $json = $this->getComposerJson($vars);
54 $content = json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
56 ->path('composer.json')
61 ->path('drush.services.yml')
62 ->template('drush.services.twig');
65 protected function getComposerJson(array $vars)
67 $composer_json_template_path = __DIR__ . '/dcf-composer.json';
68 // TODO: look up the path of the 'machine_name' module.
69 $composer_json_existing_path = DRUPAL_ROOT . '/modules/' . $vars['machine_name'] . '/composer.json';
70 $composer_json_path = file_exists($composer_json_existing_path) ? $composer_json_existing_path : $composer_json_template_path;
71 $composer_json_contents = file_get_contents($composer_json_path);
72 $composer_json_data = json_decode($composer_json_contents, true);
74 // If there is no name, fill something in
75 if (empty($composer_json_data['name'])) {
76 $composer_json_data['name'] = 'org/' . $vars['machine_name'];
79 // Add an entry for the drush services file.
80 $composer_json_data['extra']['drush']['services'] = [
81 'drush.services.yml' => '^9',
84 return $composer_json_data;
87 protected function getOwningModulePath(array $vars)
89 $module_name = $vars['machine_name'];
91 $modules = \Drupal::moduleHandler()->getModuleList();
92 $themes = \Drupal::service('theme_handler')->listInfo();
93 $projects = array_merge($modules, $themes);
95 if (!isset($projects[$module_name])) {
96 throw new \Exception(dt('{module} does not exist. Run `drush generate module-standard` to create it.', ['module' => $module_name]));
98 return $projects[$module_name]->getPath();
101 protected function adjustCommands(array $commands)
103 foreach ($commands as $name => &$command) {
104 // Drush9 uses colons in command names. Replace first dash with colon.
105 $pos = strpos($name, '-');
106 if ($pos !== false) {
107 $command['name'] = substr_replace($name, ':', $pos, 1);
110 if ($command['name'] !== $name) {
111 $command['aliases'][] = $name;
114 $command['method'] = $name;
115 if (($pos = strpos($name, '-')) !== false) {
116 $command['method'] = substr($name, $pos + 1);
118 $command['method'] = Utils::camelize(str_replace('-', '_', $command['method']), false);
119 if ($command['arguments']) {
120 foreach ($command['arguments'] as $aName => $description) {
121 // Prepend name with a '$' and replace dashes.
122 $command['arguments']['$' . Utils::human2machine($aName)] = $description;
123 unset($command['arguments'][$aName]);
125 $command['argumentsConcat'] = implode(', ', array_keys($command['arguments']));
127 if ($command['options']) {
128 foreach ($command['options'] as $oName => &$option) {
129 // We only care about option description so make value a simple string.
130 if (is_array($option)) {
131 $option = $option['description'];
133 $oNames[] = "'$oName' => null";
135 $command['optionsConcat'] = 'array $options = [' . implode(', ', $oNames) . ']';
136 if (!empty($command['arguments'])) {
137 $command['optionsConcat'] = ', ' . $command['optionsConcat'];
141 if ($deps = $command['drupal dependencies']) {
142 $command['depsConcat'] = implode(',', $deps);