Version 1
[yaffs-website] / vendor / drush / drush / includes / environment.inc
1 <?php
2
3 /**
4  * @file
5  * Functions used by drush to query the environment and
6  * setting the current configuration.
7  *
8  * Bootstrapping now occurs in bootstrap.inc.
9  *
10  * @see includes/bootstrap.inc
11  */
12
13 use Drush\Log\LogLevel;
14 use Webmozart\PathUtil\Path;
15
16 /**
17  * Log PHP errors to the Drush log. This is in effect until Drupal's error
18  * handler takes over.
19  */
20 function drush_error_handler($errno, $message, $filename, $line, $context) {
21   // E_DEPRECATED was added in PHP 5.3. Drupal 6 will not fix all the
22   // deprecated errors, but suppresses them. So we suppress them as well.
23   if (defined('E_DEPRECATED')) {
24     $errno = $errno & ~E_DEPRECATED;
25   }
26
27   // "error_reporting" is usually set in php.ini, but may be changed by
28   // drush_errors_on() and drush_errors_off().
29   if ($errno & error_reporting()) {
30     // By default we log notices.
31     $type = drush_get_option('php-notices', 'notice');
32     $halt_on_error = drush_get_option('halt-on-error', (drush_drupal_major_version() != 6));
33
34     // Bitmask value that constitutes an error needing to be logged.
35     $error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
36     if ($errno & $error) {
37       $type = 'error';
38     }
39
40     // Bitmask value that constitutes a warning being logged.
41     $warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
42     if ($errno & $warning) {
43       $type = LogLevel::WARNING;
44     }
45
46     drush_log($message . ' ' . basename($filename) . ':' . $line, $type);
47
48     if ($errno == E_RECOVERABLE_ERROR && $halt_on_error) {
49       drush_log(dt('E_RECOVERABLE_ERROR encountered; aborting. To ignore recoverable errors, run again with --no-halt-on-error'), 'error');
50       exit(DRUSH_APPLICATION_ERROR);
51     }
52
53     return TRUE;
54   }
55 }
56
57 /**
58  * Returns a localizable message about php.ini that
59  * varies depending on whether the php_ini_loaded_file()
60  * is available or not.
61  */
62 function _drush_php_ini_loaded_file_message() {
63   if (function_exists('php_ini_loaded_file')) {
64     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()));
65   }
66   else {
67     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.');
68   }
69 }
70
71 /**
72  * Evalute the environment after an abnormal termination and
73  * see if we can determine any configuration settings that the user might
74  * want to adjust.
75  */
76 function _drush_postmortem() {
77   // Make sure that the memory limit has been bumped up from the minimum default value of 32M.
78   $php_memory_limit = drush_memory_limit();
79   if (($php_memory_limit > 0) && ($php_memory_limit <= 32*DRUSH_KILOBYTE*DRUSH_KILOBYTE)) {
80     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_KILOBYTE*DRUSH_KILOBYTE) . 'M', '!php_ini_msg' => _drush_php_ini_loaded_file_message())));
81   }
82 }
83
84 /**
85  * Evaluate the environment before command bootstrapping
86  * begins.  If the php environment is too restrictive, then
87  * notify the user that a setting change is needed and abort.
88  */
89 function _drush_environment_check_php_ini() {
90   $ini_checks = array('safe_mode' => '', 'open_basedir' => '', 'disable_functions' => array('exec', 'system'), 'disable_classes' => '');
91
92   // Test to insure that certain php ini restrictions have not been enabled
93   $prohibited_list = array();
94   foreach ($ini_checks as $prohibited_mode => $disallowed_value) {
95     $ini_value = ini_get($prohibited_mode);
96     $invalid_value = FALSE;
97     if (empty($disallowed_value)) {
98       $invalid_value = !empty($ini_value) && (strcasecmp($ini_value, 'off') != 0);
99     }
100     else {
101       foreach ($disallowed_value as $test_value) {
102         if (preg_match('/(^|,)' . $test_value . '(,|$)/', $ini_value)) {
103           $invalid_value = TRUE;
104         }
105       }
106     }
107     if ($invalid_value) {
108       $prohibited_list[] = $prohibited_mode;
109     }
110   }
111   if (!empty($prohibited_list)) {
112     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())), LogLevel::ERROR);
113   }
114
115   return TRUE;
116 }
117
118 /**
119  * Returns the current working directory.
120  *
121  * This is the directory as it was when drush was started, not the
122  * directory we are currently in. For that, use getcwd() directly.
123  */
124 function drush_cwd() {
125   if ($path = drush_get_context('DRUSH_OLDCWD')) {
126     return $path;
127   }
128   // We use PWD if available because getcwd() resolves symlinks, which
129   // could take us outside of the Drupal root, making it impossible to find.
130   // $_SERVER['PWD'] isn't set on windows and generates a Notice.
131   $path = isset($_SERVER['PWD']) ? $_SERVER['PWD'] : '';
132   if (empty($path)) {
133     $path = getcwd();
134   }
135
136   // Convert windows paths.
137   $path = Path::canonicalize($path);
138
139   // Save original working dir case some command wants it.
140   drush_set_context('DRUSH_OLDCWD', $path);
141
142   return $path;
143 }
144
145 /**
146  * Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
147  * Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
148  * proper drive path, still with Unix slashes (c:/dir1).
149  */
150 function _drush_convert_path($path) {
151   $path = str_replace('\\','/', $path);
152   if (drush_is_windows(_drush_get_os()) && !drush_is_cygwin(_drush_get_os())) {
153     $path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
154   }
155
156   return $path;
157 }
158
159 /**
160  * Returns parent directory.
161  *
162  * @param string
163  *   Path to start from.
164  *
165  * @return string
166  *   Parent path of given path.
167  */
168 function _drush_shift_path_up($path) {
169   if (empty($path)) {
170     return FALSE;
171   }
172   $path = explode(DIRECTORY_SEPARATOR, $path);
173   // Move one directory up.
174   array_pop($path);
175   return implode(DIRECTORY_SEPARATOR, $path);
176   // return dirname($path);
177 }
178
179 /**
180  * Like Drupal conf_path, but searching from beneath.
181  * Allows proper site uri detection in site sub-directories.
182  *
183  * Essentially looks for a settings.php file.  Drush uses this
184  * function to find a usable site based on the user's current
185  * working directory.
186  *
187  * @param string
188  *   Search starting path. Defaults to current working directory.
189  *
190  * @return
191  *   Current site path (folder containing settings.php) or FALSE if not found.
192  */
193 function drush_site_path($path = NULL) {
194   $site_path = FALSE;
195
196   $path = empty($path) ? drush_cwd() : $path;
197   // Check the current path.
198   if (file_exists($path . '/settings.php')) {
199     $site_path = $path;
200   }
201   else {
202     // Move up dir by dir and check each.
203     // Stop if we get to a Drupal root.   We don't care
204     // if it is DRUSH_SELECTED_DRUPAL_ROOT or some other root.
205     while (($path = _drush_shift_path_up($path)) && !drush_valid_root($path)) {
206       if (file_exists($path . '/settings.php')) {
207         $site_path = $path;
208         break;
209       }
210     }
211   }
212
213   $site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
214   if (file_exists($site_root . '/sites/sites.php')) {
215     $sites = array();
216     // This will overwrite $sites with the desired mappings.
217     include($site_root . '/sites/sites.php');
218     // We do a reverse lookup here to determine the URL given the site key.
219     if ($match = array_search($site_path, $sites)) {
220       $site_path = $match;
221     }
222   }
223
224   // Last resort: try from site root
225   if (!$site_path) {
226     if ($site_root) {
227       if (file_exists($site_root . '/sites/default/settings.php')) {
228         $site_path = $site_root . '/sites/default';
229       }
230     }
231   }
232
233   return $site_path;
234 }
235
236 /**
237  * Lookup a site's directory via the sites.php file given a hostname.
238  *
239  * @param $hostname
240  *   The hostname of a site.  May be converted from URI.
241  *
242  * @return $dir
243  *   The directory associated with that hostname or FALSE if not found.
244  */
245 function drush_site_dir_lookup_from_hostname($hostname, $site_root = NULL) {
246   if (!isset($site_root)) {
247     $site_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
248   }
249   if (!empty($site_root) && file_exists($site_root . '/sites/sites.php')) {
250     $sites = array();
251     // This will overwrite $sites with the desired mappings.
252     include($site_root . '/sites/sites.php');
253     return isset($sites[$hostname]) ? $sites[$hostname] : FALSE;
254   }
255   else {
256     return FALSE;
257   }
258 }
259
260 /**
261  * This is a copy of Drupal's conf_path function, taken from D7 and
262  * adjusted slightly to search from the selected Drupal Root.
263  *
264  * Drush uses this routine to find a usable site based on a URI
265  * passed in via a site alias record or the --uri commandline option.
266  *
267  * Drush uses Drupal itself (specifically, the Drupal conf_path function)
268  * to bootstrap the site itself.  If the implementation of conf_path
269  * changes, the site should still bootstrap correctly; the only consequence
270  * of this routine not working is that drush configuration files
271  * (drushrc.php) stored with the site's drush folders might not be found.
272  */
273 function drush_conf_path($server_uri, $require_settings = TRUE) {
274   $drupal_root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
275   if(empty($drupal_root) || empty($server_uri)) {
276     return NULL;
277   }
278   $parsed_uri = parse_url($server_uri);
279   if (is_array($parsed_uri) && !array_key_exists('scheme', $parsed_uri)) {
280     $parsed_uri = parse_url('http://' . $server_uri);
281   }
282   if (!is_array($parsed_uri)) {
283     return NULL;
284   }
285   $server_host = $parsed_uri['host'];
286   if (array_key_exists('path', $parsed_uri)) {
287     $server_uri = $parsed_uri['path'] . '/index.php';
288   }
289   else {
290     $server_uri = "/index.php";
291   }
292   $confdir = 'sites';
293
294   $sites = array();
295   if (file_exists($drupal_root . '/' . $confdir . '/sites.php')) {
296     // This will overwrite $sites with the desired mappings.
297     include($drupal_root . '/' . $confdir . '/sites.php');
298   }
299
300   $uri = explode('/', $server_uri);
301   $server = explode('.', implode('.', array_reverse(explode(':', rtrim($server_host, '.')))));
302   for ($i = count($uri) - 1; $i > 0; $i--) {
303     for ($j = count($server); $j > 0; $j--) {
304       $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
305       if (isset($sites[$dir]) && file_exists($drupal_root . '/' . $confdir . '/' . $sites[$dir])) {
306         $dir = $sites[$dir];
307       }
308       if (file_exists($drupal_root . '/' . $confdir . '/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/' . $confdir . '/' . $dir))) {
309         $conf = "$confdir/$dir";
310         return $conf;
311       }
312     }
313   }
314   $conf = "$confdir/default";
315   return $conf;
316 }
317
318 /**
319  * Exhaustive depth-first search to try and locate the Drupal root directory.
320  * This makes it possible to run Drush from a subdirectory of the drupal root.
321  *
322  * @param
323  *   Search start path. Defaults to current working directory.
324  * @return
325  *   A path to drupal root, or FALSE if not found.
326  */
327 function drush_locate_root($start_path = NULL) {
328   $drupal_root = FALSE;
329
330   $start_path = empty($start_path) ? drush_cwd() : $start_path;
331   foreach (array(TRUE, FALSE) as $follow_symlinks) {
332     $path = $start_path;
333     if ($follow_symlinks && is_link($path)) {
334       $path = realpath($path);
335     }
336     // Check the start path.
337     if (drush_valid_root($path)) {
338       $drupal_root = $path;
339       break;
340     }
341     else {
342       // Move up dir by dir and check each.
343       while ($path = _drush_shift_path_up($path)) {
344         if ($follow_symlinks && is_link($path)) {
345           $path = realpath($path);
346         }
347         if (drush_valid_root($path)) {
348           $drupal_root = $path;
349           break 2;
350         }
351       }
352     }
353   }
354
355   return $drupal_root;
356 }
357
358 /**
359  * Checks whether given path qualifies as a Drupal root.
360  *
361  * @param string
362  *   Path to check.
363  *
364  * @return string
365  *   The relative path to common.inc (varies by Drupal version), or FALSE if not
366  *   a Drupal root.
367  */
368 function drush_valid_root($path) {
369   $bootstrap_class = drush_bootstrap_class_for_root($path);
370   return $bootstrap_class != NULL;
371 }
372
373 /**
374  * Tests the currently loaded database credentials to ensure a database connection can be made.
375  *
376  * @param bool $log_errors
377  *   (optional) If TRUE, log error conditions; otherwise be quiet.
378  *
379  * @return bool
380  *   TRUE if database credentials are valid.
381  */
382 function drush_valid_db_credentials() {
383   try {
384     $sql = drush_sql_get_class();
385     if (!$sqlVersion = drush_sql_get_version()) {
386       drush_log(dt('While checking DB credentials, could not instantiate SQLVersion class.'), 'debug');
387       return FALSE;
388     }
389     if (!$sqlVersion->valid_credentials($sql->db_spec())) {
390       drush_log(dt('DB credentials are invalid.'), 'debug');
391       return FALSE;
392     }
393     return $sql->query('SELECT 1;');
394   }
395   catch (Exception $e) {
396     drush_log(dt('Checking DB credentials yielded error: @e', array('@e' => $e->getMessage())), 'debug');
397     return FALSE;
398   }
399 }
400
401 /**
402  * Determine a proper way to call drush again
403  *
404  * This check if we were called directly or as an argument to some
405  * wrapper command (php and sudo are checked now).
406  *
407  * Calling ./drush.php directly yields the following environment:
408  *
409  * _SERVER["argv"][0] => ./drush.php
410  *
411  * Calling php ./drush.php also yields the following:
412  *
413  * _SERVER["argv"][0] => ./drush.php
414  *
415  * Note that the $_ global is defined only in bash and therefore cannot
416  * be relied upon.
417  *
418  * The DRUSH_COMMAND constant is initialised to the value of this
419  * function when environment.inc is loaded.
420  *
421  * @see DRUSH_COMMAND
422  */
423 function drush_find_drush() {
424   if ($drush = realpath($_SERVER['argv']['0'])) {
425     return Path::canonicalize($drush);
426   }
427   return FALSE;
428 }
429
430 /**
431  * Verify that we are running PHP through the command line interface.
432  *
433  * This function is useful for making sure that code cannot be run via the web server,
434  * such as a function that needs to write files to which the web server should not have
435  * access to.
436  *
437  * @return
438  *   A boolean value that is true when PHP is being run through the command line,
439  *   and false if being run through cgi or mod_php.
440  */
441 function drush_verify_cli() {
442   return (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0));
443 }
444
445 /**
446  * Build a drush command suitable for use for Drush to call itself
447  * e.g. in backend_invoke.
448  */
449 function drush_build_drush_command($drush_path = NULL, $php = NULL, $os = NULL, $remote_command = FALSE, $environment_variables = array()) {
450   $os = _drush_get_os($os);
451   $additional_options = '';
452   $prefix = '';
453   if (!$drush_path) {
454     if (!$remote_command) {
455       $drush_path = DRUSH_COMMAND;
456     }
457     else {
458       $drush_path = 'drush'; // drush_is_windows($os) ? 'drush.bat' : 'drush';
459     }
460   }
461   // If the path to drush points to drush.php, then we will need to
462   // run it via php rather than direct execution.  By default, we
463   // will use 'php' unless something more specific was passed in
464   // via the --php flag.
465   if (substr($drush_path, -4) == ".php") {
466     if (!isset($php)) {
467       $php = drush_get_option('php');
468       if (!isset($php)) {
469         $php = 'php';
470       }
471     }
472     if (isset($php) && ($php != "php")) {
473       $additional_options .= ' --php=' . drush_escapeshellarg($php, $os);
474     }
475     // We will also add in the php options from --php-options
476     $prefix .= drush_escapeshellarg($php, $os);
477     $php_options = implode(' ', drush_get_context_options('php-options'));
478     if (!empty($php_options)) {
479       $prefix .= ' ' . $php_options;
480       $additional_options .= ' --php-options=' . drush_escapeshellarg($php_options, $os);
481     }
482   }
483   else {
484     // Set environment variables to propogate config to redispatched calls.
485     if (drush_has_bash($os)) {
486       if ($php) {
487         $environment_variables['DRUSH_PHP'] = $php;
488       }
489       if ($php_options_alias = drush_get_option('php-options', NULL, 'alias')) {
490         $environment_variables['PHP_OPTIONS'] = $php_options_alias;
491       }
492       $columns = drush_get_context('DRUSH_COLUMNS');
493       if (($columns) && ($columns != 80)) {
494         $environment_variables['COLUMNS'] = $columns;
495       }
496     }
497   }
498
499   // Add environmental variables, if present
500   if (!empty($environment_variables)) {
501     $prefix .= ' env';
502     foreach ($environment_variables as $key=>$value) {
503       $prefix .= ' ' . drush_escapeshellarg($key, $os) . '=' . drush_escapeshellarg($value, $os);
504     }
505   }
506
507   return trim($prefix . ' ' . drush_escapeshellarg($drush_path, $os) . $additional_options);
508 }
509
510 /**
511  * Check if the operating system is Winodws
512  * running some variant of cygwin -- either
513  * Cygwin or the MSYSGIT shell.  If you care
514  * which is which, test mingw first.
515  */
516 function drush_is_cygwin($os = NULL) {
517   return _drush_test_os($os, array("CYGWIN","CWRSYNC","MINGW"));
518 }
519
520 function drush_is_mingw($os = NULL) {
521   return _drush_test_os($os, array("MINGW"));
522 }
523
524 /**
525  * Return tar executable name specific for the current OS
526  */
527 function drush_get_tar_executable() {
528   return drush_is_windows() ? (drush_is_mingw() ? "tar.exe" : "bsdtar.exe") : "tar";
529 }
530
531 /**
532  * Check if the operating system is OS X.
533  * This will return TRUE for Mac OS X (Darwin).
534  */
535 function drush_is_osx($os = NULL) {
536   return _drush_test_os($os, array("DARWIN"));
537 }
538
539 /**
540  * Checks if the operating system has bash.
541  *
542  * MinGW has bash, but PHP isn't part of MinGW and hence doesn't run in bash.
543  */
544 function drush_has_bash($os = NULL) {
545   return (drush_is_cygwin($os) && !drush_is_mingw($os)) || !drush_is_windows($os);
546 }
547
548 /**
549  * Checks operating system and returns
550  * supported bit bucket folder.
551  */
552 function drush_bit_bucket() {
553   if (drush_has_bash()) {
554     return '/dev/null';
555   }
556   else {
557     return 'nul';
558   }
559 }
560
561 /**
562  * Return the OS we are running under.
563  *
564  * @return string
565  *   Linux
566  *   WIN* (e.g. WINNT)
567  *   CYGWIN
568  *   MINGW* (e.g. MINGW32)
569  */
570 function _drush_get_os($os = NULL) {
571   // The special os "CWRSYNC" can be used to indicate that we are testing
572   // a path that will be passed as an argument to cwRsync, which requires
573   // that the path be converted to /cygdrive/c/path, even on DOS or Powershell.
574   // The special os "RSYNC" can be used to indicate that we want to assume
575   // "CWRSYNC" when cwrsync is installed, or default to the local OS otherwise.
576   if (strtoupper($os) == "RSYNC") {
577     $os = _drush_get_os("LOCAL");
578     // For now we assume that cwrsync is always installed on Windows, and never installed son any other platform.
579     return drush_is_windows($os) ? "CWRSYNC" : $os;
580   }
581   // We allow "LOCAL" to document, in instances where some parameters are being escaped
582   // for use on a remote machine, that one particular parameter will always be used on
583   // the local machine (c.f. drush_backend_invoke).
584   if (isset($os) && ($os != "LOCAL")) {
585     return $os;
586   }
587   if (_drush_test_os(getenv("MSYSTEM"), array("MINGW"))) {
588     return getenv("MSYSTEM");
589   }
590   // QUESTION: Can we differentiate between DOS and POWERSHELL? They appear to have the same environment.
591   // At the moment, it does not seem to matter; they behave the same from PHP.
592   // At this point we will just return PHP_OS.
593   return PHP_OS;
594 }
595
596 function _drush_test_os($os, $os_list_to_check) {
597   $os = _drush_get_os($os);
598   foreach ($os_list_to_check as $test) {
599     if (strtoupper(substr($os, 0, strlen($test))) == strtoupper($test)) {
600       return TRUE;
601     }
602   }
603   return FALSE;
604 }
605
606 /**
607  * Read the drush info file.
608  */
609 function drush_read_drush_info() {
610   $drush_info_file = dirname(__FILE__) . '/../drush.info';
611
612   return parse_ini_file($drush_info_file);
613 }
614
615 /**
616  * Make a determination whether or not the given
617  * host is local or not.
618  *
619  * @param host
620  *   A hostname, 'localhost' or '127.0.0.1'.
621  * @return
622  *   True if the host is local.
623  */
624 function drush_is_local_host($host) {
625   // Check to see if the provided host is "local".
626   // @see hook_drush_sitealias_alter() in drush.api.php.
627   if (
628     ($host == 'localhost') ||
629     ($host == '127.0.0.1')
630   ) {
631     return TRUE;
632   }
633
634   return FALSE;
635 }
636
637 /**
638  * Return the user's home directory.
639  */
640 function drush_server_home() {
641   try {
642     return Path::getHomeDirectory();
643   } catch (Exception $e) {
644     return NULL;
645   }
646 }
647
648 /**
649  * Return the name of the user running drush.
650  */
651 function drush_get_username() {
652   $name = NULL;
653   if (!$name = getenv("username")) { // Windows
654     if (!$name = getenv("USER")) {
655       // If USER not defined, use posix
656       if (function_exists('posix_getpwuid')) {
657         $processUser = posix_getpwuid(posix_geteuid());
658         $name = $processUser['name'];
659       }
660     }
661   }
662   return $name;
663 }
664
665 /**
666  * The path to the global cache directory.
667  *
668  * @param subdir
669  *   Return the specified subdirectory inside the global
670  *   cache directory instead.  The subdirectory is created.
671  */
672 function drush_directory_cache($subdir = '') {
673   $cache_locations = array();
674   if (getenv('CACHE_PREFIX')) {
675     $cache_locations[getenv('CACHE_PREFIX')] = 'cache';
676   }
677   $home = drush_server_home();
678   if ($home) {
679     $cache_locations[$home] = '.drush/cache';
680   }
681   $cache_locations[drush_find_tmp()] = 'drush-' . drush_get_username() . '/cache';
682   foreach ($cache_locations as $base => $dir) {
683     if (!empty($base) && is_writable($base)) {
684       $cache_dir = $base . '/' . $dir;
685       if (!empty($subdir)) {
686         $cache_dir .= '/' . $subdir;
687       }
688       if (drush_mkdir($cache_dir)) {
689         return $cache_dir;
690       }
691       else {
692         // If the base directory is writable, but the cache directory
693         // is not, then we will get an error. The error will be displayed,
694         // but we will still call drush_clear_error so that we can go
695         // on and try the next location to see if we can find a cache
696         // directory somewhere.
697         drush_clear_error();
698       }
699     }
700   }
701   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',
702     array('@locations' => implode(',', array_keys($cache_locations)))));
703 }
704
705 /**
706  * Get complete information for all available extensions (modules and themes).
707  *
708  * @return
709  *   An array containing info for all available extensions. In D8, these are Extension objects.
710  */
711 function drush_get_extensions($include_hidden = TRUE) {
712   drush_include_engine('drupal', 'environment');
713   $extensions = array_merge(drush_get_modules($include_hidden), drush_get_themes($include_hidden));
714   foreach ($extensions as $name => $extension) {
715     if (isset($extension->info['name'])) {
716       $extensions[$name]->label = $extension->info['name'].' ('.$name.')';
717     }
718     else {
719       drush_log(dt("Extension !name provides no human-readable name in .info file.", array('!name' => $name), LogLevel::DEBUG));
720       $extensions[$name]->label = $name.' ('.$name.')';
721     }
722     if (empty($extension->info['package'])) {
723       $extensions[$name]->info['package'] = dt('Other');
724     }
725   }
726   return $extensions;
727 }
728
729 /**
730  * Gets the extension name.
731  *
732  * @param $info
733  *   The extension info.
734  * @return string
735  *   The extension name.
736  */
737 function drush_extension_get_name($info) {
738   drush_include_engine('drupal', 'environment');
739   return _drush_extension_get_name($info);
740 }
741
742 /**
743  * Gets the extension type.
744  *
745  * @param $info
746  *   The extension info.
747  * @return string
748  *   The extension type.
749  */
750 function drush_extension_get_type($info) {
751   drush_include_engine('drupal', 'environment');
752   return _drush_extension_get_type($info);
753 }
754
755 /**
756  * Gets the extension path.
757  *
758  * @param $info
759  *   The extension info.
760  * @return string
761  *   The extension path.
762  */
763 function drush_extension_get_path($info) {
764   drush_include_engine('drupal', 'environment');
765   return _drush_extension_get_path($info);
766 }
767
768 /**
769  * Test compatibility of a extension with version of drupal core and php.
770  *
771  * @param $file Extension object as returned by system_rebuild_module_data().
772  * @return FALSE if the extension is compatible.
773  */
774 function drush_extension_check_incompatibility($file) {
775   if (!isset($file->info['core']) || $file->info['core'] != drush_get_drupal_core_compatibility()) {
776     return 'Drupal';
777   }
778   if (version_compare(phpversion(), $file->info['php']) < 0) {
779     return 'PHP';
780   }
781   return FALSE;
782 }
783
784 /**
785  *
786  */
787 function drush_drupal_required_modules($modules) {
788   drush_include_engine('drupal', 'environment');
789   return _drush_drupal_required_modules($modules);
790 }
791
792 /**
793  * Return the default theme.
794  *
795  * @return
796  *  Machine name of the default theme.
797  */
798 function drush_theme_get_default() {
799   drush_include_engine('drupal', 'environment');
800   return _drush_theme_default();
801 }
802
803 /**
804  * Return the administration theme.
805  *
806  * @return
807  *  Machine name of the administration theme.
808  */
809 function drush_theme_get_admin() {
810   drush_include_engine('drupal', 'environment');
811   return _drush_theme_admin();
812 }
813
814 /**
815  * Return the path to public files directory.
816  */
817 function drush_file_get_public() {
818   drush_include_engine('drupal', 'environment');
819   return _drush_file_public_path();
820 }
821
822 /**
823  * Return the path to private files directory.
824  */
825 function drush_file_get_private() {
826   drush_include_engine('drupal', 'environment');
827   return _drush_file_private_path();
828 }
829
830 /**
831  * Returns the sitewide Drupal directory for extensions.
832  */
833 function drush_drupal_sitewide_directory($major_version = NULL) {
834   if (!$major_version) {
835     $major_version = drush_drupal_major_version();
836   }
837   return ($major_version < 8) ? 'sites/all' : '';
838 }
839
840 /**
841  * Helper function to get core compatibility constant.
842  *
843  * @return string
844  *   The Drupal core compatibility constant.
845  */
846 function drush_get_drupal_core_compatibility() {
847   if (defined('DRUPAL_CORE_COMPATIBILITY')) {
848     return DRUPAL_CORE_COMPATIBILITY;
849   }
850   elseif (defined('\Drupal::CORE_COMPATIBILITY')) {
851     return \Drupal::CORE_COMPATIBILITY;
852   }
853 }
854
855 /**
856  * Set Env. Variables for given site-alias.
857  */
858 function drush_set_environment_vars(array $site_record) {
859   if (!empty($site_record)) {
860     $os = drush_os($site_record);
861     if (isset($site_record['#env-vars'])) {
862       foreach ($site_record['#env-vars'] as $var => $value) {
863         $env_var = drush_escapeshellarg($var, $os, TRUE) . '=' . drush_escapeshellarg($value, $os, TRUE);
864         putenv($env_var);
865       }
866     }
867   }
868 }