Index: commands/alias/alias.drush.inc
===================================================================
diff -u -p alias.drush.inc
--- commands/alias/alias.drush.inc   1969-12-31 16:00:00.000000000 -0800
+++ commands/alias/alias.drush.inc   2009-06-05 17:15:00.000000000 -0700
@@ -0,0 +1,70 @@
+<?php
+// $Id: alias.drush.inc,v 1.1 2009/06/02 01:01:17 ga Exp $
+
+/**
+ * @file
+ *   Site alias commands.
+ */
+
+function alias_drush_help($section) {
+  switch ($section) {
+    case 'drush:alias print':
+      return dt('Print an alias record.');
+  }
+}
+
+function alias_drush_command() {
+  $items = array();
+
+  $items['alias print'] = array(
+    'callback' => 'drush_alias_print',
+    'description' => 'Print site alias for the current drupal site.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
+    'optional-arguments' => TRUE,
+    'arguments' => array(
+      'site' => 'Site specification alias to print',
+    ),
+    'examples' => array(
+      'drush alias print' => 'Print an alias record for the default site.',
+      'drush alias print dev.example.com/path/to/drupal#dev' => 'Print an alias record for the example.com dev site.',
+    ),
+  );
+  return $items;
+}
+
+function drush_alias_print($site_alias) {
+  if (isset($site_alias)) {
+      drush_expand_site_specification($site_alias);
+  }
+  $root = drush_get_option('root');
+  if (!isset($root)) {
+    $root = drush_get_context('DRUSH_DRUPAL_ROOT');
+  }
+  $alias = drush_get_option(array('l', 'uri'));
+  $alias_name = drush_get_option('alias-name');
+  if (!isset($alias_name)) {
+    $alias_name = $alias;
+  }
+
+  $file = $root . "/sites/$alias/settings.php";
+  global $databases, $db_url;
+  require $file;
+
+  /*
+  // we could just drush_print_r this, but it wouldn't look right.
+  $site_alias = array('db-url' => $db_url,
+    'uri' => $alias,
+    'path-aliases' => array(
+      '!root' => $root )
+  );
+  */
+
+  drush_print('$options[\'site-aliases\'][\'' . $alias_name . '\'] = array(');
+  drush_print('  \'db-url\' => \'' . $db_url . '\',');
+  drush_print('  \'uri\' => \'' . $alias . '\',');
+  drush_print('  \'path-aliases\' => array(');
+  drush_print('    \'!root\' => \'' . $root . '\' )');
+  drush_print(');');
+
+}
+
Index: drush.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/drush.php,v
retrieving revision 1.68
diff -u -p -r1.68 drush.php
--- drush.php	4 Jun 2009 19:48:55 -0000	1.68
+++ drush.php	19 Jun 2009 06:01:04 -0000
@@ -71,6 +71,33 @@ function drush_main() {
   foreach ($phases as $phase) {
     if (drush_bootstrap($phase)) {
       $command = drush_parse_command();
+
+      // Process a remote command if 'remote_host' option is set.
+      $remote_host = drush_get_option('remote_host');
+      if(isset($remote_host)) {         
+        
+       $args = drush_get_arguments();
+        $command = array_shift($args);
+        $data = drush_get_context('options');
+        foreach (array('r', 'root', 'l', 'uri', 'v', 'd', 'i') as $key) {
+         unset($data[$key]);
+       }
+        foreach (array('root', 'uri') as $key) {
+         $data[$key] = drush_get_option($key);
+       }
+       
+        $drush_path = drush_get_option('drush');
+        $remote_user = drush_get_option('remote_user');
+        $output = drush_backend_invoke_args($command, $args, $data, 'GET', TRUE, $drush_path, $remote_host, $remote_user);
+       
+        // If we set INTEGRATE to FALSE, we can print the output as shown below:
+       // using 'drush_print' introduces an extra blank line at
+       // the end of the input.
+        //drush_print($output['output']);
+       
+        return;
+      }
+
       if (is_array($command)) {
         if ($command['bootstrap'] == $phase && empty($command['bootstrap_errors'])) {
           drush_log(dt("Found command: !command", array('!command' => $command['command'])), 'bootstrap');
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	19 Jun 2009 06:01:04 -0000
@@ -78,3 +78,52 @@ $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.
+ * For remote databases accessed via an ssh tunnel, set the port
+ * number to the tunneled port as it is accessed on the local machine.
+ * - 'remote-port': If the database is remote and 'db-url' contains
+ * a tunneled port number, put the actual database port number
+ * used on the remote machine in the 'remote-port' setting.
+ * - 'uri': This should always be the same as the site's folder name
+ * in the 'sites' folder.
+ * - 'remote-host': The fully-qualified domain name of the remote system
+ * hosting the Drupal instance.
+ * - 'remote-user': The username to log in as when using ssh or rsync.
+ * - 'remote-pass': 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',
+#    'uri' => 'stage.mydrupalsite.com',
+#    'ssh-user' => 'publisher',
+#    'ssh-password' => 'secretsecret',
+#    'path-aliases' => array(
+#      '!root' => '/path/to/remote/drupal/root',
+#      '!dump' => '/path/to/live/sql_dump.sql',
+#      '!files' => 'sites/mydrupalsite.com/files',
+#      '!data' => '/my/arbitrary/path',    )
+#  );
+#$options['site-aliases']['dev'] = array(
+#    'db-url' => 'pgsql://username:password@localhost/databasename',
+#    'uri' => 'dev.mydrupalsite.com',
+#    'path-aliases' => array(
+#      '!dump' => '/path/to/dev/sql_dump.sql',
+#      '!data' => '/my/other/path',    )
+#  );
+
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	19 Jun 2009 06:01:05 -0000
@@ -22,6 +22,8 @@ function sql_drush_help($section) {
       return dt("Usage: drush [options] sql query <query>...\n<query> is a SQL statement, which can alternatively be passed via STDIN. Any additional arguments are passed to the mysql command directly.");
     case 'drush:sql load':
       return dt("Usage: drush [options] sql load <source_dir> <target_dir>.\n <source_dir> and <target_dir> are names of directories under \'sites\'. These determine from where and to where you want your database copied. Optional: specify \'common\' for --skip if you wish to omit disposable tables like cache*, search*, etc. Your skip lists are specified in your drushrc.php file. Any additional arguments are passed to the mysqldump command directly.");
+    case 'drush:sql sync':
+      return dt("Usage: drush [options] sql sync <source_alias> <target_alias>.\n <source_alias> and <target_alias> are site aliases, or names of directories under \'sites\'. These determine from where and to where you want your database copied.");
   }
 }
 
@@ -54,6 +56,7 @@ function sql_drush_command() {
       'drush sql dump --result-file=../18.sql' => 'Save SQL dump to the directory above Drupal root.',
       'drush sql dump --skip-tables-key=common' => 'Skip standard tables. @see example.drushrc.com',
     ),
+    //  '--cache' => 'Skip dump is result file exists and is less than "cache" hours old. Optional.',
     'options' => array(
       '--result-file' => 'Save to a file. The file should be relative to Drupal root. Recommended.',
       '--skip-tables-key' => 'A key in the $skip_tables array. @see example.drushrc.php. Optional.',
@@ -83,6 +86,26 @@ function sql_drush_command() {
       'from' => 'Name of subdirectory within /sites. Its settings.php defines where to dump from.',
       'to' => 'Name of subdirectory within /sites. Its settings.php defines the destination for the dump.',
     ),
+    'optional-arguments' => TRUE,
+    'options' => array(
+      '--skip-tables-key' => 'A key in the $skip_tables array. @see example.drushrc.php. Optional.',
+      '--structure-tables-key' => 'A key in the $structure_tables array. @see example.drushrc.php. Optional.',
+      '--source_database' => 'The SOURCE DB connection key if using multiple connections in settings.php.',
+      '--destination_database' => 'The DESTINATION DB connection key if using multiple DB connections',
+    ),
+  );
+  $items['sql sync'] = array(
+    'callback' => 'drush_sql_sync',
+    'description' => 'Copy source database to target database using rsync.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
+    'examples' => array(
+      'drush sql sync prod dev' => 'Copy the DB defined in sites/prod to the DB in sites/dev.',
+    ),
+    'optional-arguments' => TRUE,
+    'arguments' => array(
+      'from' => 'Name of subdirectory within /sites or a site alias.',
+      'to' => 'Name of subdirectory within /sites or a site alias.',
+    ),
     'options' => array(
       '--skip-tables-key' => 'A key in the $skip_tables array. @see example.drushrc.php. Optional.',
       '--structure-tables-key' => 'A key in the $structure_tables array. @see example.drushrc.php. Optional.',
@@ -115,18 +138,22 @@ function drush_sql_conf() {
 /**
  * Command callback. Emits a connect string for mysql or pgsql.
  */
-function drush_sql_connect() {
+function _drush_sql_connect($db_spec = NULL) {
   switch (_drush_sql_get_scheme()) {
     case 'mysql':
       $command = 'mysql ' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
-      $command .= _drush_sql_get_credentials();
+      $command .= _drush_sql_get_credentials($db_spec);
       break;
     case 'pgsql':
-      $command = 'psql -d ';
-      $command .= _drush_sql_get_credentials();
+      $command = 'psql';
+      $command .= _drush_sql_get_credentials($db_spec);
       break;
   }
-  drush_print($command);
+  return $command;
+}
+
+function drush_sql_connect() {
+  drush_print(_drush_sql_connect());
 }
 
 /**
@@ -166,57 +193,73 @@ function drush_sql_dump($db_spec = NULL)
   }
   $database = $db_spec['database'];
 
+  if (is_null($db_spec)) {
+    $db_spec = _drush_sql_get_db_spec();
+  }
+  
+  $single_table = drush_get_option('table');
   switch (_drush_sql_get_scheme()) {
     case 'mysql':
-      if (is_null($db_spec)) {
-        $db_spec = _drush_sql_get_db_spec();
-      }
-
       $exec = 'mysqldump' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
       if ($file = drush_get_option('result-file')) {
         $exec .= ' --result-file '. $file;
       }
       $extra = ' --single-transaction --opt -Q' . _drush_sql_get_credentials($db_spec);
       $exec .= $extra;
-
-      // Append the ignore-table options.
-      foreach ($skip_tables as $table) {
-        $ignores[] = "--ignore-table=$database.$table";
+      
+      if ($single_table) {
+        $exec .= ' ' . $single_table;
       }
-      $exec .= ' '. implode(' ', $ignores);
+      else {
+        // Append the ignore-table options.
+        foreach ($skip_tables as $table) {
+          $ignores[] = "--ignore-table=$database.$table";
+        }
+        $exec .= ' '. implode(' ', $ignores);
 
-      // Run mysqldump again and append output if we need some structure only tables.
-      if (!empty($structure_tables)) {
-        $exec .= "; mysqldump --no-data $extra " . implode(' ', $structure_tables);
-        if ($file) {
-          $exec .= " >> $file";
+        // Run mysqldump again and append output if we need some structure only tables.
+        if (!empty($structure_tables)) {
+          $exec .= "; mysqldump --no-data $extra " . implode(' ', $structure_tables);
+          if ($file) {
+            $exec .= " >> $file";
+          }
         }
       }
       break;
     case 'pgsql':
-      if (is_null($db_spec)) {
-        $db_spec = _drush_sql_get_db_spec();
-      }
-
-      $exec = 'pg_dump --clean ' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
+      $create_db = drush_get_option('create-db');
+      $exec = 'pg_dump ' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
       if ($file = drush_get_option('result-file')) {
         $exec .= ' --file '. $file;
       }
-      $extra = ' ' . _drush_sql_get_credentials($db_spec);
+      // Unlike psql, pg_dump does not take a '-d' flag before the database name.
+      // We'll put the database name in 'by hand' and then clear the name from
+      // the record to prevent _drush_sql_get_credentials from inserting a -d term
+      // that pg_dump does not understand.
+      $extra = ' ' . $db_spec['database'];
+      $db_spec['database'] = null;
+      $extra .= _drush_sql_get_credentials($db_spec);
       $exec .= $extra;
-      foreach ($skip_tables as $table) {
-        $ignores[] = "--exclude-table=$table";
+      
+      if (isset($single_table)) {
+        $exec .= ' --data-only -t ' . $single_table;
       }
-      $exec .= ' '. implode(' ', $ignores);
-      // Run pg_dump again and append output if we need some structure only tables.
-      if (!empty($structure_tables)) {
-        $schemaonlies = array();
-	foreach ($structure_tables as $table) {
-          $schemaonlies[] = "--table=$table";
+      else {
+        $exec .= (!isset($create_db) ? '--clean ' : '');
+        foreach ($skip_tables as $table) {
+          $ignores[] = "--exclude-table=$table";
         }
-        $exec .= "; pg_dump --schema-only " . implode(' ', $schemaonlies) . $extra;
-        if ($file) {
-          $exec .= " >> $file";
+        $exec .= ' '. implode(' ', $ignores);
+        // Run pg_dump again and append output if we need some structure only tables.
+        if (!empty($structure_tables)) {
+          $schemaonlies = array();
+          foreach ($structure_tables as $table) {
+            $schemaonlies[] = "--table=$table";
+          }
+          $exec .= "; pg_dump --schema-only " . implode(' ', $schemaonlies) . $extra;
+          if ($file) {
+            $exec .= " >> $file";
+          }
         }
       }
       break;
@@ -229,22 +272,25 @@ function drush_sql_dump($db_spec = NULL)
  * Command callback. Executes the given SQL query on the Drupal database.
  */
 function drush_sql_query($query) {
+  return _drush_sql_query($query);
+}
+
+function _drush_sql_query($query, $db_spec = NULL) {
   // Save $query to a tmp file. We will redirect it in.
   if ($file = drush_save_data_to_temp_file($query)) {
     switch (_drush_sql_get_scheme()) {
       case 'mysql':
         $exec = 'mysql' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
-        $exec .= _drush_sql_get_credentials();
+        $exec .= _drush_sql_get_credentials($db_spec);
         $exec .= drush_get_option('extra');
         $exec .= " < $file";
 
         break;
       case 'pgsql':
-        $exec = 'psql -d ';
-        $exec .= _drush_sql_get_credentials();
+        $exec = 'psql';
+        $exec .= _drush_sql_get_credentials($db_spec);
         $exec .= (drush_get_context('DRUSH_VERBOSE') ? '' : ' -q');
-        $exec .= ' --file -';
-        $exec .= " < $file";
+        $exec .= ' --file $file';
         break;
     }
     
@@ -254,6 +300,182 @@ function drush_sql_query($query) {
   }
 }
 
+function drush_sql_sync($source, $destination) {
+  // Expand the source and destination specifications into options
+  drush_expand_site_specification($source, 'source-');
+  drush_expand_site_specification($destination, 'target-');
+
+  // Get the options for the source and target databases
+  $source = _drush_sql_get_spec_from_options('source-');
+  $source_remote_host = drush_get_option('source-remote-host');
+  $source_remote_port = drush_get_option('source-remote-port');
+
+  $target = _drush_sql_get_spec_from_options('target-');
+  $target_remote_host = drush_get_option('target-remote-host');
+  $target_remote_port = drush_get_option('target-remote-port');
+    
+  // Prompt for confirmation. This is destructive.
+  if (!drush_get_context('DRUSH_SIMULATE')) {
+    $txt_source = (isset($source_remote_host) ? $source_remote_host . '/' : '') . $source['database'];
+    $txt_destination = (isset($target_remote_host) ? $target_remote_host . '/' : '') . $target['database'];
+    drush_print(dt("You will destroy data from !target and replace with data from !source.", array('!source' => $txt_source, '!target' => $txt_destination)));
+    drush_print();
+    // TODO: actually make the backup if desired.
+    drush_print(dt("You might want to make a backup first, using sql_dump command.\n"));
+    if (!drush_confirm(dt('Do you really want to continue?'))) {
+      drush_die('Aborting.');
+    }
+  }
+
+  // Set up the result file and the remote file.
+  // If the result file is not set, then create a temporary file.
+  // If the remote file is not set, use the same name for the remote
+  // and local files and hope for the best.
+  $source_dump = drush_get_option('source-dump');
+  if (!isset($source_dump)) {
+    $source_dump = tempnam(sys_get_temp_dir(), $source['database'] . '.sql.');
+    $source_is_tmp = TRUE;
+  }
+  $target_dump = drush_get_option('target-dump');
+  if (!isset($target_dump)) {
+    $target_dump = tempnam(sys_get_temp_dir(), $target['database'] . '.sql.');
+  }
+
+  if (isset($source_remote_host) && isset($target_remote_host)) {
+    $local_file = tempnam(sys_get_temp_dir(), $source['database'] . ($source['database'] == $target['database'] ? '' : '-to-' . $target['database']) . '.sql.');
+  }
+  elseif (!isset($source_remote_host) && !isset($target_remote_host)) {
+    $source_dump = $target_dump;
+    $local_file = $source_dump;
+    
+  }
+  elseif (!isset($source_remote_host)) {
+    $local_file = $source_dump;
+  }
+  else {
+    $local_file = $target_dump;
+  }
+
+  //
+  // If source is remote, then use ssh to dump the database and then rsync to local machine
+  // If source is local, call drush_sql_dump to dump the database to local machine
+  // In either case, the '--no-dump' option will cause the sql dump step to be skipped, and
+  // we will import from the existing local file (first using rsync to fetch it if it does not exist)
+  //  
+  // No dump affects both local and remote sql dumps; it prevents drush sql sync
+  // from calling sql dump when the local cache file is newer than the cache threshhold
+  // No sync affects the remote sql dump; it will prevent drush sql sync from
+  // rsyncing the local sql dump file with the remote sql dump file.
+  $no_sync = drush_get_option(array('no-sync', 'source-no-sync'));
+  $no_dump = drush_get_option(array('no-dump', 'source-no-dump'));
+  $cache = drush_get_option(array('cache', 'source-cache'));
+  if (!isset($cache)) {
+    $cache = 24; // default cache is 24 hours if nothing else is specified.
+  }
+  // If the 'cache' option is set, then we will set the no-dump option iff the
+  // target file exists and its modification date is less than "cache" hours.
+  if (isset($cache)) {
+    if (file_exists($local_file) && (filesize($local_file) > 0)) {
+      //drush_print('file ' . $local_file . ' exists; checking modification time for cache.');
+      if ((filemtime($local_file) - time()) < ($cache * 60 * 60)) {
+        //drush_print('modification time is less than ' . $cache . ' hours old.');
+        $no_dump = TRUE;
+        $no_sync = TRUE;
+      }
+    }
+  }
+  if (isset($source_remote_host)) {
+    if (isset($source_remote_port)) {
+      $source['port'] = $source_remote_port;
+    }
+    $source_remote_user = drush_get_option('source-remote-user'); 
+    if (isset($source_remote_user)) {
+      $source_at ='@';
+      $source_remote_pass = drush_get_option('source-remote-pass') ? ':' . drush_get_option('source-remote-pass') : '';
+    }
+    
+    if (!isset($no_dump)) {
+      $source_intermediate = $source_dump;
+      $mv_intermediate = '';
+      // If we are doing a remote dump and the source is not a temporary file,
+      // then first dump to a temporary file and move it to the specified file after 
+      // the dump is complete.  This will reduce contention during simultaneous dumps 
+      // from different users sharing the same dump file.
+      if (!isset($source_is_tmp)) {
+        $source_intermediate = $source_dump . '-' . date("U");
+        $mv_intermediate = '; mv -f ' . $source_intermediate . ' ' . $source_dump;
+      }
+      drush_set_option('result-file', $source_intermediate);
+      $dump_exec = drush_sql_dump($source) . $mv_intermediate;
+      if (isset($cache) && !isset($source_is_tmp)) {
+        // Inject some bash commands to remotely test the modification date of the target file
+        // if the cache option is set.
+        $dump_exec = 'if [ ! -s ' . $source_dump . '] || [ $((`date "+%s"`-`stat --format="%Y" ' . $source_dump . '`)) -gt ' . ($cache * 60 *  60) . ' ] ; then ' . $dump_exec . '; fi';
+      }
+      $dump_exec = 'ssh ' . $source_remote_user . $source_at . $source_remote_host . ' ' . escapeshellarg($dump_exec) . ' && ';
+    }
+    if (!isset($no_sync)) {
+      $dump_exec = $dump_exec . 'rsync ' . $source_remote_user . $source_remote_pass . $source_at . $source_remote_host . ':' . $source_dump . ' ' . $local_file;
+    }
+    // TODO:  Delete the remote source file here if it is a temporary file.
+  }
+  else {
+    if (!isset($no_dump)) {
+      drush_set_option('result-file', $local_file);
+      $dump_exec = drush_sql_dump($source);
+    }
+  }
+  
+  if (!empty($dump_exec)) {
+    drush_op('system', $dump_exec);
+    // TODO: IF FAILURE THEN ABORT
+  }
+  
+  // Prior to database import, we will generate a "create database" command
+  // if the '--create-db' option was specified.  Note that typically the
+  // web server user will not have permissions to create a database; to specify
+  // a different user to use with the create db command, the '--db-su' option
+  // may be used.
+  // Under postgres, "alter role username with createdb;" will give create database 
+  // permissions to the specified user if said user was not created with this right.
+  $create_db_command = '';
+  $create_db = drush_get_option('create-db');
+  if (isset($create_db)) {
+    $create_db_target = $target;
+    $create_db_target['database'] = '';
+    $db_superuser = drush_get_option(array('db-su', 'target-db-su'));
+    if (isset($db_superuser)) {
+      $create_db_target['username'] = $db_superuser;
+    }
+    $db_su_connect = _drush_sql_connect($create_db_target);
+    $create_db_command = 'echo "create database ' . $target['database'] . '" | ' . $db_su_connect . '; ';
+  }
+  
+  // If destination is remote, then use rsync to push the database, then use ssh to import the database
+  // If destination is local, then just import the database locally
+  if (isset($target_remote_host)) {
+    if (isset($target_remote_port)) {
+      $target['port'] = $target_remote_port;
+    }
+    $target_remote_user = drush_get_option('target-remote-user'); 
+    if (isset($target_remote_user)) {
+      $target_at ='@';
+      $target_remote_pass = drush_get_option('target-remote-pass') ? ':' . drush_get_option('target-remote-pass') : '';
+    }
+        
+    $connect_exec = $create_db_command . _drush_sql_connect($target) . ' < ' . $target_dump;
+    $import_exec = 'rsync ' . $local_file . ' ' . $target_remote_user . $target_remote_pass . $target_at . $target_remote_host . ':' . $target_dump;
+    $import_exec = $import_exec . '; ssh ' . $target_remote_user . $target_at . $target_remote_host . ' ' . escapeshellarg($connect_exec);
+    // TODO:  we could easily delete the remote target file here if it is a temporary file
+  }
+  else {
+    $import_exec = $create_db_command . _drush_sql_connect($target) . ' < ' . $local_file;
+  }
+  
+  drush_op('system', $import_exec);
+  // TODO:  delete local temporary files
+}
+
 /**
  * Copy an entire database to another database. For example, migrate from production to dev
  * or dev to staging.
@@ -267,8 +489,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')) {
@@ -296,7 +520,7 @@ function drush_sql_load($source, $destin
       $send = 'mysql' . _drush_sql_get_credentials($destination);
       break;
     case 'pgsql':
-      $send .= 'psql -d ' . _drush_sql_get_credentials($destination) . ' --file -';
+      $send .= 'psql' . _drush_sql_get_credentials($destination) . ' --file -';
       break;
     }
     
@@ -314,7 +538,7 @@ function drush_sql_cli() {
       $command .= _drush_sql_get_credentials();
       break;
     case 'pgsql':
-      $command = ' psql -d ';
+      $command = ' psql';
       $command .= _drush_sql_get_credentials();
       break;
   }
@@ -367,6 +591,18 @@ 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();
+  }
+  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
@@ -384,6 +620,19 @@ function _drush_sql_get_spec_from_settin
   return _drush_sql_get_db_spec();
 }
 
+function _drush_sql_get_spec_from_options($prefix) {
+  $alias = drush_get_option($prefix . 'uri');
+  if (isset($alias)) {
+    return _drush_sql_get_spec_from_site_alias($alias, $prefix);
+  }
+  else {
+    global $db_url;
+  
+    $db_url = drush_get_option($prefix . 'db-url');
+    return _drush_sql_get_db_spec();
+  }
+}
+
 function _drush_sql_get_scheme($db_spec = NULL) {
   if (is_null($db_spec)) {
     $db_spec = _drush_sql_get_db_spec();
@@ -398,31 +647,27 @@ function _drush_sql_get_scheme($db_spec 
  * @return string
  */
 function _drush_sql_get_credentials($db_spec = NULL) {
+  if (is_null($db_spec)) {
+    $db_spec = _drush_sql_get_db_spec();
+  }
+  
   switch (_drush_sql_get_scheme()) {
     case 'mysql':
-      if (is_null($db_spec)) {
-        $db_spec = _drush_sql_get_db_spec();
-      }
-
       $cred = ' -h' . $db_spec['host'] .
          (empty($db_spec['port']) ? '' : ' -P' . $db_spec['port']) .
          ' -u' . $db_spec['username'] .
          (empty($db_spec['password']) ? '' : ' -p' . $db_spec['password']) . ' ' . $db_spec['database'];
       break;
   case 'pgsql':
-      if (is_null($db_spec)) {
-        $db_spec = _drush_sql_get_db_spec();
-      }
-
-      $cred = $db_spec['database'] . ' ' .
-         (empty($db_spec['host']) || ($db_spec['host'] == "localhost") ? '' : '-h ' . $db_spec['host']) . ' ' .
-         (empty($db_spec['port']) ? '' : '-p' . $db_spec['port']) . ' ';
+      $cred = (isset($db_spec['database']) ? ' -d ' . (empty($db_spec['database']) ? 'template1' :  $db_spec['database']) : '') .
+         (empty($db_spec['host'])  ? ' -h localhost ' : ' -h ' . $db_spec['host']) .
+         (empty($db_spec['port']) ? ' -p 5432 ' : ' -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
       // "local all all ident sameuser" in your Postgres pg_hba.conf file.
       // See: http://drupal.org/node/438828
-      // $cred .= '-U ' . $db_spec['username'] . ' ';
+      $cred .= ' -U ' . $db_spec['username'] . ' ';
       break;
   }
   return escapeshellcmd($cred);
Index: includes/backend.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/backend.inc,v
retrieving revision 1.15
diff -u -p -r1.15 backend.inc
--- includes/backend.inc	20 May 2009 21:26:55 -0000	1.15
+++ includes/backend.inc	19 Jun 2009 06:01:06 -0000
@@ -233,7 +233,13 @@ function _drush_proc_open($cmd, $data = 
  *   If the command was completed, this will return an associative array containing the data from drush_backend_output().
  */
 function drush_backend_invoke($command, $data = array(), $method = 'GET', $integrate = TRUE, $drush_path = NULL, $hostname = NULL, $username = NULL) {
-  $cmd = _drush_backend_generate_command($command, $data, $method, $drush_path, $hostname, $username);
+  $args = explode(" ", $command);
+  $command = array_shift($args);
+  return drush_backend_invoke_args($command, $args, $data, $method, $integrate, $drush_path, $hostname, $username);
+}
+
+function drush_backend_invoke_args($command, $args, $data = array(), $method = 'GET', $integrate = TRUE, $drush_path = NULL, $hostname = NULL, $username = NULL) {
+  $cmd = _drush_backend_generate_command($command, $args, $data, $method, $drush_path, $hostname, $username);
   drush_log(dt('Running: !cmd', array('!cmd' => $cmd)), 'command');
   return _drush_backend_invoke($cmd, $data, $integrate);
 }
@@ -280,9 +286,11 @@ function _drush_backend_invoke($cmd, $da
 
 /**
  * Generate a command to execute.
-
+ *
  * @param command
  *    A defined drush command such as 'cron', 'status' or any of the available ones such as 'drush pm'.
+ * @param args
+ *    An array or arguments for the command.
  * @param data
  *    Optional. An array containing options to pass to the remote script.
  *    Array items with a numeric key are treated as optional arguments to the command.
@@ -308,20 +316,18 @@ function _drush_backend_invoke($cmd, $da
  * @return
  *   A text string representing a fully escaped command.
  */
-function _drush_backend_generate_command($command, &$data, $method = 'GET', $drush_path = null, $hostname = null, $username = null) {
+function _drush_backend_generate_command($command, $args, &$data, $method = 'GET', $drush_path = null, $hostname = null, $username = null) {
   $drush_path = !is_null($drush_path) ? $drush_path : DRUSH_COMMAND; // Call own drush.php file.
   $data['root'] = ($data['root']) ? $data['root'] : drush_get_context('DRUSH_DRUPAL_ROOT');
   $data['uri'] = array_key_exists('uri', $data) ? $data['uri'] : drush_get_context('DRUSH_URI');
 
   $option_str = _drush_backend_argument_string($data, $method);
-  $args = explode(" ", $command);
   foreach ($data as $key => $arg) {
     if (is_numeric($key)) {
       $args[] = $arg;
       unset($data[$key]);
     }
   }
-  $command = '';
   foreach ($args as $arg) {
     $command .= ' ' . escapeshellarg($arg);
   }
@@ -347,7 +353,9 @@ function _drush_backend_generate_command
  */
 function drush_backend_fork($command, $data, $drush_path = null, $hostname = null, $username = null) {
   $data['quiet'] = TRUE;
-  $cmd = "(" . _drush_backend_generate_command($command, $data, 'GET', $drush_path, $hostname, $username) . ' &) > /dev/null';
+  $args = explode(" ", $command);
+  $command = array_shift($args);
+  $cmd = "(" . _drush_backend_generate_command($command, $args, $data, 'GET', $drush_path, $hostname, $username) . ' &) > /dev/null';
   drush_log(dt("Forking : !cmd", array('!cmd' => $cmd)));
   system($cmd);
 }
Index: includes/command.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/command.inc,v
retrieving revision 1.36
diff -u -p -r1.36 command.inc
--- includes/command.inc	27 May 2009 19:38:12 -0000	1.36
+++ includes/command.inc	19 Jun 2009 06:01:06 -0000
@@ -147,6 +147,16 @@ function drush_get_commands() {
  */
 function drush_parse_command() {
   $args = drush_get_arguments();
+  
+  // Test to see if the first arg is a site specification
+  if (drush_expand_site_specification($args[0])) {
+    array_shift($args);
+    // We only need to expand the site specification
+    // once, then we are done.  (Should we set a flag indicating
+    // that we already did this?  Otherwise 'drush alias1 alias2 command'
+    // would behave strangely.)
+    drush_set_arguments($args);
+  }
 
   // Get a list of all implemented commands.
   $implemented = drush_get_commands();
@@ -156,6 +166,7 @@ function drush_parse_command() {
   // Try to determine the handler for the current command.
   while (!$command && count($args)) {
     $part = implode(" ", $args);
+    drush_log(dt("part is !part", array('!part' => $part)));
     if (isset($implemented[$part])) {
       $command = $implemented[$part];
     }
@@ -167,7 +178,15 @@ function drush_parse_command() {
   // We have found a command that matches. Set the appropriate values.
   if ($command) {
     $arguments = array_reverse($arguments);
-
+    // If the command has the 'optional-arguments' flag set, then
+    // insure that there are enough arguments provided on the command
+    // line.  Keep adding null parameters until there are enough.
+    if (isset($command['optional-arguments']) && isset($command['arguments'])) {
+      while (count($arguments) < count($command['arguments'])) {
+        $arguments[] = null;
+      }
+    }
+    
     // Merge specified callback arguments, which precede the arguments passed on the command line.
     if (isset($command['callback arguments']) && is_array($command['callback arguments'])) {
       $arguments = array_merge($command['callback arguments'], $arguments);
Index: includes/context.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/context.inc,v
retrieving revision 1.8
diff -u -p -r1.8 context.inc
--- includes/context.inc	24 May 2009 18:42:09 -0000	1.8
+++ includes/context.inc	19 Jun 2009 06:01:06 -0000
@@ -265,7 +265,7 @@ function drush_get_option($option, $defa
   else {
     // We are not checking a specific context, so check them in a predefined order of precedence.
     static $contexts = array(
-      'process', 'options', 'stdin', 
+      'process', 'options', 'stdin', 'alias',
       'custom', 'site', 'drupal', 'user', 'system', 
       'drush', 'default');
 
@@ -290,7 +290,7 @@ function drush_get_option($option, $defa
  */
 function drush_get_merged_options() {
   static $contexts = array(
-      'process', 'options', 'stdin', 
+      'process', 'options', 'stdin', 'alias', 
       'custom', 'site', 'drupal', 'user', 'system',
       'drush', 'default');
   $cache = drush_get_context();
Index: includes/environment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/environment.inc,v
retrieving revision 1.36
diff -u -p -r1.36 environment.inc
--- includes/environment.inc	4 Jun 2009 19:48:55 -0000	1.36
+++ includes/environment.inc	19 Jun 2009 06:01:08 -0000
@@ -398,6 +398,9 @@ function _drush_bootstrap_drush() {
   // Load a drushrc.php file in the ~/.drush directory.
   drush_load_config('user');
 
+  // If the '-l' / '--uri' option is a site alias, then process it
+  _drush_process_site_alias();
+  
   $backend = drush_set_context('DRUSH_BACKEND', drush_get_option(array('b', 'backend')));
 
   if ($backend) {
@@ -432,6 +435,99 @@ function _drush_bootstrap_drush() {
   _drush_find_commandfiles(DRUSH_BOOTSTRAP_DRUSH);
 }
 
+function _drush_process_site_alias() {
+  return drush_expand_site_alias(drush_get_option(array('l', 'uri')));
+}
+
+function drush_expand_site_alias($alias, $prefix = '') {
+  if(isset($alias)) {
+    // Test to see if uri is a site alias
+    $all_site_aliases = drush_get_option('site-aliases', array());
+    if (array_key_exists($alias, $all_site_aliases)) {
+      $site_alias_settings = $all_site_aliases[$alias];
+      
+      // Transfer all non-array options from the site alias to the drush options
+      // in the 'alias' context.
+      foreach ($site_alias_settings as $key => $value) {
+        if (!is_array($value)) {
+	  drush_set_option($prefix . $key, $value, 'alias');
+	}
+      }
+      // Transfer selected path aliases to the drush options.
+      if (array_key_exists('path-aliases', $site_alias_settings)) {
+  	foreach (array('!root', '!drush', '!dump') 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');
+  	  }
+  	}
+      }
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+// Site specifications come in several forms:
+// 1.) /path/to/drupal#sitename
+// 2.) user@server/path/to/drupal#sitename
+// 3.) user@server/path/to/drupal            (sitename == server)
+// 4.) user@server#sitename                  (only if $option['r'] set in some drushrc file on server)
+// 5.) #sitename                             (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)      
+// 6.) sitename                              (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)      
+function drush_expand_site_specification($alias, $prefix = '') {
+  $result = FALSE;
+  if (!empty($alias)) {    
+    // Cases 1.) - 4.):
+    // We will check for a site specification if the alias has at least
+    // two characters from the set '@', '/', '#'.
+    if ((strpos($alias, '@') === FALSE ? 0 : 1) + (strpos($alias, '/') === FALSE ? 0 : 1) + (strpos($alias, '#') === FALSE ? 0 : 1) >= 2) {
+      if ((substr($alias,0,7) != 'http://') && (substr($alias,0,1) != '/')) {
+        // Add on a scheme so that "user:pass@server" will always parse correctly
+        $parsed = parse_url('http://' . $alias);
+      }
+      else {
+        $parsed = parse_url($alias);
+      }
+      foreach (array('host' => 'remote_host', 'user' => 'remote_user', 'pass' => 'remote_pass', 'path' => 'root', 'fragment' => 'uri') as $url_key => $option_key) {
+        if (array_key_exists($url_key, $parsed)) {
+          drush_set_option($prefix . $option_key, $parsed[$url_key]);
+	}
+      }
+      // Case 3.): If the URL contains a 'host' portion but no fragment, then set the uri to the host
+      // Note: We presume that 'server' is the best default for case 3; without this code, the default would
+      // be whatever is set in $options['l'] on the target machine's drushrc.php settings file.
+      if (array_key_exists('host', $parsed) && !array_key_exists('fragment', $parsed)) {
+        drush_set_option($prefix . 'uri', $parsed['host']);
+      }
+      $result = TRUE;
+    }
+    if ($result === FALSE) {
+      // Next test to see if it is a site alias.
+      $result = drush_expand_site_alias($alias, $prefix);
+    }
+    if ($result === FALSE) {
+      // Case 5.) and 6.):
+      // If the alias is the name of a folder in the 'sites' directory, 
+      // then use it as a local site specification.
+      // BUG WORKAROUND:  if we use 'drush_locate_root' we will set 'uri' after 
+      // drush_bootstrap_drush, which works.  If we use drush_get_context('DRUSH_DRUPAL_ROOT'),
+      // then we set 'uri' after drush_bootstrap_drupal_root, which seems like it should work
+      // but doesn't.
+      $drupal_root = drush_get_option(array('r', 'root'), drush_locate_root());
+      // drush_get_context('DRUSH_DRUPAL_ROOT');
+      if (substr($alias,0,1) == '#') {
+        $alias = substr($alias,1);
+      }
+      $site_settings_file = $drupal_root . '/sites/' . $alias . '/settings.php';
+      if (isset($drupal_root) && file_exists($site_settings_file)) {
+        drush_set_option($prefix . 'uri', $alias);
+        $result = TRUE;
+      }
+    }
+  }
+  return $result;
+}
+
 /**
  * Validate the DRUSH_BOOTSTRAP_DRUPAL_ROOT phase.
  *
