context.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <?php
  2. /**
  3. * @file
  4. * The Drush context API implementation.
  5. *
  6. * This API acts as a storage mechanism for all options, arguments and
  7. * configuration settings that are loaded into drush.
  8. *
  9. * This API also acts as an IPC mechanism between the different drush commands,
  10. * and provides protection from accidentally overriding settings that are
  11. * needed by other parts of the system.
  12. *
  13. * It also avoids the necessity to pass references through the command chain
  14. * and allows the scripts to keep track of whether any settings have changed
  15. * since the previous execution.
  16. *
  17. * This API defines several contexts that are used by default.
  18. *
  19. * Argument contexts :
  20. * These contexts are used by Drush to store information on the command.
  21. * They have their own access functions in the forms of
  22. * drush_set_arguments(), drush_get_arguments(), drush_set_command(),
  23. * drush_get_command().
  24. *
  25. * command : The drush command being executed.
  26. * arguments : Any additional arguments that were specified.
  27. *
  28. * Setting contexts :
  29. * These contexts store options that have been passed to the drush.php
  30. * script, either through the use of any of the config files, directly from
  31. * the command line through --option='value' or through a JSON encoded string
  32. * passed through the STDIN pipe.
  33. *
  34. * These contexts are accessible through the drush_get_option() and
  35. * drush_set_option() functions. See drush_context_names() for a description
  36. * of all of the contexts.
  37. *
  38. * Drush commands may also choose to save settings for a specific context to
  39. * the matching configuration file through the drush_save_config() function.
  40. */
  41. /**
  42. * Return a list of the valid drush context names.
  43. *
  44. * These context names are carefully ordered from
  45. * highest to lowest priority.
  46. *
  47. * These contexts are evaluated in a certain order, and the highest priority value
  48. * is returned by default from drush_get_option. This allows scripts to check whether
  49. * an option was different before the current execution.
  50. *
  51. * Specified by the script itself :
  52. * process : Generated in the current process.
  53. * cli : Passed as --option=value to the command line.
  54. * stdin : Passed as a JSON encoded string through stdin.
  55. * specific : Defined in a command-specific option record, and
  56. * set in the command context whenever that command is used.
  57. * alias : Defined in an alias record, and set in the
  58. * alias context whenever that alias is used.
  59. *
  60. * Specified by config files :
  61. * custom : Loaded from the config file specified by --config or -c
  62. * site : Loaded from the drushrc.php file in the Drupal site directory.
  63. * drupal : Loaded from the drushrc.php file in the Drupal root directory.
  64. * user : Loaded from the drushrc.php file in the user's home directory.
  65. * home.drush Loaded from the drushrc.php file in the $HOME/.drush directory.
  66. * system : Loaded from the drushrc.php file in the system's $PREFIX/etc/drush directory.
  67. * drush : Loaded from the drushrc.php file in the same directory as drush.php.
  68. *
  69. * Specified by the script, but has the lowest priority :
  70. * default : The script might provide some sensible defaults during init.
  71. */
  72. function drush_context_names() {
  73. static $contexts = array(
  74. 'process', 'cli', 'stdin', 'specific', 'alias',
  75. 'custom', 'site', 'drupal', 'user', 'home.drush', 'system',
  76. 'drush', 'default');
  77. return $contexts;
  78. }
  79. /**
  80. * Return a list of possible drushrc file locations.
  81. *
  82. * @context
  83. * A valid drush context from drush_context_names().
  84. * @prefix
  85. * Optional. Specify a prefix to prepend to ".drushrc.php" when looking
  86. * for config files. Most likely used by contrib commands.
  87. * @return
  88. * An associative array containing possible config files to load
  89. * The keys are the 'context' of the files, the values are the file
  90. * system locations.
  91. */
  92. function _drush_config_file($context, $prefix = NULL) {
  93. $configs = array();
  94. $config_file = $prefix ? $prefix . '.' . 'drushrc.php' : 'drushrc.php';
  95. // Did the user explicitly specify a config file?
  96. if ($config = drush_get_option(array('c', 'config'))) {
  97. if (is_dir($config)) {
  98. $config = $config . '/drushrc.php';
  99. }
  100. $configs['custom'] = $config;
  101. }
  102. if ($site_path = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
  103. $configs['site'] = $site_path . "/" . $config_file;
  104. }
  105. if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
  106. $configs['drupal'] = $drupal_root . '/' . $config_file;
  107. }
  108. // in the user home directory
  109. if (!is_null(drush_server_home())) {
  110. $configs['user'] = drush_server_home() . '/.' . $config_file;
  111. }
  112. // in $HOME/.drush directory
  113. if (!is_null(drush_server_home())) {
  114. $configs['home.drush'] = drush_server_home() . '/.drush/' . $config_file;
  115. }
  116. // In the system wide configuration folder.
  117. $configs['system'] = drush_get_context('ETC_PREFIX', '') . '/etc/drush/' . $config_file;
  118. // in the drush installation folder
  119. $configs['drush'] = dirname(__FILE__) . '/../' . $config_file;
  120. return empty($configs[$context]) ? '' : $configs[$context];
  121. }
  122. /**
  123. * Load drushrc files (if available) from several possible locations.
  124. */
  125. function drush_load_config($context) {
  126. drush_load_config_file($context, _drush_config_file($context));
  127. }
  128. function drush_load_config_file($context, $config) {
  129. if (file_exists($config)) {
  130. $options = $aliases = $command_specific = $override = array();
  131. drush_log(dt('Loading drushrc "!config" into "!context" scope.', array('!config' => realpath($config), '!context' => $context)), 'bootstrap');
  132. $ret = @include_once($config);
  133. if ($ret === FALSE) {
  134. drush_log(dt('Cannot open drushrc "!config", ignoring.', array('!config' => realpath($config))), 'warning');
  135. return FALSE;
  136. }
  137. if (!empty($options) || !empty($aliases) || !empty($command_specific)) {
  138. $options = array_merge(drush_get_context($context), $options);
  139. $options['config-file'] = realpath($config);
  140. //$options['site-aliases'] = array_merge(isset($aliases) ? $aliases : array(), isset($options['site-aliases']) ? $options['site-aliases'] : array());
  141. unset($options['site-aliases']);
  142. $options['command-specific'] = array_merge(isset($command_specific) ? $command_specific : array(), isset($options['command-specific']) ? $options['command-specific'] : array());
  143. drush_set_config_options($context, $options, $override);
  144. }
  145. }
  146. }
  147. function drush_set_config_options($context, $options, $override = array()) {
  148. global $drush_conf_override;
  149. // Only reset $drush_conf_override if the array is not set, otherwise keep old values and append new values to it.
  150. if (!isset($drush_conf_override)) {
  151. $drush_conf_override = array();
  152. }
  153. // Copy 'config-file' into 'context-path', converting to an array to hold multiple values if necessary
  154. if (isset($options['config-file'])) {
  155. if (isset($options['context-path'])) {
  156. $options['context-path'] = array_merge(array($options['config-file']), is_array($options['context-path']) ? $options['context-path'] : array($options['context-path']));
  157. }
  158. else {
  159. $options['context-path'] = $options['config-file'];
  160. }
  161. }
  162. // Take out $aliases and $command_specific options
  163. drush_set_config_special_contexts($options);
  164. drush_set_context($context, $options);
  165. // Instruct core not to store queries since we are not outputting them.
  166. // Don't run poormanscron during drush request (D7+).
  167. $defaults = array(
  168. 'dev_query' => FALSE,
  169. 'cron_safe_threshold' => 0,
  170. );
  171. foreach ($defaults as $key => $value) {
  172. // This can be overridden by a command or a drushrc file if needed.
  173. if (!isset($drush_conf_override[$key])) {
  174. $drush_conf_override[$key] = $value;
  175. }
  176. }
  177. /**
  178. * Allow the drushrc.php file to override $conf settings.
  179. * This is a separate variable because the $conf array gets
  180. * initialized to an empty array, in the drupal bootstrap process,
  181. * and changes in settings.php would wipe out the drushrc.php settings.
  182. */
  183. if (!empty($override)) {
  184. $drush_conf_override = array_merge($drush_conf_override, $override);
  185. }
  186. }
  187. /**
  188. * There are certain options such as 'site-aliases' and 'command-specific'
  189. * that must be merged together if defined in multiple drush configuration
  190. * files. If we did not do this merge, then the last configuration file
  191. * that defined any of these properties would overwrite all of the options
  192. * that came before in previously-loaded configuration files. We place
  193. * all of them into their own context so that this does not happen.
  194. */
  195. function drush_set_config_special_contexts(&$options) {
  196. if (isset($options)) {
  197. $has_command_specific = array_key_exists('command-specific', $options);
  198. // Change the keys of the site aliases from 'alias' to '@alias'
  199. if (array_key_exists('site-aliases', $options)) {
  200. $user_aliases = $options['site-aliases'];
  201. $options['site-aliases'] = array();
  202. foreach ($user_aliases as $alias_name => $alias_value) {
  203. if (substr($alias_name,0,1) != '@') {
  204. $alias_name = "@$alias_name";
  205. }
  206. $options['site-aliases'][$alias_name] = $alias_value;
  207. }
  208. }
  209. // Copy site aliases and command-specific options into their
  210. // appropriate caches.
  211. $special_contexts = drush_get_special_keys();
  212. foreach ($special_contexts as $option_name) {
  213. if (isset($options[$option_name])) {
  214. $cache =& drush_get_context($option_name);
  215. $cache = array_merge($cache, $options[$option_name]);
  216. unset($options[$option_name]);
  217. }
  218. }
  219. // If command-specific options were set and if we already have
  220. // a command, then apply the command-specific options immediately.
  221. if ($has_command_specific) {
  222. drush_command_default_options();
  223. }
  224. }
  225. }
  226. /**
  227. * Set a specific context.
  228. *
  229. * @param context
  230. * Any of the default defined contexts.
  231. * @param value
  232. * The value to store in the context
  233. *
  234. * @return
  235. * An associative array of the settings specified in the request context.
  236. */
  237. function drush_set_context($context, $value) {
  238. $cache =& drush_get_context($context);
  239. $cache = $value;
  240. return $value;
  241. }
  242. /**
  243. * Return a specific context, or the whole context cache
  244. *
  245. * This function provides a storage mechanism for any information
  246. * the currently running process might need to communicate.
  247. *
  248. * This avoids the use of globals, and constants.
  249. *
  250. * Functions that operate on the context cache, can retrieve a reference
  251. * to the context cache using :
  252. * $cache = &drush_get_context($context);
  253. *
  254. * This is a private function, because it is meant as an internal
  255. * generalized API for writing static cache functions, not as a general
  256. * purpose function to be used inside commands.
  257. *
  258. * Code that modifies the reference directly might have unexpected consequences,
  259. * such as modifying the arguments after they have already been parsed and dispatched
  260. * to the callbacks.
  261. *
  262. * @param context
  263. * Optional. Any of the default defined contexts.
  264. *
  265. * @return
  266. * If context is not supplied, the entire context cache will be returned.
  267. * Otherwise only the requested context will be returned.
  268. * If the context does not exist yet, it will be initialized to an empty array.
  269. */
  270. function &drush_get_context($context = NULL, $default = NULL) {
  271. static $cache = array();
  272. if (!is_null($context)) {
  273. if (!isset($cache[$context])) {
  274. $default = !is_null($default) ? $default : array();
  275. $cache[$context] = $default;
  276. }
  277. return $cache[$context];
  278. }
  279. return $cache;
  280. }
  281. /**
  282. * Set the arguments passed to the drush.php script.
  283. *
  284. * This function will set the 'arguments' context of the current running script.
  285. *
  286. * When initially called by drush_parse_args, the entire list of arguments will
  287. * be populated. Once the command is dispatched, this will be set to only the remaining
  288. * arguments to the command (i.e. the command name is removed).
  289. *
  290. * @param arguments
  291. * Command line arguments, as an array.
  292. */
  293. function drush_set_arguments($arguments) {
  294. drush_set_context('arguments', $arguments);
  295. }
  296. /**
  297. * Get the arguments passed to the drush.php script.
  298. *
  299. * When drush_set_arguments is initially called by drush_parse_args,
  300. * the entire list of arguments will be populated.
  301. * Once the command has been dispatched, this will be return only the remaining
  302. * arguments to the command.
  303. */
  304. function drush_get_arguments() {
  305. return drush_get_context('arguments');
  306. }
  307. /**
  308. * Set the command being executed.
  309. *
  310. * Drush_dispatch will set the correct command based on it's
  311. * matching of the script arguments retrieved from drush_get_arguments
  312. * to the implemented commands specified by drush_get_commands.
  313. *
  314. * @param
  315. * A numerically indexed array of command components.
  316. */
  317. function drush_set_command($command) {
  318. drush_set_context('command', $command);
  319. }
  320. /**
  321. * Return the command being executed.
  322. *
  323. *
  324. */
  325. function drush_get_command() {
  326. return drush_get_context('command');
  327. }
  328. /**
  329. * Get the value for an option.
  330. *
  331. * If the first argument is an array, then it checks whether one of the options
  332. * exists and return the value of the first one found. Useful for allowing both
  333. * -h and --host-name
  334. *
  335. * @param option
  336. * The name of the option to get
  337. * @param default
  338. * Optional. The value to return if the option has not been set
  339. * @param context
  340. * Optional. The context to check for the option. If this is set, only this context will be searched.
  341. */
  342. function drush_get_option($option, $default = NULL, $context = NULL) {
  343. $value = NULL;
  344. if ($context) {
  345. // We have a definite context to check for the presence of an option.
  346. $value = _drush_get_option($option, drush_get_context($context));
  347. }
  348. else {
  349. // We are not checking a specific context, so check them in a predefined order of precedence.
  350. $contexts = drush_context_names();
  351. foreach ($contexts as $context) {
  352. $value = _drush_get_option($option, drush_get_context($context));
  353. if ($value !== NULL) {
  354. return $value;
  355. }
  356. }
  357. }
  358. if ($value !== NULL) {
  359. return $value;
  360. }
  361. return $default;
  362. }
  363. /**
  364. * Get the value for an option and return it as a list. If the
  365. * option in question is passed on the command line, its value should
  366. * be a comma-separated list (e.g. --flag=1,2,3). If the option
  367. * was set in a drushrc.php file, then its value may be either a
  368. * comma-separated list or an array of values (e.g. $option['flag'] = array('1', '2', '3')).
  369. *
  370. * @param option
  371. * The name of the option to get
  372. * @param default
  373. * Optional. The value to return if the option has not been set
  374. * @param context
  375. * Optional. The context to check for the option. If this is set, only this context will be searched.
  376. */
  377. function drush_get_option_list($option, $default = array(), $context = NULL) {
  378. $result = drush_get_option($option, $default, $context);
  379. if (!is_array($result)) {
  380. $result = explode(',', $result);
  381. }
  382. return $result;
  383. }
  384. /**
  385. * Get the value for an option, but first checks the provided option overrides.
  386. *
  387. * The feature of drush_get_option that allows a list of option names
  388. * to be passed in an array is NOT supported.
  389. *
  390. * @param option_overrides
  391. * An array to check for values before calling drush_get_option.
  392. * @param option
  393. * The name of the option to get.
  394. * @param default
  395. * Optional. The value to return if the option has not been set.
  396. * @param context
  397. * Optional. The context to check for the option. If this is set, only this context will be searched.
  398. *
  399. */
  400. function drush_get_option_override($option_overrides, $option, $value = NULL, $context = NULL) {
  401. if (array_key_exists($option, $option_overrides)) {
  402. return $option_overrides[$option];
  403. }
  404. else {
  405. return drush_get_option($option, $value, $context);
  406. }
  407. }
  408. /**
  409. * Get all of the values for an option in every context.
  410. *
  411. * @param option
  412. * The name of the option to get
  413. * @return
  414. * An array whose key is the context name and value is
  415. * the specific value for the option in that context.
  416. */
  417. function drush_get_context_options($option, $flatten = FALSE) {
  418. $result = array();
  419. $contexts = drush_context_names();
  420. foreach ($contexts as $context) {
  421. $value = _drush_get_option($option, drush_get_context($context));
  422. if ($value !== NULL) {
  423. if ($flatten && is_array($value)) {
  424. $result = array_merge($value, $result);
  425. }
  426. else {
  427. $result[$context] = $value;
  428. }
  429. }
  430. }
  431. return $result;
  432. }
  433. /**
  434. * Retrieves a collapsed list of all options
  435. */
  436. function drush_get_merged_options() {
  437. $contexts = drush_context_names();
  438. $cache = drush_get_context();
  439. $result = array();
  440. foreach (array_reverse($contexts) as $context) {
  441. if (array_key_exists($context, $cache)) {
  442. $result = array_merge($result, $cache[$context]);
  443. }
  444. }
  445. return $result;
  446. }
  447. /**
  448. * Helper function to recurse through possible option names
  449. */
  450. function _drush_get_option($option, $context) {
  451. if (is_array($option)) {
  452. foreach ($option as $current) {
  453. if (array_key_exists($current, $context)) {
  454. return $context[$current];
  455. }
  456. }
  457. }
  458. elseif (array_key_exists($option, $context)) {
  459. return $context[$option];
  460. }
  461. return NULL;
  462. }
  463. /**
  464. * Set an option in one of the option contexts.
  465. *
  466. * @param option
  467. * The option to set.
  468. * @param value
  469. * The value to set it to.
  470. * @param context
  471. * Optional. Which context to set it in.
  472. * @return
  473. * The value parameter. This allows for neater code such as
  474. * $myvalue = drush_set_option('http_host', $_SERVER['HTTP_HOST']);
  475. * Without having to constantly type out the value parameter.
  476. */
  477. function drush_set_option($option, $value, $context = 'process') {
  478. $cache =& drush_get_context($context);
  479. $cache[$option] = $value;
  480. return $value;
  481. }
  482. /**
  483. * A small helper function to set the value in the default context
  484. */
  485. function drush_set_default($option, $value) {
  486. return drush_set_option($option, $value, 'default');
  487. }
  488. /**
  489. * Remove a setting from a specific context.
  490. *
  491. * @param
  492. * Option to be unset
  493. * @param
  494. * Context in which to unset the value in.
  495. */
  496. function drush_unset_option($option, $context = NULL) {
  497. if ($context != NULL) {
  498. $cache =& drush_get_context($context);
  499. if (array_key_exists($option, $cache)) {
  500. unset($cache[$option]);
  501. }
  502. }
  503. else {
  504. $contexts = drush_context_names();
  505. foreach ($contexts as $context) {
  506. drush_unset_option($option, $context);
  507. }
  508. }
  509. }
  510. /**
  511. * Save the settings in a specific context to the applicable configuration file
  512. * This is useful is you want certain settings to be available automatically the next time a command is executed.
  513. *
  514. * @param $context
  515. * The context to save
  516. */
  517. function drush_save_config($context) {
  518. $filename = _drush_config_file($context);
  519. if ($filename) {
  520. $cache = drush_get_context($context);
  521. $fp = fopen($filename, "w+");
  522. if (!$fp) {
  523. return drush_set_error('DRUSH_PERM_ERROR', dt('Drushrc (!filename) could not be written', array('!filename' => $filename)));
  524. }
  525. else {
  526. fwrite($fp, "<?php\n");
  527. $timestamp = mktime();
  528. foreach ($cache as $key => $value) {
  529. $line = "\n\$options['$key'] = ". var_export($value, TRUE) .';';
  530. fwrite($fp, $line);
  531. }
  532. fwrite($fp, "\n");
  533. fclose($fp);
  534. drush_log(dt('Drushrc file (!filename) was written successfully', array('!filename' => $filename)));
  535. return TRUE;
  536. }
  537. }
  538. return FALSE;
  539. }