? example.drushrc.phpe
? includes/table.inc
Index: example.drushrc.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/example.drushrc.php,v
retrieving revision 1.33
diff -u -p -r1.33 example.drushrc.php
--- example.drushrc.php	28 Feb 2010 05:15:53 -0000	1.33
+++ example.drushrc.php	28 Feb 2010 09:31:57 -0000
@@ -124,8 +124,8 @@ $options['skip-tables'] = array(
  * Limitation: If 'verbose' is set in a command-specific option,
  * it must be cleared by '--no-verbose', not '--no-v', and visa-versa.
  */
-# $options['command-specific']['rsync'] = array('verbose' => TRUE);
-# $options['command-specific']['dl'] = array('cvscredentials' => 'user:pass');
+# $command_specific['rsync'] = array('verbose' => TRUE);
+# $command_specific['dl'] = array('cvscredentials' => 'user:pass');
 
 // Specify additional directories to search for scripts
 // Use POSIX path separator (':')
@@ -152,12 +152,12 @@ $options['skip-tables'] = array(
  * Site aliases:
  *
  * To create aliases to remote Drupal installations, add entries
- * to the site aliases option array here.  These settings can be
+ * to the site aliases array here.  These settings can be
  * used in place of a site specification on the command line, and
  * may also be used in arguments to certain commands such as
  * "drush rsync" and "drush sql-sync".
  *
- * Each entry in the 'site-aliases' array is accessed by its
+ * Each entry in the aliases array is accessed by its
  * site alias (e.g. 'stage' or 'dev').  Only the 'uri' and 'root'
  * items are required, and most alias records use only a few of
  * the optional keys, if any.  A simple alias record can be generated
@@ -204,7 +204,7 @@ $options['skip-tables'] = array(
  *
  * Remove the leading hash signs to enable.
  */
-#$options['site-aliases']['stage'] = array(
+#$aliases['stage'] = array(
 #    'uri' => 'stage.mydrupalsite.com',
 #    'root' => '/path/to/remote/drupal/root',
 #    'db-url' => 'pgsql://username:password@dbhost.com:port/databasename',
@@ -218,7 +218,7 @@ $options['skip-tables'] = array(
 #      '%custom' => '/my/custom/path',
 #     ),
 #  );
-#$options['site-aliases']['dev'] = array(
+#$aliases['dev'] = array(
 #    'uri' => 'dev.mydrupalsite.com',
 #    'root' => '/path/to/drupal/root',
 #  );
Index: commands/core/core.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/core.drush.inc,v
retrieving revision 1.81
diff -u -p -r1.81 core.drush.inc
--- commands/core/core.drush.inc	23 Feb 2010 19:32:09 -0000	1.81
+++ commands/core/core.drush.inc	28 Feb 2010 09:31:57 -0000
@@ -102,7 +102,7 @@ function core_drush_command() {
   );
   $items['rsync'] = array(
     'description' => 'Rsync the Drupal tree to/from another server using ssh.  Relative paths start from the Drupal root folder if a site alias is used; otherwise they start from the current working directory.',
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
     'arguments' => array(
       'source' => 'May be rsync path or site alias. See rsync documentation and example.drushrc.php.',
       'destination' => 'May be rsync path or site alias. See rsync documentation and example.drushrc.php.',
@@ -399,7 +399,7 @@ function _core_site_status_table() {
     $status_table['PHP configuration'] = php_ini_loaded_file();
   }
   $status_table['Drush Version'] = DRUSH_VERSION;
-  $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path'));
+  $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE));
   return $status_table;
 }
 
Index: commands/core/rsync.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/rsync.inc,v
retrieving revision 1.11
diff -u -p -r1.11 rsync.inc
--- commands/core/rsync.inc	23 Feb 2010 18:10:36 -0000	1.11
+++ commands/core/rsync.inc	28 Feb 2010 09:31:57 -0000
@@ -67,7 +67,9 @@ function drush_core_rsync($source, $dest
  * @return void
  **/
 function _drush_core_sync($source, $destination, $parametric_options = array()) {
-  // evaluate file paths
+  // Preflight destination in case it defines aliases used by the source
+  _drush_core_evaluate_path($destination);
+  // After preflight, evaluate file paths
   $source_settings = _drush_core_evaluate_path($source);
   $destination_settings = _drush_core_evaluate_path($destination);
   $source_path = $source_settings['rsync-path'];
@@ -250,9 +252,13 @@ function _drush_core_evaluate_path($path
     $alias = substr($path, 0, $colon_pos);
     $path = substr($path, $colon_pos + 1);
     $site_alias_settings = drush_sitealias_get_record($alias);
+    if (empty($site_alias_settings)) {
+      return NULL;
+    }
     $machine = $alias;
   }
   else {
+    $machine = '';
     // if the path is a site alias or a local site...
     $site_alias_settings = drush_sitealias_get_record($path);
     if (!empty($site_alias_settings) || drush_is_local_host($path)) {
@@ -260,7 +266,7 @@ function _drush_core_evaluate_path($path
       $path = '';
     }
   }
-
+  
   if (!empty($site_alias_settings)) {
     // Use 'remote-host' from settings if available; otherwise site is local
     if (array_key_exists('remote-host', $site_alias_settings)) {
@@ -304,12 +310,20 @@ function _drush_core_evaluate_path($path
     $path_aliases = $site_alias_settings['path-aliases'];
   }
 
-  // If site alias does not contain a 'root',
-  // then assume that the remote Drupal root is the same
-  // as the local Drupal root.
-  $drupal_root = array_key_exists('root', $site_alias_settings) ? $site_alias_settings['root'] : drush_get_context('DRUSH_DRUPAL_ROOT');
+  // Get the 'root' setting from the alias; if it does not
+  // exist, then get the root from the bootstrapped site.
+  if (array_key_exists('root', $site_alias_settings)) {
+    $drupal_root = $site_alias_settings['root'];
+  }
+  else {
+    drush_bootstrap_max();
+    $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
+  }
+  if (empty($drupal_root)) {
+    $drupal_root = '';
+  }
   // Add a slash to the end of the drupal root, as below.
-  if ($drupal_root[strlen($drupal_root)-1] != '/') {
+  elseif ($drupal_root[strlen($drupal_root)-1] != '/') {
     $drupal_root = $drupal_root . '/';
   }
   foreach ($path_aliases as $key => $value) {
Index: commands/core/sitealias.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/sitealias.drush.inc,v
retrieving revision 1.13
diff -u -p -r1.13 sitealias.drush.inc
--- commands/core/sitealias.drush.inc	24 Feb 2010 04:54:31 -0000	1.13
+++ commands/core/sitealias.drush.inc	28 Feb 2010 09:31:57 -0000
@@ -48,7 +48,7 @@ function sitealias_drush_command() {
  * is the site specification for the given alias.
  */
 function _drush_sitealias_alias_list() {
-  return drush_get_option('site-aliases', array());
+  return drush_get_context('site-aliases');
 }
 
 /**
Index: commands/sql/sync.sql.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/sql/sync.sql.inc,v
retrieving revision 1.19
diff -u -p -r1.19 sync.sql.inc
--- commands/sql/sync.sql.inc	26 Feb 2010 14:16:16 -0000	1.19
+++ commands/sql/sync.sql.inc	28 Feb 2010 09:31:58 -0000
@@ -36,6 +36,9 @@ function drush_sql_sync($source = null, 
 }
 
 function _drush_sql_sync($source, $destination, $show_warning = TRUE) {
+  // Preflight destination in case it defines the alias used by the source
+  drush_sitealias_get_record($destination);
+  // After preflight, get source and destination settings
   $source_settings = drush_sitealias_get_record($source, TRUE);
   $destination_settings = drush_sitealias_get_record($destination, TRUE);
 
Index: includes/command.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/command.inc,v
retrieving revision 1.66
diff -u -p -r1.66 command.inc
--- includes/command.inc	22 Feb 2010 04:03:17 -0000	1.66
+++ includes/command.inc	28 Feb 2010 09:31:58 -0000
@@ -634,7 +634,7 @@ function drush_command_default_options($
 
 function _drush_command_set_default_options($command) {
   $options_were_set = FALSE;
-  $command_default_options = drush_get_option('command-specific', array());
+  $command_default_options = drush_get_context('command-specific');
   if (array_key_exists($command, $command_default_options)) {
     foreach ($command_default_options[$command] as $key => $value) {
       // We set command-specific options in their own context
Index: includes/context.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/context.inc,v
retrieving revision 1.22
diff -u -p -r1.22 context.inc
--- includes/context.inc	23 Feb 2010 19:32:10 -0000	1.22
+++ includes/context.inc	28 Feb 2010 09:31:59 -0000
@@ -131,55 +131,78 @@ function drush_load_config($context) {
 }
 
 function drush_load_config_file($context, $config) {
-  global $drush_conf_override;
+  if (file_exists($config)) {
+    $options = $aliases = $command_specific = $override = array();
+    drush_log(dt('Loading drushrc "!config" into "!context" scope.', array('!config' => realpath($config), '!context' => $context)), 'bootstrap');
+    require_once($config);
+    if (!empty($options) || !empty($aliases) || !empty($command_specific)) {
+      $options = array_merge(drush_get_context($context), $options);
+      $options['config-file'] = realpath($config);
+    
+      $options['site-aliases'] = array_merge(isset($aliases) ? $aliases : array(), isset($options['site-aliases']) ? $options['site-aliases'] : array());
+      $options['command-specific'] = array_merge(isset($command_specific) ? $command_specific : array(), isset($options['command-specific']) ? $options['command-specific'] : array());
+
+      drush_set_config_options($context, $options, $override);
+    }
+  }
+}
 
+function drush_set_config_options($context, $options, $override = array()) {
+  global $drush_conf_override;
+  
   // Only reset $drush_conf_override if the array is not set, otherwise keep old values and append new values to it.
   if (!isset($drush_conf_override)) {
     $drush_conf_override = array();
   }
-
-  if (file_exists($config)) {
-    drush_log(dt('Loading drushrc "!config" into "!context" scope.', array('!config' => realpath($config), '!context' => $context)), 'bootstrap');
-    $options['context-path'] = realpath($config);
-    require_once($config);
-
-    // There are certain options such as 'site-aliases' and 'command-specific'
-    // that must be merged together if defined in multiple drush configuration
-    // files.  If we did not do this merge, then the last configuration file
-    // that defined any of these properties would overwrite all of the options
-    // that came before in previously-loaded configuration files.  We place
-    // all of them into the 'default' context so that this does not happen.
-    if (isset($options)) {
-      foreach (array('site-aliases', 'command-specific') as $option_name) {
-        if ((isset($options)) && (array_key_exists($option_name, $options))) {
-          $cache =& drush_get_context('default');
-          if (array_key_exists($option_name, $cache)) {
-            $cache[$option_name] = array_merge($cache[$option_name], $options[$option_name]);
-          }
-          else {
-            $cache[$option_name] = $options[$option_name];
-          }
-          unset($options[$option_name]);
-        }
-      }
+  
+  // Copy 'config-file' into 'context-path', converting to an array to hold multiple values if necessary
+  if (isset($options['config-file'])) {
+    if (isset($options['context-path'])) {
+      $options['context-path'] = array_merge(array($options['config-file']), is_array($options['context-path']) ? $options['context-path'] : array($options['context-path']));
+    }
+    else {
+      $options['context-path'] = $options['config-file'];
     }
+  }
+  
+  // Take out $aliases and $command_specific options
+  drush_set_config_special_contexts($options);
+
+  drush_set_context($context, $options);
 
-    drush_set_context($context, $options);
+  // Instruct core not to queries since we are not outputting them.
+  // This can be overridden by a command or a drushrc file if needed.
+  if (!isset($drush_conf_override['dev_query'])) {
+    $drush_conf_override['dev_query'] = FALSE;
+  }
+
+  /**
+   * Allow the drushrc.php file to override $conf settings.
+   * This is a separate variable because the $conf array gets
+   * initialized to an empty array, in the drupal bootstrap process,
+   * and changes in settings.php would wipe out the drushrc.php settings.
+   */
+  if (!empty($override)) {
+    $drush_conf_override = array_merge($drush_conf_override, $override);
+  }
+}
 
-    // Instruct core not to queries since we are not outputting them.
-    // This can be overridden by a command or a drushrc file if needed.
-    if (!isset($drush_conf_override['dev_query'])) {
-      $drush_conf_override['dev_query'] = FALSE;
-    }
-
-    /**
-     * Allow the drushrc.php file to override $conf settings.
-     * This is a separate variable because the $conf array gets
-     * initialized to an empty array, in the drupal bootstrap process,
-     * and changes in settings.php would wipe out the drushrc.php settings.
-     */
-    if (!empty($override)) {
-      $drush_conf_override = array_merge($drush_conf_override, $override);
+/**
+ * There are certain options such as 'site-aliases' and 'command-specific'
+ * that must be merged together if defined in multiple drush configuration
+ * files.  If we did not do this merge, then the last configuration file
+ * that defined any of these properties would overwrite all of the options
+ * that came before in previously-loaded configuration files.  We place
+ * all of them into their own context so that this does not happen.
+ */
+function drush_set_config_special_contexts(&$options) {  
+  if (isset($options)) {
+    foreach (array('site-aliases', 'command-specific') as $option_name) {
+      if ((isset($options)) && (array_key_exists($option_name, $options))) {
+        $cache =& drush_get_context($option_name);
+        $cache = array_merge($cache, $options[$option_name]);
+        unset($options[$option_name]);
+      }
     }
   }
 }
@@ -342,15 +365,20 @@ function drush_get_option($option, $defa
  *   An array whose key is the context name and value is
  *   the specific value for the option in that context.
  */
-function drush_get_context_options($option) {
+function drush_get_context_options($option, $flatten = FALSE) {
   $result = array();
   
   $contexts = drush_context_names();
   foreach ($contexts as $context) {
     $value = _drush_get_option($option, drush_get_context($context));
-
+    
     if ($value !== null) {
-      $result[$context] = $value;
+      if ($flatten && is_array($value)) {
+        $result = array_merge($value, $result);
+      }
+      else {
+        $result[$context] = $value;
+      }
     }
   }
   
Index: includes/sitealias.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/sitealias.inc,v
retrieving revision 1.26
diff -u -p -r1.26 sitealias.inc
--- includes/sitealias.inc	24 Feb 2010 14:12:59 -0000	1.26
+++ includes/sitealias.inc	28 Feb 2010 09:31:59 -0000
@@ -92,19 +92,15 @@ function drush_sitealias_get_record($ali
 }
 
 function _drush_sitealias_get_record($alias, $db_settings_needed = false) {
-  // Sometimes getting an alias record involves loading settings.php or calling
-  // backend invoke.  We'll cache all alias records fetched by this routine to
-  // insure that we never have to do anything like that twice.
-  $alias_record = drush_get_option('sitealias-' . $alias, array(), 'sitealias-cache');
-  if (empty($alias_record)) {
-    // Check to see if the provided parameter is in fact a defined alias.
-    $all_site_aliases = drush_get_option('site-aliases', array());
-    if (array_key_exists($alias, $all_site_aliases)) {
-      $alias_record = $all_site_aliases[$alias];
-    }
-    // If the parameter is not an alias, then it is some form of
-    // site specification (or it is nothing at all)
-    elseif (isset($alias)) {
+  // Check to see if the provided parameter is in fact a defined alias.
+  $all_site_aliases =& drush_get_context('site-aliases');
+  if (array_key_exists($alias, $all_site_aliases)) {
+    $alias_record = $all_site_aliases[$alias];
+  }
+  // If the parameter is not an alias, then it is some form of
+  // site specification (or it is nothing at all)
+  else {
+    if (isset($alias)) {
       // Cases 1.) - 4.):
       // We will check for a site specification if the alias has at least
       // two characters from the set '@', '/', '#'.
@@ -155,28 +151,40 @@ function _drush_sitealias_get_record($al
       }
 
     }
-
+  }
+  
+  if (!empty($alias_record)) {
     // Process site list related fields
     _drush_sitealias_check_sitelist_fields($alias_record);
 
-    // Cache the result
-    drush_set_option('sitealias-' . $alias, $alias_record, 'sitealias-cache');
+    // Load the drush config file if there is one associated with this alias
+    if (!isset($alias_record['remote']) && !isset($alias_record['loaded-config'])) {
+      if (!isset($alias_record['config']) && isset($alias_record['uri']) && isset($alias_record['root'])) {
+	$alias_record['config'] = realpath($alias_record['root'] . '/sites/' . drush_sitealias_uri_to_site_dir($alias_record['uri']) . '/drushrc.php');
+      }
+      if (isset($alias_record['config']) && file_exists($alias_record['config'])) {
+	drush_load_config_file('site', $alias_record['config']);
+	$alias_record['loaded-config'] = TRUE;
+      }
+      unset($alias_record['config']);
 
-    // Load the drush config file if there is one in the site folder just found
-    if (!isset($alias_record['remote']) && isset($alias_record['uri']) && isset($alias_record['root'])) {
-      drush_load_config_file('site', $alias_record['root'] . '/sites/' . drush_sitealias_uri_to_site_dir($alias_record['uri']) . '/drushrc.php');
+      // Handle nested alias definitions and command-specific options.
+      drush_set_config_special_contexts($alias_record);
     }
-  }
 
-  // If the alias record does not have a defined 'databases' entry,
-  // then we'll need to look one up
-  if ($db_settings_needed) {
-    drush_sitealias_add_db_settings($alias_record);
-  }
+    // If the alias record does not have a defined 'databases' entry,
+    // then we'll need to look one up
+    if ($db_settings_needed) {
+      drush_sitealias_add_db_settings($alias_record);
+    }
 
-  // Add the static defaults
-  _drush_sitealias_add_static_defaults($alias_record);
+    // Add the static defaults
+    _drush_sitealias_add_static_defaults($alias_record);
 
+    // Cache the result
+    $all_site_aliases[$alias] = $alias_record;
+  }
+  
   // Fail fast if database settings are not available and the caller
   // said that they are required (but give site lists a pass)
   if ($db_settings_needed && !isset($alias_record['databases']) && !isset($alias_record['site-list'])) {
@@ -633,7 +641,7 @@ function _drush_sitealias_find_record_fo
   //$drupal_root = drush_bootstrap_value('drupal_root');
   $drupal_root = drush_get_option(array('r', 'root'), drush_locate_root());
 
-  $all_site_aliases = drush_get_option('site-aliases', array());
+  $all_site_aliases = drush_get_context('site-aliases');
   foreach ($all_site_aliases as $one_alias_name => $one_alias_record) {
     if (!isset($one_alias_record['remote-host']) && isset($one_alias_record['root']) && isset($one_alias_record['uri']) && ($one_alias_record['uri'] == $alias) && ($one_alias_record['root'] == $drupal_root)) {
       $alias_record = $one_alias_record;
@@ -834,66 +842,30 @@ function _drush_sitealias_set_context_by
  *   'destination-databases'.
  */
 function drush_sitealias_set_alias_context($site_alias_settings, $prefix) {
+  $options = drush_get_context('alias');
+  
   // backend invoke needs 'root' and 'uri' on the command line, so we will
   // handle these two specially
-  $special = empty($prefix) ? array('root', 'uri') : array();
-  // Transfer all non-array options from the site alias to the drush options
+  $options_context = empty($prefix) ? array('root', 'uri') : array();
+  // There are some items that we should just skip
+  $skip_list = array('site-aliases', 'command-specific');
+  // Transfer all options from the site alias to the drush options
   // in the 'alias' context.
   foreach ($site_alias_settings as $key => $value) {
-    if (!is_array($value) || ($key == "databases") || ($key == "site-list")) {
-      drush_set_option($prefix . $key, $value, in_array($key, $special) ? 'options' : 'alias');
-    }
-  }
-  // Transfer selected path aliases to the drush options.
-  if (array_key_exists('path-aliases', $site_alias_settings)) {
-    foreach (array('%drush-script', '%dump', '%include') as $key) {
-      if (array_key_exists($key, $site_alias_settings['path-aliases'])) {
-        drush_set_option($prefix . substr($key, 1), $site_alias_settings['path-aliases'][$key], 'alias');
+    // Special handling for path aliases:
+    if ($key == "path-aliases") {
+      foreach (array('%drush-script', '%dump', '%include') as $path_key) {
+	if (array_key_exists($path_key, $value)) {
+          $options[$prefix . substr($path_key, 1)] = $value[$path_key];
+	}
       }
     }
-  }
-  // If there are prefix-specific options (e.g. 'source-options' or 'target-options'),
-  // then transfer those values as well.
-  drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix);
-}
-
-/**
- * Looks up the specified alias record and then calls through
- * to drush_sitealias_apply_special_alias_record_options, below.
- *
- * @param alias
- *   The name of the alias record.
- * @param prefix
- *   The prefix value to afix to the beginning of every
- *   key set.
- */
-function drush_sitealias_apply_special_alias_options($alias, $prefix) {
-  if ($prefix != '') {
-    $site_alias_settings = drush_sitealias_get_record($alias);
-    if (!empty($site_alias_settings)) {
-      drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix);
+    elseif (in_array($key, $options_context)) {
+      drush_set_option($prefix . $key, $value, 'options');
     }
-  }
-}
-
-/**
- * Site alias records can have special options sections,
- * one for every kind of prefix used with 'drush_sitealias_set_alias_context.
- * The options stored in this record are copied to the 'alias'
- * context whenever that prefix is used.
- *
- * @param site_alias_settings
- *   The alias record.
- * @param prefix
- *   The prefix value to afix to the beginning of every
- *   key set.
- */
-function drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix) {
-  if ($prefix != '') {
-    if ((array_key_exists($prefix . 'options', $site_alias_settings))) {
-      foreach ($site_alias_settings[$prefix . 'options'] as $key => $value) {
-        drush_set_option($key, $value, 'alias');
-      }
+    elseif (!in_array($key, $skip_list)) {
+      $options[$prefix . $key] = $value;
     }
   }
+  drush_set_config_options('alias', $options);
 }
