cvs diff: Diffing modules/update
Index: modules/update/update.api.php
===================================================================
RCS file: /Users/wright/drupal/local_repo/drupal/modules/update/update.api.php,v
retrieving revision 1.5
diff -u -p -r1.5 update.api.php
--- modules/update/update.api.php	30 Apr 2010 16:27:02 -0000	1.5
+++ modules/update/update.api.php	5 Dec 2010 18:21:22 -0000
@@ -115,16 +115,18 @@ function hook_update_status_alter(&$proj
  *   The directory that the archive was extracted into.
  *
  * @return
- *   If there is a problem, return any non-null value. If there is no problem,
- *   don't return anything (null).
+ *   If there are any problems, return an array of error messages. If there are
+ *   no problems, return an empty array.
  *
  * @see update_manager_archive_verify()
  */
 function hook_verify_update_archive($project, $archive_file, $directory) {
+  $errors = array();
   if (!file_exists($directory)) {
-    return TRUE;
+    $errors[] = t('The %directory does not exist.', array('%directory' => $directory));
   }
   // Add other checks on the archive integrity here.
+  return $errors;
 }
 
 /**
Index: modules/update/update.manager.inc
===================================================================
RCS file: /Users/wright/drupal/local_repo/drupal/modules/update/update.manager.inc,v
retrieving revision 1.28
diff -u -p -r1.28 update.manager.inc
--- modules/update/update.manager.inc	1 Dec 2010 07:02:14 -0000	1.28
+++ modules/update/update.manager.inc	5 Dec 2010 18:25:52 -0000
@@ -557,11 +557,16 @@ function update_manager_install_form_sub
   // Unfortunately, we can only use the directory name for this. :(
   $project = drupal_substr($files[0], 0, -1);
 
-  try {
-    update_manager_archive_verify($project, $local_cache, $directory);
-  }
-  catch (Exception $e) {
-    form_set_error($field, $e->getMessage());
+  $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
+  if (!empty($archive_errors)) {
+    form_set_error($field, array_shift($archive_errors));
+    // @todo: Fix me in D8: We need a way to set multiple errors on the same
+    // form element and have all of them appear!
+    if (!empty($archive_errors)) {
+      foreach ($archive_errors as $error) {
+        drupal_set_message($error, 'error');
+      }
+    }
     return;
   }
 
@@ -682,15 +687,13 @@ function update_manager_archive_extract(
  * @param string $directory
  *   The directory that the archive was extracted into.
  *
- * @return void
- * @throws Exception on failure.
+ * @return array
+ *   An array of error messages to display if the archive was invalid. If
+ *   there are no errors, it will be an empty array.
  *
  */
 function update_manager_archive_verify($project, $archive_file, $directory) {
-  $failures = module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
-  if (!empty($failures)) {
-    throw new Exception(t('Unable to extract %file', array('%file' => $archive_file)));
-  }
+  return module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
 }
 
 /**
@@ -770,11 +773,13 @@ function update_manager_batch_project_ge
   }
 
   // Verify it.
-  try {
-    update_manager_archive_verify($project, $local_cache, $extract_directory);
-  }
-  catch (Exception $e) {
-    $context['results']['errors'][$project] = $e->getMessage();
+  $archive_errors = update_manager_archive_verify($project, $local_cache, $extract_directory);
+  if (!empty($archive_errors)) {
+    // We just need to make sure our array keys don't collide, so use the
+    // numeric keys from the $archive_errors array.
+    foreach ($archive_errors as $key => $error) {
+      $context['results']['errors']["$project-$key"] = $error;
+    }
     return;
   }
 
Index: modules/update/update.module
===================================================================
RCS file: /Users/wright/drupal/local_repo/drupal/modules/update/update.module,v
retrieving revision 1.70
diff -u -p -r1.70 update.module
--- modules/update/update.module	6 Oct 2010 13:36:30 -0000	1.70
+++ modules/update/update.module	5 Dec 2010 18:37:31 -0000
@@ -641,6 +641,81 @@ function theme_update_last_check($variab
 }
 
 /**
+ * Implements hook_verify_update_archive().
+ *
+ * First, we ensure that the archive isn't a copy of Drupal core, which the
+ * Update manager does not yet support. @see http://drupal.org/node/606592
+ *
+ * Then, we make sure that every module included in the archive has an info
+ * file.
+ *
+ * Finally, we check that all the .info files claim the code is compatible
+ * with the current version of Drupal core.
+ *
+ * @see drupal_system_listing()
+ * @see _system_rebuild_module_data()
+ */
+function update_verify_update_archive($project, $archive_file, $directory) {
+  $errors = array();
+
+  // Make sure this isn't a tarball of Drupal core.
+  if (
+    file_exists("$directory/$project/index.php")
+    && file_exists("$directory/$project/update.php")
+    && file_exists("$directory/$project/includes/bootstrap.inc")
+    && file_exists("$directory/$project/modules/node/node.module")
+    && file_exists("$directory/$project/modules/system/system.module")
+  ) {
+    return array(
+      'no-core' => t('Automatic updating of Drupal core is not supported. See the <a href="@upgrade-guide">upgrade guide</a> for information on how to update Drupal core manually.', array('@upgrade-guide' => 'http://drupal.org/upgrade')),
+    );
+  }
+
+  // Look for any .module file that doesn't have a corresponding .info file.
+  $missing_info = array();
+  $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', array('key' => 'name', 'min_depth' => 0));
+  foreach ($files as $key => $file) {
+    // If it has no info file, set an error.
+    $info_file = dirname($file->uri) . '/' . $file->name . '.info';
+    if (!file_exists($info_file)) {
+      $missing_info[] = $file->filename;
+    }
+  }
+  if (!empty($missing_info)) {
+    $errors[] = format_plural(
+      count($missing_info),
+      '%archive_file contains %names which is missing an info file.',
+      '%archive_file contains the following modules which are missing info files: %names',
+      array('%archive_file' => basename($archive_file), '%names' => implode(', ', $missing_info))
+    );
+  }
+
+  // Parse all the .info files and make sure they're compatible with this
+  // version of Drupal core.
+  $incompatible = array();
+  $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info/', array('key' => 'name', 'min_depth' => 0));
+  foreach ($files as $key => $file) {
+    // Get the .info file for the module or theme this file belongs to.
+    $info = drupal_parse_info_file($file->uri);
+
+    // If the module or theme is incompatible with Drupal core, set an error.
+    if (empty($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
+      $incompatible[] = $info['name'];
+    }
+  }
+  if (!empty($incompatible)) {
+    $errors[] = format_plural(
+      count($incompatible),
+      '%archive_file contains a version of %names that is not compatible with Drupal !version.',
+      '%archive_file contains versions of modules or themes that are not compatible with Drupal !version: %names',
+      array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => basename($archive_file), '%names' => implode(', ', $incompatible))
+    );
+  }
+
+  return $errors;
+}
+
+/**
  * @defgroup update_status_cache Private update status cache system
  * @{
  *
cvs diff: Diffing modules/update/tests
