a10996d486c48071910b179d5253fcdc62bd6228
[yaffs-website] / vendor / drush / drush / includes / context.inc
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 use Drush\Log\LogLevel;
43
44
45 /**
46  * Return a list of the valid drush context names.
47  *
48  * These context names are carefully ordered from
49  * highest to lowest priority.
50  *
51  * These contexts are evaluated in a certain order, and the highest priority value
52  * is returned by default from drush_get_option. This allows scripts to check whether
53  * an option was different before the current execution.
54  *
55  *   Specified by the script itself :
56  *     process  : Generated in the current process.
57  *     cli      : Passed as --option=value to the command line.
58  *     stdin    : Passed as a JSON encoded string through stdin.
59  *     specific : Defined in a command-specific option record, and
60  *                set in the command context whenever that command is used.
61  *     alias    : Defined in an alias record, and set in the
62  *                alias context whenever that alias is used.
63  *
64  *   Specified by config files :
65  *     custom   : Loaded from the config file specified by --config or -c
66  *     site     : Loaded from the drushrc.php file in the Drupal site directory.
67  *     drupal   : Loaded from the drushrc.php file in the Drupal root directory.
68  *     user     : Loaded from the drushrc.php file in the user's home directory.
69  *     home.drush Loaded from the drushrc.php file in the $HOME/.drush directory.
70  *     system   : Loaded from the drushrc.php file in the system's $PREFIX/etc/drush directory.
71  *     drush    : Loaded from the drushrc.php file in the same directory as drush.php.
72  *
73  *   Specified by the script, but has the lowest priority :
74  *     default  : The script might provide some sensible defaults during init.
75  */
76 function drush_context_names() {
77   static $contexts = array(
78     'process', 'cli', 'stdin', 'specific', 'alias',
79     'custom', 'site', 'drupal', 'user', 'home.drush', 'system',
80     'drush', 'default');
81
82   return $contexts;
83 }
84
85 /**
86  * Return a list of possible drushrc file locations.
87  *
88  * @context
89  *   A valid drush context from drush_context_names().
90  * @prefix
91  *   Optional. Specify a prefix to prepend to ".drushrc.php" when looking
92  *   for config files. Most likely used by contrib commands.
93  * @return
94  *   An associative array containing possible config files to load
95  *   The keys are the 'context' of the files, the values are the file
96  *   system locations.
97  */
98 function _drush_config_file($context, $prefix = NULL, $version = '') {
99   $configs = array();
100   $base_name = 'drush' . $version . 'rc.php';
101   $config_file = $prefix ? $prefix . '.' . $base_name : $base_name;
102
103   // Did the user explicitly specify a config file?
104   if ($config_list = (array)drush_get_context('DRUSH_CONFIG')) {
105     foreach ($config_list as $config) {
106       if (is_dir($config)) {
107         $config = $config . '/' . $config_file;
108       }
109       $configs['custom'][] = $config;
110     }
111   }
112
113   if ($drupal_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT')) {
114     $configs['drupal'] = array(
115       $drupal_root . '/../drush/' . $config_file,
116       $drupal_root . '/sites/all/drush/' . $config_file,
117       $drupal_root . '/drush/' . $config_file,
118     );
119
120     if ($conf_path = drush_get_context('DRUSH_SELECTED_DRUPAL_SITE_CONF_PATH', 'sites/default')) {
121       $site_path = $drupal_root . '/' . $conf_path;
122       $configs['site'] = $site_path . "/" . $config_file;
123     }
124   }
125
126   // in the user home directory
127   $server_home = drush_server_home();
128   if (isset($server_home)) {
129     $configs['user'] = $server_home . '/.' . $config_file;
130   }
131
132   // in $HOME/.drush directory
133   $per_user_config_dir = drush_get_context('DRUSH_PER_USER_CONFIGURATION');
134   if (!empty($per_user_config_dir)) {
135     $configs['home.drush'] = $per_user_config_dir . '/' . $config_file;
136   }
137
138   // In the system wide configuration folder.
139   $configs['system'] = drush_get_context('DRUSH_SITE_WIDE_CONFIGURATION') . '/' . $config_file;
140
141   // in the drush installation folder
142   $configs['drush'] = dirname(__FILE__) . '/../' . $config_file;
143
144   return empty($configs[$context]) ? '' : $configs[$context];
145 }
146
147
148 /**
149  * Load drushrc files (if available) from several possible locations.
150  */
151 function drush_load_config($context) {
152   drush_load_config_file($context, _drush_config_file($context));
153   drush_load_config_file($context, _drush_config_file($context, '', DRUSH_MAJOR_VERSION));
154 }
155
156 function drush_load_config_file($context, $config_list) {
157   foreach ((array)$config_list as $config) {
158     if (file_exists($config)) {
159       $options = $aliases = $command_specific = $override = array();
160       drush_log(dt('Loading drushrc "!config" into "!context" scope.', array('!config' => realpath($config), '!context' => $context)), LogLevel::BOOTSTRAP);
161       $ret = @include_once($config);
162       if ($ret === FALSE) {
163         drush_log(dt('Cannot open drushrc "!config", ignoring.', array('!config' => realpath($config))), LogLevel::WARNING);
164         return FALSE;
165       }
166       if (!empty($options) || !empty($aliases) || !empty($command_specific) || !empty($override)) {
167         $options = array_merge(drush_get_context($context), $options);
168         $options['config-file'] = realpath($config);
169
170         unset($options['site-aliases']);
171         $options['command-specific'] = array_merge(isset($command_specific) ? $command_specific : array(), isset($options['command-specific']) ? $options['command-specific'] : array());
172
173         drush_set_config_options($context, $options, $override);
174       }
175     }
176   }
177 }
178
179 function drush_set_config_options($context, $options, $override = array()) {
180   // Copy 'config-file' into 'context-path', converting to an array to hold multiple values if necessary
181   if (isset($options['config-file'])) {
182     if (isset($options['context-path'])) {
183       $options['context-path'] = array_merge(array($options['config-file']), is_array($options['context-path']) ? $options['context-path'] : array($options['context-path']));
184     }
185     else {
186       $options['context-path'] = $options['config-file'];
187     }
188   }
189
190   // Take out $aliases and $command_specific options
191   drush_set_config_special_contexts($options);
192
193   drush_set_context($context, $options);
194 }
195
196 /**
197  * For all global options with a short form, convert all options in the option
198  * array that use the short form into the long form.
199  */
200 function drush_expand_short_form_options(&$options) {
201   foreach (drush_get_global_options() as $name => $info) {
202     if (is_array($info)) {
203       // For any option with a short form, check to see if the short form was set in the
204       // options.  If it was, then rename it to its long form.
205       if (array_key_exists('short-form', $info) && array_key_exists($info['short-form'], $options)) {
206         if (!array_key_exists($name, $options) || !array_key_exists('merge-pathlist', $info)) {
207           $options[$name] = $options[$info['short-form']];
208         }
209         else {
210           $options[$name] = array_merge((array)$options[$name], (array)$options[$info['short-form']]);
211         }
212         unset($options[$info['short-form']]);
213       }
214     }
215   }
216 }
217
218 /**
219  * There are certain options such as 'site-aliases' and 'command-specific'
220  * that must be merged together if defined in multiple drush configuration
221  * files.  If we did not do this merge, then the last configuration file
222  * that defined any of these properties would overwrite all of the options
223  * that came before in previously-loaded configuration files.  We place
224  * all of them into their own context so that this does not happen.
225  */
226 function drush_set_config_special_contexts(&$options) {
227   if (isset($options) && is_array($options)) {
228     $has_command_specific = array_key_exists('command-specific', $options);
229     // Change the keys of the site aliases from 'alias' to '@alias'
230     if (array_key_exists('site-aliases', $options)) {
231       $user_aliases = $options['site-aliases'];
232       $options['site-aliases'] = array();
233       foreach ($user_aliases as $alias_name => $alias_value) {
234         if (substr($alias_name,0,1) != '@') {
235           $alias_name = "@$alias_name";
236         }
237         $options['site-aliases'][$alias_name] = $alias_value;
238       }
239     }
240     // Expand -s into --simulate, etc.
241     drush_expand_short_form_options($options);
242
243     foreach (drush_get_global_options() as $name => $info) {
244       if (is_array($info)) {
245         // For any global option with the 'merge-pathlist' or 'merge-associative' flag, set its
246         // value in the specified context.  The option is 'merged' because we
247         // load $options with the value from the context prior to including the
248         // configuration file.  If the configuration file sets $option['special'][] = 'value',
249         // then the configuration will be merged.  $option['special'] = array(...), on the
250         // other hand, will replace rather than merge the values together.
251         if ((array_key_exists($name, $options)) && (array_key_exists('merge', $info) || (array_key_exists('merge-pathlist', $info) || array_key_exists('merge-associative', $info)))) {
252           $context = array_key_exists('context', $info) ? $info['context'] : $name;
253           $cache =& drush_get_context($context);
254           $value = $options[$name];
255           if (!is_array($value) && array_key_exists('merge-pathlist', $info)) {
256             $value = explode(PATH_SEPARATOR, $value);
257           }
258           if (array_key_exists('merge-associative', $info)) {
259             foreach ($value as $subkey => $subvalue) {
260               $cache[$subkey] = array_merge(isset($cache[$subkey]) ? $cache[$subkey] : array(), $subvalue);
261             }
262           }
263           else {
264             $cache = array_unique(array_merge($cache, $value));
265           }
266           // Once we have moved the option to its special context, we
267           // can remove it from its option context -- unless 'propagate-cli-value'
268           // is set, in which case we need to let it stick around in options
269           // in case it is needed in backend invoke.
270           if (!array_key_exists('propagate-cli-value', $info)) {
271             unset($options[$name]);
272           }
273         }
274       }
275     }
276
277     // If command-specific options were set and if we already have
278     // a command, then apply the command-specific options immediately.
279     if ($has_command_specific) {
280       drush_command_default_options();
281     }
282   }
283 }
284
285 /**
286  * Set a specific context.
287  *
288  * @param context
289  *   Any of the default defined contexts.
290  * @param value
291  *   The value to store in the context
292  *
293  * @return
294  *   An associative array of the settings specified in the request context.
295  */
296 function drush_set_context($context, $value) {
297   $cache =& drush_get_context($context);
298   $cache = $value;
299   return $value;
300 }
301
302
303 /**
304  * Return a specific context, or the whole context cache
305  *
306  * This function provides a storage mechanism for any information
307  * the currently running process might need to communicate.
308  *
309  * This avoids the use of globals, and constants.
310  *
311  * Functions that operate on the context cache, can retrieve a reference
312  * to the context cache using :
313  *     $cache = &drush_get_context($context);
314  *
315  * This is a private function, because it is meant as an internal
316  * generalized API for writing static cache functions, not as a general
317  * purpose function to be used inside commands.
318  *
319  * Code that modifies the reference directly might have unexpected consequences,
320  * such as modifying the arguments after they have already been parsed and dispatched
321  * to the callbacks.
322  *
323  * @param context
324  *   Optional. Any of the default defined contexts.
325  *
326  * @return
327  *   If context is not supplied, the entire context cache will be returned.
328  *   Otherwise only the requested context will be returned.
329  *   If the context does not exist yet, it will be initialized to an empty array.
330  */
331 function &drush_get_context($context = NULL, $default = NULL) {
332   static $cache = array();
333   if (isset($context)) {
334     if (!isset($cache[$context])) {
335       $default = !isset($default) ? array() : $default;
336       $cache[$context] = $default;
337     }
338     return $cache[$context];
339   }
340   return $cache;
341 }
342
343 /**
344  * Set the arguments passed to the drush.php script.
345  *
346  * This function will set the 'arguments' context of the current running script.
347  *
348  * When initially called by drush_parse_args, the entire list of arguments will
349  * be populated. Once the command is dispatched, this will be set to only the remaining
350  * arguments to the command (i.e. the command name is removed).
351  *
352  * @param arguments
353  *   Command line arguments, as an array.
354  */
355 function drush_set_arguments($arguments) {
356   drush_set_context('arguments', $arguments);
357 }
358
359 /**
360  * Gets the command line arguments passed to Drush.
361  *
362  * @return array
363  *   An indexed array of arguments. Until Drush has dispatched the command, the
364  *   array will include the command name as the first element. After that point
365  *   the array will not include the command name.
366  *
367  * @see drush_set_arguments()
368  */
369 function drush_get_arguments() {
370   return drush_get_context('arguments');
371 }
372
373 /**
374  * Set the command being executed.
375  *
376  * Drush_dispatch will set the correct command based on it's
377  * matching of the script arguments retrieved from drush_get_arguments
378  * to the implemented commands specified by drush_get_commands.
379  *
380  * @param
381  *   A numerically indexed array of command components.
382  */
383 function drush_set_command($command) {
384   drush_set_context('command', $command);
385 }
386
387 /**
388  * Return the command being executed.
389  */
390 function drush_get_command() {
391   return drush_get_context('command');
392 }
393
394 /**
395  * Get the value for an option.
396  *
397  * If the first argument is an array, then it checks whether one of the options
398  * exists and return the value of the first one found. Useful for allowing both
399  * -h and --host-name
400  *
401  * @param option
402  *   The name of the option to get
403  * @param default
404  *   Optional. The value to return if the option has not been set
405  * @param context
406  *   Optional. The context to check for the option. If this is set, only this context will be searched.
407  */
408 function drush_get_option($option, $default = NULL, $context = NULL) {
409   $value = NULL;
410
411   if ($context) {
412     // We have a definite context to check for the presence of an option.
413     $value = _drush_get_option($option, drush_get_context($context));
414   }
415   else {
416     // We are not checking a specific context, so check them in a predefined order of precedence.
417     $contexts = drush_context_names();
418
419     foreach ($contexts as $context) {
420       $value = _drush_get_option($option, drush_get_context($context));
421
422       if ($value !== NULL) {
423         return $value;
424       }
425     }
426   }
427
428   if ($value !== NULL) {
429     return $value;
430   }
431
432   return $default;
433 }
434
435 /**
436  * Get the value for an option and return it as a list.  If the
437  * option in question is passed on the command line, its value should
438  * be a comma-separated list (e.g. --flag=1,2,3).  If the option
439  * was set in a drushrc.php file, then its value may be either a
440  * comma-separated list or an array of values (e.g. $option['flag'] = array('1', '2', '3')).
441  *
442  * @param option
443  *   The name of the option to get
444  * @param default
445  *   Optional. The value to return if the option has not been set
446  * @param context
447  *   Optional. The context to check for the option. If this is set, only this context will be searched.
448  */
449 function drush_get_option_list($option, $default = array(), $context = NULL) {
450   $result = drush_get_option($option, $default, $context);
451
452   if (!is_array($result)) {
453     $result = array_map('trim', array_filter(explode(',', $result)));
454   }
455
456   return $result;
457 }
458
459 /**
460  * Get the value for an option, but first checks the provided option overrides.
461  *
462  * The feature of drush_get_option that allows a list of option names
463  * to be passed in an array is NOT supported.
464  *
465  * @param option_overrides
466  *   An array to check for values before calling drush_get_option.
467  * @param option
468  *   The name of the option to get.
469  * @param default
470  *   Optional. The value to return if the option has not been set.
471  * @param context
472  *   Optional. The context to check for the option. If this is set, only this context will be searched.
473  *
474  */
475 function drush_get_option_override($option_overrides, $option, $default = NULL, $context = NULL) {
476   return drush_sitealias_get_option($option_overrides, $option, $default, '', $context);
477 }
478
479 /**
480  * Get an option out of the specified alias.  If it has not been
481  * set in the alias, then get it via drush_get_option.
482  *
483  * @param site_alias_record
484  *   An array of options for an alias record.
485  * @param option
486  *   The name of the option to get.
487  * @param default
488  *   Optional. The value to return if the option does not exist in the site record and has not been set in a context.
489  * @param context
490  *   Optional. The context to check for the option. If this is set, only this context will be searched.
491  */
492 function drush_sitealias_get_option($site_alias_record, $option, $default = NULL, $prefix = '', $context = NULL) {
493   if (is_array($site_alias_record) && array_key_exists($option, $site_alias_record)) {
494     return $site_alias_record[$option];
495   }
496   else {
497     return drush_get_option($prefix . $option, $default, $context);
498   }
499 }
500
501 /**
502  * Get all of the values for an option in every context.
503  *
504  * @param option
505  *   The name of the option to get
506  * @return
507  *   An array whose key is the context name and value is
508  *   the specific value for the option in that context.
509  */
510 function drush_get_context_options($option, $flatten = FALSE) {
511   $result = array();
512
513   $contexts = drush_context_names();
514   foreach ($contexts as $context) {
515     $value = _drush_get_option($option, drush_get_context($context));
516
517     if ($value !== NULL) {
518       if ($flatten && is_array($value)) {
519         $result = array_merge($value, $result);
520       }
521       else {
522         $result[$context] = $value;
523       }
524     }
525   }
526
527   return $result;
528 }
529
530 /**
531  * Retrieves a collapsed list of all options.
532  */
533 function drush_get_merged_options() {
534   $contexts = drush_context_names();
535   $cache = drush_get_context();
536   $result = array();
537   foreach (array_reverse($contexts) as $context) {
538     if (array_key_exists($context, $cache)) {
539       $result = array_merge($result, $cache[$context]);
540     }
541   }
542
543   return $result;
544 }
545
546 /**
547  * Retrieves a collapsed list of all options
548  * with a specified prefix.
549  */
550 function drush_get_merged_prefixed_options($prefix) {
551   $merged_options = drush_get_merged_options();
552   $result = array();
553   foreach ($merged_options as $key => $value) {
554     if ($prefix == substr($key, 0, strlen($prefix))) {
555       $result[substr($key, strlen($prefix))] = $value;
556     }
557   }
558
559   return $result;
560 }
561
562 /**
563  * Helper function to recurse through possible option names
564  */
565 function _drush_get_option($option, $context) {
566   if (is_array($option)) {
567     foreach ($option as $current) {
568       $current_value = _drush_get_option($current, $context);
569       if (isset($current_value)) {
570         return $current_value;
571       }
572     }
573   }
574   elseif (array_key_exists('no-' . $option, $context)) {
575     return FALSE;
576   }
577   elseif (array_key_exists($option, $context)) {
578     return $context[$option];
579   }
580
581   return NULL;
582 }
583
584 /**
585  * Set an option in one of the option contexts.
586  *
587  * @param option
588  *   The option to set.
589  * @param value
590  *   The value to set it to.
591  * @param context
592  *   Optional. Which context to set it in.
593  * @return
594  *   The value parameter. This allows for neater code such as
595  *     $myvalue = drush_set_option('http_host', $_SERVER['HTTP_HOST']);
596  *   Without having to constantly type out the value parameter.
597  */
598 function drush_set_option($option, $value, $context = 'process') {
599   $cache =& drush_get_context($context);
600   $cache[$option] = $value;
601   return $value;
602 }
603
604 /**
605  * A small helper function to set the value in the default context
606  */
607 function drush_set_default($option, $value) {
608   return drush_set_option($option, $value, 'default');
609 }
610
611 /**
612  * Remove a setting from a specific context.
613  *
614  * @param
615  *   Option to be unset
616  * @param
617  *   Context in which to unset the value in.
618  */
619 function drush_unset_option($option, $context = NULL) {
620   if ($context != NULL) {
621     $cache =& drush_get_context($context);
622     if (array_key_exists($option, $cache)) {
623       unset($cache[$option]);
624     }
625   }
626   else {
627     $contexts = drush_context_names();
628
629     foreach ($contexts as $context) {
630       drush_unset_option($option, $context);
631     }
632   }
633 }
634
635 /**
636  * Save the settings in a specific context to the applicable configuration file
637  * This is useful is you want certain settings to be available automatically the next time a command is executed.
638  *
639  * @param $context
640  *   The context to save
641  */
642 function drush_save_config($context) {
643   $filename = _drush_config_file($context);
644   if (is_array($filename)) {
645     $filename = $filename[0];
646   }
647
648   if ($filename) {
649     $cache = drush_get_context($context);
650
651     $fp = fopen($filename, "w+");
652     if (!$fp) {
653       return drush_set_error('DRUSH_PERM_ERROR', dt('Drushrc (!filename) could not be written', array('!filename' => $filename)));
654     }
655     else {
656       fwrite($fp, "<?php\n");
657       foreach ($cache as $key => $value) {
658         $line = "\n\$options['$key'] = ". var_export($value, TRUE) .';';
659         fwrite($fp, $line);
660       }
661       fwrite($fp, "\n");
662       fclose($fp);
663       drush_log(dt('Drushrc file (!filename) was written successfully', array('!filename' => $filename)));
664       return TRUE;
665     }
666
667   }
668   return FALSE;
669 }