by chx: Proper recursive dependency checking and ordering module installation in dependency order, so later installed modules can use previously installed module functionality

6.x
Gábor Hojtsy 2007-12-13 10:46:43 +00:00
parent a64e5f38d1
commit 050008410d
3 changed files with 81 additions and 13 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}