? boo.php
? drush-shebang.txt
? drushscript
? includes/table.inc
Index: drush.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/drush.api.php,v
retrieving revision 1.13
diff -u -p -r1.13 drush.api.php
--- drush.api.php	12 Oct 2010 14:00:25 -0000	1.13
+++ drush.api.php	8 Nov 2010 03:55:02 -0000
@@ -176,24 +176,16 @@ function hook_drush_pm_download_destinat
 }
 
 /**
- * Post-sync sanitization example.  This is equivalent to
+ * Sql-sync sanitization example.  This is equivalent to
  * the built-in --sanitize option of sql-sync, but simplified
  * to only work with default values on Drupal 6 + mysql.
  *
- * We test for both 'sanitize' and 'destination-sanitize'
- * options because we want to allow options set in a site-alias
- * to control the post-sync operations.  The options from the
- * destination alias are applied to the drush options context
- * with the prefix 'destination-'.
- *
- * @see drush_sql_pre_sql_sync().
+ * @see sql_drush_sql_sync_sanitize().
  */
-function drush_hook_pre_sql_sync($source = NULL, $destination = NULL) {
-  if (drush_get_option(array('sanitize', 'destination-sanitize'), FALSE)) {
-    drush_sql_register_post_sync_op('my-sanitize-id',
-      dt('Reset passwords and email addresses in user table'),
-      "update users set pass = MD5('password'), mail = concat('user+', uid, '@localhost') where uid > 0;");
-  }
+function hook_drush_sql_sync_sanitize($source) {
+  drush_sql_register_post_sync_op('my-sanitize-id',
+    dt('Reset passwords and email addresses in user table'),
+    "update users set pass = MD5('password'), mail = concat('user+', uid, '@localhost') where uid > 0;");
 }
 
 /**
Index: commands/sql/sql.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/sql/sql.drush.inc,v
retrieving revision 1.58
diff -u -p -r1.58 sql.drush.inc
--- commands/sql/sql.drush.inc	6 Nov 2010 05:20:33 -0000	1.58
+++ commands/sql/sql.drush.inc	8 Nov 2010 03:55:03 -0000
@@ -132,6 +132,7 @@ function sql_drush_command() {
       '--sanitize' => array(
         '--sanitize-password' => 'The password to assign to all accounts in the sanitization operation, or "no" to keep passwords unchanged.  Default is "password".',
         '--sanitize-email' => 'The username for test email addresses in the sanitization operation, or "no" to keep email addresses unchanged.  May contain replacement patterns %uid, %mail or %login.  Default is "user+%uid@localhost".',
+        '--confirm-sanitizations' => 'Prompt yes/no after importing the database, but before running the sanitizations',
       ),
     ),
   );
@@ -712,4 +713,4 @@ function drush_sql_build_exec($db_spec, 
       break;
   }
   return $exec;
-}
\ No newline at end of file
+}
Index: commands/sql/sync.sql.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/sql/sync.sql.inc,v
retrieving revision 1.31
diff -u -p -r1.31 sync.sql.inc
--- commands/sql/sync.sql.inc	5 Nov 2010 04:31:35 -0000	1.31
+++ commands/sql/sync.sql.inc	8 Nov 2010 03:55:03 -0000
@@ -26,20 +26,31 @@ function drush_sql_sync_init($source = N
   sitealias_get_databases_from_record($source_settings);
   sitealias_get_databases_from_record($destination_settings);
   
-  // Bootstrap to one of the sites being sync'ed.  This allows modules
-  // enabled in the site to participate in the sql-sync hook functions
-  // (e.g. to add sanitization operations, etc.)
-  drush_bootstrap_max_to_local_sitealias(array($source_settings, $destination_settings));
+  // Bootstrap to the source sites being sync'ed if it is local.  
+  // This allows modules enabled in the site to participate in the 
+  // sql-sync hook functions (e.g. to add sanitization operations, etc.).
+  // If the source is remote and the destination is local, then we
+  // will determine the sanitization operations after the database
+  // has been copied.
+  if (!drush_get_option('deferred-sanitization', FALSE) && drush_get_option(array('sanitize', 'destination-sanitize'), FALSE)) {
+    $bootstrapped = drush_bootstrap_max_to_sitealias($source_settings);
+    if ($bootstrapped) {
+      drush_command_invoke_all('drush_sql_sync_sanitize', $source);
+    }
+    else {
+      drush_set_option('deferred-sanitization', TRUE);
+    }
+  }
   
   return TRUE;
 }
 
 /**
- * Pre sql sync function.  This hook function will sanitize usernames and
+ * Sql sync sanitization function.  This hook function will sanitize usernames and
  * passwords in the user table when the --sanitize option is used.  It is
  * also an example of how to write a database sanitizer for sql sync.
  *
- * To write your own sync hook function, define drush_mymodule_pre_sql_sync()
+ * To write your own sync hook function, define mymodule_drush_sql_sync_sanitize()
  * and follow the form of this function to add your own database
  * sanitization operations via the register post-sync op function;
  * @see drush_sql_register_post_sync_op().  This is the only thing that the
@@ -49,67 +60,61 @@ function drush_sql_sync_init($source = N
  * generate the correct SQL regardless of whether Postgres, Mysql,
  * Drupal 6 or Drupal 7 is in use.  A simpler sanitize function that
  * always used default values and only worked with Drupal 6 + mysql
- * appears in the drush.api.php.  @see drush_hook_pre_sql_sync().
+ * appears in the drush.api.php.  @see hook_drush_sql_sync_sanitize().
  */
-function drush_sql_pre_sql_sync($source = NULL, $destination = NULL) {
-  $source_settings = drush_sitealias_get_record($source);
-  $destination_settings = drush_sitealias_get_record($destination);
+function sql_drush_sql_sync_sanitize($site) {
+  $site_settings = drush_sitealias_get_record($site);
   $user_table_updates = array();
   $message_list = array();
 
-  // Test to see if 'sanitize' option was specified.
-  if (drush_get_option(array('sanitize', 'destination-sanitize'), FALSE)) {
-    // Sanitize email addresses
-    $newpassword = drush_get_option(array('sanitize-password', 'destination-sanitize-password'), 'password');
-    if ($newpassword != 'no') {
-      $major_version = drush_drupal_major_version();
-      $pw_op = "";
-
-      // In Drupal 6, passwords are hashed via the MD5 algorithm.
-      if ($major_version == 6) {
-        $pw_op = "MD5('$newpassword')";
-      }
-      // In Drupal 7, passwords are hashed via a more complex algorithm,
-      // available via the user_hash_password function.
-      elseif ($major_version >= 7) {
-        $drupal_root = sitealias_find_local_drupal_root(array($source_settings, $destination_settings));
-        if (isset($drupal_root)) {
-          include_once $drupal_root . '/includes/password.inc';
-          include_once $drupal_root . '/includes/bootstrap.inc';
-          $hash = user_hash_password($newpassword);
-          $pw_op = "'$hash'";
-        }
-      }
-      if (!empty($pw_op)) {
-        $user_table_updates[] = "pass = $pw_op";
-        $message_list[] =  "passwords";
-      }
+  // Sanitize email addresses
+  $newpassword = drush_get_option(array('sanitize-password', 'destination-sanitize-password'), 'password');
+  if ($newpassword != 'no') {
+    $major_version = drush_drupal_major_version();
+    $pw_op = "";
+
+    // In Drupal 6, passwords are hashed via the MD5 algorithm.
+    if ($major_version == 6) {
+      $pw_op = "MD5('$newpassword')";
+    }
+    // In Drupal 7, passwords are hashed via a more complex algorithm,
+    // available via the user_hash_password function.
+    elseif ($major_version >= 7) {
+      include_once DRUPAL_ROOT . '/includes/password.inc';
+      include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+      $hash = user_hash_password($newpassword);
+      $pw_op = "'$hash'";
+    }
+    if (!empty($pw_op)) {
+      $user_table_updates[] = "pass = $pw_op";
+      $message_list[] =  "passwords";
     }
+  }
 
-    // Sanitize passwords
-    $newemail = drush_get_option(array('sanitize-email', 'destination-sanitize-email'), 'user+%uid@localhost');
-    if ($newemail != 'no') {
-      if (strpos($newemail, '%') !== FALSE) {
-        // We need a different sanitization query for Postgres and Mysql
-        $db_driver = $destination_settings['databases']['default']['default']['driver'];
-        if ($db_driver == 'pgsql') {
-          $email_map = array('%uid' => "' || uid || '", '%mail' => "' || replace(mail, '@', '_') || '", '%login' => "' || replace(login, ' ', '_') || '");
-          $newmail =  "'" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "'";
-        }
-        else {
-          $email_map = array('%uid' => "', uid, '", '%mail' => "', replace(mail, '@', '_'), '", '%login' => "', replace(login, ' ', '_'), '");
-          $newmail =  "concat('" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "')";
-        }
+  // Sanitize passwords
+  $newemail = drush_get_option(array('sanitize-email', 'destination-sanitize-email'), 'user+%uid@localhost');
+  if ($newemail != 'no') {
+    if (strpos($newemail, '%') !== FALSE) {
+      // We need a different sanitization query for Postgres and Mysql
+      $db_driver = $site_settings['databases']['default']['default']['driver'];
+      if ($db_driver == 'pgsql') {
+        $email_map = array('%uid' => "' || uid || '", '%mail' => "' || replace(mail, '@', '_') || '", '%login' => "' || replace(login, ' ', '_') || '");
+        $newmail =  "'" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "'";
+      }
+      else {
+        $email_map = array('%uid' => "', uid, '", '%mail' => "', replace(mail, '@', '_'), '", '%login' => "', replace(login, ' ', '_'), '");
+        $newmail =  "concat('" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "')";
       }
-      $user_table_updates[] = "mail = $newmail";
-      $message_list[] = 'email addresses';
     }
+    $user_table_updates[] = "mail = $newmail";
+    $message_list[] = 'email addresses';
+  }
 
-    if (!empty($user_table_updates)) {
-      $sanitize_query = "update users set " . implode(', ', $user_table_updates) . " where uid > 0;";
-      drush_sql_register_post_sync_op('user-email', dt('Reset !message in user table', array('!message' => implode(' and ', $message_list))), $sanitize_query);
-    }
+  if (!empty($user_table_updates)) {
+    $sanitize_query = "update users set " . implode(', ', $user_table_updates) . " where uid > 0;";
+    drush_sql_register_post_sync_op('user-email', dt('Reset !message in user table', array('!message' => implode(' and ', $message_list))), $sanitize_query);
   }
+  
 }
 
 
@@ -249,14 +254,6 @@ function drush_sql_sync($source = NULL, 
         }
       }
 
-      // If any sanitization operations are to be done, then get the
-      // sanitization messages and print them as part of the confirmation.
-      $messages = _drush_sql_get_post_sync_messages();
-      if ($messages) {
-        drush_print();
-        drush_print($messages);
-      }
-
       // If there are multiple destinations, then
       // prompt once here and suppress the warning message
       // and the normal confirmation below.
@@ -274,6 +271,21 @@ function drush_sql_sync($source = NULL, 
         drush_print(dt("You will destroy data from !target and replace with data from !source.", array('!source' => $txt_source, '!target' => $txt_destination)));
       }
 
+      // If any sanitization operations are to be done, then get the
+      // sanitization messages and print them as part of the confirmation.
+      // If --sanitize was specified but there were no sanitize messages,
+      // then warn that sanitization operations will be accumulated and
+      // processed after the sync completes.
+      $messages = _drush_sql_get_post_sync_messages();
+      if ($messages) {
+        drush_print();
+        drush_print($messages);
+      }
+      else if (drush_get_option('deferred-sanitization', FALSE) && !drush_get_option('confirm-sanitizations', FALSE)) {
+        drush_print();
+	drush_print("WARNING: --sanitize was specified, but deferred (e.g. the source site is remote).  The sanitization operatins will be determined after the database is copied to the local system and will be run without further confirmation.  Run with --confirm-sanitizations to force confirmation after the sync.");
+      }
+
       // TODO: actually make the backup if desired.
       drush_print();
       drush_print(dt("You might want to make a backup first, using the sql-dump command.\n"));
@@ -412,6 +424,20 @@ function drush_sql_sync($source = NULL, 
       }
 
       drush_op('system', $import_exec);
+      
+      // After the database is imported into the destination, we
+      // will check and see if we did not collect sanitization
+      // operations in drush_sql_sync_init (i.e. because the source
+      // site was remote), and if the destination site is local,
+      // then we will call the sanitization hooks now.
+      // This presumes an important precondition, that the code
+      // files were sync'ed before the database was sync'ed.
+      if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_SITE) == FALSE) {
+	$bootstrapped = drush_bootstrap_max_to_sitealias($destination_settings);
+	if ($bootstrapped) {
+	  drush_command_invoke_all('drush_sql_sync_sanitize', $destination);
+	}
+      }
     }
   }
 }
