#194010 by chx: Proper recursive dependency checking and ordering module installation in dependency order, so later installed modules can use previously installed module functionality
parent
a64e5f38d1
commit
050008410d
includes
modules/system
|
@ -301,6 +301,24 @@ function drupal_verify_profile($profile, $locale) {
|
|||
* The modules to install.
|
||||
*/
|
||||
function drupal_install_modules($module_list = array()) {
|
||||
$files = module_rebuild_cache();
|
||||
$module_list = array_flip(array_values($module_list));
|
||||
do {
|
||||
$moved = FALSE;
|
||||
foreach ($module_list as $module => $weight) {
|
||||
$file = $files[$module];
|
||||
if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
|
||||
foreach ($file->info['dependencies'] as $dependency) {
|
||||
if (isset($module_list[$dependency]) && $module_list[$module] < $module_list[$dependency] +1) {
|
||||
$module_list[$module] = $module_list[$dependency] +1;
|
||||
$moved = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ($moved);
|
||||
asort($module_list);
|
||||
$module_list = array_keys($module_list);
|
||||
array_filter($module_list, '_drupal_install_module');
|
||||
module_enable($module_list);
|
||||
}
|
||||
|
|
|
@ -147,30 +147,74 @@ function module_rebuild_cache() {
|
|||
db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap);
|
||||
}
|
||||
}
|
||||
$files = _module_build_dependents($files);
|
||||
$files = _module_build_dependencies($files);
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find dependents; modules that are required by other modules.
|
||||
* Adds an array of dependents to the $file->info array.
|
||||
* Find dependencies any level deep and fill in dependents information too.
|
||||
*
|
||||
* If module A depends on B which in turn depends on C then this function will
|
||||
* add C to the list of modules A depends on. This will be repeated until
|
||||
* module A has a list of all modules it depends on. If it depends on itself,
|
||||
* called a circular dependency, that's marked by adding a nonexistent module,
|
||||
* called -circular- to this list of modules. Because this does not exist,
|
||||
* it'll be impossible to switch module A on.
|
||||
*
|
||||
* Also we fill in a dependents array in $file->info. Using the names above,
|
||||
* the dependents array of module B lists A.
|
||||
*
|
||||
* @param $files
|
||||
* The array of filesystem objects used to rebuild the cache.
|
||||
* @return
|
||||
* The list of files array with dependents added where applicable.
|
||||
* The same array with dependencies and dependents added where applicable.
|
||||
*/
|
||||
function _module_build_dependents($files) {
|
||||
foreach ($files as $filename => $file) {
|
||||
if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
|
||||
foreach ($file->info['dependencies'] as $dependency) {
|
||||
if (!empty($files[$dependency]) && is_array($files[$dependency]->info)) {
|
||||
if (!isset($files[$dependency]->info['dependents'])) {
|
||||
$files[$dependency]->info['dependents'] = array();
|
||||
function _module_build_dependencies($files) {
|
||||
do {
|
||||
$new_dependency = FALSE;
|
||||
foreach ($files as $filename => $file) {
|
||||
// We will modify this object (module A, see doxygen for module A, B, C).
|
||||
$file = &$files[$filename];
|
||||
if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
|
||||
foreach ($file->info['dependencies'] as $dependency_name) {
|
||||
// This is a nonexistent module.
|
||||
if ($dependency_name == '-circular-') {
|
||||
continue;
|
||||
}
|
||||
// $dependency_name is module B (again, see doxygen).
|
||||
$files[$dependency_name]->info['dependents'][$filename] = $filename;
|
||||
$dependency = $files[$dependency_name];
|
||||
if (isset($dependency->info['dependencies']) && is_array($dependency->info['dependencies'])) {
|
||||
// Let's find possible C modules.
|
||||
foreach ($dependency->info['dependencies'] as $candidate) {
|
||||
if (array_search($candidate, $file->info['dependencies']) === FALSE) {
|
||||
// Is this a circular dependency?
|
||||
if ($candidate == $filename) {
|
||||
// As a module name can not contain dashes, this makes
|
||||
// impossible to switch on the module.
|
||||
$candidate = '-circular-';
|
||||
// Do not display the message or add -circular- more than once.
|
||||
if (array_search($candidate, $file->info['dependencies']) !== FALSE) {
|
||||
continue;
|
||||
}
|
||||
drupal_set_message(t('%module is part of a circular dependency. This is not supported and you will not be able to switch it on.', array('%module' => $file->info['name'])), 'error');
|
||||
}
|
||||
else {
|
||||
// We added a new dependency to module A. The next loop will
|
||||
// be able to use this as "B module" thus finding even
|
||||
// deeper dependencies.
|
||||
$new_dependency = TRUE;
|
||||
}
|
||||
$file->info['dependencies'][] = $candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
$files[$dependency]->info['dependents'][] = $filename;
|
||||
}
|
||||
}
|
||||
// Don't forget to break the reference.
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
} while ($new_dependency);
|
||||
return $files;
|
||||
}
|
||||
|
||||
|
|
|
@ -535,6 +535,12 @@ function system_theme_settings_submit($form, &$form_state) {
|
|||
* Recursively check compatability
|
||||
*/
|
||||
function _system_is_incompatible(&$incompatible, $files, $file) {
|
||||
static $seen;
|
||||
// We need to protect ourselves in case of a circular dependency.
|
||||
if (isset($seen[$file->name])) {
|
||||
return isset($incompatible[$file->name]);
|
||||
}
|
||||
$seen[$file->name] = TRUE;
|
||||
if (isset($incompatible[$file->name])) {
|
||||
return TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue