If a module fails requirements in hook_requirements('install'), it is not installed. However, modules that depend on this module will still be installed. As an example use case, module B depends on module A. Module A fails hook_requirements('install') when a user attempts to install it. If the user attempts to install module A and module B at the same time, module A will not be installed while module B will be. This could lead to fatal errors and other unwanted behavior as the functions in module A will not be available to module B.

This patch modifies the logic in system_modules_submit() to prevent modules from being installed if they depend on a module that returns errors in hook_requirements('install'). I have unit tests 90% completed that fail when the patch is not applied and succeed when it is. I will post soon. This bug exists in D6 as well, and was discovered in the Search Lucene API module. A lot of extra coding had to be done to get around it.

Thanks,
Chris

Comments

moshe weitzman’s picture

Nice sleuthing. Is there any chance you would refactor this submit handler a bit? It is really hard to follow all the flow. And other code like drush wants to reuse parts of it.

In any case, we look forward to your tests on this.

cpliakas’s picture

Hi Moshe.

Anything to help out the Drush project :-). I agree that the submit handler is due for refactoring, as it took me a while to figure out what was going on. I will take a crack at it and will post for review. In terms of Drush, I am assuming that you are looking for the dependency checking logic within the function, or am I off on this one? Either way, that should probably be broken out into a separate API function anyways IMHO.

Thanks,
Chris

Status: Needs review » Needs work

The last submitted patch failed testing.

cpliakas’s picture

Status: Needs work » Needs review
StatusFileSize
new8.17 KB

Moshe,

I was able to refactor the submit handler so that it is bit more transparent in terms of what it is doing. It also fixes the issue raised by this post. The code is a bit more compartmentalized, so parts can be separated out into API functions if you feel that is the avenue that should be taken. Also, I didn't want to add this in without discussion, but I think it would be helpful to alert the user if a module couldn't be installed because the one it is dependent on fails hook_requirements('install'). I'm not sure if it would be better to simply display a message or not allow the changes to be made. Thanks in advance for your input.

~Chris

cpliakas’s picture

Finally got the unit tests in working order. The attached patch is the same as the one above with unit testing added.

Status: Needs review » Needs work

The last submitted patch failed testing.

cpliakas’s picture

Seems like recent additions broke the patch. Will rework with latest version of HEAD and re-commit.

cpliakas’s picture

Status: Needs work » Needs review
StatusFileSize
new16.1 KB

Refreshed with latest version of HEAD.

sun.core’s picture

Status: Needs review » Needs work

This needs a re-roll.

sun.core’s picture

Status: Needs work » Needs review

#8: system-592800-8.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, system-592800-8.patch, failed testing.

berdir’s picture

StatusFileSize
new12.18 KB

re-roll, this was definitely not trivial, I just hope that we have good test coverage of that function :)

Atleast the module test group passes locally for me...

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new15.32 KB

The patch above was missing the test modules...

sun’s picture

Status: Needs review » Needs work
+++ modules/simpletest/tests/requirements1_test.info
@@ -0,0 +1,9 @@
\ No newline at end of file

+++ modules/simpletest/tests/requirements1_test.install
@@ -0,0 +1,34 @@
\ No newline at end of file

+++ modules/simpletest/tests/requirements1_test.module
@@ -0,0 +1,8 @@
\ No newline at end of file

+++ modules/simpletest/tests/requirements2_test.info
@@ -0,0 +1,9 @@
\ No newline at end of file

+++ modules/simpletest/tests/requirements2_test.module
@@ -0,0 +1,8 @@
\ No newline at end of file

This should not happen.

