annotationcommand_adapter.inc

annotationcommand_adapter.inc

Functions

Namesort descending Description
annotatedcomand_adapter_backend_result Callback function called by HookManager::EXTRACT_OUTPUT to set the backend result.
annotatedcomand_adapter_get_formatter Fetch the formatter manager from the command processor
annotationcommand_adapter_add_hook_options Modify a $command record, adding option definitions defined by any command hook.
annotationcommand_adapter_alter_option_description_fields TODO: Document
annotationcommand_adapter_alter_option_description_format TODO: Document
annotationcommand_adapter_build_input TODO: This could probably just be a DrushInputAdapter now.
annotationcommand_adapter_cache_module_console_commands TODO: document
annotationcommand_adapter_cache_module_service_commands TODO: document
annotationcommand_adapter_call_hook_command Convert from an old-style Drush 'command' hook into annotated-command hooks.
annotationcommand_adapter_call_hook_post_command Convert from an old-style Drush post-command hook into annotated-command hooks.
annotationcommand_adapter_call_hook_pre_command Convert from an old-style Drush pre-command hook into annotated-command hooks.
annotationcommand_adapter_call_hook_pre_validate Convert from an old-style Drush pre-validate hook into annotated-command hooks.
annotationcommand_adapter_call_hook_process_and_alter After the primary Drush command hook is called, call all of the annotated-command process and alter hooks.
annotationcommand_adapter_call_hook_validate Convert from an old-style Drush validate hook into annotated-command hooks.
annotationcommand_adapter_call_initialize Convert from an old-style Drush initialize hook into annotated-command hooks.
annotationcommand_adapter_call_process_interface Given a list of hooks that conform to the interface ProcessResultInterface, call them and return the result.
annotationcommand_adapter_call_validate_interface Given a list of hooks that conform to the interface ValidatorInterface, call them and return the result.
annotationcommand_adapter_commands Return the cached commands built by annotationcommand_adapter_discover.
annotationcommand_adapter_command_names Build all of the name variants for a Drush $command record
annotationcommand_adapter_create_commandfile_instance Create and cache a commandfile instance.
annotationcommand_adapter_discover Search for annotation commands at the provided search path.
annotationcommand_adapter_get_commands Internal function called by annotationcommand_adapter_commands, which is called by drush_get_commands().
annotationcommand_adapter_get_commands_for_commandhandler Convert an annotated command command handler object into a Drush $command record.
annotationcommand_adapter_get_command_for_console_command Convert a Symfony Console command into a Drush $command record
annotationcommand_adapter_get_discovery Cache the command file discovery object. @todo There probably isn't any need to cache this object.
annotationcommand_adapter_get_options Collect all of the options defined in every relevant context, and merge them together to form the options array.
annotationcommand_adapter_get_processor Fetch the command processor from the factory.
annotationcommand_adapter_process_command This function is set as the $command['callback'] for commands that have been converted to annotated commands. When the DRUSH_SYMFONY environment variable is set, these will be called via Symfony's Application::run() method. Otherwise,…
annotationcommand_adapter_refine_searchpaths In some circumstances, Drush just does a deep search for any *.drush.inc file, so that it can find all commands, in enabled and disabled modules alike, for the purpose of displaying the help text for that command.
annotationcommand_adapter_run_console_command This function is set as the $command['callback'] for Symfony Console commands e.g. those provided by Drupal 8 modules. When the DRUSH_SYMFONY environment variable is set, these will be called via Symfony's Application::run()…

File

