bootstrap.inc

  1. 8.0.x tests/bootstrap.inc
  2. 8.0.x includes/bootstrap.inc
  3. 6.x includes/bootstrap.inc
  4. 7.x tests/bootstrap.inc
  5. 7.x includes/bootstrap.inc
  6. 5.x includes/bootstrap.inc
  7. master includes/bootstrap.inc
  8. master tests/bootstrap.inc

Functions

Namesort descending Description
drush_autoload Used by a Drush extension to request that its Composer autoload files be loaded by Drush, if they have not already been.
drush_bootstrap Bootstrap Drush to the desired phase.
drush_bootstrap_class_for_root
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_max_to_sitealias Bootstrap the specified site alias. The site alias must be a valid alias to a local site.
drush_bootstrap_to_phase Bootstrap to the specified phase.
drush_bootstrap_validate Validate whether a bootstrap phase can be reached.
drush_bootstrap_value Helper function to store any context settings that are being validated.
drush_get_bootstrap_candidates Return the list of bootstrap objects that are available for initializing a CMS with Drush. We insure that any given candidate class is instantiated only once.
drush_get_bootstrap_candidate_classnames Find the list of bootstrap classnames available for initializing a CMS with Drush.
drush_get_bootstrap_object Get the appropriate bootstrap object. We'll search for a new bootstrap object every time someone asks for one until we start bootstrapping; then we'll returned the same cached one every time.
drush_has_boostrapped Determine whether a given bootstrap phase has been completed
drush_latch_bootstrap_object Don't allow the bootstrap object to change once we start bootstrapping
drush_select_bootstrap_class Select the bootstrap class to use. If this is called multiple times, the bootstrap class returned might change on subsequent calls, if the root directory changes. Once the bootstrap object starts changing the state of the system, however, it will be…
_drush_bootstrap_output_prepare
_drush_bootstrap_phases Helper function listing phases.
_drush_bootstrap_selected_uri Find the URI that has been selected by the cwd if it was not previously set via the --uri / -l option

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 @deprecated
DRUSH_BOOTSTRAP_MAX Use drush_bootstrap_max instead of drush_bootstrap_to_phase
DRUSH_BOOTSTRAP_NONE No bootstrap.

File

