Skip to content

Commit 82a1e24

Browse files
Load the autoloader as soon as the Drupal root is identified. (#2865)
* Load the autoloader as soon as the Drupal root is identified. * Fix some typos related to autoloading. * Create a failing test. * Redispatch if Drupal root changes during bootstrap. * Fix up tests - we need to make a duplicate SUT, just cloning 'web' is insufficient. * Just skip slow test on highest / lowest.
1 parent 160cd16 commit 82a1e24

File tree

8 files changed

+148
-37
lines changed

8 files changed

+148
-37
lines changed

includes/drupal.inc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ use Drush\Drush;
1313
function drush_drupal_load_autoloader($drupal_root) {
1414
static $autoloader = FALSE;
1515

16-
if (!$autoloader) {
17-
$autoloader = require $drupal_root .'/autoload.php';
18-
if ($autoloader === TRUE) {
19-
// The autoloader was already require(). Assume that Drush and Drupal share an autoloader per
20-
// "Point autoload.php to the proper vendor directory" - https://www.drupal.org/node/2404989
21-
$autoloader = drush_get_context('DRUSH_CLASSLOADER');
22-
}
16+
$autoloadFilePath = $drupal_root .'/autoload.php';
17+
if (!$autoloader && file_exists($autoloadFilePath)) {
18+
$autoloader = require $autoloadFilePath;
19+
}
20+
21+
if ($autoloader === TRUE) {
22+
// The autoloader was already required. Assume that Drush and Drupal share an autoloader per
23+
// "Point autoload.php to the proper vendor directory" - https://www.drupal.org/node/2404989
24+
$autoloader = drush_get_context('DRUSH_CLASSLOADER');
2325
}
26+
2427
return $autoloader;
2528
}
2629

includes/preflight.inc

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -497,19 +497,9 @@ function drush_preflight() {
497497
drush_preflight_site();
498498

499499
// Check to see if anything changed during the 'site' preflight
500-
// that might allow us to find our alias record now
500+
// that might allow us to find our alias record now.
501501
if (empty($alias_record)) {
502502
$alias_record = _drush_sitealias_set_context_by_name($target_alias);
503-
504-
// If the site alias settings changed late in the preflight,
505-
// then run the preflight for the root and site contexts again.
506-
if (!empty($alias_record)) {
507-
$remote_host = drush_get_option('remote-host');
508-
if (!isset($remote_host)) {
509-
drush_preflight_root();
510-
drush_preflight_site();
511-
}
512-
}
513503
}
514504

515505
// Fail if we could not find the selected site alias.
@@ -544,6 +534,11 @@ function drush_preflight() {
544534
function drush_preflight_root() {
545535
$root = drush_get_option('root');
546536
Drush::bootstrapManager()->locateRoot($root);
537+
$root = Drush::bootstrapManager()->getRoot();
538+
539+
// Load the autoload file and provide it to the bootstrap manager.
540+
$siteAutoloader = drush_drupal_load_autoloader($root);
541+
Drush::bootstrapManager()->setAutoloader($siteAutoloader);
547542

548543
// Load the config options from Drupal's /drush, ../drush, and sites/all/drush directories,
549544
// even prior to bootstrapping the root.
@@ -799,14 +794,21 @@ function drush_preflight_command_dispatch() {
799794
$args = drush_get_arguments();
800795
$command_name = array_shift($args);
801796
$root = Drush::bootstrapManager()->getRoot();
802-
$local_drush = drush_get_option('drush-script');
803797
$is_local = drush_get_option('local');
804798
$values = NULL;
805-
if (!empty($root) && !empty($local_drush) && empty($is_local)) {
799+
800+
$local_drush = drush_get_option('drush-script');
801+
if (!empty($local_drush)) {
806802
if (!drush_is_absolute_path($local_drush)) {
807803
$local_drush = $root . DIRECTORY_SEPARATOR . $local_drush;
808804
}
809805
$local_drush = realpath($local_drush);
806+
}
807+
808+
$drupal_root_from_alias = drush_get_option('root', $root, 'alias');
809+
$shouldRedispatch = (!empty($root)) && ($root != $drupal_root_from_alias);
810+
811+
if (!empty($root) && !empty($local_drush) && empty($is_local)) {
810812
$this_drush = drush_find_drush();
811813
// If there is a local Drush selected, and it is not the
812814
// same Drush that is currently running, redispatch to it.
@@ -817,18 +819,23 @@ function drush_preflight_command_dispatch() {
817819
// infinite loop.
818820
if (file_exists($local_drush) && !drush_is_nested_directory(dirname($root), $this_drush)) {
819821
$uri = drush_get_context('DRUSH_SELECTED_URI');
820-
$aditional_options = array(
821-
'root' => $root,
822-
);
823-
if (!empty($uri)) {
824-
$aditional_options['uri'] = $uri;
825-
}
826-
// We need to chdir to the Drupal root here, for the
827-
// benefit of the Drush wrapper.
828-
chdir($root);
829-
$values = drush_do_command_redispatch(is_array($command) ? $command : $command_name, $args, NULL, NULL, $local_drush, TRUE, $aditional_options);
822+
$shouldRedispatch = true;
830823
}
831824
}
825+
826+
if ($shouldRedispatch) {
827+
$aditional_options = [
828+
'root' => $drupal_root_from_alias,
829+
];
830+
if (!empty($uri)) {
831+
$aditional_options['uri'] = $uri;
832+
}
833+
// We need to chdir to the Drupal root here, for the
834+
// benefit of the Drush wrapper.
835+
chdir($root);
836+
$values = drush_do_command_redispatch(is_array($command) ? $command : $command_name, $args, NULL, NULL, $local_drush, TRUE, $aditional_options);
837+
}
838+
832839
// If the command sets the 'handle-remote-commands' flag, then we will short-circuit
833840
// remote command dispatching and site-list command dispatching, and always let
834841
// the command handler run on the local machine.

includes/sitealias.inc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,8 +1772,6 @@ function _drush_sitealias_set_context_by_name($alias, $prefix = '') {
17721772
}
17731773

17741774
_drush_sitealias_cache_alias('@self', $site_alias_settings);
1775-
// Change the selected site to match the new --root and --uri, if any were set.
1776-
_drush_preflight_root_uri();
17771775
}
17781776
return $site_alias_settings;
17791777
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
namespace Drush\Boot;
3+
4+
interface AutoloaderAwareInterface
5+
{
6+
public function setAutoloader($loader);
7+
8+
public function autoloader();
9+
10+
public function hasAutoloader();
11+
}

src/Boot/AutoloaderAwareTrait.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
namespace Drush\Boot;
3+
4+
trait AutoloaderAwareTrait
5+
{
6+
protected $loader;
7+
8+
public function setAutoloader($loader)
9+
{
10+
$this->loader = $loader;
11+
}
12+
13+
public function autoloader()
14+
{
15+
return $this->loader;
16+
}
17+
18+
public function hasAutoloader()
19+
{
20+
return isset($this->loader);
21+
}
22+
}

src/Boot/BootstrapManager.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
use Psr\Log\LoggerAwareInterface;
99
use Psr\Log\LoggerAwareTrait;
1010

11-
class BootstrapManager implements LoggerAwareInterface
11+
class BootstrapManager implements LoggerAwareInterface, AutoloaderAwareInterface
1212
{
1313
use LoggerAwareTrait;
14+
use AutoloaderAwareTrait;
1415

1516
/**
1617
* @var DrupalFinder
@@ -137,6 +138,9 @@ public function bootstrapObjectForRoot($path)
137138
{
138139
foreach ($this->bootstrapCandidates as $candidate) {
139140
if ($candidate->validRoot($path)) {
141+
if ($candidate instanceof AutoloaderAwareInterface) {
142+
$candidate->setAutoloader($this->autoloader());
143+
}
140144
return $candidate;
141145
}
142146
}

src/Boot/DrupalBoot8.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
use Drush\Log\LogLevel;
1313

14-
class DrupalBoot8 extends DrupalBoot
14+
class DrupalBoot8 extends DrupalBoot implements AutoloaderAwareInterface
1515
{
16+
use AutoloaderAwareTrait;
1617

1718
/**
1819
* @var \Drupal\Core\DrupalKernelInterface
@@ -40,8 +41,10 @@ public function validRoot($path)
4041

4142
public function getVersion($drupal_root)
4243
{
43-
// Load the autoloader so we can access the class constants.
44-
drush_drupal_load_autoloader($drupal_root);
44+
// Are the class constants available?
45+
if (!$this->hasAutoloader()) {
46+
throw new \Exception('Cannot access Drupal 8 class constants - Drupal autoloader not loaded yet.');
47+
}
4548
// Drush depends on bootstrap being loaded at this point.
4649
require_once $drupal_root .'/core/includes/bootstrap.inc';
4750
if (defined('\Drupal::VERSION')) {
@@ -129,7 +132,7 @@ public function bootstrapDrupalDatabase()
129132
public function bootstrapDrupalConfiguration()
130133
{
131134
$this->request = Request::createFromGlobals();
132-
$classloader = drush_drupal_load_autoloader(DRUPAL_ROOT);
135+
$classloader = $this->autoloader();
133136
// @todo - use Request::create() and then no need to set PHP superglobals
134137
$kernelClass = new \ReflectionClass('\Drupal\Core\DrupalKernel');
135138
if ($kernelClass->hasMethod('addServiceModifier')) {

tests/siteAliasTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,69 @@
88
* @group base
99
*/
1010
class saCase extends CommandUnishTestCase {
11+
/**
12+
* Covers the following responsibilities:
13+
* - Dispatching a Drush command via an alias that is defined in a
14+
* site-local alias file. The target alias points to a different
15+
* Drupal site at a different docroot on the same system.
16+
*/
17+
function testSiteLocalAliasDispatch() {
18+
$sites = $this->setUpDrupal(2, TRUE);
19+
20+
// Make a separate copy of the stage site so that we can test
21+
// to see if we can switch to a separate site via an site-local alias.
22+
$dev_root = $sites['dev']['root'];
23+
$drush_sut = dirname($dev_root);
24+
$other_sut = dirname($drush_sut) . '/drush-other-sut';
25+
$other_root = $other_sut . '/web';
26+
@mkdir($other_sut);
27+
self::recursive_copy($dev_root, $other_root);
28+
29+
if (!file_exists($drush_sut . '/composer.json') || !file_exists($drush_sut . '/composer.lock')) {
30+
$this->markTestSkipped('This test does not run in the highest / lowest configurations.');
31+
}
32+
33+
copy($drush_sut . '/composer.json', $other_sut . '/composer.json');
34+
copy($drush_sut . '/composer.lock', $other_sut . '/composer.lock');
35+
36+
// Hopefully this will run quickly from the cache.
37+
passthru("composer --working-dir=$other_sut install");
38+
39+
$aliasPath = $dev_root . '/drush';
40+
$aliasFile = "$aliasPath/aliases.drushrc.php";
41+
$aliasContents = <<<EOD
42+
<?php
43+
// Written by Unish. This file is safe to delete.
44+
45+
\$aliases["other"] = array (
46+
'root' => '$other_root',
47+
'uri' => 'stage',
48+
);
49+
EOD;
50+
if (!is_dir($aliasPath)) {
51+
mkdir($aliasPath);
52+
}
53+
file_put_contents($aliasFile, $aliasContents);
54+
55+
// Ensure that we can access the 'other' alias from the context
56+
// of the 'dev' site, and that it has the right drupal root.
57+
$options = [
58+
];
59+
$this->drush('sa', array('@other'), $options, '@dev');
60+
$output = $this->getOutput();
61+
$this->assertContains("root: $other_root", $output);
62+
63+
// Ensure that we can get status on the 'other' alias when the
64+
// root of the dev site is provided (to allow Drush to find the 'other' alias)
65+
$options = [
66+
'root' => $dev_root,
67+
'format' => 'yaml',
68+
];
69+
$this->drush('core-status', [], $options, '@other');
70+
$output = $this->getOutput();
71+
$this->assertContains("root: $other_root", $output);
72+
}
73+
1174
/**
1275
* Covers the following responsibilities.
1376
* - Dispatching a Drush command that uses strict option handling

0 commit comments

Comments
 (0)