-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
environment.inc
963 lines (894 loc) · 32.1 KB
/
environment.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
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
<?php
/**
* @file
* Functions used by drush to query the environment and
* setting the current configuration.
*
* Bootstrapping now occurs in bootstrap.inc.
*
* @see includes/bootstrap.inc
*/
/**
* Supported version of Console Table. This is displayed in the manual install help.
*/
define('DRUSH_TABLE_VERSION', '1.1.5');
/**
* Base URL for automatic file download of PEAR packages.
*/
define('CONSOLE_TABLE_BASE_URL', 'https://github.com/RobLoach/Console_Table/archive/');
/**
* Log PHP errors to the Drush log. This is in effect until Drupal's error
* handler takes over.
*/
function drush_error_handler($errno, $message, $filename, $line, $context) {
// E_DEPRECATED was added in PHP 5.3. Drupal 6 will not fix all the
// deprecated errors, but suppresses them. So we suppress them as well.
if (defined('E_DEPRECATED')) {
$errno = $errno & ~E_DEPRECATED;
}
// "error_reporting" is usually set in php.ini, but may be changed by
// drush_errors_on() and drush_errors_off().
if ($errno & error_reporting()) {
// By default we log notices.
$type = drush_get_option('php-notices', 'notice');
// Bitmask value that constitutes an error needing to be logged.
$error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR;
if ($errno & $error) {
$type = 'error';
}
// Bitmask value that constitutes a warning being logged.
$warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
if ($errno & $warning) {
$type = 'warning';
}
drush_log($message . ' ' . basename($filename) . ':' . $line, $type);
return TRUE;
}
}
/**
* Returns a localizable message about php.ini that
* varies depending on whether the php_ini_loaded_file()
* is available or not.
*/
function _drush_php_ini_loaded_file_message() {
if (function_exists('php_ini_loaded_file')) {
return dt('Please check your configuration settings in !phpini or in your drush.ini file; see examples/example.drush.ini for details.', array('!phpini' => php_ini_loaded_file()));
}
else {
return dt('Please check your configuration settings in your php.ini file or in your drush.ini file; see examples/example.drush.ini for details.');
}
}
/**
* Evalute the environment after an abnormal termination and
* see if we can determine any configuration settings that the user might
* want to adjust.
*/
function _drush_postmortem() {
// Make sure that the memory limit has been bumped up from the minimum default value of 32M.
$php_memory_limit = drush_memory_limit();
if (($php_memory_limit > 0) && ($php_memory_limit <= 32*DRUSH_DRUPAL_KILOBYTE*DRUSH_DRUPAL_KILOBYTE)) {
drush_set_error('DRUSH_MEMORY_LIMIT', dt('Your memory limit is set to !memory_limit; drush needs as much memory to run as Drupal. !php_ini_msg', array('!memory_limit' => $php_memory_limit / (DRUSH_DRUPAL_KILOBYTE*DRUSH_DRUPAL_KILOBYTE) . 'M', '!php_ini_msg' => _drush_php_ini_loaded_file_message())));
}
}
/**
* Evaluate the environment before command bootstrapping
* begins. If the php environment is too restrictive, then
* notify the user that a setting change is needed and abort.
*/
function _drush_environment_check_php_ini() {
$ini_checks = array('safe_mode' => '', 'open_basedir' => '', 'disable_functions' => array('exec', 'system'), 'disable_classes' => '');
// Test to insure that certain php ini restrictions have not been enabled
$prohibited_list = array();
foreach ($ini_checks as $prohibited_mode => $disallowed_value) {
$ini_value = ini_get($prohibited_mode);
$invalid_value = FALSE;
if (empty($disallowed_value)) {
$invalid_value = !empty($ini_value) && (strcasecmp($ini_value, 'off') != 0);
}
else {
foreach ($disallowed_value as $test_value) {
if (preg_match('/(^|,)' . $test_value . '(,|$)/', $ini_value)) {
$invalid_value = TRUE;
}
}
}
if ($invalid_value) {
$prohibited_list[] = $prohibited_mode;
}
}
if (!empty($prohibited_list)) {
drush_log(dt('The following restricted PHP modes have non-empty values: !prohibited_list. This configuration is incompatible with drush. !php_ini_msg', array('!prohibited_list' => implode(' and ', $prohibited_list), '!php_ini_msg' => _drush_php_ini_loaded_file_message())), 'error');
}
return TRUE;
}
/**
* Check for the existence of the specified lib directory, and create if needed.
*/
function drush_environment_lib() {
$lib = drush_get_option('lib', DRUSH_BASE_PATH . '/lib');
// We tell drush_mkdir that $lib is not required, because otherwise it
// will throw an error if the folder exists but is not writable. It
// is okay with us if the $lib dir is not writable by the current
// user, as it may have already been set up by the user who installed Drush.
drush_mkdir($lib, FALSE);
if (!is_dir($lib)) {
return FALSE;
}
}
function drush_environment_table_lib() {
// Try using the PEAR installed version of Console_Table.
$tablefile = 'Console/Table.php';
if (@file_get_contents($tablefile, FILE_USE_INCLUDE_PATH) === FALSE) {
$lib = drush_get_option('lib', DRUSH_BASE_PATH . '/lib');
$tablefile = $lib . '/Console_Table-' . DRUSH_TABLE_VERSION . '/Table.php';
// If it is not already present, download Console Table.
if (!drush_file_not_empty($tablefile)) {
// Attempt to remove the old Console Table file, from the legacy location.
// TODO: Remove this (and associated .git.ignore) in Drush 6.x.
$tablefile_legacy = DRUSH_BASE_PATH . '/includes/table.inc';
if (drush_file_not_empty($tablefile_legacy)) {
drush_op('unlink', $tablefile_legacy);
}
// Download and extract Console_Table, and confirm success.
if (drush_lib_fetch(CONSOLE_TABLE_BASE_URL . DRUSH_TABLE_VERSION . '.tar.gz')) {
// Remove unneccessary package.xml file which ends up in /lib.
drush_op('unlink', $lib . '/package.xml');
}
if (!drush_file_not_empty($tablefile)) {
return drush_bootstrap_error('DRUSH_TABLES_LIB_NOT_FOUND', 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 into !lib directory, such that Table.php exists at !tablefile.", array('!version' => DRUSH_TABLE_VERSION, '!tablefile' => $tablefile, '!lib' => $lib)));
}
}
}
require_once $tablefile;
}
/**
* Returns the current working directory.
*
* This is the directory as it was when drush was started, not the
* directory we are currently in. For that, use getcwd() directly.
*/
function drush_cwd() {
if ($path = drush_get_context('DRUSH_OLDCWD')) {
return $path;
}
// We use PWD if available because getcwd() resolves symlinks, which
// could take us outside of the Drupal root, making it impossible to find.
// $_SERVER['PWD'] isn't set on windows and generates a Notice.
$path = isset($_SERVER['PWD']) ? $_SERVER['PWD'] : '';
if (empty($path)) {
$path = getcwd();
}
// Convert windows paths.
$path = _drush_convert_path($path);
// Save original working dir case some command wants it.
drush_set_context('DRUSH_OLDCWD', $path);
return $path;
}
/**
* Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
* Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
* proper drive path, still with Unix slashes (c:/dir1).
*/
function _drush_convert_path($path) {
$path = str_replace('\\','/', $path);
$path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
return $path;
}
/**
* Returns parent directory.
*
* @param string
* Path to start from.
*
* @return string
* Parent path of given path.
*/
function _drush_shift_path_up($path) {
if (empty($path)) {
return FALSE;
}
$path = explode('/', $path);
// Move one directory up.
array_pop($path);
return implode('/', $path);
}
/**
* Like Drupal conf_path, but searching from beneath.
* Allows proper site uri detection in site sub-directories.
*
* Essentially looks for a settings.php file. Drush uses this
* function to find a usable site based on the user's current
* working directory.
*
* @param string
* Search starting path. Defaults to current working directory.
*
* @return
* Current site path (folder containing settings.php) or FALSE if not found.
*/
function drush_site_path($path = NULL) {
$site_path = FALSE;
$path = empty($path) ? drush_cwd() : $path;
// Check the current path.
if (file_exists($path . '/settings.php')) {
$site_path = $path;
}
else {
// Move up dir by dir and check each.
while ($path = _drush_shift_path_up($path)) {
if (file_exists($path . '/settings.php')) {
$site_path = $path;
break;
}
}
}
$site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
if (file_exists($site_root . '/sites/sites.php')) {
$sites = array();
// This will overwrite $sites with the desired mappings.
include($site_root . '/sites/sites.php');
// We do a reverse lookup here to determine the URL given the site key.
if ($match = array_search($site_path, $sites)) {
$site_path = $match;
}
}
// Last resort: try from site root
if (!$site_path) {
if ($site_root) {
if (file_exists($site_root . '/sites/default/settings.php')) {
$site_path = $site_root . '/sites/default';
}
}
}
return $site_path;
}
/**
* Lookup a site's directory via the sites.php file given a hostname.
*
* @param $hostname
* The hostname of a site. May be converted from URI.
*
* @return $dir
* The directory associated with that hostname or FALSE if not found.
*/
function drush_site_dir_lookup_from_hostname($hostname) {
$site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
if (file_exists($site_root . '/sites/sites.php')) {
$sites = array();
// This will overwrite $sites with the desired mappings.
include($site_root . '/sites/sites.php');
return isset($sites[$hostname]) ? $sites[$hostname] : FALSE;
}
else {
return FALSE;
}
}
/**
* This is a copy of Drupal's conf_path function, taken from D7 and
* adjusted slightly to search from the selected Drupal Root.
*
* Drush uses this routine to find a usable site based on a URI
* passed in via a site alias record or the --uri commandline option.
*
* Drush uses Drupal itself (specifically, the Drupal conf_path function)
* to bootstrap the site itself. If the implementation of conf_path
* changes, the site should still bootstrap correctly; the only consequence
* of this routine not working is that drush configuration files
* (drushrc.php) stored with the site's settimight not be found.
*/
function drush_conf_path($server_uri, $require_settings = TRUE) {
$drupal_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
if(empty($drupal_root) || empty($server_uri)) {
return NULL;
}
$parsed_uri = parse_url($server_uri);
if (is_array($parsed_uri) && !array_key_exists('scheme', $parsed_uri)) {
$parsed_uri = parse_url('http://' . $server_uri);
}
if (!is_array($parsed_uri)) {
return NULL;
}
$server_host = $parsed_uri['host'];
if (array_key_exists('path', $parsed_uri)) {
$server_uri = $parsed_uri['path'] . '/index.php';
}
else {
$server_uri = "/index.php";
}
$confdir = 'sites';
$sites = array();
if (file_exists($drupal_root . '/' . $confdir . '/sites.php')) {
// This will overwrite $sites with the desired mappings.
include($drupal_root . '/' . $confdir . '/sites.php');
}
$uri = explode('/', $server_uri);
$server = explode('.', implode('.', array_reverse(explode(':', rtrim($server_host, '.')))));
for ($i = count($uri) - 1; $i > 0; $i--) {
for ($j = count($server); $j > 0; $j--) {
$dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
if (isset($sites[$dir]) && file_exists($drupal_root . '/' . $confdir . '/' . $sites[$dir])) {
$dir = $sites[$dir];
}
if (file_exists($drupal_root . '/' . $confdir . '/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/' . $confdir . '/' . $dir))) {
$conf = "$confdir/$dir";
return $conf;
}
}
}
$conf = "$confdir/default";
return $conf;
}
/**
* Exhaustive depth-first search to try and locate the Drupal root directory.
* This makes it possible to run drush from a subdirectory of the drupal root.
*
* @param
* Search start path. Defaults to current working directory.
* @return
* A path to drupal root, or FALSE if not found.
*/
function drush_locate_root($start_path = NULL) {
$drupal_root = FALSE;
$start_path = empty($start_path) ? drush_cwd() : $start_path;
foreach (array(TRUE, FALSE) as $follow_symlinks) {
$path = $start_path;
if ($follow_symlinks && is_link($path)) {
$path = realpath($path);
}
// Check the start path.
if (drush_valid_drupal_root($path)) {
$drupal_root = $path;
break;
}
else {
// Move up dir by dir and check each.
while ($path = _drush_shift_path_up($path)) {
if ($follow_symlinks && is_link($path)) {
$path = realpath($path);
}
if (drush_valid_drupal_root($path)) {
$drupal_root = $path;
break 2;
}
}
}
}
return $drupal_root;
}
/**
* Checks whether given path qualifies as a Drupal root.
*
* @param string
* Path to check.
*
* @return string
* The relative path to common.inc (varies by Drupal version), or FALSE if not
* a Drupal root.
*/
function drush_valid_drupal_root($path) {
if (!empty($path) && is_dir($path) && file_exists($path . '/index.php')) {
// Drupal 8 root. Additional check for the presence of core/composer.json to
// grant it is not a Drupal 7 site with a base folder named "core".
$candidate = 'core/includes/common.inc';
if (file_exists($path . '/' . $candidate) && file_exists($path . '/core/misc/drupal.js') && file_exists($path . '/composer.json')) {
return $candidate;
}
// Drupal 7 root. Additional check for the absence of core/composer.json to
// grant $path is not core/ of a Drupal 8 root.
$candidate = 'includes/common.inc';
if (file_exists($path . '/' . $candidate) && file_exists($path . '/misc/drupal.js') && ((basename($path) != 'core') || !file_exists($path . '/../composer.json'))) {
return $candidate;
}
}
return FALSE;
}
/**
* Tests the currently loaded database credentials to ensure a database connection can be made.
*/
function drush_valid_db_credentials() {
$creds = drush_get_context('DRUSH_DB_CREDENTIALS');
// Do minimal checking that we have the necessary information.
if (count($creds) == 0) {
return FALSE;
}
$type = $creds['driver'];
switch (drush_drupal_major_version()) {
case 6:
// Check availability of db extension in PHP and also Drupal support.
if (file_exists('./includes/install.'. $type .'.inc')) {
require_once './includes/install.'. $type .'.inc';
$function = $type .'_is_available';
if (!$function()) {
drush_log(dt('!type extension for PHP is not installed. Check your php.ini to see how you can enable it.', array('!type' => $type)), 'bootstrap');
return FALSE;
}
}
else {
drush_log(dt('!type database type is unsupported.', array('!type' => $type)), 'bootstrap');
return FALSE;
}
// Verify connection settings.
switch ($type) {
case 'mysql':
$hostspec = $creds['port'] ? $creds['host'] . ':' . $creds['port'] : $creds['host'];
$connection = @mysql_connect($hostspec, $creds['user'], $creds['pass']);
if (!$connection || !mysql_select_db($creds['name'])) {
drush_log(mysql_error(), 'bootstrap');
return FALSE;
}
break;
case 'mysqli':
$connection = mysqli_init();
@mysqli_real_connect($connection, $creds['host'], $creds['user'], $creds['pass'], $creds['name'], (int)$creds['port']);
if (mysqli_connect_errno() > 0) {
drush_log(mysqli_connect_error(), 'bootstrap');
return FALSE;
}
break;
case 'pgsql':
$conn_string = sprintf("host=%s user=%s password=%s dbname=%s", $creds['host'], $creds['user'], $creds['pass'], $creds['name']);
if (isset($creds['port'])) {
$conn_string .= ' port=' . $creds['port'];
}
// Copied from d6's database.pgsql.inc:
// pg_last_error() does not return a useful error message for database
// connection errors. We must turn on error tracking to get at a good error
// message, which will be stored in $php_errormsg.
$php_errormsg = '';
$track_errors_previous = ini_get('track_errors');
ini_set('track_errors', 1);
$connection = @pg_connect($conn_string);
// Restore error tracking setting
ini_set('track_errors', $track_errors_previous);
if (!$connection) {
if (empty($php_errormsg)) {
drush_log(dt("Unknown error connecting to pgsql database via !constr", array('!constr' => $conn_string)), 'bootstrap');
}
else {
require_once './includes/unicode.inc';
drush_log(decode_entities($php_errormsg), 'bootstrap');
}
return FALSE;
}
break;
}
break;
case 7:
default:
$type = ( $type=='oracle' ? 'oci' : $type); // fix PDO driver name, should go away in Drupal 8
// Drupal >=7 requires PDO and drush requires php 5.3 which ships with PDO
// but it may be compiled with --disable-pdo.
if (!class_exists('PDO')) {
drush_log(dt('PDO support is required.'), 'bootstrap');
return FALSE;
}
// Warn if the database specific driver is available. We don't return FALSE since
// Drush6 supports DB drivers that extend mysql.
if (!in_array($type, PDO::getAvailableDrivers())) {
drush_log(dt('!type extension for PHP PDO is not installed. Check your php.ini to see how you can enable it. Proceeding with the mysql PDO extension.', array('!type' => $type)), 'bootstrap');
$type = 'mysql';
}
// Build the connection string.
if ($type === 'sqlite') {
$constr = 'sqlite:' . $creds['name'];
}
elseif ($type === 'sqlsrv') {
$server = $creds['host'];
if (!empty($creds['port'])) {
$server .= ", " . $creds['port'];
}
$constr = sprintf("%s:database=%s;server=%s", $type, $creds['name'], $server);
}
elseif ($type === 'oci') {
if (empty($creds['port']))
$creds['port'] = 1521;
if ($creds['host'] == 'USETNS')
$constr = 'oci:dbname=' . $creds['database'] . ';charset=AL32UTF8';
else
$constr = 'oci:dbname=//' . $creds['host'] . ':' . $creds['port'] . '/' . $creds['database'] . ';charset=AL32UTF8';
}
else {
$constr = sprintf("%s:dbname=%s", $type, $creds['name']);
// Use unix_socket if set instead of host:port.
if (!empty($creds['unix_socket'])) {
$constr .= sprintf(";unix_socket=%s", $creds['unix_socket']);
}
else {
$constr .= sprintf(";host=%s", $creds['host']);
if (!empty($creds['port'])) {
$constr .= sprintf(";port=%d", $creds['port']);
}
}
}
try {
$db = new PDO($constr, $creds['user'], $creds['pass'], $creds['pdo']);
$db = null;
}
catch (PDOException $e) {
drush_log($e->getMessage(), 'bootstrap');
return FALSE;
}
break;
}
return TRUE;
}
/**
* Determine a proper way to call drush again
*
* This check if we were called directly or as an argument to some
* wrapper command (php and sudo are checked now).
*
* Calling ./drush.php directly yields the following environment:
*
* _SERVER["argv"][0] => ./drush.php
*
* Calling php ./drush.php also yields the following:
*
* _SERVER["argv"][0] => ./drush.php
*
* Note that the $_ global is defined only in bash and therefore cannot
* be relied upon.
*
* The DRUSH_COMMAND constant is initialised to the value of this
* function when environment.inc is loaded.
*
* @see DRUSH_COMMAND
*/
function drush_find_drush() {
$drush = realpath($_SERVER['argv']['0']);
// TODO: On Windows, if we leave $drush as-is, then callbacks will
// be done just as we were called by the batch file: php.exe C:\path\drush.php
// We could also convert drush.php to drush.bat to run the batch file again,
// but this works just as well.
return $drush;
}
/**
* Verify that we are running PHP through the command line interface.
*
* This function is useful for making sure that code cannot be run via the web server,
* such as a function that needs to write files to which the web server should not have
* access to.
*
* @return
* A boolean value that is true when PHP is being run through the command line,
* and false if being run through cgi or mod_php.
*/
function drush_verify_cli() {
return (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0));
}
/**
* Build a drush command suitable for use for drush to call itself
* e.g. in backend_invoke.
*/
function drush_build_drush_command($drush_path = NULL, $php = NULL, $os = NULL, $remote_command = FALSE) {
$environment_variables = array();
$os = _drush_get_os($os);
$additional_options = '';
if (!isset($drush_path)) {
if (!$remote_command) {
$drush_path = DRUSH_COMMAND;
}
else {
$drush_path = drush_is_windows($os) ? 'drush.bat' : 'drush';
}
}
// If the path to drush points to drush.php, then we will need to
// run it via php rather than direct execution. By default, we
// will use 'php' unless something more specific was passed in
// via the --php flag.
if (substr($drush_path, -4) == ".php") {
if (!isset($php)) {
$php = drush_get_option('php');
if (!isset($php)) {
$php = 'php';
}
}
if (isset($php) && ($php != "php")) {
$additional_options .= ' --php=' . drush_escapeshellarg($php, $os);
}
// We will also add in the php options from --php-options
$prefix = drush_escapeshellarg($php, $os);
$php_options = implode(' ', drush_get_context_options('php-options'));
if (!empty($php_options)) {
$prefix .= ' ' . $php_options;
$additional_options .= ' --php-options=' . drush_escapeshellarg($php_options, $os);
}
}
else {
// Set environment variables to propogate config to redispatched calls.
if (drush_has_bash($os)) {
if ($php) {
$environment_variables[] = 'DRUSH_PHP=' . drush_escapeshellarg($php, $os);
}
if ($php_options_alias = drush_get_option('php-options', NULL, 'alias')) {
$environment_variables[] = 'PHP_OPTIONS=' . drush_escapeshellarg($php_options_alias, $os);
}
$columns = drush_get_context('DRUSH_COLUMNS');
if (($columns) && ($columns != 80)) {
$environment_variables[] = 'COLUMNS=' . $columns;
}
$prefix = implode(' ', $environment_variables);
}
}
return trim($prefix . ' ' . drush_escapeshellarg($drush_path, $os) . $additional_options);
}
/**
* Check if the operating system is Windows.
* This will return TRUE under DOS, Powershell
* Cygwin and MSYSGIT shells, so test for the
* Windows variant FIRST if you care.
*/
function drush_is_windows($os = NULL) {
return _drush_test_os($os, array("WIN","CYGWIN","CWRSYNC","MINGW"));
}
/**
* Check if the operating system is Winodws
* running some variant of cygwin -- either
* Cygwin or the MSYSGIT shell. If you care
* which is which, test mingw first.
*/
function drush_is_cygwin($os = NULL) {
return _drush_test_os($os, array("CYGWIN","CWRSYNC","MINGW"));
}
function drush_is_mingw($os = NULL) {
return _drush_test_os($os, array("MINGW"));
}
/**
* Return tar executable name specific for the current OS
*/
function drush_get_tar_executable() {
return drush_is_windows() ? (drush_is_mingw() ? "tar.exe" : "bsdtar.exe") : "tar";
}
/**
* Check if the operating system is OS X.
* This will return TRUE for Mac OS X (Darwin).
*/
function drush_is_osx($os = NULL) {
return _drush_test_os($os, array("DARWIN"));
}
/**
* Checks if the operating system has bash.
*
* MinGW has bash, but PHP isn't part of MinGW and hence doesn't run in bash.
*/
function drush_has_bash($os = NULL) {
return (drush_is_cygwin($os) && !drush_is_mingw($os)) || !drush_is_windows($os);
}
/**
* Checks operating system and returns
* supported bit bucket folder.
*/
function drush_bit_bucket() {
if (drush_has_bash()) {
return '/dev/null';
}
else {
return 'nul';
}
}
/**
* Return the OS we are running under.
*
* @return string
* Linux
* WIN* (e.g. WINNT)
* CYGWIN
* MINGW* (e.g. MINGW32)
*/
function _drush_get_os($os = NULL) {
// The special os "CWRSYNC" can be used to indicate that we are testing
// a path that will be passed as an argument to cwRsync, which requires
// that the path be converted to /cygdrive/c/path, even on DOS or Powershell.
// The special os "RSYNC" can be used to indicate that we want to assume
// "CWRSYNC" when cwrsync is installed, or default to the local OS otherwise.
if (strtoupper($os) == "RSYNC") {
$os = _drush_get_os("LOCAL");
// For now we assume that cwrsync is always installed on Windows, and never installed son any other platform.
return drush_is_windows($os) ? "CWRSYNC" : $os;
}
// We allow "LOCAL" to document, in instances where some parameters are being escaped
// for use on a remote machine, that one particular parameter will always be used on
// the local machine (c.f. drush_backend_invoke).
if (isset($os) && ($os != "LOCAL")) {
return $os;
}
if (_drush_test_os(getenv("MSYSTEM"), array("MINGW"))) {
return getenv("MSYSTEM");
}
// QUESTION: Can we differentiate between DOS and POWERSHELL? They appear to have the same environment.
// At the moment, it does not seem to matter; they behave the same from PHP.
// At this point we will just return PHP_OS.
return PHP_OS;
}
function _drush_test_os($os, $os_list_to_check) {
$os = _drush_get_os($os);
foreach ($os_list_to_check as $test) {
if (strtoupper(substr($os, 0, strlen($test))) == strtoupper($test)) {
return TRUE;
}
}
return FALSE;
}
/**
* Read the drush info file.
*/
function drush_read_drush_info() {
$drush_info_file = dirname(__FILE__) . '/../drush.info';
return parse_ini_file($drush_info_file);
}
/**
* Make a determination whether or not the given
* host is local or not.
*
* @param host
* A hostname, 'localhost' or '127.0.0.1'.
* @return
* True if the host is local.
*/
function drush_is_local_host($host) {
// In order for this to work right, you must use 'localhost' or '127.0.0.1'
// or the machine returned by 'uname -n' for your 'remote-host' entry in
// your site alias.
if (($host == 'localhost') || ($host == '127.0.0.1')) {
return TRUE;
}
// We'll start out by asking for uname -n via php_uname, since
// that is most portable. On Linux, uname -n returns the contents of
// /etc/hostname, which, according to `man hostname`, should never
// contain the fqdn. We will therefore also try `hostname -f`, and
// see if we can get the fqdn from that.
$uname = php_uname('n');
if ((strpos($uname,'.') === FALSE) && (!drush_is_windows())) {
$hostname = exec('hostname -f');
if (!empty($hostname)) {
$uname = $hostname;
}
}
// We will require an exact match if we have the fqdn for this
// host; if we only have the short name, then we will consider it
// to be a match if it matches the first part of the remote-host
// item (up to the first dot).
return (strpos($uname,'.') !== FALSE) ? ($host == $uname) : substr($host . '.',0,strlen($uname)+1) == $uname . '.';
}
/**
* Return the user's home directory.
*/
function drush_server_home() {
// Cannot use $_SERVER superglobal since that's empty during Drush_UnitTestCase
// getenv('HOME') isn't set on windows and generates a Notice.
$home = getenv('HOME');
if (empty($home)) {
if (!empty($_SERVER['HOMEDRIVE']) && !empty($_SERVER['HOMEPATH'])) {
// home on windows
$home = $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
}
}
return empty($home) ? NULL : $home;
}
/**
* Return the name of the user running drush.
*/
function drush_get_username() {
$name = NULL;
if (!$name = getenv("username")) { // Windows
if (!$name = getenv("USER")) {
// If USER not defined, use posix
if (function_exists('posix_getpwuid')) {
$processUser = posix_getpwuid(posix_geteuid());
$name = $processUser['name'];
}
}
}
return $name;
}
/**
* The path to the global cache directory.
*
* @param subdir
* Return the specified subdirectory inside the global
* cache directory instead. The subdirectory is created.
*/
function drush_directory_cache($subdir = '') {
$cache_locations = array();
if (getenv('CACHE_PREFIX')) {
$cache_locations[getenv('CACHE_PREFIX')] = 'cache';
}
$home = drush_server_home();
if ($home) {
$cache_locations[$home] = '.drush/cache';
}
$cache_locations[drush_find_tmp()] = 'drush-' . drush_get_username() . '/cache';
foreach ($cache_locations as $base => $dir) {
if (!empty($base) && is_writable($base)) {
$cache_dir = $base . '/' . $dir;
if (!empty($subdir)) {
$cache_dir .= '/' . $subdir;
}
if (drush_mkdir($cache_dir)) {
return $cache_dir;
}
else {
// If the base directory is writable, but the cache directory
// is not, then we will get an error. The error will be displayed,
// but we will still call drush_clear_error so that we can go
// on and try the next location to see if we can find a cache
// directory somewhere.
drush_clear_error();
}
}
}
return drush_set_error('DRUSH_NO_WRITABLE_CACHE', dt('Drush must have a writable cache directory; please insure that one of the following locations is writable: @locations',
array('@locations' => implode(',', array_keys($cache_locations)))));
}
/**
* Get complete information for all available extensions (modules and themes).
*
* @return
* An array containing info for all available extensions.
*/
function drush_get_extensions($include_hidden = TRUE) {
drush_include_engine('drupal', 'environment');
$extensions = array_merge(drush_get_modules($include_hidden), drush_get_themes($include_hidden));
foreach ($extensions as $name => $extension) {
if (isset($extension->info['name'])) {
$extensions[$name]->label = $extension->info['name'].' ('.$extension->name.')';
}
else {
drush_log(dt("Extension !name provides no human-readable name in .info file.", array('!name' => $name), 'debug'));
$extensions[$name]->label = $name.' ('.$extension->name.')';
}
if (empty($extension->info['package'])) {
$extensions[$name]->info['package'] = dt('Other');
}
}
return $extensions;
}
/**
* Test compatibility of a extension with version of drupal core and php.
*
* @param $file Extension object as returned by system_rebuild_module_data().
* @return FALSE if the extension is compatible.
*/
function drush_extension_check_incompatibility($file) {
if (!isset($file->info['core']) || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY) {
return 'Drupal';
}
if (version_compare(phpversion(), $file->info['php']) < 0) {
return 'PHP';
}
return FALSE;
}
/**
*
*/
function drush_drupal_required_modules($modules) {
drush_include_engine('drupal', 'environment');
return _drush_drupal_required_modules($modules);
}
/**
* Return the default theme.
*
* @return
* Machine name of the default theme.
*/
function drush_theme_get_default() {
return variable_get('theme_default', 'garland');
}
/**
* Return the administration theme.
*
* @return
* Machine name of the administration theme.
*/
function drush_theme_get_admin() {
return variable_get('admin_theme', drush_theme_get_default());
}
/**
* Returns the sitewide Drupal directory for extensions.
*/
function drush_drupal_sitewide_directory($major_version = NULL) {
if (!$major_version) {
$major_version = drush_drupal_major_version();
}
return ($major_version < 8) ? 'sites/all' : '';
}