/[drupal]/contributions/modules/drush/includes/environment.inc
ViewVC logotype

Contents of /contributions/modules/drush/includes/environment.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.51 - (show annotations) (download) (as text)
Wed Nov 4 22:29:52 2009 UTC (3 weeks, 1 day ago) by weitzman
Branch: MAIN
Changes since 1.50: +72 -11 lines
File MIME type: text/x-php
#460924 by greg.1.anderson. remote aliases bug fix - backend_invoke(), small refactor.
1 <?php
2 // $Id: environment.inc,v 1.50 2009/10/30 21:12:21 weitzman Exp $
3
4 /**
5 * @file
6 * Functions used by drush to query the environment and
7 * setting the current configuration.
8 */
9
10 /**
11 * The indicator for a Drupal installation folder.
12 */
13 define('DRUSH_DRUPAL_BOOTSTRAP', 'includes/bootstrap.inc');
14
15 /**
16 * @name Drush bootstrap phases
17 * @{
18 * Sequential Drush bootstrapping phases.
19 */
20
21 /**
22 * Only bootstrap Drush, without any Drupal specific code.
23 *
24 * Any code that operates on the Drush installation, and not specifically
25 * any Drupal directory, should bootstrap to this phase.
26 */
27 define('DRUSH_BOOTSTRAP_DRUSH', 0);
28
29 /**
30 * Set up and test for a valid drupal root, either through the -r/--root options,
31 * or evaluated based on the current working directory.
32 *
33 * Any code that interacts with an entire Drupal installation, and not a specific
34 * site on the Drupal installation should use this bootstrap phase.
35 */
36 define('DRUSH_BOOTSTRAP_DRUPAL_ROOT', 1);
37
38 /**
39 * Set up a Drupal site directory and the correct environment variables to
40 * allow Drupal to find the configuration file.
41 *
42 * If no site is specified with the -l / --uri options, Drush will assume the
43 * site is 'default', which mimics Drupal's behaviour.
44 *
45 * If you want to avoid this behaviour, it is recommended that you use the
46 * DRUSH_BOOTSTRAP_DRUPAL_ROOT bootstrap phase instead.
47 *
48 * Any code that needs to modify or interact with a specific Drupal site's
49 * settings.php file should bootstrap to this phase.
50 */
51 define('DRUSH_BOOTSTRAP_DRUPAL_SITE', 2);
52
53 /**
54 * Load the settings from the Drupal sites directory.
55 *
56 * This phase is analagous to the DRUPAL_BOOTSTRAP_CONFIGURATION bootstrap phase in Drupal
57 * itself, and this is also the first step where Drupal specific code is included.
58 *
59 * This phase is commonly used for code that interacts with the Drupal install API,
60 * as both install.php and update.php start at this phase.
61 */
62 define('DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION', 3);
63
64 /**
65 * Connect to the Drupal database using the database credentials loaded
66 * during the previous bootstrap phase.
67 *
68 * This phase is analogous to the DRUPAL_BOOTSTRAP_DATABASE bootstrap phase in
69 * Drupal.
70 *
71 * Any code that needs to interact with the Drupal database API needs to
72 * be bootstrapped to at least this phase.
73 */
74 define('DRUSH_BOOTSTRAP_DRUPAL_DATABASE', 4);
75
76 /**
77 * Fully initialize Drupal.
78 *
79 * This is the default bootstrap phase all commands will try to reach,
80 * unless otherwise specified.
81 * This is analogous to the DRUPAL_BOOTSTRAP_FULL bootstrap phase in
82 * Drupal.
83 *
84 * Any code that interacts with the general Drupal API should be
85 * bootstrapped to this phase.
86 */
87 define('DRUSH_BOOTSTRAP_DRUPAL_FULL', 5);
88
89 /**
90 * Log in to the initialiased Drupal site.
91 *
92 * This bootstrap phase is used after the site has been
93 * fully bootstrapped.
94 *
95 * This phase will log you in to the drupal site with the username
96 * or user ID specified by the --user/ -u option.
97 *
98 * Use this bootstrap phase for your command if you need to have access
99 * to information for a specific user, such as listing nodes that might
100 * be different based on who is logged in.
101 */
102 define('DRUSH_BOOTSTRAP_DRUPAL_LOGIN', 6);
103
104 /**
105 * Supported version of Console Table. This is displayed in the manual install help.
106 */
107 define('DRUSH_TABLE_VERSION', '1.1.3');
108
109 /**
110 * URL for automatic file download for supported version of Console Table.
111 */
112 define('DRUSH_TABLE_URL', 'http://cvs.php.net/viewvc.cgi/pear/Console_Table/Table.php?revision=1.28&view=co');
113
114 /**
115 * Helper function listing phases.
116 *
117 * For commands that need to iterate through the phases, such as help
118 */
119 function _drush_bootstrap_phases($function_names = FALSE) {
120 static $functions = array(
121 DRUSH_BOOTSTRAP_DRUSH => '_drush_bootstrap_drush',
122 DRUSH_BOOTSTRAP_DRUPAL_ROOT => '_drush_bootstrap_drupal_root',
123 DRUSH_BOOTSTRAP_DRUPAL_SITE => '_drush_bootstrap_drupal_site',
124 DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION => '_drush_bootstrap_drupal_configuration',
125 DRUSH_BOOTSTRAP_DRUPAL_DATABASE => '_drush_bootstrap_drupal_database',
126 DRUSH_BOOTSTRAP_DRUPAL_FULL => '_drush_bootstrap_drupal_full',
127 DRUSH_BOOTSTRAP_DRUPAL_LOGIN => '_drush_bootstrap_drupal_login');
128 static $phases;
129 if ($function_names) {
130 return $functions;
131 }
132 if (!$phases) {
133 $phases = array_keys($functions);
134 }
135 return $phases;
136 }
137
138 /**
139 * @} End of Drush bootstrap phases.
140 */
141
142 /**
143 * Bootstrap Drush to the desired phase.
144 *
145 * This function will sequentially bootstrap each
146 * lower phase up to the phase that has been requested.
147 *
148 * @param phase
149 * The bootstrap phase to bootstrap to.
150 * Any of the following constants :
151 * DRUSH_BOOTSTRAP_DRUSH = Only Drush.
152 * DRUSH_BOOTSTRAP_DRUPAL_ROOT = Find a valid Drupal root.
153 * DRUSH_BOOTSTRAP_DRUPAL_SITE = Find a valid Drupal site.
154 * DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION = Load the site's settings.
155 * DRUSH_BOOTSTRAP_DRUPAL_DATABASE = Initialize the database.
156 * DRUSH_BOOTSTRAP_DRUPAL_FULL = Initialize Drupal fully.
157 * DRUSH_BOOTSTRAP_DRUPAL_LOGIN = Log into Drupal with a valid user.
158 */
159 function drush_bootstrap($phase) {
160 static $phases;
161 if (!$phases) {
162 $phases = _drush_bootstrap_phases(TRUE);
163 }
164 static $phase_index = 0;
165
166 drush_set_context('DRUSH_BOOTSTRAPPING', TRUE);
167 while ($phase >= $phase_index && isset($phases[$phase_index])) {
168 if (drush_bootstrap_validate($phase_index)) {
169 $current_phase = $phases[$phase_index];
170 if (function_exists($current_phase) && !drush_get_error()) {
171 drush_log(dt("Drush bootstrap phase : !function()", array('!function' => $current_phase)), 'bootstrap');
172 $current_phase();
173 }
174 drush_set_context('DRUSH_BOOTSTRAP_PHASE', $phase_index);
175 }
176 else {
177 $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS', array());
178 foreach ($errors as $code => $message) {
179 drush_set_error($code, $message);
180 }
181 }
182 unset($phases[$phase_index++]);
183 }
184 drush_set_context('DRUSH_BOOTSTRAPPING', FALSE);
185
186 return !drush_get_error();
187 }
188
189 /**
190 * Validate whether a bootstrap phases can be reached.
191 *
192 * This function will validate the settings that will be used
193 * during the actual bootstrap process, and allow commands to
194 * progressively bootstrap to the highest level that can be reached.
195 *
196 * This function will only run the validation function once, and
197 * store the result from that execution in a local static. This avoids
198 * validating phases multiple times.
199 *
200 * @param phase
201 * The bootstrap phase to validate to.
202 * Any of the following constants :
203 * DRUSH_BOOTSTRAP_DRUSH = Only Drush.
204 * DRUSH_BOOTSTRAP_DRUPAL_ROOT = Find a valid Drupal root.
205 * DRUSH_BOOTSTRAP_DRUPAL_SITE = Find a valid Drupal site.
206 * DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION = Load the site's settings.
207 * DRUSH_BOOTSTRAP_DRUPAL_DATABASE = Initialize the database.
208 * DRUSH_BOOTSTRAP_DRUPAL_FULL = Initialize Drupal fully.
209 * DRUSH_BOOTSTRAP_DRUPAL_LOGIN = Log into Drupal with a valid user.
210 *
211 * @return
212 * True if bootstrap is possible, False if the validation failed.
213 *
214 */
215 function drush_bootstrap_validate($phase) {
216 static $phases;
217 static $result_cache = array();
218 if (!$phases) {
219 $phases = _drush_bootstrap_phases(TRUE);
220 }
221 static $phase_index = 0;
222 if (!array_key_exists($phase, $result_cache)) {
223 drush_set_context('DRUSH_BOOTSTRAP_ERRORS', array());
224 drush_set_context('DRUSH_BOOTSTRAP_VALUES', array());
225
226 while ($phase >= $phase_index && isset($phases[$phase_index])) {
227 $current_phase = $phases[$phase_index] . '_validate';
228 if (function_exists($current_phase)) {
229 $result_cache[$phase_index] = $current_phase();
230 }
231 else {
232 $result_cache[$phase_index] = TRUE;
233 }
234 drush_set_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', $phase_index);
235 unset($phases[$phase_index++]);
236 }
237 }
238 return $result_cache[$phase];
239 }
240
241 /**
242 * Bootstrap to the highest level possible, without triggering any errors.
243 */
244 function drush_bootstrap_max() {
245 $phases = _drush_bootstrap_phases();
246 $phase_index = DRUSH_BOOTSTRAP_DRUSH;
247
248 // Try to bootstrap to the maximum possible level, without generating errors
249 foreach ($phases as $phase_index) {
250 if (drush_bootstrap_validate($phase_index)) {
251 if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
252 drush_bootstrap($phase_index);
253 }
254 }
255 else {
256 break;
257 }
258 }
259
260 return $phase_index;
261 }
262
263
264 /**
265 * Helper function to collect any errors that occur during the bootstrap process.
266 * Always returns FALSE, for convenience.
267 */
268 function drush_bootstrap_error($code, $message = null) {
269 $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS');
270 $errors[$code] = $message;
271 drush_set_context('DRUSH_BOOTSTRAP_ERRORS', $errors);
272 return FALSE;
273 }
274
275 /**
276 * Log PHP errors to the Drush log. This is in effect until Drupal's error
277 * handler takes over.
278 */
279 function drush_error_handler($errno, $message, $filename, $line, $context) {
280 // If the @ error suppression operator was used, error_reporting will have
281 // been temporarily set to 0.
282 if (error_reporting() == 0) {
283 return;
284 }
285
286 if ($errno & (E_ALL)) {
287 // By default we log notices.
288 $type = 'notice';
289
290 // Bitmask value that constitutes an error needing to be logged.
291 $error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR;
292 if ($errno & $error) {
293 $type = 'error';
294 }
295
296 // Bitmask value that constitutes a warning being logged.
297 $warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
298 if ($errno & $warning) {
299 $type = 'warning';
300 }
301
302 drush_log($message, $type);
303
304 return TRUE;
305 }
306 }
307
308 /**
309 * Helper function to store any context settings that are being validated.
310 */
311 function drush_bootstrap_value($context, $value = null) {
312 $values =& drush_get_context('DRUSH_BOOTSTRAP_VALUES', array());
313
314 if (!is_null($value)) {
315 $values[$context] = $value;
316 }
317
318 if (array_key_exists($context, $values)) {
319 return $values[$context];
320 }
321
322 return null;
323 }
324
325 /**
326 * Validate initial Drush bootstrap phase.
327 */
328 function _drush_bootstrap_drush_validate() {
329 // Test safe mode is off.
330 if (ini_get('safe_mode')) {
331 return drush_bootstrap_error('DRUSH_SAFE_MODE', dt('PHP safe mode is activated. Drush requires that safe mode is disabled.'));
332 }
333
334 // Attempt to download Console Table, via various methods.
335 $tablefile = DRUSH_BASE_PATH . '/includes/table.inc';
336 if (!file_exists($tablefile)) {
337 if ($file = @file_get_contents(DRUSH_TABLE_URL)) {
338 @file_put_contents($tablefile, $file);
339 }
340 if (!file_exists($tablefile)) {
341 drush_shell_exec("wget -q -O $tablefile " . DRUSH_TABLE_URL);
342 if (!file_exists($tablefile)) {
343 drush_shell_exec("curl -s -o $tablefile " . DRUSH_TABLE_URL);
344 if (!file_exists($tablefile)) {
345 return drush_bootstrap_error('DRUSH_TABLES_INC', dt("Drush needs a copy of the PEAR Console_Table library in order to function, and the attempt to download this file automatically failed. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract it, and copy the Table.php file into Drush's directory as !tablefile.", array('!version' => DRUSH_TABLE_VERSION ,'!tablefile' => $tablefile)));
346 }
347 }
348 }
349 }
350 require_once $tablefile;
351
352 return TRUE;
353 }
354
355 /**
356 * Initial Drush bootstrap phase.
357 *
358 * During the initialization of Drush,
359 * this is the first step where all we are
360 * aware of is Drush itself.
361 *
362 * In this step we will register the shutdown function,
363 * parse the command line arguments and store them in their
364 * related contexts.
365 *
366 * Configuration files (drushrc.php) that are
367 * a) Specified on the command line
368 * b) Stored in the root directory of drush.php
369 * c) Stored in the home directory of the system user.
370 *
371 * Additionally the DRUSH_QUIET and DRUSH_BACKEND contexts,
372 * will be evaluated now, as they need to be set very early in
373 * the execution flow to be able to take affect/
374 */
375 function _drush_bootstrap_drush() {
376 // The bootstrap can fail silently, so we catch that in a shutdown function.
377 register_shutdown_function('drush_shutdown');
378
379 // Attempt to set the screen width to the current screen width.
380 // This will only work if the user has exported COLUMNS in his session.
381 if (!($columns = getenv('COLUMNS'))) {
382 $columns = 80;
383 }
384 drush_set_context('DRUSH_COLUMNS', $columns);
385
386 // parse the command line arguments.
387 drush_parse_args();
388
389 // Load a custom config specified with the --config option.
390 drush_load_config('custom');
391
392 // Load a drushrc.php file in the drush.php's directory.
393 drush_load_config('drush');
394
395 // Load a drushrc.php file in the $ETC_PREFIX/etc/drush directory.
396 drush_load_config('system');
397
398 // Load a drushrc.php file in the ~/.drush directory.
399 drush_load_config('user');
400
401 // Process the site alias that specifies which instance
402 // of drush (local or remote) this command will operate on.
403 // We must do this after we load our config files (so that
404 // site aliases are available), but before the rest
405 // of the drush and drupal root bootstrap phases are
406 // done, since site aliases may set option values that
407 // affect these phases.
408 // TODO: Note that this function will call drush_locate_root
409 // (from within _drush_sitealias_find_record_for_local_site),
410 // and drush_locate_root will be called again when bootstrapping
411 // the drupal root below. Is there a good way to refactor this
412 // so that we do not need to search for the root twice?
413 drush_sitealias_check_arg();
414
415 $backend = drush_set_context('DRUSH_BACKEND', drush_get_option(array('b', 'backend')));
416
417 if ($backend) {
418 // Load options passed as a JSON encoded string through STDIN.
419 $stdin_options = _drush_backend_get_stdin();
420 if (is_array($stdin_options)) {
421 drush_set_context('stdin', $stdin_options);
422 }
423 }
424
425 // Pipe implies quiet.
426 $quiet = drush_set_context('DRUSH_QUIET', drush_get_option(array('q', 'quiet', 'p', 'pipe')));
427
428 drush_set_context('DRUSH_PIPE', drush_get_option(array('p', 'pipe')));
429
430 // When running in backend mode, all output is buffered, and returned
431 // as a property of a JSON encoded associative array.
432 if ($backend || $quiet) {
433 ob_start();
434 }
435
436 // Debug implies verbose
437 drush_set_context('DRUSH_VERBOSE', drush_get_option(array('v', 'verbose', 'd', 'debug'), FALSE));
438 drush_set_context('DRUSH_DEBUG', drush_get_option(array('d', 'debug')));
439
440
441 // Backend implies affirmative
442 drush_set_context('DRUSH_AFFIRMATIVE', drush_get_option(array('y', 'yes', 'b', 'backend'), FALSE));
443 drush_set_context('DRUSH_SIMULATE', drush_get_option(array('s', 'simulate'), FALSE));
444
445 // Suppress colored logging if --nocolor option is explicitly given or if
446 // terminal does not support it.
447 $nocolor = (drush_get_option(array('n', 'nocolor'), FALSE) || !getenv('TERM'));
448 if (!$nocolor) {
449 // Check for colorless terminal.
450 $colors = exec('tput colors 2>&1');
451 $nocolor = !($colors === FALSE || (is_numeric($colors) && $colors >= 3));
452 }
453 drush_set_context('DRUSH_NOCOLOR', $nocolor);
454
455 // Find any command files that are available during this bootstrap phase.
456 _drush_find_commandfiles(DRUSH_BOOTSTRAP_DRUSH);
457 }
458
459 /**
460 * Validate the DRUSH_BOOTSTRAP_DRUPAL_ROOT phase.
461 *
462 * In this function, we will check if a valid Drupal directory is available.
463 * We also determine the value that will be stored in the DRUSH_DRUPAL_ROOT
464 * context and DRUPAL_ROOT constant if it is considered a valid option.
465 */
466 function _drush_bootstrap_drupal_root_validate() {
467 $drupal_root = drush_get_option(array('r', 'root'), drush_locate_root());
468
469 if (empty($drupal_root)) {
470 return drush_bootstrap_error('DRUSH_NO_DRUPAL_ROOT', dt("A Drupal installation directory could not be found"));
471 }
472 if (!drush_valid_drupal_root($drupal_root)) {
473 return drush_bootstrap_error('DRUSH_INVALID_DRUPAL_ROOT', dt("The directory !drupal_root does not contain a valid Drupal installation", array('!drupal_root' => $drupal_root)));
474 }
475
476 drush_bootstrap_value('drupal_root', $drupal_root);
477
478 return TRUE;
479 }
480
481 /**
482 * Bootstrap Drush with a valid Drupal Directory.
483 *
484 * In this function, the pwd will be moved to the root
485 * of the Drupal installation.
486 *
487 * The DRUSH_DRUPAL_ROOT context and the DRUPAL_ROOT constant are
488 * populated from the value that we determined during the validation phase.
489 *
490 * We also now load the drushrc.php for this specific platform.
491 * We can now include files from the Drupal Tree, and figure
492 * out more context about the platform, such as the version of Drupal.
493 */
494 function _drush_bootstrap_drupal_root() {
495 $drupal_root = drush_set_context('DRUSH_DRUPAL_ROOT', drush_bootstrap_value('drupal_root'));
496 define('DRUPAL_ROOT', $drupal_root);
497
498 // Save original working dir case some command wants it.
499 drush_set_context('DRUSH_OLDCWD', getcwd());
500
501 chdir($drupal_root);
502 drush_load_config('drupal');
503 require_once(DRUSH_DRUPAL_BOOTSTRAP);
504 $version = drush_set_context('DRUSH_DRUPAL_VERSION', drush_drupal_version());
505 $major_version = drush_set_context('DRUSH_DRUPAL_MAJOR_VERSION', drush_drupal_major_version());
506
507 drush_log(dt("Initialized Drupal !version root directory at !drupal_root", array("!version" => $version, '!drupal_root' => $drupal_root)));
508 }
509
510 /**
511 * VALIDATE the DRUSH_BOOTSTRAP_DRUPAL_SITE phase.
512 *
513 * In this function we determine the URL used for the command,
514 * and check for a valid settings.php file.
515 *
516 * To do this, we need to set up the $_SERVER environment variable,
517 * to allow us to use conf_path to determine what Drupal will load
518 * as a configuration file.
519 */
520 function _drush_bootstrap_drupal_site_validate() {
521 $site_path = drush_site_path();
522 $elements = explode('/', $site_path);
523 $current = array_pop($elements);
524 if (!$current) {
525 $current = 'default';
526 }
527 $uri = 'http://'. $current;
528
529 $drush_uri = drush_bootstrap_value('drush_uri', drush_get_option(array('l', 'uri'), $uri));
530
531 // Fake the necessary HTTP headers that Drupal needs:
532 if ($drush_uri) {
533 $drupal_base_url = parse_url($drush_uri);
534 // If there's no url scheme set, add http:// and re-parse the url
535 // so the host and path values are set accurately.
536 if (!array_key_exists('scheme', $drupal_base_url)) {
537 $drush_uri = 'http://' . $drush_uri;
538 $drupal_base_url = parse_url($drush_uri);
539 }
540 // Fill in defaults.
541 $drupal_base_url += array(
542 'path' => NULL,
543 'host' => NULL,
544 );
545 $_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
546 $_SERVER['PHP_SELF'] = $drupal_base_url['path'] . '/index.php';
547 }
548 else {
549 $_SERVER['HTTP_HOST'] = 'default';
550 $_SERVER['PHP_SELF'] = '/index.php';
551 }
552
553 $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $_SERVER['PHP_SELF'];
554 $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
555 $_SERVER['REQUEST_METHOD'] = NULL;
556 $_SERVER['SERVER_SOFTWARE'] = NULL;
557 $_SERVER['HTTP_USER_AGENT'] = NULL;
558
559 $site = drush_bootstrap_value('site', $_SERVER['HTTP_HOST']);
560
561 $conf_path = drush_bootstrap_value('conf_path', conf_path(TRUE, TRUE));
562 $conf_file = "./$conf_path/settings.php";
563 if (!file_exists($conf_file)) {
564 return drush_bootstrap_error('DRUPAL_SITE_SETTINGS_NOT_FOUND', dt("Could not find a Drupal settings.php file at !file.",
565 array('!file' => $conf_file)));
566 }
567
568 return TRUE;
569 }
570
571 /**
572 * Called by _drush_bootstrap_drupal_site to do the main work
573 * of the drush drupal site bootstrap.
574 */
575 function _drush_bootstrap_do_drupal_site() {
576 $drush_uri = drush_set_context('DRUSH_URI', drush_bootstrap_value('drush_uri'));
577 $site = drush_set_context('DRUSH_DRUPAL_SITE', drush_bootstrap_value('site'));
578 $conf_path = drush_set_context('DRUSH_DRUPAL_SITE_ROOT', drush_bootstrap_value('conf_path'));
579
580 // Find any command files that are available during this bootstrap phase.
581 _drush_find_commandfiles(DRUSH_BOOTSTRAP_DRUPAL_SITE);
582
583 drush_log(dt("Initialized Drupal site !site at !site_root", array('!site' => $site, '!site_root' => $conf_path)));
584 drush_load_config('site');
585 }
586
587 /**
588 * Initialize a site on the Drupal root.
589 *
590 * We now set various contexts that we determined and confirmed to be valid.
591 * Additionally we load an optional drushrc.php file in the site directory.
592 */
593 function _drush_bootstrap_drupal_site() {
594 _drush_bootstrap_do_drupal_site();
595 _drush_bootstrap_redo_drupal_site();
596 }
597
598 /**
599 * Re-do the drupal site bootstrap (and possibly the
600 * drupal root bootstrap) if a site alias was processed
601 * after the site bootstrap phase completed. This will
602 * happen when processing "drush sitealias command" for
603 * a site alias defined in a drushrc.php file in the
604 * default site's drush configuration directory.
605 */
606 function _drush_bootstrap_redo_drupal_site() {
607 // If drush_load_config defined a site alias that did not
608 // exist before, then sitealias check arg might now match
609 // against one of those aliases.
610 if (drush_sitealias_check_arg() === TRUE) {
611 $remote_host = drush_get_option('remote-host');
612 if (!isset($remote_host)) {
613 // Check to see if the drupal root changed.
614 // If it has, we will set remote-host to cause
615 // this command to be executed via the backend invoke
616 // process.
617 $sitealias_drupal_root = drush_get_option(array('r', 'root'));
618 if (($sitealias_drupal_root != null) && (DRUPAL_ROOT != $sitealias_drupal_root)) {
619 drush_set_option('remote-host', 'localhost');
620 }
621 else {
622 // If we set an alias, then we need to bootstrap the
623 // drupal site once again. It is possible to re-bootstrap
624 // the site at this point because settings.php has not
625 // been included yet.
626 drush_log(dt("Re-bootstrap drupal site."));
627 _drush_bootstrap_drupal_site_validate();
628 _drush_bootstrap_do_drupal_site();
629 }
630 }
631 }
632 }
633
634 /**
635 * Initialize and load the Drupal configuration files.
636 *
637 * We process and store a normalized set of database credentials
638 * from the loaded configuration file, so we can validate them
639 * and access them easily in the future.
640 */
641 function _drush_bootstrap_drupal_configuration() {
642 global $conf, $drush_conf_override;
643
644 drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
645
646 // Overriding the $conf array from drupal CONFIGURATION bootstrap with the
647 // overrides we collected on the loaded config files on DRUSH_BOOTSTRAP_DRUSH
648 $conf = is_array($conf) ? array_merge($conf, $drush_conf_override) : $drush_conf_override;
649
650 // Populate the DRUSH_DB_CREDENTIALS with the fields loaded from the configuration.
651 $creds = array();
652 switch (drush_drupal_major_version()) {
653 case 5:
654 case 6:
655 if (isset($GLOBALS['db_url'])) {
656 $url = $GLOBALS['db_url'];
657 if (is_array($url)) {
658 $url = $url['default'];
659 }
660 $parts = parse_url($url);
661 $parts += array('pass' => '', 'port' => '');
662 $creds['driver'] = $parts['scheme'];
663 $creds['user'] = urldecode($parts['user']);
664 $creds['host'] = $parts['host'];
665 $creds['port'] = $parts['port'];
666 $creds['pass'] = urldecode($parts['pass']);
667 $creds['name'] = trim($parts['path'], '/');
668 }
669 break;
670 case 7:
671 if (isset($GLOBALS['databases']['default']['default'])) {
672 $conn = $GLOBALS['databases']['default']['default'];
673 $creds['driver'] = $conn['driver'];
674 $creds['user'] = $conn['username'];
675 $creds['host'] = $conn['host'];
676 $creds['port'] = $conn['port'];
677 $creds['name'] = $conn['database'];
678 $creds['pass'] = $conn['password'];
679 }
680 break;
681 }
682
683 drush_set_context('DRUSH_DB_CREDENTIALS', $creds);
684 }
685
686 /**
687 * Validate the DRUSH_BOOTSTRAP_DRUPAL_DATABASE phase
688 *
689 * Attempt to making a working database connection using the
690 * database credentials that were loaded during the previous
691 * phase.
692 */
693 function _drush_bootstrap_drupal_database_validate() {
694 if (!drush_valid_db_credentials()) {
695 return drush_bootstrap_error("DRUSH_DRUPAL_DB_ERROR");
696 }
697 return TRUE;
698 }
699
700 /**
701 * Boostrap the Drupal database.
702 */
703 function _drush_bootstrap_drupal_database() {
704 drush_log(dt("Successfully connected to the Drupal database."), 'bootstrap');
705 drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
706 }
707
708 /**
709 * Attempt to load the full Drupal system.
710 */
711 function _drush_bootstrap_drupal_full() {
712 ob_start();
713 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
714 ob_end_clean();
715 _drush_log_drupal_messages();
716 // Find any command files that are available during this bootstrap phase.
717 _drush_find_commandfiles(DRUSH_BOOTSTRAP_DRUPAL_FULL);
718 }
719
720 /**
721 * Log into the bootstrapped Drupal site with a specific
722 * username or user id.
723 */
724 function _drush_bootstrap_drupal_login() {
725 $drush_user = drush_set_context('DRUSH_USER', drush_get_option(array('u', 'user'), 0));
726
727 drush_drupal_login($drush_user);
728 _drush_log_drupal_messages();
729 }
730
731
732 /**
733 * Returns the current working directory.
734 *
735 * TODO: Could cache result, but it isn't really expensive.
736 */
737 function drush_cwd() {
738 // We use PWD if available because getcwd() resolves symlinks, which
739 // could take us outside of the Drupal root, making it impossible to find.
740 // $_SERVER['PWD'] isn't set on windows and generates a Notice.
741 $path = isset($_SERVER['PWD'])?$_SERVER['PWD']:'';
742 if (empty($path)) {
743 $path = getcwd();
744 }
745
746 // Convert windows paths.
747 $path = _drush_convert_path($path);
748
749 return $path;
750 }
751
752 /**
753 * Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
754 * Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
755 * proper drive path, still with Unix slashes (c:/dir1).
756 */
757 function _drush_convert_path($path) {
758 $path = str_replace('\\','/', $path);
759 $path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
760
761 return $path;
762 }
763
764 /**
765 * Returns parent directory.
766 *
767 * @param string
768 * Path to start from.
769 *
770 * @return string
771 * Parent path of given path.
772 */
773 function _drush_shift_path_up($path) {
774 if (empty($path)) {
775 return FALSE;
776 }
777 $path = explode('/', $path);
778 // Move one directory up.
779 array_pop($path);
780 return implode('/', $path);
781 }
782
783 /**
784 * Like Drupal conf_path, but searching from beneath.
785 * Allows proper site uri detection in site sub-directories.
786 *
787 * Essentially looks for a settings.php file.
788 *
789 * @param string
790 * Search starting path. Defaults to current working directory.
791 *
792 * @return
793 * Current site path (folder containing settings.php) or FALSE if not found.
794 */
795 function drush_site_path($path = NULL) {
796 static $site_path;
797
798 if (!isset($site_path)) {
799 $site_path = FALSE;
800
801 $path = empty($path) ? drush_cwd() : $path;
802 // Check the current path.
803 if (file_exists($path . '/settings.php')) {
804 $site_path = $path;
805 }
806 else {
807 // Move up dir by dir and check each.
808 while ($path = _drush_shift_path_up($path)) {
809 if (file_exists($path . '/settings.php')) {
810 $site_path = $path;
811 break;
812 }
813 }
814 }
815
816 $site_root = drush_locate_root();
817 if (file_exists($site_root . '/sites/sites.php')) {
818 $sites = array();
819 // This will overwrite $sites with the desired mappings.
820 include($site_root . '/sites/sites.php');
821 // We do a reverse lookup here to determine the URL given the site key.
822 if ($match = array_search($site_path, $sites)) {
823 $site_path = $match;
824 }
825 }
826
827 // Last resort: try from site root
828 if (!$site_path) {
829 if ($site_root) {
830 if (file_exists($site_root . '/sites/default/settings.php')) {
831 $site_path = $site_root . '/sites/default';
832 }
833 }
834 }
835 }
836
837 return $site_path;
838 }
839
840 /**
841 * Exhaustive depth-first search to try and locate the Drupal root directory.
842 * This makes it possible to run drush from a subdirectory of the drupal root.
843 *
844 * @param
845 * Search start path. Defaults to current working directory.
846 */
847 function drush_locate_root($path = NULL) {
848 $drupal_root = FALSE;
849
850 $path = empty($path) ? drush_cwd() : $path;
851 // Check the start path.
852 if (drush_valid_drupal_root($path)) {
853 $drupal_root = $path;
854 }
855 else {
856 // Move up dir by dir and check each.
857 while ($path = _drush_shift_path_up($path)) {
858 if (drush_valid_drupal_root($path)) {
859 $drupal_root = $path;
860 break;
861 }
862 }
863 }
864
865 return $drupal_root;
866 }
867
868 /**
869 * Checks whether given path qualifies as a Drupal root.
870 *
871 * @param string
872 * Path to check.
873 *
874 * @return boolean
875 * True if given path seems to be a Drupal root, otherwise false.
876 */
877 function drush_valid_drupal_root($path) {
878 return !empty($path) && is_dir($path) && file_exists($path . '/' . DRUSH_DRUPAL_BOOTSTRAP);
879 }
880
881 /**
882 * Tests the currently loaded database credentials to ensure a database connection can be made.
883 */
884 function drush_valid_db_credentials() {
885 if (class_exists('PDO')) {
886 $creds = drush_get_context('DRUSH_DB_CREDENTIALS');
887
888 $type = ($creds['driver'] == 'mysqli') ? 'mysql' : $creds['driver'];
889
890 if (!in_array($type, PDO::getAvailableDrivers())) {
891 drush_log(dt('PDO support available, but the !type driver has not been installed. Assuming success.', array('!type' => $type)), 'bootstrap');
892 return TRUE;
893 }
894
895 $constr = sprintf("%s:dbname=%s;host=%s", $type, $creds['name'], $creds['host']);
896 if (!empty($creds['port'])) {
897 $constr .= sprintf(";port=%d", $creds['port']);
898 }
899
900 try {
901 $db = new PDO($constr, $creds['user'], $creds['pass']);
902 $db = null;
903 return TRUE;
904 }
905 catch (PDOException $e) {
906 // We do not use drush_set_error here , because it's up to the calling function
907 // to determine whether or not this is an error or a warning.
908 drush_log($e->getMessage(), 'warning');
909 return FALSE;
910 }
911 }
912 else {
913 drush_log(dt('PDO support not available. Could not pre-validate database credentials. Assuming success'), 'bootstrap');
914 return TRUE;
915 }
916 }
917
918 // Copied from run-tests.sh
919 function drush_find_php() {
920 // Determine location of php command automatically, unless a command line argument is supplied.
921 if (!$php = drush_get_option('php')) {
922 if (!empty($_ENV['_'])) {
923 // '_' is an environment variable set by the shell. It contains the command that was executed.
924 $php = $_ENV['_'];
925 }
926 elseif (!empty($_ENV['SUDO_COMMAND'])) {
927 // 'SUDO_COMMAND' is an environment variable set by the sudo program.
928 // Extract only the PHP interpreter, not the rest of the command.
929 list($php, ) = explode(' ', $_ENV['SUDO_COMMAND'], 2);
930 }
931 else {
932 drush_set_error('DRUSH_PHP_PATH_NOT_FOUND', dt('Unable to automatically determine the path to the PHP interpreter. Please supply the --php argument.'));
933 }
934 }
935 return $php;
936 }
937
938 /**
939 * Get module information for all installed modules. Wrapper for _drush_get_modules().
940 *
941 * @return
942 * An array containing module info for all installed modules or FALSE on error.
943 */
944 function drush_get_modules() {
945 if(drush_include_engine('drupal', 'environment')){
946 return _drush_get_modules();
947 }
948 else {
949 return drush_set_error('DRUSH_CORE', dt('Drush was unable to load module information.'));
950 }
951 }
952
953 /**
954 * Get theme information for all installed themes. Wrapper for _drush_get_themes().
955 *
956 * @return
957 * An array containing theme info for all installed themes or FALSE on error.
958 */
959 function drush_get_themes() {
960 if(drush_include_engine('drupal', 'environment')){
961 return _drush_get_themes();
962 }
963 else {
964 return drush_set_error('DRUSH_CORE', dt('Drush was unable to load theme information.'));
965 }
966 }
967
968 /**
969 * Make a determination whether or not the given
970 * host is local or not.
971 *
972 * @param host
973 * A hostname, 'localhost' or '127.0.0.1'.
974 * @return
975 * True if the host is local.
976 */
977 function drush_is_local_host($host) {
978 // @TODO: Check DNS against local interface settings?
979 // (Maybe not portable, maybe too slow?)
980 // @TODO: Allow user to specify host names in a configuration
981 // option (e.g. $options['local-hosts'] = array('myhostname1.com', 'myhostname2.com'); )
982 return ($host == 'localhost') || ($host == '127.0.0.1') || (file_exists(drush_get_context('DRUSH_DRUPAL_ROOT') . "/sites/$host"));
983 }

  ViewVC Help
Powered by ViewVC 1.1.2