? search-settings.patch
? modules/search/t
? sites/default/files
? sites/default/modules
? sites/default/private
? sites/default/settings.php
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.519
diff -u -u -p -r1.519 theme.inc
--- includes/theme.inc	31 Aug 2009 19:50:17 -0000	1.519
+++ includes/theme.inc	4 Sep 2009 15:25:24 -0000
@@ -1914,9 +1914,9 @@ function theme_username($object) {
  * @return
  *   A themed HTML string representing the progress bar.
  */
-function theme_progress_bar($percent, $message) {
+function theme_progress_bar($percent, $message, $class = 'active') {
   $output = '<div id="progress" class="progress">';
-  $output .= '<div class="bar"><div class="filled" style="width: ' . $percent . '%"></div></div>';
+  $output .= '<div class="bar '. $class .'"><div class="filled" style="width: ' . $percent . '%"></div></div>';
   $output .= '<div class="percentage">' . $percent . '%</div>';
   $output .= '<div class="message">' . $message . '</div>';
   $output .= '</div>';
Index: modules/field/modules/field_sql_storage/field_sql_storage.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/field_sql_storage/field_sql_storage.module,v
retrieving revision 1.20
diff -u -u -p -r1.20 field_sql_storage.module
--- modules/field/modules/field_sql_storage/field_sql_storage.module	31 Aug 2009 22:57:54 -0000	1.20
+++ modules/field/modules/field_sql_storage/field_sql_storage.module	4 Sep 2009 15:25:24 -0000
@@ -332,6 +332,7 @@ function field_sql_storage_field_storage
             ->execute();
         }
       }
+   
 
       if (!empty($available_translations)) {
         // Prepare the multi-insert query.
Index: modules/search/search.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.admin.inc,v
retrieving revision 1.11
diff -u -u -p -r1.11 search.admin.inc
--- modules/search/search.admin.inc	29 Aug 2009 21:05:16 -0000	1.11
+++ modules/search/search.admin.inc	4 Sep 2009 15:25:24 -0000
@@ -9,15 +9,23 @@
 /**
  * Menu callback: confirm wiping of the index.
  */
-function search_reindex_confirm() {
-  return confirm_form(array(), t('Are you sure you want to re-index the site?'),
-                  'admin/config/search/settings', t(' The search index is not cleared but systematically updated to reflect the new settings. Searching will continue to work but new content won\'t be indexed until all existing content has been re-indexed. This action cannot be undone.'), t('Re-index site'), t('Cancel'));
+function search_clear_confirm() {
+  $form = search_status_form('content items that will be cleared');
+  $form['status']['#description'] = t("Do you want to clear the search index and cause new and changed content to be re-indexed using cron? Searching will continue to work but new content won't be indexed until all existing content has been re-indexed. This action cannot be undone.");
+  return confirm_form(
+    $form,
+    t('Are you sure you want to clear the search index?'),
+    'admin/config/search/settings',
+    '',
+    t('Clear index'),
+    t('Cancel')
+  );
 }
 
 /**
- * Handler for wipe confirmation
+ * Handler for wipe confirmation.
  */
-function search_reindex_confirm_submit(&$form, &$form_state) {
+function search_clear_confirm_submit(&$form, &$form_state) {
   if ($form['confirm']) {
     search_reindex();
     drupal_set_message(t('The index will be rebuilt.'));
@@ -48,30 +56,54 @@ function _search_get_module_names() {
 }
 
 /**
- * Menu callback; displays the search module settings page.
- *
- * @ingroup forms
- * @see system_settings_form()
- * @see search_admin_settings_submit()
- * @see search_admin_reindex_submit()
+ * Return the search status form, which is used by several of the search forms.
  */
-function search_admin_settings() {
-  // Collect some stats
+function search_status_form($action = 'left to index') {
+  // Collect some stats.
   $remaining = 0;
   $total = 0;
-  foreach(variable_get('search_active_modules', array('node', 'user')) as $module) {
+  foreach (variable_get('search_active_modules', array('node', 'user')) as $module) {
     if ($status = module_invoke($module, 'search_status')) {
       $remaining += $status['remaining'];
       $total += $status['total'];
     }
   }
 
-  $count = format_plural($remaining, 'There is 1 item left to index.', 'There are @count items left to index.');
-  $percentage = ((int)min(100, 100 * ($total - $remaining) / max(1, $total))) . '%';
-  $status = '<p><strong>' . t('%percentage of the site has been indexed.', array('%percentage' => $percentage)) . ' ' . $count . '</strong></p>';
-  $form['status'] = array('#type' => 'fieldset', '#title' => t('Indexing status'));
-  $form['status']['status'] = array('#markup' => $status);
-  $form['status']['wipe'] = array('#type' => 'submit', '#value' => t('Re-index site'), '#submit' => array('search_admin_reindex_submit'));
+  // Return the status form.
+  $count = format_plural($remaining, 'There is 1 item ' . $action . '.', 'There are @count items ' . $action . '.');
+  $percentage = (int) min(100, 100 * ($total - $remaining) / max(1, $total));
+  return array(
+    'status' => array(
+      '#type' => 'fieldset',
+      'progress' => array(
+        '#type' => 'markup',
+        '#markup' => theme('progress_bar', $percentage, $count, 'inactive'),
+      ),
+    ),
+  );
+}
+
+/**
+ * Menu callback; displays the search module settings page.
+ *
+ * @ingroup forms
+ * @see system_settings_form()
+ * @see search_admin_settings_submit()
+ * @see search_admin_clear_submit()
+ * @see search_admin_index_submit()
+ */
+function search_admin_settings() {
+  $form = search_status_form();
+  $form['status']['wipe'] = array(
+    '#type' => 'submit',
+    '#value' => t('Wipe index'),
+    '#submit' => array('search_admin_clear_submit'),
+  );
+  $form['status']['build'] = array(
+    '#type' => 'submit',
+    '#value' => t('Build index now'),
+    '#submit' => array('search_admin_index_submit'),
+  );
 
   $items = drupal_map_assoc(array(10, 20, 50, 100, 200, 500));
 
@@ -156,9 +188,17 @@ function search_admin_settings_submit($f
 }
 
 /**
- * Submit callback.
+ * Submit callback to wipe the search index.
  */
-function search_admin_reindex_submit($form, &$form_state) {
+function search_admin_clear_submit($form, &$form_state) {
   // send the user to the confirmation page
-  $form_state['redirect'] = 'admin/config/search/settings/reindex';
-}
\ No newline at end of file
+  $form_state['redirect'] = 'admin/config/search/settings/clear';
+}
+
+/**
+ * Submit callback to index the search index.
+ */
+function search_admin_index_submit($form, &$form_state) {
+  // send the user to the confirmation page
+  $form_state['redirect'] = 'admin/config/search/settings/index';
+}
Index: modules/search/search.batch.inc
===================================================================
RCS file: modules/search/search.batch.inc
diff -N modules/search/search.batch.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/search/search.batch.inc	4 Sep 2009 15:25:24 -0000
@@ -0,0 +1,121 @@
+<?php
+// $Id: search.admin.inc,v 1.11 2009/08/29 21:05:16 dries Exp $
+
+/**
+ * @file
+ * Batch page callbacks for the search module.
+ */
+
+/**
+ * Menu callback: confirm wiping of the index.
+ */
+function search_batch_index_confirm() {
+  module_load_include('inc', 'search', 'search.admin');
+  $form = search_status_form();
+  $form['status']['#description'] =  t("Do you want to index all new and changed content immediately? The search index is not cleared immediately, but the content is progressively reindexed while you wait. This action is resource intensive and may slow down your site. You do not need to do this here. You typically let cron index your content slowly over time.");
+  return confirm_form(
+    $form,
+    t('Are you sure you want to build the search index now?'),
+    'admin/config/search/settings',
+    '',
+    t('Confirm, this may take a long time'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Handler for build confirmation.
+ */
+function search_batch_index_confirm_submit(&$form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    $operations = array();
+    // Build nodes in chunks, just like cron does.
+    $results = db_query("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0 ORDER BY d.reindex ASC, n.nid ASC");
+    $nids = array();
+    $limit = (int) variable_get('search_cron_limit', 100);
+    while ($node = db_fetch_object($results)) {
+      $nids[] = $node->nid;
+      if (count($nids) >= $limit) {
+        $operations[] = array('search_batch_index', array($nids));
+        $nids = array();
+      }
+    }
+    if (count($nids)) {
+      $operations[] = array('search_batch_index', array($nids));
+    }
+    // When done with all the indexing, update the totals.
+    $operations[] = array('search_batch_done', array());
+
+    // when done redirect to the settings page.
+    $form_state['redirect'] = 'admin/config/search/settings';
+
+    // start the batch
+    $batch = array(
+      'title' => t('Building Search Index'),
+      'operations' => $operations,
+      'finished' => 'search_batch_finished',
+      'file' => drupal_get_path('module', 'search') . '/search.batch.inc',
+      'progress_message' => t('Completed @current of @total.') . ' '. l(t('Cancel'), $form_state['redirect']),
+    );
+    batch_set($batch);
+  }
+}
+
+/**
+ * Batch callback to index a set of nodes.
+ */
+function search_batch_index($nids, &$context) {
+  if (!isset($context['results'])) {
+    $context['results'] = array('attempted' => 0, 'success' => 0);
+  }
+
+  foreach ($nids as $nid) {
+    if (isset($_SESSION['batch-search-stop'])) {
+      // @TODO: how do we stop batch api?
+      return;
+    }
+    $context['results']['attempted'] ++;
+
+    // Build the node body.
+    $node = node_load($nid);
+    $node = node_build_content($node, 'search_index');
+    $node->rendered = drupal_render($node->content);
+
+    $text = '<h1>'. check_plain($node->title) .'</h1>'. $node->rendered;
+
+    // Fetch extra data normally not visible
+    $extra = module_invoke_all('node_update_index', $node);
+    foreach ($extra as $t) {
+      $text .= $t;
+    }
+
+    search_index($node->nid, 'node', $text);
+    $context['results']['success'] ++;
+  }
+}
+
+/**
+ * Batch callback to update the search totals after the last search build is completed.
+ */
+function search_batch_done(&$context) {
+  // Update word IDF (Inverse Document Frequency) counts for all words
+  db_query("DELETE FROM {search_total}");
+  db_query("INSERT INTO {search_total} (word, count) SELECT word, LOG10(1+1/GREATEST(1, SUM(score))) FROM {search_index} GROUP BY word");
+}
+
+/**
+ * Batch callback when search building is finished.
+ */
+function search_batch_finished($success, $results, $operations) {
+  if ($success) {
+    if ($results['success'] == $results['attempted']) {
+      drupal_set_message(t('Finished indexing @success nodes successfully.', array('@success' => $results['success'])));
+    }
+    else {
+      drupal_set_message(t('Finished indexing @success of @attempted successfully.', array('@success' => $results['success'], '@attempt' => $results['attempted'])));
+    }
+  }
+  else {
+    drupal_set_message(t('Finished with an error.'));
+  }
+}
Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.312
diff -u -u -p -r1.312 search.module
--- modules/search/search.module	31 Aug 2009 17:06:09 -0000	1.312
+++ modules/search/search.module	4 Sep 2009 15:25:24 -0000
@@ -201,14 +201,22 @@ function search_menu() {
     'type' => MENU_NORMAL_ITEM,
     'file' => 'search.admin.inc',
   );
-  $items['admin/config/search/settings/reindex'] = array(
+  $items['admin/config/search/settings/clear'] = array(
     'title' => 'Clear index',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('search_reindex_confirm'),
+    'page arguments' => array('search_clear_confirm'),
     'access arguments' => array('administer search'),
     'type' => MENU_CALLBACK,
     'file' => 'search.admin.inc',
   );
+  $items['admin/config/search/settings/index'] = array(
+    'title' => 'Build index',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('search_batch_index_confirm'),
+    'access arguments' => array('administer search'),
+    'type' => MENU_CALLBACK,
+    'file' => 'search.batch.inc',
+  );
   $items['admin/reports/search'] = array(
     'title' => 'Top search phrases',
     'description' => 'View most popular search phrases.',
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.61
diff -u -u -p -r1.61 system.css
--- modules/system/system.css	24 Aug 2009 03:11:34 -0000	1.61
+++ modules/system/system.css	4 Sep 2009 15:25:24 -0000
@@ -428,11 +428,13 @@ html.js .no-js {
   font-weight: bold;
 }
 .progress .bar {
-  background: #fff url(../../misc/progress.gif);
   border: 1px solid #00375a;
   height: 1.5em;
   margin: 0 0.2em;
 }
+.progress .bar.active {
+  background: #fff url(../../misc/progress.gif);
+}
 .progress .filled {
   background: #0072b9;
   height: 1em;