@@ -425,6 +451,26 @@ function drush_sql_sync($source = NULL, 
 function drush_sql_post_sql_sync($source = NULL, $destination = NULL) {
   $options = drush_get_context('post-sync-ops');
   if (!empty($options)) {
+    // If 'deferred-sanitization' is set, then we collected the
+    // sanitization operations -after- the database sync, which
+    // means they were not confirmed up-front.  We will show the
+    // operations here, but we will not offer an opportunity to
+    // confirm unless --confirm-sanitizations is specified.
+    if (drush_get_option('deferred-sanitization', FALSE) || drush_get_option('confirm-sanitizations', FALSE)) {
+      if (!drush_get_context('DRUSH_SIMULATE')) {
+	$messages = _drush_sql_get_post_sync_messages();
+	if ($messages) {
+          drush_print();
+          drush_print($messages);
+          if (drush_get_option('confirm-sanitizations', FALSE)) {
+            if (!drush_confirm(dt('Do you really want to sanitize?'))) {
+              drush_die('Aborting; sql-sync completed, but sanitizations skipped.');
+	    }
+	  }
+	}
+      }
+    }
+    
     $destination_settings = drush_sitealias_get_record($destination);
     $sanitize_query = '';
     foreach($options as $id => $data) {
Index: includes/environment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/environment.inc,v
retrieving revision 1.95
diff -u -p -r1.95 environment.inc
--- includes/environment.inc	4 Nov 2010 17:07:09 -0000	1.95
+++ includes/environment.inc	8 Nov 2010 03:55:04 -0000
@@ -204,6 +204,21 @@ function drush_bootstrap($phase, $phase_
 }
 
 /**
+ * Determine whether a given bootstrap phase has been completed
+ *
+ * @param phase
+ *   The bootstrap phase to test
+ *
+ * @returns
+ *   TRUE if the specified bootstrap phase has completed.
+ */
+function drush_has_boostrapped($phase) {
+  $phase_index = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
+  
+  return isset($phase_index) && ($phase_index >= $phase);
+}
+
+/**
  * Validate whether a bootstrap phases can be reached.
  *
  * This function will validate the settings that will be used
@@ -320,44 +335,24 @@ function drush_bootstrap_max($max_phase_
 }
 
 /**
- * Bootstrap the specified site alias.
+ * Bootstrap the specified site alias.  The site alias must
+ * be a valid alias to a local site.
  *
  * @param $site_record
  *   The alias record for the given site alias.
  *   @see drush_sitealias_get_record().
  * @param $max_phase_index
  *   Only attempt bootstrap to the specified level.
+ * @returns TRUE if attempted to bootstrap, or FALSE
+ *   if no bootstrap attempt was made.
  */
 function drush_bootstrap_max_to_sitealias($site_record, $max_phase_index = NULL) {
-  drush_sitealias_set_alias_context($site_record);
-  drush_bootstrap_max($max_phase_index);
-}
-
-/**
- * Bootstrap the first site alias in the provided list
- * that is local.  This is used, for example, by sql-sync,
- * which passes the source and destination targets so that
- * the local site is bootstrapped.
- *
- * @param $site_record
- *   The alias record for the given site alias.
- *   @see drush_sitealias_get_record().
- * @param $max_phase_index
- *   Only attempt bootstrap to the specified level.
- * @returns array
- *   The alias record for the site that was bootstrapped
- */
-function drush_bootstrap_max_to_local_sitealias($site_list, $max_phase_index = NULL) {
-  $bootstrapped_site = NULL;
-
-  foreach ($site_list as $site) {
-    if (($bootstrapped_site == NULL) && (array_key_exists('root', $site) && !array_key_exists('remote-host', $site))) {
-      $bootstrapped_site = $site;
-      drush_bootstrap_max_to_sitealias($site, $max_phase_index);
-    }
+  if ((array_key_exists('root', $site_record) && !array_key_exists('remote-host', $site_record))) {
+    drush_sitealias_set_alias_context($site_record);
+    drush_bootstrap_max($max_phase_index);
+    return TRUE;
   }
-
-  return $bootstrapped_site;
+  return FALSE;
 }
 
 /**
