X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fdrush%2Fdrush%2Fsrc%2FBoot%2FBootstrapManager.php;fp=vendor%2Fdrush%2Fdrush%2Fsrc%2FBoot%2FBootstrapManager.php;h=b24fd2f492667c0dc3743a5aa5c8dba0cb51077a;hp=0000000000000000000000000000000000000000;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0 diff --git a/vendor/drush/drush/src/Boot/BootstrapManager.php b/vendor/drush/drush/src/Boot/BootstrapManager.php new file mode 100644 index 000000000..b24fd2f49 --- /dev/null +++ b/vendor/drush/drush/src/Boot/BootstrapManager.php @@ -0,0 +1,517 @@ +defaultBootstrapObject = $default; + + // Reset our bootstrap phase to the beginning + drush_set_context('DRUSH_BOOTSTRAP_PHASE', DRUSH_BOOTSTRAP_NONE); + } + + /** + * Add a bootstrap object to the list of candidates + * + * @param \Drush\Boot\Boot|Array + * List of boot candidates + */ + public function add($candidateList) + { + foreach (func_get_args() as $candidate) { + $this->bootstrapCandidates[] = $candidate; + } + } + + public function drupalFinder() + { + if (!isset($this->drupalFinder)) { + $this->drupalFinder = new DrupalFinder(); + } + return $this->drupalFinder; + } + + public function setDrupalFinder(DrupalFinder $drupalFinder) + { + $this->drupalFinder = $drupalFinder; + } + + /** + * Return the framework root selected by the user. + */ + public function getRoot() + { + return $this->drupalFinder()->getDrupalRoot(); + } + + /** + * Return the composer root for the selected Drupal site. + */ + public function getComposerRoot() + { + return $this->drupalFinder()->getComposerRoot(); + } + + public function locateRoot($root, $start_path = null) + { + // TODO: Throw if we already bootstrapped a framework? + + if (!isset($root)) { + $root = $this->getConfig()->cwd(); + } + if (!$this->drupalFinder()->locateRoot($root)) { + // echo ' Drush must be executed within a Drupal site.'. PHP_EOL; + // exit(1); + } + } + + /** + * Return the framework uri selected by the user. + */ + public function getUri() + { + return $this->uri; + } + + /** + * This method is called by the Application iff the user + * did not explicitly provide a URI. + */ + public function selectUri($cwd) + { + $uri = $this->bootstrap()->findUri($this->getRoot(), $cwd); + $this->setUri($uri); + return $uri; + } + + public function setUri($uri) + { + // TODO: Throw if we already bootstrapped a framework? + // n.b. site-install needs to set the uri. + $this->uri = $uri; + if ($this->bootstrap) { + $this->bootstrap->setUri($this->getUri()); + } + } + + /** + * Return the bootstrap object in use. This will + * be the latched bootstrap object if we have started + * bootstrapping; otherwise, it will be whichever bootstrap + * object is best for the selected root. + * + * @return \Drush\Boot\Boot + */ + public function bootstrap() + { + if ($this->bootstrap) { + return $this->bootstrap; + } + return $this->selectBootstrapClass(); + } + + /** + * Look up the best bootstrap class for the given location + * from the set of available candidates. + * + * @return \Drush\Boot\Boot + */ + public function bootstrapObjectForRoot($path) + { + foreach ($this->bootstrapCandidates as $candidate) { + if ($candidate->validRoot($path)) { + // This is not necessary when the autoloader is inflected + // TODO: The autoloader is inflected in the symfony dispatch, but not the traditional Drush dispatcher + if ($candidate instanceof AutoloaderAwareInterface) { + $candidate->setAutoloader($this->autoloader()); + } + $candidate->setUri($this->getUri()); + return $candidate; + } + } + return null; + } + + /** + * 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 'latched', and further calls to Drush::bootstrapf() + * will always return the same object. + */ + protected function selectBootstrapClass() + { + // Once we have selected a Drupal root, we will reduce our bootstrap + // candidates down to just the one used to select this site root. + $bootstrap = $this->bootstrapObjectForRoot($this->getRoot()); + // If we have not found a bootstrap class by this point, + // then return our default bootstrap object. The default bootstrap object + // should pass through all calls without doing anything that + // changes state in a CMS-specific way. + if ($bootstrap == null) { + $bootstrap = $this->defaultBootstrapObject; + } + + return $bootstrap; + } + + /** + * Once bootstrapping has started, we stash the bootstrap + * object being used, and do not allow it to change any + * longer. + */ + public function latch($bootstrap) + { + $this->bootstrap = $bootstrap; + } + + /** + * Returns an array that determines what bootstrap phases + * are necessary to bootstrap the CMS. + * + * @param bool $function_names + * (optional) If TRUE, return an array of method names index by their + * corresponding phase values. Otherwise return an array of phase values. + * + * @return array + * + * @see \Drush\Boot\Boot::bootstrapPhases() + */ + public function bootstrapPhases($function_names = false) + { + $result = []; + + if ($bootstrap = $this->bootstrap()) { + $result = $bootstrap->bootstrapPhases(); + if (!$function_names) { + $result = array_keys($result); + } + } + return $result; + } + + /** + * Bootstrap Drush to the desired phase. + * + * This function will sequentially bootstrap each + * lower phase up to the phase that has been requested. + * + * @param int $phase + * The bootstrap phase to bootstrap to. + * @param int $phase_max + * (optional) The maximum level to boot to. This does not have a use in this + * function itself but can be useful for other code called from within this + * function, to know if e.g. a caller is in the process of booting to the + * specified level. If specified, it should never be lower than $phase. + * @param \Consolidation\AnnotatedCommand\AnnotationData $annotationData + * Optional annotation data from the command. + * + * @return bool + * TRUE if the specified bootstrap phase has completed. + * + * @see \Drush\Boot\Boot::bootstrapPhases() + */ + public function doBootstrap($phase, $phase_max = false, AnnotationData $annotationData = null) + { + $bootstrap = $this->bootstrap(); + $phases = $this->bootstrapPhases(true); + $result = true; + + // If the requested phase does not exist in the list of available + // phases, it means that the command requires bootstrap to a certain + // level, but no site root could be found. + if (!isset($phases[$phase])) { + $result = drush_bootstrap_error('DRUSH_NO_SITE', dt("We could not find an applicable site for that command.")); + } + + // Once we start bootstrapping past the DRUSH_BOOTSTRAP_DRUSH phase, we + // will latch the bootstrap object, and prevent it from changing. + if ($phase > DRUSH_BOOTSTRAP_DRUSH) { + $this->latch($bootstrap); + } + + drush_set_context('DRUSH_BOOTSTRAPPING', true); + foreach ($phases as $phase_index => $current_phase) { + $bootstrapped_phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE', -1); + if ($phase_index > $phase) { + break; + } + if ($phase_index > $bootstrapped_phase) { + if ($result = $this->bootstrapValidate($phase_index)) { + if (method_exists($bootstrap, $current_phase) && !drush_get_error()) { + $this->logger->log(LogLevel::BOOTSTRAP, 'Drush bootstrap phase: {function}()', ['function' => $current_phase]); + $bootstrap->{$current_phase}($annotationData); + } + drush_set_context('DRUSH_BOOTSTRAP_PHASE', $phase_index); + } + } + } + drush_set_context('DRUSH_BOOTSTRAPPING', false); + if (!$result || drush_get_error()) { + $errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS', []); + foreach ($errors as $code => $message) { + drush_set_error($code, $message); + } + } + return !drush_get_error(); + } + + /** + * Determine whether a given bootstrap phase has been completed + * + * This function name has a typo which makes me laugh so we choose not to + * fix it. Take a deep breath, and smile. See + * http://en.wikipedia.org/wiki/HTTP_referer + * + * + * @param int $phase + * The bootstrap phase to test + * + * @return bool + * TRUE if the specified bootstrap phase has completed. + */ + public function hasBootstrapped($phase) + { + $phase_index = drush_get_context('DRUSH_BOOTSTRAP_PHASE'); + + return isset($phase_index) && ($phase_index >= $phase); + } + + /** + * Validate whether a bootstrap phase can be reached. + * + * This function will validate the settings that will be used + * during the actual bootstrap process, and allow commands to + * progressively bootstrap to the highest level that can be reached. + * + * This function will only run the validation function once, and + * store the result from that execution in a local static. This avoids + * validating phases multiple times. + * + * @param int $phase + * The bootstrap phase to validate to. + * + * @return bool + * TRUE if bootstrap is possible, FALSE if the validation failed. + * + * @see \Drush\Boot\Boot::bootstrapPhases() + */ + public function bootstrapValidate($phase) + { + $bootstrap = $this->bootstrap(); + $phases = $this->bootstrapPhases(true); + static $result_cache = []; + + if (!array_key_exists($phase, $result_cache)) { + drush_set_context('DRUSH_BOOTSTRAP_ERRORS', []); + drush_set_context('DRUSH_BOOTSTRAP_VALUES', []); + + foreach ($phases as $phase_index => $current_phase) { + $validated_phase = drush_get_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', -1); + if ($phase_index > $phase) { + break; + } + if ($phase_index > $validated_phase) { + $current_phase .= 'Validate'; + if (method_exists($bootstrap, $current_phase)) { + $result_cache[$phase_index] = $bootstrap->{$current_phase}(); + } else { + $result_cache[$phase_index] = true; + } + drush_set_context('DRUSH_BOOTSTRAP_VALIDATION_PHASE', $phase_index); + } + } + } + return $result_cache[$phase]; + } + + /** + * Bootstrap to the specified phase. + * + * @param string $bootstrapPhase + * Name of phase to bootstrap to. Will be converted to appropriate index. + * @param \Consolidation\AnnotatedCommand\AnnotationData $annotationData + * Optional annotation data from the command. + * + * @return bool + * TRUE if the specified bootstrap phase has completed. + * + * @throws \Exception + * Thrown when an unknown bootstrap phase is passed in the annotation + * data. + */ + public function bootstrapToPhase($bootstrapPhase, AnnotationData $annotationData = null) + { + $this->logger->log(LogLevel::BOOTSTRAP, 'Bootstrap to {phase}', ['phase' => $bootstrapPhase]); + $phase = $this->bootstrap()->lookUpPhaseIndex($bootstrapPhase); + if (!isset($phase)) { + throw new \Exception(dt('Bootstrap phase !phase unknown.', ['!phase' => $bootstrapPhase])); + } + // Do not attempt to bootstrap to a phase that is unknown to the selected bootstrap object. + $phases = $this->bootstrapPhases(); + if (!array_key_exists($phase, $phases) && ($phase >= 0)) { + return false; + } + return $this->bootstrapToPhaseIndex($phase, $annotationData); + } + + protected function maxPhaseLimit($bootstrap_str) + { + $bootstrap_words = explode(' ', $bootstrap_str); + array_shift($bootstrap_words); + if (empty($bootstrap_words)) { + return null; + } + $stop_phase_name = array_shift($bootstrap_words); + return $this->bootstrap()->lookUpPhaseIndex($stop_phase_name); + } + + /** + * Bootstrap to the specified phase. + * + * @param int $max_phase_index + * Only attempt bootstrap to the specified level. + * @param \Consolidation\AnnotatedCommand\AnnotationData $annotationData + * Optional annotation data from the command. + * + * @return bool + * TRUE if the specified bootstrap phase has completed. + */ + public function bootstrapToPhaseIndex($max_phase_index, AnnotationData $annotationData = null) + { + if ($max_phase_index == DRUSH_BOOTSTRAP_MAX) { + // Try get a max phase. + $bootstrap_str = $annotationData->get('bootstrap'); + $stop_phase = $this->maxPhaseLimit($bootstrap_str); + $this->bootstrapMax($stop_phase); + return true; + } + + $this->logger->log(LogLevel::BOOTSTRAP, 'Drush bootstrap phase {phase}', ['phase' => $max_phase_index]); + $phases = $this->bootstrapPhases(); + $result = true; + + // Try to bootstrap to the maximum possible level, without generating errors + foreach ($phases as $phase_index) { + if ($phase_index > $max_phase_index) { + // Stop trying, since we achieved what was specified. + break; + } + + $this->logger->log(LogLevel::BOOTSTRAP, 'Try to validate bootstrap phase {phase}', ['phase' => $max_phase_index]); + + if ($this->bootstrapValidate($phase_index)) { + if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE', DRUSH_BOOTSTRAP_NONE)) { + $this->logger->log(LogLevel::BOOTSTRAP, 'Try to bootstrap at phase {phase}', ['phase' => $max_phase_index]); + $result = $this->doBootstrap($phase_index, $max_phase_index, $annotationData); + } + } else { + $this->logger->log(LogLevel::BOOTSTRAP, 'Could not bootstrap at phase {phase}', ['phase' => $max_phase_index]); + $result = false; + break; + } + } + + return $result; + } + + /** + * Bootstrap to the highest level possible, without triggering any errors. + * + * @param int $max_phase_index + * (optional) Only attempt bootstrap to the specified level. + * @param \Consolidation\AnnotatedCommand\AnnotationData $annotationData + * Optional annotation data from the command. + * + * @return int + * The maximum phase to which we bootstrapped. + */ + public function bootstrapMax($max_phase_index = false, AnnotationData $annotationData = null) + { + // Bootstrap as far as we can without throwing an error, but log for + // debugging purposes. + + $phases = $this->bootstrapPhases(true); + if (!$max_phase_index) { + $max_phase_index = count($phases); + } + + if ($max_phase_index >= count($phases)) { + $this->logger->log(LogLevel::DEBUG, 'Trying to bootstrap as far as we can'); + } + + // Try to bootstrap to the maximum possible level, without generating errors. + foreach ($phases as $phase_index => $current_phase) { + if ($phase_index > $max_phase_index) { + // Stop trying, since we achieved what was specified. + break; + } + + if ($this->bootstrapValidate($phase_index)) { + if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) { + $this->doBootstrap($phase_index, $max_phase_index, $annotationData); + } + } else { + // $this->bootstrapValidate() only logs successful validations. For us, + // knowing what failed can also be important. + $previous = drush_get_context('DRUSH_BOOTSTRAP_PHASE'); + $this->logger->log(LogLevel::DEBUG, 'Bootstrap phase {function}() failed to validate; continuing at {current}()', ['function' => $current_phase, 'current' => $phases[$previous]]); + break; + } + } + + return drush_get_context('DRUSH_BOOTSTRAP_PHASE'); + } +}