includes/bootstrap.inc
View source
  1. <?php
  2. use Drush\Log\LogLevel;
  3. /**
  4. * No bootstrap.
  5. *
  6. * Commands that only preflight, but do not bootstrap, should use
  7. * a bootstrap level of DRUSH_BOOTSTRAP_NONE.
  8. */
  9. define('DRUSH_BOOTSTRAP_NONE', -1);
  10. /**
  11. * Use drush_bootstrap_max instead of drush_bootstrap_to_phase
  12. *
  13. * This constant is only usable as the value of the 'bootstrap'
  14. * item of a command object, or as the parameter to
  15. * drush_bootstrap_to_phase. It is not a real bootstrap state.
  16. */
  17. define('DRUSH_BOOTSTRAP_MAX', -2);
  18. /**
  19. * @deprecated
  20. *
  21. * No longer used, but 0 remains reserved. Drush always runs preflight.
  22. * Commands may alternatively use DRUSH_BOOTSTRAP_NONE.
  23. */
  24. define('DRUSH_BOOTSTRAP_DRUSH', 0);
  25. // TODO: Move all of the constants below to a Drupal-specific file.
  26. // We can't do this until commands are declaring which CMS they work
  27. // with, because right now, commands that do not declare a 'bootstrap'
  28. // level default to DRUSH_BOOTSTRAP_DRUPAL_LOGIN, so we need this constant,
  29. // at least, available in non-Drupal contexts.
  30. /**
  31. * Set up and test for a valid drupal root, either through the -r/--root options,
  32. * or evaluated based on the current working directory.
  33. *
  34. * Any code that interacts with an entire Drupal installation, and not a specific
  35. * site on the Drupal installation should use this bootstrap phase.
  36. */
  37. define('DRUSH_BOOTSTRAP_DRUPAL_ROOT', 1);
  38. /**
  39. * Set up a Drupal site directory and the correct environment variables to
  40. * allow Drupal to find the configuration file.
  41. *
  42. * If no site is specified with the -l / --uri options, Drush will assume the
  43. * site is 'default', which mimics Drupal's behaviour.
  44. *
  45. * If you want to avoid this behaviour, it is recommended that you use the
  46. * DRUSH_BOOTSTRAP_DRUPAL_ROOT bootstrap phase instead.
  47. *
  48. * Any code that needs to modify or interact with a specific Drupal site's
  49. * settings.php file should bootstrap to this phase.
  50. */
  51. define('DRUSH_BOOTSTRAP_DRUPAL_SITE', 2);
  52. /**
  53. * Load the settings from the Drupal sites directory.
  54. *
  55. * This phase is analagous to the DRUPAL_BOOTSTRAP_CONFIGURATION bootstrap phase in Drupal
  56. * itself, and this is also the first step where Drupal specific code is included.
  57. *
  58. * This phase is commonly used for code that interacts with the Drupal install API,
  59. * as both install.php and update.php start at this phase.
  60. */
  61. define('DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION', 3);
  62. /**
  63. * Connect to the Drupal database using the database credentials loaded
  64. * during the previous bootstrap phase.
  65. *
  66. * This phase is analogous to the DRUPAL_BOOTSTRAP_DATABASE bootstrap phase in
  67. * Drupal.
  68. *
  69. * Any code that needs to interact with the Drupal database API needs to
  70. * be bootstrapped to at least this phase.
  71. */
  72. define('DRUSH_BOOTSTRAP_DRUPAL_DATABASE', 4);
  73. /**
  74. * Fully initialize Drupal.
  75. *
  76. * This is analogous to the DRUPAL_BOOTSTRAP_FULL bootstrap phase in
  77. * Drupal.
  78. *
  79. * Any code that interacts with the general Drupal API should be
  80. * bootstrapped to this phase.
  81. */
  82. define('DRUSH_BOOTSTRAP_DRUPAL_FULL', 5);
  83. /**
  84. * Log in to the initialiased Drupal site.
  85. *
  86. * This is the default bootstrap phase all commands will try to reach,
  87. * unless otherwise specified.
  88. *
  89. * This bootstrap phase is used after the site has been
  90. * fully bootstrapped.
  91. *
  92. * This phase will log you in to the drupal site with the username
  93. * or user ID specified by the --user/ -u option.
  94. *
  95. * Use this bootstrap phase for your command if you need to have access
  96. * to information for a specific user, such as listing nodes that might
  97. * be different based on who is logged in.
  98. */
  99. define('DRUSH_BOOTSTRAP_DRUPAL_LOGIN', 6);
  100. /**
  101. * Return the list of bootstrap objects that are available for
  102. * initializing a CMS with Drush. We insure that any given candidate
  103. * class is instantiated only once.
  104. *
  105. * @return \Drush\Boot\Boot[]
  106. */
  107. function drush_get_bootstrap_candidates() {
  108. $candidate_classes = drush_get_bootstrap_candidate_classnames();
  109. $cache =& drush_get_context('DRUSH_BOOTSTRAP_CANDIDATE_OBJECTS');
  110. $result = array();
  111. foreach($candidate_classes as $candidate_class) {
  112. if (array_key_exists($candidate_class, $cache)) {
  113. $result[$candidate_class] = $cache[$candidate_class];
  114. }
  115. else {
  116. $result[$candidate_class] = new $candidate_class;
  117. }
  118. }
  119. $cache = $result;
  120. return $result;
  121. }
  122. /**
  123. * Find the list of bootstrap classnames available for initializing a
  124. * CMS with Drush.
  125. *
  126. * @return array
  127. */
  128. function drush_get_bootstrap_candidate_classnames() {
  129. // Give all commandfiles a chance to return candidates. They should
  130. // return STRINGS with the class name of the bootstrap object they provide.
  131. $candidates = drush_command_invoke_all('bootstrap_candidates');
  132. // If a bootstrap class was specified on the command line, consider it first.
  133. $bootstrap_class = drush_get_option('bootstrap_class', FALSE);
  134. if ($bootstrap_class) {
  135. array_unshift($candidates, $bootstrap_class);
  136. }
  137. // Add candidate bootstrap classes for Drupal
  138. foreach (array('8', '7', '6') as $version) {
  139. $drupal_bootstrap_class = 'Drush\Boot\DrupalBoot' . $version;
  140. $candidates[] = $drupal_bootstrap_class;
  141. }
  142. // Always consider our default bootstrap class last.
  143. $candidates[] = 'Drush\Boot\EmptyBoot';
  144. return $candidates;
  145. }
  146. function drush_bootstrap_class_for_root($path) {
  147. $candidates = drush_get_bootstrap_candidates();
  148. foreach ($candidates as $candidate) {
  149. if ($candidate->valid_root($path)) {
  150. return $candidate;
  151. }
  152. }
  153. return NULL;
  154. }
  155. /**
  156. * Select the bootstrap class to use. If this is called multiple
  157. * times, the bootstrap class returned might change on subsequent
  158. * calls, if the root directory changes. Once the bootstrap object
  159. * starts changing the state of the system, however, it will
  160. * be 'latched', and further calls to drush_select_bootstrap_class()
  161. * will always return the same object.
  162. */
  163. function drush_select_bootstrap_class() {
  164. $root = drush_get_context('DRUSH_SELECTED_DRUPAL_ROOT');
  165. // Once we have selected a Drupal root, we will reduce our bootstrap
  166. // candidates down to just the one used to select this site root.
  167. $bootstrap = drush_bootstrap_class_for_root($root);
  168. // If we have not found a bootstrap class by this point,
  169. // then take the last one and use it. This should be our
  170. // default bootstrap class. The default bootstrap class
  171. // should pass through all calls without doing anything that
  172. // changes state in a CMS-specific way.
  173. if ($bootstrap == NULL) {
  174. $candidates = drush_get_bootstrap_candidates();
  175. $bootstrap = array_pop($candidates);
  176. }
  177. return $bootstrap;
  178. }
  179. /**
  180. * Don't allow the bootstrap object to change once we start bootstrapping
  181. */
  182. function drush_latch_bootstrap_object($bootstrap) {
  183. drush_set_context('DRUSH_BOOTSTRAP_OBJECT', $bootstrap);
  184. }
  185. /**
  186. * Get the appropriate bootstrap object. We'll search for a new
  187. * bootstrap object every time someone asks for one until we start
  188. * bootstrapping; then we'll returned the same cached one every time.
  189. */
  190. function drush_get_bootstrap_object() {
  191. $bootstrap = drush_get_context('DRUSH_BOOTSTRAP_OBJECT', FALSE);
  192. if (!$bootstrap) {
  193. $bootstrap = drush_select_bootstrap_class();
  194. }
  195. return $bootstrap;
  196. }
  197. /**
  198. * Find the URI that has been selected by the cwd
  199. * if it was not previously set via the --uri / -l option
  200. */
  201. function _drush_bootstrap_selected_uri() {
  202. $uri = drush_get_context('DRUSH_SELECTED_URI');
  203. if (empty($uri)) {
  204. $site_path = drush_site_path();
  205. $elements = explode('/', $site_path);
  206. $current = array_pop($elements);
  207. if (!$current) {
  208. $current = 'default';
  209. }
  210. $uri = 'http://'. $current;
  211. $uri = drush_set_context('DRUSH_SELECTED_URI', $uri);
  212. drush_sitealias_create_self_alias();
  213. }
  214. return $uri;
  215. }
  216. /**
  217. * Helper function to store any context settings that are being validated.
  218. */
  219. function drush_bootstrap_value($context, $value = null) {
  220. $values =& drush_get_context('DRUSH_BOOTSTRAP_VALUES', array());
  221. if (isset($value)) {
  222. $values[$context] = $value;
  223. }
  224. if (array_key_exists($context, $values)) {
  225. return $values[$context];
  226. }
  227. return null;
  228. }
  229. /**
  230. * Helper function listing phases.
  231. *
  232. * For commands that need to iterate through the phases, such as help
  233. */
  234. function _drush_bootstrap_phases($function_names = FALSE) {
  235. $result = array();
  236. if ($bootstrap = drush_get_bootstrap_object()) {
  237. $result = $bootstrap->bootstrap_phases();
  238. if (!$function_names) {
  239. $result = array_keys($result);
  240. }
  241. }
  242. return $result;
  243. }
  244. /**
  245. * Bootstrap Drush to the desired phase.
  246. *
  247. * This function will sequentially bootstrap each
  248. * lower phase up to the phase that has been requested.
  249. *
  250. * @param phase
  251. * The bootstrap phase to bootstrap to. @see \Drush\Boot::bootstrap_phases
  252. */
  253. function drush_bootstrap($phase, $phase_max = FALSE) {
  254. $bootstrap = drush_get_bootstrap_object();
  255. $phases = _drush_bootstrap_phases(TRUE);
  256. $result = TRUE;
  257. // If the requested phase does not exist in the list of available
  258. // phases, it means that the command requires bootstrap to a certain
  259. // level, but no site root could be found.
  260. if (!isset($phases[$phase])) {
  261. $result = drush_bootstrap_error('DRUSH_NO_SITE', dt("We could not find an applicable site for that command."));
  262. }
  263. // Once we start bootstrapping past the DRUSH_BOOTSTRAP_DRUSH phase, we
  264. // will latch the bootstrap object, and prevent it from changing.
  265. if ($phase > DRUSH_BOOTSTRAP_DRUSH) {
  266. drush_latch_bootstrap_object($bootstrap);
  267. }
  268. drush_set_context('DRUSH_BOOTSTRAPPING', TRUE);
  269. foreach ($phases as $phase_index => $current_phase) {
  270. $bootstrapped_phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE', -1);
  271. if ($phase_index > $phase) {
  272. break;
  273. }
  274. if ($phase_index > $bootstrapped_phase) {
  275. if ($result = drush_bootstrap_validate($phase_index)) {
  276. if (method_exists($bootstrap, $current_phase) && !drush_get_error()) {
  277. drush_log(dt("Drush bootstrap phase : !function()", array('!function' => $current_phase)), LogLevel::BOOTSTRAP);
  278. $bootstrap->{$current_phase}();
  279. // Reset commandfile cache and find any new command files that are available during this bootstrap phase.
  280. drush_get_commands(TRUE);
  281. _drush_find_commandfiles($phase_index, $phase_max);
  282. }
  283. drush_set_context('DRUSH_BOOTSTRAP_PHASE', $phase_index);
  284. }
  285. }
  286. }
  287. drush_set_context('DRUSH_BOOTSTRAPPING', FALSE);
  288. if (!$result || drush_get_error()) {
  289. $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS', array());
  290. foreach ($errors as $code => $message) {
  291. drush_set_error($code, $message);
  292. }
  293. }
  294. return !drush_get_error();
  295. }
  296. /**
  297. * Determine whether a given bootstrap phase has been completed
  298. *
  299. * This function name has a typo which makes me laugh so we choose not to
  300. * fix it. Take a deep breath, and smile. See
  301. * http://en.wikipedia.org/wiki/HTTP_referer
  302. *
  303. *
  304. * @param phase
  305. * The bootstrap phase to test
  306. *
  307. * @returns
  308. * TRUE if the specified bootstrap phase has completed.
  309. */
  310. function drush_has_boostrapped($phase) {
  311. $phase_index = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  312. return isset($phase_index) && ($phase_index >= $phase);
  313. }
  314. /**
  315. * Validate whether a bootstrap phase can be reached.
  316. *
  317. * This function will validate the settings that will be used
  318. * during the actual bootstrap process, and allow commands to
  319. * progressively bootstrap to the highest level that can be reached.
  320. *
  321. * This function will only run the validation function once, and
  322. * store the result from that execution in a local static. This avoids
  323. * validating phases multiple times.
  324. *
  325. * @param phase
  326. * The bootstrap phase to validate to. @see \Drush\Boot::bootstrap_phases
  327. *
  328. * @return
  329. * True if bootstrap is possible, False if the validation failed.
  330. *
  331. */
  332. function drush_bootstrap_validate($phase) {
  333. $bootstrap = drush_get_bootstrap_object();
  334. $phases = _drush_bootstrap_phases(TRUE);
  335. static $result_cache = array();
  336. if (!array_key_exists($phase, $result_cache)) {
  337. drush_set_context('DRUSH_BOOTSTRAP_ERRORS', array());
  338. drush_set_context('DRUSH_BOOTSTRAP_VALUES', array());
  339. foreach ($phases as $phase_index => $current_phase) {
  340. $validated_phase = drush_get_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', -1);
  341. if ($phase_index > $phase) {
  342. break;
  343. }
  344. if ($phase_index > $validated_phase) {
  345. $current_phase .= '_validate';
  346. if (method_exists($bootstrap, $current_phase)) {
  347. $result_cache[$phase_index] = $bootstrap->{$current_phase}();
  348. }
  349. else {
  350. $result_cache[$phase_index] = TRUE;
  351. }
  352. drush_set_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', $phase_index);
  353. }
  354. }
  355. }
  356. return $result_cache[$phase];
  357. }
  358. /**
  359. * Bootstrap to the specified phase.
  360. *
  361. * @param $max_phase_index
  362. * Only attempt bootstrap to the specified level.
  363. */
  364. function drush_bootstrap_to_phase($max_phase_index) {
  365. // If $max_phase_index is DRUSH_BOOTSTRAP_MAX, then
  366. // we will bootstrap as far as we can. drush_bootstrap_max
  367. // is different than drush_bootstrap_to_phase in that
  368. // it is not an error if DRUSH_BOOTSTRAP_LOGIN is not reached.
  369. if ($max_phase_index == DRUSH_BOOTSTRAP_MAX) {
  370. drush_bootstrap_max();
  371. return TRUE;
  372. }
  373. drush_log(dt("Bootstrap to phase !phase.", array('!phase' => $max_phase_index)), LogLevel::BOOTSTRAP);
  374. $phases = _drush_bootstrap_phases();
  375. $result = TRUE;
  376. // Try to bootstrap to the maximum possible level, without generating errors
  377. foreach ($phases as $phase_index) {
  378. if ($phase_index > $max_phase_index) {
  379. // Stop trying, since we achieved what was specified.
  380. break;
  381. }
  382. if (drush_bootstrap_validate($phase_index)) {
  383. if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE', DRUSH_BOOTSTRAP_NONE)) {
  384. $result = drush_bootstrap($phase_index, $max_phase_index);
  385. }
  386. }
  387. else {
  388. $result = FALSE;
  389. break;
  390. }
  391. }
  392. return $result;
  393. }
  394. /**
  395. * Bootstrap to the highest level possible, without triggering any errors.
  396. *
  397. * @param $max_phase_index
  398. * Only attempt bootstrap to the specified level.
  399. *
  400. * @return int
  401. * The maximum phase to which we bootstrapped.
  402. */
  403. function drush_bootstrap_max($max_phase_index = FALSE) {
  404. $phases = _drush_bootstrap_phases();
  405. $phase_index = DRUSH_BOOTSTRAP_DRUSH;
  406. if (!$max_phase_index) {
  407. $max_phase_index = count($phases);
  408. }
  409. // Try to bootstrap to the maximum possible level, without generating errors
  410. foreach ($phases as $phase_index) {
  411. if ($phase_index > $max_phase_index) {
  412. // Stop trying, since we achieved what was specified.
  413. break;
  414. }
  415. if (drush_bootstrap_validate($phase_index)) {
  416. if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
  417. drush_bootstrap($phase_index, $max_phase_index);
  418. }
  419. }
  420. else {
  421. break;
  422. }
  423. }
  424. return drush_get_context('DRUSH_BOOTSTRAP_PHASE');
  425. }
  426. /**
  427. * Bootstrap the specified site alias. The site alias must
  428. * be a valid alias to a local site.
  429. *
  430. * @param $site_record
  431. * The alias record for the given site alias.
  432. * @see drush_sitealias_get_record().
  433. * @param $max_phase_index
  434. * Only attempt bootstrap to the specified level.
  435. * @returns TRUE if attempted to bootstrap, or FALSE
  436. * if no bootstrap attempt was made.
  437. */
  438. function drush_bootstrap_max_to_sitealias($site_record, $max_phase_index = NULL) {
  439. if ((array_key_exists('root', $site_record) && !array_key_exists('remote-host', $site_record))) {
  440. drush_sitealias_set_alias_context($site_record);
  441. drush_bootstrap_max($max_phase_index);
  442. return TRUE;
  443. }
  444. return FALSE;
  445. }
  446. /**
  447. * Helper function to collect any errors that occur during the bootstrap process.
  448. * Always returns FALSE, for convenience.
  449. */
  450. function drush_bootstrap_error($code, $message = null) {
  451. $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS');
  452. $errors[$code] = $message;
  453. drush_set_context('DRUSH_BOOTSTRAP_ERRORS', $errors);
  454. return FALSE;
  455. }
  456. function _drush_bootstrap_output_prepare() {
  457. // Note that as soon as we set the DRUSH_BACKEND context, we change
  458. // the behavior of drush_log(). It is therefore important that we
  459. // should not set this context until immediately before we call ob_start
  460. // (i.e., in this function).
  461. $backend = drush_set_context('DRUSH_BACKEND', drush_get_option('backend'));
  462. $quiet = drush_get_context('DRUSH_QUIET');
  463. if ($backend) {
  464. // Load options passed as a JSON encoded string through STDIN.
  465. $stdin_options = _drush_backend_get_stdin();
  466. if (is_array($stdin_options)) {
  467. drush_set_context('stdin', $stdin_options);
  468. }
  469. // Add an output buffer handler to collect output/pass through backend
  470. // packets. Using a chunksize of 2 ensures that each line is flushed
  471. // straight away.
  472. if ($quiet) {
  473. // Pass through of backend packets, discard regular output.
  474. ob_start('drush_backend_output_discard', 2);
  475. }
  476. else {
  477. // Collect output.
  478. ob_start('drush_backend_output_collect', 2);
  479. }
  480. }
  481. // In non-backend quiet mode we start buffering and discards it on command
  482. // completion.
  483. if ($quiet && !$backend) {
  484. ob_start();
  485. }
  486. }
  487. /**
  488. * Used by a Drush extension to request that its Composer autoload
  489. * files be loaded by Drush, if they have not already been.
  490. *
  491. * Usage:
  492. *
  493. * function mycommandfile_drush_init() {
  494. * drush_autoload(__FILE__)
  495. * }
  496. *
  497. */
  498. function drush_autoload($commandfile) {
  499. $already_added = commandfiles_cache()->add($commandfile);
  500. $dir = dirname($commandfile);
  501. $candidates = array("vendor/autoload.php", "../../../vendor/autoload.php");
  502. $drush_autoload_file = drush_get_context('DRUSH_VENDOR_PATH', '');
  503. foreach ($candidates as $candidate) {
  504. $autoload = $dir . '/' . $candidate;
  505. if (file_exists($autoload) && (realpath($autoload) != $drush_autoload_file)) {
  506. include $autoload;
  507. }
  508. }
  509. }