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.

Functions

Namesort descending Description
drush_bootstrap Bootstrap Drush to the desired phase.
drush_bootstrap_error Helper function to collect any errors that occur during the bootstrap process. Always returns FALSE, for convenience.
drush_bootstrap_max Bootstrap to the highest level possible, without triggering any errors.
drush_bootstrap_validate Validate whether a bootstrap phases can be reached.
drush_bootstrap_value Helper function to store any context settings that are being validated.
drush_cwd Returns the current working directory.
drush_error_handler Log PHP errors to the Drush log. This is in effect until Drupal's error handler takes over.
drush_find_drush Determine a proper way to call drush again
drush_get_projects Get complete information for all available modules and themes.
drush_get_project_status Calculate a project status based on current status and schema version.
drush_is_local_host Make a determination whether or not the given host is local or not.
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
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_bootstrap_do_drupal_site Called by _drush_bootstrap_drupal_site to do the main work of the drush drupal site bootstrap.
_drush_bootstrap_drupal_configuration Initialize and load the Drupal configuration files.
_drush_bootstrap_drupal_database Boostrap the Drupal database.
_drush_bootstrap_drupal_database_validate Validate the DRUSH_BOOTSTRAP_DRUPAL_DATABASE phase
_drush_bootstrap_drupal_full Attempt to load the full Drupal system.
_drush_bootstrap_drupal_login Log into the bootstrapped Drupal site with a specific username or user id.
_drush_bootstrap_drupal_root Bootstrap Drush with a valid Drupal Directory.
_drush_bootstrap_drupal_root_validate Validate the DRUSH_BOOTSTRAP_DRUPAL_ROOT phase.
_drush_bootstrap_drupal_site Initialize a site on the Drupal root.
_drush_bootstrap_drupal_site_validate VALIDATE the DRUSH_BOOTSTRAP_DRUPAL_SITE phase.
_drush_bootstrap_drush Initial Drush bootstrap phase.
_drush_bootstrap_drush_validate Validate initial Drush bootstrap phase.
_drush_bootstrap_global_options
_drush_bootstrap_phases Helper function listing phases.
_drush_bootstrap_redo_drupal_site Re-do the drupal site bootstrap (and possibly the drupal root bootstrap) if a site alias was processed after the site bootstrap phase completed. This will happen when processing "drush sitealias command" for a site alias defined in a…
_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_shift_path_up Returns parent directory.

Constants

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