Issue #1719648 by joachim, ttkaminski, kshama_deshmukh: ModuleInstaller::install() silently fails if a module isn't in the file system
parent
4a6fce7b9a
commit
78e9940a30
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\Core\Extension\MissingDependencyException.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\Extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception class to throw when modules are missing on install.
|
||||||
|
*
|
||||||
|
* @see \Drupal\Core\Extension\ModuleInstaller::install()
|
||||||
|
*/
|
||||||
|
class MissingDependencyException extends \Exception {}
|
|
@ -11,6 +11,7 @@ use Drupal\Component\Serialization\Yaml;
|
||||||
use Drupal\Core\Cache\Cache;
|
use Drupal\Core\Cache\Cache;
|
||||||
use Drupal\Core\Cache\CacheBackendInterface;
|
use Drupal\Core\Cache\CacheBackendInterface;
|
||||||
use Drupal\Core\DrupalKernelInterface;
|
use Drupal\Core\DrupalKernelInterface;
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the module installer.
|
* Default implementation of the module installer.
|
||||||
|
@ -83,9 +84,12 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
||||||
// Get all module data so we can find dependencies and sort.
|
// Get all module data so we can find dependencies and sort.
|
||||||
$module_data = system_rebuild_module_data();
|
$module_data = system_rebuild_module_data();
|
||||||
$module_list = $module_list ? array_combine($module_list, $module_list) : array();
|
$module_list = $module_list ? array_combine($module_list, $module_list) : array();
|
||||||
if (array_diff_key($module_list, $module_data)) {
|
if ($missing_modules = array_diff_key($module_list, $module_data)) {
|
||||||
// One or more of the given modules doesn't exist.
|
// One or more of the given modules doesn't exist.
|
||||||
return FALSE;
|
throw new MissingDependencyException(String::format('Unable to install modules %modules due to missing modules %missing.', array(
|
||||||
|
'%modules' => implode(', ', $module_list),
|
||||||
|
'%missing' => implode(', ', $missing_modules),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only process currently uninstalled modules.
|
// Only process currently uninstalled modules.
|
||||||
|
@ -101,7 +105,10 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
||||||
foreach (array_keys($module_data[$module]->requires) as $dependency) {
|
foreach (array_keys($module_data[$module]->requires) as $dependency) {
|
||||||
if (!isset($module_data[$dependency])) {
|
if (!isset($module_data[$dependency])) {
|
||||||
// The dependency does not exist.
|
// The dependency does not exist.
|
||||||
return FALSE;
|
throw new MissingDependencyException(String::format('Unable to install modules: module %module is missing its dependency module %dependency.', array(
|
||||||
|
'%module' => $module,
|
||||||
|
'%dependency' => $dependency,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip already installed modules.
|
// Skip already installed modules.
|
||||||
|
|
|
@ -31,7 +31,10 @@ interface ModuleInstallerInterface {
|
||||||
* if you know $module_list is already complete.
|
* if you know $module_list is already complete.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* FALSE if one or more dependencies are missing, TRUE otherwise.
|
* TRUE if the modules were successfully installed.
|
||||||
|
*
|
||||||
|
* @throws \Drupal\Core\Extension\MissingDependencyException
|
||||||
|
* Thrown when a requested module, or a dependency of one, can not be found.
|
||||||
*
|
*
|
||||||
* @see hook_module_preinstall()
|
* @see hook_module_preinstall()
|
||||||
* @see hook_install()
|
* @see hook_install()
|
||||||
|
|
|
@ -132,8 +132,7 @@ class ConfigInstallWebTest extends WebTestBase {
|
||||||
// Turn on the test module, which will attempt to replace the
|
// Turn on the test module, which will attempt to replace the
|
||||||
// configuration data. This attempt to replace the active configuration
|
// configuration data. This attempt to replace the active configuration
|
||||||
// should be ignored.
|
// should be ignored.
|
||||||
$status = \Drupal::service('module_installer')->install(array('config_existing_default_config_test'));
|
\Drupal::service('module_installer')->install(array('config_existing_default_config_test'));
|
||||||
$this->assertTrue($status, "The module config_existing_default_config_test was installed.");
|
|
||||||
|
|
||||||
// Verify that the test module has not been able to change the data.
|
// Verify that the test module has not been able to change the data.
|
||||||
$config = $this->config($config_name);
|
$config = $this->config($config_name);
|
||||||
|
|
|
@ -210,7 +210,7 @@ EOD;
|
||||||
* Confirm that the stub test produced the desired results.
|
* Confirm that the stub test produced the desired results.
|
||||||
*/
|
*/
|
||||||
function confirmStubTestResults() {
|
function confirmStubTestResults() {
|
||||||
$this->assertAssertion(t('Enabled modules: %modules', array('%modules' => 'non_existent_module')), 'Other', 'Fail', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->setUp()');
|
$this->assertAssertion(t('Unable to install modules %modules due to missing modules %missing.', array('%modules' => 'non_existent_module', '%missing' => 'non_existent_module')), 'Other', 'Fail', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->setUp()');
|
||||||
|
|
||||||
$this->assertAssertion($this->passMessage, 'Other', 'Pass', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->stubTest()');
|
$this->assertAssertion($this->passMessage, 'Other', 'Pass', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->stubTest()');
|
||||||
$this->assertAssertion($this->failMessage, 'Other', 'Fail', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->stubTest()');
|
$this->assertAssertion($this->failMessage, 'Other', 'Fail', 'SimpleTestTest.php', 'Drupal\simpletest\Tests\SimpleTestTest->stubTest()');
|
||||||
|
|
|
@ -916,8 +916,15 @@ abstract class WebTestBase extends TestBase {
|
||||||
}
|
}
|
||||||
if ($modules) {
|
if ($modules) {
|
||||||
$modules = array_unique($modules);
|
$modules = array_unique($modules);
|
||||||
|
try {
|
||||||
$success = $container->get('module_installer')->install($modules, TRUE);
|
$success = $container->get('module_installer')->install($modules, TRUE);
|
||||||
$this->assertTrue($success, String::format('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
|
$this->assertTrue($success, String::format('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
|
||||||
|
}
|
||||||
|
catch (\Drupal\Core\Extension\MissingDependencyException $e) {
|
||||||
|
// The exception message has all the details.
|
||||||
|
$this->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
$this->rebuildContainer();
|
$this->rebuildContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,10 @@ class ModulesListConfirmForm extends ConfirmFormBase {
|
||||||
|
|
||||||
// Install the given modules.
|
// Install the given modules.
|
||||||
if (!empty($this->modules['install'])) {
|
if (!empty($this->modules['install'])) {
|
||||||
|
// Don't catch the exception that this can throw for missing dependencies:
|
||||||
|
// the form doesn't allow modules with unmet dependencies, so the only way
|
||||||
|
// this can happen is if the filesystem changed between form display and
|
||||||
|
// submit, in which case the user has bigger problems.
|
||||||
$this->moduleInstaller->install(array_keys($this->modules['install']));
|
$this->moduleInstaller->install(array_keys($this->modules['install']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,8 +116,14 @@ class ModuleHandlerTest extends KernelTestBase {
|
||||||
\Drupal::state()->set('module_test.dependency', 'missing dependency');
|
\Drupal::state()->set('module_test.dependency', 'missing dependency');
|
||||||
drupal_static_reset('system_rebuild_module_data');
|
drupal_static_reset('system_rebuild_module_data');
|
||||||
|
|
||||||
|
try {
|
||||||
$result = $this->moduleInstaller()->install(array('color'));
|
$result = $this->moduleInstaller()->install(array('color'));
|
||||||
$this->assertFalse($result, 'ModuleHandler::install() returns FALSE if dependencies are missing.');
|
$this->fail(t('ModuleInstaller::install() throws an exception if dependencies are missing.'));
|
||||||
|
}
|
||||||
|
catch (\Drupal\Core\Extension\MissingDependencyException $e) {
|
||||||
|
$this->pass(t('ModuleInstaller::install() throws an exception if dependencies are missing.'));
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'ModuleHandler::install() aborts if dependencies are missing.');
|
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'ModuleHandler::install() aborts if dependencies are missing.');
|
||||||
|
|
||||||
// Fix the missing dependency.
|
// Fix the missing dependency.
|
||||||
|
|
Loading…
Reference in New Issue