includes/annotationcommand_adapter.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * annotationcommand_adapter.inc
  5. */
  6. use Consolidation\AnnotatedCommand\CommandFileDiscovery;
  7. use Consolidation\AnnotatedCommand\AnnotatedCommandFactory;
  8. use Consolidation\AnnotatedCommand\CommandProcessor;
  9. use Consolidation\AnnotatedCommand\Hooks\HookManager;
  10. use Consolidation\OutputFormatters\FormatterManager;
  11. use Consolidation\OutputFormatters\Options\FormatterOptions;
  12. use Symfony\Component\Console\Input\ArrayInput;
  13. use Consolidation\AnnotatedCommand\AnnotationData;
  14. use Consolidation\AnnotatedCommand\CommandData;
  15. use Drush\Command\DrushInputAdapter;
  16. use Drush\Command\DrushOutputAdapter;
  17. use Symfony\Component\Console\Output\ConsoleOutput;
  18. /**
  19. * Cache the command file discovery object.
  20. * @todo There probably isn't any need to cache this object.
  21. *
  22. * @return CommandFileDiscovery
  23. */
  24. function annotationcommand_adapter_get_discovery() {
  25. static $discovery;
  26. if (!isset($discovery)) {
  27. $discovery = new CommandFileDiscovery();
  28. }
  29. return $discovery;
  30. }
  31. /**
  32. * Fetch the command processor from the factory.
  33. *
  34. * @return AnnotatedCommandFactory
  35. */
  36. function annotationcommand_adapter_get_processor() {
  37. $factory = \Drush::commandFactory();
  38. return $factory->commandProcessor();
  39. }
  40. /**
  41. * Fetch the formatter manager from the command processor
  42. *
  43. * @return FormatterManager
  44. */
  45. function annotatedcomand_adapter_get_formatter() {
  46. $commandProcessor = annotationcommand_adapter_get_processor();
  47. return $commandProcessor->formatterManager();
  48. }
  49. /**
  50. * Callback function called by HookManager::EXTRACT_OUTPUT to set
  51. * the backend result.
  52. */
  53. function annotatedcomand_adapter_backend_result($structured_data) {
  54. $return = drush_backend_get_result();
  55. if (empty($return)) {
  56. drush_backend_set_result($structured_data);
  57. }
  58. }
  59. /**
  60. * Return the cached commands built by annotationcommand_adapter_discover.
  61. * @see drush_get_commands()
  62. */
  63. function annotationcommand_adapter_commands() {
  64. $annotation_commandfiles = drush_get_context('DRUSH_ANNOTATED_COMMANDFILES');
  65. // Remove any entry in the commandfiles list from an ignored module.
  66. $ignored = implode('|', drush_get_option_list('ignored-modules'));
  67. $regex = "#/(modules|themes|profiles)(/|/.*/)($ignored)/#";
  68. foreach ($annotation_commandfiles as $key => $path) {
  69. if (preg_match($regex, $path)) {
  70. unset($annotation_commandfiles[$key]);
  71. }
  72. }
  73. $commands = annotationcommand_adapter_get_commands($annotation_commandfiles);
  74. $module_service_commands = drush_get_context('DRUSH_MODULE_SERVICE_COMMANDS');
  75. return array_merge($commands, $module_service_commands);
  76. }
  77. /**
  78. * Search for annotation commands at the provided search path.
  79. * @see _drush_find_commandfiles()
  80. */
  81. function annotationcommand_adapter_discover($searchpath, $phase = false, $phase_max = false) {
  82. if (empty($searchpath)) {
  83. return;
  84. }
  85. if (($phase >= DRUSH_BOOTSTRAP_DRUPAL_SITE) && (drush_drupal_major_version() >= 8)) {
  86. return;
  87. }
  88. $annotation_commandfiles = [];
  89. // Assemble a cid specific to the bootstrap phase and searchpaths.
  90. // Bump $cf_version when making a change to a dev version of Drush
  91. // that invalidates the commandfile cache.
  92. $cf_version = 1;
  93. $cid = drush_get_cid('annotationfiles-' . $phase, array(), array_merge($searchpath, array($cf_version)));
  94. $command_cache = drush_cache_get($cid);
  95. if (isset($command_cache->data)) {
  96. $annotation_commandfiles = $command_cache->data;
  97. }
  98. else {
  99. // Check to see if this is the Drush searchpath for instances where we are
  100. // NOT going to do a full bootstrap (e.g. when running a help command)
  101. if (($phase == DRUSH_BOOTSTRAP_DRUPAL_SITE) && ($phase_max < DRUSH_BOOTSTRAP_DRUPAL_FULL)) {
  102. $searchpath = annotationcommand_adapter_refine_searchpaths($searchpath);
  103. }
  104. $discovery = annotationcommand_adapter_get_discovery();
  105. $annotation_commandfiles = $discovery->discoverNamespaced($searchpath, '\Drupal');
  106. drush_cache_set($cid, $annotation_commandfiles);
  107. }
  108. drush_set_context(
  109. 'DRUSH_ANNOTATED_COMMANDFILES',
  110. array_merge(
  111. drush_get_context('DRUSH_ANNOTATED_COMMANDFILES'),
  112. $annotation_commandfiles
  113. )
  114. );
  115. }
  116. /**
  117. * This function is set as the $command['callback'] for Symfony Console commands
  118. * e.g. those provided by Drupal 8 modules. When the DRUSH_SYMFONY environment
  119. * variable is set, these will be called via Symfony's Application::run() method.
  120. * Otherwise, the legacy Drush command dispatcher will be used for all commands.
  121. *
  122. * @return bool false if command failed (expect drush_set_error was called in this case)
  123. */
  124. function annotationcommand_adapter_run_console_command() {
  125. $args = func_get_args();
  126. $command = drush_get_command();
  127. $console_command = $command['drush-console-command'];
  128. // TODO: Build an appropriate input object
  129. $input = annotationcommand_adapter_build_input($console_command, $args);
  130. $output = new ConsoleOutput();
  131. $result = $console_command->run($input, $output);
  132. return $result;
  133. }
  134. /**
  135. * TODO: This could probably just be a DrushInputAdapter now.
  136. */
  137. function annotationcommand_adapter_build_input($console_command, $userArgs) {
  138. $args = [];
  139. $defaultOptions = [];
  140. $definition = $console_command->getDefinition();
  141. $inputArguments = $definition->getArguments();
  142. foreach ($inputArguments as $key => $inputOption) {
  143. $value = array_shift($userArgs);
  144. if (!isset($value)) {
  145. $value = $inputOption->getDefault();
  146. }
  147. $args[$key] = $value;
  148. }
  149. $inputOptions = $definition->getOptions();
  150. foreach ($inputOptions as $option => $inputOption) {
  151. $defaultOptions[$option] = $inputOption->getDefault();
  152. }
  153. foreach ($defaultOptions as $option => $value) {
  154. $args["--$option"] = drush_get_option($option, $value);
  155. }
  156. // TODO: Need to add global options. Note that ArrayInput is validated.
  157. $input = new ArrayInput($args, $definition);
  158. return $input;
  159. }
  160. /**
  161. * Collect all of the options defined in every relevant context, and
  162. * merge them together to form the options array.
  163. *
  164. * @return array
  165. */
  166. function annotationcommand_adapter_get_options($command) {
  167. $default_options = isset($command['consolidation-option-defaults']) ? $command['consolidation-option-defaults'] : [];
  168. $options = drush_redispatch_get_options() + $default_options;
  169. $options += drush_get_merged_options();
  170. return $options;
  171. }
  172. /**
  173. * This function is set as the $command['callback'] for commands that have
  174. * been converted to annotated commands. When the DRUSH_SYMFONY environment
  175. * variable is set, these will be called via Symfony's Application::run() method.
  176. * Otherwise, the legacy Drush command dispatcher will be used for all commands.
  177. *
  178. * @return bolean false if command failed (expect drush_set_error was called in this case)
  179. */
  180. function annotationcommand_adapter_process_command() {
  181. $userArgs = func_get_args();
  182. $commandprocessor = annotationcommand_adapter_get_processor();
  183. $command = drush_get_command();
  184. annotationcommand_adapter_add_hook_options($command);
  185. $args = [];
  186. foreach ($command['consolidation-arg-defaults'] as $key => $default) {
  187. $value = array_shift($userArgs);
  188. if (!isset($value)) {
  189. $value = $default;
  190. }
  191. $args[$key] = $value;
  192. }
  193. $input = new DrushInputAdapter($args, annotationcommand_adapter_get_options($command), $command['command']);
  194. $output = new DrushOutputAdapter();
  195. $annotationData = $command['annotations'];
  196. $commandData = new CommandData(
  197. $annotationData,
  198. $input,
  199. $output
  200. );
  201. $commandData->setIncludeOptionsInArgs($command['add-options-to-arguments']);
  202. $names = annotationcommand_adapter_command_names($command);
  203. // n.b.: backend result is set by a post-alter hook.
  204. $result = $commandprocessor->process(
  205. $output,
  206. $names,
  207. $command['annotated-command-callback'],
  208. $commandData
  209. );
  210. return $result;
  211. }
  212. /**
  213. * Internal function called by annotationcommand_adapter_commands, which
  214. * is called by drush_get_commands().
  215. *
  216. * @param array $annotation_commandfiles path => class mapping
  217. *
  218. * @return object[]
  219. */
  220. function annotationcommand_adapter_get_commands($annotation_commandfiles) {
  221. $commands = [];
  222. // This will give us a list containing something akin to:
  223. // 'modules/default_content/src/CliTools/DefaultContentCommands.php' =>
  224. // '\\Drupal\\default_content\\CliTools\\DefaultContentCommands',
  225. foreach ($annotation_commandfiles as $commandfile_path => $commandfile_class) {
  226. if (file_exists($commandfile_path)) {
  227. $commandhandler = annotationcommand_adapter_create_commandfile_instance($commandfile_path, $commandfile_class);
  228. $commands_for_this_commandhandler = annotationcommand_adapter_get_commands_for_commandhandler($commandhandler, $commandfile_path);
  229. $commands = array_merge($commands, $commands_for_this_commandhandler);
  230. }
  231. }
  232. return $commands;
  233. }
  234. /**
  235. * Create and cache a commandfile instance.
  236. *
  237. * @param string $commandfile_path Path to the commandfile implementation
  238. * @param string $commandfile_class Namespace and class of the commandfile object
  239. *
  240. * @return object
  241. */
  242. function annotationcommand_adapter_create_commandfile_instance($commandfile_path, $commandfile_class) {
  243. $runner = \Drush::runner();
  244. $app = \Drush::service('application');
  245. $cache =& drush_get_context('DRUSH_ANNOTATION_COMMANDFILE_INSTANCES');
  246. if (!isset($cache[$commandfile_path])) {
  247. include_once $commandfile_path;
  248. $commandhandler = $runner->registerCommandClass($app, $commandfile_class);
  249. $cache[$commandfile_path] = $commandhandler;
  250. }
  251. return $cache[$commandfile_path];
  252. }
  253. /**
  254. * TODO: document
  255. */
  256. function annotationcommand_adapter_cache_module_console_commands($console_command, $commandfile_path = null) {
  257. if (!isset($commandfile_path)) {
  258. $class = new \ReflectionClass($console_command);
  259. $commandfile_path = $class->getFileName();
  260. }
  261. $module_service_commands = drush_get_context('DRUSH_MODULE_SERVICE_COMMANDS');
  262. $commands = annotationcommand_adapter_get_command_for_console_command($console_command, $commandfile_path);
  263. drush_set_context('DRUSH_MODULE_SERVICE_COMMANDS', array_merge($commands, $module_service_commands));
  264. }
  265. /**
  266. * TODO: document
  267. */
  268. function annotationcommand_adapter_cache_module_service_commands($commandhandler, $commandfile_path = null) {
  269. if (!isset($commandfile_path)) {
  270. $class = new \ReflectionClass($commandhandler);
  271. $commandfile_path = $class->getFileName();
  272. }
  273. $module_service_commands = drush_get_context('DRUSH_MODULE_SERVICE_COMMANDS');
  274. $commands = annotationcommand_adapter_get_commands_for_commandhandler($commandhandler, $commandfile_path);
  275. drush_set_context('DRUSH_MODULE_SERVICE_COMMANDS', array_merge($commands, $module_service_commands));
  276. }
  277. /**
  278. * Convert a Symfony Console command into a Drush $command record
  279. *
  280. * @param Symfony\Component\Console\Command\Command $console_command The Symfony Console command to convert
  281. * @param string $commandfile_path Path to console command file
  282. *
  283. * @return array Drush $command record
  284. */
  285. function annotationcommand_adapter_get_command_for_console_command($console_command, $commandfile_path) {
  286. $commands = [];
  287. $commandfile = basename($commandfile_path, '.php');
  288. $factory = \Drush::commandFactory();
  289. $inputDefinition = $console_command->getDefinition();
  290. $inputArguments = $inputDefinition->getArguments();
  291. $inputOptions = $inputDefinition->getOptions();
  292. $aliases = $console_command->getAliases();
  293. $command_name = strtolower($console_command->getName());
  294. $standard_alias = str_replace(':', '-', $command_name);
  295. if ($command_name != $standard_alias) {
  296. $aliases[] = $standard_alias;
  297. }
  298. $command = [
  299. 'name' => $command_name,
  300. 'callback' => 'annotationcommand_adapter_run_console_command',
  301. 'drush-console-command' => $console_command,
  302. 'commandfile' => $commandfile,
  303. 'category' => $commandfile,
  304. 'options' => [],
  305. 'arguments' => [],
  306. 'description' => $console_command->getDescription(),
  307. 'examples' => $console_command->getUsages(),
  308. 'aliases' => $aliases,
  309. ];
  310. foreach ($inputArguments as $arg => $inputArg) {
  311. $command['arguments'][$arg] = $inputArg->getDescription();
  312. }
  313. $command['required-arguments'] = $inputDefinition->getArgumentRequiredCount();
  314. foreach ($inputOptions as $option => $inputOption) {
  315. $description = $inputOption->getDescription();
  316. $default = $inputOption->getDefault();
  317. $command['options'][$option] = ['description' => $description];
  318. if (!empty($default)) {
  319. $command['options'][$option]['example-value'] = $default;
  320. }
  321. }
  322. $command += drush_command_defaults($command_name, $commandfile, $commandfile_path);
  323. $commands[$command_name] = $command;
  324. return $commands;
  325. }
  326. /**
  327. * Convert an annotated command command handler object into a Drush $command record.
  328. *
  329. * @param object $commandhandler Command handler object
  330. * @param string $commandfile_path
  331. * @param boolean $includeAllPublicMethods TODO remove this, make it 'false' always
  332. *
  333. * @return array Drush $command record
  334. */
  335. function annotationcommand_adapter_get_commands_for_commandhandler($commandhandler, $commandfile_path) {
  336. $cache =& drush_get_context('DRUSH_ANNOTATION_COMMANDS_FOR_COMMANDFILE');
  337. if (isset($cache[$commandfile_path])) {
  338. return $cache[$commandfile_path];
  339. }
  340. $factory = \Drush::commandFactory();
  341. $commands = [];
  342. $commandfile = basename($commandfile_path, '.php');
  343. $commandinfo_list = $factory->getCommandInfoListFromClass($commandhandler);
  344. foreach ($commandinfo_list as $commandinfo) {
  345. $factory->registerCommandHook($commandinfo, $commandhandler);
  346. // Skip anything that is not a command
  347. if (!AnnotatedCommandFactory::isCommandMethod($commandinfo, false)) {
  348. continue;
  349. }
  350. $aliases = $commandinfo->getAliases();
  351. $command_name = strtolower($commandinfo->getName());
  352. $standard_alias = str_replace(':', '-', $command_name);
  353. if ($command_name != $standard_alias) {
  354. $aliases[] = $standard_alias;
  355. }
  356. $handle_remote_commands = strtolower($commandinfo->getAnnotation('handle-remote-commands')) == 'true';
  357. $hidden = $commandinfo->hasAnnotation('hidden');
  358. // If there is no 'bootstrap' annotation, default to NONE.
  359. $bootstrap = DRUSH_BOOTSTRAP_NONE;
  360. if ($bootstrap = $commandinfo->getAnnotation('bootstrap')) {
  361. $bootstrap = constant($bootstrap);
  362. }
  363. $command = [
  364. 'name' => $command_name,
  365. //'callback' => [$commandhandler, $commandinfo->getMethodName()],
  366. 'callback' => 'annotationcommand_adapter_process_command',
  367. 'annotated-command-callback' => [$commandhandler, $commandinfo->getMethodName()],
  368. 'commandfile' => $commandfile,
  369. 'category' => $commandfile,
  370. 'options' => [],
  371. 'arguments' => [],
  372. 'description' => $commandinfo->getDescription(),
  373. 'examples' => $commandinfo->getExampleUsages(),
  374. 'bootstrap' => $bootstrap,
  375. 'handle-remote-commands' => $handle_remote_commands,
  376. 'hidden' => $hidden,
  377. 'aliases' => $aliases,
  378. 'add-options-to-arguments' => TRUE,
  379. 'consolidation-output-formatters' => TRUE,
  380. 'consolidation-option-defaults' => $commandinfo->options()->getValues(),
  381. 'consolidation-arg-defaults' => $commandinfo->arguments()->getValues(),
  382. ];
  383. $required_arguments = 0;
  384. foreach ($commandinfo->arguments()->getValues() as $arg => $default) {
  385. $command['arguments'][$arg] = $commandinfo->arguments()->getDescription($arg);
  386. if (!$commandinfo->arguments()->hasDefault($arg)) {
  387. ++$required_arguments;
  388. }
  389. }
  390. $command['required-arguments'] = $required_arguments;
  391. foreach ($commandinfo->options()->getValues() as $option => $default) {
  392. $description = $commandinfo->options()->getDescription($option);
  393. $command['options'][$option] = ['description' => $description];
  394. if (!empty($default)) {
  395. $command['options'][$option]['example-value'] = $default;
  396. }
  397. $fn = 'annotationcommand_adapter_alter_option_description_' . $option;
  398. if (function_exists($fn)) {
  399. $command['options'][$option] = $fn($command['options'][$option], $commandinfo, $default);
  400. }
  401. if ($commandinfo->getAnnotation('hidden-option') == $option) {
  402. $command['options'][$option]['hidden'] = TRUE;
  403. }
  404. }
  405. $command['annotations'] = $commandinfo->getAnnotations();
  406. // If the command has a '@return' annotation, then
  407. // remember information we will need to use the output formatter.
  408. $returnType = $commandinfo->getReturnType();
  409. if (isset($returnType)) {
  410. $command['return-type'] = $returnType;
  411. }
  412. if ($commandinfo->getAnnotation('allow-additional-options') !== null) {
  413. $command['allow-additional-options'] = TRUE;
  414. }
  415. $command += drush_command_defaults($command_name, $commandfile, $commandfile_path);
  416. $commands[$command_name] = $command;
  417. }
  418. $cache[$commandfile_path] = $commands;
  419. return $commands;
  420. }
  421. /**
  422. * Modify a $command record, adding option definitions defined by any
  423. * command hook.
  424. *
  425. * @param array $command Drush command record to modify
  426. */
  427. function annotationcommand_adapter_add_hook_options(&$command)
  428. {
  429. // Get options added by hooks. We postpone doing this until the
  430. // last minute rather than doing it when processing commandfiles
  431. // so that we do not need to worry about what order we process the
  432. // commandfiles in -- we can load extensions late, and still have
  433. // the extension hook a core command, or have an early-loaded global
  434. // extension hook a late-loaded extension (e.g. attached to a module).
  435. $names = annotationcommand_adapter_command_names($command);
  436. $names[] = '*'; // we are missing annotations here; maybe we just don't support that? (TODO later, maybe)
  437. $factory = \Drush::commandFactory();
  438. $extraOptions = $factory->hookManager()->getHookOptions($names);
  439. foreach ($extraOptions as $commandinfo) {
  440. if (!isset($command['consolidation-option-defaults'])) {
  441. $command['consolidation-option-defaults'] = array();
  442. }
  443. $command['consolidation-option-defaults'] += $commandinfo->options()->getValues();
  444. foreach ($commandinfo->options()->getValues() as $option => $default) {
  445. $description = $commandinfo->options()->getDescription($option);
  446. $command['options'][$option] = ['description' => $description];
  447. if (!empty($default)) {
  448. $command['options'][$option]['example-value'] = $default;
  449. }
  450. if ($commandinfo->getAnnotation('hidden-option') == $option) {
  451. $command['options'][$option]['hidden'] = TRUE;
  452. }
  453. $fn = 'annotationcommand_adapter_alter_option_description_' . $option;
  454. if (function_exists($fn)) {
  455. $command['options'][$option] = $fn($command['options'][$option], $commandinfo, $default);
  456. }
  457. }
  458. }
  459. }
  460. /**
  461. * Build all of the name variants for a Drush $command record
  462. *
  463. * @param array $command Drush command record
  464. *
  465. * @return string[]
  466. */
  467. function annotationcommand_adapter_command_names($command)
  468. {
  469. $names = array_merge(
  470. [$command['command']],
  471. $command['aliases']
  472. );
  473. if (!empty($command['annotated-command-callback'])) {
  474. $commandHandler = $command['annotated-command-callback'][0];
  475. $reflectionClass = new \ReflectionClass($commandHandler);
  476. $commandFileClass = $reflectionClass->getName();
  477. $names[] = $commandFileClass;
  478. }
  479. return $names;
  480. }
  481. /**
  482. * Convert from an old-style Drush initialize hook into annotated-command hooks.
  483. * @see _drush_invoke_hooks().
  484. *
  485. * @param string[] $names All of the applicable names for the command being hooked
  486. * @param CommandData $commandData All of the parameter data associated with the
  487. * current command invokation, including the InputInterface, OutputInterface
  488. * and AnnotationData
  489. */
  490. function annotationcommand_adapter_call_initialize($names, CommandData $commandData)
  491. {
  492. $factory = \Drush::commandFactory();
  493. $hookManager = $factory->hookManager();
  494. $hooks = $hookManager->getHooks(
  495. $names,
  496. [
  497. HookManager::PRE_INITIALIZE,
  498. HookManager::INITIALIZE,
  499. HookManager::POST_INITIALIZE,
  500. ],
  501. $commandData->annotationData()
  502. );
  503. foreach ((array)$hooks as $hook) {
  504. if (!is_object($hook)) {
  505. $hook($commandData->input(), $commandData->annotationData());
  506. }
  507. }
  508. }
  509. /**
  510. * Convert from an old-style Drush pre-validate hook into annotated-command hooks.
  511. * @see _drush_invoke_hooks().
  512. *
  513. * @param string[] $names All of the applicable names for the command being hooked
  514. * @param CommandData $commandData All of the parameter data associated with the
  515. * current command invokation, including the InputInterface, OutputInterface
  516. * and AnnotationData
  517. *
  518. * @return boolean|object
  519. */
  520. function annotationcommand_adapter_call_hook_pre_validate($names, CommandData $commandData)
  521. {
  522. return annotationcommand_adapter_call_validate_interface(
  523. $names,
  524. [
  525. HookManager::PRE_ARGUMENT_VALIDATOR,
  526. ],
  527. $commandData
  528. );
  529. }
  530. /**
  531. * Convert from an old-style Drush validate hook into annotated-command hooks.
  532. * @see _drush_invoke_hooks().
  533. *
  534. * @param string[] $names All of the applicable names for the command being hooked
  535. * @param CommandData $commandData All of the parameter data associated with the
  536. * current command invokation, including the InputInterface, OutputInterface
  537. * and AnnotationData
  538. *
  539. * @return boolean|object
  540. */
  541. function annotationcommand_adapter_call_hook_validate($names, CommandData $commandData)
  542. {
  543. return annotationcommand_adapter_call_validate_interface(
  544. $names,
  545. [
  546. HookManager::ARGUMENT_VALIDATOR,
  547. ],
  548. $commandData
  549. );
  550. }
  551. /**
  552. * Convert from an old-style Drush pre-command hook into annotated-command hooks.
  553. * @see _drush_invoke_hooks().
  554. *
  555. * @param string[] $names All of the applicable names for the command being hooked
  556. * @param CommandData $commandData All of the parameter data associated with the
  557. * current command invokation, including the InputInterface, OutputInterface
  558. * and AnnotationData
  559. *
  560. * @return boolean|object
  561. */
  562. function annotationcommand_adapter_call_hook_pre_command($names, CommandData $commandData)
  563. {
  564. return annotationcommand_adapter_call_validate_interface(
  565. $names,
  566. [
  567. HookManager::PRE_COMMAND_HOOK,
  568. ],
  569. $commandData
  570. );
  571. }
  572. /**
  573. * Convert from an old-style Drush 'command' hook into annotated-command hooks.
  574. * @see _drush_invoke_hooks().
  575. *
  576. * @param string[] $names All of the applicable names for the command being hooked
  577. * @param CommandData $commandData All of the parameter data associated with the
  578. * current command invokation, including the InputInterface, OutputInterface
  579. * and AnnotationData
  580. *
  581. * @return boolean|object
  582. */
  583. function annotationcommand_adapter_call_hook_command($names, CommandData $commandData)
  584. {
  585. return annotationcommand_adapter_call_validate_interface(
  586. $names,
  587. [
  588. HookManager::COMMAND_HOOK,
  589. ],
  590. $commandData
  591. );
  592. }
  593. /**
  594. * Convert from an old-style Drush post-command hook into annotated-command hooks.
  595. * @see _drush_invoke_hooks().
  596. *
  597. * @param string[] $names All of the applicable names for the command being hooked
  598. * @param CommandData $commandData All of the parameter data associated with the
  599. * current command invokation, including the InputInterface, OutputInterface
  600. * and AnnotationData
  601. * @param mixed $return The return value of the command being executed
  602. *
  603. * @return mixed The altered command return value
  604. */
  605. function annotationcommand_adapter_call_hook_post_command($names, CommandData $commandData, $return)
  606. {
  607. return annotationcommand_adapter_call_process_interface(
  608. $names,
  609. [
  610. HookManager::POST_COMMAND_HOOK,
  611. ],
  612. $commandData,
  613. $return
  614. );
  615. }
  616. /**
  617. * After the primary Drush command hook is called, call all of the annotated-command
  618. * process and alter hooks.
  619. * @see _drush_invoke_hooks().
  620. *
  621. * @param string[] $names All of the applicable names for the command being hooked
  622. * @param CommandData $commandData All of the parameter data associated with the
  623. * current command invokation, including the InputInterface, OutputInterface
  624. * and AnnotationData
  625. * @param mixed $return The return value of the command being executed
  626. *
  627. * @return mixed The altered command return value
  628. */
  629. function annotationcommand_adapter_call_hook_process_and_alter($names, $commandData, $return)
  630. {
  631. return annotationcommand_adapter_call_process_interface(
  632. $names,
  633. [
  634. HookManager::PRE_PROCESS_RESULT,
  635. HookManager::PROCESS_RESULT,
  636. HookManager::POST_PROCESS_RESULT,
  637. HookManager::PRE_ALTER_RESULT,
  638. HookManager::ALTER_RESULT,
  639. HookManager::POST_ALTER_RESULT,
  640. ],
  641. $commandData,
  642. $return
  643. );
  644. }
  645. /**
  646. * Given a list of hooks that conform to the interface ProcessResultInterface,
  647. * call them and return the result.
  648. *
  649. * @param string[] $names All of the applicable names for the command being hooked
  650. * @param string[] $hooks All of the HookManager hooks that should be called
  651. * @param CommandData $commandData All of the parameter data associated with the
  652. * current command invokation, including the InputInterface, OutputInterface
  653. * and AnnotationData
  654. * @param mixed $return The return value of the command being executed
  655. *
  656. * @return mixed The altered command return value
  657. */
  658. function annotationcommand_adapter_call_process_interface($names, $hooks, CommandData $commandData, $return)
  659. {
  660. $factory = \Drush::commandFactory();
  661. $hookManager = $factory->hookManager();
  662. $hooks = $hookManager->getHooks($names, $hooks, $commandData->annotationData());
  663. foreach ((array)$hooks as $hook) {
  664. // @todo: $hook might be a ProcessResultInterface object. Support those?
  665. if (is_object($hook)) {
  666. continue;
  667. }
  668. $result = $hook($return, $commandData);
  669. if (isset($result)) {
  670. $return = $result;
  671. }
  672. }
  673. return $return;
  674. }
  675. /**
  676. * Given a list of hooks that conform to the interface ValidatorInterface,
  677. * call them and return the result.
  678. *
  679. * @param string[] $names All of the applicable names for the command being hooked
  680. * @param string[] $hooks All of the HookManager hooks that should be called
  681. * @param CommandData $commandData All of the parameter data associated with the
  682. * current command invokation, including the InputInterface, OutputInterface
  683. * and AnnotationData
  684. *
  685. * @return boolean|object
  686. */
  687. function annotationcommand_adapter_call_validate_interface($names, $hooks, CommandData $commandData)
  688. {
  689. $factory = \Drush::commandFactory();
  690. $hookManager = $factory->hookManager();
  691. $annotationData = $commandData->annotationData();
  692. $hooks = $hookManager->getHooks($names, $hooks, $annotationData);
  693. foreach ((array)$hooks as $hook) {
  694. // @todo: $hook might be a ValidatorInterface object. Support those?
  695. if (is_object($hook)) {
  696. continue;
  697. }
  698. $validated = $hook($commandData);
  699. // TODO: if $validated is a CommandError, maybe the best thing to do is 'return drush_set_error()'?
  700. if (is_object($validated) || ($validated === false)) {
  701. return $validated;
  702. }
  703. }
  704. return true;
  705. }
  706. /**
  707. * TODO: Document
  708. */
  709. function annotationcommand_adapter_alter_option_description_format($option_help, $commandinfo, $default) {
  710. $formatterManager = annotatedcomand_adapter_get_formatter();
  711. $return_type = $commandinfo->getReturnType();
  712. if (!empty($return_type)) {
  713. $available_formats = $formatterManager->validFormats($return_type);
  714. $option_help['description'] = dt('Select output format. Available: !formats.', array('!formats' => implode(', ', $available_formats)));
  715. if (!empty($default)) {
  716. $option_help['description'] .= dt(' Default is !default.', array('!default' => $default));
  717. }
  718. }
  719. return $option_help;
  720. }
  721. /**
  722. * TODO: Document
  723. */
  724. function annotationcommand_adapter_alter_option_description_fields($option_help, $commandinfo, $default) {
  725. $formatOptions = new FormatterOptions($commandinfo->getAnnotations()->getArrayCopy());
  726. $field_labels = $formatOptions->get(FormatterOptions::FIELD_LABELS, [], '');
  727. $default_fields = $formatOptions->get(FormatterOptions::DEFAULT_FIELDS, [], array_keys($field_labels));
  728. $available_fields = array_keys($field_labels);
  729. // @todo silencing a notice that will likely be fixed on views-list fixes https://github.com/consolidation/output-formatters/issues/35
  730. $option_help['example-value'] = @implode(', ', $default_fields);
  731. $option_help['description'] = dt('Fields to output. All available fields are: !available.', array('!available' => implode(', ', $available_fields)));
  732. return $option_help;
  733. }
  734. /**
  735. * In some circumstances, Drush just does a deep search for any *.drush.inc
  736. * file, so that it can find all commands, in enabled and disabled modules alike,
  737. * for the purpose of displaying the help text for that command.
  738. */
  739. function annotationcommand_adapter_refine_searchpaths($searchpath) {
  740. $result = [];
  741. foreach ($searchpath as $path) {
  742. $max_depth = TRUE;
  743. $pattern = '/.*\.info$/';
  744. if (drush_drupal_major_version() > 7) {
  745. $pattern = '/.*\.info.yml$/';
  746. }
  747. $locations = drush_scan_directory($path, $pattern, ['.', '..'], false, $max_depth);
  748. // Search for any directory that might be a module or theme (contains
  749. // a *.info or a *.info.yml file)
  750. foreach ($locations as $key => $info) {
  751. $result[dirname($key)] = true;
  752. }
  753. }
  754. return array_keys($result);
  755. }