Index: example.drushrc.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/example.drushrc.php,v
retrieving revision 1.11
diff -u -p -r1.11 example.drushrc.php
--- example.drushrc.php	19 Apr 2009 03:13:09 -0000	1.11
+++ example.drushrc.php	14 May 2009 17:47:20 -0000
@@ -78,3 +78,46 @@ $options['structure-tables'] = array(
 #   'theme_default' => 'minnelli',
 #   'anonymous' => 'Visitor',
 # );
+
+/**
+ * Site aliases:
+ *
+ * To create aliases to remote Drupal installations, add entries
+ * to the site-aliases option array here.  These settings are
+ * only respected by "drush sql load" and "drush sync".
+ *
+ * Each entry in the 'site-aliases' array is accessed by its
+ * site alias (e.g. 'stage' or 'dev').  The following settings
+ * are stored in the site alias record:
+ *
+ * - 'db_url': The database connection string from settings.php.
+ * - 'fqdn': The fully-qualified domain name of the remote system
+ * hosting the Drupal instance.  If not specified, the site alias
+ * is used.  When making site aliases for local Drupal instances,
+ * it is important that the fqdn be exactly the same as the folder
+ * name for the site as stored in the 'sites' folder (or "localhost").
+ * - 'ssh-user': The username to log in as when using rsync
+ * - 'ssh-password': The password to use with rsync
+ * - 'path-aliases': An array of aliases for common rsync targets.
+ * Relative aliases are always taken from the Drupal root.  The
+ * '!root' alias must not be specified as a relative path.
+ *
+ * Remove the leading hash signs to enable.
+ */
+#$options['site-aliases']['stage'] = array(
+#    'db_url' => 'pgsql://username:password@dbhost.com:port/databasename',
+#    'fqdn' => 'stage.mydrupalsite.com',
+#    'ssh-user' => 'publisher',
+#    'ssh-password' => 'secretsecret',
+#    'path-aliases' => array(
+#      '!root' => '/path/to/remote/drupal/root',
+#      '!files' => 'sites/mydrupalsite.com/files',
+#      '!data' => '/my/arbitrary/path',    )
+#  );
+#$options['site-aliases']['dev'] = array(
+#    'db_url' => 'pgsql://username:password@localhost/databasename',
+#    'fqdn' => 'dev.mydrupalsite.com',
+#    'path-aliases' => array(
+#      '!data' => '/my/other/path',    )
+#  );
+
Index: commands/core/core.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/core.drush.inc,v
retrieving revision 1.27
diff -u -p -r1.27 core.drush.inc
--- commands/core/core.drush.inc	8 May 2009 03:46:15 -0000	1.27
+++ commands/core/core.drush.inc	14 May 2009 17:47:20 -0000
@@ -82,13 +82,14 @@ function core_drush_command() {
     
   );
   $items['sync'] = array(
-    'description' => 'Rsync the Drupal tree to/from another server using ssh.',
+    '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.',
     'arguments' => array(
-      'source' => 'See rsync documentation.',
-      'destination' => 'See rsync documentation.',
+      'source' => 'See rsync documentation and example.drushrc.php.',
+      'destination' => 'See rsync documentation and example.drushrc.php.',
     ),
     'examples' => array(
-      'sync dev:/var/www/files/ stage:/var/www/files/' => 'Rsync \'files\' dir from dev to stage',
+      'sync dev:. stage:.' => 'Rsync entire Drupal tree from dev to stage (one of which must be local).',
+      'sync ./ stage:!files/img' => 'Rsync all files in the current directory to the \'img\' directory in the file storage folder on stage.',
     ),
   );
   $items['eval'] = array(
@@ -327,15 +328,26 @@ function drush_core_cache_clear() {
  * @return void
  **/
 function drush_core_sync($source, $destination) {
-  // Local paths are relative to Drupal root
-  $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
+  $options = '-az';
+  $remote_user = '';
+  $pwfile = '';
   
-  if (!strstr($source, ':')) {
-    $source = $drupal_root. "/$source";
-  }
-  if (!strstr($destination, ':')) {
-    $destination = $drupal_root . "/$destination";
+  // One of $souruce or $destination (at most) will be remote;
+  // get the site alias settings for the remote component.
+  $remote_alias_settings = _drush_core_get_site_alias_settings_for_remote($source, $destination);
+  if (!empty($remote_alias_settings)) {
+    if (array_key_exists('ssh-user', $remote_alias_settings)) {
+      $remote_user = $remote_alias_settings['ssh-user'] . '@';
+    }
+    if (array_key_exists('ssh-password', $remote_alias_settings)) {
+      $pwfile = drush_save_data_to_temp_file($remote_alias_settings['ssh-password']);
+      $options = "$options --password-file $pwfile";
+    }    
   }
+  
+  // expand file paths
+  $source = _drush_core_expand_path($source, $remote_user);
+  $destination = _drush_core_expand_path($destination, $remote_user);
 
   // Prompt for confirmation. This is destructive.
   if (!drush_get_context('DRUSH_SIMULATE')) {
@@ -345,14 +357,122 @@ function drush_core_sync($source, $desti
     }
   }
 
-  $options = '-az';
   $exec = "rsync -e ssh $options --exclude \"*.svn*\" $source $destination";
   if (drush_get_context('drush_log')) {
     // the drush_op() will be verbose about the command that gets executed.
     $options .= 'v';
   }
 
-  return drush_op('system', $exec) !== FALSE;
+  $exec_result=drush_op('system', $exec) !== FALSE;
+  if (!empty($pwfile)) {
+    drush_op('unlink', $pwfile);
+  }
+  
+  return $exec_result;
+}
+
+// a path is "machine:/path" or "machine:path" or "/path" or "path"
+function _drush_core_expand_path($path, $remote_user) {
+  $machine = '';
+  $path_aliases = array();
+  // Parse site aliases if there is a colon in the path
+  $colon_pos = strpos($path, ':');
+  if ($colon_pos != FALSE) {
+    $alias = substr($path, 0, $colon_pos);
+    $machine = $alias;
+    $path = substr($path, $colon_pos + 1);
+    $site_alias_settings=_drush_core_get_site_alias_settings($alias);
+    if (!empty($site_alias_settings)) {
+      if (array_key_exists('path-aliases', $site_alias_settings)) {
+        $path_aliases = $site_alias_settings['path-aliases'];
+      }
+      // Use 'fqdn' from settings if available; otherwise use alias name itself 
+      if (array_key_exists('fqdn', $site_alias_settings)) {
+        $machine = $site_alias_settings['fqdn'];
+      }
+    }
+    // Strip the machine portion of the path if the
+    // alias points to the local machine.
+    if (_drush_core_is_local_machine($machine)) {
+      $machine = '';
+    }
+    else {
+      $machine = "$remote_user$machine:";
+    }
+  }
+  // If path aliases does not contain an alias for '!root',
+  // then assume that the remote Drupal root is the same
+  // as the local Drupal root.
+  if (!array_key_exists('!root', $path_aliases)) {
+    $path_aliases['!root'] = drush_get_context('DRUSH_DRUPAL_ROOT');
+  }
+  // If path aliases does not contain an alias for '!files',
+  // and no machine alias was specified, then fill in file_directory_path().
+  if ((!array_key_exists('!files', $path_aliases)) && (empty($alias))) {
+    $path_aliases['!files'] = file_directory_path();
+  }
+  // Expand all relative path aliases to be based off of the Drupal root
+  foreach ($path_aliases as $key => $value) {
+    if (($value[0] != '/') && ($key != 'root')) {
+      $path_aliases[$key] = $path_aliases['!root'] . '/' . $path_aliases[$key];
+    }
+  }
+  // Check for path aliases if the path does not start with a '/'.
+  if ($path[0] != '/') {
+    $path = dt($path, $path_aliases);
+  }
+  // If we have a relative path that was used with an alias, then make
+  // it relative to the Drupal root.
+  if (($path[0] != '/') && (!empty($alias))) {
+      $path = $path_aliases['!root'] . '/' . $path;
+  }
+  return "$machine$path";
+}
+
+function _drush_core_is_local_machine($alias) {
+  // To do:  the directory in 'sites' might contain
+  // a component for the port or local path, so it
+  // would be better to do a 'contains' test on all
+  // files in 'sites' to determine if 'alias' is local.
+  // This might give a false positive, though: a remote
+  // 'mysite.com' would look local if there was a local
+  // 'dev.mysite.com'.
+  return ($alias == 'localhost') || ($alias == '127.0.0.1') || (file_exists(drush_get_context('DRUSH_DRUPAL_ROOT') . "/sites/$alias"));
+}
+
+function _drush_core_get_site_alias_settings($alias) {
+  $site_alias_settings = array();
+  $all_site_aliases = drush_get_option('site-aliases', array());
+  if (array_key_exists($alias, $all_site_aliases)) {
+    $site_alias_settings = $all_site_aliases[$alias];
+  }
+  return $site_alias_settings;
+}
+
+function _drush_core_get_site_alias_settings_if_remote($path) {
+  $site_alias_settings = array();
+  $colon_pos = strpos($path, ':');
+  if ($colon_pos != FALSE) {
+    $alias = substr($path, 0, $colon_pos);
+    if (!_drush_core_is_local_machine($alias)) {
+      $site_alias_settings = _drush_core_get_site_alias_settings($alias);
+    }
+  }
+  return $site_alias_settings;
+}
+
+function _drush_core_get_site_alias_settings_for_remote($source, $destination) {
+  $source_settings = _drush_core_get_site_alias_settings_if_remote($source);
+  $destination_settings = _drush_core_get_site_alias_settings_if_remote($destination);
+  /*if ((!empty($source_settings)) && (!empty($destination_settings))) {
+    return FALSE;
+  }
+  else*/if (!empty($source_settings)) {
+    return $source_settings;
+  }
+  else {
+    return $destination_settings;
+  }
 }
 
 /**
Index: commands/sql/sql.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/sql/sql.drush.inc,v
retrieving revision 1.17
diff -u -p -r1.17 sql.drush.inc
--- commands/sql/sql.drush.inc	11 May 2009 20:53:10 -0000	1.17
+++ commands/sql/sql.drush.inc	14 May 2009 17:47:21 -0000
@@ -267,8 +267,10 @@ function drush_sql_query($query) {
  *    be replaced with the contents of `source`. *
  **/
 function drush_sql_load($source, $destination) {
-  $source = _drush_sql_get_spec_from_settings("./sites/$source/settings.php", 'source');
-  $destination = _drush_sql_get_spec_from_settings("./sites/$destination/settings.php", 'target');
+  # $source = _drush_sql_get_spec_from_settings("./sites/$source/settings.php", 'source');
+  # $destination = _drush_sql_get_spec_from_settings("./sites/$destination/settings.php", 'target');
+  $source = _drush_sql_get_spec_from_site_alias($source, 'source');
+  $destination = _drush_sql_get_spec_from_site_alias($destination, 'target');
   
   // Prompt for confirmation. This is destructive.
   if (!drush_get_context('DRUSH_SIMULATE')) {
@@ -367,6 +369,21 @@ function _drush_sql_get_db_spec() {
   }
 }
 
+// Build a $db_spec from a given site alias
+function _drush_sql_get_spec_from_site_alias($alias, $prefix) {
+  global $db_url;
+  $all_site_aliases = drush_get_option('site-aliases', array());
+  if (array_key_exists($alias, $all_site_aliases)) {
+    $site_alias_settings = $all_site_aliases[$alias];
+    $db_url = $site_alias_settings['db_url'];
+    return _drush_sql_get_db_spec();
+  }
+#  if ($db_url = drush_get_option($alias . '_db_url')) {
+#    return _drush_sql_get_db_spec();
+#  }
+  return _drush_sql_get_spec_from_settings("./sites/$alias/settings.php", $prefix);
+}
+
 // Build a $db_spec from a given settings.php.
 function _drush_sql_get_spec_from_settings($file, $prefix) {
   // Reset global databases to whatever is defined in $file
@@ -416,7 +433,7 @@ function _drush_sql_get_credentials($db_
 
       $cred = $db_spec['database'] . ' ' .
          (empty($db_spec['host']) || ($db_spec['host'] == "localhost") ? '' : '-h ' . $db_spec['host']) . ' ' .
-         (empty($db_spec['port']) ? '' : '-p' . $db_spec['port']) . ' ';
+         (empty($db_spec['port']) ? '' : '-p ' . $db_spec['port']) . ' ';
       // Adding '-U' will cause Postgres to prompt for a password, so disable this for now.
       // Use "sudo -u postgres drush sql ..." to access the database without a password,
       // presuming that "postgres" is the database superuser and you have
