diff --git a/core/lib/Drupal/Core/Updater/Module.php b/core/lib/Drupal/Core/Updater/Module.php index acc3028..078f991 100644 --- a/core/lib/Drupal/Core/Updater/Module.php +++ b/core/lib/Drupal/Core/Updater/Module.php @@ -31,6 +31,14 @@ class Module extends Updater implements UpdaterInterface { public function getInstallDirectory() { if ($relative_path = drupal_get_path('module', $this->name)) { $relative_path = dirname($relative_path); + $project_name = $this->getProjectName($relative_path); + do { + // Some projects keep their .info file in a subdirectory of their root + // directory, e.g., modules/MODULE/MODULE/MODULE.info. To find + // the appropriate directory to install the module in, we repeatedly + // ascend to the parent directory until the project name differs. + $relative_path = dirname($relative_path); + } while ($this->getProjectName($relative_path) == $project_name); } else { $relative_path = 'modules'; diff --git a/core/lib/Drupal/Core/Updater/Theme.php b/core/lib/Drupal/Core/Updater/Theme.php index 4bd716a..58ff830 100644 --- a/core/lib/Drupal/Core/Updater/Theme.php +++ b/core/lib/Drupal/Core/Updater/Theme.php @@ -31,6 +31,14 @@ class Theme extends Updater implements UpdaterInterface { public function getInstallDirectory() { if ($relative_path = drupal_get_path('theme', $this->name)) { $relative_path = dirname($relative_path); + $project_name = $this->getProjectName($relative_path); + do { + // Some projects keep their .info file in a subdirectory of their root + // directory, e.g., themes/THEME/THEME/THEME.info. To find + // the appropriate directory to install the theme in, we repeatedly + // ascend to the parent directory until the project name differs. + $relative_path = dirname($relative_path); + } while ($this->getProjectName($relative_path) == $project_name); } else { $relative_path = 'themes'; diff --git a/core/modules/update/lib/Drupal/update/Tests/UpdateContribTest.php b/core/modules/update/lib/Drupal/update/Tests/UpdateContribTest.php index af7d035..880d4fc 100644 --- a/core/modules/update/lib/Drupal/update/Tests/UpdateContribTest.php +++ b/core/modules/update/lib/Drupal/update/Tests/UpdateContribTest.php @@ -17,7 +17,7 @@ class UpdateContribTest extends UpdateTestBase { * * @var array */ - public static $modules = array('update_test', 'update', 'aaa_update_test', 'bbb_update_test', 'ccc_update_test'); + public static $modules = array('update_test', 'update', 'aaa_update_test', 'bbb_update_test', 'ccc_update_test', 'ddd_update_test', 'ddd_ui_update_test'); public static function getInfo() { return array( @@ -133,6 +133,20 @@ function testUpdateContribOrder() { 'version' => '8.x-1.0', 'hidden' => FALSE, ), + + // This should be its own project, and listed third on the report. + 'ddd_update_test' => array( + 'project' => 'ddd_update_test', + 'version' => '8.x-1.0', + 'hidden' => FALSE, + ), + + // This should be part of the "DDD Update test" project + 'ddd_ui_update_test' => array( + 'project' => 'ddd_update_test', + 'version' => '8.x-1.0', + 'hidden' => FALSE, + ), ); config('update_test.settings')->set('system_info', $system_info)->save(); $this->refreshUpdateStatus(array('drupal' => '0', '#all' => '1_0')); @@ -140,17 +154,21 @@ function testUpdateContribOrder() { // We're expecting the report to say all projects are up to date. $this->assertText(t('Up to date')); $this->assertNoText(t('Update available')); - // We want to see all 3 module names listed, since they'll show up either + // We want to see all 5 module names listed, since they'll show up either // as project names or as modules under the "Includes" listing. $this->assertText(t('AAA Update test')); $this->assertText(t('BBB Update test')); $this->assertText(t('CCC Update test')); + $this->assertText(t('DDD Update test')); + $this->assertText(t('DDD UI Update test')); // We want aaa_update_test included in the ccc_update_test project, not as // its own project on the report. $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project does not appear.'); - // The other two should be listed as projects. + $this->assertNoRaw(l(t('DDD UI Update test'), 'http://example.com/project/ddd_ui_update_test'), 'Link to ddd_ui_update_test project does not appear.'); + // The other three should be listed as projects. $this->assertRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), 'Link to bbb_update_test project appears.'); $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), 'Link to bbb_update_test project appears.'); + $this->assertRaw(l(t('DDD Update test'), 'http://example.com/project/ddd_update_test'), 'Link to ddd_update_test project appears.'); // We want to make sure we see the BBB project before the CCC project. // Instead of just searching for 'BBB Update test' or something, we want @@ -285,6 +303,16 @@ function testUpdateBrokenFetchURL() { 'version' => '8.x-1.0', 'hidden' => FALSE, ), + 'ddd_update_test' => array( + 'project' => 'ddd_update_test', + 'version' => '8.x-1.0', + 'hidden' => FALSE, + ), + 'ddd_ui_update_test' => array( + 'project' => 'ddd_update_test', + 'version' => '8.x-1.0', + 'hidden' => FALSE, + ), ); config('update_test.settings')->set('system_info', $system_info)->save(); @@ -293,6 +321,8 @@ function testUpdateBrokenFetchURL() { 'aaa_update_test' => '1_0', 'bbb_update_test' => 'does-not-exist', 'ccc_update_test' => '1_0', + 'ddd_update_test' => '1_0', + 'ddd_ui_update_test' => '1_0', ); $this->refreshUpdateStatus($xml_mapping); @@ -309,13 +339,14 @@ function testUpdateBrokenFetchURL() { $this->assertRaw('