environment.inc

  1. 8.0.x includes/environment.inc
  2. 8.0.x commands/core/drupal/environment.inc
  3. 6.x includes/environment.inc
  4. 6.x commands/core/drupal/environment.inc
  5. 7.x includes/environment.inc
  6. 7.x commands/core/drupal/environment.inc
  7. 3.x includes/environment.inc
  8. 4.x commands/core/drupal/environment.inc
  9. 4.x includes/environment.inc
  10. 5.x commands/core/drupal/environment.inc
  11. 5.x includes/environment.inc
  12. master commands/core/drupal/environment.inc
  13. master includes/environment.inc

Functions used by drush to query the environment and setting the current configuration.

Bootstrapping now occurs in bootstrap.inc.

See also

includes/bootstrap.inc

Functions

Namesort descending Description
drush_bit_bucket
drush_build_drush_command Build a drush command suitable for use for drush to call itself e.g. in backend_invoke.
drush_conf_path This is a copy of Drupal's conf_path function, taken from D7 and adjusted slightly to search from the selected Drupal Root.
drush_cwd Returns the current working directory.
drush_directory_cache The path to the global cache directory.
drush_drupal_required_modules
drush_environment_lib
drush_environment_table_lib
drush_error_handler Log PHP errors to the Drush log. This is in effect until Drupal's error handler takes over.
drush_extension_check_incompatibility Test compatibility of a extension with version of drupal core and php.
drush_find_drush Determine a proper way to call drush again
drush_get_extensions Get complete information for all available extensions (modules and themes).
drush_get_tar_executable
drush_get_username Return the name of the user running drush.
drush_has_bash Checks if the operating system has bash.
drush_is_cygwin 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.
drush_is_local_host Make a determination whether or not the given host is local or not.
drush_is_mingw
drush_is_osx Check if the operating system is OS X. This will return TRUE for Mac OS X (Darwin).
drush_is_windows 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.
drush_locate_root 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.
drush_read_drush_info Read the drush info file.
drush_server_home Return the user's home directory.
drush_site_path Like Drupal conf_path, but searching from beneath. Allows proper site uri detection in site sub-directories.
drush_theme_get_admin Return the administration theme.
drush_theme_get_default Return the default theme.
drush_valid_db_credentials Tests the currently loaded database credentials to ensure a database connection can be made.
drush_valid_drupal_root Checks whether given path qualifies as a Drupal root.
drush_verify_cli Verify that we are running PHP through the command line interface.
_drush_convert_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).
_drush_environment_check_php_ini 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.
_drush_get_os Return the OS we are running under.
_drush_php_ini_loaded_file_message
_drush_postmortem Evalute the environment after an abnormal termination and see if we can determine any configuration settings that the user might want to adjust.
_drush_shift_path_up Returns parent directory.
_drush_test_os

Constants

Namesort descending Description
DRUSH_PEAR_BASE_URL Base URL for automatic file download of PEAR packages.
DRUSH_TABLE_VERSION Supported version of Console Table. This is displayed in the manual install help.

File

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