Index: modules/simpletest/tests/requirements1_test.info
===================================================================
RCS file: modules/simpletest/tests/requirements1_test.info
diff -N modules/simpletest/tests/requirements1_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements1_test.info	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,9 @@
+; $Id$
+name = Requirements 1 Test
+description = "Tests that a module is not installed when it fails hook_requirements('install')."
+package = Core
+version = VERSION
+core = 7.x
+files[] = requirements1_test.install
+files[] = requirements1_test.module
+hidden = TRUE
Index: modules/simpletest/tests/requirements1_test.install
===================================================================
RCS file: modules/simpletest/tests/requirements1_test.install
diff -N modules/simpletest/tests/requirements1_test.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements1_test.install	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,22 @@
+<?php
+// $Id$
+
+/**
+ * Implements hook_requirements().
+ */
+function requirements1_test_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break at install time.
+  $t = get_t();
+
+  // Always fails requirements.
+  if ('install' == $phase) {
+    $requirements['requirements1_test'] = array(
+      'title' => $t('Requirements 1 Test'),
+      'severity' => REQUIREMENT_ERROR,
+      'description' => $t('Requirements 1 Test failed requirements.'),
+    );
+  }
+
+  return $requirements;
+}
Index: modules/simpletest/tests/requirements1_test.module
===================================================================
RCS file: modules/simpletest/tests/requirements1_test.module
diff -N modules/simpletest/tests/requirements1_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements1_test.module	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,8 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests that a module is not installed when it fails
+ * hook_requirements('install').
+ */
Index: modules/simpletest/tests/requirements2_test.info
===================================================================
RCS file: modules/simpletest/tests/requirements2_test.info
diff -N modules/simpletest/tests/requirements2_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements2_test.info	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,10 @@
+; $Id$
+name = Requirements 2 Test
+description = "Tests that a module is not installed when the one it depends on fails hook_requirements('install)."
+dependencies[] = requirements1_test
+dependencies[] = comment
+package = Core
+version = VERSION
+core = 7.x
+files[] = requirements2_test.module
+hidden = TRUE
Index: modules/simpletest/tests/requirements2_test.module
===================================================================
RCS file: modules/simpletest/tests/requirements2_test.module
diff -N modules/simpletest/tests/requirements2_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/requirements2_test.module	22 Apr 2010 22:34:12 -0000
@@ -0,0 +1,8 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests that a module is not installed when the one it depends on fails
+ * hook_requirements('install').
+ */
Index: modules/simpletest/tests/system_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/system_test.module,v
retrieving revision 1.25
diff -u -p -r1.25 system_test.module
--- modules/simpletest/tests/system_test.module	17 Feb 2010 22:44:52 -0000	1.25
+++ modules/simpletest/tests/system_test.module	22 Apr 2010 22:34:12 -0000
@@ -231,6 +231,9 @@ function system_test_system_info_alter(&
   if ($file->name == 'system_dependencies_test') {
     $info['hidden'] = FALSE;
   }
+  if ($file->name == 'requirements1_test' || $file->name == 'requirements2_test') {
+    $info['hidden'] = FALSE;
+  }
 }
 
 /**
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.268
diff -u -p -r1.268 system.admin.inc
--- modules/system/system.admin.inc	22 Apr 2010 09:54:26 -0000	1.268
+++ modules/system/system.admin.inc	22 Apr 2010 22:34:12 -0000
@@ -1074,7 +1074,7 @@ function system_modules_confirm_form($mo
   $form['validation_modules'] = array('#type' => 'value', '#value' => $modules);
   $form['status']['#tree'] = TRUE;
 
-  foreach ($storage['more_modules'] as $info) {
+  foreach ($storage['more_required'] as $info) {
     $t_argument = array(
       '@module' => $info['name'],
       '@required' => implode(', ', $info['requires']),
@@ -1110,9 +1110,12 @@ function system_modules_confirm_form($mo
  */
 function system_modules_submit($form, &$form_state) {
   include_once DRUPAL_ROOT . '/includes/install.inc';
+
+  // Builds list of modules.
   $modules = array();
   // If we're not coming from the confirmation form, build the list of modules.
   if (empty($form_state['storage'])) {
+    // If we're not coming from the confirmation form, build the module list.
     foreach ($form_state['values']['modules'] as $group_name => $group) {
       foreach ($group as $module => $enabled) {
         $modules[$module] = array('group' => $group_name, 'enabled' => $enabled['enable']);
@@ -1125,114 +1128,108 @@ function system_modules_submit($form, &$
     $modules = $form_state['storage']['modules'];
   }
 
-  // Get a list of all modules, it will be used to find which module requires
-  // which.
+  // Collect data for all modules to be able to determine dependencies.
   $files = system_rebuild_module_data();
 
-  // The modules to be enabled.
-  $modules_to_be_enabled = array();
-  // The modules to be disabled.
-  $disable_modules = array();
-  // The modules to be installed.
-  $new_modules = array();
-  // Modules that need to be switched on because other modules require them.
-  $more_modules = array();
-  $missing_modules = array();
+  // Sorts modules by weight.
+  $sort = array();
+  foreach (array_keys($modules) as $module) {
+    $sort[$module] = $files[$module]->sort;
+  }
+  array_multisort($sort, $modules);
 
-  // Go through each module, finding out if we should enable, install, or
-  // disable it. Also, we find out if there are modules it requires that are
-  // not enabled.
+  // Makes sure all required modules are set to be enabled.
+  $more_required = array();
+  $missing_modules = array();
   foreach ($modules as $name => $module) {
-    // If it's enabled, find out whether to just
-    // enable it, or install it.
     if ($module['enabled']) {
-      if (drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
-        $new_modules[$name] = $name;
-      }
-      elseif (!module_exists($name)) {
-        $modules_to_be_enabled[$name] = $name;
-      }
-
-      // If we're not coming from a confirmation form, search for modules the
-      // new ones require and see whether there are any that additionally
-      // need to be switched on.
-      if (empty($form_state['storage'])) {
-        foreach ($form['modules'][$module['group']][$name]['#requires'] as $requires => $v) {
-          if (!isset($files[$requires])) {
-            // The required module is missing, mark this module as disabled.
-            $missing_modules[$requires]['depends'][] = $name;
-            $modules[$name]['enabled'] = FALSE;
+      // Checks that all dependencies are set to be enabled.  Stores the ones
+      // that are not in $dependencies variable so that the user can be alerted
+      // in the confirmation form that more modules need to be enabled.
+      $dependencies = array();
+      foreach (array_keys($files[$name]->requires) as $required) {
+        if (empty($modules[$required]['enabled'])) {
+          if (isset($files[$required])) {
+            $dependencies[] = $files[$required]->info['name'];
+            $modules[$required]['enabled'] = TRUE;
           }
           else {
-            if (!$modules[$requires]['enabled']) {
-              if (!isset($more_modules[$name])) {
-                $more_modules[$name]['name'] = $files[$name]->info['name'];
-              }
-              $more_modules[$name]['requires'][$requires] = $files[$requires]->info['name'];
-            }
-            $modules[$requires] = array('group' => $files[$requires]->info['package'], 'enabled' => TRUE);
+            $missing_modules[$required]['depends'][] = $name;
+            $modules[$name]['enabled'] = FALSE;
           }
         }
       }
-    }
-  }
-  // A second loop is necessary, otherwise the modules set to be enabled in the
-  // previous loop would not be found.
-  foreach ($modules as $name => $module) {
-    if (module_exists($name) && !$module['enabled']) {
-      $disable_modules[$name] = $name;
+
+      // Stores additional modules that need to be enabled in $more_required.
+      if (!empty($dependencies)) {
+        $more_required[$name] = array(
+          'name' => $files[$name]->info['name'],
+          'requires' => $dependencies,
+        );
+      }
     }
   }
 
-  if ($more_modules || $missing_modules) {
-    // If we need to switch on more modules because other modules require
-    // them and they haven't confirmed, don't process the submission yet. Store
-    // the form submission data needed later.
+  // Redirects to confirmation form if more modules need to be enabled.
+  if ((!empty($more_required) || !empty($missing_modules)) && !isset($form_state['values']['confirm'])) {
     $form_state['storage'] = array(
-      'more_modules' => $more_modules,
+      'more_required' => $more_required,
+      'modules' => $modules,
       'missing_modules' => $missing_modules,
-      'modules' => $modules
     );
     $form_state['rebuild'] = TRUE;
     return;
   }
 
-  $old_module_list = module_list();
+  // Invokes hook_requirements('install').  If failures are detected, makes sure
+  // the dependent modules aren't installed either.
+  foreach ($modules as $name => $module) {
+    // Only invoke hook_requirements() on modules that are going to be installed.
+    if ($module['enabled'] && drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
+      if (!drupal_check_module($name)) {
+        $modules[$name]['enabled'] = FALSE;
+        foreach (array_keys($files[$name]->required_by) as $required_by) {
+          $modules[$required_by]['enabled'] = FALSE;
+        }
+      }
+    }
+  }
+
+  // Initializes array of actions.
+  $actions = array(
+    'enable' => array(),
+    'disable' => array(),
+    'install' => array(),
+  );
 
-  // Enable the modules needing enabling.
-  if (!empty($modules_to_be_enabled)) {
-    $sort = array();
-    foreach ($modules_to_be_enabled as $module) {
-      $sort[$module] = $files[$module]->sort;
-    }
-    array_multisort($sort, SORT_DESC, $modules_to_be_enabled);
-    module_enable($modules_to_be_enabled, FALSE);
-  }
-  // Disable the modules that need disabling.
-  if (!empty($disable_modules)) {
-    $sort = array();
-    foreach ($disable_modules as $module) {
-      $sort[$module] = $files[$module]->sort;
-    }
-    array_multisort($sort, SORT_ASC, $disable_modules);
-    module_disable($disable_modules, FALSE);
-  }
-
-  // Install new modules.
-  if (!empty($new_modules)) {
-    $sort = array();
-    foreach ($new_modules as $key => $module) {
-      if (!drupal_check_module($module)) {
-        unset($new_modules[$key]);
+  // Builds arrays of modules that need to be enabled, disabled, and installed.
+  foreach ($modules as $name => $module) {
+    if ($module['enabled']) {
+      if (drupal_get_installed_schema_version($name) == SCHEMA_UNINSTALLED) {
+        $actions['install'][] = $name;
+      }
+      elseif (!module_exists($name)) {
+        $actions['enable'][] = $name;
       }
-      $sort[$module] = $files[$module]->sort;
     }
-    array_multisort($sort, SORT_DESC, $new_modules);
-    module_enable($new_modules, FALSE);
+    elseif (module_exists($name)) {
+      $actions['disable'][] = $name;
+    }
   }
 
-  $current_module_list = module_list(TRUE);
-  if ($old_module_list != $current_module_list) {
+  // Gets list of modules prior to install process, unsets $form_state['storage']
+  // so we don't get redirected back to the confirmation form.
+  $pre_install_list = module_list();
+  unset($form_state['storage']);
+
+  // Installs, enables, and disables modules.
+  module_enable($actions['enable']);
+  module_disable($actions['disable']);
+  module_enable($actions['install']);
+
+  // Gets module list after install process, displays message if there are changes.
+  $post_install_list = module_list(TRUE);
+  if ($pre_install_list != $post_install_list) {
     drupal_set_message(t('The configuration options have been saved.'));
   }
 
@@ -1253,7 +1250,7 @@ function system_modules_submit($form, &$
   // Notify locale module about module changes, so translations can be
   // imported. This might start a batch, and only return to the redirect
   // path after that.
-  module_invoke('locale', 'system_update', $new_modules);
+  module_invoke('locale', 'system_update', $actions['install']);
 
   // Synchronize to catch any actions that were added or removed.
   actions_synchronize();
Index: modules/system/system.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.test,v
retrieving revision 1.124
diff -u -p -r1.124 system.test
--- modules/system/system.test	20 Apr 2010 09:48:06 -0000	1.124
+++ modules/system/system.test	22 Apr 2010 22:34:12 -0000
@@ -170,6 +170,35 @@ class EnableDisableTestCase extends Modu
 }
 
 /**
+ * Tests failure of hook_requirements('install').
+ */
+class HookRequirementsTestCase extends ModuleTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Requirements hook failure',
+      'description' => "Attempts enabling a module that fails hook_requirements('install').",
+      'group' => 'Module',
+    );
+  }
+
+  /**
+   * Assert that a module cannot be installed if it fails hook_requirements().
+   */
+  function testHookRequirementsFailure() {
+    $this->assertModules(array('requirements1_test'), FALSE);
+
+    // Attempt to install the requirements1_test module.
+    $edit = array();
+    $edit['modules[Core][requirements1_test][enable]'] = 'requirements1_test';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+
+    // Makes sure the module was NOT installed.
+    $this->assertText(t('Requirements 1 Test failed requirements'), t('Modules status has been updated.'));
+    $this->assertModules(array('requirements1_test'), FALSE);
+  }
+}
+
+/**
  * Test module dependency functionality.
  */
 class ModuleDependencyTestCase extends ModuleTestCase {
@@ -232,6 +261,30 @@ class ModuleDependencyTestCase extends M
     // Verify that the module has been disabled.
     $this->assertModules(array('system_dependencies_test'), FALSE);
   }
+
+  /**
+   * Tests enabling a module that depends on a module which fails hook_requirements().
+   */
+  function testEnableRequirementsFailureDependency() {
+    $this->assertModules(array('requirements1_test'), FALSE);
+    $this->assertModules(array('requirements2_test'), FALSE);
+
+    // Attempt to install both modules at the same time.
+    $edit = array();
+    $edit['modules[Core][requirements1_test][enable]'] = 'requirements1_test';
+    $edit['modules[Core][requirements2_test][enable]'] = 'requirements2_test';
+    $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+
+    // Makes sure the modules were NOT installed.
+    $this->assertText(t('Requirements 1 Test failed requirements'), t('Modules status has been updated.'));
+    $this->assertModules(array('requirements1_test'), FALSE);
+    $this->assertModules(array('requirements2_test'), FALSE);
+
+    // Makes sure that already enabled modules the failing modules depend on
+    // were not disabled.
+    $this->assertModules(array('comment'), TRUE);
+
+  }
 }
 
 /**