+++ modules/simpletest/tests/requirements1_test.install
@@ -0,0 +1,34 @@
+/**
+ * Implementation of hook_install().
+ */
+function requirements1_test_install() {
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function requirements1_test_uninstall() {
+}

It seems those can be removed?

+++ modules/simpletest/tests/requirements1_test.install
@@ -0,0 +1,34 @@
+ * Implementation of hook_requirements().

(and elsewhere) The new documentation standard is

Implements hook_HOOK().

+++ modules/simpletest/tests/requirements1_test.install
@@ -0,0 +1,34 @@
+  // Ensure translations don't break at install time
...
+  // Always fails requirements

(and possibly elsewhere) Missing trailing periods.

+++ modules/system/system.admin.inc
@@ -1125,114 +1128,108 @@ function system_modules_submit($form, &$form_state) {
+        $modules[$name]['enabled'] = FALSE;
+        foreach (array_keys($files[$name]->required_by) as $required_by) {
+          $modules[$required_by] = FALSE;
+        }
...
+  foreach ($modules as $name => $module) {
+    if ($module['enabled']) {

The boolean assignment of

$modules[$required_by] = FALSE;

will trigger a PHP notice in the following foreach when trying to access the 'enabled' key.

Not sure why tests didn't throw any exceptions.

Additionally, does this ensure that already enabled modules are not disabled upon attempt to enable a module that requires an already enabled module?

Powered by Dreditor.

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new15.18 KB

Re-roll with the comments updated and unecessary hooks removed.

Additionally, does this ensure that already enabled modules are not disabled upon attempt to enable a module that requires an already enabled module?

I'm not 100% sure that I understood you correctly. I added an additional dependency on comment.module to requirements2_test.module and added a check to confirm that comment.module is still installed after a failed attempt to install requirements2_test.module. Is that what you meant? Then yes, that seems to work correctly.

aufumy’s picture

StatusFileSize
new15.77 KB

changed (from previous patch)
$modules[$required_by] = FALSE;
to
$modules[$required_by]['enabled'] = FALSE;

tested by copying requirements1_test and requirements2_test into sites/all/modules and commenting out "hidden=true", enabled both modules, and neither was enabled, also comments which is listed as a dependency of requirements2_test was not disabled.

aufumy’s picture

MichaelCole’s picture

Priority: Critical » Normal

Why is this issue critical? From the status page: Critical - When a bug renders a module, a core system, or a popular function unusable.

Impact seems limited to extra modules enabled, only if a module fails to install... Am I missing something?

sun’s picture

Priority: Normal » Critical

seems limited to extra modules enabled, only if a module fails to install

Read that again? :) It installs modules that cannot be installed.

cpliakas’s picture

@MichaelCole... Just to further illustrate the use case that prompted this bug report, the core API packages in modules such as Apache Solr and Search Lucene API have dependencies on third party libraries. Therefore, the modules implement hook_requirements() so they are not installed if the third party libraries are not installed.

In Search Lucene API's case, there is a module called Search Lucene Content that depends on Search Lucene API. If you try to install both modules at the same time and Search Lucene API fails requirements because the third party library is not installed, Search Lucene Content will still get installed despite the fact that the module it depends on failed requirements and was NOT installed. Therefore, you have a module that is calling functions that do not exist (because the module it depends on is not installed) which throws fatal errors. To me that warrants a critical bug report not only because of the high probability of fatal errors, but also because Drupal's dependency system isn't doing it's job.

Thanks,
Chris

dries’s picture

+++ modules/simpletest/tests/requirements1_test.install	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,22 @@
Index: modules/simpletest/tests/requirements1_test.module

Index: modules/simpletest/tests/requirements1_test.module
===================================================================

===================================================================
RCS file: modules/simpletest/tests/requirements1_test.module

RCS file: modules/simpletest/tests/requirements1_test.module
diff -N modules/simpletest/tests/requirements1_test.module

diff -N modules/simpletest/tests/requirements1_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000

--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements1_test.module	22 Apr 2010 22:34:12 -0000

+++ modules/simpletest/tests/requirements1_test.module	22 Apr 2010 22:34:12 -0000
+++ modules/simpletest/tests/requirements1_test.module	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,8 @@

@@ -0,0 +1,8 @@
+<?php
+// $Id$
+

RCS file: modules/simpletest/tests/requirements2_test.info
diff -N modules/simpletest/tests/requirements2_test.info

It would be good to add a small code comment as to why this is an 'empty' module.

catch’s picture

Status: Needs review » Needs work
damien tournoud’s picture

Status: Needs work » Reviewed & tested by the community

Not sure which patch was reviewed by Dries. #16 looks good to me and has a comment block in the "empty" modules.

Still apply (with benin fuzz).

dries’s picture

Status: Reviewed & tested by the community » Fixed

I looked at this again, and decided to committed to CVS HEAD. The code looks good, comes with tests, and is, in fact, a small clean-up. Good job.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.