-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
preflight.inc
696 lines (612 loc) · 27.1 KB
/
preflight.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
<?php
/**
* @file
* Preflight, postflight and shutdown code.
*/
use Drush\Log\LogLevel;
/**
* Prepare Drush for preflight.
*
* Runs before drush_main().
*
* @see drush_main()
* @see drush.php
*/
function drush_preflight_prepare() {
define('DRUSH_BASE_PATH', dirname(dirname(__FILE__)));
// Local means that autoload.php is inside of Drush. That is, Drush is its own Composer project.
// Global means autoload.php is outside of Drush. That is, Drush is a dependency of a bigger project.
$local_vendor_path = DRUSH_BASE_PATH . '/vendor/autoload.php';
$global_vendor_path = DRUSH_BASE_PATH . '/../../../vendor/autoload.php';
// Check for a local composer install or a global composer install. Vendor dirs are in different spots).
if (file_exists($local_vendor_path)) {
$vendor_path = $local_vendor_path;
}
elseif (file_exists($global_vendor_path)) {
$vendor_path = $global_vendor_path;
}
else {
$msg = "Unable to load autoload.php. Drush now requires Composer in order to install its dependencies and autoload classes. Please see README.md\n";
fwrite(STDERR, $msg);
return FALSE;
}
$classloader = require $vendor_path;
require_once DRUSH_BASE_PATH . '/includes/bootstrap.inc';
require_once DRUSH_BASE_PATH . '/includes/environment.inc';
require_once DRUSH_BASE_PATH . '/includes/command.inc';
require_once DRUSH_BASE_PATH . '/includes/drush.inc';
require_once DRUSH_BASE_PATH . '/includes/engines.inc';
require_once DRUSH_BASE_PATH . '/includes/backend.inc';
require_once DRUSH_BASE_PATH . '/includes/batch.inc';
require_once DRUSH_BASE_PATH . '/includes/context.inc';
require_once DRUSH_BASE_PATH . '/includes/sitealias.inc';
require_once DRUSH_BASE_PATH . '/includes/exec.inc';
require_once DRUSH_BASE_PATH . '/includes/drupal.inc';
require_once DRUSH_BASE_PATH . '/includes/output.inc';
require_once DRUSH_BASE_PATH . '/includes/cache.inc';
require_once DRUSH_BASE_PATH . '/includes/filesystem.inc';
require_once DRUSH_BASE_PATH . '/includes/dbtng.inc';
// Stash our vendor path and classloader.
drush_set_context('DRUSH_VENDOR_PATH', dirname(realpath($vendor_path)));
drush_set_context('DRUSH_CLASSLOADER', $classloader);
// Can't log until we have a logger, so we'll create this ASAP.
_drush_create_default_logger();
// Terminate immediately unless invoked as a command line script
if (!drush_verify_cli()) {
return drush_set_error('DRUSH_REQUIREMENTS_ERROR', dt('Drush is designed to run via the command line.'));
}
// Check supported version of PHP.
// Note: If this is adjusted, check other code that compares
// PHP_VERSION, such as drush_json_encode(), runserver/runserver.drush.inc, and also
// adjust _drush_environment_check_php_ini() and the php_prohibited_options
// list in the drush script. See http://drupal.org/node/1748228
define('DRUSH_MINIMUM_PHP', '5.3.0');
if (version_compare(phpversion(), DRUSH_MINIMUM_PHP) < 0 && !getenv('DRUSH_NO_MIN_PHP')) {
return drush_set_error('DRUSH_REQUIREMENTS_ERROR', dt('Your command line PHP installation is too old. Drush requires at least PHP !version. To suppress this check, set the environment variable DRUSH_NO_MIN_PHP=1', array('!version' => DRUSH_MINIMUM_PHP)));
}
if (!$return = _drush_environment_check_php_ini()) {
return; // An error was logged.
}
$drush_info = drush_read_drush_info();
define('DRUSH_VERSION', $drush_info['drush_version']);
$version_parts = explode('.', DRUSH_VERSION);
define('DRUSH_MAJOR_VERSION', $version_parts[0]);
define('DRUSH_MINOR_VERSION', $version_parts[1]);
define('DRUSH_REQUEST_TIME', microtime(TRUE));
drush_set_context('argc', $GLOBALS['argc']);
drush_set_context('argv', $GLOBALS['argv']);
// Set an error handler and a shutdown function
set_error_handler('drush_error_handler');
register_shutdown_function('drush_shutdown');
// We need some global options/arguments processed at this early stage.
drush_parse_args();
// Process initial global options such as --debug.
_drush_preflight_global_options();
drush_log(dt("Drush preflight prepare loaded autoloader at !autoloader", array('!autoloader' => realpath($vendor_path))), LogLevel::PREFLIGHT);
}
/**
* During the initialization of Drush, this is the first
* step where we load our configuration and commandfiles,
* and select the site we are going to operate on; however,
* we take no irreversible actions (e.g. site bootstrapping).
* This allows commands that are declared with no bootstrap
* to select a new site root and bootstrap it.
*
* In this step we will register the shutdown function,
* parse the command line arguments and store them in their
* related contexts.
*
* Configuration files (drushrc.php) that are
* a) Specified on the command line
* b) Stored in the root directory of drush.php
* c) Stored in the home directory of the system user.
*
* Additionally the DRUSH_QUIET and DRUSH_BACKEND contexts,
* will be evaluated now, as they need to be set very early in
* the execution flow to be able to take affect.
*
* @return \Drush\Boot\Boot;
*/
function drush_preflight() {
// Create an alias '@none' to represent no Drupal site
_drush_sitealias_cache_alias('@none', array('root' => '', 'uri' => ''));
// Discover terminal width for pretty output.
_drush_preflight_columns();
// Display is tidy now that column width has been handled.
drush_log(dt('Starting Drush preflight.'), LogLevel::PREFLIGHT);
// Statically define a way to call drush again.
define('DRUSH_COMMAND', drush_find_drush());
// prime the CWD cache
drush_cwd();
// Set up base environment for system-wide file locations.
_drush_preflight_base_environment();
// Setup global alias_paths[] in context system.
if (!drush_get_option('local')) {
_drush_preflight_alias_path();
}
if (!drush_get_option('local')) {
// Load a drushrc.php file in the drush.php's directory.
drush_load_config('drush');
// Load a drushrc.php file in the $ETC_PREFIX/etc/drush directory.
drush_load_config('system');
// Load a drushrc.php file at ~/.drushrc.php.
drush_load_config('user');
// Load a drushrc.php file in the ~/.drush directory.
drush_load_config('home.drush');
}
// Load a custom config specified with the --config option.
drush_load_config('custom');
_drush_preflight_global_options();
// Load all the commandfiles findable from any of the
// scopes listed above.
_drush_find_commandfiles_drush();
// Look up the alias identifier that the user wants to use,
// either via an arguement or via 'site-set'.
$target_alias = drush_sitealias_check_arg_and_site_set();
// Process the site alias that specifies which instance
// of Drush (local or remote) this command will operate on.
// We must do this after we load our config files (so that
// site aliases are available), but before the rest of
// Drush preflight and Drupal root bootstrap phase are
// done, since site aliases may set option values that
// affect these phases.
$alias_record = _drush_sitealias_set_context_by_name($target_alias);
// Find the selected site based on --root, --uri or cwd
drush_preflight_root();
// Preflight the selected site, and load any configuration and commandfiles associated with it.
drush_preflight_site();
// Check to see if anything changed during the 'site' preflight
// that might allow us to find our alias record now
if (empty($alias_record)) {
$alias_record = _drush_sitealias_set_context_by_name($target_alias);
// If the site alias settings changed late in the preflight,
// then run the preflight for the root and site contexts again.
if (!empty($alias_record)) {
$remote_host = drush_get_option('remote-host');
if (!isset($remote_host)) {
drush_preflight_root();
drush_preflight_site();
}
}
}
// Fail if we could not find the selected site alias.
if ($target_alias && empty($alias_record)) {
// We will automatically un-set the site-set alias if it could not be found.
// Otherwise, we'd be stuck -- the user would only be able to execute Drush
// commands again after `drush @none site-set @none`, and most folks would
// have a hard time figuring that out.
$site_env = drush_sitealias_site_get();
if ($site_env == $target_alias) {
drush_sitealias_site_clear();
}
return drush_set_error('DRUSH_BOOTSTRAP_NO_ALIAS', dt("Could not find the alias !alias", array('!alias' => $target_alias)));
}
// If applicable swaps in shell alias values.
drush_shell_alias_replace($target_alias);
// Copy global options to their respective contexts
_drush_preflight_global_options();
// Set environment variables based on #env-vars.
drush_set_environment_vars($alias_record);
// Select the bootstrap object and return it.
return drush_select_bootstrap_class();
}
/**
* If --root is provided, set context.
*/
function drush_preflight_root() {
$root = drush_get_option('root');
if (!isset($root)) {
$root = drush_locate_root();
}
if ($root) {
$root = realpath($root);
}
// @todo This context name should not mention Drupal.
// @todo Drupal code should use DRUSH_DRUPAL_ROOT instead of this constant.
drush_set_context('DRUSH_SELECTED_DRUPAL_ROOT', $root);
// Load the config options from Drupal's /drush and sites/all/drush directories,
// even prior to bootstrapping the root.
drush_load_config('drupal');
}
function drush_preflight_site() {
// Load the Drupal site configuration options upfront.
drush_load_config('site');
// Determine URI and set constants/contexts accordingly. Keep this after loading of drupal,site configs.
_drush_preflight_uri();
// If someone set 'uri' in the 'site' context, then copy it
// to the 'process' context (to give it a higher priority
// than the 'cli' and 'alias' contexts) and reset our selected
// site and @self alias.
$uri = drush_get_option('uri');
if ($uri != drush_get_option('uri', $uri, 'site')) {
drush_set_option('uri', drush_get_option('uri', $uri, 'site'));
_drush_preflight_uri();
}
// Create a @self site alias record.
drush_sitealias_create_self_alias();
}
function _drush_preflight_global_options() {
// Debug implies verbose
drush_set_context('DRUSH_VERBOSE', drush_get_option(array('verbose', LogLevel::DEBUG), FALSE));
drush_set_context('DRUSH_DEBUG', drush_get_option(LogLevel::DEBUG));
drush_set_context('DRUSH_SIMULATE', drush_get_option('simulate', FALSE));
// Backend implies affirmative unless negative is explicitly specified
drush_set_context('DRUSH_NEGATIVE', drush_get_option('no', FALSE));
drush_set_context('DRUSH_AFFIRMATIVE', drush_get_option(array('yes', 'pipe'), FALSE) || (drush_get_context('DRUSH_BACKEND') && !drush_get_context('DRUSH_NEGATIVE')));
// Pipe implies quiet.
drush_set_context('DRUSH_QUIET', drush_get_option(array('quiet', 'pipe')));
drush_set_context('DRUSH_PIPE', drush_get_option('pipe'));
// Suppress colored logging if --nocolor option is explicitly given or if
// terminal does not support it.
$nocolor = (drush_get_option('nocolor', FALSE));
if (!$nocolor) {
// Check for colorless terminal. If there is no terminal, then
// 'tput colors 2>&1' will return "tput: No value for $TERM and no -T specified",
// which is not numeric and therefore will put us in no-color mode.
$colors = exec('tput colors 2>&1');
$nocolor = !($colors === FALSE || (is_numeric($colors) && $colors >= 3));
}
drush_set_context('DRUSH_NOCOLOR', $nocolor);
}
/**
* Sets up basic environment that controls where Drush looks for files on a
* system-wide basis. Important to call for "early" functions that need to
* work with unit tests.
*/
function _drush_preflight_base_environment() {
// Copy ETC_PREFIX and SHARE_PREFIX from environment variables if available.
// This alters where we check for server-wide config and alias files.
// Used by unit test suite to provide a clean environment.
if (getenv('ETC_PREFIX')) drush_set_context('ETC_PREFIX', getenv('ETC_PREFIX'));
if (getenv('SHARE_PREFIX')) drush_set_context('SHARE_PREFIX', getenv('SHARE_PREFIX'));
drush_set_context('DOC_PREFIX', DRUSH_BASE_PATH);
if (!file_exists(DRUSH_BASE_PATH . '/README.md') && file_exists(drush_get_context('SHARE_PREFIX', '/usr') . '/share/doc/drush' . '/README.md')) {
drush_set_context('DOC_PREFIX', drush_get_context('SHARE_PREFIX', '/usr') . '/share/doc/drush');
}
$default_prefix_configuration = drush_is_windows() ? getenv('ALLUSERSPROFILE') . '/Drush' : '';
$default_prefix_commandfile = drush_is_windows() ? getenv('ALLUSERSPROFILE') . '/Drush' : '/usr';
$site_wide_configuration_dir = drush_get_context('ETC_PREFIX', $default_prefix_configuration) . '/etc/drush';
$site_wide_commandfile_dir = drush_get_context('SHARE_PREFIX', $default_prefix_commandfile) . '/share/drush/commands';
drush_set_context('DRUSH_SITE_WIDE_CONFIGURATION', $site_wide_configuration_dir);
drush_set_context('DRUSH_SITE_WIDE_COMMANDFILES', $site_wide_commandfile_dir);
$server_home = drush_server_home();
if (isset($server_home)) {
drush_set_context('DRUSH_PER_USER_CONFIGURATION', $server_home . '/.drush');
}
}
/*
* Set the terminal width, used for wrapping table output.
* Normally this is exported using tput in the drush script.
* If this is not present we do an additional check using stty here.
* On Windows in CMD and PowerShell is this exported using mode con.
*/
function _drush_preflight_columns() {
if (!($columns = getenv('COLUMNS'))) {
// Trying to export the columns using stty.
exec('stty size 2>&1', $columns_output, $columns_status);
if (!$columns_status) $columns = preg_replace('/\d+\s(\d+)/', '$1', $columns_output[0], -1, $columns_count);
// If stty fails and Drush us running on Windows are we trying with mode con.
if (($columns_status || !$columns_count) && drush_is_windows()) {
$columns_output = array();
exec('mode con', $columns_output, $columns_status);
if (!$columns_status && is_array($columns_output)) {
$columns = (int)preg_replace('/\D/', '', $columns_output[4], -1, $columns_count);
}
else {
drush_log(dt('Drush could not detect the console window width. Set a Windows Environment Variable of COLUMNS to the desired width.'), LogLevel::WARNING);
}
}
// Failling back to default columns value
if (empty($columns)) {
$columns = 80;
}
}
// If a caller wants to reserve some room to add additional
// information to the drush output via post-processing, the
// --reserve-margin flag can be used to declare how much
// space to leave out. This only affects drush functions
// such as drush_print_table() that wrap the output.
$columns -= drush_get_option('reserve-margin', 0);
drush_set_context('DRUSH_COLUMNS', $columns);
}
function _drush_preflight_alias_path() {
$alias_path =& drush_get_context('ALIAS_PATH');
$default_prefix_configuration = drush_is_windows() ? getenv('ALLUSERSPROFILE') . '/Drush' : '';
$site_wide_configuration_dir = drush_get_context('ETC_PREFIX', $default_prefix_configuration) . '/etc/drush';
$alias_path[] = $site_wide_configuration_dir;
$alias_path[] = dirname(__FILE__) . '/..';
$server_home = drush_server_home();
if (isset($server_home)) {
$alias_path[] = $server_home . '/.drush';
}
}
/*
* Set root and uri.
*/
function _drush_preflight_root_uri() {
drush_preflight_root();
_drush_preflight_uri();
}
/**
* If --uri is provided, set context.
*/
function _drush_preflight_uri() {
$uri = drush_get_option('uri', '');
drush_set_context('DRUSH_SELECTED_URI', $uri);
}
function _drush_find_commandfiles_drush() {
// Core commands shipping with Drush
$searchpath[] = realpath(dirname(__FILE__) . '/../commands/');
// User commands, specified by 'include' option
$include = drush_get_context('DRUSH_INCLUDE', array());
foreach ($include as $path) {
if (is_dir($path)) {
drush_log('Include ' . $path, LogLevel::NOTICE);
$searchpath[] = $path;
}
}
if (!drush_get_option('local')) {
// System commands, residing in $SHARE_PREFIX/share/drush/commands
$share_path = drush_get_context('DRUSH_SITE_WIDE_COMMANDFILES');
if (is_dir($share_path)) {
$searchpath[] = $share_path;
}
// User commands, residing in ~/.drush
$per_user_config_dir = drush_get_context('DRUSH_PER_USER_CONFIGURATION');
if (!empty($per_user_config_dir)) {
$searchpath[] = $per_user_config_dir;
}
}
// @todo the zero parameter is a bit weird here. It's $phase.
_drush_add_commandfiles($searchpath, 0);
}
/**
* Handle any command preprocessing that may need to be done, including
* potentially redispatching the command immediately (e.g. for remote
* commands).
*
* @return
* TRUE if the command was handled remotely.
*/
function drush_preflight_command_dispatch() {
$interactive = drush_get_option('interactive', FALSE);
// The command will be executed remotely if the --remote-host flag
// is set; note that if a site alias is provided on the command line,
// and the site alias references a remote server, then the --remote-host
// option will be set when the site alias is processed.
// @see drush_sitealias_check_arg_and_site_set and _drush_sitealias_set_context_by_name
$remote_host = drush_get_option('remote-host');
$site_list = drush_get_option('site-list');
// Get the command early so that we can allow commands to directly handle remote aliases if they wish
$command = drush_parse_command();
drush_command_default_options($command);
// If the command sets the 'strict-option-handling' flag, then we will remove
// any cli options that appear after the command name from the 'cli' context.
// The cli options that appear before the command name are stored in the
// 'DRUSH_GLOBAL_CLI_OPTIONS' context, so we will just overwrite the cli context
// with this, after doing the neccessary fixup from short-form to long-form options.
// After we do that, we put back any local drush options identified by $command['options'].
if (is_array($command) && !empty($command['strict-option-handling'])) {
$cli_options = drush_get_context('DRUSH_GLOBAL_CLI_OPTIONS', array());
// Now we are going to sort out any options that exist in $command['options'];
// we will remove these from DRUSH_COMMAND_ARGS and put them back into the
// cli options.
$cli_context = drush_get_context('cli');
$remove_from_command_args = array();
foreach ($command['options'] as $option => $info) {
if (array_key_exists($option, $cli_context)) {
$cli_options[$option] = $cli_context[$option];
$remove_from_command_args[$option] = $option;
}
}
if (!empty($remove_from_command_args)) {
$drush_command_args = array();
foreach (drush_get_context('DRUSH_COMMAND_ARGS') as $arg) {
if (!_drush_should_remove_command_arg($arg, $remove_from_command_args)) {
$drush_command_args[] = $arg;
}
}
drush_set_context('DRUSH_COMMAND_ARGS', $drush_command_args);
}
drush_expand_short_form_options($cli_options);
drush_set_context('cli', $cli_options);
_drush_preflight_global_options();
}
$args = drush_get_arguments();
$command_name = array_shift($args);
$root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
$local_drush = drush_get_option('drush-script');
$is_local = drush_get_option('local');
$values = NULL;
if (!empty($root) && !empty($local_drush) && empty($is_local)) {
if (!drush_is_absolute_path($local_drush)) {
$local_drush = $root . '/' . $local_drush;
}
$local_drush = realpath($local_drush);
$this_drush = drush_find_drush();
// If there is a local drush selected, and it is not the
// same drush that is currently running, redispatch to it.
if (file_exists($local_drush) && ($this_drush != $local_drush)) {
$uri = drush_get_context('DRUSH_SELECTED_URI');
$aditional_options = array(
'root' => $root,
'local' => TRUE,
);
if (!empty($uri)) {
$aditional_options['uri'] = $uri;
}
$values = drush_do_command_redispatch(is_array($command) ? $command : $command_name, $args, NULL, NULL, $local_drush, TRUE, $aditional_options);
}
}
// If the command sets the 'handle-remote-commands' flag, then we will short-circuit
// remote command dispatching and site-list command dispatching, and always let
// the command handler run on the local machine.
if (is_array($command) && !empty($command['handle-remote-commands'])) {
return FALSE;
}
if (isset($remote_host)) {
$remote_user = drush_get_option('remote-user');
// Force interactive mode if there is a single remote target. #interactive is added by drush_do_command_redispatch
$user_interactive = drush_get_option('interactive');
drush_set_option('interactive', TRUE);
$values = drush_do_command_redispatch(is_array($command) ? $command : $command_name, $args, $remote_host, $remote_user, $user_interactive);
}
// If the --site-list flag is set, then we will execute the specified
// command once for every site listed in the site list.
if (isset($site_list)) {
if (!is_array($site_list)) {
$site_list = explode(',', $site_list);
}
$site_record = array('site-list' => $site_list);
$args = drush_get_arguments();
if (!drush_get_context('DRUSH_SIMULATE') && !$interactive && !drush_get_context('DRUSH_AFFIRMATIVE') && !drush_get_context('DRUSH_QUIET')) {
drush_print(dt("You are about to execute '!command' non-interactively (--yes forced) on all of the following targets:", array('!command' => implode(" ", $args))));
foreach ($site_list as $one_destination) {
drush_print(dt(' !target', array('!target' => $one_destination)));
}
if (drush_confirm('Continue? ') === FALSE) {
drush_user_abort();
return TRUE;
}
}
$command_name = array_shift($args);
$multi_options = drush_redispatch_get_options();
$backend_options = array();
if (drush_get_option('pipe') || drush_get_option('interactive')) {
$backend_options['interactive'] = TRUE;
}
if (drush_get_option('no-label', FALSE)) {
$backend_options['no-label'] = TRUE;
}
// If the user specified a format, try to look up the
// default list separator for the specified format.
// If the user did not specify a different label separator,
// then pass in the default as an option, so that the
// separator between the items in the list and the site
// name will be consistent.
$format = drush_get_option('format', FALSE);
if ($format && !array_key_exists('label-separator', $multi_options)) {
$formatter = drush_load_engine('outputformat', $format);
if ($formatter) {
$list_separator = $formatter->get_info('list-separator');
if ($list_separator) {
$multi_options['label-separator'] = $list_separator;
}
}
}
$values = drush_invoke_process($site_record, $command_name, $args, $multi_options, $backend_options);
}
if (isset($values)) {
if (is_array($values) && ($values['error_status'] > 0)) {
// Force an error result code. Note that drush_shutdown() will still run.
drush_set_context('DRUSH_EXECUTION_COMPLETED', TRUE);
exit($values['error_status']);
}
return TRUE;
}
return FALSE;
}
/**
* We set this context to let the shutdown function know we reached the end of drush_main().
*
* @see drush_main()
*/
function drush_postflight() {
drush_set_context("DRUSH_EXECUTION_COMPLETED", TRUE);
}
/**
* Shutdown function for use while Drush and Drupal are bootstrapping and to return any
* registered errors.
*
* The shutdown command checks whether certain options are set to reliably
* detect and log some common Drupal initialization errors.
*
* If the command is being executed with the --backend option, the script
* will return a json string containing the options and log information
* used by the script.
*
* The command will exit with '1' if it was successfully executed, and the
* result of drush_get_error() if it wasn't.
*/
function drush_shutdown() {
// Mysteriously make $user available during sess_write(). Avoids a NOTICE.
global $user;
if (!drush_get_context('DRUSH_EXECUTION_COMPLETED', FALSE) && !drush_get_context('DRUSH_USER_ABORT', FALSE)) {
$php_error_message = '';
if ($error = error_get_last()) {
$php_error_message = "\n" . dt('Error: !message in !file, line !line', array('!message' => $error['message'], '!file' => $error['file'], '!line' => $error['line']));
}
// We did not reach the end of the drush_main function,
// this generally means somewhere in the code a call to exit(),
// was made. We catch this, so that we can trigger an error in
// those cases.
drush_set_error("DRUSH_NOT_COMPLETED", dt("Drush command terminated abnormally due to an unrecoverable error.!message", array('!message' => $php_error_message)));
// Attempt to give the user some advice about how to fix the problem
_drush_postmortem();
}
// @todo Ask the bootstrap object (or maybe dispatch) how far we got.
$phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
if (drush_get_context('DRUSH_BOOTSTRAPPING')) {
switch ($phase) {
case DRUSH_BOOTSTRAP_DRUPAL_FULL :
ob_end_clean();
_drush_log_drupal_messages();
drush_set_error('DRUSH_DRUPAL_BOOTSTRAP_ERROR');
break;
}
}
if (drush_get_context('DRUSH_BACKEND', FALSE)) {
drush_backend_output();
}
elseif (drush_get_context('DRUSH_QUIET', FALSE)) {
ob_end_clean();
// If we are in pipe mode, emit the compact representation of the command, if available.
if (drush_get_context('DRUSH_PIPE')) {
drush_pipe_output();
}
}
// This way drush_return_status() will always be the last shutdown function (unless other shutdown functions register shutdown functions...)
// and won't prevent other registered shutdown functions (IE from numerous cron methods) from running by calling exit() before they get a chance.
register_shutdown_function('drush_return_status');
}
/**
* Shutdown function to save code coverage data.
*/
function drush_coverage_shutdown() {
if ($file_name = drush_get_context('DRUSH_CODE_COVERAGE', FALSE)) {
$data = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
// If coverage dump file contains anything, merge in the old data before
// saving. This happens if the current drush command invoked another drush
// command.
if (file_exists($file_name) && $content = file_get_contents($file_name)) {
$merge_data = unserialize($content);
if (is_array($merge_data)) {
foreach ($merge_data as $file => $lines) {
if (!isset($data[$file])) {
$data[$file] = $lines;
}
else {
foreach ($lines as $num => $executed) {
if (!isset($data[$file][$num])) {
$data[$file][$num] = $executed;
}
else {
$data[$file][$num] = ($executed == 1 ? $executed : $data[$file][$num]);
}
}
}
}
}
}
file_put_contents($file_name, serialize($data));
}
}
function drush_return_status() {
// If a specific exit code was set, then use it.
$exit_code = drush_get_context('DRUSH_EXIT_CODE');
if (empty($exit_code)) {
$exit_code = (drush_get_error()) ? DRUSH_FRAMEWORK_ERROR : DRUSH_SUCCESS;
}
exit($exit_code);
}