More tidying.
[yaffs-website] / vendor / drush / drush / includes / bootstrap.inc
1 <?php
2
3 use Drush\Log\LogLevel;
4
5 /**
6  * No bootstrap.
7  *
8  * Commands that only preflight, but do not bootstrap, should use
9  * a bootstrap level of DRUSH_BOOTSTRAP_NONE.
10  */
11 define('DRUSH_BOOTSTRAP_NONE', -1);
12
13 /**
14  * Use drush_bootstrap_max instead of drush_bootstrap_to_phase
15  *
16  * This constant is only usable as the value of the 'bootstrap'
17  * item of a command object, or as the parameter to
18  * drush_bootstrap_to_phase.  It is not a real bootstrap state.
19  */
20 define('DRUSH_BOOTSTRAP_MAX', -2);
21
22 /**
23  * @deprecated
24  *
25  * No longer used, but 0 remains reserved. Drush always runs preflight.
26  * Commands may alternatively use DRUSH_BOOTSTRAP_NONE.
27  */
28 define('DRUSH_BOOTSTRAP_DRUSH', 0);
29
30 // TODO: Move all of the constants below to a Drupal-specific file.
31 // We can't do this until commands are declaring which CMS they work
32 // with, because right now, commands that do not declare a 'bootstrap'
33 // level default to DRUSH_BOOTSTRAP_DRUPAL_LOGIN, so we need this constant,
34 // at least, available in non-Drupal contexts.
35
36 /**
37  * Set up and test for a valid drupal root, either through the -r/--root options,
38  * or evaluated based on the current working directory.
39  *
40  * Any code that interacts with an entire Drupal installation, and not a specific
41  * site on the Drupal installation should use this bootstrap phase.
42  */
43 define('DRUSH_BOOTSTRAP_DRUPAL_ROOT',  1);
44
45 /**
46  * Set up a Drupal site directory and the correct environment variables to
47  * allow Drupal to find the configuration file.
48  *
49  * If no site is specified with the -l / --uri options, Drush will assume the
50  * site is 'default', which mimics Drupal's behaviour.
51  *
52  * If you want to avoid this behaviour, it is recommended that you use the
53  * DRUSH_BOOTSTRAP_DRUPAL_ROOT bootstrap phase instead.
54  *
55  * Any code that needs to modify or interact with a specific Drupal site's
56  * settings.php file should bootstrap to this phase.
57  */
58 define('DRUSH_BOOTSTRAP_DRUPAL_SITE', 2);
59
60 /**
61  * Load the settings from the Drupal sites directory.
62  *
63  * This phase is analagous to the DRUPAL_BOOTSTRAP_CONFIGURATION bootstrap phase in Drupal
64  * itself, and this is also the first step where Drupal specific code is included.
65  *
66  * This phase is commonly used for code that interacts with the Drupal install API,
67  * as both install.php and update.php start at this phase.
68  */
69 define('DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION', 3);
70
71 /**
72  * Connect to the Drupal database using the database credentials loaded
73  * during the previous bootstrap phase.
74  *
75  * This phase is analogous to the DRUPAL_BOOTSTRAP_DATABASE bootstrap phase in
76  * Drupal.
77  *
78  * Any code that needs to interact with the Drupal database API needs to
79  * be bootstrapped to at least this phase.
80  */
81 define('DRUSH_BOOTSTRAP_DRUPAL_DATABASE', 4);
82
83 /**
84  * Fully initialize Drupal.
85  *
86  * This is analogous to the DRUPAL_BOOTSTRAP_FULL bootstrap phase in
87  * Drupal.
88  *
89  * Any code that interacts with the general Drupal API should be
90  * bootstrapped to this phase.
91  */
92 define('DRUSH_BOOTSTRAP_DRUPAL_FULL', 5);
93
94 /**
95  * Log in to the initialiased Drupal site.
96  *
97  * This is the default bootstrap phase all commands will try to reach,
98  * unless otherwise specified.
99  *
100  * This bootstrap phase is used after the site has been
101  * fully bootstrapped.
102  *
103  * This phase will log you in to the drupal site with the username
104  * or user ID specified by the --user/ -u option.
105  *
106  * Use this bootstrap phase for your command if you need to have access
107  * to information for a specific user, such as listing nodes that might
108  * be different based on who is logged in.
109  */
110 define('DRUSH_BOOTSTRAP_DRUPAL_LOGIN', 6);
111
112 /**
113  * Return the list of bootstrap objects that are available for
114  * initializing a CMS with Drush.  We insure that any given candidate
115  * class is instantiated only once.
116  *
117  * @return \Drush\Boot\Boot[]
118  */
119 function drush_get_bootstrap_candidates() {
120   $candidate_classes = drush_get_bootstrap_candidate_classnames();
121
122   $cache =& drush_get_context('DRUSH_BOOTSTRAP_CANDIDATE_OBJECTS');
123
124   $result = array();
125   foreach($candidate_classes as $candidate_class) {
126     if (array_key_exists($candidate_class, $cache)) {
127       $result[$candidate_class] = $cache[$candidate_class];
128     }
129     else {
130       $result[$candidate_class] = new $candidate_class;
131     }
132   }
133
134   $cache = $result;
135   return $result;
136 }
137
138 /**
139  * Find the list of bootstrap classnames available for initializing a
140  * CMS with Drush.
141  *
142  * @return array
143  */
144 function drush_get_bootstrap_candidate_classnames() {
145   // Give all commandfiles a chance to return candidates.  They should
146   // return STRINGS with the class name of the bootstrap object they provide.
147   $candidates = drush_command_invoke_all('bootstrap_candidates');
148   // If a bootstrap class was specified on the command line, consider it first.
149   $bootstrap_class = drush_get_option('bootstrap_class', FALSE);
150   if ($bootstrap_class) {
151     array_unshift($candidates, $bootstrap_class);
152   }
153   // Add candidate bootstrap classes for Drupal
154   foreach (array('8', '7', '6') as $version) {
155     $drupal_bootstrap_class = 'Drush\Boot\DrupalBoot' . $version;
156     $candidates[] = $drupal_bootstrap_class;
157   }
158   // Always consider our default bootstrap class last.
159   $candidates[] = 'Drush\Boot\EmptyBoot';
160
161   return $candidates;
162 }
163
164 /**
165  * Look up the best bootstrap class for the given location
166  * from the set of available candidates.
167  */
168 function drush_bootstrap_class_for_root($path) {
169   drush_load_bootstrap_commandfile_at_path($path);
170   $candidates = drush_get_bootstrap_candidates();
171   foreach ($candidates as $candidate) {
172     if ($candidate->valid_root($path)) {
173       return $candidate;
174     }
175   }
176   return NULL;
177 }
178
179 /**
180  * Check to see if there is a bootstrap class available
181  * at the specified location; if there is, load it.
182  */
183 function drush_load_bootstrap_commandfile_at_path($path) {
184   static $paths = array();
185
186   if (!empty($path) && (!array_key_exists($path, $paths))) {
187     $paths[$path] = TRUE;
188     // Check to see if we have any bootstrap classes in this location.
189     $bootstrap_class_dir = $path . '/drush/bootstrap';
190     if (is_dir($bootstrap_class_dir)) {
191       _drush_add_commandfiles(array($bootstrap_class_dir), DRUSH_BOOTSTRAP_NONE);
192     }
193   }
194 }
195
196 /**
197  * Select the bootstrap class to use.  If this is called multiple
198  * times, the bootstrap class returned might change on subsequent
199  * calls, if the root directory changes.  Once the bootstrap object
200  * starts changing the state of the system, however, it will
201  * be 'latched', and further calls to drush_select_bootstrap_class()
202  * will always return the same object.
203  */
204 function drush_select_bootstrap_class() {
205   $root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
206
207   // Once we have selected a Drupal root, we will reduce our bootstrap
208   // candidates down to just the one used to select this site root.
209   $bootstrap = drush_bootstrap_class_for_root($root);
210   // If we have not found a bootstrap class by this point,
211   // then take the last one and use it.  This should be our
212   // default bootstrap class.  The default bootstrap class
213   // should pass through all calls without doing anything that
214   // changes state in a CMS-specific way.
215   if ($bootstrap == NULL) {
216     $candidates = drush_get_bootstrap_candidates();
217     $bootstrap = array_pop($candidates);
218   }
219
220   return $bootstrap;
221 }
222
223 /**
224  * Don't allow the bootstrap object to change once we start bootstrapping
225  */
226 function drush_latch_bootstrap_object($bootstrap) {
227   drush_set_context('DRUSH_BOOTSTRAP_OBJECT', $bootstrap);
228 }
229
230 /**
231  * Get the appropriate bootstrap object.  We'll search for a new
232  * bootstrap object every time someone asks for one until we start
233  * bootstrapping; then we'll returned the same cached one every time.
234  *
235  * @return \Drush\Boot\Boot
236  */
237 function drush_get_bootstrap_object() {
238   $bootstrap = drush_get_context('DRUSH_BOOTSTRAP_OBJECT', FALSE);
239   if (!$bootstrap) {
240     $bootstrap = drush_select_bootstrap_class();
241   }
242   return $bootstrap;
243 }
244
245 /**
246  * Find the URI that has been selected by the cwd
247  * if it was not previously set via the --uri / -l option
248  */
249 function _drush_bootstrap_selected_uri() {
250   $uri = drush_get_context('DRUSH_SELECTED_URI');
251   if (empty($uri)) {
252     $site_path = drush_site_path();
253     $elements = explode('/', $site_path);
254     $current = array_pop($elements);
255     if (!$current) {
256       $current = 'default';
257     }
258     $uri = 'http://'. $current;
259     $uri = drush_set_context('DRUSH_SELECTED_URI', $uri);
260     drush_sitealias_create_self_alias();
261   }
262
263   return $uri;
264 }
265
266 /**
267  * Helper function to store any context settings that are being validated.
268  */
269 function drush_bootstrap_value($context, $value = null) {
270   $values =& drush_get_context('DRUSH_BOOTSTRAP_VALUES', array());
271
272   if (isset($value)) {
273     $values[$context] = $value;
274   }
275
276   if (array_key_exists($context, $values)) {
277     return $values[$context];
278   }
279
280   return null;
281 }
282
283 /**
284  * Returns an array that determines what bootstrap phases
285  * are necessary to bootstrap the CMS.
286  *
287  * @param bool $function_names
288  *   (optional) If TRUE, return an array of method names index by their
289  *   corresponding phase values. Otherwise return an array of phase values.
290  *
291  * @return array
292  *
293  * @see \Drush\Boot\Boot::bootstrap_phases()
294  */
295 function _drush_bootstrap_phases($function_names = FALSE) {
296   $result = array();
297
298   if ($bootstrap = drush_get_bootstrap_object()) {
299     $result = $bootstrap->bootstrap_phases();
300     if (!$function_names) {
301       $result = array_keys($result);
302     }
303   }
304   return $result;
305 }
306
307 /**
308  * Bootstrap Drush to the desired phase.
309  *
310  * This function will sequentially bootstrap each
311  * lower phase up to the phase that has been requested.
312  *
313  * @param int $phase
314  *   The bootstrap phase to bootstrap to.
315  * @param int $phase_max
316  *   (optional) The maximum level to boot to. This does not have a use in this
317  *   function itself but can be useful for other code called from within this
318  *   function, to know if e.g. a caller is in the process of booting to the
319  *   specified level. If specified, it should never be lower than $phase.
320  *
321  * @return bool
322  *   TRUE if the specified bootstrap phase has completed.
323  *
324  * @see \Drush\Boot\Boot::bootstrap_phases()
325  */
326 function drush_bootstrap($phase, $phase_max = FALSE) {
327   $bootstrap = drush_get_bootstrap_object();
328   $phases = _drush_bootstrap_phases(TRUE);
329   $result = TRUE;
330
331   // If the requested phase does not exist in the list of available
332   // phases, it means that the command requires bootstrap to a certain
333   // level, but no site root could be found.
334   if (!isset($phases[$phase])) {
335     $result = drush_bootstrap_error('DRUSH_NO_SITE', dt("We could not find an applicable site for that command."));
336   }
337
338   // Once we start bootstrapping past the DRUSH_BOOTSTRAP_DRUSH phase, we
339   // will latch the bootstrap object, and prevent it from changing.
340   if ($phase > DRUSH_BOOTSTRAP_DRUSH) {
341     drush_latch_bootstrap_object($bootstrap);
342   }
343
344   drush_set_context('DRUSH_BOOTSTRAPPING', TRUE);
345   foreach ($phases as $phase_index => $current_phase) {
346     $bootstrapped_phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE', -1);
347     if ($phase_index > $phase) {
348       break;
349     }
350     if ($phase_index > $bootstrapped_phase) {
351       if ($result = drush_bootstrap_validate($phase_index)) {
352         if (method_exists($bootstrap, $current_phase) && !drush_get_error()) {
353           drush_log(dt("Drush bootstrap phase : !function()", array('!function' => $current_phase)), LogLevel::BOOTSTRAP);
354           $bootstrap->{$current_phase}();
355
356           // Reset commandfile cache and find any new command files that are available during this bootstrap phase.
357           drush_get_commands(TRUE);
358           _drush_find_commandfiles($phase_index, $phase_max);
359         }
360         drush_set_context('DRUSH_BOOTSTRAP_PHASE', $phase_index);
361       }
362     }
363   }
364   drush_set_context('DRUSH_BOOTSTRAPPING', FALSE);
365   if (!$result || drush_get_error()) {
366     $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS', array());
367     foreach ($errors as $code => $message) {
368       drush_set_error($code, $message);
369     }
370   }
371   return !drush_get_error();
372 }
373
374 /**
375  * Determine whether a given bootstrap phase has been completed
376  *
377  * This function name has a typo which makes me laugh so we choose not to
378  * fix it. Take a deep breath, and smile. See
379  * http://en.wikipedia.org/wiki/HTTP_referer
380  *
381  *
382  * @param int $phase
383  *   The bootstrap phase to test
384  *
385  * @return bool
386  *   TRUE if the specified bootstrap phase has completed.
387  */
388 function drush_has_boostrapped($phase) {
389   $phase_index = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
390
391   return isset($phase_index) && ($phase_index >= $phase);
392 }
393
394 /**
395  * Validate whether a bootstrap phase can be reached.
396  *
397  * This function will validate the settings that will be used
398  * during the actual bootstrap process, and allow commands to
399  * progressively bootstrap to the highest level that can be reached.
400  *
401  * This function will only run the validation function once, and
402  * store the result from that execution in a local static. This avoids
403  * validating phases multiple times.
404  *
405  * @param int $phase
406  *   The bootstrap phase to validate to.
407  *
408  * @return bool
409  *   TRUE if bootstrap is possible, FALSE if the validation failed.
410  *
411  * @see \Drush\Boot\Boot::bootstrap_phases()
412  */
413 function drush_bootstrap_validate($phase) {
414   $bootstrap = drush_get_bootstrap_object();
415   $phases = _drush_bootstrap_phases(TRUE);
416   static $result_cache = array();
417
418   if (!array_key_exists($phase, $result_cache)) {
419     drush_set_context('DRUSH_BOOTSTRAP_ERRORS', array());
420     drush_set_context('DRUSH_BOOTSTRAP_VALUES', array());
421
422     foreach ($phases as $phase_index => $current_phase) {
423       $validated_phase = drush_get_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', -1);
424       if ($phase_index > $phase) {
425         break;
426       }
427       if ($phase_index > $validated_phase) {
428         $current_phase .= '_validate';
429         if (method_exists($bootstrap, $current_phase)) {
430           $result_cache[$phase_index] = $bootstrap->{$current_phase}();
431         }
432         else {
433           $result_cache[$phase_index] = TRUE;
434         }
435         drush_set_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', $phase_index);
436       }
437     }
438   }
439   return $result_cache[$phase];
440 }
441
442 /**
443  * Bootstrap to the specified phase.
444  *
445  * @param int $max_phase_index
446  *   Only attempt bootstrap to the specified level.
447  *
448  * @return bool
449  *   TRUE if the specified bootstrap phase has completed.
450  */
451 function drush_bootstrap_to_phase($max_phase_index) {
452   if ($max_phase_index == DRUSH_BOOTSTRAP_MAX) {
453     // Bootstrap as far as we can without throwing an error, but log for
454     // debugging purposes.
455     drush_log(dt("Trying to bootstrap as far as we can."), 'debug');
456     drush_bootstrap_max();
457     return TRUE;
458   }
459
460   drush_log(dt("Bootstrap to phase !phase.", array('!phase' => $max_phase_index)), LogLevel::BOOTSTRAP);
461   $phases = _drush_bootstrap_phases();
462   $result = TRUE;
463
464   // Try to bootstrap to the maximum possible level, without generating errors
465   foreach ($phases as $phase_index) {
466     if ($phase_index > $max_phase_index) {
467       // Stop trying, since we achieved what was specified.
468       break;
469     }
470
471     if (drush_bootstrap_validate($phase_index)) {
472       if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE', DRUSH_BOOTSTRAP_NONE)) {
473         $result = drush_bootstrap($phase_index, $max_phase_index);
474       }
475     }
476     else {
477       $result = FALSE;
478       break;
479     }
480   }
481
482   return $result;
483 }
484
485 /**
486  * Bootstrap to the highest level possible, without triggering any errors.
487  *
488  * @param int $max_phase_index
489  *   (optional) Only attempt bootstrap to the specified level.
490  *
491  * @return int
492  *   The maximum phase to which we bootstrapped.
493  */
494 function drush_bootstrap_max($max_phase_index = FALSE) {
495   $phases = _drush_bootstrap_phases(TRUE);
496   if (!$max_phase_index) {
497     $max_phase_index = count($phases);
498   }
499
500   // Try to bootstrap to the maximum possible level, without generating errors.
501   foreach ($phases as $phase_index => $current_phase) {
502     if ($phase_index > $max_phase_index) {
503       // Stop trying, since we achieved what was specified.
504       break;
505     }
506
507     if (drush_bootstrap_validate($phase_index)) {
508       if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
509         drush_bootstrap($phase_index, $max_phase_index);
510       }
511     }
512     else {
513       // drush_bootstrap_validate() only logs successful validations. For us,
514       // knowing what failed can also be important.
515       $previous = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
516       drush_log(dt("Bootstrap phase !function() failed to validate; continuing at !current().", array('!function' => $current_phase, '!current' => $phases[$previous])), 'debug');
517       break;
518     }
519   }
520
521   return drush_get_context('DRUSH_BOOTSTRAP_PHASE');
522 }
523
524 /**
525  * Bootstrap the specified site alias.  The site alias must
526  * be a valid alias to a local site.
527  *
528  * @param $site_record
529  *   The alias record for the given site alias.
530  *   @see drush_sitealias_get_record().
531  * @param $max_phase_index
532  *   Only attempt bootstrap to the specified level.
533  * @returns TRUE if attempted to bootstrap, or FALSE
534  *   if no bootstrap attempt was made.
535  */
536 function drush_bootstrap_max_to_sitealias($site_record, $max_phase_index = NULL) {
537   if ((array_key_exists('root', $site_record) && !array_key_exists('remote-host', $site_record))) {
538     drush_sitealias_set_alias_context($site_record);
539     drush_bootstrap_max($max_phase_index);
540     return TRUE;
541   }
542   return FALSE;
543 }
544
545 /**
546  * Helper function to collect any errors that occur during the bootstrap process.
547  * Always returns FALSE, for convenience.
548  */
549 function drush_bootstrap_error($code, $message = null) {
550   $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS');
551   $errors[$code] = $message;
552   drush_set_context('DRUSH_BOOTSTRAP_ERRORS', $errors);
553   return FALSE;
554 }
555
556 function _drush_bootstrap_output_prepare() {
557   // Note that as soon as we set the DRUSH_BACKEND context, we change
558   // the behavior of drush_log().  It is therefore important that we
559   // should not set this context until immediately before we call ob_start
560   // (i.e., in this function).
561   $backend = drush_set_context('DRUSH_BACKEND', drush_get_option('backend'));
562   $quiet = drush_get_context('DRUSH_QUIET');
563
564   if ($backend) {
565     // Load options passed as a JSON encoded string through STDIN.
566     $stdin_options = _drush_backend_get_stdin();
567     if (is_array($stdin_options)) {
568       drush_set_context('stdin', $stdin_options);
569     }
570     // Add an output buffer handler to collect output/pass through backend
571     // packets. Using a chunksize of 2 ensures that each line is flushed
572     // straight away.
573     if ($quiet) {
574       // Pass through of backend packets, discard regular output.
575       ob_start('drush_backend_output_discard', 2);
576     }
577     else {
578       // Collect output.
579       ob_start('drush_backend_output_collect', 2);
580     }
581   }
582
583   // In non-backend quiet mode we start buffering and discards it on command
584   // completion.
585   if ($quiet && !$backend) {
586     ob_start();
587   }
588 }
589
590 /**
591  * Used by a Drush extension to request that its Composer autoload
592  * files be loaded by Drush, if they have not already been.
593  *
594  * Usage:
595  *
596  * function mycommandfile_drush_init() {
597  *   drush_autoload(__FILE__)
598  * }
599  *
600  */
601 function drush_autoload($commandfile) {
602   $already_added = commandfiles_cache()->add($commandfile);
603
604   $dir = dirname($commandfile);
605   $candidates = array("vendor/autoload.php", "../../../vendor/autoload.php");
606   $drush_autoload_file = drush_get_context('DRUSH_VENDOR_PATH', '');
607
608   foreach ($candidates as $candidate) {
609     $autoload = $dir . '/' . $candidate;
610     if (file_exists($autoload) && (realpath($autoload) != $drush_autoload_file)) {
611       include $autoload;
612     }
613   }
614 }