diff --git a/README-UNL.txt b/README-UNL.txt
index 26af2b9a9157b9c330d6067c6a42a26d5dd3307a..3ad8986803a49d0d4302a8d55c817def92724c5a 100644
--- a/README-UNL.txt
+++ b/README-UNL.txt
@@ -10,12 +10,18 @@ function conf_path()
 
 ------------------------------------
 
-sites/all/modules/drush/commands/core/drupal/site_install_7.inc
+sites/all/modules/drush/commands/core/drupal/site_install.inc
 function drush_core_site_install_version()
  * UNL change! Setting this to FALSE because we don't want them and they're hard coded.
 
 ------------------------------------
 
+drush/commands/core/site_install.drush.inc
+function drush_core_pre_site_install()
+ * UNL change: Inserted a return before code that would otherwise drop the entire database.
+
+-------------------------------------
+
 rewrite.php
 used to allow public files to be accessed without the sites/<site_dir>/files prefix
 
@@ -40,6 +46,12 @@ includes/bootstrap.inc
 
 -------------------------------------
 
+drush/includes/environment.inc
+ * Fix so that drush pulls in the correct uri parameter.
+ * http://drupal.org/node/1331106
+
+-------------------------------------
+
 sites/sites.php
  * Added support for $default_domains array. See includes/bootstrap.inc conf_path().
 
diff --git a/sites/all/modules/drush/README.txt b/sites/all/modules/drush/README.txt
index 6895bdb092a1c47e0b4b26ed1903873272f721c6..305278bc7a5ccd6d7ca7ef4d478266d5b90a18fe 100644
--- a/sites/all/modules/drush/README.txt
+++ b/sites/all/modules/drush/README.txt
@@ -1,4 +1,3 @@
-// $Id: README.txt,v 1.52 2010/11/08 13:22:42 weitzman Exp $
 
 DESCRIPTION
 -----------
@@ -8,17 +7,14 @@ for your shell (e.g. man bash) or reading an online tutorial (e.g. search
 for "bash tutorial") will help you get the most out of Drush.
 
 Drush core ships with lots of useful commands for interacting with code
-like modules/themes/profiles/translations. Similarly, it runs update.php, executes sql
+like modules/themes/profiles. Similarly, it runs update.php, executes sql
 queries and DB migrations, and misc utilities like run cron or clear cache.
 
 REQUIREMENTS
 ------------
 * To use drush from the command line, you'll need a CLI-mode capable PHP
   binary. The minimum PHP version is 5.2.
-* drush also runs on Windows; however, drush commands make use of
-  unix command line tools, so to use it effectively, you have to install
-  some of them, e.g. from GnuWin32 (http://gnuwin32.sourceforge.net/). More info
-  about Drush on Windows available at http://drupal.org/node/594744.
+* Drush 4 does not support Windows; see "For Windows", below.
 * Drush works with Drupal 5, Drupal 6 and Drupal 7.  However, occasionally
   recent changes to the most recent version of Drupal can introduce issues
   with drush.  On Drupal 5, drush requires update_status v5.x-2.5 or later
@@ -88,17 +84,11 @@ For Linux/Unix/Mac:
     If you have troubles, try using the -l and -r options when invoking drush. See below.
 
 For Windows:
-  - Follow step 1. Use drush by navigating to /path/to/drush
-    and running 'drush.bat'.
-  - You have to install gzip, libarchive, tar and wget executables. Go to
-    http://gnuwin32.sourceforge.net/packages.html and install the packages.
-    Add the folder %ProgramFiles%\GnuWin32\bin to your PATH.
-    Documentation can be found at http://drupal.org/node/594744
-  - Whenever the documentation or the help text refers to
-   'drush [option] <command>' or something similar, 'drush' has to be replaced
-    by 'drush.bat'.
-  - If drush.bat is not working for you, either add the directory in which your
-    php.exe resides to your PATH or edit drush.bat to point to your php.exe.
+  - Drush 4 does not support Windows.  Consider using Drush 3 or Drush 5 instead.
+  - Consider using on Linux/Unix/OSX using Virtualbox or other VM. Windows support is lacking.
+  - The Drush 5 Windows installer can be found at http://drush.ws/drush_windows_installer.
+  - Instructions for installing Drush 3 on Windows can be found at 
+    http://drupal.org/node/594744.
 
 USAGE
 -----
@@ -111,6 +101,10 @@ Use the 'help' command to get a list of available options and commands:
 
   $ drush help
 
+For even more documentation, use the 'topic' command:
+
+  $ drush topic
+
 For multisite installations, you might need to use the -l or other command line
 options just to get drush to work:
 
@@ -128,11 +122,11 @@ NOTE: If you do not specify a URI with -l and drush falls back to the default
 site configuration, Drupal's $GLOBAL['base_url'] will be set to http://default.
 This may cause some functionality to not work as expected.
 
-The drush cli command provide a customized bash shell with support for handy new
-functions like cdd which whisks you to any directory in your drupal site.
+The drush core-cli command provide a customized bash shell or lets you enhance
+your usual shell with its --pipe option.
 
 Many commands support a --pipe option which returns machine readable output. See
-`drush pm-list --status=enabled --pipe` as an example
+`drush pm-list --status=enabled --pipe` as an example.
 
 Very intensive scripts can exhaust your available PHP memory. One remedy is to 
 just restart automatically using bash. For example:
@@ -196,4 +190,4 @@ CREDITS
 Originally developed by Arto Bendiken <http://bendiken.net/> for Drupal 4.7.
 Redesigned by Franz Heinzmann (frando) <http://unbiskant.org/> in May 2007 for Drupal 5.
 Maintained by Moshe Weitzman <http://drupal.org/moshe> with much help from
-Owen Barton, Adrian Rossouw, greg.1.anderson.
+Owen Barton, Adrian Rossouw, greg.1.anderson, jonhattan.
diff --git a/sites/all/modules/drush/commands/core/archive.drush.inc b/sites/all/modules/drush/commands/core/archive.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8ea6fbe5fa4c6c11730db6be38c6ca9abc9b81e7
--- /dev/null
+++ b/sites/all/modules/drush/commands/core/archive.drush.inc
@@ -0,0 +1,311 @@
+<?php
+
+/**
+ * @file
+ *   An early implementation of Site Archive dump/restore. See
+ *   http://groups.drupal.org/site-archive-format.
+ */
+
+function archive_drush_command() {
+  $items['archive-dump'] = array(
+    'description' => 'Backup your code, files, and database into a single file.',
+    'arguments' => array(
+      'targets' => 'Optional. Site specifications, delimited by commas. Typically, list subdirectory name(s) under /sites.',
+    ),
+    'options' => array(
+      'description' => 'Describe the archive contents.',
+      'tags' => 'Add tags to the archive manifest. Delimit multiple by commas.',
+      'destination' => 'The full path and filename in which the archive should be stored. If omitted, it will be saved to the drush-backups directory and a filename will be generated.',
+      'overwrite' => 'Do not fail if the destination file exists; overwrite it instead.',
+      'generator' => 'The generator name to store in the MANIFEST file. The default is "Drush archive-dump".',
+      'generatorversion' => 'The generator version number to store in the MANIFEST file. The default is ' . DRUSH_VERSION . '.',
+      'pipe' => 'Only print the destination of the archive. Useful for scripts that don\'t pass --destination.',
+    ),
+    'examples' => array(
+      'drush archive-dump default,example.com,foo.com' => 'Write an archive containing 3 sites in it.',
+      'drush archive-dump @sites' => 'Save archive containing all sites in a multi-site.',
+      'drush archive-dump default --destination=/backups/mysite.tar' => 'Save archive to custom location.',
+    ),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
+    'aliases' => array('ard', 'archive-backup', 'arb'),
+  );
+  $items['archive-restore'] = array(
+    'description' => 'Expand a site archive into a Drupal web site.',
+    'arguments' => array(
+      'file' => 'The site archive file that should be expanded.',
+      'site name' => 'Optional. Which site within the archive you want to restore. Defaults to all.',
+    ),
+    'options' => array(
+      'destination' => 'Specify where the Drupal site should be expanded. Defaults to the current working directory.',
+      'db-prefix' => 'An optional table prefix to use during restore.',
+      'db-url' => 'A Drupal 6 style database URL indicating the target for database restore. If not provided, the archived settings.php is used.',
+      'db-su' => 'Account to use when creating the new database. Optional.',
+      'db-su-pw' => 'Password for the "db-su" account. Optional.',
+      'overwrite' => 'Allow drush to overwrite any files in the destinion.',
+
+    ),
+    'examples' => array(
+      'drush archive-restore ./example.tar.gz' => 'Restore the files and databases for all sites in the archive.',
+      'drush archive-restore ./example.tar.gz example.com' => 'Restore the files and database for example.com site.',
+      'drush archive-restore ./example.tar.gz --destination=/var/www/example.com/docroot' => 'Restore archive to a custom location.',
+      'drush archive-restore ./example.tar.gz --db-url=mysql://root:pass@127.0.0.1/dbname' => 'Restore archive to a new database (and customize settings.php to point there.).',
+    ),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'aliases' => array('arr'),
+  );
+  return $items;
+}
+
+/**
+ * Command callback. Generate site archive file.
+ */
+function drush_archive_dump($sites_subdirs = '@self') {
+  $aliases = drush_sitealias_resolve_sitespecs(explode(',', $sites_subdirs));
+  foreach ($aliases as $key => $alias) {
+    if (($db_record = sitealias_get_databases_from_record($alias))) {
+      $full[$key] = $alias += $db_record;
+    }
+    else {
+      drush_log(dt('DB connections not found for !alias', array('!alias' => $alias)), 'error');
+      return;
+    }
+  }
+
+  // The user can specify a destination filepath or not. That filepath might
+  // end with .gz, .tgz, or something else. At the end of this command we will
+  // gzip a file, and we want it to end up with the user-specified name (if
+  // any), but gzip renames files and refuses to compress files ending with
+  // .gz and .tgz, making our lives difficult. Solution:
+  //
+  // 1. Create a unique temporary base name to which gzip WILL append .gz.
+  // 2. If no destination is provided, set $dest_dir to a backup directory and
+  // $final_destination to be the unique name in that dir.
+  // 3. If a destination is provided, set $dest_dir to that directory and
+  // $final_destination to the exact name given.
+  // 4. Set $destination, the actual working file we will build up, to the
+  // unqiue name in $dest_dir.
+  // 5. After gzip'ing $destination, rename $destination.gz to
+  // $final_destination.
+  //
+  // Sheesh.
+
+  // Create the unique temporary name.
+  $date = gmdate('Ymd_his');
+  $first = current($full);
+  $prefix = count($sites_subdirs) > 1 ? 'multiple_sites' : $first['default']['default']['database'];
+  $temp_dest_name = "$prefix.$date.tar";
+
+  $final_destination = drush_get_option('destination');
+  if (!$final_destination) {
+    // No destination provided.
+    drush_include_engine('version_control', 'backup');
+    $backup = new drush_pm_version_control_backup();
+    // TODO: this standard drush pattern leads to a slightly obtuse directory structure.
+    $dest_dir = $backup->prepare_backup_dir('archive-dump');
+    if (empty($dest_dir)) {
+      $dest_dir = drush_tempdir();
+    }
+    $final_destination = "$dest_dir/$temp_dest_name.gz";
+  }
+  else {
+    // Use the supplied --destination. If it is relative, resolve it
+    // relative to the directory in which drush was invoked.
+    $command_cwd = getcwd();
+    drush_op('chdir', drush_get_context('DRUSH_OLDCWD', getcwd()));
+    // This doesn't perform realpath on the basename, but that's okay. This is
+    // not path-based security. We just use it for checking for perms later.
+    $dest_dir = realpath(dirname($final_destination));
+    $final_destination = $dest_dir . '/' . basename($final_destination);
+    drush_op('chdir', $command_cwd);
+  }
+
+  // $dest_dir is either the backup directory or specified directory. Set our
+  // working file.
+  $destination = "$dest_dir/$temp_dest_name";
+
+  // Validate the FINAL destination. It should be a file that does not exist
+  // (unless --overwrite) in a writable directory (and a writable file if
+  // it exists). We check all this up front to avoid failing after a long
+  // dump process.
+  $overwrite = drush_get_option('overwrite');
+  $dest_dir = dirname($final_destination);
+  $dt_args = array('!file' => $final_destination, '!dir' => $dest_dir);
+  if (is_dir($final_destination)) {
+    drush_set_error('DRUSH_ARCHIVE_DEST_IS_DIR', dt('destination !file must be a file, not a directory.', $dt_args));
+    return;
+  }
+  else if (file_exists($final_destination)) {
+    if (!$overwrite) {
+      drush_set_error('DRUSH_ARCHIVE_DEST_EXISTS', dt('destination !file exists; specify --overwrite to overwrite.', $dt_args));
+      return;
+    }
+    else if (!is_writable($final_destination)) {
+      drush_set_error('DRUSH_ARCHIVE_DEST_FILE_NOT_WRITEABLE', dt('destination !file is not writable.', $dt_args));
+      return;
+    }
+  }
+  else if (!is_writable(dirname($final_destination))) {
+    drush_set_error('DRUSH_ARCHIVE_DEST_DIR_NOT_WRITEABLE', dt('destination directory !dir is not writable.', $dt_args));
+    return;
+  }
+
+  $docroot_path = realpath(drush_get_context('DRUSH_DRUPAL_ROOT'));
+  $docroot = basename($docroot_path);
+  $workdir = dirname($docroot_path);
+  // Archive Drupal core, excluding sites dir.
+  drush_shell_cd_and_exec($workdir, "tar --exclude '{$docroot}/sites' --dereference -cf %s %s", $destination, $docroot);
+  // Add sites/all to the same archive.
+  drush_shell_cd_and_exec($workdir, "tar --dereference -rf %s %s", $destination, "{$docroot}/sites/all");
+
+  // Dump the database(s) for each site and add to the archive.
+  foreach ($full as $key => $alias) {
+    foreach ($alias['databases'] as $dbkey => $target) {
+      $tmp = drush_tempdir();
+      // Use a subdirectory name matching the docroot name.
+      drush_mkdir("{$tmp}/{$docroot}");
+      $result_file = "{$tmp}/{$target['default']['database']}.sql";
+      drush_set_option('result-file', $result_file);
+      $table_selection = drush_sql_get_table_selection();
+      list($dump_exec, $dump_file) = drush_sql_build_dump_command($table_selection, $target['default']);
+      drush_shell_exec($dump_exec);
+      drush_shell_cd_and_exec($tmp, 'tar --dereference -rf %s %s', $destination, basename($result_file));
+    }
+  }
+
+  // Build a manifest file AND add sites/$subdir to archive as we go.
+  $platform = array(
+    'datestamp' => time(),
+    'formatversion' => '1.0',
+    'generator' => drush_get_option('generator', 'Drush archive-dump'),
+    'generatorversion' => drush_get_option('generatorversion', DRUSH_VERSION),
+    'description' => drush_get_option('description', ''),
+    'tags' => drush_get_option('tags', ''),
+  );
+  $contents = drush_export_ini(array('Global' => $platform));
+
+  $i=0;
+  foreach ($full as $key => $alias) {
+    $status = drush_invoke_sitealias_args($alias, 'core-status', array(), array());
+
+    // Add the site specific directory to archive.
+    if (!empty($status['object']['%paths']['%site'])) {
+      drush_shell_cd_and_exec($workdir, "tar --dereference -rf %s %s", $destination,  "{$docroot}/sites/" . basename($status['object']['%paths']['%site']));
+    }
+
+    $site = array(
+      'docroot' => DRUPAL_ROOT,
+      'sitedir' => @$status['object']['%paths']['%site'],
+      'files-public' => @$status['object']['%paths']['%files'],
+      'files-private' => @$status['object']['%paths']['%private'],
+    );
+    // Add info for each DB connection (usually only 1);
+    foreach ($alias['databases'] as $dbkey => $target) {
+      $site["database-$dbkey-file"] = './' . $target['default']['database'] . '.sql';
+      $site["database-$dbkey-driver"] = $target['default']['driver'];
+    }
+    // The section title is the sites subdirectory name.
+    $info[basename($site['sitedir'])] = $site;
+    $contents .= "\n" . drush_export_ini($info);
+    unset($info);
+    $i++;
+  }
+  file_put_contents("{$tmp}/MANIFEST.ini", $contents);
+
+  // Add manifest to archive.
+  drush_shell_cd_and_exec($tmp, 'tar --dereference -rf %s %s', $destination, "MANIFEST.ini");
+
+  // Compress the archive
+  drush_shell_exec("gzip --no-name -f %s", $destination);
+
+  // gzip appends .gz unless the name already ends in .gz, .tgz, or .taz.
+  if ("{$destination}.gz" != $final_destination) {
+    drush_move_dir("{$destination}.gz", $final_destination, $overwrite);
+  }
+
+  drush_log(dt('Archive saved to !dest', array('!dest' => $final_destination)), 'ok');
+  drush_print_pipe($final_destination);
+  return $final_destination;
+}
+
+/**
+ * Command callback. Restore web site(s) from a site archive file.
+ */
+function drush_archive_restore($file, $site_id = NULL) {
+  $tmp = drush_tempdir();
+
+  if (!$files = drush_tarball_extract($file, $tmp)) {
+    return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_EXTRACT', dt('Unable to extract site archive tarball to !tmp.', array('!tmp' => $tmp)));
+  }
+
+  $manifest = $tmp . '/MANIFEST.ini';
+  if (file_exists($manifest)) {
+    if (!$ini = parse_ini_file($manifest, TRUE)) {
+      return drush_set_error('DRUSH_ARCHIVE_UNABLE_TO_PARSE_MANIFEST', dt('Unable to parse MANIFEST.ini in the archive.'));
+    }
+  }
+  else {
+    // No manifest. Try to find docroot and DB dump file.
+    $db_file = drush_scan_directory($tmp, '/\.sql$/',  array('.', '..', 'CVS'), 0, 0);
+    $directories = glob($tmp . '/*' , GLOB_ONLYDIR);
+    $ini = array(
+      'Global' => array(),
+      'default' => array(
+        'docroot' => reset($directories),
+        'sitedir' => 'sites/default',
+        'database-default-file' => key($db_file),
+      ),
+    );
+  }
+
+  // Grab the first site in the Manifest and move docroot to destination.
+  $ini_tmp = $ini;
+  unset($ini_tmp['Global']);
+  $first = array_shift($ini_tmp);
+  $docroot = basename($first['docroot']);
+  $destination = drush_get_option('destination', realpath('.') . "/$docroot");
+  if (!drush_move_dir("$tmp/$docroot", $destination, drush_get_option('overwrite'))) {
+    return drush_set_error('DRUSH_ARCHIVE_UNABLE _RESTORE_FILES', dt('Unable to restore files to !dest', array('!dest' => $destination)));
+  }
+
+  // Loop over sites and restore databases and append to settings.php.
+  foreach ($ini as $section => $site) {
+    if ($section != 'Global' && (is_null($site_id) || $section == $site_id) && !empty($site['database-default-file'])) {
+
+      // Restore database
+      $sql_file = $tmp . '/' . $site['database-default-file'];
+      if ($db_url = drush_get_option('db-url')) {
+        if (empty($site_id) && count($ini) >= 3) {
+          // TODO: Use drushrc to provide multiple db-urls for multi-restore?
+          return drush_set_error('DRUSH_ARCHIVE_UNABLE_MULTI_RESTORE', dt('You must specify a site to restore when the archive contains multiple sites and a db-url is provided.'));
+        }
+        $db_spec = drush_convert_db_from_db_url($db_url);
+      }
+      else {
+        $site_specification = $destination . '#' . $section;
+        if ($return = drush_invoke_sitealias_args($site_specification, 'sql-conf', array(), array('all' => TRUE), array('integrate' => FALSE, 'override-simulated' => TRUE))) {
+          $databases = $return['object'];
+          $db_spec = $databases['default']['default'];
+        }
+        else {
+          return drush_set_error('DRUSH_ARCHIVE_UNABLE_DISCOVER_DB', dt('Unable to get database details from db-url option or settings.php', array('!key' => $key)));
+        }
+      }
+      drush_sql_empty_db($db_spec);
+      _drush_sql_query(NULL, $db_spec, $sql_file);
+
+      // Append new DB info to settings.php.
+      if ($db_url) {
+        $settingsfile = $destination . '/' . $site['sitedir'] . '/settings.php';
+        chmod($settingsfile, 0755); // Need to do something here or else we can't write.
+        file_put_contents($settingsfile, "\n// Appended by drush archive-restore command.\n", FILE_APPEND);
+        if (drush_drupal_major_version() >= 7) {
+          file_put_contents($settingsfile, "\n" . '$databases = \'' . drush_sitealias_convert_db_from_db_url($db_url) . "';\n", FILE_APPEND);
+        }
+        else {
+          file_put_contents($settingsfile, "\n" . '$db_url = \'' . $db_url . "';\n", FILE_APPEND);
+        }
+      }
+    }
+  }
+  return $destination;
+}
diff --git a/sites/all/modules/drush/commands/core/cache.drush.inc b/sites/all/modules/drush/commands/core/cache.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d32a326b0167ad66c9409df417d6f240f5b48757
--- /dev/null
+++ b/sites/all/modules/drush/commands/core/cache.drush.inc
@@ -0,0 +1,227 @@
+<?php
+
+/**
+ * Implementation of hook_drush_command().
+ */
+function cache_drush_command() {
+  $items = array();
+
+  $items['cache-get'] = array(
+    'description' => 'Fetch a cached object and display it.',
+    'examples' => array(
+      'drush cache-get schema' => 'Display the data for the cache id "schema" from the "cache" bin.',
+      'drush cache-get update_available_releases update' => 'Display the data for the cache id "update_available_releases" from the "update" bin.',
+    ),
+    'arguments' => array(
+      'cid' => 'The id of the object to fetch.',
+      'bin' => 'Optional. The cache bin to fetch from.',
+    ),
+    'options' => array(
+      'format' => 'Format to output the object. Use "print_r" for print_r (default), "export" for var_export, and "json" for JSON.',
+    ),
+    'aliases' => array('cg'),
+  );
+  $items['cache-clear'] = array(
+    'description' => 'Clear a specific cache, or all drupal caches.',
+    'arguments' => array(
+      'type' => 'The particular cache to clear. Omit this argument to choose from available caches.',
+    ),
+    'aliases' => array('cc'),
+  );
+  $items['cache-set'] = array(
+    'description' => 'Cache an object expressed in JSON or var_export() format.',
+    'arguments' => array(
+      'cid' => 'The id of the object to set.',
+      'data' => 'The object to set in the cache. Use \'-\' to read the object from STDIN.',
+      'bin' => 'Optional. The cache bin to store the object in.',
+      'expire' => 'Optional. CACHE_PERMANENT, CACHE_TEMPORARY, or a Unix timestamp.',
+    ),
+    'options' => array(
+      'format' => 'Format to parse the object. Use "string" for string (default), and "json" for JSON.',
+      'cache-get' => 'If the object is the result a previous fetch from the cache, only store the value in the "data" property of the object in the cache.',
+    ),
+    'aliases' => array('cs'),
+  );
+
+  return $items;
+}
+
+/**
+ * Command callback for drush cache-clear.
+ */
+function drush_cache_clear($type = NULL) {
+  switch (drush_drupal_major_version()) {
+    case 5:
+      // clear preprocessor cache
+      drupal_clear_css_cache();
+
+      // clear core tables
+      $core = array('cache', 'cache_filter', 'cache_menu', 'cache_page');
+      $alltables = array_merge($core, module_invoke_all('devel_caches'));
+      foreach ($alltables as $table) {
+        cache_clear_all('*', $table, TRUE);
+      }
+      drush_print(dt('Cache cleared.'));
+      break;
+    case 6:
+    case 7:
+    default:
+      $types = drush_cache_clear_types();
+      // Check if the provided type ($type) is a valid cache type.
+      if ($type && !key_exists($type, $types)) {
+        return drush_set_error(dt("'!type' cache is not a valid cache type", array('!type' => $type)));
+      }
+
+      if ($type) {
+        drush_op($types[$type]);
+        drush_log(dt("'!name' cache was cleared", array('!name' => $type)), 'success');
+      }
+      else {
+        $choice = drush_choice($types, 'Enter a number to choose which cache to clear.', '!key');
+        if ($choice !== FALSE) {
+          call_user_func($types[$choice]);
+          drush_log(dt("'!name' cache was cleared", array('!name' => $choice)), 'success');
+        }
+      }
+      break;
+  }
+}
+
+/**
+ * Print an object returned from the cache.
+ *
+ * @param $cid
+ *   The cache ID of the object to fetch.
+ * @param $bin
+ *   Optional parameter to specify a specific bin to fetch from.
+ */
+function drush_cache_get($cid = NULL, $bin = NULL) {
+  if (!$cid) {
+    drush_log(dt('You must specify a cache id to fetch.'), 'error');
+    return;
+  }
+
+  if (!$bin) {
+    $bin = 'cache';
+  }
+
+  $result = cache_get($cid, $bin);
+  if (!empty($result)) {
+    switch (drush_get_option('format', 'print_r')) {
+      case 'export':
+        drush_print(var_export($result, TRUE));
+        return;
+      case 'json':
+        drush_print(drush_json_encode($result));
+        return;
+      case 'print_r':
+      default:
+        drush_print_r($result);
+        return;
+    }
+  }
+  else {
+    drush_log(dt('The !cid object in the !bin cache bin was not found.', array('!cid' => $cid, '!bin' => $bin)), 'error');
+  }
+}
+
+/**
+ * Set an object in the cache.
+ *
+ * @param $cid
+ *   The cache ID of the object to fetch.
+ * @param $data
+ *   The data to save to the cache, or '-' to read from STDIN.
+ * @param $bin
+ *   Optional parameter to specify a specific bin to fetch from.
+ * @param $expire
+ *   Optional parameter to specify the expiry of the cached object.
+ */
+function drush_cache_set($cid = NULL, $data = '', $bin = NULL, $expire = CACHE_PERMANENT) {
+  if (!$cid) {
+    drush_log(dt('You must specify a cache id to set.'), 'error');
+    return;
+  }
+
+  if ($data === '') {
+    drush_log(dt('The data to set must be non-empty.'), 'error');
+    return;
+  }
+
+  if (!$bin) {
+    $bin = 'cache';
+  }
+
+  if ($data == '-') {
+    $data = stream_get_contents(STDIN);
+  }
+
+  // Now, we parse the object.
+  switch (drush_get_option('format', 'string')) {
+    case 'json':
+      $data = drush_json_decode($data);
+      break;
+  }
+
+  if (drush_get_option('cache-get')) {
+    $data = $data->data;
+  }
+
+  switch(drush_drupal_major_version()) {
+    case 5:
+      cache_set($cid, $bin, $data, $expire);
+      break;
+    case 6:
+    case 7:
+    default:
+      cache_set($cid, $data, $bin, $expire);
+  }
+}
+
+function drush_cache_clear_types() {
+  $types = array(
+    'all' => 'drupal_flush_all_caches',
+    'theme registry' => 'drush_cache_clear_theme_registry',
+    'menu' => 'menu_rebuild',
+    'css+js' => 'drush_cache_clear_css_js',
+    'block' => 'drush_cache_clear_block',
+    'module list' => 'drush_get_modules',
+    'theme list' => 'drush_get_themes',
+  );
+  if (drush_drupal_major_version() >= 7) {
+    $types['registry'] = 'registry_update';
+  }
+  elseif (drush_drupal_major_version() == 6 && module_exists('autoload')) {
+    // TODO: move this to autoload module.
+    $types['registry'] = 'autoload_registry_update';
+  }
+  if (count(module_implements('node_grants'))) {
+    $types['nodeaccess'] = 'node_access_rebuild';
+  }
+
+  // Include the appropriate environment engine, so callbacks can use core
+  // version specific cache clearing functions directly.
+  drush_include_engine('drupal', 'environment');
+
+  // Command files may customize $types as desired.
+  drush_command_invoke_all_ref('drush_cache_clear', $types);
+  return $types;
+}
+
+function drush_cache_clear_theme_registry() {
+  drush_db_delete('cache', 'cid LIKE :theme_registry', array(':theme_registry' => 'theme_registry%'));
+}
+
+function drush_cache_clear_css_js() {
+  _drupal_flush_css_js();
+  drupal_clear_css_cache();
+  drupal_clear_js_cache();
+}
+
+/**
+ * Clear the cache of the block output.
+ */
+function drush_cache_clear_block() {
+  cache_clear_all(NULL, 'cache_block');
+}
+
diff --git a/sites/all/modules/drush/commands/core/clear.cache.inc b/sites/all/modules/drush/commands/core/clear.cache.inc
index 043b1a86181f039819c8c1f9cd2d67fbccdfc5cc..8b137891791fe96927ad78e64b0aad7bded08bdc 100644
--- a/sites/all/modules/drush/commands/core/clear.cache.inc
+++ b/sites/all/modules/drush/commands/core/clear.cache.inc
@@ -1,84 +1 @@
-<?php
-
-/**
- * Command callback for drush cache-clear.
- */
- function drush_core_cache_clear($type = NULL) {
-  switch (drush_drupal_major_version()) {
-    case 5:
-      // clear preprocessor cache
-      drupal_clear_css_cache();
-
-      // clear core tables
-      $core = array('cache', 'cache_filter', 'cache_menu', 'cache_page');
-      $alltables = array_merge($core, module_invoke_all('devel_caches'));
-      foreach ($alltables as $table) {
-        cache_clear_all('*', $table, TRUE);
-      }
-      drush_print(dt('Cache cleared.'));
-      break;
-    case 6:
-    case 7:
-    default:
-      $types = drush_cache_clear_types();
-      // Check if the provided type ($type) is a valid cache type.
-      if ($type && !key_exists($type, $types)) {
-        return drush_set_error(dt("'!type' cache is not a valid cache type", array('!type' => $type)));
-      }
-
-      if ($type) {
-        drush_op($types[$type]);
-        drush_log(dt("'!name' cache was cleared", array('!name' => $type)), 'success');
-      }
-      else {
-        $choice = drush_choice($types, 'Enter a number to choose which cache to clear.', '!key');
-        if ($choice !== FALSE) {
-          call_user_func($types[$choice]);
-          drush_log(dt("'!name' cache was cleared", array('!name' => $choice)), 'success');
-        }
-      }
-      break;
-  }
-}
-
-function drush_cache_clear_types() {
-  $types = array(
-    'all' => 'drupal_flush_all_caches',
-    'theme' => 'drush_cache_clear_theme_registry',
-    'menu' => 'menu_rebuild',
-    'css+js' => 'drush_cache_clear_css_js',
-    'block' => 'drush_cache_clear_block',
-  );
-  if (drush_drupal_major_version() >= 7) {
-    $types['registry'] = 'registry_update';
-  }
-  elseif (drush_drupal_major_version() == 6 && module_exists('autoload')) {
-    // TODO: move this to autoload module. 
-    $types['registry'] = 'autoload_registry_update';
-  }
-  if (count(module_implements('node_grants'))) {
-    $types['nodeaccess'] = 'node_access_rebuild';
-  }
-  
-  // Command files may customize $types as desired.
-  drush_command_invoke_all_ref('drush_cache_clear', $types);
-  return $types;
-}
-
-function drush_cache_clear_theme_registry() {
-  drush_db_delete('cache', 'cid LIKE :theme_registry', array(':theme_registry' => 'theme_registry%'));
-}
-
-function drush_cache_clear_css_js() {
-  _drupal_flush_css_js();
-  drupal_clear_css_cache();
-  drupal_clear_js_cache();
-}
-
-/**
- * Clear the cache of the block output.
- */
-function drush_cache_clear_block() {
-  cache_clear_all(NULL, 'cache_block');
-}
 
diff --git a/sites/all/modules/drush/commands/core/core.drush.inc b/sites/all/modules/drush/commands/core/core.drush.inc
index 381d3d788f0b65cae56aa653070f6e06e187e048..c5b9f51eac700cc16a229b95520e8b318d0fcf25 100644
--- a/sites/all/modules/drush/commands/core/core.drush.inc
+++ b/sites/all/modules/drush/commands/core/core.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: core.drush.inc,v 1.135 2010/12/01 20:59:56 jonhattan Exp $
 
 /**
  * @file
@@ -26,10 +25,10 @@ function core_drush_command() {
     'description' => 'Print this help message. See `drush help help` for more options.',
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
     'options' => array(
-      '--sort' => 'Sort commands in alphabetical order. drush waits for full bootstrap before printing any commands when this option is used.',
-      '--filter' => 'Restrict command list to those commands defined in the specified file.',
-      '--html' => 'Print help for all commands in HTML format.',
-      '--pipe' => 'A list of available commands, one per line.',
+      'sort' => 'Sort commands in alphabetical order. drush waits for full bootstrap before printing any commands when this option is used.',
+      'filter' => 'Restrict command list to those commands defined in the specified file.',
+      'html' => 'Print help for all commands in HTML format.',
+      'pipe' => 'A list of available commands, one per line.',
     ),
     'examples' => array(
       'drush' => 'List all commands.',
@@ -37,20 +36,36 @@ function core_drush_command() {
       'drush help pm-download' => 'Show help for one command.',
       'drush help dl' => 'Show help for one command using an alias.',
     ),
-    'topics' => array('core-readme'),
+    'topics' => array('docs-readme'),
+  );
+  $items['version'] = array(
+    'description' => 'Show drush version.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
+    'options' => array(
+      'pipe' => 'Print just the version number, and nothing else.',
+      'self-update' => 'Check for pending updates to drush itself. Set to 0 to avoid check.',
+    ),
+  );
+  $items['self-update'] = array(
+    'description' => 'Update drush to the latest version, if available.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
+    'options' => array(
+      '--dev' => 'Allow updates to latest dev release.',
+    ),
+    'aliases' => array('selfupdate'),
   );
   $items['core-cron'] = array(
-    'description' => 'Run all cron hooks.',
+    'description' => 'Run all cron hooks in all active modules for specified site.',
     'aliases' => array('cron'),
   );
   $items['updatedb'] = array(
-    'description' => dt('Execute the update.php process from the command line'),
+    'description' => 'Apply any database updates required (as with running update.php).',
     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
     'aliases' => array('updb'),
   );
   $items['core-status'] = array(
     'description' => 'Provides a birds-eye view of the current Drupal installation, if any.',
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
     'aliases' => array('status', 'st'),
     'examples' => array(
       'drush status version' => 'Show all status lines that contain version information.',
@@ -58,12 +73,23 @@ function core_drush_command() {
       'drush status drush-version --pipe' => 'Emit just the drush version with no label.',
     ),
     'arguments' => array(
-      'item' => 'Optional.  The status item line(s) to display.  Any matching line is shown; if only one line matches, then only the value is displayed.  Otherwise, key=value is output.',
+      'item' => 'Optional.  The status item line(s) to display.',
     ),
     'options' => array(
       'show-passwords' => 'Show database password.',
     ),
-    'topics' => array('core-readme'),
+    'topics' => array('docs-readme'),
+  );
+  $items['php-eval'] = array(
+    'description' => 'Evaluate arbitrary php code after bootstrapping Drupal (if available).',
+    'examples' => array(
+      'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.',
+    ),
+    'arguments' => array(
+      'code' => 'PHP code',
+    ),
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
+    'aliases' => array('eval', 'ev'),
   );
   $items['php-script'] = array(
     'description' => "Run php script(s).",
@@ -78,24 +104,18 @@ function core_drush_command() {
       'filename' => 'Optional. The file you wish to execute (without extension). If omitted, list files ending in .php in the current working directory and specified script-path. Some might not be real drush scripts. Beware.',
     ),
     'options' => array(
-      '--script-path' => "Additional paths to search for scripts, separated by : (Unix-based systems) or ; (Windows).",
+      'script-path' => "Additional paths to search for scripts, separated by : (Unix-based systems) or ; (Windows).",
     ),
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
     'aliases' => array('scr'),
     'deprecated-aliases' => array('script'),
-  );
-  $items['cache-clear'] = array(
-    'description' => 'Clear a specific cache, or all drupal caches.',
-    'arguments' => array(
-      'type' => 'The particular cache to clear. Omit this argument to choose from available caches.',
-    ),
-    'aliases' => array('cc'),
+    'topics' => array('docs-examplescript', 'docs-scripts'),
   );
   $items['search-status'] = array(
     'description' => 'Show how many items remain to be indexed out of the total.',
     'drupal dependencies' => array('search'),
     'options' => array(
-      '--pipe' => 'Display in the format remaining/total for processing by scripts.',
+      'pipe' => 'Display in the format remaining/total for processing by scripts.',
     ),
   );
   $items['search-index'] = array(
@@ -106,26 +126,27 @@ function core_drush_command() {
     'description' => 'Force the search index to be rebuilt.',
     'drupal dependencies' => array('search'),
     'options' => array(
-      '--immediate' => 'Rebuild the index immediately, instead of waiting for cron.',
+      'immediate' => 'Rebuild the index immediately, instead of waiting for cron.',
     ),
   );
   $items['core-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.',
+    'description' => 'Rsync the Drupal tree to/from another server using ssh.',
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap.
     'arguments' => array(
       'source' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
       'destination' => 'May be rsync path or site alias. See rsync documentation and example.aliases.drushrc.php.',
     ),
     'options' => array(
-      '--mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz.  Default is -az.',
-      '--RSYNC-FLAG' => 'Most rsync flags passed to drush sync will be passed on to rsync.  See rsync documentation.',
-      '--exclude-conf' => 'Excludes settings.php from being rsynced.  Default.',
-      '--include-conf' => 'Allow settings.php to be rsynced',
-      '--exclude-files' => 'Exclude the files directory.',
-      '--exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
-      '--exclude-other-sites' => 'Exclude all directories in "sites/" except for "sites/all" and the site directory for the site being synced.  Note: if the site directory is different between the source and destination, use --exclude-sites followed by "drush rsync @from:%site @to:%site"',
-      '--exclude-paths' => 'List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).',
-      '--include-paths' => 'List of paths to include, seperated by : (Unix-based systems) or ; (Windows).',
+      'mode' => 'The unary flags to pass to rsync; --mode=rultz implies rsync -rultz.  Default is -az.',
+      'RSYNC-FLAG' => 'Most rsync flags passed to drush sync will be passed on to rsync.  See rsync documentation.',
+      'exclude-conf' => 'Excludes settings.php from being rsynced.  Default.',
+      'include-conf' => 'Allow settings.php to be rsynced. Default is to exclude settings.php.',
+      'include-vcs' => 'Include special version control directories (e.g. .svn).  Default is to exclude vcs files.',
+      'exclude-files' => 'Exclude the files directory.',
+      'exclude-sites' => 'Exclude all directories in "sites/" except for "sites/all".',
+      'exclude-other-sites' => 'Exclude all directories in "sites/" except for "sites/all" and the site directory for the site being synced.  Note: if the site directory is different between the source and destination, use --exclude-sites followed by "drush rsync @from:%site @to:%site"',
+      'exclude-paths' => 'List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).',
+      'include-paths' => 'List of paths to include, seperated by : (Unix-based systems) or ; (Windows).',
     ),
     'examples' => array(
       'drush rsync @dev @stage' => 'Rsync Drupal root from dev to stage (one of which must be local).',
@@ -133,50 +154,49 @@ function core_drush_command() {
     ),
     'aliases' => array('rsync'),
     'deprecated-aliases' => array('sync'),
-  );
-  $items['php-eval'] = array(
-    'description' => 'Evaluate arbitrary php code after bootstrapping Drupal.',
-    'examples' => array(
-      'drush php-eval "variable_set(\'hello\', \'world\');"' => 'Sets the hello variable using Drupal API.',
-    ),
-    'arguments' => array(
-      'code' => 'PHP code',
-    ),
-    'deprecated-aliases' => array('eval'),
+    'topics' => array('docs-aliases'),
   );
   $items['site-install'] = array(
     'description' => 'Install Drupal along with modules/themes/configuration using the specified install profile.',
     'arguments' => array(
-      'profile' => 'the install profile you wish to run. defaults to \'default\'',
+      'profile' => 'the install profile you wish to run. defaults to \'default\' in D6, \'standard\' in D7',
+      'key=value...' => 'any additional settings you wish to pass to the profile. Only support on D7. The key is in the form [form name].[parameter name].',
     ),
     'options' => array(
-      'db-url' => 'A Drupal 5/6 style database URL. Only required for initial install - not re-install.',
-      'db-prefix' => 'An optional table prefix to use for initial install.',
       'account-name' => 'uid1 name. defaults to admin',
       'account-pass' => 'uid1 pass. defaults to admin',
       'account-mail' => 'uid1 email. defaults to admin@example.com',
+      'db-url' => 'A Drupal 5/6 style database URL. Only required for initial install - not re-install.',
+      'db-prefix' => 'An optional table prefix to use for initial install.  Can be a key-value array of tables/prefixes in a drushrc file (not the command line).',
+      'db-su' => 'Account to use when creating a new database. Optional.',
+      'db-su-pw' => 'Password for the "db-su" account. Optional.',
       'locale' => 'A short language code. Sets the default site language. Language files must already be present. You may use download command to get them.',
       'clean-url'=> 'Defaults to 1',
       'site-name' => 'Defaults to Site-Install',
       'site-mail' => 'From: for system mailings. Defaults to admin@example.com',
-      'sites-subdir' => "Name of directory under 'sites' which should be created if needed. Defaults to 'default'",
+      'sites-subdir' => "Name of directory under 'sites' which should be created. Only needed when the subdirectory does not already exist. Defaults to 'default'",
     ),
     'examples' => array(
       'drush site-install expert --locale=uk' => '(Re)install using the expert install profile. Set default language to Ukranian.',
-      'drush site-install --db-url=mysql://root:pass@localhost:port/dbname ' => 'Install using the specified DB params.',
+      'drush site-install --db-url=mysql://root:pass@localhost:port/dbname' => 'Install using the specified DB params.',
+      'drush site-install --db-url=sqlite:/full/path/to/database.sqlite' => 'Install using SQLite (D7 only).',
       'drush site-install --account-name=joe --account-pass=mom' => 'Re-install with specified uid1 credentials.',
+      'drush site-install standard install_configure_form.site_default_country=FR my_profile_form.my_settings.key=value' => 'Pass additional arguments to the profile (D7 only).',
     ),
-    'core' => array(6,7),
+    'core' => array('6+'),
     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
     'aliases' => array('si'),
     'deprecated-aliases' => array('installsite', 'is'),
   );
-
   $items['drupal-directory'] = array(
-    'description' => dt('Return path to a given module/theme directory. See --help for more details.'),
+    'description' => 'Return path to a given module/theme directory.',
     'arguments' => array(
       'target' => 'A module/theme name, or special names like root, files, private, or an alias : path alias string such as @alias:%files. Defaults to root.',
     ),
+    'options' => array(
+      'component' => "The portion of the evaluated path to return.  Defaults to 'path'; 'name' returns the site alias of the target.",
+      'local' => "Reject any target that specifies a remote site.",
+    ),
     'examples' => array(
       'cd `drush dd devel`' => 'Navigate into the devel module directory',
       'cd `drush dd` ' => 'Navigate to the root of your Drupal site',
@@ -189,20 +209,33 @@ function core_drush_command() {
   );
 
   $items['core-cli'] = array(
-    'description' => dt('Enter a new shell optimized for drush use.'),
+    'description' => 'Enter a new shell optimized for drush use.',
+    'options' => array(
+      'override' => 'List of drush commands or aliases that should override built-in shell functions and commands; otherwise, built-ins override drush commands. Defaults to dd,help,sa.',
+      'contextual' => 'Additional drush overrides that function ONLY when the prompt is "@alias>".  Defaults to cc,cron,rsync,status,sync,updatedb.',
+      'ignore' => 'Drush commands or aliases that should not be usable from core-cli. Takes precedence over override and contextual options. Defaults to core-cli,cli.',
+      'pipe' => 'Print the generated .bashrc file and exit.',
+    ),
     'examples' => array(
       'help' => 'Print available drush commands',
-      'cdd' => 'Navigate to the root of your Drupal site',
-      'cdd files' => 'Navigate to the files directory.',
+      'cd @alias' => 'Navigate to the root of the site indicated by @alias; subsequent commands will target that site.',
+      'cd %files' => 'Navigate to the files directory.',
+      'cd ~' => 'Navigate back to your $HOME directory.',
       'lsd files' => 'List all files in the Drupal files directory.',
-      'on @alias status' => 'Run the command "status" on the site indicated by @alias',
+      'on @alias core-status' => 'Run the command "core-status" on the site indicated by @alias',
+      '@alias core-status' => 'An even shorter form that also runs "core-status" on the site @alias',
+      'use @alias' => 'Run subsequent commands on the site indicated by @alias',
+      'use -' => 'Switch back to the last alias "used".',
+      'use ~' => 'Use the default alias.',
+      'use' => 'Revert to an ordinary prompt; do not use an alias.',
+      'drush core-cli --pipe > ~/.bash_aliases' => 'Convert your default shell into drush core-cli.  Make sure that your .bashrc file includes .bash_aliases (e.g. "source ~/.bash_aliases" or ". ~/.bash_aliases").',
     ),
     'aliases' => array('cli'),
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
   );
 
   $items['batch-process'] = array(
-    'description' => dt('Process operations in the specified batch set'),
+    'description' => 'Process operations in the specified batch set',
     'hidden' => TRUE,
       'arguments' => array(
         'batch-id' => 'The batch id that will be processed',
@@ -211,24 +244,19 @@ function core_drush_command() {
   );
 
   $items['updatedb-batch-process'] = array(
-    'description' => dt('Perform update functions'),
+    'description' => 'Perform update functions',
     'hidden' => TRUE,
     'arguments' => array(
       'batch-id' => 'The batch id that will be processed',
     ),
     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
   );
-
-  // Topic commands
-  $items['core-readme'] = array(
-    'description' => dt('README.txt'),
+  $items['core-global-options'] = array(
+    'description' => 'All global options',
     'hidden' => TRUE,
     'topic' => TRUE,
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
-    'callback' => 'drush_print_file',
-    'callback arguments' => array(DRUSH_BASE_PATH . '/README.txt'),
   );
-
   return $items;
 }
 
@@ -246,154 +274,26 @@ function core_drush_engine_drupal() {
  */
 function drush_core_updatedb() {
   if (drush_get_context('DRUSH_SIMULATE')) {
-    return drush_set_error(dt('updatedb command does not support --simulate option.'));
+    drush_log(dt('updatedb command does not support --simulate option.'), 'ok');
+    return TRUE;
   }
 
   drush_include_engine('drupal', 'update', drush_drupal_major_version());
-  update_main();
-
-  // Clear all caches. We just performed major surgery.
-  drush_drupal_cache_clear_all();
-
-  drush_log(dt('Finished performing updates.'), 'ok');
-}
-
-/**
- * This is called for help command, or no command.
- */
-function drush_core_help() {
-  $commands = func_get_args();
-
-
-  if (empty($commands)) {
-    // Build a fake command for the purposes of showing examples and options.
-    $fake = array(
-      'description' => 'Execute a drush command. Run `drush help [command]` to view command-specific help.',
-      'options' => drush_get_global_options(),
-      'examples' => array(
-        'drush dl cck zen' => 'Download CCK module and Zen theme.',
-        'drush --uri=http://example.com status' => 'Show status command for the example.com multi-site.',
-      ),
-    );
-    $fake += drush_command_defaults('fake', 'fake', __FILE__);
-    if (!drush_get_option('html')) {
-      drush_print_help($fake);
-    }
-
-    if (!drush_get_option('html')) {
-      drush_print(dt('Commands: '));
-    }
-
-    $phases = _drush_bootstrap_phases();
-    // For speed, only bootstrap up to DRUSH_BOOTSTRAP_DRUPAL_SITE+1.
-    $phases = array_slice($phases, 0, DRUSH_BOOTSTRAP_DRUPAL_SITE+1);
-
-    $printed_rows = $all_rows = array();
-    $phase_index = DRUSH_BOOTSTRAP_DRUSH;
-
-    foreach ($phases as $phase_index) {
-      if (drush_bootstrap_validate($phase_index)) {
-        if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
-          drush_bootstrap($phase_index);
-        }
-
-        $commands = drush_get_commands();
-        // Filter by command file if specified.
-        if ($commandfile = drush_get_option('filter')) {
-          foreach ($commands as $key => $candidate) {
-            if ($candidate['commandfile'] != $commandfile) {
-              unset($commands[$key]);
-            }
-          }
-        }
-
-        $rows = array();
-        ksort($commands);
-        foreach($commands as $key => $command) {
-          if (!$command['hidden']) {
-            if (!array_key_exists('is_alias', $command) || !$command['is_alias']) {
-              if (!array_key_exists($key, $printed_rows)) {
-                $name = $command['aliases'] ? $key . ' (' . implode(', ', $command['aliases']) . ')': $key;
-                $rows[$key] = array($name, $command['description']);
-                $all_rows[$key] = array($name, $command['description']);
-                $pipe[] = "\"$key\"";
-              }
-            }
-          }
-        }
-
-        // These two options require delayed printing.
-        if (!drush_get_option('sort') && !drush_get_option('html')) {
-          drush_print_table($rows, FALSE, array(0 => 20));
-        }
-        $printed_rows = array_merge($printed_rows, $rows);
-      }
-      else {
-        break;
-      }
-    }
-
-    // We delayed printing until now.
-    ksort($all_rows);
-    if (drush_get_option('sort')) {
-      drush_print_table($all_rows, FALSE, array(0 => 20));
-    }
-    elseif (drush_get_option('html')) {
-      return drush_print(drush_help_html($commands));
-    }
-
-    // Newline-delimited list for use by other scripts. Set the --pipe option.
-    if (drush_get_option('pipe') && isset($pipe)) {
-      drush_print_pipe($pipe);
-    }
-    return;
-  }
-  else {
-    $result = TRUE;
-    while ((count($commands) > 0) && !drush_get_error()) {
-      $result =  drush_show_help(array_shift($commands));
-    }
-    return $result;
-  }
-
-  drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => implode(" ", $commands))));
-}
-
-
-/**
- * Return an HTML page documenting all available commands and global options.
- */
-function drush_help_html($commands) {
-  $output =  "<html><head><title>drush help</title><style>dt {font-size: 110%; font-weight: bold}</style></head><body>\n";
-
-  // Command table
-  $output .=  "<h3>Command list</h3>\n<table>\n";
-  foreach ($commands as $key => $command) {
-    $output .=  "  <tr><td><a href=\"#$key\">$key</a></td><td>" . $command['description'] . "</td></tr>\n";
+  if (update_main() === FALSE) {
+    return FALSE;
   }
-  $output .=  "</table>\n";
 
-  // Global options
-  $options = drush_get_global_options();
-  $output .=  '<h3>Global Options</h3><table>';
-  foreach ($options as $key => $value) {
-    $output .=  "<tr><td>$key</td><td>" . $value . "</td></tr>\n";
+  if (drush_drupal_major_version() <= 6) {
+    // Clear all caches. We just performed major surgery.
+    drush_drupal_cache_clear_all();
   }
-  $output .=  "</table>\n";
-
-  // Command details
-  $output .=  '<h3>Command detail</h3><dl>';
-  foreach ($commands as $key => $command) {
-    $output .=  "\n<a name=\"$key\"></a><dt>$key</dt><dd><pre>\n";
-    ob_start();
-    drush_show_help($key);
-    $output .= ob_get_clean();
-    $output .=  "</pre></dd>\n";
+  else {
+    // Should be unnecessary on D7.
+    // On D7 site-upgrade, this cache_clear was leading to:
+    // Call to undefined function field_read_fields() in field_sql_storage.install line 17
   }
 
-  $output .=  "</body></html>\n";
-
-  return $output;
+  drush_log(dt('Finished performing updates.'), 'ok');
 }
 
 /**
@@ -410,39 +310,25 @@ function drush_help_html($commands) {
  */
 function core_drush_help($section) {
   switch ($section) {
-    case 'drush:cron':
-      return dt("Runs all cron hooks in all active modules for specified site.");
-    case 'drush:status':
-      return dt("View the Drupal version and DB credentials for the current site.");
+    case 'meta:core:title':
+      return dt("Core drush commands");
+    case 'drush:help':
+      return dt("Drush provides an extensive help system that describes both drush commands and topics of general interest.  Use `drush help --filter` to present a list of command categories to view, and `drush topic` for a list of topics that go more in-depth on how to use and extend drush.");
     case 'drush:php-script':
       return dt("Runs the given php script(s) after a full Drupal bootstrap. A useful alternative to eval command when your php is lengthy or you can't be bothered to figure out bash quoting. If you plan to share a script with others, consider making a full drush command instead, since that's more self-documenting.  Drush provides commandline options to the script via drush_get_option('option-name'), and commandline arguments can be accessed either via drush_get_arguments(), which returns all arguments in an array, or drush_shift(), which removes the next argument from the list and returns it.");
-    case 'drush:cache-clear':
-      return dt("Delete a specific drupal cache, or all caches.");
-    case 'drush:search-status':
-      return dt("Show how many items remain to be indexed for search, and the total number of items.");
-    case 'drush:search-index':
-      return dt("Index the remaining search items.");
-    case 'drush:search-reindex':
-      return dt("Force the search index to be rebuilt.");
-    case 'drush:updatedb':
-      return dt("Run update.php just as a web browser would.");
     case 'drush:rsync':
-      return dt("Sync the entire drupal directory or a subdirectory to a <destination> using ssh. Excludes .svn directories. Useful for pushing copies of your tree to a staging server, or retrieving a files directory from a remote site. Local paths should be specified relative to Drupal root.");
-    case 'drush:php-eval':
-      return dt("Run arbitrary PHP code in the context of Drupal");
-    case 'drush:site-install':
-      return dt("Install Drupal using specified install profile.");
+      return dt("Sync the entire drupal directory or a subdirectory to a <destination> using ssh. Excludes reserved files and directories for supported VCSs. Useful for pushing copies of your tree to a staging server, or retrieving a files directory from a remote site. Relative paths start from the Drupal root directory if a site alias is used; otherwise they start from the current working directory.");
     case 'drush:drupal-directory':
-      return dt("Return the filesystem path for projects/themes and other key folders. Used by `cli` command for handy commands `cdd` and `lsd`. If you want to use this command directly, you usually want to prefix the command with cd and enclose the command invocation in backticks. See Examples below.");
+      return dt("Return the filesystem path for modules/themes and other key folders. Used by `cli` command for handy commands `cdd` and `lsd`. If you want to use this command directly, you usually want to prefix the command with cd and enclose the command invocation in backticks. See Examples below.");
     case 'drush:core-cli':
-      return dt("Enter a new shell optimized for drush use.  All .bashrc customizations are still available. See help for more details.");
-    case 'error:DRUSH_DRUPAL_DB_ERROR' :
+      return dt("Enter a new shell optimized for drush use. All .bashrc customizations are still available.");
+    case 'error:DRUSH_DRUPAL_DB_ERROR':
       $message = dt("Drush was not able to start (bootstrap) the Drupal database.\n");
       $message .= dt("Hint: This error often occurs when Drush is trying to bootstrap a site that has not been installed or does not have a configured database.\n");
       $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
       $message .= dt("You can select another site with a working database setup by specifying the URI to use with the --uri parameter on the command line or \$options['uri'] in your drushrc.php file.\n");
       return $message;
-    case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR' :
+    case 'error:DRUSH_DRUPAL_BOOTSTRAP_ERROR':
       $message = dt("Drush was not able to start (bootstrap) Drupal.\n");
       $message .= dt("Hint: This error can only occur once the database connection has already been successfully initiated, therefore this error generally points to a site configuration issue, and not a problem connecting to the database.\n");
       $message .= dt("\nDrush was attempting to connect to : \n!credentials\n", array('!credentials' => _core_site_credentials()));
@@ -496,9 +382,12 @@ function _core_path_aliases($project = '') {
         $paths['%themes'] = 'sites/all/themes';
       }
       if (drush_drupal_major_version() >= 7) {
-        if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) {
-          $paths['%files'] = DrupalPublicStreamWrapper::getDirectoryPath();
-          $paths['%private'] = DrupalPrivateStreamWrapper::getDirectoryPath();
+        if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_SITE) {
+          $paths['%files'] = variable_get('file_public_path', conf_path() . '/files');
+          $private_path = variable_get('file_private_path', FALSE);
+          if ($private_path !== FALSE) {
+            $paths['%private'] = $private_path;
+          }
         }
       }
       elseif (function_exists('file_directory_path')) {
@@ -609,19 +498,10 @@ function drush_core_cron() {
     drush_log(dt('Cron run successfully.'), 'success');
   }
   else {
-    drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
+    return drush_set_error('DRUSH_CRON_FAILED', dt('Cron run failed.'));
   }
 }
 
-/**
- * Bootstrap 'status' command during the init phase.
- * Always use bootstrap_max from _init() so that command
- * hooks have a chance to be initialized.
- */
-function drush_core_status_init() {
-  drush_bootstrap_max();
-}
-
 /**
  * Command callback. Provides a birds-eye view of the current Drupal
  * installation.
@@ -658,6 +538,15 @@ function drush_core_status() {
   return;
 }
 
+// Command callback. Show all global options. Exposed via topic command.
+function drush_core_global_options() {
+  drush_print(dt('These options are applicable to most drush commands.'));
+  drush_print();
+  $fake = drush_global_options_command(FALSE);
+  $global_option_rows = drush_format_help_section($fake, 'options');
+  drush_print_table($global_option_rows);
+}
+
 function _drush_core_is_named_in_array($key, $the_array) {
   $is_named = FALSE;
 
@@ -672,15 +561,6 @@ function _drush_core_is_named_in_array($key, $the_array) {
   return $is_named;
 }
 
-/**
- * Bootstrap 'php-script' command during the init phase.
- * Always use bootstrap_max from _init() so that command
- * hooks have a chance to be initialized.
- */
-function drush_php_script_init() {
-  drush_bootstrap_max();
-}
-
 /**
  * Command callback. Runs "naked" php scripts
  * and drush "shebang" scripts ("#!/usr/bin/env drush").
@@ -691,7 +571,7 @@ function drush_core_php_script() {
   if ($args = func_get_args()) {
     $script = $args[0];
   }
-  
+
   if ($script == '-') {
     eval(stream_get_contents(STDIN));
   }
@@ -734,11 +614,11 @@ function drush_core_php_script() {
         $all[] = $script_filename;
       }
       if (!$found) {
-        return drush_set_error('Script not found.', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
+        return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt('Unable to find any of the following: @files', array('@files' => implode(', ', $all))));
       }
     }
   }
-  
+
   if ($found) {
     // Set the DRUSH_SHIFT_SKIP to two; this will cause
     // drush_shift to skip the next two arguments the next
@@ -817,7 +697,22 @@ function drush_core_updatedb_batch_process($id) {
   _update_batch_command($id);
 }
 
-function _drush_core_directory($target = 'root') {
+/**
+ * Given a target (e.g. @site:%modules), return the evaluated
+ * directory path
+ *
+ * @param $target
+ *   The target to evaluate.  Can be @site or /path or @site:path
+ *   or @site:%pathalais, etc. (just like rsync parameters)
+ * @param $component
+ *   The portion of the evaluated path to return.  Possible values:
+ *   'path' - the full path to the target (default)
+ *   'name' - the name of the site from the path (e.g. @site1)
+ *   'user-path' - the part after the ':' (e.g. %modules)
+ *   'root' & 'uri' - the Drupal root and URI of the site from the path
+ *   'path-component' - The ':' and the path
+ */
+function _drush_core_directory($target = 'root', $component = 'path', $local_only = FALSE) {
   // Normalize to a sitealias in the target.
   $normalized_target = $target;
   if (strpos($target, ':') === FALSE) {
@@ -838,28 +733,49 @@ function _drush_core_directory($target = 'root') {
   }
 
   $additional_options = array();
-  $values = drush_sitealias_evaluate_path($normalized_target, $additional_options);
-
-  if (isset($values['path'])) {
+  $values = drush_sitealias_evaluate_path($normalized_target, $additional_options, $local_only);
+  if (isset($values[$component])) {
     // Hurray, we found the destination
-    return $values['path'];
+    return $values[$component];
   }
   return NULL;
 }
 
 function drush_core_drupal_directory($target = 'root') {
-  $path = _drush_core_directory($target);
-
-  if (isset($path)) {
+  $path = _drush_core_directory($target, drush_get_option('component', 'path'), drush_get_option('local', FALSE));
+
+  // If _drush_core_directory is working right, it will turn
+  // %blah into the path to the item referred to by the key 'blah'.
+  // If there is no such key, then no replacement is done.  In the
+  // case of the dd command, we will consider it an error if
+  // any keys are -not- replaced in _drush_core_directory.
+  if ((isset($path)) && (strpos($path, '%') === FALSE)) {
     drush_print($path);
   }
   else {
-    return drush_set_error(dt('Core directory path !target not found.', array('!target' => $target)));
+    return drush_set_error('DRUSH_TARGET_NOT_FOUND', dt("Target '!target' not found.", array('!target' => $target)));
   }
 
   return TRUE;
 }
 
+/**
+ * Called for `drush version` or `drush --version`
+ */
+function drush_core_version() {
+  drush_print(dt("drush version !version", array('!version' => DRUSH_VERSION)));
+  drush_print_pipe(DRUSH_VERSION);
+  // Next check to see if there is a newer drush.
+  if (!drush_get_context('DRUSH_PIPE') && !drush_get_option('self-update', TRUE)) {
+    drush_check_self_update();
+  }
+}
+
+function drush_core_self_update() {
+  drush_set_option('select', TRUE);
+  return drush_invoke('pm-download', 'drush');
+}
+
 function drush_core_find_project_path($target) {
   $theme_suffix = drush_drupal_major_version() >= 6 ? '.info' : '/style.css';
   $masks = array(
@@ -872,7 +788,9 @@ function drush_core_find_project_path($target) {
 
   $files = array();
   foreach ($masks as $key => $mask) {
-    if ($files = drush_scan_directory("$key", $mask, array('..', '.', 'CVS', '.svn', '.bzr'), 0, TRUE, 'name')) {
+    $skip_list = array('.', '..', 'CVS');
+    $skip_list = array_merge($skip_list, drush_version_control_reserved_files());
+    if ($files = drush_scan_directory("$key", $mask, $skip_list, 0, TRUE, 'name')) {
       // Just use the first match.
       $file = reset($files);
       return drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename);
@@ -882,39 +800,35 @@ function drush_core_find_project_path($target) {
   return NULL;
 }
 
-/**
- * Bootstrap 'cli' command during the init phase.
- * Always use bootstrap_max from _init() so that command
- * hooks have a chance to be initialized.
- */
-function drush_core_cli_init() {
-  drush_bootstrap_max();
-}
-
 function drush_core_cli() {
   // Do not allow cli to start recursively, or from backend invoke.
   if (drush_get_option('in-cli', FALSE)) {
-    return drush_set_error(dt('Already in drush core-cli; press control-d to exit.'));
+    return drush_set_error('DRUSH_CLI_NOT_REENTRANT', dt('Already in drush core-cli; press control-d to exit.'));
   }
-  if (drush_get_context('DRUSH_BACKEND')) {
-    return drush_set_error(dt('Cannot run drush core-cli from non-interactive mode; aborting.'));
+  if (drush_get_context('DRUSH_BACKEND') || drush_get_context('DRUSH_AFFIRMATIVE') || drush_get_context('DRUSH_NEGATIVE')) {
+    return drush_set_error('DRUSH_CLI_INTERACTIVE_ERROR', dt('Cannot run drush core-cli from non-interactive mode; aborting.'));
   }
 
+  // We set interactive mode if we are about to run a bash subshell.
+  // The purpose of doing this is that some options are set differently
+  // in --pipe mode.  To see everything with --pipe, use --pipe --verbose.
+  $interactive_mode = !drush_get_context('DRUSH_PIPE') || drush_get_context('DRUSH_VERBOSE');
+
   // Make sure that we call drush the same way that we were called.
-  $drush_command = DRUSH_COMMAND.' --in-cli';
+  // In --pipe mode, just use 'drush'.
+  $drush_command = $interactive_mode ? DRUSH_COMMAND.' --in-cli' : 'drush';
 
-  $bashrc_data = implode("/n/n", drush_command_invoke_all('cli_bashrc', $drush_command));
+  $bashrc_data = implode("\n\n", drush_command_invoke_all('cli_bashrc', $drush_command, $interactive_mode));
 
-  // Before entering the new bash script, cd to the current site root,
-  // if any.  This will make our default site for drush match the
-  // currently bootstrapped site (at least until the user cd's away).
-  if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
-    chdir($site_root);
+  // Print our bashrc file and exit in --pipe mode
+  if (drush_get_context('DRUSH_PIPE')) {
+    drush_print_pipe($bashrc_data);
+    return TRUE;
   }
 
-  // Print our entire bashrc file in verbose mode
-  if (drush_get_context('DRUSH_VERBOSE')) {
-    drush_print($bashrc_data);
+  // If there were any errors, then exit.
+  if (drush_get_error()) {
+    return FALSE;
   }
 
   drush_print("Entering the drush cli.  Use CONTROL-D to exit.");
@@ -924,70 +838,283 @@ function drush_core_cli() {
   // control-d to exit.  The temp file will be deleted after
   // we exit.
   $bashrc = drush_save_data_to_temp_file($bashrc_data);
-  drush_op('system', 'bash --rcfile ' . $bashrc . ' > `tty`');
+  return drush_op_system('bash --rcfile ' . $bashrc . ' > `tty`');
 }
 
 // Implement our own hook_cli_bashrc()
-function core_cli_bashrc($drush_command) {
-  // Set up our default bashrc file for the drush cli
-  $bashrc_data = <<<EOD
+function core_cli_bashrc($drush_command, $interactive_mode) {
+  $bashrc_data = '';
+
+  $initial_site = '';
+  $site_list = drush_sitealias_resolve_sitespecs(array('@self'));
+  if (!empty($site_list)) {
+    $site_list = array_keys($site_list);
+    if ($site_list[0] != "@self") {
+      $initial_site = $site_list[0];
+    }
+  }
+  if (empty($initial_site)) {
+    drush_sitealias_load_all(TRUE);
+    $initial_site = _drush_sitealias_find_local_alias_name(drush_get_context('DRUSH_DRUPAL_ROOT'), str_replace('http://','',drush_get_context('DRUSH_URI')));
+  }
 
-# source the user's .bashrc file
-[ -r ~/.bashrc ] && {
-  pushd ~ > /dev/null
-  . .bashrc
-  popd > /dev/null
-}
+  $searchpath[] = drush_get_context('SHARE_PREFIX', '/usr') . '/share/drush/commands';
+  $searchpath[] = drush_get_context('ETC_PREFIX', '') . '/etc/drush';
+  $searchpath[] = realpath(dirname(__FILE__) . '/../../');
+  $bashrc_searchpath = implode(' ', $searchpath);
 
-PS1="drush> "
+  // Set the prompt to 'drush> ' in interactive mode.
+  if ($interactive_mode) {
+    $bashrc_data .= "# Set our prompt to 'drush> '\nPS1='drush> '\n\n";
+  }
 
-alias on="$drush_command"
-alias drush="$drush_command"
+  // Set up our default bashrc file for the drush cli
+  $bashrc_data .= <<<EOD
+# Drush .bashrc file.  Copy selected portions of this
+# into your own bash resource file to add features of the
+# drush core-cli command to your default shell.
+
+# Where we will search for .bashrc files
+BASHRC_PATH="~/.drush $bashrc_searchpath"
+
+# Set the DRUSH_CLI variable; it may also be of use
+# in the user's .bashrc, or elsewhere.  If we have not
+# already set DRUSH_CLI, add ~ to our BASHRC_PATH.
+# This allows us to source ~/.bashrc when we are running
+# `drush core-cli` without causing problems with reentrancy
+# if someone sources this file from ~/.bashrc.
+[ -z \$DRUSH_CLI ] && BASHRC_PATH="~ \$BASHRC_PATH"
 DRUSH_CLI=true
 
+# Cache our initial site
+INITIAL_SITE=$initial_site
 
-function cdd() {
-  TARGET=
-  PARAM=\$1
-  if [ \$# -gt 1 ] ; then
-    TARGET=\$1
-    PARAM=\$2
+# Look for drush-specific bashrc files and
+# source any that are found.  Will also source
+# \$HOME/.bashrc if run via `drush core-cli`
+for d in \$BASHRC_PATH ; do
+  [ -r \$d/.bashrc ] && {
+    . \$d/.bashrc
+  }
+done
+
+# Display our initial site in the bash prompt.
+INITIAL_PS1="\$PS1"
+
+# When using the drush shell, all commands will
+# by default target the site specified by the
+# shell variable \$DRUPAL_SITE.  To run a command
+# on some other site, use either:
+#   drush @site command
+# or
+#   on @site command
+alias on="$drush_command"
+
+# To specify a new DRUPAL_SITE without changing
+# your current directory:
+#   use @site
+# To use the previous site (like `cd -`):
+#   use -
+# To use the initial site set when the shell was
+# first entered:
+#   use ~
+function use() {
+  if [ "x\$1" == "x-" ]
+  then
+    use \$PREVIOUS_SITE
+  # `use ~1` will go back to our initial site.  Note, however,
+  # that the shell will convert ~ to \$HOME before we get here,
+  # so we will simply test for either ~ or \$HOME for this feature.
+  elif [ "x\$1" == "x~" ] || [ "x\$1" == "x\$HOME" ]
+  then
+    use \$INITIAL_SITE
+  elif [ "x\$1" != "x" ] && [ "x\$1" != "x@self" ]
+  then
+    SITE=`drush site-alias \$1 --short 2>/dev/null`
+    if [ \$? != 0 ] || [ -z "\$SITE" ]
+    then
+      echo "Alias \$1 not found."
+    else
+      REMOTE_DRUPAL=`drush site-alias \$1 --component='remote-host' 2>/dev/null`
+      PREVIOUS_SITE=\$DRUPAL_SITE
+      DRUPAL_SITE=$1
+      if [ -n "\$REMOTE_DRUPAL" ]
+      then
+        PS1="\$REMOTE_DRUPAL:\${1:-drush}> "
+      else
+        PS1="\${1:-drush}> "
+      fi
+    fi
+  else
+    PREVIOUS_SITE=\$DRUPAL_SITE
+    DRUPAL_SITE=
+    PS1="\$INITIAL_PS1"
   fi
-  DEST=`drush \$TARGET drupal-directory \$PARAM`
-  if [ \$? != 0 ] || [ -z "\$DEST" ]
+}
+
+# We override the cd command to allow convenient
+# shorthand notations, such as:
+#   cd @site1
+#   cd %modules
+#   cd %devel
+#   cd @site2:%files
+# When changing the cwd to a new site, the DRUPAL_SITE
+# variable is also changed, so the new site becomes
+# the default drush target.
+function cd() {
+  d=\$1;
+  # If we do not have a \$DRUPAL_SITE from `use @alias`,
+  # then 'cd @alias' will still cd to @alias, but all other
+  # patterns will be passed to builtin cd.  The same behavior
+  # will be used if \$DRUPAL_SITE points to a remote alias.
+  if [ -z \$DRUPAL_SITE ] || [ -n "\$REMOTE_DRUPAL" ]
   then
-    echo "Target \$1 was not found."
+    if [ -n "\$d" ] && [ \${d:0:1} == "@" ]
+    then
+      cdd \$@;
+    else
+      builtin cd "\$d";
+    fi
   else
-    echo "cd \$DEST"
-    cd \$DEST;
+    # First special-case the no-parameter cd
+    if [ -z "\$d" ]
+    then
+      cdd %root;
+    # Next test and see if this should be an 'ordinary' cd
+    elif [ "\$1" == "-" ] || [ -d "\$d" ]
+    then
+      builtin cd "\$d";
+    else
+      cdd \$@
+    fi
   fi
 }
 
-function lsd() {
-  TARGET=
-  PARAM=\$1
-  if [ \$# -gt 1 ] ; then
-    TARGET=\$1
-    PARAM=\$2
+# Do a special drush core-cli cd, handling
+# shorthand notation directory names -- anything
+# understood by drupal-directory
+function cdd() {
+  DEST=`drupal-directory \$1 --local 2>/dev/null`
+  if [ \$? == 0 ]
+  then
+    SITE=`drupal-directory \$1 --component=name 2>/dev/null`
+    if [ -n "\$SITE" ]
+    then
+      use \$SITE;
+    fi
+    echo "cd \$DEST";
+    builtin cd "\$DEST";
+  else
+    builtin cd "\$1"
   fi
-  DEST=`drush \$TARGET drupal-directory \$PARAM`
-  if [ \$? != 0 ] || [ -z "\$DEST" ]
+}
+
+# The command lsd will quickly do an 'ls' on the
+# specified special drush directory, e.g.:
+#   lsd %modules
+function lsd() {
+  # First special-case the no-parameter cd
+  if [ "x\$1" == "x" ]
   then
-    echo "Target \$1 was not found."
+    lsd %root
   else
-    echo "ls \$DEST"
-    ls \$DEST;
+    # Do a special drush core-cli cd, handling
+    # shorthand notation directory names -- anything
+    # understood by drupal-directory
+    DEST=`drupal-directory \$1 --local`
+    if [ \$? == 0 ]
+    then
+      echo "ls \$DEST";
+      ls \$DEST;
+    fi
   fi
 }
 
 EOD;
 
-  // Add aliases for all of our commands
+  // Add aliases for all drush commands
+  $bashrc_data .= "# Add aliases for all drush commands\n";
   $commands = drush_get_commands();
+  $cli_overrides = _convert_csv_to_array(drush_get_option('override', 'dd,help,sa'));
+  $cli_contextual_commands = _convert_csv_to_array(drush_get_option('contextual', 'cc,cron,rsync,status,sync,updatedb'));
+  $cli_ignore = _convert_csv_to_array(drush_get_option('ignore','core-cli,cli'));
   foreach ($commands as $key => $command) {
-    // Filter out old commands that still have spaces
-    if (strpos($key, ' ') === FALSE) {
-      $bashrc_data .= "function $key() {\n  $drush_command $key \"\$@\"\n}\n";
+    // Filter out old commands that still have spaces;
+    // do not mask any existing bash command (e.g. 'grep')
+    // or builtin (e.g. 'eval') with drush aliases.
+    if ((strpos($key, ' ') === FALSE) && (!in_array($key, $cli_ignore))) {
+      $conflict = FALSE;
+      $is_shell_builtin = (drush_shell_exec("bash -c \"builtin $key\"") == "1");
+      if (!in_array($key, $cli_overrides)) {
+        $status = drush_shell_exec("which $key 2>&1");
+        if ($status !== FALSE) {
+          $output_lines = drush_shell_exec_output();
+          $conflict = $output_lines[0];
+        }
+        elseif ($is_shell_builtin) {
+          $conflict = "builtin $key";
+        }
+      }
+      elseif ($is_shell_builtin && ($key != "help")) {
+        drush_set_error('DRUSH_OVERRIDE_BUILTIN', dt("Cannot override shell builtin function !builtin", array('!builtin' => $key)));
+      }
+      if (!$conflict) {
+        $bashrc_data .= "function $key() {\n  $drush_command \$DRUPAL_SITE $key \"\$@\"\n}\n";
+      }
+      elseif (in_array($key, $cli_contextual_commands)) {
+        if ($is_shell_builtin) {
+          $warning = dt("Warning: overriding shell built-in command !builtin.  This could cause unpredictable results with shell scripts.", array('!builtin' => $key));
+          drush_log($warning, 'warning');
+          $bashrc_data .= "# $warning\n";
+        }
+	if ($key == 'rsync') {
+          $bashrc_data .= "function $key() { \n  HAS_SITE_PARAMS=\n  for p in \"\$@\" ; do\n    if [ \"x\${p:0:1}\" == \"x@\" ] || [ \"x\${p:0:1}\" == \"x%\" ]\n    then\n      HAS_SITE_PARAMS=true\n    fi\n  done\n  if [ -z \$HAS_SITE_PARAMS ]\n  then \n      $conflict \"\$@\"\n  else\n      $drush_command \$DRUPAL_SITE $key \"\$@\"\n  fi\n}\n";
+	}
+	else {
+          $bashrc_data .= "function $key() {\n  if [ -z \$DRUPAL_SITE ]\n  then \n    $conflict \"\$@\"\n  else\n    $drush_command \$DRUPAL_SITE $key \"\$@\"\n  fi\n}\n";
+        }
+      }
+      else {
+        $bashrc_data .= "# drush $key skipped; conflicts with $conflict\n";
+      }
+    }
+  }
+
+  // Make bash aliases for all drush site aliases.
+  // @sitealias becomes an alias for "drush @sitealias".
+  // This allows:
+  //   $ @sitealias status
+  drush_sitealias_load_all();
+  foreach (drush_get_context('site-aliases') as $site_name => $site_record) {
+    $bashrc_data .= "alias $site_name='drush $site_name'\n";
+  }
+
+  // Add some additional statements to the bashrc data that
+  // should not go into --pipe mode.
+  if ($interactive_mode) {
+    // If there is an initial site, then cd to it.  This will set the prompt.
+    if (!empty($initial_site)) {
+      $bashrc_data .= "cd $initial_site\n";
+    }
+    // Before entering the new bash script, cd to the current site root,
+    // if any.  This will make our default site for drush match the
+    // currently bootstrapped site (at least until the user cd's away).
+    // We do this -after- the drush_print_pipe($bashrc_data) because
+    // we DO NOT want to change the working directory if this bashrc
+    // is being used by a login shell.
+    elseif ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
+      $site_root = drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . $site_root;
+      $bashrc_data .= "builtin cd $site_root\n";
+    }
+    if ($drush_command != 'drush') {
+      $bashrc_data .= "alias drush=\"$drush_command\"\n";
+    }
+  }
+  // Add some additional statements that should only appear in non-interactive mode.
+  else {
+    // If there is an initial site, then use.  This will set the prompt.
+    if (!empty($initial_site)) {
+      $bashrc_data .= "use $initial_site\n";
     }
   }
 
diff --git a/sites/all/modules/drush/commands/core/docs.drush.inc b/sites/all/modules/drush/commands/core/docs.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..01f20d9cdfae473add932206a5e8e56a7efee9b7
--- /dev/null
+++ b/sites/all/modules/drush/commands/core/docs.drush.inc
@@ -0,0 +1,244 @@
+<?php
+
+/**
+ * @file
+ *   Documentation commands providing various topics.
+ */
+
+/**
+ * Implementation of hook_drush_help().
+ */
+function docs_drush_help($section) {
+  switch ($section) {
+    case 'meta:docs:title':
+      return dt('Documentation commands');
+    case 'meta:docs:summary':
+      return dt('Show information on various drush topics.');
+  }
+}
+
+/**
+ * Implementation of hook_drush_command().
+ *
+ * @return
+ *   An associative array describing your command(s).
+ */
+function docs_drush_command() {
+  $docs_dir = drush_get_context('DOC_PREFIX', DRUSH_BASE_PATH);
+
+  //
+  // Topic commands.
+  // Any commandfile may add topics.
+  // Set 'topic' => TRUE to indicate the command is a topic (REQUIRED)
+  // Begin the topic name with the name of the commandfile (just like
+  // any other command).
+  //
+  $items['docs-readme'] = array(
+    'description' => 'README.txt',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/README.txt'),
+  );
+  $items['docs-configuration'] = array(
+    'description' => 'Drush configuration overview with examples',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/example.drushrc.php'),
+  );
+  $items['docs-aliases'] = array(
+    'description' => 'Site aliases overview with examples',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/example.aliases.drushrc.php'),
+  );
+  $items['docs-ini-files'] = array(
+    'description' => 'Configuring php.ini or drush.ini for use with drush.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/example.drush.ini'),
+  );
+  $items['docs-bootstrap'] = array(
+    'description' => 'Information about the drush bootstrap process.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/bootstrap.html'),
+  );
+  $items['docs-scripts'] = array(
+    'description' => 'Overview on how to write drush shell scripts.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/shellscripts.html'),
+  );
+  $items['docs-commands'] = array(
+    'description' => 'Overview on how to write drush commands.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/commands.html'),
+  );
+  $items['docs-errorcodes'] = array(
+    'description' => 'Summary of drush error codes.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+  );
+  $items['docs-api'] = array(
+    'description' => 'Drush API',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/drush.api.php'),
+  );
+  $items['docs-context'] = array(
+    'description' => 'Drush contexts',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/context.html'),
+  );
+  $items['docs-examplescript'] = array(
+    'description' => 'Example drush script',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/helloworld.script'),
+  );
+  $items['docs-examplecommand'] = array(
+    'description' => 'Example drush command file.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/sandwich.drush.inc'),
+  );
+  $items['docs-policy'] = array(
+    'description' => 'Example policy file.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/examples/policy.drush.inc'),
+  );
+  $items['docs-upgrading'] = array(
+    'description' => 'Upgrading Drupal using the drush site-upgrade command.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array($docs_dir . '/docs/upgrade.html'),
+  );
+  return $items;
+}
+
+/**
+ * docs-error-codes command.  Print a list of all error codes
+ * that can be found.
+ */
+function drush_docs_errorcodes() {
+  $header = <<<EOD
+==== Drush Error Codes ====
+
+Drush error codes are alphanumeric constants that represent an unrecoverable error condition that may arise during the execution of some command.  They are set by the following function:
+
+  return drush_set_error('DRUSH_ERROR_CODE', dt('Error message.'));
+
+In general, any drush command that calls drush_set_error is expected to also return FALSE as its function result.  The drush_set_error function returns FALSE to make it easy to exit with an error code.  Error codes are returned as part of the drush backend invoke process, which is used by drush API functions such as drush_invoke_process.  An example of how to test for a specific error code is shown below:
+
+  \$result = drush_invoke_process('some-command');
+  if (array_key_exists('DRUSH_ERROR_CODE', \$result['error_log'])) {
+    // handle ocurrances of DRUSH_ERROR_CODE here
+  }
+
+Some of the available drush error codes are listed in the table below.
+
+
+EOD;
+
+  // Find all of the files that we will search for error messages.
+  // Start with all of the commandfiles.
+  $commandfiles = drush_commandfile_list();
+  $files = array_flip($commandfiles);
+  // In addition to the commandfiles, we will also look for files
+  // that drush will load when executing a command; examples include
+  // updatecode.pm.inc and sync.sql.inc.
+  $commands = drush_get_commands();
+  foreach ($commands as $command_name => $command) {
+    $files = array_merge($files, drush_command_get_includes($command_name));
+  }
+  // We will also search through all of the .inc files in the
+  // drush includes directory
+  $drush_include_files = drush_scan_directory(DRUSH_BASE_PATH . '/includes', '/.*\.inc$/', array('.', '..', 'CVS'), 0, FALSE);
+  foreach ($drush_include_files as $filename => $info) {
+    $files[$filename] = 'include';
+  }
+
+  // Extract error messages from all command files
+  $error_list = array();
+  foreach ($files as $file => $commandfile) {
+    _drush_docs_find_set_error_calls($error_list, $file, $commandfile);
+  }
+  // Order error messages alphabetically by key
+  ksort($error_list);
+  // Convert to a table
+  $data = array();
+  foreach ($error_list as $error_code => $error_messages) {
+    $data[] = array($error_code, '-', implode("\n", $error_messages));
+  }
+
+  $tmpfile = drush_tempnam('drush-errorcodes.');
+  file_put_contents($tmpfile, $header);
+  drush_print_table($data, FALSE, array(0 => 35), $tmpfile);
+  drush_print_file($tmpfile);
+}
+
+/**
+ * Search through a php source file looking for calls to
+ * the function drush_set_error.  If found, and if the
+ * first parameter is an uppercase alphanumeric identifier,
+ * then record the error code and the error message in our table.
+ */
+function _drush_docs_find_set_error_calls(&$error_list, $filename, $shortname) {
+  $lines = file($filename);
+  foreach ($lines as $line) {
+    $matches = array();
+    // Find the error code after the drush_set_error call.  The error code
+    // should consist of uppercase letters and underscores only (numbers thrown in just in case)
+    $match_result = preg_match("/.*drush_set_error[^'\"]['\"]([A-Z0-9_]*)['\"][^,]*,[^'\"]*(['\"])/", $line, $matches);
+    if ($match_result) {
+      $error_code = $matches[1];
+      $quote_char = $matches[2];
+      $error_message = "";
+      $message_start = strlen($matches[0]) - 1;
+
+      // Regex adapted from http://stackoverflow.com/questions/1824325/regex-expression-for-escaped-quoted-string-wont-work-in-phps-preg-match-allif ($quote_char == '"') {
+      if ($quote_char == '"') {
+	$regex = '/"((?:[^\\\]*?(?:\\\")?)*?)"/';
+      }
+      else {
+	$regex = "/'((?:[^\\\]*?(?:\\\')?)*?)'/";
+      }
+      $match_result = preg_match($regex, $line, $matches, 0, $message_start);
+
+      if ($match_result) {
+	$error_message = $matches[1];
+      }
+      $error_list[$error_code] = array_key_exists($error_code, $error_list) ? array_merge($error_list[$error_code], array($error_message)) : array($error_message);
+    }
+  }
+}
diff --git a/sites/all/modules/drush/commands/core/drupal/batch_7.inc b/sites/all/modules/drush/commands/core/drupal/batch.inc
similarity index 100%
rename from sites/all/modules/drush/commands/core/drupal/batch_7.inc
rename to sites/all/modules/drush/commands/core/drupal/batch.inc
diff --git a/sites/all/modules/drush/commands/core/drupal/environment_7.inc b/sites/all/modules/drush/commands/core/drupal/environment.inc
similarity index 85%
rename from sites/all/modules/drush/commands/core/drupal/environment_7.inc
rename to sites/all/modules/drush/commands/core/drupal/environment.inc
index c0e22634ee54d6d5c5caa4f11fa0849ee5a3c821..33dd2ffc0dc3d9b151b07316ff9736a3094cb7fb 100644
--- a/sites/all/modules/drush/commands/core/drupal/environment_7.inc
+++ b/sites/all/modules/drush/commands/core/drupal/environment.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: environment_7.inc,v 1.16 2010/10/15 09:04:37 jonhattan Exp $
 /**
  * @file
  *   Specific functions for a drupal 7 environment.
@@ -18,6 +17,19 @@ function drush_get_modules() {
   return system_rebuild_module_data();
 }
 
+/**
+ * Returns drupal required modules, including modules declared as required dynamically.
+ */
+function _drush_drupal_required_modules($module_info) {
+  $required = drupal_required_modules();
+  foreach ($module_info as $name => $module) {
+    if (isset($module->info['required']) && $module->info['required']) {
+      $required[] = $name;
+    }
+  }
+  return array_unique($required);
+}
+
 /**
  * Return dependencies and its status for modules.
  *
@@ -52,6 +64,7 @@ function drush_check_module_dependencies($modules, $module_info) {
         }
       }
     }
+    $status[$key]['unmet-dependencies'] = $unmet_dependencies;
     $status[$key]['dependencies'] = array_keys($dependencies);
   }
 
@@ -84,7 +97,10 @@ function drush_module_dependents($modules, $module_info) {
  *   Array of module names
  */
 function drush_module_enable($modules) {
-  module_enable($modules, FALSE);
+  // The list of modules already have all the dependencies, but they might not
+  // be in the correct order. Still pass $enable_dependencies = TRUE so that
+  // Drupal will enable the modules in the correct order.
+  module_enable($modules);
 }
 
 /**
@@ -94,7 +110,10 @@ function drush_module_enable($modules) {
  *   Array of module names
  */
 function drush_module_disable($modules) {
-  module_disable($modules, FALSE);
+  // The list of modules already have all the dependencies, but they might not
+  // be in the correct order. Still pass $enable_dependencies = TRUE so that
+  // Drupal will enable the modules in the correct order.
+  module_disable($modules);
 }
 
 /**
diff --git a/sites/all/modules/drush/commands/core/drupal/environment_5.inc b/sites/all/modules/drush/commands/core/drupal/environment_5.inc
index 0d5e6bf75efb0b9c8bfca59981234fa5d40fd6c8..a9839a7fa406af74ded1ba662f7990102778c87c 100644
--- a/sites/all/modules/drush/commands/core/drupal/environment_5.inc
+++ b/sites/all/modules/drush/commands/core/drupal/environment_5.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: environment_5.inc,v 1.13 2010/11/10 02:55:41 weitzman Exp $
 /**
  * @file
  *   Specific functions for a drupal 5 environment.
@@ -17,6 +16,13 @@ function drupal_required_modules() {
   return array('block', 'filter', 'node', 'system', 'user', 'watchdog');
 }
 
+/**
+ * Returns drupal required modules, including their dependencies.
+ */
+function _drush_drupal_required_modules($module_info) {
+  return drupal_required_modules();
+}
+
 /**
  * Get complete information for all available modules.
  *
diff --git a/sites/all/modules/drush/commands/core/drupal/environment_6.inc b/sites/all/modules/drush/commands/core/drupal/environment_6.inc
index b2b21e647c31be2e06f061a1d4b6212e285ed471..455f44d94d6e7eafe1058e36de678adfea2a8766 100644
--- a/sites/all/modules/drush/commands/core/drupal/environment_6.inc
+++ b/sites/all/modules/drush/commands/core/drupal/environment_6.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: environment_6.inc,v 1.11 2010/09/10 19:58:06 weitzman Exp $
 /**
  * @file
  *   Specific functions for a drupal 6 environment.
@@ -27,6 +26,19 @@ function drush_get_modules() {
   return $modules;
 }
 
+/**
+ * Returns drupal required modules, including their dependencies.
+ *
+ * A module may alter other module's .info to set a dependency on it.
+ * See for example http://drupal.org/project/phpass
+ */
+function _drush_drupal_required_modules($module_info) {
+  $required = drupal_required_modules();
+  foreach ($required as $module) {
+    $required = array_merge($required, $module_info[$module]->info['dependencies']);
+  }
+  return $required;
+}
 
 /**
  * Return dependencies and its status for modules.
@@ -49,9 +61,8 @@ function drush_check_module_dependencies($modules, $module_info) {
           'message' => dt('Module !module cannot be enabled because it depends on the following modules which could not be found: !unmet_dependencies', array('!module' => $module, '!unmet_dependencies' => implode(',', $unmet_dependencies)))
       );
     }
-    else {
-      $status[$key]['dependencies'] = $dependencies;
-    }
+    $status[$key]['unmet-dependencies'] = $unmet_dependencies;
+    $status[$key]['dependencies'] = $dependencies;
   }
 
   return $status;
diff --git a/sites/all/modules/drush/commands/core/drupal/site_install_7.inc b/sites/all/modules/drush/commands/core/drupal/site_install.inc
similarity index 73%
rename from sites/all/modules/drush/commands/core/drupal/site_install_7.inc
rename to sites/all/modules/drush/commands/core/drupal/site_install.inc
index 5c4280c68cdb093a13ce8435cbb7a396efd8d81d..34a107f48e401ee9c38c522c29f2047d5b6af33e 100644
--- a/sites/all/modules/drush/commands/core/drupal/site_install_7.inc
+++ b/sites/all/modules/drush/commands/core/drupal/site_install.inc
@@ -1,10 +1,9 @@
 <?php
-// $Id: site_install_7.inc,v 1.2 2010/11/29 13:59:58 weitzman Exp $
 
 /**
  * Install Drupal 7+
  */
-function drush_core_site_install_version($profile) {
+function drush_core_site_install_version($profile, array $additional_form_options = array()) {
   if (is_null($profile)) {
     $profile = 'standard';
   }
@@ -12,7 +11,7 @@ function drush_core_site_install_version($profile) {
   define('MAINTENANCE_MODE', 'install');
   require_once DRUPAL_ROOT . '/includes/install.core.inc';
 
-  $db_spec = drush_core_site_install_db_spec();
+  $db_spec = drush_sql_read_db_spec();
 
   $account_pass = drush_get_option('account-pass', 'admin');
   $settings = array(
@@ -22,7 +21,9 @@ function drush_core_site_install_version($profile) {
     ),
     'forms' => array(
       'install_settings_form' => array(
+        'driver' => $db_spec['driver'],
         $db_spec['driver'] => $db_spec,
+        'op' => dt('Save and continue'),
       ),
       'install_configure_form' => array(
         'site_name' => drush_get_option('site-name', 'Site-Install'),
@@ -44,9 +45,20 @@ function drush_core_site_install_version($profile) {
           */
         ),
         'clean_url' => drush_get_option('clean-url', TRUE),
+        'op' => dt('Save and continue'),
       ),
     ),
   );
+
+  // Merge in the additional options.
+  foreach ($additional_form_options as $key => $value) {
+    $current = &$settings['forms'];
+    foreach (explode('.', $key) as $param) {
+      $current = &$current[$param];
+    }
+    $current = $value;
+  }
+
   drush_log(dt('Starting Drupal installation. This takes a few seconds ...'), 'ok');
   install_drupal($settings);
 }
\ No newline at end of file
diff --git a/sites/all/modules/drush/commands/core/drupal/site_install_6.inc b/sites/all/modules/drush/commands/core/drupal/site_install_6.inc
index 2bbd593f0706a2a922a6fc8bdb52bb563c1c4fe8..21424fb9b1f75d80939842e57b8740805b82ed0b 100644
--- a/sites/all/modules/drush/commands/core/drupal/site_install_6.inc
+++ b/sites/all/modules/drush/commands/core/drupal/site_install_6.inc
@@ -1,28 +1,42 @@
 <?php
-// $Id: site_install_6.inc,v 1.1 2010/11/28 14:45:04 weitzman Exp $
 
 /**
  * Install Drupal 6.x
  */
-function drush_core_site_install_version($profile) {  
+function drush_core_site_install_version($profile) {
   if (is_null($profile)) {
     $profile = 'default';
   }
   $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
-  
-  $phpcode = _drush_site_install6_cookies($profile). ' include("'. $drupal_root .'/install.php");';
+
+  // We need to disable reporting of E_NOTICE if we want to read the command's output
+  // on Windows, because of how Windows is handling output order when using 2>&1
+  // redirect added to the command in drush_shell_exec(). We will actually take out
+  // all but fatal errors.  See http://drupal.org/node/985716 for more information.
+  $phpcode = 'error_reporting(E_ERROR);' . _drush_site_install6_cookies($profile). ' include("'. $drupal_root .'/install.php");';
   drush_shell_exec('php -r %s', $phpcode);
   $cli_output = drush_shell_exec_output();
   $cli_cookie = end($cli_output);
-  
-  $phpcode = _drush_site_install6_cookies($profile, $cli_cookie). ' $_GET["op"]="start"; include("'. $drupal_root .'/install.php");';
-  drush_shell_exec('php -r %s', $phpcode);
 
-  $phpcode = _drush_site_install6_cookies($profile, $cli_cookie). ' $_GET["op"]="do_nojs"; include("'. $drupal_root .'/install.php");';
-  drush_shell_exec('php -r %s', $phpcode);
+  // We need to bootstrap the database to be able to check the progress of the 
+  // install batch process since we're not duplicating the install process using
+  // drush_batch functions, but calling the process directly.
+  drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_DATABASE);
 
-  $phpcode = _drush_site_install6_cookies($profile, $cli_cookie). ' $_GET["op"]="finished"; include("'. $drupal_root .'/install.php");';
-  drush_shell_exec('php -r %s', $phpcode);
+  $status = _drush_site_install6_stage($profile, $cli_cookie, "start");
+  if ($status === FALSE) {
+    return FALSE;
+  }
+
+  $status = _drush_site_install6_stage($profile, $cli_cookie, "do_nojs");
+  if ($status === FALSE) {
+    return FALSE;
+  }
+
+  $status = _drush_site_install6_stage($profile, $cli_cookie, "finished");
+  if ($status === FALSE) {
+    return FALSE;
+  }
 
   $account_pass = drush_get_option('account-pass', 'admin');
   $phpcode = _drush_site_install6_cookies($profile, $cli_cookie);
@@ -47,14 +61,48 @@ function drush_core_site_install_version($profile) {
   drush_shell_exec('php -r %s', $phpcode);
 }
 
+/**
+ * Submit a given op to install.php; if a meta "Refresh" tag
+ * is returned in the result, then submit that op as well.
+ */
+function _drush_site_install6_stage($profile, $cli_cookie, $initial_op) {
+  $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
+  // Remember the install task at the start of the stage
+  $install_task = _drush_site_install6_install_task();
+  $op = $initial_op;
+  while (!empty($op)) {
+    $phpcode = _drush_site_install6_cookies($profile, $cli_cookie). ' $_GET["op"]="' . $op . '"; include("'. $drupal_root .'/install.php");';
+    drush_shell_exec('php -r %s', $phpcode);
+    $output = implode("\n", drush_shell_exec_output());
+    // Check for a "Refresh" back to the do_nojs op; e.g.:
+    //   <meta http-equiv="Refresh" content="0; URL=http://default/install.php?locale=en&profile=wk_profile6&id=1&op=do_nojs">
+    // If this pattern is NOT found, then go on to the "finished" step.
+    $matches = array();
+    $match_result = preg_match('/http-equiv="Refresh".*op=([a-zA-Z0-9_]*)/', $output, $matches);
+    if ($match_result) {
+      $op = $matches[1];
+    }
+    else {
+      $op = '';
+    }
+  }
+  if (($install_task == _drush_site_install6_install_task()) && ($initial_op != "finished")) {
+    return drush_set_error('DRUSH_SITE_INSTALL_FAILED', dt("The site install task '!task' failed.", array('!task' => $install_task)));
+  }
+  return TRUE;
+}
+
 /**
  * Utility function to grab/set current "cli cookie".
- * 
  */
 function _drush_site_install6_cookies($profile, $cookie = NULL) {
+  $drupal_base_url = parse_url(drush_get_option('uri', 'http://default'));
   $output = '$_GET=array("profile"=>"' . $profile . '", "locale"=>"' . drush_get_option('locale', 'en') . '", "id"=>"1"); $_REQUEST=&$_GET;';
   $output .= 'define("DRUSH_SITE_INSTALL6", TRUE);$_SERVER["SERVER_SOFTWARE"] = NULL;';
-  
+  $output .= '$_SERVER["SCRIPT_NAME"] = "/install.php";';
+  $output .= '$_SERVER["HTTP_HOST"] = "'.$drupal_base_url['host'].'";';
+  $output .= '$_SERVER["REMOTE_ADDR"] = "127.0.0.1";';
+
   if ($cookie) {
     $output .= sprintf('$_COOKIE=unserialize("%s");', str_replace('"', '\"', $cookie));
   }
@@ -62,6 +110,17 @@ function _drush_site_install6_cookies($profile, $cookie = NULL) {
     $output .= 'function _cli_cookie_print(){print(serialize(array(session_name()=>session_id())));}
 register_shutdown_function("_cli_cookie_print");';
   }
-  
+
   return $output;
-}
\ No newline at end of file
+}
+
+/**
+ * Utility function to check the install_task.  We are
+ * not bootstrapped to a high enough level to use variable_get.
+ */
+function _drush_site_install6_install_task() {
+  if ($data = db_result(db_query("SELECT value FROM {variable} WHERE name = 'install_task'",1))) {
+    $result = unserialize($data);
+  }
+  return $result;
+}
diff --git a/sites/all/modules/drush/commands/core/drupal/update_7.inc b/sites/all/modules/drush/commands/core/drupal/update.inc
similarity index 97%
rename from sites/all/modules/drush/commands/core/drupal/update_7.inc
rename to sites/all/modules/drush/commands/core/drupal/update.inc
index 8b01cff45df57bb1a8f890ded565cbb5d3e7bcd0..b57564fa8b42c820be833db4070f814fbef1c714 100644
--- a/sites/all/modules/drush/commands/core/drupal/update_7.inc
+++ b/sites/all/modules/drush/commands/core/drupal/update.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: update_7.inc,v 1.29 2010/11/10 02:55:41 weitzman Exp $
 /**
  * @file
  *   Update.php for provisioned sites.
@@ -16,6 +15,12 @@
  */
 define('MAINTENANCE_MODE', 'update');
 
+/**
+ * Drupal's update.inc has functions that are in previous update_X.inc files
+ * for example, update_check_incompatibility() which can prove useful when
+ * enabling modules.
+ */
+require_once DRUPAL_ROOT . '/includes/update.inc';
 /**
  * Returns (and optionally stores) extra requirements that only apply during
  * particular parts of the update.php process.
@@ -143,7 +148,6 @@ function update_main_prepare() {
   // We prepare a minimal bootstrap for the update requirements check to avoid
   // reaching the PHP memory limit.
   require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-  require_once DRUPAL_ROOT . '/includes/update.inc';
   require_once DRUPAL_ROOT . '/includes/common.inc';
   require_once DRUPAL_ROOT . '/includes/file.inc';
   require_once DRUPAL_ROOT . '/includes/entity.inc';
@@ -234,7 +238,7 @@ function update_main() {
     }
 
     if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
-      drush_user_abort();
+      return drush_user_abort();
     }
 
     drush_update_batch($start);
diff --git a/sites/all/modules/drush/commands/core/drupal/update_5.inc b/sites/all/modules/drush/commands/core/drupal/update_5.inc
index c422279dd89a4f8ffa407da6663011f91f98ef96..029ca6f97e73db77b815da46eb5d9c7b4173db70 100644
--- a/sites/all/modules/drush/commands/core/drupal/update_5.inc
+++ b/sites/all/modules/drush/commands/core/drupal/update_5.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: update_5.inc,v 1.9 2010/11/10 02:55:41 weitzman Exp $
 
 /**
  * @file
@@ -80,7 +79,7 @@ function update_main() {
       }
     }
     if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
-      drush_user_abort();
+      return drush_user_abort();
     }
 
     $update_results = array();
diff --git a/sites/all/modules/drush/commands/core/drupal/update_6.inc b/sites/all/modules/drush/commands/core/drupal/update_6.inc
index 7914e4e2dd2b9e10fc810be415aabff0e582537f..f3bcc5046d728360db481564b9768f6011e098a6 100644
--- a/sites/all/modules/drush/commands/core/drupal/update_6.inc
+++ b/sites/all/modules/drush/commands/core/drupal/update_6.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: update_6.inc,v 1.19 2010/12/01 15:53:15 jonhattan Exp $
 /**
  * @file
  *   Update.php for provisioned sites.
@@ -219,6 +218,31 @@ function update_fix_d6_requirements() {
       'primary key' => array('cid'),
     );
     db_create_table($ret, 'cache_block', $schema['cache_block']);
+    
+    // Create the semaphore table now -- the menu system after 6.15 depends on
+    // this table, and menu code runs in updates prior to the table being
+    // created in its original update function, system_update_6054().
+    $schema['semaphore'] = array(
+      'fields' => array(
+        'name' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'value' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'expire' => array(
+        'type' => 'float',
+        'size' => 'big',
+        'not null' => TRUE),
+      ),
+     'indexes' => array('expire' => array('expire')),
+     'primary key' => array('name'),
+    );
+    db_create_table($ret, 'semaphore', $schema['semaphore']);
   }
 
   return $ret;
@@ -403,7 +427,7 @@ function update_main() {
       }
     }
     if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
-      drush_user_abort();
+      return drush_user_abort();
     }
     // Proceed with running all pending updates.
     $operations = array();
diff --git a/sites/all/modules/drush/commands/core/field.drush.inc b/sites/all/modules/drush/commands/core/field.drush.inc
index ec9d66ebff9bce2c1a685263fadcadd017f12d5c..09448d6def411eb4dd902101087e595e89a6cb80 100644
--- a/sites/all/modules/drush/commands/core/field.drush.inc
+++ b/sites/all/modules/drush/commands/core/field.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: field.drush.inc,v 1.7 2010/08/12 14:28:46 weitzman Exp $
 
 /**
  * @file
@@ -10,15 +9,11 @@
  * Implementation of hook_drush_help().
  */
 function field_drush_help($section) {
-  switch ($section)  {
-    case 'drush:field-create':
-      return dt('Quickly create fields and instances for a given bundle.');
-    case 'drush:field-update':
-      return dt('Return URL for editing field.');
-    case 'drush:field-clone':
-      return dt('Clone a field and all of its instances.');
-    case 'drush:field-info':
-      return dt('View information about fields, field_types, widgets, etc.');
+  switch ($section) {
+    case 'meta:field:title':
+      return dt('Field commands');
+    case 'meta:field:summary':
+      return dt('Manipulate Drupal 7+ fields.');
   }
 }
 
@@ -28,7 +23,7 @@ function field_drush_help($section) {
 function field_drush_command() {
   $items['field-create'] = array(
     'description' => 'Create fields and instances. Returns urls for field editing.',
-    'core' => array(7),
+    'core' => array('7+'),
     'drupal_dependencies' => array('field_ui'),
     'arguments' => array(
       'bundle' => 'Content type (for nodes). Name of bundle to attach fields to. Required.',
@@ -45,7 +40,7 @@ function field_drush_command() {
   );
   $items['field-update'] = array(
     'description' => 'Return URL for field editing web page.',
-    'core' => array(7),
+    'core' => array('7+'),
     'drupal_dependencies' => array('field_ui'),
     'arguments' => array(
       'field_name' => 'Name of field that needs updating.',
@@ -56,7 +51,7 @@ function field_drush_command() {
   );
   $items['field-delete'] = array(
     'description' => 'Delete a field and its instances.',
-    'core' => array(7),
+    'core' => array('7+'),
     'arguments' => array(
       'field_name' => 'Name of field to delete.',
     ),
@@ -71,7 +66,7 @@ function field_drush_command() {
   );
   $items['field-clone'] = array(
     'description' => 'Clone a field and all its instances.',
-    'core' => array(7),
+    'core' => array('7+'),
     'arguments' => array(
       'source_field_name' => 'Name of field that will be cloned',
       'target_field_name' => 'Name of new, cloned field.',
@@ -84,31 +79,34 @@ function field_drush_command() {
   $items['field-info'] = array(
     'description' => 'View information about fields, field_types, and widgets.',
     'drupal_dependencies' => array('field_ui'),
-    'core' => array(7),
+    'core' => array('7+'),
     'arguments' => array(
       'type' => 'Recognized values: fields, types. If omitted, a choice list appears.',
     ),
+    'options' => array(
+      'pipe' => 'Return field information table as CSV.',
+    ),
     'examples' => array(
       'field-info types' => 'Show a table which lists all field types and their available widgets',
     ),
-  ); 
+  );
   return $items;
 }
 
 function drush_field_create($bundle) {
   $entity_type = drush_get_option('entity_type', 'node');
-  
+
   $args = func_get_args();
   array_shift($args);
   if (empty($args)) {
     // Just one item in this array for now.
     $args[] = drush_field_create_wizard();
   }
-  
+
   // Iterate over each field spec.
   foreach ($args as $string) {
     list($name, $type, $widget) = explode(',', $string);
-    $info = field_info_field($field_name);
+    $info = field_info_field($name);
     if (empty($info)) {
       // Field does not exist already. Create it.
       $field = array(
@@ -117,7 +115,7 @@ function drush_field_create($bundle) {
       );
       drush_op('field_create_field', $field);
     }
-    
+
     // Create the instance.
     $instance = array(
       'field_name' => $name,
@@ -128,17 +126,26 @@ function drush_field_create($bundle) {
       $instance['widget'] = array('type' => $widget);
     }
     drush_op('field_create_instance', $instance);
-    
-    $urls[] = url(_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $name, array('absolute' => TRUE));
+
+    $urls[] = url(drush_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $name, array('absolute' => TRUE));
   }
   drush_print(implode(' ', $urls));
 }
 
+// Copy of function _field_ui_bundle_admin_path() since we don't want to load UI module.
+function drush_field_ui_bundle_admin_path($entity_type, $bundle_name) {
+  $bundles = field_info_bundles($entity_type);
+  $bundle_info = $bundles[$bundle_name];
+  if (isset($bundle_info['admin'])) {
+    return isset($bundle_info['admin']['real path']) ? $bundle_info['admin']['real path'] : $bundle_info['admin']['path'];
+  }
+}
+
 function drush_field_update($field_name) {
    $info = field_info_field($field_name);
    foreach ($info['bundles'] as $entity_type => $bundles) {
      foreach ($bundles as $bundle) {
-       $urls[] = url(_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $field_name, array('absolute' => TRUE));
+       $urls[] = url(drush_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $field_name, array('absolute' => TRUE));
      }
    }
   drush_print(implode(' ', $urls));
@@ -147,7 +154,7 @@ function drush_field_update($field_name) {
 function drush_field_delete($field_name) {
   $info = field_info_field($field_name);
   $confirm = TRUE;
-  
+
   if (!$bundle = drush_get_option('bundle')) {
     foreach ($info['bundles'] as $entity_type => $bundles) {
       foreach ($bundles as $bundle) {
@@ -161,11 +168,11 @@ function drush_field_delete($field_name) {
     }
     else {
       if (!drush_confirm(dt('Do you want to delete the %field_name field?', array('%field_name' => $field_name)))) {
-        return drush_log(dt('Aborting.'));
+        return drush_user_abort();
       }
     }
   }
-  
+
   if ($bundle == 'all') {
     foreach ($info['bundles'] as $entity_type => $bundles) {
        foreach ($bundles as $bundle) {
@@ -179,7 +186,7 @@ function drush_field_delete($field_name) {
     $instance = field_info_instance($entity_type, $field_name, $bundle);
     drush_op('field_delete_instance', $instance);
   }
-  
+
   // If there are no more bundles, delete the field.
   $info = field_info_field($field_name);
   if (empty($info['bundles'])) {
@@ -191,11 +198,11 @@ function drush_field_clone($source_field_name, $target_field_name) {
    if (!$info = field_info_field($source_field_name)) {
      return drush_set_error(dt('%source not found in field list.', array('%source' => $source_field_name)));
    }
-   
+
    unset($info['id']);
    $info['field_name'] = $target_field_name;
    $target = drush_op('field_create_field', $info);
-   
+
    foreach ($info['bundles'] as $entity_type => $bundles) {
      foreach ($bundles as $bundle) {
        $instance = field_info_instance($entity_type, $source_field_name, $bundle);
@@ -203,10 +210,10 @@ function drush_field_clone($source_field_name, $target_field_name) {
        unset($instance['id']);
        $instance['field_id'] = $target['id'];
        drush_op('field_create_instance', $instance);
-       $urls[] = url(_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $target_field_name, array('absolute' => TRUE));
+       $urls[] = url(drush_field_ui_bundle_admin_path($entity_type, $bundle) . '/fields/' . $target_field_name, array('absolute' => TRUE));
      }
    }
-   
+
   drush_print(implode(' ', $urls));
 }
 
@@ -214,7 +221,7 @@ function drush_field_info($type = NULL) {
   if (is_null($type)) {
     $type = drush_choice(drupal_map_assoc(array('types', 'fields')), dt('Which information do you wish to see?'));
   }
-  
+
   switch ($type) {
     case 'fields':
       $rows[] = array(
@@ -228,11 +235,13 @@ function drush_field_info($type = NULL) {
         foreach ($field['bundles'] as $entity_type => $bundles) {
           $bundle_strs[] = implode(',', $bundles);
         }
-        $rows[] = array(
+        $row = array(
           $field_name,
           $field['type'],
           implode(' ', $bundle_strs),
         );
+        $rows[] = $row;
+        $pipe[] = implode(',', $row);
       }
       break;
     case 'types':
@@ -246,16 +255,20 @@ function drush_field_info($type = NULL) {
       $widgets = field_info_widget_types();
       foreach ($info as $type_name => $type) {
         $widgets = field_ui_widget_type_options($type_name);
-        $rows[] = array(
+        $row = array(
           $type_name,
           $type['default_widget'],
           implode(', ', array_keys($widgets)),
         );
+        $rows[] = $row;
+        $pipe[] = implode(',', $row);
       }
       break;
   }
-  
+
   drush_print_table($rows, TRUE);
+  drush_print_pipe($pipe);
+  return $rows;
 }
 
 /**
@@ -287,4 +300,4 @@ function drush_field_get_entity_from_bundle($bundle) {
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/drush/commands/core/help.drush.inc b/sites/all/modules/drush/commands/core/help.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..aeff9edfc4e3ea8a44fe80512e03b8e161197d48
--- /dev/null
+++ b/sites/all/modules/drush/commands/core/help.drush.inc
@@ -0,0 +1,261 @@
+<?php
+
+/**
+ * Build a fake command for the purposes of showing examples and options.
+ */
+function drush_global_options_command($brief = FALSE) {
+  $global_options_help = array(
+    'description' => 'Execute a drush command. Run `drush help [command]` to view command-specific help.  Run `drush topic` to read even more documentation.',
+    'sections' => array(
+      'options' => 'Global options (see `drush topic core-global-options` for the full list).',
+    ),
+    'options' => drush_get_global_options($brief),
+    'examples' => array(
+      'drush dl cck zen' => 'Download CCK module and Zen theme.',
+      'drush --uri=http://example.com status' => 'Show status command for the example.com multi-site.',
+    ),
+  );
+  $global_options_help += drush_command_defaults('global-options', 'global_options', __FILE__);
+
+  return $global_options_help;
+}
+
+/**
+ * Command callback for help command. This is the default command, when none
+ * other has been specified.
+ */
+function drush_core_help() {
+  $commands = func_get_args();
+
+  if (empty($commands)) {
+    // For speed, only bootstrap up to DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION.
+    drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION);
+    $implemented = drush_get_commands();
+    
+    // Organize all commands into categories
+    $command_categories = array();
+    $category_map = array();
+    foreach ($implemented as $key => $candidate) {
+      if ((!array_key_exists('is_alias', $candidate) || !$candidate['is_alias']) && !$candidate['hidden']) {
+	$category = $candidate['commandfile'];
+	// If we have decided to remap a category, remap every command
+	if (array_key_exists($category, $category_map)) {
+	  $category = $category_map[$category];
+	}
+	if (!array_key_exists($category, $command_categories)) {
+          $title = drush_command_invoke_all('drush_help', "meta:$category:title");
+	  $alternate_title = '';
+	  if (!$title) {
+	    // If there is no title, then check to see if the
+	    // command file is stored in a folder with the same
+	    // name as some other command file (e.g. 'core') that
+	    // defines a title.
+	    $alternate = basename($candidate['path']);
+            $alternate_title = drush_command_invoke_all('drush_help', "meta:$alternate:title");
+	  }
+	  if (!empty($alternate_title)) {
+	    $category_map[$category] = $alternate;
+	    $category = $alternate;
+	    $title = $alternate_title;
+	  }
+	  $command_categories[$category]['title'] = empty($title) ? '' : $title[0];
+          $summary = drush_command_invoke_all('drush_help', "meta:$category:summary");
+          if ($summary) {
+            $command_categories[$category]['summary'] = $summary[0];
+	  }
+	}
+	$command_categories[$category]['commands'][] = $key;
+      }
+    }
+    
+    // Sort the command categories; make sure that 'core' is
+    // always first in the list
+    $core_category = array('core' => $command_categories['core']);
+    unset($command_categories['core']);
+    // Post-process the categories that have no title.
+    // Any that have fewer than 4 commands will go into a
+    // section called "other".
+    $processed_categories = array();
+    $misc_categories = array();
+    $other_commands = array();
+    $other_categories = array();
+    foreach ($command_categories as $key => $info) {
+      if (empty($info['title'])) {
+        $one_category = $key;
+        if (count($info['commands']) < 4) {
+	  $other_commands = array_merge($other_commands, $info['commands']);
+	  $other_categories[] = $one_category;
+	}
+	else {
+	  $info['title'] = dt("All commands in !category", array('!category' => $key));
+          $misc_categories[$one_category] = $info;
+	}
+      }
+      else {
+        $processed_categories[$key] = $info;
+      }
+    }
+    $other_category = array();
+    if (!empty($other_categories)) {
+      $other_category[implode(',', $other_categories)] = array('title' => dt("Other commands"), 'commands' => $other_commands);
+    }
+    asort($processed_categories);
+    asort($misc_categories);
+    $command_categories = array_merge($core_category, $processed_categories, $misc_categories, $other_category);
+    
+    // If the user specified --filter w/out a value, then
+    // present a list of help options.
+    if (drush_get_option('filter', FALSE) === TRUE) {
+      $help_categories = array();
+      foreach ($command_categories as $key => $info) {
+        $description = $info['title'];
+	if (array_key_exists('summary', $info)) {
+	  $description .= ": " . $info['summary'];
+	}
+	$help_categories[$key] = $description;
+       }
+      $result = drush_choice($help_categories, 'Select a help category:');
+      if (!$result) {
+	return drush_user_abort();
+      }
+      drush_set_option('filter', $result);
+    }
+    
+    if (drush_get_option('html')) {
+      drush_print(drush_help_html_header());
+    }
+    
+    // Make a fake command section to hold the global options, then print it.
+    $global_options_help = drush_global_options_command(TRUE);
+    if ((!drush_get_option('html')) && (!drush_get_option('filter'))) {
+      drush_print_help($global_options_help);
+    }
+    
+    // Filter out categories that the user does not want to see
+    if ($filter_category = drush_get_option('filter')) {
+      if (!array_key_exists($filter_category, $command_categories)) {
+        return drush_set_error('DRUSH_NO_CATEGORY', dt("The specified command category !filter does not exist.", array('!filter' => $filter_category)));
+      }
+      $command_categories = array($filter_category => $command_categories[$filter_category]);
+    }
+
+    // If the user specified --sort, then merge all of the remaining
+    // categories together
+    if (drush_get_option('sort', FALSE)) {
+      $combined_commands = array();
+      foreach ($command_categories as $key => $info) {
+        $combined_commands = array_merge($combined_commands, $info['commands']);
+      }
+      $command_categories = array('all' => array('commands' => $combined_commands, 'title' => dt("Commands:")));
+    }
+    
+    // Next, print out the table of commands by category.
+    $all_commands = array();
+    foreach ($command_categories as $key => $info) {
+      // Get the commands in this category and sort them
+      $commands = $info['commands'];
+      sort($commands);
+      
+      // Remove hidden commands and build output for drush_print_table.
+      $rows = array();
+      foreach($commands as $cmd) {
+        $command = $implemented[$cmd];
+	$all_commands[$cmd] = $command;
+        $name = $command['aliases'] ? $cmd . ' (' . implode(', ', $command['aliases']) . ')': $cmd;
+        $rows[$cmd] = array($name, $command['description']);
+        $pipe[] = $cmd;
+      }
+      
+      // Vary the output by mode: text or html
+      if (drush_get_option('html')) {
+        $sorted_commands = array();
+        foreach($commands as $cmd) {
+          $sorted_commands[$cmd] = $implemented[$cmd];
+	}
+	
+        drush_print("<h3>" . $info['title'] . "</h3>");
+        drush_print(drush_help_html_command_list($sorted_commands));
+      }
+      else {      
+        drush_print($info['title'] . ": (" . $key . ")");
+	drush_print_table($rows, FALSE, array(0 => 20));
+      }
+    }
+    
+    // Print out the long-form help for all commands
+    if (drush_get_option('html')) {
+      drush_print(drush_help_html_global_options($global_options_help));
+      drush_print(drush_help_html($all_commands));
+    }
+    
+    // Newline-delimited list for use by other scripts. Set the --pipe option.
+    if (drush_get_option('pipe') && isset($pipe)) {
+    sort($pipe);
+      drush_print_pipe(implode(" ", $pipe));
+    }
+    return;
+  }
+  else {
+    $result = TRUE;
+    while ((count($commands) > 0) && !drush_get_error()) {
+      $result =  drush_show_help(array_shift($commands));
+    }
+    return $result;
+  }
+
+  return drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => implode(" ", $commands))));
+}
+
+
+/**
+ * Return an HTML page header that includes all global options.
+ */
+function drush_help_html_header() {
+  $output =  "<html><head><title>drush help</title><style>dt {font-size: 110%; font-weight: bold}</style></head><body>\n";
+}
+
+function drush_help_html_global_options($global_options_help) {
+  // Global options
+  $global_option_rows = drush_format_help_section($global_options_help, 'options');
+  $output =  '<h3>Global Options (see `drush topic core-global-options` for the full list)</h3><table>';
+  foreach ($global_option_rows as $row) {
+    $output .= "<tr>";
+    foreach ($row as $value) {
+      $output .=  "<td>" . htmlspecialchars($value) . "</td>\n";
+    }
+    $output .= "</tr>";
+  }
+  $output .=  "</table>\n";
+  
+  return $output;
+}
+
+function drush_help_html_command_list($commands) {
+  // Command table
+  $output =  "<table>\n";
+  foreach ($commands as $key => $command) {
+    $output .=  "  <tr><td><a href=\"#$key\">$key</a></td><td>" . $command['description'] . "</td></tr>\n";
+  }
+  $output .=  "</table>\n";
+  
+  return $output;
+}
+
+/**
+ * Return an HTML page documenting all available commands and global options.
+ */
+function drush_help_html($commands) {
+  // Command details
+  $output =  '<h3>Command detail</h3><dl>';
+  foreach ($commands as $key => $command) {
+    $output .=  "\n<a name=\"$key\"></a><dt>$key</dt><dd><pre>\n";
+    ob_start();
+    drush_show_help($key);
+    $output .= ob_get_clean();
+    $output .=  "</pre></dd>\n";
+  }
+
+  $output .=  "</body></html>\n";
+
+  return $output;
+}
diff --git a/sites/all/modules/drush/commands/core/image.drush.inc b/sites/all/modules/drush/commands/core/image.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..06edba79057677c4e39a11123adcdd254d400fd2
--- /dev/null
+++ b/sites/all/modules/drush/commands/core/image.drush.inc
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ *  Image module's drush integration.
+ *
+ *  @todo image-build($field_name, $bundle, $style_name)
+ */
+
+/**
+ * Implementation of hook_drush_command().
+ */
+function image_drush_command() {
+  $items['image-flush'] = array(
+    'description' => 'Flush all derived images for a given style.',
+    'core' => array('7+'),
+    'drupal_dependencies' => array('image'),
+    'arguments' => array(
+      'style' => 'An image style machine name. If not provided, user may choose from a list of names.',
+    ),
+    'options' => array(
+      'all' => 'Flush all derived images',
+    ),
+    'examples' => array(
+      'drush image-flush' => 'Pick an image style and then delete its images.',
+      'drush image-flush thumbnail' => 'Delete all thumbnail images.',
+      'drush image-flush --all' => 'Flush all derived images. They will be regenerated on the fly.',
+    ),
+  );
+  return $items;
+}
+
+function drush_image_flush($style_name = NULL) {
+  if (drush_get_option('all')) {
+    drush_image_flush_all();
+  }
+  elseif (empty($style_name)) {
+    $choices = drupal_map_assoc(array_keys(image_styles()));
+    $choices = array_merge(array('all' => 'all'), $choices);
+    $style_name = drush_choice($choices, dt("Choose a style to flush."));
+    if ($style_name == 'all') {
+      drush_image_flush_all();
+    }
+    else {
+      $commands = drush_get_commands();
+      return drush_dispatch($commands['image-flush'], array($style_name));
+    }
+  }
+  else {
+    if ($style = image_style_load($style_name)) {
+      image_style_flush($style);
+      drush_log(dt('Image style !style_name flushed', array('!style_name' => $style_name)), 'success');
+    }
+    else {
+      return drush_set_error(dt('Image style !style not recognized.', array('!style' => $style_name)));
+    }
+  }
+}
+
+function drush_image_flush_all() {
+  foreach (image_styles() as $style) {
+    image_style_flush($style);
+  }
+  drush_log(dt('All image styles flushed'), 'success');
+}
diff --git a/sites/all/modules/drush/commands/core/rsync.core.inc b/sites/all/modules/drush/commands/core/rsync.core.inc
index 2eba134fa305a4d942208e4af56d05007e714c8b..263782a8fd6797383326afcfc4f321ebbb4d0b26 100644
--- a/sites/all/modules/drush/commands/core/rsync.core.inc
+++ b/sites/all/modules/drush/commands/core/rsync.core.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: rsync.core.inc,v 1.7 2010/11/21 15:10:56 greg1anderson Exp $
 
 /**
  * Entrypoint for drush rsync.
@@ -37,7 +36,7 @@ function drush_core_rsync($source, $destination, $additional_options = array())
   if ($is_multiple === FALSE) {
     // If the user path is the same for the source and the destination, then
     // always add a slash to the end of the source.  If the user path is not
-    // the same in the source and the destinaiton, then you need to know how
+    // the same in the source and the destination, then you need to know how
     // rsync paths work, and put on the trailing '/' if you want it.
     if ($source_settings['user-path'] == $destination_settings['user-path']) {
       $source_path .= '/';
@@ -47,7 +46,7 @@ function drush_core_rsync($source, $destination, $additional_options = array())
       drush_print(dt("You will destroy data from !target and replace with data from !source", array('!source' => $source_path, '!target' => $destination_path)));
       if (!drush_confirm(dt('Do you really want to continue?'))) {
         // was: return drush_set_error('CORE_SYNC_ABORT', 'Aborting.');
-        drush_user_abort();
+        return drush_user_abort();
       }
     }
 
@@ -58,7 +57,7 @@ function drush_core_rsync($source, $destination, $additional_options = array())
     $include_settings_is_default = (strpos($source . $destination, ':') !== FALSE) || (strpos($source . $destination, '/') !== FALSE);
 
     // Go ahead and call rsync with the paths we determined
-    drush_core_call_rsync($source_path, $destination_path, $additional_options, $include_settings_is_default);
+    return drush_core_call_rsync($source_path, $destination_path, $additional_options, $include_settings_is_default);
   }
 }
 
@@ -87,11 +86,19 @@ function drush_core_rsync($source, $destination, $additional_options = array())
  *   TRUE on success, FALSE on failure.
  */
 function drush_core_call_rsync($source, $destination, $additional_options = array(), $include_settings_is_default = TRUE, $live_output = TRUE) {
-  $options = ' --exclude="*.svn*"';
+  // Exclude vcs reserved files.
+  $options = '';
+  if (!_drush_rsync_option_exists('include-vcs', $additional_options)) {
+    $vcs_files = drush_version_control_reserved_files();
+    foreach ($vcs_files as $file) {
+      $options .= ' --exclude="'.$file.'"';
+    }
+  }
+
   $mode = '-az';
   // Process --include-path and --exclude-path options the same way
   foreach (array('include', 'exclude') as $include_exclude) {
-    // Get the option --include-path or --exclude path and explode to an array of paths
+    // Get the option --include-path or --exclude-path and explode to an array of paths
     // that we will translate into an --include or --exclude option to pass to rsync
     $inc_ex_path = explode(PATH_SEPARATOR, drush_get_option(array($include_exclude . '-path', $include_exclude . '-paths'), ''));
     foreach ($inc_ex_path as $one_path_to_inc_ex) {
@@ -241,13 +248,18 @@ function drush_core_call_rsync($source, $destination, $additional_options = arra
   $exec = "rsync -e 'ssh $ssh_options' $mode$options $source $destination";
 
   if ($live_output) {
-    $exec_result = drush_op('system', $exec) !== FALSE;
+    $exec_result = drush_op_system($exec);
+    $result = ($exec_result == 0);
   }
   else {
-    $exec_result = drush_shell_exec($exec);
+    $result = drush_shell_exec($exec);
+  }
+  
+  if (!$result) {
+    drush_set_error('DRUSH_RSYNC_FAILED', dt("Could not rsync from !source to !dest", array('!source' => $source, '!dest' => $destination)));
   }
 
-  return $exec_result;
+  return $result;
 }
 
 function _drush_rsync_option_exists($option, $additional_options) {
diff --git a/sites/all/modules/drush/commands/core/search.drush.inc b/sites/all/modules/drush/commands/core/search.drush.inc
index 8c283220fbc8a4e2fc714a076e064ada2bee3a2e..8dc9fc57d32fc855cea58e2bc4331215ae3b2d54 100644
--- a/sites/all/modules/drush/commands/core/search.drush.inc
+++ b/sites/all/modules/drush/commands/core/search.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: search.drush.inc,v 1.6 2010/04/02 04:14:49 weitzman Exp $
 
 function drush_core_search_status() {
   list($remaining, $total) = _drush_core_search_status();
@@ -38,7 +37,7 @@ function _drush_core_search_status() {
 function drush_core_search_index() {
   drush_print(dt("Building the index may take a long time."));
   if (!drush_confirm(dt('Do you really want to continue?'))) {
-    return drush_set_error('CORE_SEARCH_REBUILD_ABORT', 'Aborting.');
+    return drush_user_abort();
   }
   drush_op('_drush_core_search_index');
   drush_log(dt('The search index has been built.'), 'ok');
@@ -70,7 +69,7 @@ function drush_core_search_reindex() {
     drush_print(dt("Rebuilding the index may take a long time."));
   }
   if (!drush_confirm(dt('Do you really want to continue?'))) {
-    return drush_set_error('CORE_SEARCH_REINDEX_ABORT', 'Aborting.');
+    return drush_user_abort();
   }
 
   if (drush_drupal_major_version() >= 7) {
diff --git a/sites/all/modules/drush/commands/core/site_install.drush.inc b/sites/all/modules/drush/commands/core/site_install.drush.inc
index 379915dda2d34efd1565d8e9d72111cc2961785a..77fc41039bddfc76c9bb11830c8bb233452552db 100644
--- a/sites/all/modules/drush/commands/core/site_install.drush.inc
+++ b/sites/all/modules/drush/commands/core/site_install.drush.inc
@@ -1,20 +1,31 @@
 <?php
-// $Id: site_install.drush.inc,v 1.12 2010/11/28 14:45:04 weitzman Exp $
 
-// Perform setup tasks for installation.
-function drush_core_pre_site_install() {
+/**
+ * Command validate.
+ */
+function drush_core_site_install_validate() {
+  if ($sites_subdir = drush_get_option('sites-subdir')) {
+    $lower = strtolower($sites_subdir);
+    if ($sites_subdir != $lower) {
+      drush_log(dt('Only lowercase sites-subdir are valid. Switching to !lower.', array('!lower' => $lower)), 'warning');
+      drush_set_option('sites-subdir', $lower);
+    }
+  }
+}
 
-  if (!$db_spec = drush_core_site_install_db_spec()) {
+/**
+ * Perform setup tasks for installation.
+ */
+function drush_core_pre_site_install() {
+  if (!$db_spec = drush_sql_read_db_spec()) {
     drush_set_error(dt('Could not determine database connection parameters. Pass --db-url option.'));
     return;
   }
-
-  
   if ($sites_subdir = drush_get_option('sites-subdir')) {
     // Needed so that we later bootstrap into the right site.
-    drush_set_option('uri', $sites_subdir);
+    drush_set_option('uri', 'http://'.$sites_subdir);
   }
- else {
+  else {
     $sites_subdir = 'default';
   }
 
@@ -30,7 +41,7 @@ function drush_core_pre_site_install() {
   $msg[] = dt("DROP your '@db' database and then CREATE a new one.", array('@db' => $db_spec['database']));
 
   if (!drush_confirm(dt('You are about to ') . implode(dt(' and '), $msg) . ' Do you want to continue?')) {
-    return drush_set_error('CORE_SITE_INSTALL_ABORT', 'Aborting.');
+    return drush_user_abort();
   }
 
   // Can't install without sites directory and settings.php.
@@ -49,8 +60,22 @@ function drush_core_pre_site_install() {
       return;
     }
     elseif (drush_drupal_major_version() == 6) {
-      // On D6, we have to write $db_url ourselves. On D7+, the installer does it.
+      // On D6, we have to write $db_url ourselves. In D7+, the installer does it.
       file_put_contents($settingsfile, "\n" . '$db_url = \'' . drush_get_option('db-url') . "';\n", FILE_APPEND);
+      // Instead of parsing and performing string replacement on the configuration file,
+      // the options are appended and override the defaults.
+      // Database table prefix
+      if (!empty($db_spec['db_prefix'])) {
+        if (is_array($db_spec['db_prefix'])) {
+          // Write db_prefix configuration as an array
+          $db_prefix_config = '$db_prefix = ' . var_export($db_spec['db_prefix'], TRUE) . ';';
+        }
+        else {
+          // Write db_prefix configuration as a string
+          $db_prefix_config = '$db_prefix = \'' . $db_spec['db_prefix'] . '\';';
+        }
+        file_put_contents($settingsfile, "\n" . $db_prefix_config . "\n", FILE_APPEND);
+      }
     }
   }
 
@@ -62,19 +87,14 @@ function drush_core_pre_site_install() {
     }
   }
 
-  // Now we can bootstrap up to the specified site if not already there.
-  drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE);
+  // Now we can bootstrap up to the specified site.
+  drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION);
+  // UNL Change!
   // Don't drop databases.  No idea why they wanted to do that.
   return;
+  // End UNL Change!
 
   // Drop and create DB if needed.
-  // @TODO: support db-su like sql sync.
-
-  // Can't use drush_sql_query() since might not have a DB.
-  // Get credentials to connect to the server, but not the database which we
-  // are about to DROP.
-
-  // Save the database name before we unset() it.
   $db_name = $db_spec['database'];
   $scheme = _drush_sql_get_scheme($db_spec);
   $simulate = drush_get_context('DRUSH_SIMULATE');
@@ -88,59 +108,30 @@ function drush_core_pre_site_install() {
         drush_set_error(dt('Could not drop database: @name', array('@name' => $db_name)));
       }
     }
-    // Nothing else to do for SQLite installations, so return.
-    return;
   }
-  // _drush_sql_get_credentials() will set a default database according to
-  // the scheme if one is not set.
-  unset($db_spec['database']);
-  $credentials = _drush_sql_get_credentials($db_spec);
-
-  $scheme_command = $scheme;
-  switch ($scheme) {
-    case 'mysql':
-      $command_parameter_name = 'execute';
-      break;
-    case 'pgsql':
-      $scheme_command = 'psql';
-      $command_parameter_name = 'command';
-      break;
-  }
-  $execute = "$scheme_command $credentials --$command_parameter_name";
-
-  if (drush_op('system', "$execute='DROP DATABASE IF EXISTS `$db_name`'") && !$simulate) {
-    drush_set_error(dt('Could not drop database: @name', array('@name' => $db_name)));
-    return;
-  }
-
-  if (drush_op('system', "$execute='CREATE DATABASE `$db_name`'") && !$simulate) {
-    drush_set_error(dt('Could not create new database: @name', array('@name' => $db_name)));
-    return;
+  else {
+    drush_sql_empty_db($db_spec);
   }
+  return TRUE;
 }
 
-// Command callback.
+/**
+ * Command callback.
+ */
 function drush_core_site_install($profile = NULL) {
-  drush_include_engine('drupal', 'site_install', drush_drupal_major_version());
-  drush_core_site_install_version($profile);
-}
-
-// Return a db_spec based on supplied db_url/db_prefix options or
-// an existing settings.php.
-function drush_core_site_install_db_spec() {
-  if ($db_url = drush_get_option('db-url')) {
-    // We were passed a db_url. Usually a fresh site.
-    $db_spec = drush_convert_db_from_db_url($db_url);
-    $db_spec['db_prefix'] = drush_get_option('db-prefix');
-    return $db_spec;
-  }
-  elseif (drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION)) {
-    // We have an existing settings.php.
-    $db_spec = _drush_sql_get_db_spec();
-    $db_spec['db_prefix'] = $GLOBALS['db_prefix'];
-    return $db_spec;
-  }
-  else {
-    return FALSE;
+  $args = func_get_args();
+  $form_options = array();
+
+  if ($args) {
+    // The first argument is the profile.
+    $profile = array_shift($args);
+    // Subsequent arguments are additional form values.
+    foreach ($args as $arg) {
+      list($key, $value) = explode('=', $arg);
+      $form_options[$key] = $value;
+    }
   }
+
+  drush_include_engine('drupal', 'site_install', drush_drupal_major_version());
+  drush_core_site_install_version($profile, $form_options);
 }
diff --git a/sites/all/modules/drush/commands/core/sitealias.drush.inc b/sites/all/modules/drush/commands/core/sitealias.drush.inc
index a83fd0bafd9c233391e9b80925d94e4d12426575..7ec577dc1088df070507dc605ab42d72679c42e5 100644
--- a/sites/all/modules/drush/commands/core/sitealias.drush.inc
+++ b/sites/all/modules/drush/commands/core/sitealias.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: sitealias.drush.inc,v 1.23 2010/11/28 04:50:54 greg1anderson Exp $
 
 /**
  * @file
@@ -24,19 +23,21 @@ function sitealias_drush_command() {
       'site' => 'Site specification alias to print',
     ),
     'options' => array(
-      '--full' => 'Print the full alias record for each site.  Default when aliases are specified on the command line.',
-      '--short' => 'Print only the site alias name.  Default when not command line arguments are specified.',
-      '--pipe' => 'Print the long-form site specification for each site.',
-      '--with-db' => 'Include the databases structure in the full alias record.',
-      '--with-db-url' => 'Include the short-form db-url in the full alias record.',
-      '--no-db' => 'Do not include the database record in the full alias record (default).',
-      '--with-optional' => 'Include optional default items.',
+      'full' => 'Print the full alias record for each site.  Default when aliases are specified on the command line.',
+      'component' => 'Print only the specified element from the full alias record.',
+      'short' => 'Print only the site alias name.  Default when not command line arguments are specified.',
+      'pipe' => 'Print the long-form site specification for each site.',
+      'with-db' => 'Include the databases structure in the full alias record.',
+      'with-db-url' => 'Include the short-form db-url in the full alias record.',
+      'no-db' => 'Do not include the database record in the full alias record (default).',
+      'with-optional' => 'Include optional default items.',
     ),
     'aliases' => array('sa'),
     'examples' => array(
       'drush site-alias' => 'List all alias records known to drush.',
       'drush site-alias @dev' => 'Print an alias record for the alias \'dev\'.',
     ),
+    'topics' => array('docs-aliases'),
   );
   return $items;
 }
@@ -120,7 +121,10 @@ function _drush_sitealias_user_specified_list() {
  * specified.
  */
 function drush_sitealias_print() {
-  drush_bootstrap_max();
+  // Call bootstrap max, unless the caller requested short output
+  if (!drush_get_option('short', FALSE)) {
+    drush_bootstrap_max();
+  }
   
   $site_list = _drush_sitealias_user_specified_list();
   $full_output = drush_get_option('full');
@@ -133,7 +137,18 @@ function drush_sitealias_print() {
       $site_specs[] = drush_sitealias_alias_record_to_spec($alias_record, $with_db);
     }
     if (isset($full_output)) {
-      _drush_sitealias_print_record($alias_record, $site);
+      $component = drush_get_option('component');
+      if ($component) {
+        if (array_key_exists($component, $alias_record)) {
+	  drush_print($alias_record[$component]);
+	}
+	else {
+	  drush_set_error('DRUSH_NO_SUCH_ELEMENT', dt('The element @component was not found in the alias record for @site.', array('@component' => $component, '@site' => $site)));
+	}
+      }
+      else {
+        _drush_sitealias_print_record($alias_record, $site);
+      }
     }
     else {
       drush_print($site);
@@ -201,7 +216,8 @@ function _drush_sitealias_print_record($alias_record, $site_alias = '') {
   }
 
   // We don't want the name to go into the output
-  unset($alias_record['name']);
+  unset($alias_record['#name']);
+  unset($alias_record['#hidden']);
 
   // We only want to output the 'root' item; don't output the '%root' path alias
   if (array_key_exists('path-aliases', $alias_record) && array_key_exists('%root', $alias_record['path-aliases'])) {
diff --git a/sites/all/modules/drush/commands/core/test.drush.inc b/sites/all/modules/drush/commands/core/test.drush.inc
index 9aa5c72f1d09e7e6f9e6c5739e41640e7a2e5f26..c9dd1c3cf80a8736f1c1212e2e8046d47d374f8a 100644
--- a/sites/all/modules/drush/commands/core/test.drush.inc
+++ b/sites/all/modules/drush/commands/core/test.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: test.drush.inc,v 1.12 2010/11/27 21:20:02 weitzman Exp $
 
 /**
  * @file
@@ -28,13 +27,16 @@ function test_drush_command() {
     'options' => array(
       'all' => 'Run all available tests',
       'methods' => 'A comma delimited list of methods that should be run within the test class. Defaults to all methods.',
-      'dirty' => 'Skip cleanup of temporary tables and files. Helpful for reading debug() messages and other post-mortem forensics.'
+      'dirty' => 'Skip cleanup of temporary tables and files. Helpful for reading debug() messages and other post-mortem forensics.',
+      'xml' => 'Output verbose test results to a specified directory using the JUnit test reporting format. Useful for integrating with Jenkins.'
+
     ),
     'drupal dependencies' => array('simpletest'),
-    // If you login, you fall victim to http://drupal.org/node/974768. We use a low
-    // bootstrap level here to avoid confusing the testing versus tested side. Causes some
-    // poorly written core drupal simpletests to fail.
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_DATABASE,
+    // If you DRUSH_BOOTSTRAP_DRUPAL_LOGIN, you fall victim to http://drupal.org/node/974768. We'd like
+    // to not bootstrap at all but simpletest uses Drupal to discover test classes,
+    // cache the lists of tests, file_prepare_directory(), variable lookup like
+    // httpauth creds, copy pre-built registry table from testing side, etc.
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
   );
   $items['test-clean'] = array(
     'description' => "Clean temporary tables and files.",
@@ -52,7 +54,8 @@ function drush_test_clean() {
 // Validate hook
 function drush_test_run_validate($specs = NULL) {
   if (!drush_get_option('uri')) {
-    return drush_set_error(dt("You must specify this site's URL using the --uri parameter."));
+    // No longer needed?
+    // return drush_set_error(dt("You must specify this site's URL using the --uri parameter."));
   }
 }
 
@@ -131,6 +134,10 @@ function simpletest_drush_run_test($class) {
           || (isset($test->results['#exception']) && $test->results['#exception'] > 0) ? 'error' : 'ok');
   drush_log($info['name'] . ' ' . _simpletest_format_summary_line($test->results), $status);
 
+  if ($dir = drush_get_option('xml')) {
+    drush_test_xml_results($test_id, $dir);
+  }
+
   // If there were some failed tests show them.
   if ($status === 'error') {
     if (drush_drupal_major_version() >= 7) {
@@ -191,3 +198,71 @@ function drush_test_get_all_tests() {
   }
   return array($groups, $all_tests);
 }
+
+/*
+ * Display test results.
+ */
+function drush_test_xml_results($test_id, $dir) {
+  $dir = is_string($dir) ? $dir : '.';
+
+  $results_map = array(
+    'pass' => 'Pass',
+    'fail' => 'Fail',
+    'exception' => 'Exception',
+  );
+
+  if (drush_drupal_major_version() >= 7) {
+    $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
+  }
+  else {
+    $result = db_query("SELECT * FROM {simpletest} WHERE test_id = %d ORDER BY test_class, message_id", $test_id);
+    $results = array();
+    while ($row = db_fetch_object($result)) {
+      $results[] = $row;
+    }
+  }
+
+  $test_class = '';
+  $xml_files = array();
+
+  foreach ($results as $result) {
+    if (isset($results_map[$result->status])) {
+      if ($result->test_class != $test_class) {
+        // Display test class every time results are for new test class.
+        if (isset($xml_files[$test_class])) {
+          file_put_contents($dir . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
+          unset($xml_files[$test_class]);
+        }
+        $test_class = $result->test_class;
+        if (!isset($xml_files[$test_class])) {
+          $doc = new DomDocument('1.0');
+          $root = $doc->createElement('testsuite');
+          $root = $doc->appendChild($root);
+          $xml_files[$test_class] = array('doc' => $doc, 'suite' => $root);
+        }
+      }
+      // Save the result into the XML:
+      $case = $xml_files[$test_class]['doc']->createElement('testcase');
+      $case->setAttribute('classname', $test_class);
+      list($class, $name) = explode('->', $result->function, 2);
+      $case->setAttribute('name', $name);
+
+      if ($result->status == 'fail') {
+        $fail = $xml_files[$test_class]['doc']->createElement('failure');
+        $fail->setAttribute('type', 'failure');
+        $fail->setAttribute('message', $result->message_group);
+        $text = $xml_files[$test_class]['doc']->createTextNode($result->message);
+        $fail->appendChild($text);
+        $case->appendChild($fail);
+      }
+
+      $xml_files[$test_class]['suite']->appendChild($case);
+    }
+  }
+
+  // Save the last one:
+  if (isset($xml_files[$test_class])) {
+    file_put_contents($dir . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
+    unset($xml_files[$test_class]);
+  }
+}
diff --git a/sites/all/modules/drush/commands/core/topic.drush.inc b/sites/all/modules/drush/commands/core/topic.drush.inc
index 51686bc2cd355c0aeada08eeb2302a703631b11f..cda52fec24938266f29d230883030fd4fdbac149 100644
--- a/sites/all/modules/drush/commands/core/topic.drush.inc
+++ b/sites/all/modules/drush/commands/core/topic.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: topic.drush.inc,v 1.4 2010/10/06 21:00:26 weitzman Exp $
 
 /**
  * @file
@@ -20,11 +19,14 @@ function topic_drush_command() {
     ),
     'examples' => array(
       'drush topic' => 'Show all available topics.',
-      'drush topic core-context' => 'Show documentation for the drush context API',
-      'drush core-context' => 'Show documentation for the drush context API',
+      'drush topic docs-context' => 'Show documentation for the drush context API',
+      'drush docs-context' => 'Show documentation for the drush context API',
     ),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
     'aliases' => array('topic'),
+    'topics' => array('docs-readme'),
   );
+
   return $items;
 }
 
@@ -35,10 +37,11 @@ function topic_drush_help_alter($command) {
   $implemented = drush_get_commands();
   foreach ($command['topics'] as $topic_name) {
     // We have a related topic. Inject into the $command so the topic displays.
-    $command['sections']['topic_section'] = dt('Topics');
-    $command['topic_section'][$topic_name] = dt($implemented[$topic_name]['description']);
+    $command['sections']['topic_section'] = 'Topics';
+    $command['topic_section'][$topic_name] = $implemented[$topic_name]['description'];
   }
 }
+
 /**
  * A command callback.
  *
@@ -47,18 +50,25 @@ function topic_drush_help_alter($command) {
  * @param string $topic_name
  *   A command name.
  */
-function drush_core_topic($topic_name = NULL) {
+function drush_topic_core_topic($topic_name = NULL) {
   $commands = drush_get_commands();
   if (is_null($topic_name)) {
     // Show choice list.
     foreach (drush_get_topics() as $key => $topic) {
       $choices[$key] = $topic['description'];
     }
+    natcasesort($choices);
     if (!$topic_name = drush_choice($choices, dt('Choose a topic'), '!value (!key)')) {
       return;
     }
   }
-  return drush_do_command_redispatch($topic_name);
+  // If the topic name is not found, check for
+  // "docs-$topic_name".  This allows users to be
+  // just a bit lazy when selecting core topics by name.
+  if (!isset($commands[$topic_name]) && isset($commands["docs-$topic_name"])) {
+    $topic_name = "docs-$topic_name";
+  }
+  return drush_dispatch($commands[$topic_name]);
 }
 
 /**
@@ -72,4 +82,4 @@ function drush_get_topics() {
     }
   }
   return $topics;
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/drush/commands/core/upgrade.drush.inc b/sites/all/modules/drush/commands/core/upgrade.drush.inc
index 69b16522330191b5754c93bc588ed230fa294142..e5d43feeda1058bd48a464a26d7b3f7c4ec3ebd9 100644
--- a/sites/all/modules/drush/commands/core/upgrade.drush.inc
+++ b/sites/all/modules/drush/commands/core/upgrade.drush.inc
@@ -1,11 +1,8 @@
 <?php
-// $Id: upgrade.drush.inc,v 1.21 2010/11/04 17:27:32 weitzman Exp $
 
 /**
  * @file
  *   Refine your Drupal major version upgrade.
- *
- * @todo Upgrade to specific releases.
  */
 
 /**
@@ -15,21 +12,50 @@ function upgrade_drush_command() {
   $items = array();
 
   $items['site-upgrade'] = array(
-    'description' => "Run a major version upgrade for Drupal core and contrib modules.",
+    'description' => 'Run a major version upgrade for Drupal (e.g. Drupal 6 to Drupal 7).  A copy of the site is made, and then upgraded; the source site is not changed.',
     'drupal dependencies' => array('update'),
-    'core' => array(6), // Remove once 3.0 is released.
+    'drush dependencies' => array('sql', 'pm', 'core'),
+    'core' => array(6), // Add 7 once drush supports 7 -> 8 upgrades.
     'arguments' => array(
-      'target' => 'The name of a sitealias, which points to the destination site. root, uri, and db-url keys are required. See examples/aliases.drushrc.php for more information about creating a site alias.'),
+      'target' => "The name of a sitealias, which points to the destination site. 'root' and 'uri' keys are required; db-url is recommended. See examples/aliases.drushrc.php for more information about creating a site alias.",
+    ),
     'examples' => array(
-      'drush site-upgrade @onward' => 'Upgrade from the current site to the site specified by @onward alias.'
+      'drush site-upgrade @onward' => 'Upgrade from the current site to the site specified by @onward alias.',
     ),
     'options' => array(
       'structure-tables-key' => 'A key in the structure-tables array. @see example.drushrc.php. Defaults to \'common\'.',
       'source-dump' => 'Path to dump file. Medium or large sized sites should set this. Optional; default is to create a temporary file.',
       'db-su' => 'DB username to use when dropping and creating the target database. Optional.',
       'db-su-pw' => 'DB password to use when dropping and creating the target database. Optional.',
+      'no-cache' => 'Transfer a fresh database from source site. Otherwise, DB dump is re-used for 24 hours.',
+      'core-only' => 'Stop after upgrading Drupal core; do not download and enable new versions of the site\'s modules.',
+      'force-sites-default' => 'Forces settings.php to be written in sites/default folder, even if source settings.php is not.',
+      'replace' => 'Replace target if it already exists.  Default is to prompt.',
+      'reuse' => 'Reuse target if it already exists.  Default is to prompt.',
+      'uninstall' => 'Comma-separated list of modules to uninstall in the target database prior to upgrade.  n.b. The source site is not affected.',
     ),
     'aliases' => array('sup'),
+    'topics' => array('docs-aliases'),
+  );
+  $items['site-upgrade-prepare'] = array(
+    'description' => 'Prior to running updatedb on Drupal core, disable all contrib modules and uninstall any module the user specified should be uninstalled.  Called automatically by site-upgrade.',
+    'hidden' => TRUE,
+    'arguments' => array(
+      'modules' => 'The modules to disable.',
+    ),
+    'options' => array(
+      'uninstall' => 'Comma-separated list of modules to uninstall prior to upgrade.',
+    ),
+  );
+  $items['site-upgrade-modules'] = array(
+    'description' => 'Download, enable, and run updatedb on all contrib modules after an upgrade.  Called automatically by site-upgrade.',
+    'hidden' => TRUE,
+    'arguments' => array(
+      'modules' => 'The modules to download and enable.',
+    ),
+    'options' => array(
+      'projects' => 'The projects that must be downloaded to provide the specified module list.',
+    ),
   );
   return $items;
 }
@@ -40,92 +66,212 @@ function upgrade_drush_command() {
 function upgrade_drush_help($section) {
   switch ($section) {
     case 'drush:site-upgrade':
-      return dt("Execute a major version upgrade for Drupal core and enabled contrib modules. Command will download next version of Drupal and all available contrib modules that have releases (if not already downloaded). It prepares a settings.php for the target site, and copies the prior version's database to the target site. Finally, updatedb is run. The intent is for developers to keep re-running this command until they are satisfied with the resulting site. Run this command from within your source site (D6).");
+      return dt("Execute a major version upgrade for Drupal core and enabled contrib modules. Command will download next version of Drupal and all available contrib modules that have releases. It prepares a settings.php for the target site, and copies the prior version's database to the target site. Finally, updatedb is run. The intent is for developers to keep re-running this command until they are satisfied with the resulting site. Run this command from within your source site (D6). Note that this command uses pm-download and sql-sync internally so most options for those commands are valid here too.");
   }
 }
 
+/**
+ * Do some sanity checks to make sure that we are ready to perform an upgrade, and
+ * that the command is being called with reasonable-looking parameters.
+ */
 function drush_upgrade_site_upgrade_validate($target_key = NULL) {
   if (empty($target_key)) {
-    return drush_set_error(dt('Missing argument: target'));
+    return drush_set_error('DRUSH_UPGRADE_NO_TARGET', dt('Missing argument: target'));
   }
 
   if (!$target_alias = drush_sitealias_get_record($target_key)) {
-    return drush_set_error('Site alias not found: @target-key. See example.drushrc.inc.', array('@target-key' => $target_key));
+    return drush_set_error('DRUSH_UPGRADE_NO_TARGET', dt('Site alias not found: @target-key. See example.drushrc.php.', array('@target-key' => $target_key)));
   }
 
   if (!file_exists(dirname($target_alias['root']))) {
-    drush_set_error('Site alias root not found: @root. See example.drushrc.inc.', array('@root' => dirname($target_alias['root'])));
+    drush_set_error('DRUSH_UPGRADE_NO_TARGET', dt('Parent directory for site alias root not found: @root; this folder must exist before running site-upgrade. See example.drushrc.php.', array('@root' => dirname($target_alias['root']))));
+  }
+
+  if (realpath($target_alias['root']) == realpath(DRUPAL_ROOT)) {
+    drush_set_error('DRUSH_UPGRADE_NO_TARGET', dt('Target site alias must have a different Drupal root directory than the source site.  Both are at @root.', array('@root' => $target_alias['root'])));
   }
 }
 
 /**
- * A drush command callback.
+ * Main command hook for site-upgrade.
+ *
+ * This runs bootstrapped to the SOURCE site.
  */
 function drush_upgrade_site_upgrade($target_key) {
+  // Presume we are ready to go (n.b. some checks already performed in 'validate')
+  $ready_to_upgrade = TRUE;
+  $result = TRUE;
+  
+  // PREPARE:  Find the target version and determine the contrib projects and enabled modules installed.
+
   $source_version = drush_drupal_major_version();
   $target_version = $source_version + 1;
   $target_alias = drush_sitealias_get_record($target_key);
+  if (empty($target_alias)) {
+    return drush_set_error('DRUSH_UPGRADE_NO_TARGET', dt("Could not find target site for upgrade: !target", array("!target" => $target_key)));
+  }
+
   $destination_core = $target_alias['root'];
 
-  // Fetch target core and place as per target alias root.
-  if (!file_exists($destination_core)) {
-    drush_set_option('destination', dirname($destination_core));
-    drush_set_option('drupal-project-rename', basename($destination_core));
+  $destination_conf_path = conf_path();
+  if (drush_get_option('force-sites-default')) {
+    $destination_conf_path = 'sites/default';
+  }
 
-    // No need for version control in this command.
-    drush_set_option('version-control', 'backup');
+  // Get a list of enabled contrib extensions.
+  $values = drush_invoke_process_args('pm-list', array(), array('status'=>'enabled','no-core'=>TRUE, '#integrate' => FALSE, '#override-simulated' => TRUE));
+  if ($values['error_status'] != 0) return FALSE;
+  $contrib_extensions = array_keys($values['object']);
 
-    // TODO: get releases other than dev snapshot.
-    drush_pm_download('drupal-'. $target_version . '.x');
-    if (drush_get_error()) return -1; // Early exit if we see an error.
-  }
+  // Get a list of enabled core extensions.
+  $values = drush_invoke_process_args('pm-list', array(), array('status'=>'enabled','core'=>TRUE, '#integrate' => FALSE, '#override-simulated' => TRUE));
+  if ($values['error_status'] != 0) return FALSE;
+  $core_extensions = array_keys($values['object']);
 
-  // Get enabled projects and their paths.
-  // TODO: D5 compatibility.
-  _update_cache_clear();
-  module_load_include('inc', 'update', 'update.compare');
-  $projects = update_get_projects();
-  // We already downloaded Drupal project.
-  unset($projects['drupal']);
-  $projects = pm_get_project_path($projects, 'includes');
+  // Make a list of modules that are not available to be enabled in the target
+  // version of Drupal, either because they have not been ported yet, or because
+  // they have been rolled into core.
+  $unavailable_extensions = array();
+  
+  // Get the list of modules the user would like to uninstall (if any).
+  $uninstall_extensions = drush_get_option('uninstall', '');
+  if ($uninstall_extensions == "all") {
+    $uninstall_extensions = $contrib_extensions;
+  }
+  else {
+    $uninstall_extensions = explode(',', $uninstall_extensions);
+  }
+  
+  // WARN:  Tell the user about any special situations that might exist with contrib modules.
 
-  // Fetch and place each project into target.
-  // TODO: use non dev snapshot releases.
-  // TODO: Fix pm-download so this cancel hack is not needed.
-  drush_set_option('bootstrap_cancel', TRUE);
-  foreach ($projects as $key => $project) {
-    if (empty($project['path'])) {
-      $project['path'] = 'sites/all/modules';
+  $project_download_list = array();
+  $extension_info = drush_pm_get_extensions();
+  if (!empty($contrib_extensions) && !drush_get_option('core-only')) {
+    // Make a list of all of the extensions to download.  We will
+    // download everything in the contrib extension list, but we
+    // will skip projects that already exist.
+    $special_projects = drush_upgrade_project_map($target_version);
+    $in_core = array();
+    $special_warning = array();
+    foreach ($contrib_extensions as $extension_name) {
+      // Only check extensions that are NOT in our uninstall list.
+      if (!in_array($extension_name, $uninstall_extensions) && array_key_exists($extension_name, $extension_info)) {
+        $project = $extension_info[$extension_name]->info['project'];
+        // Check our lookup table to see if a project has been renamed.
+        if (array_key_exists($project, $special_projects['project-remap'])) {
+          $project = $special_projects['project-remap'][$project];
+        }
+        // If the module has been rolled into core in the next major release of
+        // Drupal, then we do not need to download it.  Add it to an array for
+        // reporting purposes.
+        if ((in_array($project, $special_projects['projects-in-core'])) || (in_array($extension_name, $special_projects['modules-in-core']))) {
+          $in_core[$extension_name] = $extension_name;
+          // Might some of these need to be enabled?
+          $unavailable_extensions[] = $extension_name;
+        }
+        elseif (($extension_info[$extension_name]->type == 'module') && !is_dir($destination_core . '/sites/all/modules/' . $project) && !is_dir($destination_core . '/' . $destination_conf_path . '/modules/' . $project)) {
+          $project_download_list[$project][] = $extension_name;
+        }
+        // If there is a special warning about a project, then add it 
+        // to the warning list for later reporting.
+        if (array_key_exists($project . ':' . $extension_name, $special_projects['warning'])) {
+          $special_warning[$project] = $special_projects['warning'][$project . ':' . $extension_name];
+        }
+        elseif ((array_key_exists($project, $special_projects['warning'])) && (!array_key_exists($project, $special_warning))) {
+          $special_warning[$project] = $special_projects['warning'][$project];
+        }
+      }
+    }
+    
+    // Consider each project from the contrib extensions and check with PM to see if there is
+    // a recommended release available to download.  If there is NO release available, then
+    // we are not ready to upgrade (but still can, without that project); if there is no RECOMMENDED 
+    // release, then we might not be ready to upgrade (but still can, with a non-recommended release).
+    if (!empty($project_download_list)) {
+      $result = drush_invoke_sitealias_args(array('root' => '', 'uri' => ''), 'pm-releases', array_keys($project_download_list), array('default-major' => $target_version, '#integrate' => FALSE, '#override-simulated' => TRUE));
+      $project_releases = $result['object'];
+      foreach ($project_download_list as $project => $extension_list) {
+        if (!array_key_exists($project, $project_releases)) {
+          drush_log(dt('The project !project has no releases in version !version', array('!project' => $project, '!version' => $target_version)), 'warning');
+          $unavailable_extensions = array_merge($unavailable_extensions, $extension_list);
+          $ready_to_upgrade = FALSE;
+        }
+        else {
+          if (empty($project_releases[$project]['recommended'])) {
+            drush_log(dt('The project !project has no recommended release in version !version', array('!project' => $project, '!version' => $target_version)), 'warning');
+            $ready_to_upgrade = 'maybe';
+          }
+        }
+      }
     }
-    $destination_module = $destination_core . '/' . $project['path'];
-    if (!file_exists($destination_module)) {
-      drush_set_option('destination', dirname($destination_module));
-      drush_pm_download($key . '-'. $target_version . '.x');
+    
+    // Print out some messages about projects that migrated  to core, or modules that will require special processing.
+    if (!empty($in_core)) {
+      drush_log(dt('The following contrib modules were enabled in your Drupal site, but are now standard in core: !in_core.  These modules may need to be reconfigured after the upgrade is complete.', array('!in_core' => implode(', ', $in_core))), 'ok');
+    }
+    foreach ($special_warning as $project => $warning) {
+      if ($warning === TRUE) {
+        $warning = 'Please see !project_page and !source for more information on how to do this.';
+      }
+      if ($warning === FALSE) {
+        $warning = 'So far there is no indication of when a migration path will be provided.  Check !project_page for updates.';
+        $ready_to_upgrade = 'maybe';
+      }
+      drush_log(dt("You are using the project !project, which requires data migration or other special processing.  $warning", array('!project' => $project, '!project_page' => 'http://drupal.org/project/' . $project, '!source' => $special_projects['source'])), 'warning');
     }
   }
-  if (drush_get_error()) return -1; // Early exit if we see an error.
 
-  // Create sites subdirectory in target if needed.
-  $settings_source = conf_path() . '/settings.php';
-  $settings_destination = $destination_core . '/' . $settings_source;
-  $settings_destination_folder = dirname($settings_destination);
-  if (!file_exists($settings_destination_folder)) {
-    if (!drush_op('mkdir', $settings_destination_folder) && !drush_get_context('DRUSH_SIMULATE')) {
-      drush_set_error(dt('Failed to create directory @settings_destination', array('@settings_destination' => $settings_destination_folder)));
-      return;
+  // CONFIRM:  Ask the user before overwriting an exsiting site, and ask if an upgrade is really decided if the site is not ready yet.
+
+  // Summarize whether or not there is a good chance that the site can be upgraded.
+  if ($ready_to_upgrade !== TRUE) {
+    drush_log(dt("Based on the contrib modules enabled in this site, it is possible that the site-upgrade command might fail.  See warnings above."), (($ready_to_upgrade === FALSE) ? 'warning' : 'notice'));
+  }
+  // Check to see what we should do if the target Drupal folder already exists.
+  $options = array(
+    'replace' => dt("Delete the existing site and start over."),
+    'reuse' => dt("Re-use the existing code, re-import the database from the source site and run updatedb again."),
+  );
+  $selection = NULL;
+  foreach ($options as $option => $msg) {
+    if (drush_get_option($option, FALSE)) {
+      $selection = $option;
     }
   }
-
-  // Copy settings.php to target.
-  if (!file_exists($settings_destination)) {
-    if (!drush_op('copy', $settings_source, $settings_destination) && !drush_get_context('DRUSH_SIMULATE')) {
-      drush_set_error(dt('Failed to copy @source to  @dest', array('@source' => $settings_source, 'dest' => $settings_destination)));
-      return;
+  if (!isset($selection) && (file_exists($destination_core))) {
+    $selection = drush_choice($options, dt("Drupal site already exists at !root.  Would you like to:", array('!root' => $destination_core)));
+    if (!$selection) {
+      return drush_user_abort();
+    }
+  }
+  elseif($ready_to_upgrade !== TRUE) {
+    if (!drush_confirm('Would you like to continue anyway?')) {
+      return drush_user_abort();
     }
   }
 
-  // Append new $db_url with new DB name in target's settings.php.
-  drush_upgrade_fix_db_url($target_alias, $settings_destination);
+  // User has already been prompted; skip further confirms.
+  drush_set_context('DRUSH_AFFIRMATIVE', TRUE);
+  
+  // We need to know where our destination settings file is regardless of which
+  // code path we take; therefore, we will precompute it here.
+  
+  $settings_destination = $destination_core . '/' . $destination_conf_path . '/settings.php';
+  
+  // STEP 1:  Download the next major version of Drupal.
+
+  if (($selection == 'replace') || (!is_dir($destination_core))) {
+    drush_upgrade_download_drupal($target_version, $destination_core);
+    if (drush_get_error()) return FALSE; // Early exit if we see an error.
+    drush_upgrade_copy_settings($target_alias, $settings_destination);
+  }
+  else {
+    // Move sites/all/modules and $conf_path()/modules out of the way
+    // so that updatedb can be run on core only.
+    if (_drush_upgrade_preserve_modules($destination_core) === FALSE) {
+      return FALSE;
+    }
+  }
 
   // Copy source database to target database. The source DB is not changed.
   // Always set 'common' at minimum. Sites that want other can create other key in drushrc.php.
@@ -133,32 +279,425 @@ function drush_upgrade_site_upgrade($target_key) {
     drush_set_option('structure-tables-key', 'common');
   }
   // Always blow away the target database so we start fresh.
+  // We still have DRUSH_AFFIRMATIVE set from above, so this will not prompt.
   drush_set_option('create-db', TRUE);
   drush_include(DRUSH_BASE_PATH . '/commands/sql', 'sync.sql');
-  drush_invoke('sql_sync', '@self', $target_key);
-  if (drush_get_error()) return -1; // Early exit if we see an error.
+  drush_invoke('sql-sync', '@self', $target_key);
+  if (drush_get_error()) return FALSE; // Early exit if we see an error.
+
+  if (!empty($contrib_extensions)) {
+    $target_alias_databases = sitealias_get_databases_from_record($target_alias);
+    $modify_site_conf_path = NULL;
+
+    // Make an alias record that uses the CODE from @self and the DATABASE from $target.
+    // Since we just did an sql-sync from @self to @target, we can use this hybrid specification
+    // to do manipulations on the target database before runing updatedb.  In brief, we are going
+    // to disable all contrib modules to prevent problems with updatedb.
+    $modify_site = array (
+      'root' => DRUPAL_ROOT,
+      'uri' => $target_alias_databases['default']['default']['database'],
+    );
+    
+    if (!drush_get_context('DRUSH_SIMULATE')) {
+      // In theory, if the sql-sync worked, this should never be empty.
+      if (empty($modify_site['uri'])) {
+        return drush_set_error('DRUSH_UPGRADE_DATABASE_SPEC_UNKNOWN', dt('Failed to look up database spec for @target', array('@target' => $target_key)));
+      }
+      $modify_site_conf_path = dirname(conf_path()) . '/' . $modify_site['uri'];
+      $modify_site_settings = $modify_site_conf_path . '/settings.php';
+      drush_log('set up a fake site by copying ' . $settings_destination . ' to ' . $modify_site_settings);
+      if (!file_exists($modify_site_settings)) {
+        if ((drush_mkdir($modify_site_conf_path) === FALSE) || drush_op('copy', $settings_destination, $modify_site_settings) !== TRUE) {
+          return drush_set_error('DRUSH_UPGRADE_COULD_NOT_DISABLE', dt("Could not create a temporary multisite "));
+        }
+      }
+    }
+    $result = (drush_invoke_sitealias_args($modify_site, 'site-upgrade-prepare', $contrib_extensions, array('uninstall' => implode(',', $uninstall_extensions), 'yes' => TRUE, '#interactive' => TRUE)) == 0);
+
+    // Delete the temporary site now that we're done with it.
+    if (isset($modify_site_conf_path)) {
+      drush_delete_dir($modify_site_conf_path);
+    }
+    if ($result === FALSE) return FALSE;
+  }
+
+  // STEP 2:  Call updatedb for Drupal core.
 
   // Run update.php in a subshell. It is run on @target site whereas this request was on @self.
-  drush_do_site_command($target_alias, 'updatedb', array(), array(), TRUE);
+  drush_log(dt('About to perform updatedb for Drupal core on !target', array('!target' => $target_key)), 'ok');
+  // When we call drush_invoke_sitealias_args in #interactive mode, the result code comes from drush_op_system, where 0 == success.
+  $result = drush_invoke_sitealias_args($target_alias, 'updatedb', array(), array('yes' => TRUE, '#interactive' => TRUE)) == 0;
+  if ($result === FALSE) {
+    return drush_set_error('DRUSH_DRUPAL_CORE_UPGRADE_FAILED', dt("The call to updatedb failed for Drupal core.  This may be caused by a contrib module that is not yet ready for upgrade.  Try running site-upgrade again with '--uninstall={module list}' to remove all contrib extensions prior to upgrade.  Add modules back in until the problematic one is isolated.  Please report problems in the issue queue of the module that is causing problems."));
+  }
+  drush_log(dt('updatedb complete for Drupal core'), 'ok');
+
+  // If we moved our modules out of the way, bring them back now.
+  _drush_upgrade_restore_preserved_modules();
+
+  // STEP 3: Download and re-enable the contrib modules.
+
+  if (!empty($contrib_extensions) && !drush_get_option('core-only')) {
+    $options = array('#interactive' => TRUE);
+    if (!empty($project_download_list)) {
+      $projects = implode(',', array_keys($project_download_list));
+      $options['projects'] = $projects;
+    }
+    // If a module changed name, then rename it prior to calling pm-enable.
+    foreach ($contrib_extensions as $extension_name) {
+      if (array_key_exists($extension_name, $special_projects['module-remap'])) {
+        $unavailable_extensions[] = $extension_name;
+        $contrib_extensions[] = $special_projects['module-remap'][$extension_name];
+      }
+    }
+    
+    // Redispatch to site-upgrade-modules command, so that we will be
+    // bootstrapped to the target site.
+    $result = (drush_invoke_sitealias_args($target_alias, 'site-upgrade-modules', array_merge($core_extensions, array_diff($contrib_extensions, $unavailable_extensions, $uninstall_extensions)), $options) == 0);
+  }
+  
+  return $result;
+}
+
+/**
+ * http://drupal.org/node/895314 lists projects that are now in
+ * core; it also has a list of projects that require special handling.
+ * Keep a record here too.
+ *
+ * @param $target_version 
+ * The version of Drupal being upgraded to.
+ * @return @array
+ *   - source              URL to the page where more information about this upgrade can be found.
+ *   - target-version      The version of Drupal being upgraded to.
+ *   - projects-in-core    An array containing projects that were once contrib that are now in core.
+ *   - modules-in-core     An array containing modules that were once in contrib that are now in core.
+ *                         Use 'modules-in-core' in place of 'projects-in-core' only if there is a
+ *                         project where only some of its subcomponents were moved to core.
+ *   - warning             An array of warning messages to display to the user related to this upgrade.
+ *                         The key should be the name of the project that the warning applies to.
+ *                         use 'project:module' as the key if the warning only applies when the given
+ *                         module in the project is enabled; otherwise, the warning will be shown whenever
+ *                         any module in the specific project is enabled.  The value can either be the
+ *                         warning string to display, or TRUE to tell the user to see the project page
+ *                         for information on the migration path, or FALSE to tell the user that there
+ *                         currently is no migration path for the given project.
+ */
+function drush_upgrade_project_map($target_version) {
+  $result = array(
+    'source' => '',
+    'target-version' => $target_version,
+    'projects-in-core' => array(),
+    'modules-in-core' => array(),
+    'warning' => array(),
+  );
+  if ($target_version == 7) {
+    $result = array(
+      'source' => 'http://drupal.org/node/895314',
+      'projects-in-core' => array(
+        'abssrc',
+        'admin_hover',
+        'adminrole',
+        'ahah_helper',
+        'autoload',
+        'automaticmenu',
+        'automenu',
+        'auto_menutitle',
+        'block_edit',
+        'block_node_visibility',
+        'blocks404',
+        'canonical_url',
+        'checkbox_validate',
+        'comment_display',
+        'config_perms',
+        'ctm',
+        'dbtng',
+        'documentation',
+        'drupal_queue',
+        'edit_term',
+        'elements',
+        'element_themehook',
+        'filefield',
+        'filter_default',
+        'hook_file',
+        'imageapi',
+        'imagecache',
+        'imagefield',
+        'input_format_permissions',
+        'jq',
+        'jqp',
+        'jquery_cookie',
+        'jquery_form_update',
+        'jquery_ui',
+        'jsalter',
+        'login_security',
+        'menuless_nodetype',
+        'nodepreview_by_type',
+        'parallel',
+        'permissions_api',
+        'phpass',
+        'plugin_manager',
+        'plugins',
+        'poormanscron',
+        'preview',
+        'rdf',
+        'shortlink',
+        'simplecdn',
+        'simpletest',
+        'storage_api',
+        'tar',
+        'taxidermy',
+        'tinymce_ahah',
+        'tinymce_dragdrop',
+        'transaction',
+        'upload_element',
+        'upload_preview',
+        'url_alter',
+        'user_cancellation',
+        'user_default_filter',
+        'user_delete',
+        'vertical_tabs',
+        'view_unpublished',
+        'vocabperms',
+        'wysiwygcck',
+      ),
+      'modules-in-core' => array(
+        // 'date' project is still contrib, but date_timezone, one of its modules, has moved to core. See http://drupal.org/node/868028.
+        'date_timezone',
+      ),
+      'project-remap' => array(),
+      'module-remap' => array(
+        'content' => 'cck',
+      ),
+      'warning' => array(
+        'token' => dt('In Drupal 7, the contrib token module handles UI, as well as field and profile tokens; all other functionality has been migrated to core.'),
+        'cck' => TRUE,
+        'content_taxonomy' => dt('The project page for this module (!project_page) says that an upgrade path will be provided for this module at a future time.'),
+        'date:date_api' => dt("The d6 version of the date_api module in the date project defines a table called date_formats, which is also defined by system/system.install schema in d7.  If this problem has not been fixed yet, then the updatedb function will fail, and it will not be possible to upgrade to d7.  If this happens, disable and uninstall the date_api module before running site-upgrade (i.e. add '--uninstall=date_api' to site-upgrade call).  See http://drupal.org/node/1013034."),
+        'field_taxonomy' => FALSE,
+        'filefield' => dt('Data migration for this module will be provided by the Content Migrate submodule of cck.  Enable content_migrate after upgrading; see http://drupal.org/node/781088.'),
+        'imagefield' => dt('Data migration for this module will be provided by the Content Migrate submodule of cck.  Enable content_migrate after upgrading; see http://drupal.org/node/781088.'),
+        'taxonomy_delegate' => FALSE,
+        'taxonomy_intro' => FALSE,
+        'term_fields' => FALSE,
+      ),
+    );
+  }
+  drush_command_invoke_all_ref('drush_upgrade_project_map_alter', $result);
+
+  return $result;
+}
+
+/**
+ * Prepare to upgrade; the first step is to disable all contrib modules.
+ */
+function drush_upgrade_site_upgrade_prepare() {
+  $contrib_extensions = func_get_args();
+  $uninstall_extensions = explode(',', drush_get_option('uninstall', ''));
+
+  // Set theme back to garland per Upgrade.txt.
+  variable_set('theme_default', 'garland');
+
+  // http://drupal.org/node/724102 recommends using "seven" as your admin theme.  Don't switch it to garland if it is already seven.
+  $admin_theme = variable_get('admin_theme', NULL);
+  if ($admin_theme != "seven") {
+    variable_set('admin_theme', 'garland');
+  }
+  else {
+    drush_log(dt("Admin theme is already set to 'seven'."), 'ok');
+  }
+
+  // Disable all contrib modules per Upgrade.txt.
+  drush_log(dt("Disabling !list", array('!list' => implode(", ", $contrib_extensions))), 'ok');
+  call_user_func_array('drush_pm_disable', $contrib_extensions);
+  if (drush_get_error()) return FALSE; // Early exit if we see an error.
+
+  // Uninstall any modules specified via the --uninstall flag.
+  if (!empty($uninstall_extensions)) {
+    drush_log(dt("Uninstalling !list", array('!list' => implode(", ", $uninstall_extensions))), 'ok');
+    call_user_func_array('drush_pm_uninstall', $uninstall_extensions);
+    if (drush_get_error()) return FALSE; // Early exit if we see an error.
+  }
+}
+
+/**
+ * Upgrade all of the contrib modules of the site being upgraded.
+ *
+ * This runs bootstrapped to the TARGET site, after the new version
+ * of Drupal has been downloaded, and after updatedb has been run
+ * for Drupal core.
+ */
+function drush_upgrade_site_upgrade_modules() {
+  $extensions_to_enable = func_get_args();
+  $project_download_list = drush_get_option('projects', '');
+  
+  if (!empty($project_download_list)) {
+    // Download our contrib extensions.
+    drush_log(dt('Download projects: !projects', array('!projects' => $project_download_list)), 'ok');
+    drush_set_option('destination', NULL);
+    // User has already been prompted; if there is no recommended release,
+    // we will just take the most recent.
+    drush_set_option('choice', '1');
+    call_user_func_array('drush_pm_download', explode(',', $project_download_list));
+  }
+  
+  // Run updatedb to update all of the contrib extensions.
+  drush_log(dt('About to perform updatedb for extensions'), 'ok');
+  $result = drush_invoke_process_args('updatedb', array(), array('yes' => TRUE, '#interactive' => TRUE));
+  if ($result === FALSE) {
+    return drush_set_error('DRUSH_DRUPAL_CONTRIB_UPGRADE_FAILED', dt("The call to updatedb failed for the enabled contrib modules.  Try running site-upgrade again with '--uninstall={module list}' to remove all contrib extensions prior to upgrade.  Add modules back in until the problematic one is isolated.  Please report problems in the issue queue of the module that is causing problems."));
+  }
+  drush_log(dt('updatedb complete for extensions'), 'ok');
+
+  // Finally, enable the modules that site-upgrade previously disabled.
+  // We will set the option --resolve-dependencies to pick up new modules
+  // that may now be required; for example, views-7.x picked up a dependency
+  // on ctools that views-6.x did not have.  We also set DRUSH_AFFIRMATIVE,
+  // so everything from here on out will be processed with --yes.
+  drush_set_option('resolve-dependencies', TRUE);
+  drush_set_context('DRUSH_AFFIRMATIVE', TRUE);
+  $result = drush_invoke_args('pm-enable', $extensions_to_enable);
+  
+  return $result;
+}
+
+/**
+ * Download the upgraded version of Drupal for site-upgrade.
+ */
+function drush_upgrade_download_drupal($target_version, $destination_core) {
+  // Fetch target core and place as per target alias root.
+  drush_set_option('destination', dirname($destination_core));
+  drush_set_option('drupal-project-rename', basename($destination_core));
+
+  // No need for version control in this command.
+  drush_set_option('version-control', 'backup');
+
+  if (drush_get_context('DRUSH_SIMULATE')) {
+    drush_log(dt("Simulated download of drupal-!version", array('!version' => $target_version)));
+  }
+  else {
+    drush_pm_download('drupal-' . $target_version);
+    if (drush_get_error()) return FALSE; // Early exit if we see an error.
+
+    // Check and see if there is a Drupal site at the target.
+    if (!file_exists($destination_core . '/includes/bootstrap.inc')) {
+      return drush_set_error('DRUSH_UPGRADE_NO_DRUPAL', dt('Drupal could not be downloaded to the target directory, @root.  Move existing content out of the way first.', array('@root' => $target_alias['root'])));
+    }
+  }
+}
+
+/**
+ * Copy the settings.php file from the source site to the target site,
+ * and fix it up so that it will have its own database settings.
+ */
+function drush_upgrade_copy_settings(&$target_alias, $settings_destination) {
+  $settings_destination_folder = dirname($settings_destination);
+
+  // Create sites subdirectory in target if needed.
+  $settings_source = conf_path() . '/settings.php';
+  if (!file_exists($settings_destination_folder)) {
+    if (!drush_op('mkdir', $settings_destination_folder) && !drush_get_context('DRUSH_SIMULATE')) {
+      return drush_set_error('DRUSH_UPGRADE_MKDIR_FAILED', dt('Failed to create directory @settings_destination', array('@settings_destination' => $settings_destination_folder)));
+    }
+  }
+
+  // Copy settings.php to target.
+  if (!file_exists($settings_destination)) {
+    if (!drush_op('copy', $settings_source, $settings_destination) && !drush_get_context('DRUSH_SIMULATE')) {
+      return drush_set_error('DRUSH_UPGRADE_COPY_FAILED', dt('Failed to copy @source to  @dest', array('@source' => $settings_source, 'dest' => $settings_destination)));
+    }
+  }
+  // Append new $db_url with new DB name in target's settings.php.
+  return drush_upgrade_fix_db_url($target_alias, $settings_destination);
 }
 
-// Replace db_url with DB name from target. updatedb will later append a DBTNG compatible version.
-function drush_upgrade_fix_db_url($target_alias, $settings_destination) {
+/**
+ * Replace db_url with DB name from target. updatedb will later append a DBTNG compatible version.
+ */
+function drush_upgrade_fix_db_url(&$target_alias, $settings_destination) {
   $old_url = $GLOBALS['db_url'];
   if (is_array($old_url)) {
     $old_url = $old_url['default'];
   }
+  $old_databases = $GLOBALS['databases'];
+  if (empty($old_databases)) {
+    $old_databases = drush_sitealias_convert_db_from_db_url($old_url);
+  }
+
   $target_alias_databases = sitealias_get_databases_from_record($target_alias);
-  $new_url = substr($old_url, 0, strrpos(trim($old_url), '/')) . '/'. $target_alias_databases['default']['default']['database'];
+  $database_name = $target_alias_databases['default']['default']['database'];
+  if (empty($database_name)) {
+    $database_name = str_replace("@", "", $target_alias['name']) . "db";
+    drush_log(dt("No database name specified; defaulting to !dbname", array("!dbname" => $database_name)), 'notice');
+  }
 
   $append = "\n# Added by drush site-upgrade.";
   if (drush_drupal_major_version() <= 6) {
+    $new_url = substr($old_url, 0, strrpos(trim($old_url), '/')) . '/'. $database_name;
     $append .= "\n" . '$db_url = \'' . $new_url . '\';';
+    $databases = drush_sitealias_convert_db_from_db_url($new_url);
   }
   else {
     $databases = $GLOBALS['databases'];
     $databases['default']['default']['database'] = $target_alias_databases['default']['default']['database'];
     $append .= "\n" . '$databases = ' . var_export($databases, TRUE) . ';';
   }
+  // Caching the database record in the alias record allows sql-sync to work
+  // before updatedb is called. updatedb is what converts from a db_url to a
+  // DBTNG array; this conversion is required by sql-sync.
+  drush_sitealias_cache_db_settings($target_alias, $databases);
+
+  // Also append the new configuration options to the end of settings.php.
   drush_op('file_put_contents', $settings_destination, $append, FILE_APPEND);
 }
+
+/**
+ * Rollback function: restore our modules if updatedb fails.
+ */
+function drush_upgrade_site_upgrade_rollback($target_key) {
+  _drush_upgrade_restore_preserved_modules();
+}
+
+/**
+ * Preserve existing modules.  Move them out of the way prior
+ * to updatedb of Drupal core.  We will move them back afterwards.
+ */
+function _drush_upgrade_preserve_modules($destination_core) {
+  $modules_preserve['root'] = $destination_core;
+  $modules_preserve['list'] = array();
+  
+  $moduledir_list = array(
+    'sites_all_modules' => $destination_core . '/sites/all/modules',
+    'sites_conf_path_modules' => $destination_core . conf_path() . '/modules',
+  );
+  
+  foreach ($moduledir_list as $moduledir_name => $moduledir) {
+    if (is_dir($moduledir)) {
+      $preserved_moduledir = drush_tempnam($moduledir_name, dirname($moduledir));
+      $result = drush_move_dir($moduledir, $preserved_moduledir, TRUE);
+      if ($result) {
+        $modules_preserve['list'][$moduledir] = $preserved_moduledir;
+        drush_log(dt('Move !src to !dest prior to updatedb on Drupal core.', array('!src' => $moduledir, '!dest' => $preserved_moduledir)), 'ok');
+      }
+      else {
+        return drush_set_error('DRUSH_MODULE_PRESERVE_FAILED', dt('Failed to move !src to !dest.', array('!src' => $moduledir, '!dest' => $preserved_moduledir)));
+      }
+    }
+  }
+  
+  drush_set_context('DRUSH_MODULES_PRESERVE', $modules_preserve);
+  return TRUE;
+}
+
+/**
+ * Restore modules that were preserved by _drush_upgrade_preserve_modules.
+ */
+function _drush_upgrade_restore_preserved_modules() {
+  $modules_preserve = drush_get_context('DRUSH_MODULES_PRESERVE', array());
+  
+  if (!empty($modules_preserve) && array_key_exists('list', $modules_preserve)) {
+    foreach ($modules_preserve['list'] as $moduledir => $preserved_moduledir) {
+      drush_move_dir($preserved_moduledir, $moduledir, TRUE);
+    }
+  }
+  drush_set_context('DRUSH_MODULES_PRESERVE', array());
+}
diff --git a/sites/all/modules/drush/commands/core/variable.drush.inc b/sites/all/modules/drush/commands/core/variable.drush.inc
index efe8a065d61ba77f5e27e54c4872ee96521111eb..31d3c11a0f5b86ffec80295f9a1ded56365d8d49 100644
--- a/sites/all/modules/drush/commands/core/variable.drush.inc
+++ b/sites/all/modules/drush/commands/core/variable.drush.inc
@@ -1,29 +1,4 @@
 <?php
-// $Id: variable.drush.inc,v 1.20 2010/11/27 02:22:21 weitzman Exp $
-
-/**
- * Implementation of hook_drush_help().
- *
- * This function is called whenever a drush user calls
- * 'drush help <name-of-your-command>'
- *
- * @param
- *   A string with the help section (prepend with 'drush:')
- *
- * @return
- *   A string with the help text for your command.
- */
-function variable_drush_help($section) {
-  switch ($section) {
-    case 'drush:variable-get':
-      return dt("Lists the variables for your site");
-    case 'drush:variable-set':
-      return dt("Set a variable");
-    case 'drush:variable-delete':
-      return dt("Delete a variable.");
-  }
-}
-
 
 /**
  * Implementation of hook_drush_command().
@@ -49,7 +24,7 @@ function variable_drush_command() {
       'drush vget user' => 'List all variables beginning with the string "user".',
     ),
     'options' => array(
-      '--pipe' => 'Use var_export() to emit executable PHP. Useful for pasting into code.',
+      'pipe' => 'Use var_export() to emit executable PHP. Useful for pasting into code.',
     ),
     'aliases' => array('vget'),
   );
@@ -60,8 +35,8 @@ function variable_drush_command() {
       'value' => 'The value to assign to the variable.',
     ),
     'options' => array(
-      '--yes' => 'Skip confirmation if only one variable name matches.',
-      '--always-set' => 'Always skip confirmation.',
+      'yes' => 'Skip confirmation if only one variable name matches.',
+      'always-set' => 'Always skip confirmation.',
     ),
     'examples' => array(
       'drush vset --yes preprocess_css 1' => 'Set the preprocess_css variable to true. Skip confirmation if variable already exists.',
@@ -76,7 +51,7 @@ function variable_drush_command() {
       'name' => 'The name of a variable or the first few letters of its name.',
     ),
     'options' => array(
-      '--yes' => 'Skip confirmation if only one variable name matches.',
+      'yes' => 'Skip confirmation if only one variable name matches.',
     ),
     'examples' => array(
       'drush vdel user_pictures' => 'Delete the user_pictures variable.',
diff --git a/sites/all/modules/drush/commands/core/watchdog.drush.inc b/sites/all/modules/drush/commands/core/watchdog.drush.inc
index bdc32c0c0b202c1ee127a233278d1b18dd826eb5..c34bfb741fdfd3e22dd74b805b0541f695bbfcb8 100644
--- a/sites/all/modules/drush/commands/core/watchdog.drush.inc
+++ b/sites/all/modules/drush/commands/core/watchdog.drush.inc
@@ -30,11 +30,11 @@ function watchdog_drush_command() {
       'wid' => 'Optional id of a watchdog message to show in detail. If not provided, a listing of most recent 10 messages will be displayed. Alternatively if a string is provided, watchdog messages will be filtered by it.',
     ),
     'options' => array(
-      '--count' => 'The number of messages to show. Defaults to 10.',
-      '--severity' => 'Restrict to messages of a given severity level.',
-      '--type' => 'Restrict to messages of a given type.',
-      '--tail' => 'Continuously show new watchdog messages until interrupted.',
-      '--sleep-delay' => 'To be used in conjunction with --tail. This is the number of seconds to wait between each poll to the database. Delay is 1 second by default.'
+      'count' => 'The number of messages to show. Defaults to 10.',
+      'severity' => 'Restrict to messages of a given severity level.',
+      'type' => 'Restrict to messages of a given type.',
+      'tail' => 'Continuously show new watchdog messages until interrupted.',
+      'sleep-delay' => 'To be used in conjunction with --tail. This is the number of seconds to wait between each poll to the database. Delay is 1 second by default.'
     ),
     'examples' => array(
       'drush watchdog-show' => 'Show a listing of most recent 10 messages.',
@@ -52,8 +52,8 @@ function watchdog_drush_command() {
     'description' => 'Delete watchdog messages.',
     'drupal dependencies' => drush_drupal_major_version() >= 6 ? array('dblog') : array('watchdog'),
     'arguments' => array(
-      '--severity' => 'Delete messages of a given severity level.',
-      '--type' => 'Delete messages of a given type.',
+      'severity' => 'Delete messages of a given severity level.',
+      'type' => 'Delete messages of a given type.',
     ),
     'examples' => array(
       'drush watchdog-delete all' => 'Delete all messages.',
@@ -85,7 +85,7 @@ function drush_core_watchdog_list() {
   }
   $option = drush_choice($options, dt('Select a message type or severity level.'));
   if ($option === FALSE) {
-    return drush_log(dt('Aborting.'));
+    return drush_user_abort();
   }
   $ntypes = count($types);
   if ($option < $ntypes) {
@@ -263,7 +263,7 @@ function drush_core_watchdog_delete($arg = NULL) {
   if ($arg == 'all') {
     drush_print(dt('All watchdog messages will be deleted.'));
     if (!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
     drush_db_delete('watchdog');
     drush_log(dt('All watchdog messages have been deleted.'), 'ok');
@@ -271,7 +271,7 @@ function drush_core_watchdog_delete($arg = NULL) {
   else if (is_numeric($arg)) {
     drush_print(dt('Watchdog message #!wid will be deleted.', array('!wid' => $arg)));
     if(!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
     $affected_rows = drush_db_delete('watchdog', 'wid=:wid', array(':wid' => $arg));
     if ($affected_rows == 1) {
@@ -289,11 +289,12 @@ function drush_core_watchdog_delete($arg = NULL) {
     }
     $where = core_watchdog_query($type, $severity, $arg, 'OR');
     if ($where === FALSE) {
-      return drush_log(dt('Aborting.'), 'error');
+      // Drush set error was already called by core_watchdog_query
+      return FALSE;
     }
     drush_print(dt('All messages with !where will be deleted.', array('!where' => preg_replace("/message LIKE %$arg%/", "message body containing '$arg'" , strtr($where['where'], $where['args'])))));
     if(!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
     $affected_rows = drush_db_delete('watchdog', $where['where'], $where['args']);
     drush_log(dt('!affected_rows watchdog messages have been deleted.', array('!affected_rows' => $affected_rows)), 'ok');
@@ -321,7 +322,7 @@ function core_watchdog_query($type = NULL, $severity = NULL, $filter = NULL, $cr
     $types = core_watchdog_message_types();
     if (array_search($type, $types) === FALSE) {
       $msg = "Unrecognized message type: !type.\nRecognized types are: !types.";
-      return drush_set_error(dt($msg, array('!type' => $type, '!types' => implode(', ', $types))));
+      return drush_set_error('WATCHDOG_UNRECOGNIZED_TYPE', dt($msg, array('!type' => $type, '!types' => implode(', ', $types))));
     }
     $conditions[] = "type = :type";
     $args[':type'] = $type;
diff --git a/sites/all/modules/drush/commands/pm/package_handler/cvs.inc b/sites/all/modules/drush/commands/pm/package_handler/cvs.inc
index 10b136da1de7a4eae31326ec4960e156e97cb76d..f81856778cdccf09c0bebd1aa8733797e413d75a 100644
--- a/sites/all/modules/drush/commands/pm/package_handler/cvs.inc
+++ b/sites/all/modules/drush/commands/pm/package_handler/cvs.inc
@@ -1,17 +1,36 @@
 <?php
-// $Id: cvs.inc,v 1.21 2010/10/13 19:48:58 jonhattan Exp $
 
 /**
  * @file Drush PM CVS extension
  */
 
+/**
+ * Validate this package handler can run.
+ */
+function package_handler_validate() {
+  // Check cvs command exists. Disable possible output.
+  $debug = drush_get_context('DRUSH_DEBUG');
+  drush_set_context('DRUSH_DEBUG', FALSE);
+  $success = drush_shell_exec('cvs --version');
+  drush_set_context('DRUSH_DEBUG', $debug);
+  if (!$success) {
+    return drush_set_error('DRUSH_SHELL_COMMAND_NOT_FOUND', dt('cvs executable not found.'));
+  }
+  // Check cvs_deploy is enabled. Only for bootstrapped sites.
+  if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) {
+    if (!module_exists('cvs_deploy')) {
+      drush_log(dt('cvs package handler needs cvs_deploy module enabled to work properly.'), 'warning');
+    }
+  }
+}
+
 /**
  * Install a project.
  *
  * @param $project The project array with name, base and full (final) paths.
  * @param $release The release details array from drupal.org
  */
-function package_handler_install_project($project, $release) {
+function package_handler_download_project(&$project, $release) {
   // Check it out.
   drush_pm_cvs($project, $release);
 
@@ -21,8 +40,7 @@ function package_handler_install_project($project, $release) {
       return TRUE;
     }
     else {
-      drush_set_error('DRUSH_PM_CVS_CHECKOUT_PROBLEMS', dt("Unable to check out !project to !destination from cvs.drupal.org", array('!project' => $project['name'], '!destination' => $project['full_project_path'])));
-      return FALSE;
+      return drush_set_error('DRUSH_PM_CVS_CHECKOUT_PROBLEMS', dt("Unable to check out !project to !destination from cvs.drupal.org", array('!project' => $project['name'], '!destination' => $project['full_project_path'])));
     }
   }
 }
@@ -33,7 +51,7 @@ function package_handler_install_project($project, $release) {
  * @param $project The project array with name, base and full (final) paths.
  * @param $release The release details array from drupal.org
  */
-function package_handler_update_project($project, $release) {
+function package_handler_update_project(&$project, $release) {
   drush_log('Updating project ' . $project['name'] . ' ...');
 
   // Check out a fresh copy, or update an existing one.
@@ -54,7 +72,7 @@ function package_handler_update_project($project, $release) {
  * @param $project The project array with name, base and full (final) paths.
  * @param $release The release details array from drupal.org
  */
-function drush_pm_cvs($project, $release) {
+function drush_pm_cvs(&$project, $release) {
   // Build the cvs command to execute.
   $command = array('cvs');
 
@@ -95,17 +113,19 @@ function drush_pm_cvs($project, $release) {
   }
   else {
     if ($cvsparams === FALSE) {
-      // By default we update overwriting changes, however if we have
-      // an existing CVS checkout that is version controlled then the
-      // default is to update in place, which will attempt to merge changes
-      // but we assume anyone using SVN is competent enough to deal with this!
-      // TODO: Make this work with BZR etc.
-      if (!file_exists($project['full_project_path'] . '/.svn')) {
-        $command[] = '-dPC';
-      }
-      else {
-        $command[] = '-dP';
+      // By default we update overwriting changes, however if we have an
+      // existing CVS checkout that is version controlled then the default is
+      // to update in place, which will attempt to merge changes but we assume
+      // anyone using a VCS is competent enough to deal with this!
+      $reserved_files = drush_version_control_reserved_files();
+      $overwrite = TRUE;
+      foreach ($reserved_files as $file) {
+        if (file_exists($project['full_project_path'] . '/' . $file)) {
+          $overwrite = FALSE;
+          break;
+        }
       }
+      $command[] = $overwrite?'-dPC':'-dP';
     }
     // Directory to work on.
     $command[] = $project['project_dir'];
@@ -114,6 +134,15 @@ function drush_pm_cvs($project, $release) {
   // CVS only accepts relative paths. We will cd in the checkout path right
   // before running the cvs command.
   if (!drush_shell_cd_and_exec($project['base_project_path'], implode(' ', $command))) {
-    drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to checkout ' . $project['name'] . ' from cvs.drupal.org.');
+    return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', dt('Unable to !op !project from cvs.drupal.org.', array('!op' => $cvsmethod, '!project' => $project['name'])));
   }
 }
+
+/**
+ * Post download action.
+ *
+ * This action take place once the project is placed in its final location.
+ */
+function package_handler_post_download($project) {
+}
+
diff --git a/sites/all/modules/drush/commands/pm/package_handler/git_drupalorg.inc b/sites/all/modules/drush/commands/pm/package_handler/git_drupalorg.inc
index fd294187b4f9fcb97dfeff35f1e7a16a5decfe62..062bea146dca3dbe1c04803a60035ea9f4679abc 100644
--- a/sites/all/modules/drush/commands/pm/package_handler/git_drupalorg.inc
+++ b/sites/all/modules/drush/commands/pm/package_handler/git_drupalorg.inc
@@ -1,117 +1,191 @@
 <?php
-// $Id: git_drupalorg.inc,v 1.2 2010/11/29 13:52:59 weitzman Exp $
 
 /**
  * @file Drush PM drupal.org Git extension.
  */
 
 /**
- * Install a project.
- *
- * @param $project The project array with name, base and full (final) paths.
- * @param $release The release details array from drupal.org
+ * Validate this package handler can run.
  */
-function package_handler_install_project($project, $release) {
-  drush_log('Downloading project ' . $project['name'] . ' ...');
-
-  $project_name = strtok($project['name'], ' ');
-
-  if (isset($release['version_extra']) && $release['version_extra'] == 'dev') {
-    // Use the development repository, not supported yet.
-    $repository = 'git://git.drupal.org/project/' . $project_name . '.git';
-    $tag = $release['tag'];
+function package_handler_validate() {
+  // Check git command exists. Disable possible output.
+  $debug = drush_get_context('DRUSH_DEBUG');
+  drush_set_context('DRUSH_DEBUG', FALSE);
+  $success = drush_shell_exec('git --version');
+  drush_set_context('DRUSH_DEBUG', $debug);
+  if (!$success) {
+    return drush_set_error('DRUSH_SHELL_COMMAND_NOT_FOUND', dt('git executable not found.'));
   }
-  else {
-    // Use a stable repository.
-    $repository = 'git://git.drupal.org/contributions-stable/' . $project_name . '.git';
-    $tag = $release['version'];
+  // Check git_deploy is enabled. Only for bootstrapped sites.
+  if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) {
+    if (!module_exists('git_deploy')) {
+      drush_log(dt('git package handler needs git_deploy module enabled to work properly.'), 'warning');
+    }
   }
-
-  // Determine if we're going to init using submodules or not, as our logic
-  // branches as a result
-  $submodule = drush_get_option('gitsubmodule', FALSE);
-  $function = 'package_handler_install_project_gitdo_' . ($submodule ? 'submodule' : 'normal');
-  return $function($project, $repository, $tag);
-
-
 }
 
-function package_handler_install_project_gitdo_normal($project, $repository, $tag) {
-  // Clone the repo into its appropriate target location.
-  $commands = array();
-  $commands[] = 'git clone ' . escapeshellarg($repository) . ' ' . escapeshellarg($project['full_project_path']);
-  // Check out the appropriate branch.
-  $commands[] = 'cd ' . escapeshellarg($project['full_project_path']);
-  $commands[] = 'git checkout ' . escapeshellarg($tag);
-
-  if (!drush_shell_exec(implode(' && ', $commands))) {
-    return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $project['name'] . ' from git.drupal.org.');
+/**
+ * Download a project.
+ *
+ * @param $request
+ *   The project array with name, base and full (final) paths.
+ * @param $release
+ *   The release details array from drupal.org.
+ */
+function package_handler_download_project(&$request, $release) {
+  if ($username = drush_get_option('gitusername')) {
+    // Uses SSH, which enables pushing changes back to git.drupal.org.
+    $repository = $username . '@git.drupal.org:project/' . $request['name'] . '.git';
   }
   else {
-    return TRUE;
+    $repository = 'git://git.drupal.org/project/' . $request['name'] . '.git';
   }
-}
-
-function package_handler_install_project_gitdo_submodule($project, $repository, $tag) {
-  // Verify that we are in a Git repository.
-  if (drush_shell_exec("cd " . escapeshellarg($project['base_project_path']) . " ; git rev-parse --git-dir")) {
-    $output = drush_shell_exec_output();
-    if (isset($output[0])) {
-      $git_dir = $output[0];
+  $request['repository'] = $repository;
+  $tag = $release['tag'];
+
+  // If the --cache option was given, create a new git reference cache of the
+  // remote repository, or update the existing cache to fetch recent changes.
+  if (drush_get_option('cache') && ($cachedir = drush_directory_cache())) {
+    $gitcache = $cachedir . '/git';
+    $projectcache = $gitcache . '/' . $request['name'] . '.git';
+    drush_mkdir($gitcache);
+    // Setup a new cache, if we don't have this project yet.
+    if (!file_exists($projectcache)) {
+      // --mirror works similar to --bare, but retrieves all tags, local
+      // branches, remote branches, and any other refs (notes, stashes, etc).
+      // @see http://stackoverflow.com/questions/3959924
+      $command = 'git clone --mirror';
+      if (drush_get_context('DRUSH_VERBOSE')) {
+        $command .= ' --verbose --progress';
+      }
+      $command .= ' %s %s';
+      drush_shell_cd_and_exec($gitcache, $command, $repository, $request['name'] . '.git');
     }
-  }
-  if (!isset($git_dir)) {
-    return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to create !project as a git submodule: !dir is not in a Git repository.', array('!project' => $project['name'], '!dir' => $project['base_project_path'])));
+    // If we already have this project, update it to speed up subsequent clones.
+    else {
+      // A --mirror clone is fully synchronized with `git remote update` instead
+      // of `git fetch --all`.
+      // @see http://stackoverflow.com/questions/6150188
+      drush_shell_cd_and_exec($projectcache, 'git remote update');
+    }
+    $gitcache = $projectcache;
   }
 
-  // Create the project path and find its true location, git submodule doesn't
-  // like symbolic links.
-  mkdir($project['full_project_path']);
-  $full_project_path = realpath($project['full_project_path']);
-  rmdir($full_project_path);
-
-  // Add the submodule; this clones it into place and registers it in the
-  // superproject.
-  $commands = array();
-  $commands[] = 'cd ' . escapeshellarg($git_dir . '/..');
-  $commands[] = 'git submodule add ' . escapeshellarg($repository) . ' ' . escapeshellarg($full_project_path);
-  $commands[] = 'cd ' . escapeshellarg($project['full_project_path']);
-  $commands[] = 'git checkout ' . escapeshellarg($tag);
+  // Clone the repo into its appropriate target location.
+  $command  = 'git clone';
+  $command .= ' ' . drush_get_option('gitcloneparams');
+  if (drush_get_option('cache')) {
+    $command .= ' --reference ' . drush_escapeshellarg($gitcache);
+  }
+  if (drush_get_context('DRUSH_VERBOSE')) {
+    $command .= ' --verbose --progress';
+  }
+  $command .= ' ' . drush_escapeshellarg($repository);
+  $command .= ' ' . drush_escapeshellarg($request['full_project_path']);
+  if (!drush_shell_exec($command)) {
+    return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to clone project !name from git.drupal.org.', array('!name' => $request['name'])));
+  }
 
-  if (!drush_shell_exec(implode(' && ', $commands))) {
-    return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $project['name'] . ' from git.drupal.org.');
+  // Check if the 'tag' from the release feed is a tag or a branch.
+  // If the tag exists, git will return it
+  if (!drush_shell_cd_and_exec($request['full_project_path'], 'git tag -l ' . drush_escapeshellarg($tag))) {
+    return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to clone project !name from git.drupal.org.', array('!name' => $request['name'])));
+  }
+  $output = drush_shell_exec_output();
+
+  if (isset($output[0]) && ($output[0] == $tag)) {
+    // If we want a tag, simply checkout it. The checkout will end up in
+    // "detached head" state.
+    $command  = 'git checkout ' . drush_get_option('gitcheckoutparams');
+    $command .= ' ' . drush_escapeshellarg($tag);
+    if (!drush_shell_cd_and_exec($request['full_project_path'], $command)) {
+      return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.');
+    }
   }
   else {
-    return TRUE;
+    // Else, we want to checkout a branch.
+    // First check if we are not already in the correct branch.
+    if (!drush_shell_cd_and_exec($request['full_project_path'], 'git symbolic-ref HEAD')) {
+      return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.');
+    }
+    $output = drush_shell_exec_output();
+    $current_branch = preg_replace('@^refs/heads/@', '', $output[0]);
+
+    // If we are not on the correct branch already, switch to the correct one.
+    if ($current_branch != $tag) {
+      $command  = 'git checkout';
+      $command .= ' ' . drush_get_option('gitcheckoutparams');
+      $command .= ' --track ' . drush_escapeshellarg('origin/' . $tag) . ' -b ' . drush_escapeshellarg($tag);
+      if (!drush_shell_cd_and_exec($request['full_project_path'], $command)) {
+        return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to retrieve ' . $request['name'] . ' from git.drupal.org.');
+      }
+    }
   }
+
+  return TRUE;
 }
 
 /**
  * Update a project (so far, only modules are supported).
  *
- * @param $project The project array with name, base and full (final) paths.
- * @param $release The release details array from drupal.org
+ * @param $request
+ *   The project array with name, base and full (final) paths.
+ * @param $release
+ *   The release details array from drupal.org.
  */
-function package_handler_update_project($project, $release) {
-  drush_log('Updating project ' . $project['name'] . ' ...');
+function package_handler_update_project($request, $release) {
+  drush_log('Updating project ' . $request['name'] . ' ...');
 
   $commands = array();
-  $commands[] = 'cd ' . escapeshellarg($project['full_project_path']);
-
   if ($release['version_extra'] == 'dev') {
     // Update the branch of the development repository.
     $commands[] = 'git pull';
+    $commands[] = drush_get_option('gitpullparams');
   }
   else {
     // Use a stable repository.
     $commands[] = 'git fetch';
-    $commands[] = 'git checkout ' . escapeshellarg($release['version']);
+    $commands[] = drush_get_option('gitfetchparams');
+    $commands[] = ';';
+    $commands[] = 'git checkout';
+    $commands[] = drush_get_option('gitcheckoutparams');
+    $commands[] = $release['version'];
   }
 
-  if (!drush_shell_exec(implode(' ; ', $commands))) {
-    return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to update ' . $project['name'] . ' from git.drupal.org.');
+  if (!drush_shell_cd_and_exec($request['full_project_path'], implode(' ', $commands))) {
+    return drush_set_error('DRUSH_PM_UNABLE_CHECKOUT', 'Unable to update ' . $request['name'] . ' from git.drupal.org.');
   }
-  else {
-    return TRUE;
+
+  return TRUE;
+}
+
+/**
+ * Post download action.
+ *
+ * This action take place once the project is placed in its final location.
+ *
+ * Here we add the project as a git submodule.
+ */
+function package_handler_post_download($project) {
+  if (drush_get_option('gitsubmodule', FALSE)) {
+    // Obtain the superproject path, then add as submodule.
+    if (drush_shell_cd_and_exec(dirname($project['full_project_path']), 'git rev-parse --show-toplevel')) {
+      $output = drush_shell_exec_output();
+      $superproject = $output[0];
+      // Add the downloaded project as a submodule of its git superproject.
+      $command = array();
+      $command[] = 'git submodule add';
+      $command[] = drush_get_option('gitsubmoduleaddparams');
+      $command[] = $project['repository'];
+      // We need the submodule relative path.
+      $command[] = substr($project['full_project_path'], strlen($superproject) + 1);
+      if (!drush_shell_cd_and_exec($superproject, implode(' ', $command))) {
+        return drush_set_error('DRUSH_PM_GIT_CHECKOUT_PROBLEMS', dt('Unable to add !name as a git submodule of !super.', array('!name' => $project['name'], '!super' => $superproject)));
+      }
+    }
+    else {
+      return drush_set_error('DRUSH_PM_GIT_SUBMODULE_PROBLEMS', dt('Unable to create !project as a git submodule: !dir is not in a Git repository.', array('!project' => $project['name'], '!dir' => dirname($project['full_project_path']))));
+    }
   }
 }
+
diff --git a/sites/all/modules/drush/commands/pm/package_handler/wget.inc b/sites/all/modules/drush/commands/pm/package_handler/wget.inc
index 6b8d41d76e5201cbbe31a4903984b6114e664c0b..3dc8e79c5f82ae2feb5a2d449122cbd630b4e162 100644
--- a/sites/all/modules/drush/commands/pm/package_handler/wget.inc
+++ b/sites/all/modules/drush/commands/pm/package_handler/wget.inc
@@ -1,79 +1,104 @@
 <?php
-// $Id: wget.inc,v 1.17 2010/11/24 12:39:59 jonhattan Exp $
 
 /**
  * @file Drush PM Wget extension
  */
 
+/**
+ * Validate this package handler can run.
+ */
+function package_handler_validate() {
+  // Check wget or curl command exists. Disable possible output.
+  $debug = drush_get_context('DRUSH_DEBUG');
+  drush_set_context('DRUSH_DEBUG', FALSE);
+  $success = drush_shell_exec('wget --version');
+  if (!$success) {
+    $success = drush_shell_exec('curl --version');
+    // Old version of curl shipped in darwin returns error status for --version
+    // and --help. Give the chance to use it.
+    if (!$success) {
+      $success = drush_shell_exec('which curl');
+    }
+  }
+  drush_set_context('DRUSH_DEBUG', $debug);
+  if (!$success) {
+    return drush_set_error('DRUSH_SHELL_COMMAND_NOT_FOUND', dt('wget nor curl executables found.'));
+  }
+}
+
 /**
  * Download a project.
  *
  * @param $request Array with information on the request to download.
  * @param $release The release details array from drupal.org.
  */
-function package_handler_install_project(&$request, $release) {
-  // Get the filename.
+function package_handler_download_project(&$request, $release) {
+  // Install profiles come in several variants. User may specify which one she wants.
+  if ($request['project_type'] == 'profile') {
+    // @todo Use xpath to get the right file url.
+    $files = $release['files'];
+    foreach ($files as $key => $file) {
+      if ((string)$file->variant == drush_get_option('variant', 'full') && (string)$file->archive_type == 'tar.gz') {
+        $release['download_link'] = (string)$file->url;
+        $release['mdhash'] = (string)$file->md5;
+        break;
+      }
+    }
+  }
+
   $filename = explode('/', $release['download_link']);
   $filename = array_pop($filename);
 
-  // Chdir to the download location.
-  $olddir = getcwd();
-  chdir($request['base_project_path']);
-
   // Download the project.
-  if (!drush_shell_exec("wget -P . " . $release['download_link'])) {
-    drush_shell_exec("curl -O " . $release['download_link']);
+  if (!drush_shell_exec("wget -P . %s", $release['download_link'])) {
+    drush_shell_exec("curl -O %s", $release['download_link']);
   }
   if (file_exists($filename) || drush_get_context('DRUSH_SIMULATE')) {
     drush_log("Downloading " . $filename . " was successful.");
   }
   else {
-    chdir($olddir);
     return drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', 'Unable to download ' . $filename . ' to ' . $request['base_project_path'] . ' from '. $release['download_link']);
   }
 
   // Check Md5 hash.
-  if (md5_file($filename) != $release['mdhash'] && !drush_get_context('DRUSH_SIMULATE')) {
+  if (drush_op('md5_file', $filename) != $release['mdhash'] && !drush_get_context('DRUSH_SIMULATE')) {
     drush_set_error('DRUSH_PM_FILE_CORRUPT', "File $filename is corrupt (wrong md5 checksum).");
     drush_op('unlink', $filename);
-    chdir($olddir);
     return FALSE;
   }
   else {
     drush_log("Md5 checksum of $filename verified.");
   }
 
-  // Decompress and untar in two steps as tar -xzf does not work on windows.
-  drush_shell_exec("gzip -d " . $filename);
-  $tarpath = basename($filename, '.tar.gz');
-  $tarpath = basename($tarpath, '.tgz');
-  $tarpath .= '.tar';
-  drush_shell_exec("tar -xf $tarpath");
+  // Extract the tarball.
+  $file_list = drush_tarball_extract($filename, $request['base_project_path'], TRUE);
+  drush_op('unlink', $filename);
 
   // Move untarred directory to project_dir, if distinct.
   if (($request['project_type'] == 'core') || (($request['project_type'] == 'profile') && (drush_get_option('variant', 'core') == 'core'))) {
     // Obtain the dodgy project_dir for drupal core.
-    // We use a separate tar -tf instead of -xvf above because
-    // the output is not the same in Mac.
-    drush_shell_exec("tar -tf $tarpath");
-    $output = drush_shell_exec_output();
-    $project_dir = rtrim($output[0], DIRECTORY_SEPARATOR);
+
+    $project_dir = rtrim($file_list[0], DIRECTORY_SEPARATOR);
     if ($request['project_dir'] != $project_dir) {
       $path = $request['base_project_path'];
-      drush_op('rename', $path . '/'. $project_dir, $path . '/' . $request['project_dir']);
+      drush_move_dir($path . '/'. $project_dir, $path . '/' . $request['project_dir']);
     }
   }
 
-  // Cleanup. Remove the tar file and set previous working directory.
-  drush_op('unlink', $tarpath);
-  chdir($olddir);
-
   return TRUE;
 }
 
 /**
- * This is an alias of the install function, since they are identical
+ * This is an alias of the download function, since they are identical
  */
 function package_handler_update_project(&$request, $release) {
-  return package_handler_install_project($request, $release);
+  return package_handler_download_project($request, $release);
+}
+
+/**
+ * Post download action.
+ *
+ * This action take place once the project is placed in its final location.
+ */
+function package_handler_post_download($project) {
 }
diff --git a/sites/all/modules/drush/commands/pm/pm.drush.inc b/sites/all/modules/drush/commands/pm/pm.drush.inc
index f12d36f7ef51ce16b4830f7f1cefb424e9027cc4..8a9573cd5be785ee9d41b9eb549059bfebcf61d7 100644
--- a/sites/all/modules/drush/commands/pm/pm.drush.inc
+++ b/sites/all/modules/drush/commands/pm/pm.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: pm.drush.inc,v 1.146 2010/12/01 21:02:21 jonhattan Exp $
 
 /**
  * @file
@@ -8,7 +7,7 @@
  * Terminology:
  * - Request: a requested project (string or keyed array), with a name and (optionally) version.
  * - Project: a drupal.org project (i.e drupal.org/project/*), such as cck or zen.
- * - Extension: a drupal.org module or theme.
+ * - Extension: a drupal.org module, theme or profile.
  * - Version: a requested version, such as 1.0 or 1.x-dev.
  * - Release: a specific release of a project, with associated metadata (from the drupal.org update service).
  */
@@ -24,66 +23,57 @@ define('DRUSH_PM_REQUESTED_UPDATE', 101);
 define('DRUSH_PM_REQUESTED_CURRENT', 102);
 
 /**
- * User requested version already installed.
+ * User requested project was not packaged by drupal.org.
  */
-define('DRUSH_PM_NO_VERSION', 103);
+define('DRUSH_PM_REQUESTED_PROJECT_NOT_PACKAGED', 103);
 
 /**
  * User requested version not found.
  */
-define('DRUSH_PM_REQUESTED_NOT_FOUND', 104);
+define('DRUSH_PM_REQUESTED_VERSION_NOT_FOUND', 104);
 
 /**
- * Sort callback function for sorting extensions.
- *
- * It will sort first by type, second by package and third by name.
+ * User requested project not found.
  */
-function _drush_pm_sort_extensions($a, $b) {
-  if ($a->type == 'module' && $b->type == 'theme') {
-    return -1;
-  }
-  if ($a->type == 'theme' && $b->type == 'module') {
-    return 1;
-  }
-  $cmp = strcasecmp($a->info['package'], $b->info['package']);
-  if ($cmp == 0) {
-    $cmp = strcasecmp($a->info['name'], $b->info['name']);
-  }
-  return $cmp;
-}
+define('DRUSH_PM_REQUESTED_PROJECT_NOT_FOUND', 105);
+
+/**
+ * User requested project not updateable.
+ */
+define('DRUSH_PM_REQUESTED_PROJECT_NOT_UPDATEABLE', 106);
+
 
 /**
  * Implementation of hook_drush_help().
  */
 function pm_drush_help($section) {
   switch ($section) {
+    case 'meta:pm:title':
+      return dt('Project manager commands');
+    case 'meta:pm:summary':
+      return dt('Download, enable, examine and update your modules and themes.');
     case 'drush:pm-enable':
       return dt('Enable one or more extensions (modules or themes). Enable dependant extensions as well.');
     case 'drush:pm-disable':
-      return dt('Disable one or more extensions. Disable dependant extensions as well.');
-    case 'drush:pm-info':
-      return dt('Show detailed info for one or more extensions.');
-    case 'drush:pm-uninstall':
-      return dt('Uninstall one or more modules. Modules must be disabled first.');
-    case 'drush:pm-list':
-      return dt('Show a list of available extensions.');
-    case 'drush:pm-refresh':
-      return dt('Refresh update status information. Run this before running pm-update or pm-updatecode commands.');
+      return dt('Disable one or more extensions (modules or themes). Disable dependant extensions as well.');
     case 'drush:pm-updatecode':
-      return dt("Display available update information and allow updating of all installed project code to the specified version (or latest by default). Note: The user is asked to confirm before the actual update. Use the --yes option to answer yes automatically.");
-    case 'drush:pm-updatecode-notify-pending-db-updates':
-      return dt("This is a helper command needed by updatecode. It is used to check for db updates in a backend process after code updated have been performed. We need to run this task in a separate process to not conflict with old code already in memory.");
     case 'drush:pm-update':
-      return dt("Display available update information and allow updating of all installed projects to the specified version (or latest by default), followed by applying any database updates required (as with running update.php). Note: The user is asked to confirm before the actual update. Use the --yes option to answer yes automatically.");
+      $message = dt("Display available update information for Drupal core and all enabled projects and allow updating to latest recommended releases.");
+      if ($section == 'drush:pm-update') {
+        $message .= ' '.dt("Also apply any database updates required (same as pm-updatecode + updatedb).");
+      }
+      $message .= ' '.dt("Note: The user is asked to confirm before the actual update. Backups are performed unless directory is already under version control. Updated projects can potentially break your site. It is NOT recommended to update production sites without prior testing.");
+      return $message;
+    case 'drush:pm-updatecode-postupdate':
+      return dt("This is a helper command needed by updatecode. It is used to check for db updates in a backend process after code updated have been performed. We need to run this task in a separate process to not conflict with old code already in memory.");
       case 'drush:pm-releases':
       return dt("View all releases for a given drupal.org project. Useful for deciding which version to install/update.");
     case 'drush:pm-download':
-      return dt("Download Drupal core or projects from drupal.org (Drupal core, modules, themes, profiles or translations) and other sources. It will automatically figure out which project version you want based on its latest release, or you may specify a particular version.
+      return dt("Download Drupal core or projects from drupal.org (Drupal core, modules, themes or profiles) and other sources. It will automatically figure out which project version you want based on its recommended release, or you may specify a particular version.
 
-If no destination is provided, then it depends on the project type:
+If no --destination is provided, then destination depends on the project type:
   - Profiles will be downloaded to profiles/ in your Drupal root.
-  - Translations will be decompressed from your Drupal root.
-  - Modules and themes will be downloaded to the site specific directory (sites/example.com/modules|themes if available) or to sites/all/modules|themes.
+  - Modules and themes will be downloaded to the site specific directory (sites/example.com/modules|themes) if available, or to sites/all/modules|themes.
   - If you're downloading drupal core or you are not running the command within a bootstrapped drupal site, the default location is the current directory.
   - Drush commands will be relocated to /usr/share/drush/commands (if available) or ~/.drush. Relocation is determined once the project is downloaded by examining its content. Note you can provide your own function in a commandfile to determine the relocation of any project.");
   }
@@ -104,16 +94,16 @@ function pm_drush_command() {
     ),
   );
   $update_options = array(
-    '--security-only' => 'Only update modules that have security updates available. However, if there were other releases of a module between the installed version the security update, other changes to features or functionality may occur.',
-    '--lock' => 'Add a persistent lock to remove the specified projects from consideration during updates.  Locks may be removed with the --unlock parameter, or overridden by specifically naming the project as a parameter to pm-update or pm-updatecode.  The lock does not affect pm-download.  See also the update-advanced project for similar and improved functionality.',
+    'security-only' => 'Only update modules that have security updates available. However, if there were other releases of a module between the installed version the security update, other changes to features or functionality may occur.',
+    'lock' => 'Add a persistent lock to remove the specified projects from consideration during updates.  Locks may be removed with the --unlock parameter, or overridden by specifically naming the project as a parameter to pm-update or pm-updatecode.  The lock does not affect pm-download.  See also the update-advanced project for similar and improved functionality.',
   );
   $update_suboptions = array(
-    '--lock' => array(
-      '--lock-message' => 'A brief message explaining why a project is being locked; displayed during pm-updatecode.  Optional.',
-      '--unlock' => 'Remove the persistent lock from the specified projects so that they may be updated again.',
+    'lock' => array(
+      'lock-message' => 'A brief message explaining why a project is being locked; displayed during pm-updatecode.  Optional.',
+      'unlock' => 'Remove the persistent lock from the specified projects so that they may be updated again.',
     ),
   );
-  
+
   $items['pm-enable'] = array(
     'description' => 'Enable one or more extensions (modules or themes).',
     'arguments' => array(
@@ -131,10 +121,11 @@ function pm_drush_command() {
     'deprecated-aliases' => array('disable'),
   );
   $items['pm-info'] = array(
-    'description' => 'Show info for one or more modules or themes.',
+    'description' => 'Show detailed info for one or more extensions (modules or themes).',
     'arguments' => array(
-      'extensions' => 'A list of modules or themes. You can use the * wildcard at the end of extension names to show info for multiple matches.',
+      'extensions' => 'A list of modules or themes. You can use the * wildcard at the end of extension names to show info for multiple matches. If no argument is provided it will show info for all available extensions.',
     ),
+    'aliases' => array('pmi'),
   );
   // Install command is reserved for the download and enable of projects including dependencies.
   // @see http://drupal.org/node/112692 for more information.
@@ -152,15 +143,15 @@ function pm_drush_command() {
     'description' => 'Show a list of available extensions (modules and themes).',
     'callback arguments' => array(array(), FALSE),
     'options' => array(
-      '--type' => 'Filter by extension type. Choices: module, theme.',
-      '--status' => 'Filter by extension status. Choices: enabled, disable and/or \'not installed\'. You can use multiple comma separated values. (i.e. --status="disabled,not installed").',
-      '--package' => 'Filter by project packages. You can use multiple comma separated values. (i.e. --package="Core - required,Other").',
-      '--core' => 'Filter out extensions that are not in core.',
-      '--no-core' => 'Filter out extensions that are provided by core projects.',
-      '--pipe' => 'Returns a space delimited list of the names of the resulting extensions.',
+      'type' => 'Filter by extension type. Choices: module, theme.',
+      'status' => 'Filter by extension status. Choices: enabled, disable and/or \'not installed\'. You can use multiple comma separated values. (i.e. --status="disabled,not installed").',
+      'package' => 'Filter by project packages. You can use multiple comma separated values. (i.e. --package="Core - required,Other").',
+      'core' => 'Filter out extensions that are not in drupal core.',
+      'no-core' => 'Filter out extensions that are provided by drupal core.',
+      'pipe' => 'Returns a space delimited list of the names of the resulting extensions.',
     ),
-    'aliases' => array('sm'),
-    'deprecated-aliases' => array('statusmodules'),
+    'aliases' => array('pml'),
+    'deprecated-aliases' => array('sm'),
   );
   $items['pm-refresh'] = array(
     'description' => 'Refresh update status information.',
@@ -169,51 +160,62 @@ function pm_drush_command() {
     'deprecated-aliases' => array('refresh'),
   );
   $items['pm-updatecode'] = array(
-    'description' => 'Update your project code',
+    'description' => 'Update Drupal core and contrib projects to latest recommended releases.',
     'drupal dependencies' => array($update),
     'arguments' => array(
       'projects' => 'Optional. A list of installed projects to update.',
     ),
     'options' => array(
-      '--pipe' => 'Returns a space delimited list of projects with any of its extensions enabled and their respective version and update information, one project per line. Order: project name, current version, recommended version, update status.',
+      'pipe' => 'Returns a space delimited list of projects with any of its extensions enabled and their respective version and update information, one project per line. Order: project name, current version, recommended version, update status.',
+      'notes' => 'Show release notes for each project to be updated.',
+      'no-core' => 'Only update modules and skip the core update.',
+      'self-update' => 'Check for pending updates to drush itself. Set to 0 to avoid check.',
     ) + $update_options,
     'sub-options' => $update_suboptions,
     'aliases' => array('upc'),
     'deprecated-aliases' => array('updatecode'),
+    'topics' => array('docs-policy'),
   ) + $engines;
   // Merge all items from above.
   $items['pm-update'] = array_merge($items['pm-updatecode'], array(
-    'description' => 'Update your project code and apply any database updates required (update.php).',
+    'description' => 'Update Drupal core and contrib projects and apply any pending database updates (Same as pm-updatecode + updatedb).',
     'aliases' => array('up'),
     'deprecated-aliases' => array('update'),
   ));
-  $items['pm-updatecode-notify-pending-db-updates'] = array(
+  $items['pm-updatecode-postupdate'] = array(
     'description' => 'Notify of pending db updates.',
     'hidden' => TRUE
   );
   $items['pm-releasenotes'] = array(
     'description' => 'Print release notes for given projects.',
-    'drupal dependencies' => array($update),
     'arguments' => array(
       'projects' => 'A list of drupal.org project names, with optional version. Defaults to \'drupal\'',
     ),
+    'options' => array(
+      'html' => dt('Display releasenotes in HTML rather than plain text.'),
+    ),
     'examples' => array(
-      'drush rln cck' => 'Prints the release notes for the recommended version of CCK package.',
+      'drush rln cck' => 'Prints the release notes for the recommended version of CCK project.',
       'drush rln token-1.13' => 'View release notes of a specfic version of the Token project for my version of Drupal.',
       'drush rln pathauto zen' => 'View release notes for the recommended version of Pathauto and Zen projects.',
     ),
     'aliases' => array('rln'),
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
   );
   $items['pm-releases'] = array(
     'description' => 'Print release information for given projects.',
-    'drupal dependencies' => array($update),
     'arguments' => array(
       'projects' => 'A list of drupal.org project names. Defaults to \'drupal\'',
     ),
+    'options' => array(
+      'dev' => "Show only development releases.",
+      'all' => "Shows all available releases instead of the default short list of recent releases.",
+    ),
     'examples' => array(
-      'drush pm-releases cck zen' => 'View releases for cck and Zen projects.',
+      'drush pm-releases cck zen' => 'View releases for cck and Zen projects for your Drupal version.',
     ),
-    'deprecated-aliases' => array('info'),
+    'aliases' => array('rl'),
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
   );
   $items['pm-download'] = array(
     'description' => 'Download projects from drupal.org or other sources.',
@@ -221,23 +223,30 @@ function pm_drush_command() {
       'drush dl' => 'Download latest recommended release of Drupal core.',
       'drush dl drupal' => 'Same as `drush dl`.',
       'drush dl drupal-7.x' => 'Download latest 7.x development version of Drupal core.',
-      'drush dl cck zen es' => 'Download latest versions of CCK, Zen and Spanish translations for your Drupal version.',
+      'drush dl drupal-6' => 'Download latest recommended release of Drupal 6.x.',
+      'drush dl cck zen' => 'Download latest versions of CCK and Zen projects.',
       'drush dl og-1.3' => 'Download a specfic version of Organic groups module for my version of Drupal.',
       'drush dl diff-6.x-2.x' => 'Download a specific development branch of diff module for a specific Drupal version.',
+      'drush dl views --select' => 'Show a list of recent releases of the views project, prompt for which one to download.',
+      'drush dl webform --dev' => 'Download the latest dev release of webform.',
     ),
     'arguments' => array(
-      'projects' => 'A list of drpal.org project names, with optional version. Defaults to \'drupal\'',
+      'projects' => 'A comma delimited list of drupal.org project names, with optional version. Defaults to \'drupal\'',
     ),
     'options' => array(
-      '--destination' => 'Path to which the project will be copied. If you\'re providing a relative path, note it is relative to the drupal root (if bootstrapped).',
-      '--use-site-dir' => 'Force to use the site specific directory. It will create the directory if it doesn\'t exist. If --destination is also present this option will be ignored.',
-      '--source' => 'The base URL which provides project release history in XML. Defaults to http://updates.drupal.org/release-history.',
-      '--notes' => 'Show release notes after each project is downloaded.',
-      '--variant' => "Only useful for install profiles. Possible values: 'core', 'no-core', 'make'.",
-      '--drupal-project-rename' => 'Alternate name for "drupal-x.y" directory when downloading Drupal project. If empty, will defaults to "drupal".',
-      '--pipe' => 'Returns a list of the names of the extensions (modules and themes) contained in the downloaded projects.',
+      'destination' => 'Path to which the project will be copied. If you\'re providing a relative path, note it is relative to the drupal root (if bootstrapped).',
+      'use-site-dir' => 'Force to use the site specific directory. It will create the directory if it doesn\'t exist. If --destination is also present this option will be ignored.',
+      'source' => 'The base URL which provides project release history in XML. Defaults to http://updates.drupal.org/release-history.',
+      'notes' => 'Show release notes after each project is downloaded.',
+      'variant' => "Only useful for install profiles. Possible values: 'full', 'projects', 'profile-only'.",
+      'dev' => "Download a development release.",
+      'select' => "Select the version to download interactively from a list of available releases.",
+      'all' => "Useful only with --select; shows all available releases instead of a short list of recent releases.",
+      'drupal-project-rename' => 'Alternate name for "drupal-x.y" directory when downloading Drupal project. Defaults to "drupal".',
+      'default-major' => 'Specify the default major version of modules to download when there is no bootstrapped Drupal site.  Defaults to "7".',
+      'pipe' => 'Returns a list of the names of the extensions (modules and themes) contained in the downloaded projects.',
     ),
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap required.
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
     'aliases' => array('dl'),
     'deprecated-aliases' => array('download'),
   ) + $engines;
@@ -245,8 +254,180 @@ function pm_drush_command() {
 }
 
 /**
- * Command callback. Show a list of extensions with type and status.
+ * @defgroup extensions Extensions management.
+ * @{
+ * Functions to manage extensions.
+ */
+
+/**
+ * Sort callback function for sorting extensions.
+ *
+ * It will sort first by type, second by package and third by name.
+ */
+function _drush_pm_sort_extensions($a, $b) {
+  if ($a->type == 'module' && $b->type == 'theme') {
+    return -1;
+  }
+  if ($a->type == 'theme' && $b->type == 'module') {
+    return 1;
+  }
+  $cmp = strcasecmp($a->info['package'], $b->info['package']);
+  if ($cmp == 0) {
+    $cmp = strcasecmp($a->info['name'], $b->info['name']);
+  }
+  return $cmp;
+}
+
+/**
+ * Calculate a extension status based on current status and schema version.
+ *
+ * @param $extension
+ *   Object of a single extension info.
+ *
+ * @return
+ *   String describing extension status. Values: enabled|disabled|not installed
+ */
+function drush_get_extension_status($extension) {
+  if (($extension->type == 'module')&&($extension->schema_version == -1)) {
+    $status = "not installed";
+  }
+  else {
+    $status = ($extension->status == 1)?'enabled':'disabled';
+  }
+
+  return $status;
+}
+
+/**
+ * Wrapper of drupal_get_extensions() with additional information used by
+ * pm- commands.
+ *
+ * @return
+ *   An array containing info for all available extensions w/additional info.
+ */
+function drush_pm_get_extensions() {
+  $extensions = drush_get_extensions();
+  foreach ($extensions as $key => $extension) {
+    if (empty($extension->info['package'])) {
+      $extensions[$key]->info['package'] = dt('Other');
+    }
+  }
+  return $extensions;
+}
+
+/**
+ * Classify extensions as modules, themes or unknown.
+ *
+ * @param $extensions
+ *   Array of extension names, by reference.
+ * @param $modules
+ *   Empty array to be filled with modules in the provided extension list.
+ * @param $themes
+ *   Empty array to be filled with themes in the provided extension list.
+ */
+function drush_pm_classify_extensions(&$extensions, &$modules, &$themes, $extension_info) {
+  _drush_pm_expand_extensions($extensions, $extension_info);
+  foreach ($extensions as $extension) {
+    if (!isset($extension_info[$extension])) {
+      continue;
+    }
+    if ($extension_info[$extension]->type == 'module') {
+      $modules[$extension] = $extension;
+    }
+    else if ($extension_info[$extension]->type == 'theme') {
+      $themes[$extension] = $extension;
+    }
+  }
+}
+
+/**
+ * Obtain an array of installed projects off the extensions available.
  *
+ * A project is considered to be 'enabled' when any of its extensions is
+ * enabled.
+ * If any extension lacks project information and it is found that the
+ * extension was obtained from drupal.org's cvs or git repositories, a new
+ * 'vcs' attribute will be set on the extension. Example:
+ *   $extensions[name]->vcs = 'cvs';
+ *
+ * @param array $extensions.
+ *   Array of extensions as returned by drush_get_extensions().
+ * @return
+ *   Array of installed projects with info of version, status and provided
+* extensions.
+ */
+function drush_get_projects(&$extensions = NULL) {
+  if (is_null($extensions)) {
+    $extensions = drush_get_extensions();
+  }
+  $projects = array('drupal' => array('version' => VERSION));
+  foreach ($extensions as $extension) {
+    // The project name is not available in this cases:
+    // 1. the extension is part of drupal core.
+    // 2. the project was checked out from CVS/git and cvs_deploy/git_deploy
+    // is not installed.
+    // 3. it is not a project hosted in drupal.org.
+    if (empty($extension->info['project'])) {
+      if (isset($extension->info['version']) && ($extension->info['version'] == VERSION)) {
+        $project = 'drupal';
+      }
+      else {
+        if (is_dir(dirname($extension->filename) . '/CVS') && (!module_exists('cvs_deploy'))) {
+          $extension->vcs = 'cvs';
+          drush_log(dt('Extension !extension is fetched from cvs. Ignoring.', array('!extension' => $extension->name)), 'debug');
+        }
+        elseif (is_dir(dirname($extension->filename) . '/.git') && (!module_exists('git_deploy'))) {
+          $extension->vcs = 'git';
+          drush_log(dt('Extension !extension is fetched from git. Ignoring.', array('!extension' => $extension->name)), 'debug');
+        }
+        continue;
+      }
+    }
+    else {
+        $project = $extension->info['project'];
+    }
+    // Create/update the project in $projects with the project data.
+    if (!isset($projects[$project])) {
+      $projects[$project] = array(
+        'type' => $extension->type,
+        'version' => $extension->info['version'],
+        'status' => $extension->status,
+        'extensions' => array(),
+      );
+      if (isset($extension->info['project status url'])) {
+        $projects[$project]['status url'] = $extension->info['project status url'];
+      }
+    }
+    elseif ($extension->status != 0) {
+      $projects[$project]['status'] = $extension->status;
+    }
+    $projects[$project]['extensions'][] = $extension->name;
+  }
+
+  return $projects;
+}
+
+/**
+ * Returns a list of enabled modules.
+ *
+ * This is a simplified version of module_list().
+ */
+function pm_module_list() {
+  $enabled = array();
+  $rsc = drush_db_select('system', 'name', 'type=:type AND status=:status', array(':type' => 'module', ':status' => 1));
+  while ($row = drush_db_result($rsc)) {
+    $enabled[$row] = $row;
+  }
+
+  return $enabled;
+}
+
+/**
+ * @} End of "defgroup extensions".
+ */
+
+/**
+ * Command callback. Show a list of extensions with type and status.
  */
 function drush_pm_list() {
   //--package
@@ -306,28 +487,33 @@ function drush_pm_list() {
   uasort($extension_info, '_drush_pm_sort_extensions');
 
   $major_version = drush_drupal_major_version();
-  foreach ($extension_info as $extension) {
+  foreach ($extension_info as $key => $extension) {
     if (!in_array($extension->type, $type_filter)) {
+      unset($extension_info[$key]);
       continue;
     }
     $status = drush_get_extension_status($extension);
     if (!in_array($status, $status_filter)) {
+      unset($extension_info[$key]);
       continue;
     }
     if (($major_version >= 6) and (isset($extension->info['hidden']))) {
+      unset($extension_info[$key]);
       continue;
     }
-    
+
     // filter out core if --no-core specified
     if (drush_get_option('no-core', FALSE)) {
-      if (strcasecmp("Core ", substr($extension->info['package'], 0, 5)) == 0) {
+      if ($extension->info['version'] == VERSION) {
+        unset($extension_info[$key]);
         continue;
       }
     }
-    
+
     // filter out non-core if --core specified
     if (drush_get_option('core', FALSE)) {
-      if (strcasecmp("Core ", substr($extension->info['package'], 0, 5)) != 0) {
+      if ($extension->info['version'] != VERSION) {
+        unset($extension_info[$key]);
         continue;
       }
     }
@@ -335,6 +521,7 @@ function drush_pm_list() {
     // filter by package
     if (!empty($package_filter)) {
       if (!in_array(strtolower($extension->info['package']), $package_filter)) {
+        unset($extension_info[$key]);
         continue;
       }
     }
@@ -370,49 +557,110 @@ function drush_pm_list() {
     // Newline-delimited list for use by other scripts. Set the --pipe option.
     drush_print_pipe($pipe);
   }
+  // Set the result for backend invoke
+  drush_backend_set_result($extension_info);
+}
+
+function drush_pm_find_project_from_extension($extension) {
+  $result =  drush_pm_lookup_extension_in_cache($extension);
+
+  if (!isset($result)) {
+    // If we can find info on a project that has the same name
+    // as the requested extension, then we'll call that a match.
+    $info = _drush_pm_get_releases(array($extension));
+    if (!empty($info)) {
+      $result = $extension;
+    }
+  }
+
+  return $result;
 }
 
 /**
  * Command callback. Enable one or more extensions from downloaded projects.
  */
 function drush_pm_enable() {
+  // Include update engine so we can use update_check_incompatibility().
+  drush_include_engine('drupal', 'update');
   $args = _convert_csv_to_array(func_get_args());
 
   $extension_info = drush_get_extensions();
 
-  // Classify $args in themes, modules or unknown.
-  $modules = array();
-  $themes = array();
-  drush_pm_classify_extensions($args, $modules, $themes, $extension_info);
-  $extensions = array_merge($modules, $themes);
-  $unknown = array_diff($args, $extensions);
+  $recheck = TRUE;
+  while ($recheck) {
+    $recheck = FALSE;
 
-  // Discard and set an error for each unknown extension.
-  foreach ($unknown as $name) {
-    drush_set_error('DRUSH_PM_ENABLE_EXTENSION_NOT_FOUND', dt('!extension was not found and will not be enabled.', array('!extension' => $name)));
-  }
+    // Classify $args in themes, modules or unknown.
+    $modules = array();
+    $themes = array();
+    drush_pm_classify_extensions($args, $modules, $themes, $extension_info);
+    $extensions = array_merge($modules, $themes);
+    $unknown = array_diff($args, $extensions);
 
-  // Discard already enabled extensions.
-  foreach ($extensions as $name) {
-    if ($extension_info[$name]->status) {
-      if ($extension_info[$name]->type == 'module') {
-        unset($modules[$name]);
+    // Discard and set an error for each unknown extension.
+    foreach ($unknown as $name) {
+      drush_log(dt('!extension was not found and will not be enabled.', array('!extension' => $name)), 'warning');
+    }
+
+    // Discard already enabled and incompatible extensions.
+    foreach ($extensions as $name) {
+      if ($extension_info[$name]->status) {
+        drush_log(dt('!extension is already enabled.', array('!extension' => $name)), 'ok');
       }
-      else {
-        unset($themes[$name]);
+      // Check if is compatible with Drupal core.
+      if (update_check_incompatibility($name, $extension_info[$name]->type)) {
+        drush_set_error('DRUSH_PM_ENABLE_MODULE_INCOMPATIBLE', dt('!name is incompatible with the Drupal version.', array('!name' => $name)));
+        if ($extension_info[$name]->type == 'module') {
+          unset($modules[$name]);
+        }
+        else {
+          unset($themes[$name]);
+        }
+      }
+    }
+
+    if (!empty($modules)) {
+      // Check module dependencies.
+      $dependencies = drush_check_module_dependencies($modules, $extension_info);
+      $unmet_dependencies = array();
+      foreach ($dependencies as $module => $info) {
+        if (!empty($info['unmet-dependencies'])) {
+          foreach ($info['unmet-dependencies'] as $unmet_module) {
+            $unmet_project = drush_pm_find_project_from_extension($unmet_module);
+            if (!empty($unmet_project)) {
+              $unmet_dependencies[$module][$unmet_project] = $unmet_project;
+            }
+          }
+        }
+      }
+      if (!empty($unmet_dependencies)) {
+        $msgs = array();
+        $unmet_project_list = array();
+        foreach ($unmet_dependencies as $module => $unmet_projects) {
+          $unmet_project_list = array_merge($unmet_project_list, $unmet_projects);
+          $msgs[] = dt("!module requires !unmet-projects", array('!unmet-projects' => implode(', ', $unmet_projects), '!module' => $module));
+        }
+        if (drush_get_option('resolve-dependencies') || drush_confirm(dt("The following projects have unmet dependencies:\n!list\nWould you like to download them?", array('!list' => implode("\n", $msgs))))) {
+          // If we did not already print a log message via drush_confirm, then print one now.
+          if (drush_get_option('resolve-dependencies')) {
+            drush_log(dt("The following projects have unmet dependencies:\n@list\nThey are being downloaded.", array('@list' => implode("\n", $msgs))));
+          }
+          $result = drush_invoke_process_args('pm-download', $unmet_project_list, array('y' => TRUE));
+          // Refresh module cache after downloading the new modules.
+          $extension_info = drush_get_extensions();
+          $recheck = TRUE;
+        }
       }
-      drush_log(dt('!extension is already enabled.', array('!extension' => $name)), 'ok');
     }
   }
 
   if (!empty($modules)) {
-    // Check module dependencies.
-    $dependencies = drush_check_module_dependencies($modules, $extension_info);
     $all_dependencies = array();
+    $dependencies_ok = TRUE;
     foreach ($dependencies as $key => $info) {
       if (isset($info['error'])) {
         unset($modules[$key]);
-        drush_set_error($info['error']['code'], $info['error']['message']);
+        $dependencies_ok = drush_set_error($info['error']['code'], $info['error']['message']);
       }
       elseif (!empty($info['dependencies'])) {
         // Make sure we have an assoc array.
@@ -420,10 +668,10 @@ function drush_pm_enable() {
         $all_dependencies = array_merge($all_dependencies, $assoc);
       }
     }
-    $enabled = array_keys(array_filter(drush_get_modules(), 'pm_is_enabled'));
-    $needed = array_diff($all_dependencies, $enabled);
-    $modules = $needed + $modules;
-
+    if (!$dependencies_ok) {
+      return FALSE;
+    }
+    $modules = array_diff(array_merge($modules, $all_dependencies), pm_module_list());
     // Discard modules which doesn't meet requirements.
     require_once drush_get_context('DRUSH_DRUPAL_ROOT') . '/includes/install.inc';
     foreach ($modules as $key => $module) {
@@ -433,6 +681,7 @@ function drush_pm_enable() {
         unset($modules[$key]);
         drush_set_error('DRUSH_PM_ENABLE_MODULE_UNMEET_REQUIREMENTS', dt('Module !module doesn\'t meet the requirements to be enabled.', array('!module' => $module)));
         _drush_log_drupal_messages();
+        return FALSE;
       }
     }
   }
@@ -445,7 +694,7 @@ function drush_pm_enable() {
   else {
     drush_print(dt('The following extensions will be enabled: !extensions', array('!extensions' => implode(', ', $extensions))));
     if(!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
   }
 
@@ -457,22 +706,32 @@ function drush_pm_enable() {
   // Enable modules and pass dependency validation in form submit.
   if (!empty($modules)) {
     drush_module_enable($modules);
-    $current = drupal_map_assoc($enabled, 'pm_true');
-    $processed = drupal_map_assoc($modules, 'pm_true');
-    $active_modules = array_merge($current, $processed);
-    drush_system_modules_form_submit($active_modules);
+    drush_system_modules_form_submit(pm_module_list());
   }
 
   // Inform the user of final status.
   $rsc = drush_db_select('system', array('name', 'status'), 'name IN (:extensions)', array(':extensions' => $extensions));
+  $problem_extensions = array();
+  $searchpath = array();
   while ($extension = drush_db_fetch_object($rsc)) {
     if ($extension->status) {
       drush_log(dt('!extension was enabled successfully.', array('!extension' => $extension->name)), 'ok');
+      $searchpath[] = dirname($extension_info[$extension->name]->filename);
     }
     else {
-      drush_set_error('DRUSH_PM_ENABLE_EXTENSION_ISSUE', dt('There was a problem enabling !extension.', array('!extension' => $extension->name)));
+      $problem_extensions[] = $extension->name;
     }
   }
+  // Add all modules that were enabled to the drush
+  // list of commandfiles (if they have any).  This
+  // will allow these newly-enabled modules to participate
+  // in the post_pm_enable hook.
+  if (!empty($searchpath)) {
+    _drush_add_commandfiles($searchpath);
+  }
+  if (!empty($problem_extensions)) {
+    return drush_set_error('DRUSH_PM_ENABLE_EXTENSION_ISSUE', dt('There was a problem enabling !extension.', array('!extension' => implode(',', $problem_extensions))));
+  }
 }
 
 /**
@@ -491,8 +750,8 @@ function drush_pm_disable() {
   $unknown = array_diff($args, $extensions);
 
   // Discard and set an error for each unknown extension.
-  foreach ($unknown as $namew) {
-    drush_set_error('DRUSH_PM_ENABLE_EXTENSION_NOT_FOUND', dt('!extension was not found and will not be disabled.', array('!extension' => $name)));
+  foreach ($unknown as $name) {
+    drush_log('DRUSH_PM_ENABLE_EXTENSION_NOT_FOUND', dt('!extension was not found and will not be disabled.', array('!extension' => $name)), 'warning');
   }
 
   // Discard already disabled extensions.
@@ -519,20 +778,18 @@ function drush_pm_disable() {
 
   if (!empty($modules)) {
     // Add enabled dependents to the list of modules to disable.
-    $enabled = array_keys(array_filter(drush_get_modules(), 'pm_is_enabled'));
     $dependents = drush_module_dependents($modules, $extension_info);
-    $dependents = array_unique($dependents);
-    $dependents = array_intersect($dependents, $enabled);
+    $dependents = array_intersect($dependents, pm_module_list());
     $modules = array_merge($modules, $dependents);
 
     // Discard required modules.
-    $required = drupal_required_modules();
+    $required = drush_drupal_required_modules($extension_info);
     foreach ($required as $module) {
       if (isset($modules[$module])) {
         unset($modules[$module]);
         // No message for hidden modules.
         if (!isset($extension_info[$module]->info['hidden'])) {
-          drush_log(dt('!module is a required module and can\'t be disabled.', array('!module' => $module)), 'ok'); 
+          drush_log(dt('!module is a required module and can\'t be disabled.', array('!module' => $module)), 'ok');
         }
       }
     }
@@ -546,7 +803,7 @@ function drush_pm_disable() {
   else {
     drush_print(dt('The following extensions will be disabled: !extensions', array('!extensions' => implode(', ', $extensions))));
     if(!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
   }
 
@@ -558,65 +815,25 @@ function drush_pm_disable() {
   // Disable modules and pass dependency validation in form submit.
   if (!empty($modules)) {
     drush_module_disable($modules);
-    $active_modules = array_diff($enabled, $modules);
-    $active_modules = drupal_map_assoc($active_modules, 'pm_true');
-    drush_system_modules_form_submit($active_modules);
+    drush_system_modules_form_submit(pm_module_list());
   }
 
   // Inform the user of final status.
   $rsc = drush_db_select('system', array('name', 'status'), 'name IN (:extensions)', array(':extensions' => $extensions));
+  $problem_extensions = array();
   while ($extension = drush_db_fetch_object($rsc)) {
     if (!$extension->status) {
       drush_log(dt('!extension was disabled successfully.', array('!extension' => $extension->name)), 'ok');
     }
     else {
-      drush_set_error('DRUSH_PM_DISABLE_EXTENSION_ISSUE', dt('There was a problem disabling !extension.', array('!extension' => $extension->name)));
+      $problem_extensions[] = $extension->name;
     }
   }
-}
-
-/**
- * Wrapper of drupal_get_extensions() with additional information used by
- * pm- commands.
- *
- * @return
- *   An array containing info for all available extensions w/additional info.
- */
-function drush_pm_get_extensions() {
-  $extensions = drush_get_extensions();
-  foreach ($extensions as $key => $extension) {
-    if (empty($extension->info['package'])) {
-      $extensions[$key]->info['package'] = dt('Other');
-    }
+  if (!empty($problem_extensions)) {
+    return drush_set_error('DRUSH_PM_DISABLE_EXTENSION_ISSUE', dt('There was a problem disabling !extension.', array('!extension' => implode(',', $problem_extensions))));
   }
-  return $extensions;
 }
-
-/**
- * Classify extensions as modules, themes or unknown.
- *
- * @param $extensions
- *   Array of extension names, by reference.
- * @param $modules
- *   Empty array to be filled with modules in the provided extension list.
- * @param $themes
- *   Empty array to be filled with themes in the provided extension list.
- */
-function drush_pm_classify_extensions(&$extensions, &$modules, &$themes, $extension_info) {
-  _drush_pm_expand_extensions($extensions, $extension_info);
-  foreach ($extensions as $extension) {
-    if (!isset($extension_info[$extension])) {
-      continue;
-    }
-    if ($extension_info[$extension]->type == 'module') {
-      $modules[$extension] = $extension;
-    }
-    else if ($extension_info[$extension]->type == 'theme') {
-      $themes[$extension] = $extension;
-    }
-  }
-}
-
+  
 /**
  * Command callback. Show detailed info for one or more extension.
  */
@@ -625,13 +842,22 @@ function drush_pm_info() {
 
   $extension_info = drush_pm_get_extensions();
   _drush_pm_expand_extensions($args, $extension_info);
+  // If no extensions are provided, select all but the hidden ones.
+  if (count($args) == 0) {
+    foreach ($extension_info as $key => $extension) {
+      if (isset($extension->info['hidden'])) {
+        unset($extension_info[$key]);
+      }
+    }
+    $args = array_keys($extension_info);
+  }
 
   foreach ($args as $project) {
     if (isset($extension_info[$project])) {
       $info = $extension_info[$project];
     }
     else {
-      drush_set_error('DRUSH_PM_INFO_PROJECT_NOT_FOUND', dt('!project was not found.', array('!project' => $project)));
+      drush_log(dt('!project was not found.', array('!project' => $project)), 'warning');
       continue;
     }
     if ($info->type == 'module') {
@@ -768,7 +994,7 @@ function _drush_pm_expand_extensions(&$extensions, $extension_info = array()) {
   foreach ($extensions as $key => $extension) {
     if (($wildcard = rtrim($extension, '*')) !== $extension) {
       foreach (array_keys($extension_info) as $extension_name) {
-        if (strpos($extension_name, $wildcard) !== FALSE) {
+        if (substr($extension_name, 0, strlen($wildcard)) == $wildcard) {
           $extensions[] = $extension_name;
         }
       }
@@ -787,24 +1013,37 @@ function drush_pm_uninstall() {
 
   drush_include_engine('drupal', 'environment');
   $module_info = drush_get_modules();
+  $required = drupal_required_modules();
 
   // Discards modules which are enabled, not found or already uninstalled.
   foreach ($modules as $key => $module) {
     if (!isset($module_info[$module])) {
       // The module does not exist in the system.
       unset($modules[$key]);
-      drush_set_error('DRUSH_PM_ENABLE_MODULE_NOT_FOUND', dt('Module !module was not found and will not be uninstalled.', array('!module' => $module)));
+      drush_log(dt('Module !module was not found and will not be uninstalled.', array('!module' => $module)), 'warning');
     }
     else if ($module_info[$module]->status) {
       // The module is enabled.
       unset($modules[$key]);
-      drush_set_error('DRUSH_PM_UNINSTALL_ACTIVE_MODULE', dt('!module is not disabled. Use `pm-disable` command before `pm-uninstall`.', array('!module' => $module)));
+      drush_log(dt('!module is not disabled. Use `pm-disable` command before `pm-uninstall`.', array('!module' => $module)), 'warning');
     }
     else if ($module_info[$module]->schema_version == -1) { // SCHEMA_UNINSTALLED
       // The module is uninstalled.
       unset($modules[$key]);
       drush_log(dt('!module is already uninstalled.', array('!module' => $module)), 'ok');
     }
+    else {
+      $required_by = array();
+      foreach (array_keys($module_info[$module]->required_by) as $dependent) {
+        if (!in_array($dependent, $required) && ($module_info[$dependent]->schema_version != -1)) {
+          $required_by[] = $dependent;
+        }
+      }
+      if (count($required_by)) {
+        drush_log(dt('To uninstall !module, the following modules must be uninstalled first: !required', array('!module' => $module, '!required' => implode(', ', $required_by))), 'error');
+        unset($modules[$key]);
+      }
+    }
   }
 
   // Inform the user which modules will finally be uninstalled.
@@ -814,7 +1053,7 @@ function drush_pm_uninstall() {
   else {
     drush_print(dt('The following modules will be uninstalled: !modules', array('!modules' => implode(', ', $modules))));
     if(!drush_confirm(dt('Do you really want to continue?'))) {
-      return drush_log(dt('Aborting.'));
+      return drush_user_abort();
     }
   }
 
@@ -827,23 +1066,6 @@ function drush_pm_uninstall() {
   }
 }
 
-/**
- * Array filter callback to return enabled modules.
- *
- * @param $module
- *  A module object as returned by drush_get_modules().
- */
-function pm_is_enabled($module) {
-  return $module->status;
-}
-
-/**
- * Callback helper.
- */
-function pm_true() {
-  return TRUE;
-}
-
 /**
  * Completes projects' update data with the path to install location on disk.
  *
@@ -856,43 +1078,64 @@ function _pm_get_project_path($data, $lookup) {
     }
     // Array of extensions (modules/themes) within the project.
     $extensions = array_keys($release[$lookup]);
-    // Select the first path as the candidate to be the common prefix.
-    $path = drupal_get_path($release['project_type'], array_pop($extensions));
-    // If there's only one extension we are done. Otherwise, we need to find
-    // the common prefix for all of them.
-    if (count($extensions) > 0) {
-      // Iterate over the other projects.
-      while($project = array_pop($extensions)) {
-        $path2 = drupal_get_path($release['project_type'], $project);
-        // Option 1: same path.
-        if ($path == $path2) {
-          continue;
-        }
-        // Option 2: $path is a prefix of $path2.
+    $path = _pm_find_common_path($release['project_type'], $extensions);
+    $reserved = array('modules', 'sites', 'themes');
+    if ((in_array(basename($path), $reserved)) && (!in_array($name, $reserved))) {
+      drush_log(dt('Error while trying to find the common path for enabled extensions of project !project. Extensions are: !extensions.', array('!project' => $name, '!extensions' => implode(', ', $extensions))), 'error');
+      unset($data[$name]);
+    }
+    else {
+      $data[$name]['path'] = $path;
+    }
+  }
+
+  return $data;
+}
+
+/**
+ * Helper function to find the common path for a list of extensions in the aim to obtain the project name.
+ *
+ * @param $project_type
+ *  Type of project we're trying to find. Valid values: module, theme.
+ * @param $extensions
+ *  Array of extension names.
+ */
+function _pm_find_common_path($project_type, $extensions) {
+  // Select the first path as the candidate to be the common prefix.
+  $path = drupal_get_path($project_type, array_pop($extensions));
+  // If there's only one extension we are done. Otherwise, we need to find
+  // the common prefix for all of them.
+  if (count($extensions) > 0) {
+    // Iterate over the other projects.
+    while($project = array_pop($extensions)) {
+      $path2 = drupal_get_path($project_type, $project);
+      // Option 1: same path.
+      if ($path == $path2) {
+        continue;
+      }
+      // Option 2: $path is a prefix of $path2.
+      if (strpos($path2, $path) === 0) {
+        continue;
+      }
+      // Option 3: $path2 is a prefix of $path.
+      if (strpos($path, $path2) === 0) {
+        $path = $path2;
+        continue;
+      }
+      // Option 4: no one is a prefix of the other. Find the common
+      // prefix by iteratively strip the rigthtmost piece of $path.
+      // We will iterate until a prefix is found or path = '.', that on the
+      // other hand is a condition theorically impossible to reach.
+      do {
+        $path = dirname($path);
         if (strpos($path2, $path) === 0) {
-          continue;
-        }
-        // Option 3: $path2 is a prefix of $path.
-        if (strpos($path, $path2) === 0) {
-          $path = $path2;
-          continue;
+          break;
         }
-        // Option 4: no one is a prefix of the other. Find the common
-        // prefix by iteratively strip the rigthtmost piece of $path.
-        // We will iterate until a prefix is found or path = '.', that on the
-        // other hand is a condition theorically impossible to reach.
-        do {
-          $path = dirname($path);
-          if (strpos($path2, $path) === 0) {
-            break;
-          }
-        } while ($path != '.');
-      }
+      } while ($path != '.');
     }
-    $data[$name]['path'] = $path;
   }
 
-  return $data;
+  return $path;
 }
 
 /**
@@ -912,114 +1155,238 @@ function drush_pm_releases() {
     $header = dt('------- RELEASES FOR \'!name\' PROJECT -------', array('!name' => strtoupper($name)));
     $rows = array();
     $rows[] = array(dt('Release'), dt('Date'), dt('Status'));
-    foreach ($project['releases'] as $release) {
+    $releases = _drush_pm_filter_releases($project['releases'], drush_get_option('all', FALSE), drush_get_option('dev', FALSE));
+    foreach ($releases as $release) {
       $rows[] = array(
         $release['version'],
-        format_date($release['date'], 'custom', 'Y-M-d'),
+        gmdate('Y-M-d', $release['date']),
         implode(', ', $release['release_status'])
       );
     }
     drush_print($header);
     drush_print_table($rows, TRUE, array(0 => 14));
   }
+
+  return $info;
 }
 
 /**
- * Get releases for given projects and fill in status information.
- *
- * @param $projects
- *   An array of drupal.org projects.
- *
- * @see drush_pm_releases()
- * @see _drush_pm_releasenotes()
+ * Obtain releases for a project's xml as returned by the update service.
  */
-function _drush_pm_get_releases($projects) {
-  // We don't provide for other options here, so we supply an explicit path.
-  drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
-
-  $projects = drupal_map_assoc($projects);
-  $info = pm_get_project_info($projects);
-  foreach ($projects as $project) {
-    if (!isset($info[$project])) {
-      drush_set_error('DRUSH_PM_PROJECT_NOT_FOUND', dt("No release history was found for the requested project (!project).", array('!project' => $project)));
-      continue;
+function _drush_pm_get_releases_from_xml($xml, $project) {
+  // If bootstraped, we can obtain which is the installed release of a project.
+  static $installed_projects = FALSE;
+  if (!$installed_projects) {
+    if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_FULL) {
+      $installed_projects = drush_get_projects();
     }
-    if ($info[$project]['project_status'] == 'unpublished') {
-      drush_set_error('DRUSH_PM_PROJECT_UNPUBLISHED', dt("Project !project is unpublished ans has no releases available.", array('!project' => $key)), 'warning');
-      unset($info[$key]);
-      continue;
+    else {
+      $installed_projects = array();
     }
   }
 
-  // Info on extensions present in the bootstrapped site will be used to
-  // identify if any project release is installed.
-  $extension_info = drush_get_extensions();
+  foreach (array('title', 'short_name', 'dc:creator', 'api_version', 'recommended_major', 'supported_majors', 'default_major', 'project_status', 'link') as $item) {
+    if (array_key_exists($item, $xml)) {
+      $value = $xml->xpath($item);
+      $project_info[$item] = (string)$value[0];
+    }
+  }
 
-  // Iterate the projects to collect relevant information.
-  foreach ($info as $key => $project) {
-    // Find latest and recommended versions based on the recommended
-    // major version.
-    $recommended = isset($project['recommended_major'])?$project['recommended_major']:NULL;
-    $recommended_version = NULL;
-    $latest_version = NULL;
-    foreach ($project['releases'] as $release) {
-      //Only consider releases of recommended major version.
-      if ($release['version_major'] == $recommended) {
-        // First release is the latest version.
-        if (!isset($latest_version)) {
-          $latest_version = $release['version'];
-        }
-        // First stable release is the recommended version.
-        if (empty($release['version_extra'])) {
-          if (!isset($recommended_version)) {
-            $recommended_version = $release['version'];
-          }
-        }
+  $recommended_major = @$xml->xpath("/project/recommended_major");
+  $recommended_major = empty($recommended_major)?"":(string)$recommended_major[0];
+  $supported_majors = @$xml->xpath("/project/supported_majors");
+  $supported_majors = empty($supported_majors)?array():array_flip(explode(',', (string)$supported_majors[0]));
+  $releases_xml = @$xml->xpath("/project/releases/release[status='published']");
+  $recommended_version = NULL;
+  $latest_version = NULL;
+  foreach ($releases_xml as $release) {
+    $release_info = array();
+    foreach (array('name', 'version', 'tag', 'version_major', 'version_extra', 'status', 'release_link', 'download_link', 'date', 'mdhash', 'filesize') as $item) {
+      if (array_key_exists($item, $release)) {
+        $value = $release->xpath($item);
+        $release_info[$item] = (string)$value[0];
       }
     }
-    // If no stable release of  recomended major version found, set
-    // latest version as the recommended one.
-    if (!isset($recommended_version)) {
-      $recommended_version = $latest_version;
-    }
-
-    // Iterate the releases to fill in status data.
-    $supported = isset($project['supported_majors'])?explode(',', $project['supported_majors']):array();
-    foreach ($project['releases'] as $version => $release) {
-      $status = array();
-      if (($k = array_search($release['version_major'], $supported)) !== FALSE) {
-        $status[] = dt('Supported');
-        unset($supported[$k]);
-      }
-      if ((isset($recommended_version)) && ($version == $recommended_version)) {
-        $status[] = dt('Recommended');
-        $info[$key]['recommended'] = $version;
-      }
-      if ($release['version_extra'] == 'dev') {
-        $status[] = dt('Development');
-      }
-      // #TODO# Note here we suffer the project<->package-name problem:
-      // Following only works for modules/themes with name with
-      // drupal.org's project name (zen->zen but not for cck->content).
-      // See _drush_pm_releasenotes() for an option to get that info
-      // from update's project data.
-      if (isset($extension_info[$key])) {
-        if ($extension_info[$key]->info['version'] == $version) {
-          $status[] = dt('Installed');
-          $info[$key]['installed'] = $version;
-        }
+    $statuses = array();
+    if (array_key_exists($release_info['version_major'], $supported_majors)) {
+      $statuses[] = "Supported";
+      unset($supported_majors[$release_info['version_major']]);
+    }
+    if ($release_info['version_major'] == $recommended_major) {
+      if (!isset($latest_version)) {
+        $latest_version = $release_info['version'];
+      }
+      // The first stable version (no 'version extra') in the recommended major
+      // is the recommended release
+      if (empty($release_info['version_extra']) && (!isset($recommended_version))) {
+        $statuses[] = "Recommended";
+        $recommended_version = $release_info['version'];
       }
-      if (isset($release['terms']) && array_key_exists('Release type', $release['terms'])) {
-        foreach ($release['terms']['Release type'] as $one_type) {
-          if ($one_type == 'Security update') {
-            $status[] = dt('Security');
+    }
+    if (!empty($release_info['version_extra']) && ($release_info['version_extra'] == "dev")) {
+      $statuses[] = "Development";
+    }
+    foreach ($release->xpath('terms/term/value') as $release_type) {
+      // There are three kinds of release types that we recognize:
+      // "Bug fixes", "New features" and "Security update".
+      // We will add "Security" for security updates, and nothing
+      // for the other kinds.
+      if (strpos($release_type, "Security") !== FALSE) {
+        $statuses[] = "Security";
+      }
+    }
+    // Add to status whether the project is installed.
+    if (isset($installed_projects[$project])) {
+      if ($installed_projects[$project]['version'] == $release_info['version']) {
+         $statuses[] = dt('Installed');
+         $project_info['installed'] = $release_info['version'];
+       }
+    }
+    $release_info['release_status'] = $statuses;
+    $releases[$release_info['version']] = $release_info;
+  }
+  // If there is no -stable- release in the recommended major,
+  // then take the latest verion in the recommended major to be
+  // the recommended release.
+  if (!isset($recommended_version) && isset($latest_version)) {
+    $recommended_version = $latest_version;
+    $releases[$recommended_version]['release_status'][] = "Recommended";
+  }
+
+  $project_info['releases'] = $releases;
+  $project_info['recommended'] = $recommended_version;
+
+  return $project_info;
+}
+
+/**
+ * Helper function for _drush_pm_filter_releases().
+ */
+function _drush_pm_compare_date($a, $b) {
+    if ($a['date'] == $b['date']) {
+        return 0;
+    }
+    if ($a['version_major'] == $b['version_major']) {
+      return ($a['date'] > $b['date']) ? -1 : 1;
+    }
+    return ($a['version_major'] > $b['version_major']) ? -1 : 1;
+}
+
+/**
+ * Filter a list of releases.
+ *
+ * @param $releases
+ *   Array of release information
+ * @param $all
+ *   Show all releases. If FALSE, shows only the first release that is
+ *   Recommended or Supported or Security or Installed.
+ * @param $dev
+ *   Show only development release.
+ * @param $show_all_until_installed
+ *   If TRUE, then all releases will be shown until the INSTALLED release is found,
+ *   at which point the algorithm will stop.
+ */
+function _drush_pm_filter_releases($releases, $all = FALSE, $dev = FALSE, $show_all_until_installed = TRUE) {
+  // Start off by sorting releases by release date.
+  uasort($releases, '_drush_pm_compare_date');
+  // Find version_major for the installed release
+  $installed_version_major = FALSE;
+  foreach ($releases as $version => $release_info) {
+    if (in_array("Installed", $release_info['release_status'])) {
+      $installed_version_major = $release_info['version_major'];
+    }
+  }
+  // Now iterate through and filter out the releases we're
+  // interested in.
+  $options = array();
+  $limits_list = array();
+  foreach ($releases as $version => $release_info) {
+    if (!$dev || ((array_key_exists('version_extra', $release_info)) && ($release_info['version_extra'] == 'dev'))) {
+      $saw_unique_status = FALSE;
+      foreach ($release_info['release_status'] as $one_status) {
+        // We will show the first release of a given kind;
+        // after we show the first security release, we show
+        // no other.  We do this on a per-major-version basis,
+        // though, so if a project has three major versions, then
+        // we will show the first security release from each.
+        // This rule is overridden by $all and $show_all_until_installed.
+        $test_key = $release_info['version_major'] . $one_status;
+        if (!array_key_exists($test_key, $limits_list)) {
+          $limits_list[$test_key] = TRUE;
+          $saw_unique_status = TRUE;
+          // Once we see the "Installed" release we will stop
+          // showing all releases
+          if ($one_status == "Installed") {
+            $show_all_until_installed = FALSE;
+            $installed_release_date = $release_info['date'];
           }
         }
       }
-      $info[$key]['releases'][$version]['release_status'] = $status;
+      if ($all || ($show_all_until_installed && ($installed_version_major == $release_info['version_major'])) || $saw_unique_status) {
+        $options[$release_info['version']] = $release_info;
+      }
     }
   }
+  // If "show all until installed" is still true, that means that
+  // we never encountered the installed release anywhere in releases,
+  // and therefore we did not filter out any releases at all.  If this
+  // is the case, then call ourselves again, this time with
+  // $show_all_until_installed set to FALSE from the beginning.
+  // The other situation we might encounter is when we do not encounter
+  // the installed release, and $options is still empty.  This means
+  // that there were no supported or recommented or security or development
+  // releases found.  If this is the case, then we will force ALL to TRUE
+  // and show everything on the second iteration.
+  if (($all === FALSE) && ($show_all_until_installed === TRUE)) {
+    $options = _drush_pm_filter_releases($releases, empty($options), $dev, FALSE);
+  }
+  return $options;
+}
+
+/**
+ * Return an array of available releases for given project(s).
+ *
+ * Helper function for pm-download.
+ */
+function _drush_pm_download_releases_choice($xml, $project, $all = FALSE, $dev = FALSE) {
+  $project_info = _drush_pm_get_releases_from_xml($xml, $project);
+  $releases = _drush_pm_filter_releases($project_info['releases'], $all, $dev);
+
+  $options = array();
+  foreach($releases as $version => $release) {
+    $options[$version] = array($version, '-', gmdate('Y-M-d', $release['date']), '-', implode(', ', $release['release_status']));
+  }
+  return $options;
+}
+
+/**
+ * Obtain releases info for given projects and fill in status information.
+ *
+ * It does connect directly to the update service and does not depend on
+ * a bootstraped site.
+ *
+ * @param $requests
+ *   An array of drupal.org project names optionally with a version.
+ *
+ * @see drush_pm_releases()
+ * @see _drush_pm_releasenotes()
+ */
+function _drush_pm_get_releases($requests) {
+  $info = array();
+
+  // Parse out project name and version.
+  $requests = pm_parse_project_version($requests);
+
+  // Get release history for each request.
+  foreach ($requests as $name => $request) {
+    $xml = _drush_pm_get_release_history_xml($request);
+    if (!$xml) {
+      continue;
+    }
 
+    $project_info = _drush_pm_get_releases_from_xml($xml, $name);
+    $info[$name] = $project_info;
+  }
   return $info;
 }
 
@@ -1041,10 +1408,16 @@ function drush_pm_releasenotes() {
  *   An array of drupal.org project names optionally with a version.
  * @param $print_status
  *   Boolean. Used by pm-download to not print a informative note.
+ * @param $tmpfile
+ *   If provided, a file that contains contents to show before the
+ *   release notes.
  *
  * @see drush_pm_releasenotes()
  */
-function _drush_pm_releasenotes($requests, $print_status = TRUE) {
+function _drush_pm_releasenotes($requests, $print_status = TRUE, $tmpfile = NULL) {
+  if ($tmpfile == NULL) {
+    $tmpfile = drush_tempnam('rln-' . implode('-', $requests) . '.');
+  }
   // Parse requests to strip versions.
   $requests = pm_parse_project_version($requests);
   // Get the releases.
@@ -1055,26 +1428,18 @@ function _drush_pm_releasenotes($requests, $print_status = TRUE) {
 
   foreach ($info as $key => $project) {
     $selected_versions = array();
-    // #TODO# project<->package-name problem. See _drush_pm_get_releases().
-    if (!isset($project['installed'])) {
-      // Installed package's version (e.g. cck) is detected by
-      // _drush_pm_get_releases(). Attempted to obtain information
-      // about it from update_cache.
-      $cache_project_info = _update_cache_get('update_project_projects');
-      if (isset($cache_project_info->data[$key])) {
-        $project['installed'] = $cache_project_info->data[$key]['info']['version'];
-      }
-    }
     // If the request included version, only show its release notes.
     if (isset($requests[$key]['version'])) {
       $selected_versions[] = $requests[$key]['version'];
     }
     else {
-      // Special handling if the project is installed. 
+      // Special handling if the project is installed.
       if (isset($project['recommended'], $project['installed'])) {
         $releases = array_reverse($project['releases']);
         foreach($releases as $version => $release) {
           if ($release['date'] >= $project['releases'][$project['installed']]['date']) {
+            $release += array('version_extra' => '');
+            $project['releases'][$project['installed']] += array('version_extra' => '');
             if ($release['version_extra'] == 'dev' && $project['releases'][$project['installed']]['version_extra'] != 'dev') {
               continue;
             }
@@ -1088,7 +1453,7 @@ function _drush_pm_releasenotes($requests, $print_status = TRUE) {
         $selected_versions[] = $project['recommended'];
       }
     }
-    
+
     foreach ($selected_versions as $version) {
       // Stage of parsing.
       if (!isset($project['releases'][$version]['release_link'])) {
@@ -1111,12 +1476,24 @@ function _drush_pm_releasenotes($requests, $print_status = TRUE) {
           continue;
         }
       }
-      $data = drupal_http_request($release_page_url);
-      if (isset($data->error)) {
-        drush_log(dt("Error (!error) while requesting the release notes' page for !project project.", array('!error' => $data->error, '!project' => $key)), 'error');
-        continue;
+      // We'll use drupal_http_request if available; it provides better error reporting.
+      if (function_exists('drupal_http_request')) {
+        $data = drupal_http_request($release_page_url);
+        if (isset($data->error)) {
+          drush_log(dt("Error (!error) while requesting the release notes page for !project project.", array('!error' => $data->error, '!project' => $key)), 'error');
+          continue;
+        }
+        @$dom = DOMDocument::loadHTML($data->data);
+      }
+      else {
+        $filename = _drush_download_file($release_page_url);
+        @$dom = DOMDocument::loadHTMLFile($filename);
+        @unlink($filename);
+        if ($dom === FALSE) {
+          drush_log(dt("Error while requesting the release notes page for !project project.", array('!project' => $key)), 'error');
+          continue;
+        }
       }
-      @$dom = DOMDocument::loadHTML($data->data);
       if ($dom) {
         drush_log(dt("Successfully parsed and loaded the HTML contained in the release notes' page for !project (!version) project.", array('!project' => $key, '!version' => $version)), 'notice');
       }
@@ -1128,51 +1505,28 @@ function _drush_pm_releasenotes($requests, $print_status = TRUE) {
       $notes_last_update = $node_content[0]->div[1]->div[0]->asXML();
       unset($node_content[0]->div);
       $project_notes = $node_content[0]->asXML();
-      if (isset($project['installed'])) {
-        if (isset($request['version'])) {
-          $status_msg = 'Note: type in only the project name to see the release notes for all newer versions.';
-        }
-        else {
-          if ($version == $project['installed']) {
-            $status_msg = 'Note: this is the installed version.';
-            if ($version == $project['recommended']) {
-              $status_msg = 'Note: this is the installed & recommended version.';
-            }
-          }
-          elseif ($version == $project['recommended']) {
-            $status_msg = 'Note: this is the recommended version.';
-          }
-          else {
-            $status_msg = dt('Note: the installed version is !version.', array('!version' => $project['installed']));
-          }
-        }
-      }
-      else {
-        $status_msg = 'Note: specific non-installed version.';
-        if (!isset($request['version'])) {
-          $status_msg = 'Note: recommended non-installed version.';
-        }
-      }
-      // #TODO# d5 compatibility && try a cleaner way to do this.
-      if (drush_drupal_major_version() < 7) {
-        $break = '<br>';
-        $status_msg = '> ' . $status_msg;
+
+      // Build the status message from the info from _drush_pm_get_releases
+      $status_msg = '> ' . implode(', ', $project['releases'][$version]['release_status']);
+      $break = '<br>';
+      $notes_header = dt("<hr>
+ > RELEASE NOTES FOR '!name' PROJECT, VERSION !version:!break
+ > !time.!break
+ !status
+<hr>
+", array('!status' => $print_status ? $status_msg : '', '!name' => strtoupper($key), '!break' => $break, '!version' => $version, '!time' => $notes_last_update));
+      // Finally we print the release notes for the requested project.
+      if (drush_get_option('html', FALSE)) {
+        $print = $notes_header . $project_notes;
       }
       else {
-        $break = ' -<hr>';
-        $status_msg = '> ' . $status_msg . ' -<hr>';
+        $print = drush_html_to_text($notes_header . $project_notes . "\n", array('br', 'p', 'ul', 'ol', 'li', 'hr'));
+        if (drush_drupal_major_version() < 7) { $print .= "\n"; }
       }
-      $notes_header = dt("<hr>
-        > RELEASE NOTES FOR '!name' PROJECT, VERSION !version:!break
-        > !time.!break
-        !status
-        <hr>", array('!status' => $print_status ? $status_msg : '', '!name' => strtoupper($key), '!break' => $break, '!version' => $version, '!time' => $notes_last_update));
-      // Finally we print the release notes for the requested project.
-      $print = drupal_html_to_text($notes_header . $project_notes, array('br', 'p', 'ul', 'ol', 'li', 'hr'));
-      drush_print($print);
-      if (drush_drupal_major_version() < 7) {drush_print();}
+      file_put_contents($tmpfile, $print, FILE_APPEND);
     }
   }
+  drush_print_file($tmpfile);
 }
 
 /**
@@ -1189,23 +1543,10 @@ function drush_pm_refresh() {
  * Command callback. Execute pm-update.
  */
 function drush_pm_update() {
-  // Signal that we will update drush core after the drush modules
-  // are updated, if an update to core is available.
-  drush_set_context('DRUSH_PM_UPDATE_ALL', TRUE);
-
   // Call pm-updatecode.  updatedb will be called in the post-update process.
   $args = _convert_csv_to_array(func_get_args());
   array_unshift($args, 'pm-updatecode');
-  call_user_func_array('drush_invoke', $args);
-
-  // pm-updatecode will not do a core update of Drupal
-  // on the same invocation where non-core modules are
-  // updated.  If there is a core update available, then
-  // call pm-updatecode a second time to update core
-  // (but only if the first run finished successfully).
-  if (drush_get_context('DRUSH_PM_CORE_UPDATE_AVAILABLE', FALSE) && (drush_get_error() == DRUSH_SUCCESS)) {
-    call_user_func_array('drush_invoke', array('pm-updatecode', 'drupal'));
-  }
+  return call_user_func_array('drush_invoke', $args);
 }
 
 /**
@@ -1214,38 +1555,51 @@ function drush_pm_update() {
  */
 function drush_pm_post_pm_update() {
   // Use drush_backend_invoke to start a subprocess. Cleaner that way.
-  drush_backend_invoke('updatedb');
+  if (drush_get_context('DRUSH_PM_UPDATED', FALSE) !== FALSE) {
+    drush_backend_invoke('updatedb');
+  }
 }
 
 /**
- * Validate callback for updatecode command. Abort if 'backup' folder exists.
+ * Validate callback for updatecode command. Abort if 'backup' directory exists.
  */
 function drush_pm_updatecode_validate() {
-  $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
-  if (is_dir($drupal_root . '/' . 'backup')) {
-    return drush_set_error('DRUSH_PM_BACKUP_DIR_FORBIDDEN', dt('It\'s a security risk to have a backup folder in your Drupal root. You must move it elsewhere before proceeding.'));
+  $path = drush_get_context('DRUSH_DRUPAL_ROOT') . '/backup';
+  if (is_dir($path) && (realpath(drush_get_option('backup-dir', FALSE)) != $path)) {
+    return drush_set_error('', dt('Backup directory !path found. It\'s a security risk to store backups inside the Drupal tree. Drush now uses by default ~/drush-backups. You need to move !path out of the Drupal tree to proceed. Note: if you know what you\'re doing you can explicitly set --backup-dir to !path and continue.', array('!path' => $path)));
   }
+
+  // Validate package-handler.
+  $package_handler = drush_get_option('package-handler', 'wget');
+  drush_include_engine('package_handler', $package_handler);
+  return package_handler_validate();
 }
 
 /**
  * Post-command callback for updatecode.
  *
- * Execute pm-updatecode-notify-pending-db-updates in a backend process to not
- * conflict with old code already in memory.
+ * Execute pm-updatecode-postupdate in a backend process to not conflict with
+ * old code already in memory.
  */
 function drush_pm_post_pm_updatecode() {
   // Skip if updatecode was invoked by pm-update.
   // This way we avoid being noisy, as updatedb is to be executed.
   $command = drush_get_command();
   if ($command['command'] != 'pm-update') {
-    drush_backend_invoke('pm-updatecode-notify-pending-db-updates');
+    if (drush_get_context('DRUSH_PM_UPDATED', FALSE) !== FALSE) {
+      drush_backend_invoke('pm-updatecode-postupdate');
+    }
   }
 }
 
 /**
- * Command callback. Execute updatecode-notify-pending-db-updates.
+ * Command callback. Execute updatecode-postupdate.
  */
-function drush_pm_updatecode_notify_pending_db_updates() {
+function drush_pm_updatecode_postupdate() {
+  // Clear the cache, since some projects could have moved around.
+  drush_drupal_cache_clear_all();
+
+  // Notify of pending database updates.
   // Make sure the installation API is available
   require_once drush_get_context('DRUSH_DRUPAL_ROOT') . '/includes/install.inc';
 
@@ -1253,12 +1607,12 @@ function drush_pm_updatecode_notify_pending_db_updates() {
   drupal_load_updates();
 
   // @see system_requirements().
-  foreach (module_list() as $module) {
+  foreach (pm_module_list() as $module) {
     $updates = drupal_get_schema_versions($module);
     if ($updates !== FALSE) {
       $default = drupal_get_installed_schema_version($module);
       if (max($updates) > $default) {
-        drush_log(dt("You have pending database updates. Please run `drush updatedb` or visit update.php in your browser."), 'warning');
+        drush_log(dt("You have pending database updates. Run `drush updatedb` or visit update.php in your browser."), 'warning');
         break;
       }
     }
@@ -1285,7 +1639,6 @@ function pm_dl_destination_lookup($type, $drupal_root, $sitepath, $create = FALS
     case 'theme engine':
       $destination = $sitepath . '/themes/engines';
       break;
-    //case 'translation': We never hit this case.
     case 'profile':
       $destination = $drupal_root . '/profiles';
       break;
@@ -1358,6 +1711,68 @@ function pm_dl_destination($type) {
   return $destination;
 }
 
+/*
+ * Pick most appropriate release from XML list.
+ *
+ * @param array $request
+ *   An array of version specifications as returned by pm_parse_project_version().
+ * @param resource $xml
+ *   A handle to the XML document.
+ */
+function pm_parse_release($request, $xml) {
+  if (!empty($request['version'])) {
+    $releases = $xml->xpath("/project/releases/release[status='published'][version='" . $request['version'] . "']");
+    if (empty($releases)) {
+      drush_log(dt("Could not locate specified project version, downloading latest stable version"), 'warning');
+    }
+  }
+  // If that did not work, we will get the first published release for the
+  // recommended major version.
+  if (empty($releases)) {
+    if ($recommended_major = $xml->xpath("/project/recommended_major")) {
+      $xpath_releases = "/project/releases/release[status='published'][version_major=" . (string)$recommended_major[0] . "]";
+      $releases = @$xml->xpath($xpath_releases);
+    }
+  }
+  // If there are recommended releases (no 'version_extra' elements), then use
+  // only recommended releases.  Otherwise, use all; in this case, the
+  // recommended release defaults to the latest published release with the
+  // right recommended major version number.
+  $recommended_releases = array();
+  if (!empty($releases)) {
+    foreach ($releases as $one_release) {
+      if (!array_key_exists('version_extra', $one_release)) {
+        $recommended_releases[] = $one_release;
+      }
+    }
+  }
+  if (!empty($recommended_releases)) {
+    $releases = $recommended_releases;
+  }
+  $release_type = 'recommended';
+  if (drush_get_option('dev', FALSE)) {
+    $releases = @$xml->xpath("/project/releases/release[status='published'][version_extra='dev']");
+    $release_type = 'development';
+  }
+  if (drush_get_option('select', FALSE) || empty($releases)) {
+    if (empty($releases)) {
+      drush_print(dt('There is no !type release for project !project.', array('!type' => $release_type, '!project' => $request['name'])));
+    }
+    $options = _drush_pm_download_releases_choice($xml, $request['name'], drush_get_option('all', FALSE), drush_get_option('dev', FALSE));
+    $choice = drush_choice($options, dt('Choose one of the available releases:'));
+    if ($choice) {
+      $releases = $xml->xpath("/project/releases/release[status='published'][version='" . $choice . "']");
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  // First published release for the recommended major version is just the
+  // first value in $releases.
+  return (array)$releases[0];
+}
+
 /**
  * Parse out the project name and version and return as a structured array
  *
@@ -1365,11 +1780,8 @@ function pm_dl_destination($type) {
  */
 function pm_parse_project_version($requests) {
   $requestdata = array();
-  $drupal_version_default = drush_get_context('DRUSH_DRUPAL_MAJOR_VERSION', 6) . '.x';
-  // ignore-bootstrap is a temporary hack. You can't currently download a 7.x
-  // module after bootstrapping a 6.x site. This is needed by core-upgrade.
-  // Related to http://drupal.org/node/463110.
-  $drupal_bootstrap = drush_get_option('bootstrap_cancel') ? !drush_get_option('bootstrap_cancel') : drush_get_context('DRUSH_BOOTSTRAP_PHASE') > 0;
+  $drupal_version_default = drush_get_context('DRUSH_DRUPAL_MAJOR_VERSION', drush_get_option('default-major',7)) . '.x';
+  $drupal_bootstrap = drush_get_context('DRUSH_BOOTSTRAP_PHASE') > 0;
   foreach($requests as $request) {
     $drupal_version = $drupal_version_default;
     $project_version = NULL;
@@ -1383,7 +1795,7 @@ function pm_parse_project_version($requests) {
       $project = trim(substr($request, 0, strlen($request) - strlen($matches[0])), ' -');
 
       if ($matches[1] == 'HEAD' || $matches[2] == 'HEAD') {
-        drush_set_error('DRUSH_PM_HEAD', 'Can\'t download HEAD releases because Drupal.org project information only provides for numbered release nodes.');
+        drush_log('DRUSH_PM_HEAD', 'Can\'t download HEAD releases because Drupal.org project information only provides for numbered release nodes.', 'warning');
         continue;
       }
       if (!empty($matches[2])) {
@@ -1407,6 +1819,12 @@ function pm_parse_project_version($requests) {
         }
       }
     }
+    // special checking for 'drupal-VERSION', == drupal latest stable release
+    elseif ((substr($request,0,7) == 'drupal-') && (is_numeric(substr($request,7)))) {
+      $project = 'drupal';
+      $drupal_version = substr($request,7) . '.x';
+      $project_version = $version;
+    }
     if ($project_version) {
       if ($project == 'drupal') {
         // For project Drupal, ensure the major version branch is correct, so
@@ -1434,12 +1852,12 @@ function pm_parse_project_version($requests) {
 function pm_project_types() {
   // Lookup the 'Project type' vocabulary to some standard strings.
   $types = array(
-    'core' => 'Drupal project',
+    'core' => 'Drupal core',
     'profile' => 'Installation profiles',
     'module' => 'Modules',
     'theme' => 'Themes',
     'theme engine' => 'Theme engines',
-    'translation' => 'Translations',
+    'translation' => 'Translations'
   );
   return $types;
 }
@@ -1452,13 +1870,13 @@ function pm_drush_engine_package_handler() {
     'wget' => array(),
     'cvs' => array(
       'options' => array(
-        '--package-handler=cvs' => 'Use CVS to checkout and update projects.',
+        'package-handler=cvs' => 'Use CVS to checkout and update projects.',
       ),
       'sub-options' => array(
-        '--package-handler=cvs' => array(
-          '--cvsparams' => 'Add options to the `cvs` program',
-          '--cvsmethod' => 'Force cvs updates or checkouts (checkout is default unless the directory is managed by a supported version control system).',
-          '--cvscredentials' => 'A username and password that is sent for cvs checkout command. Defaults to anonymous:anonymous',
+        'package-handler=cvs' => array(
+          'cvsparams' => 'Add options to the `cvs` program',
+          'cvsmethod' => 'Force cvs updates or checkouts (checkout is default unless the directory is managed by a supported version control system).',
+          'cvscredentials' => 'A username and password that is sent for cvs checkout command. Defaults to anonymous:anonymous',
         ),
       ),
       'examples' => array(
@@ -1469,8 +1887,19 @@ function pm_drush_engine_package_handler() {
     ),
     'git_drupalorg' => array(
       'options' => array(
-        '--package-handler=git_drupalorg' => 'Use git.drupal.org to checkout and update projects.',
-        '--gitsubmodule' => 'Use git submodules for checking out new projects. Existing git checkouts are unaffected, and will continue to (not) use submodules regardless of this setting.',
+        'package-handler=git_drupalorg' => 'Use git.drupal.org to checkout and update projects.',
+      ),
+      'sub-options' => array(
+        'package-handler=git_drupalorg' => array(
+          'gitusername' => 'Your git username as shown on user/[uid]/edit/git. Typically, this is set this in drushrc.php. Omitting this prevents users from pushing changes back to git.drupal.org.',
+          'gitsubmodule' => 'Use git submodules for checking out new projects. Existing git checkouts are unaffected, and will continue to (not) use submodules regardless of this setting.',
+          'gitcheckoutparams' => 'Add options to the `git checkout` command.',
+          'gitcloneparams' => 'Add options to the `git clone` command.',
+          'gitfetchparams' => 'Add options to the `git fetch` command.',
+          'gitpullparams' => 'Add options to the `git pull` command.',
+          'gitsubmoduleaddparams' => 'Add options to the `git submodule add` command.',
+          'cache' => 'Use a local git cache and clone projects using --reference.',
+        ),
       ),
     ),
   );
@@ -1483,49 +1912,54 @@ function pm_drush_engine_version_control() {
   return array(
     'backup' => array(
       'options' => array(
-        '--version-control=backup' => 'Default engine. Backup all project files before updates.',
+        'version-control=backup' => 'Default engine. Backup all project files before updates.',
       ),
       'sub-options' => array(
-        '--version-control=backup' => array(
-          '--backup-dir' => 'Specify a directory to backup packages into. Defaults to .drush-backups within the home directory of the user running the command. It is forbidden to specify a directory inside your drupal root.',
+        'version-control=backup' => array(
+          'no-backup' => 'Do not perform backups.',
+          'backup-dir' => 'Specify a directory to backup projects into. Defaults to drush-backups within the home directory of the user running the command. It is forbidden to specify a directory inside your drupal root.',
         ),
       ),
     ),
-    'svn' => array(
-      'signature' => 'svn info %s',
+    'bzr' => array(
+      'signature' => 'bzr root %s',
       'options' => array(
-        '--version-control=svn' => 'Quickly add/remove/commit your project changes to Subversion.',
+        'version-control=bzr' => 'Quickly add/remove/commit your project changes to Bazaar.',
       ),
       'sub-options' => array(
-        '--version-control=svn' => array(
-          '--svnsync' => 'Automatically add new files to the SVN repository and remove deleted files. Caution.',
-          '--svncommit' => 'Automatically commit changes to SVN repository. You must also using the --svnsync option.',
-          '--svnmessage' => 'Override default commit message which is: Drush automatic commit: <the drush command line used>',
-          '--svnstatusparams' => "Add options to the 'svn status' command",
-          '--svnaddparams' => 'Add options to the `svn add` command',
-          '--svnremoveparams' => 'Add options to the `svn remove` command',
-          '--svnrevertparams' => 'Add options to the `svn revert` command',
-          '--svncommitparams' => 'Add options to the `svn commit` command',
+        'version-control=bzr' => array(
+          'bzrsync' => 'Automatically add new files to the Bazaar repository and remove deleted files. Caution.',
+          'bzrcommit' => 'Automatically commit changes to Bazaar repository. You must also usw the --bzrsync option.',
         ),
+        'bzrcommit' => array(
+          'bzrmessage' => 'Override default commit message which is: Drush automatic commit. Project <name> <type> Command: <the drush command line used>',
+        )
       ),
       'examples' => array(
-        'drush [command] cck --svncommitparams=\"--username joe\"' =>  'Commit changes as the user \'joe\' (Quotes are required).'
+        'drush dl cck --version-control=bzr --bzrsync --bzrcommit' =>  'Download the cck project and then add it and commit it to Bazaar.'
       ),
     ),
-    'bzr' => array(
-      'signature' => 'bzr root %s',
+    'svn' => array(
+      'signature' => 'svn info %s',
       'options' => array(
-        '--version-control=bzr' => 'Quickly add/remove/commit your project changes to Bazaar.',
+        'version-control=svn' => 'Quickly add/remove/commit your project changes to Subversion.',
       ),
       'sub-options' => array(
-        '--version-control=bzr' => array(
-          '--bzrsync' => 'Automatically add new files to the Bazaar repository and remove deleted files. Caution.',
-          '--bzrcommit' => 'Automatically commit changes to Bazaar repository. You must also using the --bzrsync option.',
-          '  --bzrmessage' => 'Override default commit message which is: Drush automatic commit. Project <name> <type> Command: <the drush command line used>',
+        'version-control=svn' => array(
+          'svnsync' => 'Automatically add new files to the SVN repository and remove deleted files. Caution.',
+          'svncommit' => 'Automatically commit changes to SVN repository. You must also using the --svnsync option.',
+          'svnstatusparams' => "Add options to the 'svn status' command",
+          'svnaddparams' => 'Add options to the `svn add` command',
+          'svnremoveparams' => 'Add options to the `svn remove` command',
+          'svnrevertparams' => 'Add options to the `svn revert` command',
+          'svncommitparams' => 'Add options to the `svn commit` command',
         ),
+        'svncommit' => array(
+          'svnmessage' => 'Override default commit message which is: Drush automatic commit: <the drush command line used>',
+        )
       ),
       'examples' => array(
-        'drush dl cck --version-control=bzr --bzrsync --bzrcommit' =>  'Download the cck module and then add it and commit it to Bazaar.'
+        'drush [command] cck --svncommitparams=\"--username joe\"' =>  'Commit changes as the user \'joe\' (Quotes are required).'
       ),
     ),
   );
@@ -1541,6 +1975,7 @@ interface drush_pm_version_control {
   function rollback($project);
   function post_update($project);
   function post_download($project);
+  static function reserved_files();
 }
 
 /**
@@ -1549,8 +1984,16 @@ interface drush_pm_version_control {
  * specific directory.
  */
 function drush_pm_include_version_control($directory = '.') {
-  $version_controls = explode(',', drush_get_option('version-control', 'svn,backup,bzr'));
   $version_control_engines = drush_get_engines('version_control');
+  $version_controls = drush_get_option('version-control', FALSE);
+  // If no version control was given, use a list of defaults.
+  if (!$version_controls) {
+    // Backup engine is the last option.
+    $version_controls = array_reverse(array_keys($version_control_engines));
+  }
+  else {
+    $version_controls = array($version_controls);
+  }
 
   // Find the first valid engine in the list, checking signatures if needed.
   $engine = FALSE;
@@ -1558,6 +2001,7 @@ function drush_pm_include_version_control($directory = '.') {
     $version_control = array_shift($version_controls);
     if (isset($version_control_engines[$version_control])) {
       if (!empty($version_control_engines[$version_control]['signature'])) {
+        drush_log(dt('Verifying signature for !vcs version control engine.', array('!vcs' => $version_control)), 'debug');
         if (drush_shell_exec($version_control_engines[$version_control]['signature'], $directory)) {
           $engine = $version_control;
         }
@@ -1570,22 +2014,12 @@ function drush_pm_include_version_control($directory = '.') {
   if (!$engine) {
     return drush_set_error('DRUSH_PM_NO_VERSION_CONTROL', dt('No valid version control or backup engine found (the --version-control option was set to "!version-control").', array('!version-control' => $version_control)));
   }
-  if (!drush_include_engine('version_control', $engine)) {
-    return FALSE;
-  }
-  $engine = 'drush_pm_version_control_' . $engine;
-  return new $engine();
-}
 
-/**
- * Implementation of drush_COMMAND_init().
- *
- * pm-download doesn't require any bootstrap level to operate but it needs to
- * know if running on a drupal directory in order to select the best location
- * for projects to download.
- */
-function drush_pm_download_init() {
-  drush_bootstrap_max();
+  drush_include_engine('version_control', $version_control);
+  $class = 'drush_pm_version_control_' . $engine;
+  $instance = new $class();
+  $instance->engine = $engine;
+  return $instance;
 }
 
 /**
@@ -1619,25 +2053,25 @@ function drush_pm_download_validate() {
   // Validate --variant or enforce a sane default.
   $variant = drush_get_option('variant', FALSE);
   if ($variant) {
-    if (!in_array($variant, array('core', 'no-core', 'make'))) {
+    if (!in_array($variant, array('full', 'projects', 'profile-only'))) {
       drush_log(dt('Unknown variant !variant. Valid values: !variations', array('!variant' => $variant, '!variations' => implode(', ', $variations))), 'error');
     }
   }
-  // core and no-core variants are only valid for wget package handler.
+  // full and projects variants are only valid for wget package handler.
   $package_handler = drush_get_option('package-handler', 'wget');
-  if (($package_handler != 'wget') && ($variant != 'make')) {
-    $new_variant = 'make';
+  if (($package_handler != 'wget') && ($variant != 'profile-only')) {
+    $new_variant = 'profile-only';
     if ($variant) {
       drush_log(dt('Variant !variant is incompatible with !ph package-handler.', array('!variant' => $variant, '!ph' => $package_handler)), 'warning');
     }
   }
-  // If we are working on a drupal root, core variant is not an option.
+  // If we are working on a drupal root, full variant is not an option.
   else if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') >= DRUSH_BOOTSTRAP_DRUPAL_ROOT) {
-    if ((!$variant) || (($variant == 'core') && (!isset($new_variant)))) {
-      $new_variant = 'no-core';
+    if ((!$variant) || (($variant == 'full') && (!isset($new_variant)))) {
+      $new_variant = 'projects';
     }
-    if ($variant == 'core') {
-      drush_log(dt('Variant core is not a valid option within a Drupal root.'), 'warning');
+    if ($variant == 'full') {
+      drush_log(dt('Variant full is not a valid option within a Drupal root.'), 'warning');
     }
   }
 
@@ -1647,27 +2081,44 @@ function drush_pm_download_validate() {
       drush_log(dt('Switching to --variant=!variant.', array('!variant' => $new_variant)), 'ok');
     }
   }
-  
-  // At present we depend on update module to show release notes.
-  $notes = TRUE;
-  if (drush_get_option('notes', FALSE)) {
-    $update = 'update';
-    if (drush_drupal_major_version() == 5) {
-      $update = 'update_status';
-    }  
-    if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') < DRUSH_BOOTSTRAP_DRUPAL_FULL) {
-      $msg = dt('A higher bootstrap level is needed to show release notes.');
-      $notes = FALSE;
-    }
-    elseif (!module_exists($update)) {
-      $msg = dt('!module is required to show release notes.', array('!module' => $update));
-      $notes = FALSE;
-    }
-    if (!$notes) {
-      drush_log($msg . ' ' . dt('Disabling --notes option.'), 'warning');
-      drush_set_option('notes', FALSE);
-    }
+
+  // Validate package-handler.
+  $package_handler = drush_get_option('package-handler', 'wget');
+  drush_include_engine('package_handler', $package_handler);
+  // Return value not currently used.
+  return package_handler_validate();
+}
+
+/**
+ * Download the release history xml for the specified request.
+ */
+function _drush_pm_get_release_history_xml($request) {
+  // Don't rely on UPDATE_DEFAULT_URL since perhaps we are not fully
+  // bootstrapped.
+  $url = drush_get_option('source', 'http://updates.drupal.org/release-history') . '/' . $request['name'] . '/' . $request['drupal_version'];
+  drush_log('Downloading release history from ' . $url);
+  // Some hosts have allow_url_fopen disabled.
+  if (!$xml = @simplexml_load_file($url)) {
+    $filename = _drush_download_file($url);
+    $xml = simplexml_load_file($filename);
+    drush_op('unlink', $filename);
+  }
+  if (!$xml) {
+    // We are not getting here since drupal.org always serves an XML response.
+    return drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt('Could not download project status information from !url', array('!url' => $url)));
+  }
+  if ($error = $xml->xpath('/error')) {
+    // Don't set an error here since it stops processing during site-upgrade.
+    drush_log($error[0], 'warning'); // 'DRUSH_PM_COULD_NOT_LOAD_UPDATE_FILE',
+    return FALSE;
   }
+  // Unpublished project?
+  $project_status = $xml->xpath('/project/project_status');
+  if ($project_status[0][0] == 'unpublished') {
+    return drush_set_error('DRUSH_PM_PROJECT_UNPUBLISHED', dt("Project !project is unpublished and has no releases available.", array('!project' => $request['name'])), 'warning');
+  }
+
+  return $xml;
 }
 
 /**
@@ -1688,66 +2139,15 @@ function drush_pm_download() {
   $project_types = pm_project_types();
   $project_types_xpath = '(value="' . implode('" or value="', $project_types) . '")';
   foreach ($requests as $name => $request) {
-    // Cleanup. We need to unset those variables to avoid using garbage from
-    // previous iteration.
-    unset($error, $release, $releases, $types);
-
-    // Don't rely on UPDATE_DEFAULT_URL since perhaps we are not fully
-    // bootstrapped.
-    $url = drush_get_option('source', 'http://updates.drupal.org/release-history') . '/' . $request['name'] . '/' . $request['drupal_version'];
-    drush_log('Downloading release history from ' . $url);
-    // Some hosts have allow_url_fopen disabled.
-    if (!$xml = @simplexml_load_file($url)) {
-      if (!drush_shell_exec("wget $url")) {
-        drush_shell_exec("curl -O $url");
-      }
-      $filename = explode('/', $url);
-      $filename = array_pop($filename);
-      $xml = simplexml_load_file($filename);
-      drush_op('unlink', $filename);
-    }
+    $xml = _drush_pm_get_release_history_xml($request);
     if (!$xml) {
-      // We are not getting here since drupal.org always serves an XML response.
-      drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt('Could not download project status information from !url', array('!url' => $url)));
-      continue;
-    }
-    if ($error = $xml->xpath('/error')) {
-      drush_set_error('DRUSH_PM_COULD_NOT_LOAD_UPDATE_FILE', $error[0]);
       continue;
     }
 
-    // Try to get the specified release.
-    if (!empty($request['version'])) {
-      $releases = $xml->xpath("/project/releases/release[status='published'][version='" . $request['version'] . "']");
-      if (empty($releases)) {
-        drush_log(dt("Could not locate specified project version, downloading latest stable version"), 'warning');
-      }
-    }
-    // If that did not work, we will get the first published release for the
-    // recommended major version.
-    if (empty($releases)) {
-      if ($recommended_major = $xml->xpath("/project/recommended_major")) {
-        $xpath_releases = "/project/releases/release[status='published'][version_major=" . (string)$recommended_major[0] . "]";
-        $releases = @$xml->xpath($xpath_releases);
-      }
-    }
-    // If there are recommended releases (no 'version_extra' elements), then use
-    // only recommended releases.  Otherwise, use all; in this case, the
-    // recommended release defaults to the latest published release with the
-    // right recommended major version number.
-    $recommended_releases = array();
-    if (!empty($releases)) {
-      foreach ($releases as $one_release) {
-        if (!array_key_exists('version_extra', $one_release)) {
-          $recommended_releases[] = $one_release;
-        }
-      }
-    }
-    if (!empty($recommended_releases)) {
-      $releases = $recommended_releases;
-    }
-    if (empty($releases)) {
-      drush_log(dt('There is no *recommended* release for project !project on Drupal !drupal_version. Ask the maintainer to review http://drupal.org/node/197584 and create/recommend a release in order to be compatible with drush and the drupal.org security broadcast system. A recommended development snapshot release is sufficient. Alternatively, run pm-releases command and explicity pm-download any non-recommended release that might be available.', array('!drupal_version' => $request['drupal_version'], '!project' => $request['name'])), 'ok');
+    // Identify the most appropriate release.
+    $release = pm_parse_release($request, $xml);
+
+    if (!$release) {
       continue;
     }
 
@@ -1757,23 +2157,10 @@ function drush_pm_download() {
       $request['project_type'] = array_search($types[0]->value, $project_types);
     }
 
-    // First published release for the recommended major version is just the
-    // first value in $releases.  Special case for profiles, that have 3
-    // variants(releases) for a given real release.
-    if ($request['project_type'] == 'profile') {
-      // Variants always come in a fixed order in releases list.
-      $variations = array('core', 'no-core', 'make');
-      $variant = drush_get_option('variant', 'core');
-      $release = (array)$releases[array_search($variant, $variations)];
-    }
-    // Translations can't be obtained from cvs.
-    else if (($request['project_type'] == 'translation') && ($package_handler != 'wget')) {
-      drush_log(dt('Requested project !request is a translation package and can\'t be obtained from !ph.', array('!request' => $request['name'], '!ph' => $package_handler)), 'error');
+    if ($request['project_type'] == 'translation') {
+      drush_set_error('DRUSH_PM_DOWNLOAD_TRANSLATIONS_FORBIDDEN', dt('Drush has dropped support for downloading translation projects. See l10n_update and l10n_install projects.'));
       continue;
     }
-    else {
-      $release = (array)$releases[0];
-    }
 
     // Determine the name of the directory that will contain the project.
     // We face here all the asymetries to make it smooth for package handlers.
@@ -1803,31 +2190,11 @@ function drush_pm_download() {
     $request['base_project_path'] = drush_tempdir();
     $request['full_project_path'] = $request['base_project_path'] .'/'. $request['project_dir'];
     drush_log(dt('Downloading project !name to !dir ...', array('!name' => $request['name'], '!dir' => $request['base_project_path'])));
-    if (!package_handler_install_project($request, $release)) {
+    if (!package_handler_download_project($request, $release)) {
       drush_log('Error downloading '.$request['name']);
       continue;
     }
 
-    // Special case: translation projects. Content of .tar.gz is not within a
-    // common directory.
-    if ($request['project_type'] == 'translation') {
-      // If bootstrapped, copy the translation files over the drupal root and
-      // we are done.
-      if (defined('DRUPAL_ROOT')) {
-        drush_shell_exec('cp -r ' . $request['base_project_path'] . '/* ' . DRUPAL_ROOT);
-        drush_log(dt("Translation !project (!version) decompressed over !dest.", array('!project' => $request['name'], '!version' => $release['version'], '!dest' => DRUPAL_ROOT)), 'success');
-        continue;
-      }
-      else {
-        // Move to its own directory, as any other project.
-        $olddir = drush_cwd();
-        chdir($request['base_project_path']);
-        drush_shell_exec('mkdir ' . $request['project_dir']);
-        drush_shell_exec('mv * ' . $request['project_dir']);
-        chdir($olddir);
-      }
-    }
-
     // Determine the install location for the project.  User provided
     // --destination has preference.
     $destination = drush_get_option('destination');
@@ -1840,9 +2207,12 @@ function drush_pm_download() {
 
     // If user did not provide --destination, then call the
     // download-destination-alter hook to give the chance to any commandfiles
-    // to adjust the install location.
+    // to adjust the install location or abort it.
     if (empty($destination)) {
-      drush_command_invoke_all_ref('drush_pm_download_destination_alter', $request, $release);
+      $result = drush_command_invoke_all_ref('drush_pm_download_destination_alter', $request, $release);
+      if (array_search(FALSE, $result, TRUE) !== FALSE) {
+        return FALSE;
+      }
     }
 
     // Load version control engine and detect if (the parent directory of) the
@@ -1851,13 +2221,29 @@ function drush_pm_download() {
       continue;
     }
 
-    // Final project install location.
-    $request['project_install_location'] .= '/' . $request['project_dir'];
+    // Check for drush self update
+    if ($request['project_install_location'] == DRUSH_BASE_PATH && $request['name'] == 'drush') {
+      if (($backup_dir = drush_prepare_backup_dir()) === FALSE) {
+        return FALSE;
+      }
+      // Move the running drush out of the way
+      $drush_backup = $backup_dir . "/drush";
+      if (drush_move_dir(DRUSH_BASE_PATH, $drush_backup, TRUE) == FALSE) {
+        return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Failed to move drush directory !drush to !backup_target', array('!drush' => DRUSH_BASE_PATH, '!backup_target' => $drush_backup)));
+      }
+      else {
+        drush_log(dt("drush backed up to !targetdir", array('!targetdir' => $drush_backup)), "ok");
+      }
+    }
+    else {
+      // For all other projects, the final project install location will go in the project_dir.
+      $request['project_install_location'] .= '/' . $request['project_dir'];
+    }
 
     // Check if install location already exists.
     if (is_dir($request['project_install_location'])) {
       if (!drush_confirm(dt('Install location !location already exists. Do you want to overwrite it?', array('!location' => $request['project_install_location'])))) {
-        drush_log(dt("Abort installation of !project to !dest.", array('!project' => $request['name'], '!dest' => $request['project_install_location'])), 'warning');
+        drush_log(dt("Skip installation of !project to !dest.", array('!project' => $request['name'], '!dest' => $request['project_install_location'])), 'warning');
         continue;
       }
     }
@@ -1867,6 +2253,9 @@ function drush_pm_download() {
       drush_log(dt("Project !project (!version) downloaded to !dest.", array('!project' => $request['name'], '!version' => $release['version'], '!dest' => $request['project_install_location'])), 'success');
       $request['base_project_path'] = basename($request['project_install_location']);
       $request['full_project_path'] = $request['project_install_location'];
+      if ($request['project_install_location'] == DRUSH_BASE_PATH) {
+        drush_log(dt("Drush successfully updated to version !version.", array('!version' => $release['version'])), 'success');
+      }
     }
     else {
       drush_log(dt("Project !project (!version) could not be downloaded to !dest.", array('!project' => $request['name'], '!version' => $release['version'], '!dest' => $request['project_install_location'])), 'error');
@@ -1874,6 +2263,7 @@ function drush_pm_download() {
     }
 
     // Post download actions.
+    package_handler_post_download($request);
     drush_command_invoke_all('drush_pm_post_download', $request, $release);
     $version_control->post_download($request);
 
@@ -1882,7 +2272,7 @@ function drush_pm_download() {
       _drush_pm_releasenotes(array($name . '-' . $release['version']), FALSE);
     }
 
-    // Inform the user about available modules a/o themes in the downloaded package.
+    // Inform the user about available modules a/o themes in the downloaded project.
     drush_pm_extensions_in_project($request);
   }
 }
@@ -1890,7 +2280,7 @@ function drush_pm_download() {
 /**
  * Implementation of hook_drush_pm_download_destination_alter().
  *
- * Built-in download-destination-alter hook.  This particular version of
+ * Built-in download-destination-alter hook. This particular version of
  * the hook will move modules that contain only drush commands to
  * /usr/share/drush/commands if it exists, or $HOME/.drush if the
  * site-wide location does not exist.
@@ -1901,19 +2291,38 @@ function pm_drush_pm_download_destination_alter(&$project, $release) {
   if ($project['project_type'] == 'module') {
     $module_files = drush_scan_directory($project['full_project_path'], '/.*\.module/');
     if (empty($module_files)) {
-      $drush_command_files = drush_scan_directory($project['full_project_path'], '/.*\.drush.inc/');
-      if (!empty($drush_command_files)) {
-        $install_dir = drush_get_context('SHARE_PREFIX', '/usr') . '/share/drush/commands';
-        if (!is_dir($install_dir)) {
-          $install_dir = drush_server_home() . '/.drush';
-        }
-        // Make the .drush dir if it does not already exist.
-        if (!is_dir($install_dir)) {
-          mkdir($install_dir);
+      if ($project['name'] == 'drush') {
+        // $project['version'] is empty here, so compose the version from the $release structure.
+        $drush_release_version = $release['version_major'] . "." . $release['version_patch'] . (empty($release['version_extra']) ? '' : ('-' . $release['version_extra']));
+        if(($project['project_install_location'] != DRUSH_BASE_PATH) && ($release['version_major'] >= '4')) {
+          $backup_dir = drush_preflight_backup_dir();
+          if (drush_confirm(dt('Would you like to back up your current drush version !currentversion to !backup and replace it with drush !version?', array('!version' => $drush_release_version, '!backup' => $backup_dir, '!currentversion' => DRUSH_VERSION)))) {
+            $project['project_install_location'] = DRUSH_BASE_PATH;
+          }
+          else {
+            // If we are called via 'drush self-update', then "no" means "do nothing".
+            // If we are called via 'drush dl drush', then "no" means "download to cwd".
+            if (drush_get_option('self-update', FALSE)) {
+              return drush_user_cancel();
+            }
+          }
         }
-        // Change the location if the mkdir worked.
-        if (is_dir($install_dir)) {
-          $project['project_install_location'] = $install_dir;
+      }
+      else {
+        $drush_command_files = drush_scan_directory($project['full_project_path'], '/.*\.drush.inc/');
+        if (!empty($drush_command_files)) {
+          $install_dir = drush_get_context('SHARE_PREFIX', '/usr') . '/share/drush/commands';
+          if (!is_dir($install_dir)) {
+            $install_dir = drush_server_home() . '/.drush';
+          }
+          // Make the .drush dir if it does not already exist.
+          if (!is_dir($install_dir)) {
+            drush_mkdir($install_dir);
+          }
+          // Change the location if the mkdir worked.
+          if (is_dir($install_dir)) {
+            $project['project_install_location'] = $install_dir;
+          }
         }
       }
     }
@@ -1950,7 +2359,7 @@ function drush_pm_update_lock(&$projects, $projects_to_lock, $projects_to_unlock
     $projects_to_unlock = array();
     drush_log(dt('Ignoring --unlock with no value.'), 'warning');
   }
-  
+
   // Log if we are going to lock or unlock anything
   if (!empty($projects_to_unlock)) {
     drush_log(dt('Unlocking !projects', array('!projects' => implode(',', $projects_to_unlock))), 'ok');
@@ -1958,17 +2367,20 @@ function drush_pm_update_lock(&$projects, $projects_to_lock, $projects_to_unlock
   if (!empty($projects_to_lock)) {
     drush_log(dt('Locking !projects', array('!projects' => implode(',', $projects_to_lock))), 'ok');
   }
-  
+
   $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
   foreach ($projects as $name => $project) {
+    if ($name == 'drupal') {
+      continue;
+    }
     $message = NULL;
     $lockfile = $drupal_root . '/' . $project['path'] . '/.drush-lock-update';
-    
+
     // Remove the lock file if the --unlock option was specified
     if (((in_array($name, $projects_to_unlock)) || (in_array('all', $projects_to_unlock))) && (file_exists($lockfile))) {
       drush_op('unlink', $lockfile);
     }
-    
+
     // Create the lock file if the --lock option was specified
     if ((in_array($name, $projects_to_lock)) || (in_array('all', $projects_to_lock))) {
       drush_op('file_put_contents', $lockfile, $lock_message != NULL ? $lock_message : "Locked via drush.");
@@ -1978,29 +2390,69 @@ function drush_pm_update_lock(&$projects, $projects_to_lock, $projects_to_unlock
       // read from the lock file below.
       $message = drush_get_context('DRUSH_SIMULATE') ? 'Simulated lock.' : 'Transient lock.';
     }
-    
+
     // If the persistent lock file exists, then mark the project as locked.
     if (file_exists($lockfile)) {
       $message = trim(file_get_contents($lockfile));
     }
-    
+
     // If there is a message set, then mark the project as locked.
     if (isset($message)) {
       $projects[$name]['locked'] = !empty($message) ? $message : "Locked.";
       $locked_result[$name] = $project;
     }
   }
-  
+
   return $locked_result;
 }
 
+function _drush_pm_extension_cache_file() {
+  return drush_server_home() . "/.drush/drush-extension-cache.inc";
+}
+
+function _drush_pm_get_extension_cache() {
+  $extension_cache = array();
+  $cache_file = _drush_pm_extension_cache_file();
+
+  if (file_exists($cache_file)) {
+    include $cache_file;
+  }
+  if (!array_key_exists('extension-map', $extension_cache)) {
+    $extension_cache['extension-map'] = array();
+  }
+  return $extension_cache;
+}
+
+function drush_pm_lookup_extension_in_cache($extension) {
+  $result = NULL;
+  $extension_cache = _drush_pm_get_extension_cache();
+  if (!empty($extension_cache) && array_key_exists($extension, $extension_cache)) {
+    $result = $extension_cache[$extension];
+  }
+  return $result;
+}
+
+function drush_pm_put_extension_cache($extension_cache) {
+}
+
+function drush_pm_cache_project_extensions($project, $found) {
+  $extension_cache = _drush_pm_get_extension_cache();
+  foreach($found as $extension) {
+    // Simple cache does not handle conflicts
+    // We could keep an array of projects, and count
+    // how many times each one has been seen...
+    $extension_cache[$extension] = $project['name'];
+  }
+  drush_pm_put_extension_cache($extension_cache);
+}
+
 /**
  * Print out all extensions (modules/themes/profiles) found in specified project.
  *
  * Find .info files in the project path and identify modules, themes and
  * profiles. It handles two kind of projects: drupal core/profiles and
  * modules/themes.
- * It does nothing with translation or theme engine projects.
+ * It does nothing with theme engine projects.
  */
 function drush_pm_extensions_in_project($project) {
   // Mask for drush_scan_directory, to  avoid tests directories.
@@ -2068,5 +2520,61 @@ function drush_pm_extensions_in_project($project) {
       drush_print(dt($msg, array('!project' => $project['name'], '!count' => count($found), '!type' => $project['project_type'], '!found' => implode(', ', $found))));
     }
     drush_print_pipe($found);
+    // Cache results.
+    drush_pm_cache_project_extensions($project, $found);
+  }
+}
+
+/**
+ * Return an array of empty directories.
+ *
+ * Walk a directory and return an array of subdirectories that are empty. Will
+ * return the given directory if it's empty.
+ * If a list of items to exclude is provided, subdirectories will be condidered
+ * empty even if they include any of the items in the list.
+ *
+ * @param string $dir
+ *   Path to the directory to work in.
+ * @param array $exclude
+ *   Array of files or directory to exclude in the check.
+ */
+function drush_find_empty_directories($dir, $exclude = array()) {
+  $to_exclude = array_merge(array('.', '..'), $exclude);
+  $empty = array();
+  $dir_is_empty = TRUE;
+  if ($dh = opendir($dir)) {
+    while (($file = readdir($dh)) !== FALSE) {
+      if (in_array($file, $to_exclude)) {
+        continue;
+      }
+      if (is_dir($dir .'/'. $file)) {
+        $subdir = $dir .'/'. $file;
+        $subdir_is_empty = TRUE;
+        if ($dh2 = opendir($subdir)) {
+          while (($file2 = readdir($dh2)) !== FALSE) {
+            if (in_array($file2, $to_exclude)) {
+              continue;
+            }
+            $subdir_is_empty = FALSE;
+            if (is_dir($subdir . '/'. $file2)) {
+              $empty2 = drush_find_empty_directories($subdir . '/'. $file2, $exclude);
+              $empty = array_merge($empty, $empty2);
+            }
+          }
+          if ($subdir_is_empty) {
+            $empty[] = $subdir . '/'. $file2;
+          }
+        }
+        closedir($dh2);
+      }
+      $dir_is_empty = FALSE;
+    }
+  }
+  closedir($dh);
+
+  if ($dir_is_empty) {
+    return array($dir);
   }
+
+  return $empty;
 }
diff --git a/sites/all/modules/drush/commands/pm/update_info/drupal.inc b/sites/all/modules/drush/commands/pm/update_info/drupal.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b520bbba7810bfeb55ae258f44f9d5dacc34309f
--- /dev/null
+++ b/sites/all/modules/drush/commands/pm/update_info/drupal.inc
@@ -0,0 +1,145 @@
+<?php
+
+function pm_update_filter(&$project) {
+  $update = FALSE;
+  switch($project['status']) {
+    case UPDATE_CURRENT:
+      $status = dt('Up to date');
+      $project['candidate_version'] = $project['recommended'];
+      break;
+    case UPDATE_NOT_CURRENT:
+      $status = dt('Update available');
+      pm_release_recommended($project);
+      break;
+    case UPDATE_NOT_SECURE:
+      $status = dt('SECURITY UPDATE available');
+      pm_release_recommended($project);
+      break;
+    case UPDATE_REVOKED:
+      $status = dt('Installed version REVOKED');
+      pm_release_recommended($project);
+      break;
+    case UPDATE_NOT_SUPPORTED:
+      $status = dt('Installed version not supported');
+      pm_release_recommended($project);
+      break;
+    case UPDATE_NOT_CHECKED:
+      $status = dt('Unable to check status');
+      break;
+    default:
+      $status = dt('Unknown');
+      break;
+  }
+  return $status;
+}
+
+function pm_update_last_check() {
+  return variable_get('update_last_check', 0);
+}
+
+/**
+ * Command callback. Refresh update status information.
+ */
+function _pm_refresh() {
+  drush_print(dt("Refreshing update status information ..."));
+  update_refresh();
+  drush_print(dt("Done."));
+}
+
+/**
+ * Get update information for all installed projects.
+ *
+ * @see update_get_available().
+ * @see update_manual_status().
+ *
+ * @return An array containing remote and local versions for all installed
+ *  projects
+ */
+function _pm_get_update_info($projects) {
+  // Force to invalidate some caches that are only cleared
+  // when visiting update status report page. This allow to detect changes in
+  // .info files.
+  _update_cache_clear('update_project_data');
+  _update_cache_clear('update_project_projects');
+
+  // From update_get_available(): Iterate all projects and create a fetch task
+  // for those we have no information or is obsolete.
+  module_load_include('inc', 'update', 'update.compare');
+  $available = _update_get_cached_available_releases();
+  $update_projects = update_get_projects();
+  foreach ($update_projects as $key => $project) {
+    if (empty($available[$key])) {
+      update_create_fetch_task($project);
+      continue;
+    }
+    if ($project['info']['_info_file_ctime'] > $available[$key]['last_fetch']) {
+      $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
+    }
+    if (empty($available[$key]['releases'])) {
+      $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
+    }
+    if (!empty($available[$key]['fetch_status']) && $available[$key]['fetch_status'] == UPDATE_FETCH_PENDING) {
+      update_create_fetch_task($project);
+    }
+  }
+
+  // Set a batch to process all pending tasks.
+  $batch = array(
+    'operations' => array(
+      array('update_fetch_data_batch', array()),
+    ),
+    'finished' => 'update_fetch_data_finished',
+    'file' => drupal_get_path('module', 'update') . '/update.fetch.inc',
+  );
+  batch_set($batch);
+  drush_backend_batch_process();
+
+  // Calculate update status data.
+  $available = _update_get_cached_available_releases();
+  $data = update_calculate_project_data($available);
+  foreach ($data as $project_name => $project) {
+    // Discard custom projects.
+    if ($project['status'] == UPDATE_UNKNOWN) {
+      unset($data[$project_name]);
+      continue;
+    }
+    // Allow to update disabled projects.
+    if (in_array($project['project_type'], array('module-disabled', 'theme-disabled'))) {
+      $data[$project_name]['project_type'] = substr($project['project_type'], 0, strpos($project['project_type'], '-'));
+    }
+    // Set 'includes' key to all extensions. By default it only contain enabled
+    // extensions and _pm_get_project_path() needs all of them.
+    $data[$project_name]['includes'] = drupal_map_assoc($projects[$project_name]['extensions']);
+    // Store all releases, not just the ones selected by update.module.
+    $data[$project_name]['releases'] = $available[$project_name]['releases'];
+  }
+  $data = _pm_get_project_path($data, 'includes');
+
+  return $data;
+}
+
+function pm_get_project_info($projects) {
+  $data = array();
+  include_once drupal_get_path('module', 'update') .'/update.fetch.inc';
+
+  foreach ($projects as $project_name => $project) {
+    $url = UPDATE_DEFAULT_URL. "/$project_name/". drush_drupal_major_version() . '.x';
+    $xml = drupal_http_request($url);
+    if (isset($xml->error)) {
+      drush_set_error(dt(
+        'HTTP Request to @request has failed. @error',
+        array('@request' => $xml->request, '@error' => $xml->error)
+      ));
+    }
+    elseif (!$info = update_parse_xml($xml->data)) {
+      drush_set_error(dt(
+        'No release history found for @project_name',
+        array('@project_name' => $project_name)
+      ));
+    }
+    else {
+      $data[$project_name] = $info;
+    }
+  }
+  return $data;
+}
diff --git a/sites/all/modules/drush/commands/pm/update_info/drupal_5.inc b/sites/all/modules/drush/commands/pm/update_info/drupal_5.inc
index 54a9e06f42d0158f460c9750457a66af94205c09..edd09501a81f04b3fc374f41d9bc47cf810d0f30 100644
--- a/sites/all/modules/drush/commands/pm/update_info/drupal_5.inc
+++ b/sites/all/modules/drush/commands/pm/update_info/drupal_5.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: drupal_5.inc,v 1.10 2010/11/24 10:00:02 jonhattan Exp $
 
 function pm_update_filter(&$project) {
   $update = FALSE;
@@ -51,7 +50,7 @@ function _pm_refresh() {
  *
  * @return An array containing remote and local versions for all installed projects
  */
-function _pm_get_update_info($projects = NULL) {
+function _pm_get_update_info($projects) {
   // We force a refresh if the cache is not available.
   if (!cache_get('update_status_info', 'cache')) {
     _pm_refresh();
@@ -70,6 +69,7 @@ function _pm_get_update_info($projects = NULL) {
   // or pm_get_project_path() will fail
   foreach ($data as $project_name => $project_data) {
     $data[$project_name]['project_type'] = 'module';
+    $data[$project_name]['modules'] = drupal_map_assoc($projects[$project_name]['extensions']);
   }
   $data = _pm_get_project_path($data, 'modules');
 
diff --git a/sites/all/modules/drush/commands/pm/update_info/drupal_6.inc b/sites/all/modules/drush/commands/pm/update_info/drupal_6.inc
index c8085c4d8c47d9791d76a991b0562a84ed99df6f..e6d4a3a9436f90ca5af2ff821d0a58829a70283c 100644
--- a/sites/all/modules/drush/commands/pm/update_info/drupal_6.inc
+++ b/sites/all/modules/drush/commands/pm/update_info/drupal_6.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: drupal_6.inc,v 1.10 2010/11/24 10:00:02 jonhattan Exp $
 
 function pm_update_filter(&$project) {
   $update = FALSE;
@@ -27,7 +26,6 @@ function pm_update_filter(&$project) {
     case UPDATE_NOT_CHECKED:
       $status = dt('Unable to check status');
       break;
-    case UPDATE_UNKNOWN:
     default:
       $status = dt('Unknown');
       break;
@@ -53,7 +51,7 @@ function _pm_refresh() {
  *
  * @return An array containing remote and local versions for all installed projects
  */
-function _pm_get_update_info($projects = NULL) {
+function _pm_get_update_info($projects) {
   // We force a refresh if the cache is not available.
   if (!cache_get('update_available_releases', 'cache_update')) {
     _pm_refresh();
@@ -67,6 +65,17 @@ function _pm_get_update_info($projects = NULL) {
   _update_cache_clear('update_project_projects');
 
   $data = update_calculate_project_data($info);
+  foreach ($data as $project_name => $project) {
+    // Discard custom projects.
+    if ($project['status'] == UPDATE_UNKNOWN) {
+      unset($data[$project_name]);
+      continue;
+    }
+    if (in_array($project['project_type'], array('disabled-module', 'disabled-theme'))) {
+      $data[$project_name]['project_type'] = substr($project['project_type'], strpos($project['project_type'], '-') + 1);
+    }
+    $data[$project_name]['includes'] = drupal_map_assoc($projects[$project_name]['extensions']);
+  }
   $data = _pm_get_project_path($data, 'includes');
 
   return $data;
diff --git a/sites/all/modules/drush/commands/pm/update_info/drupal_7.inc b/sites/all/modules/drush/commands/pm/update_info/drupal_7.inc
deleted file mode 100644
index ddbfe89c5332486590f7f5ed20c2040bf30b5e58..0000000000000000000000000000000000000000
--- a/sites/all/modules/drush/commands/pm/update_info/drupal_7.inc
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-// $Id: drupal_7.inc,v 1.10 2010/11/24 10:00:02 jonhattan Exp $
-
-function pm_update_filter(&$project) {
-  $update = FALSE;
-  switch($project['status']) {
-    case UPDATE_CURRENT:
-      $status = dt('Up to date');
-      $project['candidate_version'] = $project['recommended'];
-      break;
-    case UPDATE_NOT_CURRENT:
-      $status = dt('Update available');
-      pm_release_recommended($project);
-      break;
-    case UPDATE_NOT_SECURE:
-      $status = dt('SECURITY UPDATE available');
-      pm_release_recommended($project);
-      break;
-    case UPDATE_REVOKED:
-      $status = dt('Installed version REVOKED');
-      pm_release_recommended($project);
-      break;
-    case UPDATE_NOT_SUPPORTED:
-      $status = dt('Installed version not supported');
-      pm_release_recommended($project);
-      break;
-    case UPDATE_NOT_CHECKED:
-      $status = dt('Unable to check status');
-      break;
-    case UPDATE_UNKNOWN:
-    default:
-      $status = dt('Unknown');
-      break;
-  }
-  return $status;
-}
-
-function pm_update_last_check() {
-  return variable_get('update_last_check', 0);
-}
-
-/**
- * Command callback. Refresh update status information.
- */
-function _pm_refresh() {
-  drush_print(dt("Refreshing update status information ..."));
-  update_refresh(TRUE);
-  drush_print(dt("Done."));
-}
-
-/**
- * Get update information for all installed projects.
- *
- * @return An array containing remote and local versions for all installed projects
- */
-function _pm_get_update_info($projects = NULL) {
-  // We force a refresh if the cache is not available.
-  if (!cache_get('update_available_releases', 'cache_update')) {
-    _pm_refresh();
-  }
-
-  $info = update_get_available(TRUE);
-
-  // Force to invalidate some update_status caches that are only cleared
-  // when visiting update status report page.
-  _update_cache_clear('update_project_data');
-  _update_cache_clear('update_project_projects'); 
-  $data = update_calculate_project_data($info);
-  $data = _pm_get_project_path($data, 'includes');
-
-  return $data;
-}
-
-function pm_get_project_info($projects) {
-  $data = array();
-  include_once drupal_get_path('module', 'update') .'/update.fetch.inc';
-
-  foreach ($projects as $project_name => $project) {
-    $url = UPDATE_DEFAULT_URL. "/$project_name/". drush_drupal_major_version() . '.x';
-    $xml = drupal_http_request($url);
-    if (isset($xml->error)) {
-      drush_set_error(dt(
-        'HTTP Request to @request has failed. @error',
-        array('@request' => $xml->request, '@error' => $xml->error)
-      ));
-    }
-    elseif (!$info = update_parse_xml($xml->data)) {
-      drush_set_error(dt(
-        'No release history found for @project_name',
-        array('@project_name' => $project_name)
-      ));
-    }
-    else {
-      $data[$project_name] = $info;
-    }
-  }
-  return $data;
-}
diff --git a/sites/all/modules/drush/commands/pm/updatecode.pm.inc b/sites/all/modules/drush/commands/pm/updatecode.pm.inc
index ec408521f2b283d223bac9747e79297793d2594d..f293069dd9eefd8ca12874bf6ea83340e0a8d177 100644
--- a/sites/all/modules/drush/commands/pm/updatecode.pm.inc
+++ b/sites/all/modules/drush/commands/pm/updatecode.pm.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: updatecode.pm.inc,v 1.24 2010/12/01 15:53:15 jonhattan Exp $
 
 /**
  * Command callback. Displays update status info and allows to update installed
@@ -14,58 +13,101 @@ function drush_pm_updatecode() {
   // We don't provide for other options here, so we supply an explicit path.
   drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
 
-  // Get update status information.
-  $projects = _pm_get_update_info();
-
   // Find only security updates?
   $security_only = drush_get_option('security-only');
 
-  // Process locks specified on the command line.
-  $locked_list = drush_pm_update_lock($projects, drush_get_option_list('lock'), drush_get_option_list('unlock'), drush_get_option('lock-message'));
-
   // Get specific requests.
   $requests = _convert_csv_to_array(func_get_args());
 
   // Parse out project name and version.
   $requests = pm_parse_project_version($requests);
 
-  // Preprocess releases.
-  if (!empty($requests)) {
-    // Check requests are installed and enabled projects and force
-    // update projects where a specific version is requested.
-    foreach ($requests as $name => $request) {
-      if (!isset($projects[$name])) {
-        // Catch projects with no version data (common for CVS checkouts
-        // if you don't have CVS deploy installed).
-        $projects[$name] = array(
+  // Get installed extensions and projects.
+  $extensions = drush_get_extensions();
+  $projects = drush_get_projects($extensions);
+
+  // Get update status information.
+  $update_info = _pm_get_update_info($projects);
+
+  // Process locks specified on the command line.
+  $locked_list = drush_pm_update_lock($update_info, drush_get_option_list('lock'), drush_get_option_list('unlock'), drush_get_option('lock-message'));
+
+  foreach ($extensions as $name => $extension) {
+    // Add an item to $update_info for each enabled extension which was obtained
+    // from cvs or git and its project is unknown (because of cvs_deploy or
+    // git_deploy is not enabled).
+    if (!isset($extension->info['project'])) {
+      if ((isset($extension->vcs)) && ($extension->status)) {
+        $update_info[$name] = array(
+          'title' => $extension->info['name'],
+          'existing_version' => 'Unknown',
+          'status' => DRUSH_PM_REQUESTED_PROJECT_NOT_PACKAGED,
+          'status_msg' => dt('Project was not packaged by drupal.org but obtained from !vcs. You need to enable !vcs_deploy module', array('!vcs' => $extension->vcs))
+        );
+        // The user may have requested to update a project matching this
+        // extension. If it was by coincidence or error we don't mind as we've
+        // already added an item to $update_info. Just clean up $requests.
+        if (isset($requests[$name])) {
+          unset($requests[$name]);
+        }
+      }
+    }
+    // Aditionally if the extension name is distinct to the project name and
+    // the user asked to update the extension, fix the request.
+    elseif ((isset($requests[$name])) && ($extension->name != $extension->info['project'])) {
+      $requests[$extension->info['project']] = $requests[$name];
+      unset($requests[$name]);
+    }
+  }
+
+  // Add an item to $update_info for each request not present in $update_info.
+  foreach ($requests as $name => $request) {
+    if (!isset($update_info[$name])) {
+      // Disabled projects.
+      if ((isset($projects[$name])) && ($projects[$name]['status'] == 0)) {
+        $update_info[$name] = array(
+          'title' => $name,
+          'existing_version' => $projects[$name]['version'],
+          'status' => DRUSH_PM_REQUESTED_PROJECT_NOT_UPDATEABLE
+        );
+        unset($requests[$name]);
+      }
+      // At this point we are unable to find matching installed project.
+      // It does not exist at all or it is mispelled,...
+      else {
+        $update_info[$name] = array(
           'title' => $name,
           'existing_version' => 'Unknown',
-          'status'=> DRUSH_PM_NO_VERSION,
+          'status'=> DRUSH_PM_REQUESTED_PROJECT_NOT_FOUND,
         );
       }
-      else if (!empty($request['version'])) {
-        // Match the requested release
-        $release = pm_get_release($request, $projects[$name]);
-        if (!$release) {
-          $projects[$name]['status'] = DRUSH_PM_REQUESTED_NOT_FOUND;
-        }
-        else if ($release['version'] == $projects[$name]['existing_version']) {
-          $projects[$name]['status'] = DRUSH_PM_REQUESTED_CURRENT;
-        }
-        else {
-          $projects[$name]['status'] = DRUSH_PM_REQUESTED_UPDATE;
-        }
-        // Set the candidate version to the requested release
-        $projects[$name]['candidate_version'] = $release['version'];
+    }
+  }
+
+  // If specific versions were requested, match the requested release.
+  foreach ($requests as $name => $request) {
+    if (!empty($request['version'])) {
+      $release = pm_get_release($request, $update_info[$name]);
+      if (!$release) {
+        $update_info[$name]['status'] = DRUSH_PM_REQUESTED_VERSION_NOT_FOUND;
       }
+      else if ($release['version'] == $update_info[$name]['existing_version']) {
+        $update_info[$name]['status'] = DRUSH_PM_REQUESTED_CURRENT;
+      }
+      else {
+        $update_info[$name]['status'] = DRUSH_PM_REQUESTED_UPDATE;
+      }
+      // Set the candidate version to the requested release.
+      $update_info[$name]['candidate_version'] = $release['version'];
     }
   }
 
   // Table headers.
   $rows[] = array(dt('Name'), dt('Installed version'), dt('Proposed version'), dt('Status'));
 
-  // Process releases, notifying user of status and building a list of proposed updates
-  $updateable = pm_project_filter($projects, $rows, $security_only);
+  // Process releases, notifying user of status and
+  // building a list of proposed updates.
+  $updateable = pm_project_filter($update_info, $rows, $security_only);
 
   // Pipe preparation.
   if (drush_get_context('DRUSH_PIPE')) {
@@ -77,18 +119,23 @@ function drush_pm_updatecode() {
       $pipe .= str_replace(' ', '-', pm_update_filter($project)). "\n";
     }
     drush_print_pipe($pipe);
-    // Automatically curtail update process if in pipe mode
-    $updateable = FALSE;
+    // Automatically curtail update process if in pipe mode.
+    $updateable = array();
   }
 
+  $tmpfile = drush_tempnam('pm-updatecode.');
+
   $last = pm_update_last_check();
   drush_print(dt('Update information last refreshed: ') . ($last  ? format_date($last) : dt('Never')));
   drush_print();
   drush_print(dt("Update status information on all installed and enabled Drupal projects:"));
-  drush_print_table($rows, TRUE);
+  drush_print_table($rows, TRUE, array(3 => 40), $tmpfile);
+  $contents = file_get_contents($tmpfile);
+  drush_print($contents);
   drush_print();
 
-  // If specific project updates were requested then remove releases for all others
+  // If specific project updates were requested then remove releases for all
+  // others.
   if (!empty($requests)) {
     foreach ($updateable as $name => $project) {
       if (!isset($requests[$name])) {
@@ -96,8 +143,14 @@ function drush_pm_updatecode() {
       }
     }
   }
-  
-  // If there are any locked projects that were not requested, then remove them
+
+  // Prevent update of core if --no-core was specified.
+  if (isset($updateable['drupal']) && drush_get_option('no-core', FALSE)) {
+    unset($updateable['drupal']);
+    drush_print(dt('Skipping core update (--no-core specified).'));
+  }
+
+  // If there are any locked projects that were not requested, then remove them.
   if (!empty($locked_list)) {
     foreach ($updateable as $name => $project) {
       if ((isset($locked_list[$name])) && (!isset($requests[$name]))) {
@@ -106,49 +159,50 @@ function drush_pm_updatecode() {
     }
   }
 
-  // Do no updates in simulated mode
+  // First check to see if there is a newer drush.
+  $drush_update_available = NULL;
+  if (drush_get_option('self-update', TRUE)) {
+    $drush_update_available = drush_check_self_update();
+  }
+
+  // Do no updates in simulated mode.
   if (drush_get_context('DRUSH_SIMULATE')) {
     return drush_log(dt('No action taken in simulated mode.'), 'ok');
     return TRUE;
   }
 
+  $core_update_available = FALSE;
   if (isset($updateable['drupal'])) {
     $drupal_project = $updateable['drupal'];
-    unset($projects['drupal']);
+    unset($update_info['drupal']);
     unset($updateable['drupal']);
-    $module_list = array_keys($projects);
-
-    // We can only upgrade drupal core if there are no non-core
-    // modules enabled.  _pm_update_core will disable the
-    // modules passed in, and insure that they are enabled again
-    // when we're done.  However, each run of pm-updatecode will
-    // update -either- core, or the non-core modules; never both.
-    // This simplifies rollbacks.
+
+    // At present we need to update drupal core after non-core projects
+    // are updated.
     if (empty($updateable)) {
-      return _pm_update_core($drupal_project, $module_list);
+      return _pm_update_core($drupal_project, $tmpfile);
     }
-    // If there are modules other than drupal core enabled, then go
-    // ahead and print instructions on how to upgrade core.  We will
-    // also continue, allowing the user to upgrade any upgradable
-    // modules if desired.
+    // If there are modules other than drupal core enabled, then update them
+    // first.
     else {
+      $core_update_available = TRUE;
       if ($drupal_project['status'] == UPDATE_NOT_SECURE) {
         drush_print(dt("NOTE: A security update for the Drupal core is available."));
       }
       else {
         drush_print(dt("NOTE: A code update for the Drupal core is available."));
       }
-      if (drush_get_context('DRUSH_PM_UPDATE_ALL', FALSE)) {
-        drush_print(dt("Drupal core will be updated after all of the non-core modules are updated.\n"));
-      }
-      else {
-        drush_print(dt("Drupal core cannot be updated at the same time that non-core modules are updated.  In order to update Drupal core with this tool, first allow the update of the modules listed above to complet, and then run pm-updatecode again.\n"));
-      }
-      drush_set_context('DRUSH_PM_CORE_UPDATE_AVAILABLE', TRUE);
+      drush_print(dt("Drupal core will be updated after all of the non-core modules are updated.\n"));
     }
   }
 
+  // If there are no releases to update, then print a final
+  // exit message.  Supress the message if we already printed
+  // a message about a drush update being available.
   if (empty($updateable)) {
+    if ($drush_update_available === TRUE) {
+      return FALSE;
+    }
     if ($security_only) {
       return drush_log(dt('No security updates available.'), 'ok');
     }
@@ -157,8 +211,16 @@ function drush_pm_updatecode() {
     }
   }
 
-  // Offer to update to the identified releases
-  return pm_update_packages($updateable);
+  // Offer to update to the identified releases.
+  if (!pm_update_packages($updateable, $tmpfile)) {
+    return FALSE;
+  }
+
+  // After projects are updated we can update core.
+  if ($core_update_available) {
+    drush_print();
+    return _pm_update_core($drupal_project, $tmpfile);
+  }
 }
 
 /**
@@ -166,12 +228,9 @@ function drush_pm_updatecode() {
  *
  * @param $project
  *   The drupal project information from the drupal.org update service,
- *   copied from $projects['drupal'].  @see drush_pm_updatecode.
- * @param $module_list
- *   A list of the non-core modules that are enabled.  These must be disabled
- *   before core can be updated.
+ *   copied from $update_info['drupal'].  @see drush_pm_updatecode.
  */
-function _pm_update_core(&$project, $module_list = array()) {
+function _pm_update_core(&$project, $tmpfile) {
   drush_include_engine('package_handler', drush_get_option('package-handler', 'wget'));
   $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
 
@@ -179,9 +238,13 @@ function _pm_update_core(&$project, $module_list = array()) {
   drush_print(dt("WARNING:  Updating core will discard any modifications made to Drupal core files, most noteworthy among these are .htaccess and robots.txt.  If you have made any modifications to these files, please back them up before updating so that you can re-create your modifications in the updated version of the file."));
   drush_print(dt("Note: Updating core can potentially break your site. It is NOT recommended to update production sites without prior testing."));
   drush_print();
-  drush_pm_releasenotes();
+  if (drush_get_option('notes', FALSE)) {
+    drush_print('Obtaining release notes for above projects...');
+    _drush_pm_releasenotes(array('drupal'), TRUE, $tmpfile);
+  }
   if(!drush_confirm(dt('Do you really want to continue?'))) {
-    drush_user_abort();
+    drush_print(dt('Rolling back all changes. Run again with --no-core to update modules only.'));
+    return drush_user_abort();
   }
 
   // We need write permission on $drupal_root.
@@ -193,11 +256,11 @@ function _pm_update_core(&$project, $module_list = array()) {
   $project['path'] = 'drupal-' . $project['candidate_version'];
   $project['full_project_path'] = $drupal_root . '/' . $project['path'];
   if (!is_dir($project['full_project_path'])) {
-    drush_op('mkdir', $project['full_project_path']);
+    drush_mkdir($project['full_project_path']);
   }
 
   // Create a list of directories to exclude from the update process.
-  $skip_list = array('sites', $project['path'], '.svn');
+  $skip_list = array('sites', $project['path']);
   // Add non-writable directories: we can't move them around.
   // We will also use $items_to_test later for $version_control check.
   $items_to_test = drush_scan_directory($drupal_root, '/.*/', array_merge(array('.', '..'), $skip_list), 0, FALSE, 'basename', 0, TRUE);
@@ -240,6 +303,9 @@ function _pm_update_core(&$project, $module_list = array()) {
   // the drupal root
   _pm_update_move_files($project['full_project_path'], $drupal_root, $project['skip_list']);
   drush_delete_dir($project['full_project_path']);
+  
+  // Version control engines expect full_project_path to exist and be accurate.
+  $project['full_project_path'] = $project['base_project_path'];
 
   // If there is a backup target, then find items
   // in the backup target that do not exist at the
@@ -264,67 +330,67 @@ function _pm_update_move_files($src_dir, $dest_dir, $skip_list, $remove_conflict
       drush_delete_dir($dest_dir . '/' . basename($filename));
     }
     if (!file_exists($dest_dir . '/' . basename($filename))) {
-      $move_result = rename($filename,  $dest_dir . '/' . basename($filename));
+      $move_result = drush_move_dir($filename,  $dest_dir . '/' . basename($filename));
     }
   }
   return TRUE;
 }
 
 /**
- * Update packages according to an array of releases and print the release notes
+ * Update projects according to an array of releases and print the release notes
  * for each project, following interactive confirmation from the user.
  *
- * @param $projects
+ * @param $update_info
  *   An array of projects from the drupal.org update service, with an additional
  *   array key candidate_version that specifies the version to be installed.
  */
-function pm_update_packages($projects) {
+function pm_update_packages($update_info, $tmpfile) {
   drush_include_engine('package_handler', drush_get_option('package-handler', 'wget'));
   $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
 
   $print = '';
   $status = array();
-  foreach($projects as $project) {
+  foreach($update_info as $project) {
     $print .= $project['title'] . " [" . $project['name'] . '-' . $project['candidate_version'] . "], ";
     $status[$project['status']] = $project['status'];
   }
   // We print the list of the projects that need to be updated.
   if (isset($status[UPDATE_NOT_SECURE])) {
     if (isset($status[UPDATE_NOT_CURRENT])) {
-      drush_print(dt('Security and code updates will be made to the following projects:'));
+      $title = (dt('Security and code updates will be made to the following projects:'));
     }
     else {
-      drush_print(dt('Security updates will be made to the following projects:'));
+      $title = (dt('Security updates will be made to the following projects:'));
     }
   }
   else {
-    drush_print(dt('Code updates will be made to the following projects:'));
+    $title = (dt('Code updates will be made to the following projects:'));
   }
-  drush_print(substr($print, 0, strlen($print)-2));
+  $print = "$title " . (substr($print, 0, strlen($print)-2));
+  drush_print($print);
+  file_put_contents($tmpfile, "\n\n$print\n\n", FILE_APPEND);
 
-  // Print the release notes for projects to be updated. Ask before if
-  // there is more than one project.
-  $keys = array_keys($projects);
-  if (count($keys) == 1) {
-    if (!drush_get_context('DRUSH_NEGATIVE')) {
-      _drush_pm_releasenotes($keys);
-    }
-  }
-  elseif (drush_confirm(dt('Do you want to see the release notes of the above exposed versions?'))) {
-    _drush_pm_releasenotes($keys);
+  // Print the release notes for projects to be updated.
+  if (drush_get_option('notes', FALSE)) {
+    drush_print('Obtaining release notes for above projects...');
+    _drush_pm_releasenotes(array_keys($update_info), TRUE, $tmpfile);
   }
 
   // We print some warnings before the user confirms the update.
   drush_print();
-  drush_print(dt("Note: Updated projects can potentially break your site. It is NOT recommended to update production sites without prior testing."));
-  drush_print(dt("Note: A backup of your package will be stored to backups directory if it is not managed by a supported version control system."));
-  drush_print(dt('Note: If you have made any modifications to any file that belongs to one of these projects, you will have to migrate those modifications after updating.'));
+  if (drush_get_option('no-backup', FALSE)) {
+    drush_print(dt("Note: You have selected to not store backups."));
+  }
+  else {
+    drush_print(dt("Note: A backup of your project will be stored to backups directory if it is not managed by a supported version control system."));
+    drush_print(dt('Note: If you have made any modifications to any file that belongs to one of these projects, you will have to migrate those modifications after updating.'));
+  }
   if(!drush_confirm(dt('Do you really want to continue with the update process?'))) {
-    drush_user_abort();
+    return drush_user_abort();
   }
 
   // Now we start the actual updating.
-  foreach($projects as $project) {
+  foreach($update_info as $project) {
     if (empty($project['path'])) {
       return drush_set_error('DRUSH_PM_UPDATING_NO_PROJECT_PATH', dt('The !project project path is not available, perhaps the !type is enabled but has been deleted from disk.', array('!project' => $project['name'], '!type' => $project['project_type'])));
     }
@@ -355,8 +421,8 @@ function pm_update_packages($projects) {
     }
     pm_update_complete($project, $version_control);
   }
-  // Clear the cache, since some projects could have moved around.
-  drush_drupal_cache_clear_all();
+
+  return TRUE;
 }
 
 /**
@@ -367,6 +433,21 @@ function pm_update_packages($projects) {
  *   to the location where this project is stored.
  */
 function pm_update_project($project, $version_control) {
+  // 1. If the version control engine is a proper vcs we need to remove project
+  // files in order to not have orphan files after update.
+  // 2. If the package-handler is cvs or git, it will remove upstream removed
+  // files and no orphans will exist after update.
+  // So, we must remove all files previous update if the directory is not a
+  // working copy of cvs or git but we don't need to remove them if the version
+  // control engine is backup, as it did already move the project out to the
+  // backup directory.
+  if (($version_control->engine != 'backup') && (drush_get_option('package-handler', 'wget') == 'wget')) {
+    // Find and unlink all files but the ones in the vcs control directories.
+    $skip_list = array('.', '..');
+    $skip_list = array_merge($skip_list, drush_version_control_reserved_files());
+    drush_scan_directory($project['full_project_path'], '/.*/', $skip_list, 'unlink', TRUE, 'filename', 0, TRUE);
+  }
+
   // Add the project to a context so we can roll back if needed.
   $updated = drush_get_context('DRUSH_PM_UPDATED');
   $updated[] = $project;
@@ -376,6 +457,13 @@ function pm_update_project($project, $version_control) {
     return drush_set_error('DRUSH_PM_UPDATING_FAILED', dt('Updating project !project failed. Attempting to roll back to previously installed version.', array('!project' => $project['name'])));
   }
 
+  // If the version control engine is a proper vcs we also need to remove
+  // orphan directories.
+  if (($version_control->engine != 'backup') && (drush_get_option('package-handler', 'wget') == 'wget')) {
+    $files = drush_find_empty_directories($project['full_project_path'], $version_control->reserved_files());
+    array_map('drush_delete_dir', $files);
+  }
+
   return TRUE;
 }
 
@@ -401,17 +489,23 @@ function drush_pm_updatecode_rollback() {
   }
 
   // Post rollback, we will do additional repair if the project is drupal core.
-  $drupal_core = drush_get_context('DRUSH_PM_DRUPAL_CORE');
-  if (isset($drupal_core)) {
+  $drupal_core = drush_get_context('DRUSH_PM_DRUPAL_CORE', FALSE);
+  if ($drupal_core) {
     $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
     _pm_update_move_files($drupal_core['full_project_path'], $drupal_root, $drupal_core['skip_list']);
     drush_delete_dir($drupal_core['full_project_path']);
   }
 }
 
-function pm_project_filter(&$projects, &$rows, $security_only) {
+/**
+ * Return an array of updateable projects and fill $rows.
+ *
+ * Array of updateable projects is obtained from calculated project update
+ * status and $security_only flag. 
+ */
+function pm_project_filter(&$update_info, &$rows, $security_only) {
   $updateable = array();
-  foreach ($projects as $key => $project) {
+  foreach ($update_info as $key => $project) {
     if (empty($project['title'])) {
       continue;
     }
@@ -423,12 +517,18 @@ function pm_project_filter(&$projects, &$rows, $security_only) {
       case DRUSH_PM_REQUESTED_CURRENT:
         $status = dt('Specified version already installed');
         break;
-      case DRUSH_PM_NO_VERSION:
-        $status = dt('No version information found (if you have a CVS checkout you should install CVS Deploy module)');
+      case DRUSH_PM_REQUESTED_PROJECT_NOT_PACKAGED:
+        $status = $project['status_msg'];
         break;
-      case DRUSH_PM_REQUESTED_NOT_FOUND:
+      case DRUSH_PM_REQUESTED_VERSION_NOT_FOUND:
         $status = dt('Specified version not found');
         break;
+      case DRUSH_PM_REQUESTED_PROJECT_NOT_FOUND:
+        $status = dt('Specified project not found');
+        break;
+      case DRUSH_PM_REQUESTED_PROJECT_NOT_UPDATEABLE:
+        $status = dt('Project has no enabled extensions and can\'t be updated');
+        break;
       default:
         $status = pm_update_filter($project);
         break;
@@ -437,20 +537,22 @@ function pm_project_filter(&$projects, &$rows, $security_only) {
     // Special checking:  if drush decides that the candidate version is older
     // than the installed version, then we will set the candidate version to
     // the installed version.
-    if ($project['releases'][$project['candidate_version']]['date'] < $project['releases'][$project['existing_version']]['date']) {
-      $project['candidate_version'] = $project['existing_version'];
+    if (isset($project['candidate_version'], $project['releases'][$project['candidate_version']], $project['releases'][$project['existing_version']])) {
+      if ($project['releases'][$project['candidate_version']]['date'] < $project['releases'][$project['existing_version']]['date']) {
+        $project['candidate_version'] = $project['existing_version'];
+      }
     }
-    
+
     if (isset($project['locked'])) {
       $status = $project['locked'] . " ($status)";
     }
 
-    // Persist candidate_version in $projects (plural).
+    // Persist candidate_version in $update_info (plural).
     if (empty($project['candidate_version'])) {
-      $projects[$key]['candidate_version'] = $project['existing_version']; // Default to no change
+      $update_info[$key]['candidate_version'] = $project['existing_version']; // Default to no change
     }
     else {
-      $projects[$key]['candidate_version'] = $project['candidate_version'];
+      $update_info[$key]['candidate_version'] = $project['candidate_version'];
     }
     if (!empty($project['updateable'])) {
       $updateable[$key] = $project;
@@ -459,7 +561,7 @@ function pm_project_filter(&$projects, &$rows, $security_only) {
         unset($updateable[$key]);
       }
     }
-    $rows[] = array($project['title'], $project['existing_version'], $projects[$key]['candidate_version'], $status);
+    $rows[] = array($project['title'], $project['existing_version'], $update_info[$key]['candidate_version'], $status);
   }
   return $updateable;
 }
diff --git a/sites/all/modules/drush/commands/pm/version_control/backup.inc b/sites/all/modules/drush/commands/pm/version_control/backup.inc
index 8b0e7c507b8d84da2dc3c9a2a9ddfada5a9f4fb9..1bcf4a593f2523b836aedb15e4357c293e4a20e2 100644
--- a/sites/all/modules/drush/commands/pm/version_control/backup.inc
+++ b/sites/all/modules/drush/commands/pm/version_control/backup.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: backup.inc,v 1.8 2010/11/30 16:45:36 weitzman Exp $
 
 /**
  * @file Drush pm directory copy backup extension
@@ -11,17 +10,29 @@ class drush_pm_version_control_backup implements drush_pm_version_control {
    * Implementation of pre_update().
    */
   public function pre_update(&$project, $items_to_test = array()) {
-    if ($backup_dir = $this->prepare_back_dir()) {
-      $backup_target = $backup_dir . '/' . $project['name'];
+    if (drush_get_option('no-backup', FALSE)) {
+      return TRUE;
+    }
+    if ($backup_target = $this->prepare_backup_dir()) {
+      if ($project['project_type'] != 'core') {
+        $backup_target .= '/' . $project['project_type'] . 's';
+        drush_mkdir($backup_target);
+      }
+      $backup_target .= '/'. $project['name'];
       // Save for rollback or notifications.
       $project['backup_target'] = $backup_target;
-      if (!drush_move_dir($project['full_project_path'], $backup_target)) {
-        return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Failed to backup project directory !project to !backup_target', array('!project' => $project['full_project_path'], '!backup_target' => $backup_target)));
+
+      // Move or copy to backup target based in package-handler.
+      if (drush_get_option('package-handler', 'wget') == 'wget') {
+        if (drush_move_dir($project['full_project_path'], $backup_target)) {
+          return TRUE;
+        }
       }
-      return TRUE;  
-    }
-    else {
-      return FALSE;
+      // cvs or git.
+      elseif (drush_copy_dir($project['full_project_path'], $backup_target)) {
+        return TRUE;
+      }
+      return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Failed to backup project directory !project to !backup_target', array('!project' => $project['full_project_path'], '!backup_target' => $backup_target)));
     }
   }
 
@@ -29,7 +40,10 @@ class drush_pm_version_control_backup implements drush_pm_version_control {
    * Implementation of rollback().
    */
   public function rollback($project) {
-    if (drush_op('rename', $project['backup_target'], $project['full_project_path']) && is_dir($project['full_project_path'])) {
+    if (drush_get_option('no-backup', FALSE)) {
+      return;
+    }
+    if (drush_move_dir($project['backup_target'], $project['full_project_path'], TRUE)) {
       return drush_log(dt("Backups were restored successfully."), 'ok');
     }
     return drush_set_error('DRUSH_PM_BACKUP_ROLLBACK_FAILED', dt('Could not restore backup and rollback from failed upgrade. You will need to resolve manually.'));
@@ -39,6 +53,9 @@ class drush_pm_version_control_backup implements drush_pm_version_control {
    * Implementation of post_update().
    */
   public function post_update($project) {
+    if (drush_get_option('no-backup', FALSE)) {
+      return;
+    }
     if ($project['backup_target']) {
       drush_log(dt("Backups were saved into the directory !backup_target.", array('!backup_target' => $project['backup_target'])), 'ok');
     }
@@ -50,22 +67,13 @@ class drush_pm_version_control_backup implements drush_pm_version_control {
   public function post_download($project) {
    // NOOP
   }
-  
-  // Helper for pre_update.
-  public function prepare_backup_dir() {  
-    $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
 
-    // Save the date to be used in the backup directory's path name.
-    $date = date('YmdHis', $_SERVER['REQUEST_TIME']);
+  // Helper for pre_update.
+  public function prepare_backup_dir($subdir = NULL) {
+    return drush_prepare_backup_dir($subdir);
+  }
 
-    $backup_dir = drush_get_option('backup-dir', $_SERVER['HOME'] . '/' . '.drush-backups');
-    if (strpos($backup_dir, $drupal_root) === 0) {
-      return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('It\'s not allowed to store backups inside the Drupal root directory.'));
-    }
-    $backup_dir = rtrim($backup_dir, DIRECTORY_SEPARATOR);
-    
-    if (drush_mkdir($backup_dir)) {
-      return $backup_dir .= '/' . $date . '/' . 'modules';
-    }
+  public static function reserved_files() {
+    return array();
   }
 }
diff --git a/sites/all/modules/drush/commands/pm/version_control/bzr.inc b/sites/all/modules/drush/commands/pm/version_control/bzr.inc
index 7d885e36586d421928e0964304ae0687c84dc4ca..35c184e57036e8379caa52bd141e659da0e65e4e 100644
--- a/sites/all/modules/drush/commands/pm/version_control/bzr.inc
+++ b/sites/all/modules/drush/commands/pm/version_control/bzr.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: bzr.inc,v 1.7 2010/09/02 23:51:50 weitzman Exp $
 
 /**
  * @file Drush pm Bazaar extension
@@ -9,17 +8,23 @@ class drush_pm_version_control_bzr implements drush_pm_version_control {
 
   /**
    * Implementation of pre_update().
+   *
+   * Check that the project or drupal core directory looks clean
    */
   public function pre_update(&$project, $items_to_test = array()) {
-    // If items to test is empty, test everything; otherwise, pass just
-    // the list of files to test to Bazaar status.
-    $status_files = implode(' ', array_keys($items_to_test));
-
-    // Check the project directory looks clean
-    if (drush_shell_exec('cd %s && bzr status --short %s', $project['full_project_path'], $status_files)) {
+    // Bazaar needs a list of items to test within the given project.
+    // If $items_to_test is empty we need to force it to test the project
+    // directory itself --once we've cd'ed to it.
+    if (empty($items_to_test)) {
+      $items_to_test = array('.' => '.');
+    }
+    $args = array_keys($items_to_test);
+    array_unshift($args, 'bzr status --short' . str_repeat(' %s', count($args)));
+    array_unshift($args, $project['full_project_path']);
+    if (call_user_func_array('drush_shell_cd_and_exec', $args)) {
       $output = preg_grep('/^[\sRCP][\sNDKM][\s\*]/', drush_shell_exec_output());
       if (!empty($output)) {
-        return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommmitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
+        return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
       }
     }
     else {
@@ -35,7 +40,7 @@ class drush_pm_version_control_bzr implements drush_pm_version_control {
     if (drush_shell_exec('bzr revert %s', $project['full_project_path'])) {
       $output = drush_shell_exec_output();
       if (!empty($output)) {
-        return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommmitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
+        return drush_set_error('DRUSH_PM_BZR_LOCAL_CHANGES', dt("The Bazaar working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
       }
     }
     else {
@@ -80,8 +85,7 @@ class drush_pm_version_control_bzr implements drush_pm_version_control {
         foreach ($output as $line) {
           if (preg_match('/^\?\s+(.*)/', $line, $matches)) {
             $path = $root[0] .'/'. $matches[1];
-            // Bazaar add is by default recursive so only run on "full_project_path".
-            if (($path == $project['full_project_path'] .'/') && !drush_shell_exec('bzr add %s', $path)) {
+            if (!drush_shell_exec('bzr add --no-recurse %s', $path)) {
               $errors .= implode("\n", drush_shell_exec_output());
             }
           }
@@ -123,4 +127,8 @@ class drush_pm_version_control_bzr implements drush_pm_version_control {
       drush_print(dt("You should consider committing the new code to your Bazaar repository.\nIf this version becomes undesireable, use Bazaar to roll back."));
     }
   }
+
+  public static function reserved_files() {
+    return array('.bzr', '.bzrignore', '.bzrtags');
+  }
 }
diff --git a/sites/all/modules/drush/commands/pm/version_control/svn.inc b/sites/all/modules/drush/commands/pm/version_control/svn.inc
index ec5a9a32a27c1590a7e57ce9f94c5083454a868f..50795b729a18d9f3cf332f9bacd994114dfcf9f8 100644
--- a/sites/all/modules/drush/commands/pm/version_control/svn.inc
+++ b/sites/all/modules/drush/commands/pm/version_control/svn.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: svn.inc,v 1.14 2010/08/17 05:52:12 greg1anderson Exp $
 
 /**
  * @file Drush pm SVN extension
@@ -13,28 +12,31 @@ class drush_pm_version_control_svn implements drush_pm_version_control {
   public function pre_update(&$project, $items_to_test = array()) {
     // If items to test is empty, test everything; otherwise, pass just
     // the list of files to test to svn status.
-    $status_files = implode(' ', array_keys($items_to_test));
-    
-    // Check the project directory looks clean
-    if (drush_shell_cd_and_exec($project['full_project_path'], 'svn status '. drush_get_option('svnstatusparams') .' '. $status_files)) {
+    $args = array_keys($items_to_test);
+    array_unshift($args, 'svn status '. drush_get_option('svnstatusparams') . str_repeat('%s ', count($args)));
+    array_unshift($args, $project['full_project_path']);
+    if (call_user_func_array('drush_shell_cd_and_exec', $args)) {
       $output = preg_grep('/^[ ACDMRX?!~][ CM][ L][ +][ SX][ K]/', drush_shell_exec_output());
       if (!empty($output)) {
-        return drush_set_error('DRUSH_PM_SVN_LOCAL_CHANGES', dt("The SVN working copy at !path appears to have uncommmitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
+        return drush_set_error('DRUSH_PM_SVN_LOCAL_CHANGES', dt("The SVN working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
       }
     }
     else {
-      return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn status on !path. Check that you have Subversion \ninstalled and that this directory is a subversion working copy.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
+      return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
     }
-    
+
     // Check for incoming updates
-    if (drush_shell_cd_and_exec($project['full_project_path'], 'svn status -u '. drush_get_option('svnstatusparams') .' '. $status_files)) {
+    $args = array_keys($items_to_test);
+    array_unshift($args, 'svn status -u '. drush_get_option('svnstatusparams') . str_repeat('%s ', count($args)));
+    array_unshift($args, $project['full_project_path']);
+    if (call_user_func_array('drush_shell_cd_and_exec', $args)) {
       $output = preg_grep('/\*/', drush_shell_exec_output());
       if (!empty($output)) {
         return drush_set_error('DRUSH_PM_SVN_REMOTE_CHANGES', dt("The SVN working copy at !path appears to be out of date with the repository (see below). Please run 'svn update' to pull down changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
       }
     }
     else {
-      return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn remote status on !path. Check that you have Subversion \ninstalled, that this directory is a subversion working copy and that you have connectivity to the repository.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
+      return drush_set_error('DRUSH_PM_SVN_NOT_FOUND', dt("Drush was unable to get the svn remote status on !path. Check that you have connectivity to the repository.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
     }
     return TRUE;
   }
@@ -46,7 +48,7 @@ class drush_pm_version_control_svn implements drush_pm_version_control {
     if (drush_shell_exec('svn revert '. drush_get_option('svnrevertparams') .' '. $project['full_project_path'])) {
       $output = drush_shell_exec_output();
       if (!empty($output)) {
-        return drush_set_error('DRUSH_PM_SVN_LOCAL_CHANGES', dt("The SVN working copy at !path appears to have uncommmitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
+        return drush_set_error('DRUSH_PM_SVN_LOCAL_CHANGES', dt("The SVN working copy at !path appears to have uncommitted changes (see below). Please commit or revert these changes before continuing:\n!output", array('!path' => $project['full_project_path'], '!output' => implode("\n", $output))));
       }
     }
     else {
@@ -126,4 +128,8 @@ class drush_pm_version_control_svn implements drush_pm_version_control {
       drush_print(dt("You should consider committing the new code to your Subversion repository.\nIf this version becomes undesireable, use Subversion to roll back."));
     }
   }
+
+  public static function reserved_files() {
+    return array('.svn');
+  }
 }
diff --git a/sites/all/modules/drush/commands/sql/sql.drush.inc b/sites/all/modules/drush/commands/sql/sql.drush.inc
index 2bfb4e24e271a623d5d0fad7044f2344b67d1ad1..4ce6f4fe504b2bfdec690e88a4b981bfc3f4969e 100644
--- a/sites/all/modules/drush/commands/sql/sql.drush.inc
+++ b/sites/all/modules/drush/commands/sql/sql.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: sql.drush.inc,v 1.67 2010/12/01 04:46:08 greg1anderson Exp $
 
 /**
  * @file Drush sql commands
@@ -10,18 +9,10 @@
  */
 function sql_drush_help($section) {
   switch ($section) {
-    case 'drush:sql-conf':
-      return dt('Show database connection details.');
-    case 'drush:sql-connect':
-      return dt('A string which connects to the current database.');
-    case 'drush:sql-cli':
-      return dt('Quickly enter the mysql command line.');
-    case 'drush:sql-dump':
-      return dt('Prints the whole database to STDOUT or save to a file.');
-    case 'drush:sql-query':
-      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-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.");
+    case 'meta:sql:title':
+      return dt('SQL commands');
+    case 'meta:sql:summary':
+      return dt('Examine and modify your Drupal database.');
   }
 }
 
@@ -29,23 +20,25 @@ function sql_drush_help($section) {
  * Implementation of hook_drush_command().
  */
 function sql_drush_command() {
-  $options['--database'] = 'The DB connection key if using multiple connections in settings.php.';
+  $options['database'] = 'The DB connection key if using multiple connections in settings.php.';
   if (drush_drupal_major_version() >= 7) {
-    $options['--target'] = 'The name of a target within the specified database.';
+    $options['target'] = 'The name of a target within the specified database.';
   }
 
   $items['sql-drop'] = array(
     'description' => 'Drop all tables in a given database.',
     'arguments' => array(
     ),
-    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_DATABASE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION,
     'options' => array(
-      '--yes' => 'Skip confirmation and proceed.',
-      '--result-file' => 'Save to a file. The file should be relative to Drupal root. Recommended.',
+      'yes' => 'Skip confirmation and proceed.',
+      'result-file' => 'Save to a file. The file should be relative to Drupal root. Recommended.',
     ) + $options,
+    'topics' => array('docs-policy'),
   );
   $items['sql-conf'] = array(
     'description' => 'Print database connection details using print_r().',
+    'hidden' => TRUE,
     'arguments' => array(
       'all' => 'Show all database connections, instead of just one.',
       'show-passwords' => 'Show database password.',
@@ -70,15 +63,16 @@ function sql_drush_command() {
       'drush sql-dump --skip-tables-key=common' => 'Skip standard tables. @see example.drushrc.com',
     ),
     '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.',
-      '--structure-tables-key' => 'A key in the $structure_tables array. @see example.drushrc.php. Optional.',
-      '--tables-key' => 'A key in the $tables array. Optional.',
-      '--tables-list' => 'A comma-separated list of tables to transfer. Optional.',
-      '--ordered-dump' => 'Use this option to output ordered INSERT statements in the sql-dump.Useful when backups are managed in a Version Control System. Optional.',
-      '--create-db' => 'Wipe existing tables.',
-      '--data-only' => 'Omit CREATE TABLE statements. Postgres only.',
-      '--ordered-dump' => 'Order by primary key and add line breaks for efficient diff in revision control. Also, faster rsync. Slows down the dump. Mysql only.',
+      'result-file' => 'Save to a file. The file should be relative to Drupal root. If --result-file is provided with no value, then date based filename will be created under ~/drush-backups directory.',
+      '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.',
+      'tables-key' => 'A key in the $tables array. Optional.',
+      'tables-list' => 'A comma-separated list of tables to transfer. Optional.',
+      'ordered-dump' => 'Use this option to output ordered INSERT statements in the sql-dump.Useful when backups are managed in a Version Control System. Optional.',
+      'create-db' => 'Wipe existing tables.',
+      'data-only' => 'Omit CREATE TABLE statements. Postgres only.',
+      'ordered-dump' => 'Order by primary key and add line breaks for efficient diff in revision control. Also, faster rsync. Slows down the dump. Mysql only.',
+      'gzip' => 'Compress the dump using the gzip program which must be in your $PATH.',
     ) + $options,
   );
   $items['sql-query'] = array(
@@ -86,18 +80,23 @@ function sql_drush_command() {
     'description' => 'Execute a query against the site database.',
     'examples' => array(
       'drush sql-query "SELECT * FROM {users} WHERE uid=1"' => 'Browse user record. Table prefixes are honored.',
+      '`drush sql-connect` < example.sql' => 'Import sql statements from a file into the current database.',
+      'drush sql-query --input-file=example.sql' => 'Alternate way to import sql statements from a file.',
     ),
     'arguments' => array(
-       'query' => 'A SQL query. Mandatory.',
+       'query' => 'An SQL query. Ignored if \'file\' is provided.',
     ),
     'options' => array(
-      '--extra' => 'Add custom options to the mysql command.',
+      'result-file' => 'Save to a file. The file should be relative to Drupal root. Optional.',
+      'input-file' => 'Path to a file containing the SQL to be run.',
+      'extra' => 'Add custom options to the mysql command.',
     ) + $options,
     'aliases' => array('sqlq'),
   );
   $items['sql-sync'] = array(
-    'description' => 'Copy source database to target database using rsync.',
+    'description' => 'Copy and import source database to target database. Transfers via rsync.',
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'drush dependencies' => array('core'), // core-rsync.
     'examples' => array(
       'drush sql-sync @dev @prod' => 'Copy the DB defined in sites/dev to the DB in sites/prod.',
     ),
@@ -106,45 +105,47 @@ function sql_drush_command() {
       '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.',
-      '--tables-key' => 'A key in the $tables array. Optional.',
-      '--tables-list' => 'A comma-separated list of tables to transfer. Optional.',
-      '--cache' => 'Skip dump if result file exists and is less than "cache" hours old. Optional; default is 24 hours.',
-      '--no-cache' => 'Do not cache the sql-dump file.',
-      '--no-dump' => 'Do not dump the sql database; always use an existing dump file.',
-      '--source-db-url' => 'Database specification for source system to dump from.',
-      '--source-remote-port' => 'Override sql database port number in source-db-url. Optional.',
-      '--source-remote-host' => 'Remote machine to run sql-dump file on. Optional; default is local machine.',
-      '--source-dump' => 'Path to dump file. Optional; default is to create a temporary file.',
-      '--target-database' => 'A key in the $db_url (D6) or $databases (D7+) array which provides the data.',
-      '--source-target' => 'Oy. A key within the --target_database identifying a particular server in the database group.',
-      '--target-db-url' => '',
-      '--target-remote-port' => '',
-      '--target-remote-host' => '',
-      '--target-dump' => '',
-      '--target-database' => 'A key in the $db_url (D6) or $databases (D7+) array which shall receive the data.',
-      '--target-target' => 'Oy. A key within the --target_database identifying a particular server in the database group.',
-      '--temp' => 'Use a temporary file to hold dump files.  Implies --no-cache.',
-      '--dump-dir' => 'Directory to store sql dump files in when --source-dump or --target-dump are not used.  Takes precedence over --temp.',
-      '--create-db' => 'Create a new database before importing the database dump on the target machine.',
-      '--db-su' => 'Account to use when creating a new database. Optional.',
-      '--db-su-pw' => 'Password for the "db-su" account. Optional.',
-      '--sanitize' => 'Obscure email addresses and reset passwords in the user table post-sync. Optional.',
+      '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.',
+      'tables-key' => 'A key in the $tables array. Optional.',
+      'tables-list' => 'A comma-separated list of tables to transfer. Optional.',
+      'cache' => 'Skip dump if result file exists and is less than "cache" hours old. Optional; default is 24 hours.',
+      'no-cache' => 'Do not cache the sql-dump file.',
+      'no-dump' => 'Do not dump the sql database; always use an existing dump file.',
+      'source-db-url' => 'Database specification for source system to dump from.',
+      'source-remote-port' => 'Override sql database port number in source-db-url. Optional.',
+      'source-remote-host' => 'Remote machine to run sql-dump file on. Optional; default is local machine.',
+      'source-dump' => 'Path to dump file. Optional; default is to create a temporary file.',
+      'target-database' => 'A key in the $db_url (D6) or $databases (D7+) array which provides the data.',
+      'source-target' => 'Oy. A key within the --target_database identifying a particular server in the database group.',
+      'target-db-url' => '',
+      'target-remote-port' => '',
+      'target-remote-host' => '',
+      'target-dump' => '',
+      'target-database' => 'A key in the $db_url (D6) or $databases (D7+) array which shall receive the data.',
+      'target-target' => 'Oy. A key within the --target_database identifying a particular server in the database group.',
+      'temp' => 'Use a temporary file to hold dump files.  Implies --no-cache.',
+      'dump-dir' => 'Directory to store sql dump files in when --source-dump or --target-dump are not used.  Takes precedence over --temp.',
+      'create-db' => 'Create a new database before importing the database dump on the target machine.',
+      'db-su' => 'Account to use when creating a new database. Optional.',
+      'db-su-pw' => 'Password for the "db-su" account. Optional.',
+      'no-ordered-dump' => 'Do not pass --ordered-dump to sql-dump.  sql-sync orders the dumpfile by default in order to increase the efficiency of rsync.',
+      'sanitize' => 'Obscure email addresses and reset passwords in the user table post-sync. Optional.',
     ),
     'sub-options' => array(
-      '--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',
+      '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',
       ),
     ),
+    'topics' => array('docs-aliases', 'docs-policy'),
   );
   if (drush_drupal_major_version() >= 7) {
 
     $items['sql-sync']['options'] += array(
-      '--source-target' => 'The name of a target within the SOURCE database.',
-      '--destination-target' => 'The name of a target within the specified DESTINATION database.',
+      'source-target' => 'The name of a target within the SOURCE database.',
+      'destination-target' => 'The name of a target within the specified DESTINATION database.',
     );
   }
   $items['sql-cli'] = array(
@@ -153,6 +154,16 @@ function sql_drush_command() {
     'options' => $options,
     'aliases' => array('sqlc'),
   );
+  $items['sql-sanitize'] = array(
+    'description' => "Run sanitization operations on the current database.",
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_DATABASE,
+    'hidden' => TRUE,
+    'options' => 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".',
+    ),
+    'aliases' => array('sqlsan'),
+  );
   return $items;
 }
 
@@ -164,10 +175,7 @@ function drush_sql_conf() {
     $db_spec['db-url'] = $GLOBALS['db_url'];
   }
   elseif (drush_get_option('all', FALSE)) {
-    $db_spec = $GLOBALS['databases'];
-    if (!isset($db_spec)) {
-      $db_spec = array('default' => array('default' => _drush_sql_get_db_spec()));
-    }
+    $db_spec = _drush_sql_get_all_db_specs();
   }
   if (!isset($db_spec)) {
     $db_spec = _drush_sql_get_db_spec();
@@ -185,18 +193,16 @@ function drush_sql_conf() {
 function _drush_sql_connect($db_spec = NULL) {
   switch (_drush_sql_get_scheme($db_spec)) {
     case 'mysql':
-      $command = 'mysql ';
-      $command .= _drush_sql_get_credentials($db_spec);
+      $command = 'mysql';
       break;
     case 'pgsql':
       $command = 'psql';
-      $command .= _drush_sql_get_credentials($db_spec);
       break;
     case 'sqlite':
-      $command = 'sqlite3 ';
-      $command .= _drush_sql_get_credentials($db_spec);
+      $command = 'sqlite3';
       break;
   }
+  $command .= _drush_sql_get_credentials($db_spec);
   return $command;
 }
 
@@ -208,9 +214,13 @@ function drush_sql_connect() {
  * Command callback. Outputs the entire Drupal database in SQL format using mysqldump.
  */
 function drush_sql_dump_execute() {
-  $exec = drush_sql_dump();
+  list($exec, $file) = drush_sql_dump();
   // Avoid the php memory of the $output array in drush_shell_exec().
-  $return = drush_op('system', $exec);
+  if (!$return = drush_op_system($exec)) {
+    if ($file) {
+      drush_log(dt('Database dump saved to !path', array('!path' => $file)), 'success');
+    }
+  }
   return $return;
 }
 
@@ -226,21 +236,35 @@ function drush_sql_get_table_selection() {
 }
 
 /**
- * Build a mysqldump statement.
+ * Build a mysqldump/pg_dump/sqlite statement.
  *
  * @param db_spec
  *   For D5/D6, a $db_url. For D7, a target in the default DB connection.
- * @return string
- *   A mysqldump statement that is ready for executing.
+ * @return array
+ *   An array with items.
+ *     1. A mysqldump/pg_dump/sqlite statement that is ready for executing.
+ *     2. The filepath where the dump will be saved.
  */
 function drush_sql_dump($db_spec = NULL) {
   return drush_sql_build_dump_command(drush_sql_get_table_selection(), $db_spec);
 }
 
-function drush_sql_build_dump_command($tabel_selection, $db_spec = NULL) {
-  $skip_tables = $tabel_selection['skip'];
-  $structure_tables = $tabel_selection['structure'];
-  $tables = $tabel_selection['tables'];
+/**
+ * Build a mysqldump/pg_dump/sqlite statement.
+ *
+ * @param array $table_selection
+ *   Supported keys: 'skip', 'structure', 'tables'.
+ * @param db_spec
+ *   For D5/D6, a $db_url. For D7, a target in the default DB connection.
+ * @return array
+ *   An array with items.
+ *     1. A mysqldump/pg_dump/sqlite statement that is ready for executing.
+ *     2. The filepath where the dump will be saved.
+ */
+function drush_sql_build_dump_command($table_selection, $db_spec = NULL) {
+  $skip_tables = $table_selection['skip'];
+  $structure_tables = $table_selection['structure'];
+  $tables = $table_selection['tables'];
 
   $ignores = array();
   $skip_tables  = array_merge($structure_tables, $skip_tables);
@@ -254,23 +278,24 @@ function drush_sql_build_dump_command($tabel_selection, $db_spec = NULL) {
     $db_spec = _drush_sql_get_db_spec();
   }
   $database = $db_spec['database'];
-  
+
   // Get the setting of --result-file.  If the user
   // has set $options['result-file'] = TRUE, then we
   // will generate an SQL dump file in the same backup
   // directory that pm-updatecode uses.
+  $file = NULL;
   if ($file = drush_get_option('result-file', FALSE)) {
     if ($file === TRUE) {
       // User did not pass a specific value for --result-file. Make one.
       drush_include_engine('version_control', 'backup');
       $backup = new drush_pm_version_control_backup();
-      $backup_dir = $backup->prepare_backup_dir();
+      $backup_dir = $backup->prepare_backup_dir($db_spec['database']);
       if (empty($backup_dir)) {
         $backup_dir = "/tmp";
       }
       $file = $backup_dir . '/@DATABASE_@DATE.sql';
     }
-    $file = str_replace(array('@DATABASE', '@DATE'), array($database, date('Ymd_his')), $file);
+    $file = str_replace(array('@DATABASE', '@DATE'), array($database, gmdate('Ymd_his')), $file);
   }
 
   switch (_drush_sql_get_scheme($db_spec)) {
@@ -314,13 +339,8 @@ function drush_sql_build_dump_command($tabel_selection, $db_spec = NULL) {
       if ($file) {
         $exec .= ' --file '. $file;
       }
-      // 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);
+      // Unlike psql, pg_dump does not take a '--dbname=' before the database name.
+      $extra = str_replace('--dbname=', ' ', _drush_sql_get_credentials($db_spec));
       if (isset($data_only)) {
         $extra .= ' --data-only';
       }
@@ -366,7 +386,19 @@ function drush_sql_build_dump_command($tabel_selection, $db_spec = NULL) {
       break;
   }
 
-  return $exec;
+  if (drush_get_option('gzip')) {
+    if ($file) {
+      // Gzip the result-file
+      $exec .= "; gzip $file";
+      $file .= '.gz';
+    }
+    else {
+      // gzip via pipe since user has not specified a file.
+      $exec .= "| gzip";
+    }
+  }
+
+  return array($exec, $file);
 }
 
 /**
@@ -383,7 +415,7 @@ function drush_sql_build_dump_command($tabel_selection, $db_spec = NULL) {
  *   found, or an empty array if there were no matches.
  */
 function _drush_sql_get_table_list($option_name) {
-  foreach(array('' => 'options', 'target-,,source-' => NULL) as $prefix_list => $context) {
+  foreach(array('' => 'cli', 'target-,,source-' => NULL) as $prefix_list => $context) {
     foreach(explode(',',$prefix_list) as $prefix) {
       $key_list = drush_get_option($prefix . $option_name . '-key', NULL, $context);
       foreach(explode(',', $key_list) as $key) {
@@ -412,18 +444,34 @@ function _drush_sql_get_table_list($option_name) {
  * Command callback. Executes the given SQL query on the Drupal database.
  */
 function drush_sql_query($query) {
-  return _drush_sql_query($query);
+  $filename = drush_get_option('file', NULL);
+  return _drush_sql_query($query, NULL, $filename);
 }
 
-function _drush_sql_query($query, $db_spec = NULL) {
+/*
+ * Execute a SQL query.
+ *
+ * @param string $query
+ *   The SQL to be executed. Should be NULL if $file is provided.
+ * @param array $db_spec
+ *   A database target.
+ * @param string $filename
+ *   A path to a file containing the SQL to be executed.
+ */
+function _drush_sql_query($query, $db_spec = NULL, $filename = NULL) {
   $scheme = _drush_sql_get_scheme($db_spec);
 
   // Inject table prefixes as needed.
-  if (drush_drupal_major_version() >= 7) {
-    $query = Database::getConnection()->prefixTables($query);
-  }
-  else {
-    $query = db_prefix_tables($query);
+  if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_DATABASE)) {
+    if ($filename) {
+      $query = file_get_contents($filename);
+    }
+    if (drush_drupal_major_version() >= 7) {
+      $query = Database::getConnection()->prefixTables($query);
+    }
+    else {
+      $query = db_prefix_tables($query);
+    }
   }
 
   // Convert mysql 'show tables;' query into something pgsql understands
@@ -431,28 +479,39 @@ function _drush_sql_query($query, $db_spec = NULL) {
     $query = drush_sql_show_tables_pgsql();
   }
 
-  // Save $query to a tmp file. We will redirect it in.
-  if ($filename = drush_save_data_to_temp_file($query)) {
-    $exec = drush_sql_build_exec($db_spec, $filename);
-    // In --simulate mode, drush_op will show the call to mysql or psql,
-    // but the sql query itself is stored in a temp file and not displayed.
-    // We will therefore show the query explicitly in the interest of full disclosure.
-    if (drush_get_context('DRUSH_SIMULATE')) {
-      drush_print('sql-query: ' . $query);
-    }
-    $return = drush_op('system', $exec) !== FALSE;
-    return $return;
+  // Save $query to a tmp file if needed. We will redirect it in.
+  if (!$filename) {
+    $filename = drush_save_data_to_temp_file($query);
+  }
+  $exec = drush_sql_build_exec($db_spec, $filename);
+  if ($output_file = drush_get_option('result-file')) {
+    $exec .= ' > '. drush_escapeshellarg($output_file);
   }
+  // In --simulate mode, drush_op will show the call to mysql or psql,
+  // but the sql query itself is stored in a temp file and not displayed.
+  // We will therefore show the query explicitly in the interest of full disclosure.
+  if (drush_get_context('DRUSH_SIMULATE')) {
+    drush_print('sql-query: ' . $query);
+  }
+  $return = drush_op_system($exec) == 0;
+  return $return;
 }
 
 function drush_sql_drop() {
   if (!drush_confirm(dt('Do you really want to drop all tables?'))) {
-    drush_user_abort();
+    return drush_user_abort();
   }
+  _drush_sql_drop();
+}
 
+// n.b. site-install uses _drush_sql_drop as a fallback technique if
+// drop database; create database fails.  If _drush_sql_drop
+// is rewritten to also use that technique, it should maintain
+// the drop tables code here as a fallback.
+function _drush_sql_drop($db_spec = NULL) {
   // TODO: integrate with _drush_sql_get_table_list?
 
-  $scheme = _drush_sql_get_scheme();
+  $scheme = _drush_sql_get_scheme($db_spec);
   switch ($scheme) {
     case 'pgsql':
       $query = drush_sql_show_tables_pgsql();
@@ -463,68 +522,92 @@ function drush_sql_drop() {
     default:
       $query = 'SHOW TABLES;';
   }
-  
+
   $filename = drush_save_data_to_temp_file($query);
-  $exec = drush_sql_build_exec(NULL, $filename);
-  
+  $exec = drush_sql_build_exec($db_spec, $filename);
+
   // Actually run this prep query no matter if in SIMULATE.
   $old = drush_get_context('DRUSH_SIMULATE');
   drush_set_context('DRUSH_SIMULATE', FALSE);
   drush_shell_exec($exec);
   drush_set_context('DRUSH_SIMULATE', $old);
-  $tables = drush_shell_exec_output();
-  if ($scheme === 'sqlite') {
-    // SQLite's '.tables' command always outputs the table names in a column
-    // format, like this:
-    // table_alpha    table_charlie    table_echo
-    // table_bravo    table_delta      table_foxtrot
-    // …and there doesn't seem to be a way to fix that. So we need to do some
-    // clean-up.
-    // Since we're already doing iteration here, might as well build the SQL
-    // too, since SQLite only wants one table per DROP TABLE command (so we have
-    // to do "DROP TABLE foo; DROP TABLE bar;" instead of
-    // "DROP TABLE foo, bar;").
-    $sql = '';
-    foreach ($tables as $line) {
-      preg_match_all('/[^\s]+/', $line, $matches);
-      if (!empty($matches[0])) {
-        foreach ($matches[0] as $match) {
-          $sql .= "DROP TABLE {$match};";
+  if ($tables = drush_shell_exec_output()) {
+    if ($scheme === 'sqlite') {
+      // SQLite's '.tables' command always outputs the table names in a column
+      // format, like this:
+      // table_alpha    table_charlie    table_echo
+      // table_bravo    table_delta      table_foxtrot
+      // …and there doesn't seem to be a way to fix that. So we need to do some
+      // clean-up.
+      // Since we're already doing iteration here, might as well build the SQL
+      // too, since SQLite only wants one table per DROP TABLE command (so we have
+      // to do "DROP TABLE foo; DROP TABLE bar;" instead of
+      // "DROP TABLE foo, bar;").
+      $sql = '';
+      foreach ($tables as $line) {
+        preg_match_all('/[^\s]+/', $line, $matches);
+        if (!empty($matches[0])) {
+          foreach ($matches[0] as $match) {
+            $sql .= "DROP TABLE {$match};";
+          }
         }
       }
+      // We can't use drush_op('db_query', $sql) because it will only perform one
+      // SQL command and we're technically performing several.
+      $exec = _drush_sql_connect($db_spec);
+      $exec .= " '{$sql}'";
+      return drush_op_system($exec) == 0;
+    }
+    else {
+      // Shift off the header of the column of data returned.
+      array_shift($tables);
+      $sql = 'DROP TABLE '. implode(', ', $tables);
+      return _drush_sql_query($sql, $db_spec);
     }
-    // We can't use drush_op('db_query', $sql) because it will only perform one
-    // SQL command and we're technically performing several.
-    $exec = _drush_sql_connect();
-    $exec .= " '{$sql}'";
-    return drush_op('system', $exec);
   }
   else {
-    // Shift off the header of the column of data returned.
-    array_shift($tables);
-    $sql = 'DROP TABLE '. implode(', ', $tables);
-    return drush_op('db_query', $sql);
+    drush_log(dt('No tables to drop.'), 'ok');
   }
+  return TRUE;
 }
 
 function drush_sql_cli() {
-  switch (_drush_sql_get_scheme()) {
-    case 'mysql':
-      $command = 'mysql ' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
-      $command .= _drush_sql_get_credentials();
-      break;
-    case 'pgsql':
-      $command = 'psql ';
-      $command .= _drush_sql_get_credentials();
-      break;
-    case 'sqlite':
-      $command = 'sqlite3 ';
-      $command .= _drush_sql_get_credentials();
-      break;
-  }
-  proc_close(proc_open($command, array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $pipes));
+  proc_close(proc_open(_drush_sql_connect(), array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $pipes));
 }
 
+/**
+ * Command callback. Run's the sanitization operations on the current database.
+ */
+function drush_sql_sanitize() {
+  if (!drush_confirm(dt('Do you really want to sanitize the current database?'))) {
+    return drush_user_abort();
+  }
+  drush_include(DRUSH_BASE_PATH . '/commands/sql', 'sync.sql');
+  drush_command_invoke_all('drush_sql_sync_sanitize', 'default');
+  $options = drush_get_context('post-sync-ops');
+  if (!empty($options)) {
+    if (!drush_get_context('DRUSH_SIMULATE')) {
+      $messages = _drush_sql_get_post_sync_messages();
+      if ($messages) {
+        drush_print();
+        drush_print($messages);
+      }
+    }
+  }
+
+  $sanitize_query = '';
+  foreach($options as $id => $data) {
+    $sanitize_query .= $data['query'] . " ";
+  }
+  if ($sanitize_query) {
+    if (!drush_get_context('DRUSH_SIMULATE')) {
+      drush_sql_query($sanitize_query);
+    }
+    else {
+      drush_print("Executing: $sanitize_query");
+    }
+  }
+}
 
 //////////////////////////////////////////////////////////////////////////////
 // SQL SERVICE HELPERS
@@ -557,6 +640,20 @@ function _drush_sql_get_db_spec() {
   }
 }
 
+function _drush_sql_get_all_db_specs() {
+  switch (drush_drupal_major_version()) {
+    case 5:
+    case 6:
+      return drush_sitealias_convert_db_from_db_url($GLOBALS['db_url']);
+
+    default:
+      if (!isset($GLOBALS['databases'])) {
+        return NULL;
+      }
+      return $GLOBALS['databases'];
+  }
+}
+
 function _drush_sql_get_spec_from_options($prefix, $default_to_self = TRUE) {
   $db_spec = NULL;
   $databases = drush_get_option($prefix . 'databases');
@@ -673,10 +770,9 @@ function _drush_sql_get_credentials($db_spec = NULL) {
       break;
 
     case 'pgsql':
-      // Database is optional in Postgres.
-      if (isset($db_spec['database'])) {
-        $parameters['dbname'] = empty($db_spec['database']) ? 'template1' : $db_spec['database'];
-      }
+      // Some drush commands (e.g. site-install) want to connect to the
+      // server, but not the database.  Connect to the built-in database.
+      $parameters['dbname'] = empty($db_spec['database']) ? 'template1' : $db_spec['database'];
 
       // Host and port are optional but have defaults.
       $parameters['host'] = empty($db_spec['host']) ? 'localhost' : $db_spec['host'];
@@ -781,20 +877,114 @@ function drush_sql_show_tables_pgsql() {
   return "select tablename from pg_tables where schemaname='public';";
 }
 
+/*
+ * Drop all tables or DROP+CREATE target database.
+ *
+ * return boolean
+ *   TRUE or FALSE depending on success.
+ */
+function drush_sql_empty_db($db_spec = NULL) {
+  if (is_null($db_spec)) {
+    $db_spec = drush_sql_read_db_spec();
+  }
+  $sql = drush_sql_build_createdb_sql($db_spec, TRUE);
+  // Get credentials to connect to the server, but not the database which we
+  // are about to DROP. @see _drush_sql_get_credentials().
+  $create_db_spec = $db_spec;
+  unset($create_db_spec['database']);
+  $create_db_su = drush_sql_su($create_db_spec);
+  if (!_drush_sql_query($sql, $create_db_su)) {
+    // If we could not drop the database, try instead to drop all
+    // of the tables in the database (presuming it exists...).
+    // If we cannot do either operation, then fail with an error.
+    if (!_drush_sql_drop($db_spec)) {
+      return drush_set_error(dt('Could not drop and create database: @name', array('@name' => $db_name)));
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Return a db_spec based on supplied db_url/db_prefix options or an existing
+ * settings.php.
+ */
+function drush_sql_read_db_spec() {
+  if ($db_url = drush_get_option('db-url')) {
+    // We were passed a db_url. Usually a fresh site.
+    $db_spec = drush_convert_db_from_db_url($db_url);
+    $db_spec['db_prefix'] = drush_get_option('db-prefix');
+    return $db_spec;
+  }
+  elseif (drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION)) {
+    // We have an existing settings.php.
+    $db_spec = _drush_sql_get_db_spec();
+    $db_spec['db_prefix'] = $GLOBALS['db_prefix'];
+    return $db_spec;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/*
+ * Build DB connection array with superuser credentials if provided.
+ */
+function drush_sql_su($db_spec) {
+  $create_db_target = $db_spec;
+  $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_pw = drush_get_option(array('db-su-pw', 'target-db-su-pw'));
+  if (isset($db_su_pw)) {
+    $create_db_target['password'] = $db_su_pw;
+  }
+  return $create_db_target;
+}
+
+/*
+ * Build a SQL string for dropping and creating a database.
+ *
+ * @param array $db_spec
+ *   A database specification array.
+ *
+ * @param boolean $quoted
+ *   Quote the database name. Mysql uses backticks to quote which can cause problems
+ *   in a Windows shell. Set TRUE of the CREATE is not running on the bash command line.
+ */
+function drush_sql_build_createdb_sql($db_spec, $quoted = FALSE) {
+  switch (_drush_sql_get_scheme($db_spec)) {
+    case 'mysql':
+      $dbname = $quoted ? '`' . $db_spec['database'] . '`' : $db_spec['database'];
+      $sql[] = sprintf('DROP DATABASE IF EXISTS %s; ', $dbname);
+      $sql[] = sprintf('CREATE DATABASE %s /*!40100 DEFAULT CHARACTER SET utf8 */;', $dbname);
+      $sql[] = sprintf('GRANT ALL PRIVILEGES ON %s.* TO \'%s\'@\'%s\'', $dbname, $db_spec['username'], $db_spec['host']);
+      $sql[] = sprintf("IDENTIFIED BY '%s';", $db_spec['password']);
+      $sql[] = 'FLUSH PRIVILEGES;';
+      break;
+    case 'pgsql':
+      $dbname = $quoted ? '"' . $db_spec['database'] . '"' : $db_spec['database'];
+      $sql[] = sprintf('drop database if exists %s;', $dbname);
+      $sql[] = sprintf("create database %s ENCODING 'UTF8';", $dbname);
+      break;
+  }
+  return implode(' ', $sql);
+}
+
 function drush_sql_build_exec($db_spec, $filepath) {
   $scheme = _drush_sql_get_scheme($db_spec);
   switch ($scheme) {
     case 'mysql':
-      $exec = 'mysql' . (drush_get_context('DRUSH_VERBOSE') ? ' -v' : '');
+      $exec = 'mysql';
       $exec .= _drush_sql_get_credentials($db_spec);
       $exec .= ' ' . drush_get_option('extra');
       $exec .= " < $filepath";
 
       break;
     case 'pgsql':
-      $exec = 'psql';
+      $exec = 'psql -q ';
       $exec .= _drush_sql_get_credentials($db_spec);
-      $exec .= (drush_get_context('DRUSH_VERBOSE') ? '' : ' -q');
       $exec .= ' ' . (drush_get_option('extra') ? drush_get_option('extra') : "--no-align --field-separator='\t' --pset footer=off");
       $exec .= " --file $filepath";
       break;
diff --git a/sites/all/modules/drush/commands/sql/sync.sql.inc b/sites/all/modules/drush/commands/sql/sync.sql.inc
index d57d6abffde5f65f9aff591396851a9f0c9c49d9..29f8cedb9f33125f3272f9fce5091e6dc9ce9f9c 100644
--- a/sites/all/modules/drush/commands/sql/sync.sql.inc
+++ b/sites/all/modules/drush/commands/sql/sync.sql.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: sync.sql.inc,v 1.37 2010/12/01 15:45:53 weitzman Exp $
 
 require_once DRUSH_BASE_PATH . '/commands/core/rsync.core.inc';
 
@@ -42,6 +41,12 @@ function drush_sql_sync_init($source = NULL, $destination = NULL) {
     }
   }
   
+  // By default, sql-sync will do an ordered dump.
+  // Set --no-ordered-dump to override.
+  if (!drush_get_option('no-ordered-dump', FALSE)) {
+    drush_set_option('ordered-dump', TRUE);
+  }
+  
   return TRUE;
 }
 
@@ -67,7 +72,7 @@ function sql_drush_sql_sync_sanitize($site) {
   $user_table_updates = array();
   $message_list = array();
 
-  // Sanitize email addresses
+  // Sanitize passwords.
   $newpassword = drush_get_option(array('sanitize-password', 'destination-sanitize-password'), 'password');
   if ($newpassword != 'no') {
     $major_version = drush_drupal_major_version();
@@ -91,18 +96,18 @@ function sql_drush_sql_sync_sanitize($site) {
     }
   }
 
-  // Sanitize passwords
+  // Sanitize email addresses.
   $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
+      // 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, ' ', '_') || '");
+        $email_map = array('%uid' => "' || uid || '", '%mail' => "' || replace(mail, '@', '_') || '", '%name' => "' || replace(name, ' ', '_') || '");
         $newmail =  "'" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "'";
       }
       else {
-        $email_map = array('%uid' => "', uid, '", '%mail' => "', replace(mail, '@', '_'), '", '%login' => "', replace(login, ' ', '_'), '");
+        $email_map = array('%uid' => "', uid, '", '%mail' => "', replace(mail, '@', '_'), '", '%name' => "', replace(name, ' ', '_'), '");
         $newmail =  "concat('" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "')";
       }
     }
@@ -283,14 +288,14 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
       }
       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 operations 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.");
+        drush_print("WARNING: --sanitize was specified, but deferred (e.g. the source site is remote).  The sanitization operations 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"));
       if (!drush_confirm(dt('Do you really want to continue?'))) {
-        drush_user_abort();
+        return drush_user_abort();
       }
     }
 
@@ -314,7 +319,8 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
           $mv_intermediate = '; mv -f ' . $source_intermediate . ' ' . $source_dump;
         }
         drush_set_option('result-file', $source_intermediate);
-        $dump_exec = drush_sql_build_dump_command($table_selection, $source_db_url) . $mv_intermediate;
+        list($dump_exec, $dump_file) = drush_sql_build_dump_command($table_selection, $source_db_url);
+        $dump_exec .= $mv_intermediate;
         if (isset($cache) && !$source_db_url['dump-is-temp']) {
           // Inject some bash commands to remotely test the modification date of the target file
           // if the cache option is set.
@@ -326,14 +332,14 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
     else {
       if (!isset($no_dump)) {
         drush_set_option('result-file', $local_file);
-        $dump_exec = drush_sql_build_dump_command($table_selection, $source_db_url);
+        list($dump_exec, $dump_file) = drush_sql_build_dump_command($table_selection, $source_db_url);
       }
       $no_sync = TRUE;
     }
 
     // Call sql-dump, either on the local machine or remotely via ssh, as appropriate.
     if (!empty($dump_exec)) {
-      drush_op('system', $dump_exec);
+      drush_op_system($dump_exec);
       // TODO: IF FAILURE THEN ABORT
     }
 
@@ -341,7 +347,9 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
     if (!isset($no_sync)) {
       // If the source file is a temporary file, then we will have rsync
       // delete it for us (remove-source-files option set above).
-      drush_core_call_rsync($source_remote_user . $source_at . $source_db_url['remote-host'] . ':' . $source_dump, $local_file, $source_rsync_options);
+      if (!drush_core_call_rsync($source_remote_user . $source_at . $source_db_url['remote-host'] . ':' . $source_dump, $local_file, $source_rsync_options)) {
+        return FALSE;
+      }
     }
 
     // We will handle lists of destination sites differently from
@@ -370,25 +378,10 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
       $pre_import_commands = '';
       $create_db = drush_get_option('create-db');
       if (isset($create_db)) {
-        $create_db_target = $target_db_url;
-        $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_pw = drush_get_option(array('db-su-pw', 'target-db-su-pw'));
-        if (isset($db_su_pw)) {
-          $create_db_target['password'] = $db_su_pw;
-        }
-        $db_su_connect = _drush_sql_connect($create_db_target);
-        switch (_drush_sql_get_scheme($target_db_url)) {
-          case 'mysql':
-            $pre_import_commands = 'echo "DROP DATABASE IF EXISTS ' . $target_db_url['database'] . '; CREATE DATABASE ' . $target_db_url['database'] . '; GRANT ALL PRIVILEGES ON ' . $target_db_url['database'] . '.* TO \'' . $target_db_url['username'] . '\'@\'' . $target_db_url['host'] . '\' IDENTIFIED BY \'' . $target_db_url['password'] . '\';" | ' . $db_su_connect . '; ';
-            break;
-          case 'pgsql':
-            $pre_import_commands = 'echo "drop database if exists ' . $target_db_url['database'] . '; create database ' . $target_db_url['database'] . ';" | ' . $db_su_connect . '; ';
-            break;
-        }
+        $create_db_su = drush_sql_su($target_db_url);
+        $db_su_connect = _drush_sql_connect($create_db_su);
+        $pre_import_sql = drush_sql_build_createdb_sql($target_db_url);
+        $pre_import_commands = sprintf('echo "%s" | %s; ', $pre_import_sql, $db_su_connect);
       }
 
       // Generate the import command
@@ -412,7 +405,9 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
           $target_remote_pass = drush_get_option('target-remote-pass') ? ':' . drush_get_option('target-remote-pass') : '';
         }
 
-        drush_core_call_rsync($local_file, $target_remote_user . $target_at . $target_db_url['remote-host'] . ':' . $target_dump, $target_rsync_options);
+        if (!drush_core_call_rsync($local_file, $target_remote_user . $target_at . $target_db_url['remote-host'] . ':' . $target_dump, $target_rsync_options)) {
+          return FALSE;
+        }
 
         $connect_exec = $pre_import_commands . $import_command . ' < ' . $target_dump;
         $import_exec = "ssh $target_remote_ssh_options $target_remote_user$target_at" . $target_db_url['remote-host'] . ' ' . escapeshellarg($connect_exec);
@@ -425,7 +420,7 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
         $import_exec = $pre_import_commands . $import_command . ' < ' . $local_file;
       }
 
-      drush_op('system', $import_exec);
+      drush_op_system($import_exec);
       
       // After the database is imported into the destination, we
       // will check and see if we did not collect sanitization
@@ -435,10 +430,10 @@ function drush_sql_sync($source = NULL, $destination = NULL) {
       // This presumes an important precondition, that the code
       // files were sync'ed before the database was sync'ed.
       if (drush_get_option('deferred-sanitization', FALSE) && (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);
-	}
+        $bootstrapped = drush_bootstrap_max_to_sitealias($destination_settings);
+        if ($bootstrapped) {
+          drush_command_invoke_all('drush_sql_sync_sanitize', $destination);
+        }
       }
     }
   }
@@ -460,16 +455,19 @@ function drush_sql_post_sql_sync($source = NULL, $destination = NULL) {
     // 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) {
+        $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_user_abort('Aborting; sql-sync completed, but sanitizations skipped.');
-	    }
-	  }
-	}
+              // Do not abort or return FALSE; that would trigger a rollback.
+              // Just skip the sanitizations and signal that all is ok.
+              drush_log(dt('Sanitizations skipped.'), 'ok');
+              return TRUE;
+            }
+          }
+        }
       }
     }
     
@@ -480,7 +478,7 @@ function drush_sql_post_sql_sync($source = NULL, $destination = NULL) {
     }
     if ($sanitize_query) {
       if (!drush_get_context('DRUSH_SIMULATE')) {
-        $result = drush_do_site_command($destination_settings, "sql-query", array($sanitize_query));
+        $result = drush_invoke_sitealias_args($destination_settings, "sql-query", array($sanitize_query));
       }
       else {
         drush_print("Executing on $destination: $sanitize_query");
diff --git a/sites/all/modules/drush/commands/user/user.drush.inc b/sites/all/modules/drush/commands/user/user.drush.inc
index 40b384645a1317296eb5e23a6a751c086ca2669c..bb932b14387d9e79b30bc681f219ec02426ccb46 100644
--- a/sites/all/modules/drush/commands/user/user.drush.inc
+++ b/sites/all/modules/drush/commands/user/user.drush.inc
@@ -5,29 +5,12 @@
  * @file Drush User Management commands
  */
 
-/**
- * Implementation of hook_drush_help().
- */
 function user_drush_help($section) {
   switch ($section) {
-    case 'drush:user-information':
-      return dt("Display information about a user identified by username, uid or email address.");
-    case 'drush:user-block':
-      return dt("Block the specified user(s).");
-    case 'drush:user-unblock':
-      return dt("Unblock the specified user(s).");
-    case 'drush:user-add-role':
-      return dt("Add a role to the specified user accounts.");
-    case 'drush:user-remove-role':
-      return dt("Remove a role from the specified user accounts.");
-    case 'drush:user-create':
-      return dt("Create a user account.");
-    case 'drush:user-cancel':
-      return dt("Cancel a user account.");
-    case 'drush:user-password':
-      return dt("(Re)Set the password for the given user account.");
-    case 'drush:user-login':
-      return dt("Display a one time login link for the given user account (defaults to uid 1).");
+    case 'meta:user:title':
+      return dt('User commands');
+    case 'meta:user:summary':
+      return dt('Add, modify and delete users.');
   }
 }
 
@@ -47,8 +30,8 @@ function user_drush_command() {
       'users' => 'A comma delimited list of uids, user names, or email addresses.',
     ),
     'options' => array(
-      '--full' => 'show extended information about the user',
-      '--short' => 'show basic information about the user (this is the default)',
+      'full' => 'show extended information about the user',
+      'short' => 'show basic information about the user (this is the default)',
     ),
   );
   $items['user-block'] = array(
@@ -63,9 +46,9 @@ function user_drush_command() {
         'Block the users with name, id, or email 5 or user3, uids 2 and 3, names someguy and somegal, and email address of billgates@microsoft.com',
     ),
     'options' => array(
-      '--uid' => 'A comma delimited list of uids to block',
-      '--name' => 'A comma delimited list of user names to block',
-      '--mail' => 'A comma delimited list of user mail addresses to block',
+      'uid' => 'A comma delimited list of uids to block',
+      'name' => 'A comma delimited list of user names to block',
+      'mail' => 'A comma delimited list of user mail addresses to block',
     ),
   );
   $items['user-unblock'] = array(
@@ -80,9 +63,9 @@ function user_drush_command() {
         'Unblock the users with name, id, or email 5 or user3, uids 2 and 3, names someguy and somegal, and email address of billgates@microsoft.com',
     ),
     'options' => array(
-      '--uid' => 'A comma delimited list of uids to unblock',
-      '--name' => 'A comma delimited list of user names to unblock',
-      '--mail' => 'A comma delimited list of user mail addresses to unblock',
+      'uid' => 'A comma delimited list of uids to unblock',
+      'name' => 'A comma delimited list of user names to unblock',
+      'mail' => 'A comma delimited list of user mail addresses to unblock',
     ),
   );
   $items['user-add-role'] = array(
@@ -98,9 +81,9 @@ function user_drush_command() {
         'Add the "power user" role to the accounts with name, id, or email 5 or user3, uids 2 and 3, names someguy and somegal, and email address of billgates@microsoft.com',
     ),
     'options' => array(
-      '--uid' => 'A comma delimited list of uids',
-      '--name' => 'A comma delimited list of user names',
-      '--mail' => 'A comma delimited list of user mail addresses',
+      'uid' => 'A comma delimited list of uids',
+      'name' => 'A comma delimited list of user names',
+      'mail' => 'A comma delimited list of user mail addresses',
     ),
   );
   $items['user-remove-role'] = array(
@@ -116,9 +99,9 @@ function user_drush_command() {
         'Remove the "power user" role from the accounts with name, id, or email 5 or user3, uids 2 and 3, names someguy and somegal, and email address of billgates@microsoft.com',
     ),
     'options' => array(
-      '--uid' => 'A comma delimited list of uids',
-      '--name' => 'A comma delimited list of user names',
-      '--mail' => 'A comma delimited list of user mail addresses',
+      'uid' => 'A comma delimited list of uids',
+      'name' => 'A comma delimited list of user names',
+      'mail' => 'A comma delimited list of user mail addresses',
     ),
   );
   $items['user-create'] = array(
@@ -133,8 +116,8 @@ function user_drush_command() {
         'Create a new user account with the name newuser, the email address person@example.com, and the password letmein',
     ),
     'options' => array(
-      '--password' => 'The password for the new account',
-      '--mail' => 'The email address for the new account',
+      'password' => 'The password for the new account',
+      'mail' => 'The email address for the new account',
     ),
   );
   $items['user-cancel'] = array(
@@ -157,7 +140,7 @@ function user_drush_command() {
       'name' => 'The name of the account to modify'
     ),
     'options' => array(
-      '--password' => '(required) The new password for the account',
+      'password' => '(required) The new password for the account',
     ),
     'examples' => array(
       'drush user-password someuser --password="gr3@tP@$s"' => 
@@ -396,6 +379,7 @@ function drush_user_create($name) {
       $new_user_object = user_save(NULL, $new_user, NULL);
       if ($new_user_object !== FALSE) {
         _drush_user_print_info($new_user_object->uid);
+        return $new_user_object->uid;
       }
       else {
         drush_set_error("Could not create a new user account with the name " . $name . "!");
@@ -490,7 +474,9 @@ function drush_user_login($name = NULL) {
   }
 
   if ($user !== FALSE) {
-    drush_print(user_pass_reset_url($user));
+    $link = user_pass_reset_url($user);
+    drush_print($link);
+    return $link;
   }
   else {
     drush_set_error("The user account with the name " . $name . " could not be loaded!");
diff --git a/sites/all/modules/drush/docs/bootstrap.html b/sites/all/modules/drush/docs/bootstrap.html
new file mode 100644
index 0000000000000000000000000000000000000000..b17244b898fd32eb0c2f22be4515af18511f2dad
--- /dev/null
+++ b/sites/all/modules/drush/docs/bootstrap.html
@@ -0,0 +1,135 @@
+<h1>The Drush Bootstrap Process</h1>
+<p>
+When preparing to run a command, drush works by "bootstrapping" 
+the Drupal environment in very much the same way that is done 
+during a normal page request from the web server, so most drush 
+commands run in the context of a fully-initialized website.
+<p>
+For efficiency and convenience, some drush commands can work
+without first bootstrapping a Drupal site, or by only partially
+bootstrapping a site.  This is more efficient, because there is
+sometimes a slight delay involved with bootstrapping, especially
+in some of the later stages.  It is also a matter of convenience,
+because some commands are useful to use even when you do not
+have a working Drupal site available to bootstrap.  For example,
+you can use drush to download Drupal with `drush dl drupal`.  This
+obviously does not require any bootstrapping to work.
+<p>
+The drush bootstrapping process is also very closely related with
+drush configuration files.  At each bootstrap phase, drush may load
+additional configuration files that may contain additional drush
+settings.  This has two very important connotations.  First, settings
+that are only loaded in a later bootstrap phase are not available
+for commands that do not reach that bootstrap phase.  Second, it
+is possible to alter drush behavior on a per-site basis by applying
+settings in a site-specific configuration file.  See 
+`drush topic docs-configuration` for details on drush configuration
+files.
+
+<h2>DRUSH_BOOTSTRAP_DRUSH</h2>
+<p>
+Configuration files loaded during this phase:<ul>
+<li>Drush installation folder.
+<li>System wide configuration folder (e.g. /etc/drush/drushrc.php).
+<li>User's .drush folder (i.e. ~/.drush/drushrc.php).
+<li>In any location, as specified by the --config (-c) option.
+</ul><p>
+Only bootstrap Drush, without any Drupal specific code.
+<p>
+Any code that operates on the Drush installation, and not specifically
+any Drupal directory, should bootstrap to this phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_ROOT</h2>
+<p>
+Configuration files loaded during this phase:<ul>
+<li>Drupal installation root.
+</ul><p>
+Set up and test for a valid drupal root, either through the -r/--root options,
+or evaluated based on the current working directory.
+<p>
+Any code that interacts with an entire Drupal installation, and not a specific
+site on the Drupal installation should use this bootstrap phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_SITE</h2>
+<p>
+Configuration files loaded during this phase:<ul>
+<li>Drupal site folder (e.g sites/{default|example.com}/drushrc.php).
+</ul><p>
+Set up a Drupal site directory and the correct environment variables to
+allow Drupal to find the configuration file.
+<p>
+If no site is specified with the -l / --uri options, Drush will assume the
+site is 'default', which mimics Drupal's behaviour.
+<p>
+If you want to avoid this behaviour, it is recommended that you use the
+DRUSH_BOOTSTRAP_DRUPAL_ROOT bootstrap phase instead.
+<p>
+Any code that needs to modify or interact with a specific Drupal site's
+settings.php file should bootstrap to this phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION</h2>
+<p>
+Load the settings from the Drupal sites directory.
+<p>
+This phase is analagous to the DRUPAL_BOOTSTRAP_CONFIGURATION bootstrap phase in Drupal
+itself, and this is also the first step where Drupal specific code is included.
+<p>
+This phase is commonly used for code that interacts with the Drupal install API,
+as both install.php and update.php start at this phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_DATABASE</h2>
+<p>
+Connect to the Drupal database using the database credentials loaded
+during the previous bootstrap phase.
+<p>
+This phase is analogous to the DRUPAL_BOOTSTRAP_DATABASE bootstrap phase in
+Drupal.
+<p>
+Any code that needs to interact with the Drupal database API needs to
+be bootstrapped to at least this phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_FULL</h2>
+<p>
+Fully initialize Drupal.
+<p>
+This is the default bootstrap phase all commands will try to reach,
+unless otherwise specified.
+This is analogous to the DRUPAL_BOOTSTRAP_FULL bootstrap phase in
+Drupal.
+<p>
+Any code that interacts with the general Drupal API should be
+bootstrapped to this phase.
+
+
+<h2>DRUSH_BOOTSTRAP_DRUPAL_LOGIN</h2>
+<p>
+Log in to the initialiased Drupal site.
+<p>
+This bootstrap phase is used after the site has been
+fully bootstrapped.
+<p>
+This phase will log you in to the drupal site with the username
+or user ID specified by the --user/ -u option.
+<p>
+Use this bootstrap phase for your command if you need to have access
+to information for a specific user, such as listing nodes that might
+be different based on who is logged in.
+
+
+<h2>DRUSH_BOOTSTRAP_MAX</h2>
+<p>
+This is not an actual bootstrap phase.  Commands that use
+DRUSH_BOOTSTRAP_MAX will cause drush to bootstrap as far
+as possible, and then run the command regardless of the
+bootstrap phase that was reached.  This is useful for drush
+commands that work without a bootstrapped site, but that
+provide additional information or capabilities in the presence
+of a bootstrapped site.  For example, `drush pm-releases modulename`
+works without a bootstrapped Drupal site, but will include
+the version number for the installed module if a Drupal site
+has been bootstrapped.
diff --git a/sites/all/modules/drush/docs/commands.html b/sites/all/modules/drush/docs/commands.html
new file mode 100644
index 0000000000000000000000000000000000000000..50f471580cdbc7f29b415a67aa5a4acac213fc44
--- /dev/null
+++ b/sites/all/modules/drush/docs/commands.html
@@ -0,0 +1,254 @@
+<h1>Creating Custom Drush Commands</h1>
+<p>
+Creating a new drush command is very easy.  There are
+four simple steps.
+<ol>
+<li>Create a command file called COMMANDFILE.drush.inc
+
+<li>Implement the function COMMANDFILE_drush_help(). Optional.
+
+<li>Implement the function COMMANDFILE_drush_command()
+
+<li>Implement the functions that your commands will call.
+    These will usually be named drush_COMMANDFILE_COMMANDNAME().
+</ol><p>
+For an example drush command, see examples/sandwich.drush.inc.
+The steps for implementing your command are explained in more
+detail below.
+
+<h2>Create COMMANDFILE.drush.inc</h2>
+<p>
+The name of your drush command is very important.  It must end
+in ".drush.inc" to be recognized as a drush command.  The part
+of the filename that comes before the ".drush.inc" becomes the
+name of the commandfile.  Your commandfile name is used by
+drush to compose the names of the functions it will call, so
+choose wisely.
+<p>
+The example drush command, 'make-me-a-sandwich', is stored
+in the 'sandwich' commandfile, 'sandwich.drush.inc'.
+<p>
+Drush searches for commandfiles in the following locations:
+<ul>
+<li>The "/path/to/drush/commands" folder.
+
+<li>Folders listed in the 'include' option (see `drush topic docs-configuration`).
+
+<li>The system-wide drush commands folder, e.g. /usr/share/drush/commands
+
+<li>The ".drush" folder in the user's HOME folder.
+
+<li>All modules in the current Drupal installation
+</ul> <p>
+Note that modules in the current Drupal installation will only
+be considered if drush has bootstrapped to at least the DRUSH_BOOSTRAP_SITE
+level.  Usually, when working with a Drupal site, drush will
+bootstrap to DRUSH_BOOTSTRAP_FULL; in this case, only the drush
+commandfiles in enabled modules will be considered eligible for
+loading.  If a drush only bootstraps to DRUSH_BOOTSTRAP_SITE,
+though, then all drush commandfiles will be considered, whether the
+module is enabled or not.  See `drush topic docs-bootstrap` for
+more information on bootstrapping.
+<p>
+Additionally, drush commandfiles may optionally define a function
+COMMANDFILE_drush_load() in the file COMMANDFILE.drush.load.inc.
+If this function returns FALSE, then the commandfile will not be loaded.
+
+<h2>Implement COMMANDFILE_drush_help()</h2>
+<p>
+The drush_help hook is an optional place to describe a command in long form. If
+the command only requires a brief description, use the description key in
+COMMANDFILE_drush_command(). The drush_help hook for the 'sandwich' commandfile looks
+like this:
+<pre>
+        function sandwich_drush_help($section) {
+          switch ($section) {
+            case 'drush:make-me-a-sandwich':
+              return dt("... brief help summary goes here ...");
+          }
+        }
+</pre><p>
+Note that the command name is prepended with 'drush:' in
+the drush_help hook.  Your commandfile may implement
+multiple commands; to do so, just add more 'case' statements
+to the switch, one for each command.
+
+<h2>Implement COMMANDFILE_drush_command()</h2>
+<p>
+The drush_command hook is the most important part of the
+commandfile.  It returns an array of items that define
+how your commands should be called, and how they work.
+Drush commands are very similar to the Drupal menu system.
+The elements that can appear in a drush command definition
+are shown below.
+<ul>
+<li>'aliases':
+
+     Provides a list of shorter names for the command.
+     For example, pm-download may also be called via `drush dl`.
+     If the alias is used, drush will substitute back in the
+     primary command name, so pm-download will still be used
+     to generate the command hook, etc.
+
+<li>'deprecated-aliases':
+
+     Works just like 'aliases', but does not
+     appear in help.  Used in instances where the drush
+     maintainers intend to eventually remove support for a
+     command alias.  If someone runs a drush command using a
+     deprecated alias, drush will print a warning message.
+
+<li>'command hook':
+
+     Change the name of the function drush will
+     call to execute the command from drush_COMMANDFILE_COMMANDNAME()
+     to drush_COMMANDFILE_COMMANDHOOK(), where COMMANDNAME is the
+     original name of the command, and COMMANDHOOK is the value
+     of the 'command hook' item.
+
+<li>'callback':
+
+     Name of function to invoke for this command.  The callback
+     function name _must_ begin with "drush_commandfile_", where commandfile
+     is from the file "commandfile.drush.inc", which contains the
+     commandfile_drush_command() function that returned this command.
+     Note that the callback entry is optional; it is preferable to
+     omit it, in which case drush_invoke() will generate the hook function name.
+
+<li>'callback arguments':
+
+     An array of arguments to pass to the callback.
+     The command line arguments, if any, will appear after the
+     callback arguments in the function parameters.
+
+<li>'description':
+
+     Description of the command.
+
+<li>'arguments':
+
+     An array of arguments that are understood by the command.
+     Used by `drush help` only.
+
+<li>'options':
+
+     An array of options that are understood by the command.
+     Used by `drush help` only.
+
+<li>'examples':
+
+     An array of examples that are understood by the command.
+     Used by `drush help` only.
+
+<li>'scope':
+
+     One of 'system', 'project', 'site'.  Not currently used.
+
+<li>'bootstrap':
+
+     Drupal bootstrap level.  Valid values are:
+<ul>
+      <li>DRUSH_BOOTSTRAP_DRUSH
+      <li>DRUSH_BOOTSTRAP_DRUPAL_ROOT
+      <li>DRUSH_BOOTSTRAP_DRUPAL_SITE
+      <li>DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION
+      <li>DRUSH_BOOTSTRAP_DRUPAL_DATABASE
+      <li>DRUSH_BOOTSTRAP_DRUPAL_FULL
+      <li>DRUSH_BOOTSTRAP_DRUPAL_LOGIN
+      <li>DRUSH_BOOTSTRAP_MAX
+</ul>
+     See `drush topic docs-bootstrap`.
+
+<li>'core':
+
+     Drupal major version required. Append a '+' to indicate 'and later versions.'
+
+<li>'drupal dependencies':
+
+     Drupal modules required for this command.
+
+<li>'drush dependencies':
+
+     Other drush commandfiles required for this command.
+
+ <li>'topics':
+
+     Provides a list of topic commands that are related in
+     some way to this command.  Used by `drush help` only.
+
+<li>'topic':
+
+     Set to TRUE if this command is a topic, callable from the
+     `drush docs-topics` command.
+</ul><p>
+The 'sandwich' drush_command hook looks like this:
+<pre>
+        function sandwich_drush_command() {
+          $items = array();
+
+          $items['make-me-a-sandwich'] = array(
+            'description' => "Makes a delicious sandwich.",
+            'arguments' => array(
+              'filling' => 'The type of the sandwich (turkey, cheese, etc.)',
+            ),
+            'options' => array(
+              'spreads' => 'Comma delimited list of spreads (e.g. mayonnaise, mustard)',
+            ),
+            'examples' => array(
+              'drush mmas turkey --spreads=ketchup,mustard' => 'Make a terrible-tasting sandwich that is lacking in pickles.',
+            ),
+            'aliases' => array('mmas'),
+            'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap at all.
+          );
+
+          return $items;
+        }
+</pre><p>
+Most of the items in the 'make-me-a-sandwich' command
+definition have no effect on execution, and are used only
+by `drush help`.  The exceptions are 'aliases' (described
+above) and 'bootstrap'.  As previously mentioned,
+`drush topic docs-bootstrap` explains the drush bootstrapping
+process in detail.
+
+<h2>Implement drush_COMMANDFILE_COMMANDNAME()</h2>
+<p>
+The 'make-me-a-sandwich' command in sandwich.drush.inc
+is defined as follows:
+<pre>
+	function drush_sandwich_make_me_a_sandwich($filling = 'ascii') {
+	  ... implementation here ...
+        }
+</pre><p>
+If a user runs `drush make-me-a-sandwich` with no command line
+arguments, then drush will call drush_sandwich_make_me_a_sandwich()
+with no function parameters; in this case, $filling will take on
+the provided default value, 'ascii'.  (If there is no default
+value provided, then the variable will be NULL, and a warning
+will be printed.)  Running `drush make-me-a-sandwich ham` will
+cause drush to call drush_sandwich_make_me_a_sandwich('ham').  In
+the same way, commands that take two command line arguments can
+simply define two functional parameters, and a command that takes
+a variable number of command line arguments can use the standard
+php function func_get_args() to get them all in an array for easy
+processing.
+<p>
+Note that drush will actually call a sequence of functions before
+and after your drush command function.  One of these hooks is the
+"validate" hook.  The 'sandwich' commandfile provides a validate
+hook for the 'make-me-a-sandwich' command:
+<pre>
+        function drush_sandwich_make_me_a_sandwich_validate() {
+          $name = posix_getpwuid(posix_geteuid());
+          if ($name['name'] !== 'root') {
+            return drush_set_error('MAKE_IT_YOUSELF', dt('What? Make your own sandwich.'));
+          }
+        }
+</pre><p>
+The validate function should call drush_set_error and return
+its result if the command cannot be validated for some reason.
+See `drush topic docs-policy` for more information on defining
+policy functions with validate hooks, and `drush topic docs-api`
+for information on how the command hook process works.  Also,
+the list of defined drush error codes can be found in
+`drush topic docs-errorcodes`.
diff --git a/sites/all/modules/drush/docs/context.html b/sites/all/modules/drush/docs/context.html
new file mode 100644
index 0000000000000000000000000000000000000000..8d0d6c6e57f2c56a524d9c8e9ccc510d1456c1fe
--- /dev/null
+++ b/sites/all/modules/drush/docs/context.html
@@ -0,0 +1,73 @@
+<h1>Drush Contexts</h1>
+<p>
+The drush contexts API acts as a storage mechanism for all options, 
+arguments and configuration settings that are loaded into drush.
+<p>
+This API also acts as an IPC mechanism between the different drush commands,
+and provides protection from accidentally overriding settings that are
+needed by other parts of the system.
+<p>
+It also avoids the necessity to pass references through the command chain
+and allows the scripts to keep track of whether any settings have changed
+since the previous execution.
+<p>
+This API defines several contexts that are used by default.
+
+<h2>Argument contexts</h2>
+<p>
+These contexts are used by Drush to store information on the command.
+They have their own access functions in the forms of
+drush_set_arguments(), drush_get_arguments(), drush_set_command(),
+drush_get_command().
+<ul>
+<li>command : The drush command being executed.</li>
+<li>arguments : Any additional arguments that were specified.</li>
+</ul>
+
+<h2>Setting contexts</h2>
+<p>
+These contexts store options that have been passed to the drush.php
+script, either through the use of any of the config files, directly from
+the command line through --option='value' or through a JSON encoded string
+passed through the STDIN pipe.
+<p>
+These contexts are accessible through the drush_get_option() and
+drush_set_option() functions.  See drush_context_names() for a description
+of all of the contexts.
+<p>
+Drush commands may also choose to save settings for a specific context to
+the matching configuration file through the drush_save_config() function.
+
+<h2>Available Setting contexts</h2>
+<p>
+These contexts are evaluated in a certain order, and the highest priority value
+is returned by default from drush_get_option. This allows scripts to check whether
+an option was different before the current execution.
+<p>
+Specified by the script itself :
+<ul>
+<li>process  : Generated in the current process.
+<li>cli      : Passed as --option=value to the command line.
+<li>stdin    : Passed as a JSON encoded string through stdin.
+<li>alias    : Defined in an alias record, and set in the
+               alias context whenever that alias is used.
+<li>specific : Defined in a command-specific option record, and
+               set in the command context whenever that command is used.
+</ul>
+<p>
+Specified by config files :
+
+<ul>
+<li>custom   : Loaded from the config file specified by --config or -c
+<li>site     : Loaded from the drushrc.php file in the Drupal site directory.
+<li>drupal   : Loaded from the drushrc.php file in the Drupal root directory.
+<li>user     : Loaded from the drushrc.php file in the user's home directory.
+<li>drush    : Loaded from the drushrc.php file in the $HOME/.drush directory.
+<li>system   : Loaded from the drushrc.php file in the system's $PREFIX/etc/drush directory.
+<li>drush    : Loaded from the drushrc.php file in the same directory as drush.php.
+</ul>
+<p>
+Specified by the script, but has the lowest priority :
+<ul>
+<li>default  : The script might provide some sensible defaults during init.
+</ul>
diff --git a/sites/all/modules/drush/drush.api.php b/sites/all/modules/drush/docs/drush.api.php
similarity index 75%
rename from sites/all/modules/drush/drush.api.php
rename to sites/all/modules/drush/docs/drush.api.php
index f4933e1bc1c69863f6d82ef5e2576c7a38ee9f67..06f71c28bc8a29fa78670d7acd11bc3d3f5ae8d1 100644
--- a/sites/all/modules/drush/drush.api.php
+++ b/sites/all/modules/drush/docs/drush.api.php
@@ -1,5 +1,4 @@
 <?php
-// $Id: drush.api.php,v 1.16 2010/11/30 15:12:49 weitzman Exp $
 
 /**
  * @file
@@ -17,7 +16,7 @@
  * 2. drush_hook_pre_COMMAND()
  * 3. drush_hook_COMMAND()
  * 4. drush_hook_post_COMMAND()
- * 
+ *
  * For example, here are the hook opportunities for a mysite.drush.inc file
  * that wants to hook into the `pm-download` command.
  *
@@ -29,9 +28,21 @@
  * Note that the drush_COMMAND_init() hook is only for use by the
  * commandfile that defines the command.
  *
- * If any of hook function fails, the rollback mechanism is called. It will
- * call, in reverse, all _rollback hooks. The mysite command file can implement
- * the following rollback hooks:
+ * If any of hook function fails, either by calling drush_set_error
+ * or by returning FALSE as its function result, then the rollback
+ * mechanism is called.  To fail with an error, call drush_set_error:
+ *
+ *   return drush_set_error('MY_ERROR_CODE', dt('Error message.'));
+ *
+ * To allow the user to confirm or cancel a command, use drush_confirm
+ * and drush_user_abort:
+ *
+ *   if (!drush_confirm(dt('Are you sure?'))) {
+ *     return drush_user_abort();
+ *   }
+ *
+ * The rollback mechanism will call, in reverse, all _rollback hooks.
+ * The mysite command file can implement the following rollback hooks:
  *
  * 1. drush_mysite_post_pm_download_rollback()
  * 2. drush_mysite_pm_download_rollback()
@@ -150,6 +161,15 @@ function hook_drush_exit() {
 
 }
 
+/*
+ * A commandfile may choose to decline to load for the current bootstrap
+ * level by returning FALSE. This hook must be placed in MODULE.drush.load.inc.
+ * @see drush_commandfile_list().
+ */
+function hook_drush_load() {
+
+}
+
 /**
  * Take action after a project has been downloaded.
  */
@@ -175,6 +195,17 @@ function hook_drush_pm_download_destination_alter(&$project, $release) {
   }
 }
 
+/**
+ * Add information to the upgrade project map; this information
+ * will be shown to the user when upgrading Drupal to the next
+ * major version if the module containing this hook is enabled.
+ *
+ * @see drush_upgrade_project_map().
+ */
+function hook_drush_upgrade_project_map_alter(&$project_map) {
+  $project_map['warning']['hook'] = dt("You need to take special action before upgrading this module. See http://mysite.com/mypage for more information.");
+}
+
 /**
  * Sql-sync sanitization example.  This is equivalent to
  * the built-in --sanitize option of sql-sync, but simplified
@@ -188,13 +219,26 @@ function hook_drush_sql_sync_sanitize($source) {
     "update users set pass = MD5('password'), mail = concat('user+', uid, '@localhost') where uid > 0;");
 }
 
+/**
+ * Take action before modules are disabled in a major upgrade.
+ * Note that when this hook fires, it will be operating on a
+ * copy of the database.
+ */
+function drush_hook_pre_site_upgrade_prepare() {
+  // site upgrade prepare will disable contrib_extensions and
+  // uninstall the uninstall_extension
+  $contrib_extensions = func_get_args();
+  $uninstall_extensions = explode(',', drush_get_option('uninstall', ''));
+}
+
+
 /**
  * Add help components to a command
  */
 function hook_drush_help_alter(&$command) {
   if ($command['command'] == 'sql-sync') {
-    $command['options']['--myoption'] = "Description of modification of sql-sync done by hook";
-    $command['sub-options']['--sanitize']['--my-sanitize-option'] = "Description of sanitization option added by hook (grouped with --sanitize option)";
+    $command['options']['myoption'] = "Description of modification of sql-sync done by hook";
+    $command['sub-options']['sanitize']['my-sanitize-option'] = "Description of sanitization option added by hook (grouped with --sanitize option)";
   }
 }
 
@@ -212,7 +256,7 @@ function hook_drush_cache_clear(&$types) {
  *   Bash code typically found in a .bashrc file.
  *
  * @see core_cli_bashrc() for an example implementation.
- */ 
+ */
 function hook_cli_bashrc() {
   $string = "
     alias siwef='drush site-install wef --account-name=super --account-mail=me@wef'
diff --git a/sites/all/modules/drush/docs/shellscripts.html b/sites/all/modules/drush/docs/shellscripts.html
new file mode 100644
index 0000000000000000000000000000000000000000..039237a7a4b455e8bcfc70f33f89cefa73f35bc9
--- /dev/null
+++ b/sites/all/modules/drush/docs/shellscripts.html
@@ -0,0 +1,80 @@
+<h1>The Drush Shell Scripts</h1>
+<p>
+A drush shell script is any Unix shell script file that has
+its "execute" bit set (i.e., via `chmod +x myscript.drush`)
+and that begins with a specific line:
+<pre>
+	#!/usr/bin/env drush
+</pre>
+ - or -
+<pre> 
+	#!/full/path/to/drush
+</pre><p>
+The former is the usual form, and is more convenient in that
+it will allow you to run the script regardless of where drush
+has been installed on your system, as long as it appears in
+your PATH.  The later form allows you to specify the drush
+command add options to use, as in:
+<pre>
+	#!/full/path/to/drush php-script --some-option
+</pre><p>
+Adding specific options is important only in certain cases,
+described later; it is usually not necessary.
+<p>
+Drush scripts do not need to be named "*.drush" or "*.script";
+they can be named anything at all.  To run them, make sure they 
+are executable (`chmod +x helloworld.script`) and then run them 
+from the shell like any other script.
+<p>
+There are two big advantages to drush scripts over bash scripts:
+<ul>
+<li>They are written in php
+
+<li>drush can bootstrap your Drupal site before
+    running your script.
+</ul><p>
+To bootstrap a Drupal site, provide an alias to the site to 
+bootstrap as the first commandline argument.
+<p>
+For example:
+<pre>
+	$ helloworld.script @dev a b c
+</pre><p>
+If the first argument is a valid site alias, drush will remove 
+it from the arument list and bootstrap that site, then run
+your script.  The script itself will not see @dev on its
+argument list.  If you do not want drush to remove the first
+site alias from your scripts argument list (e.g. if your script
+wishes to syncronise two sites, specified by the first two
+arguments, and does not want to bootstrap either of those
+two sites), then fully specify the drush command (php-script)
+and options to use, as shown above.  By default, if the drush
+command is not specified, drush will provide the following default
+line:
+<pre>
+	#!/full/path/to/drush php-script --bootstrap-to-first-arg
+</pre><p>
+It is the option --bootstrap-to-first-arg that causes drush to
+pull off the first argument and bootstrap it.  The way to get rid
+of that option is to specify the php-script line to run, and leave
+it off, like so:
+<pre>
+	#!/full/path/to/drush php-script
+</pre><p>
+Note that 'php-script' is the only built-in drush command that
+makes sense to put on the "shebang" ("#!" is pronounced "shebang")
+line.  However, if you wanted to, you could implement your own
+custom version of php-script (e.g. to preprocess the script input,
+perhaps), and specify that command on the shebang line.
+<p>
+Drush scripts can access their arguments via the drush_shift()
+function:
+<pre>
+        while ($arg = drush_shift()) {
+          drush_print($arg);
+        }
+</pre><p>
+Options are available via drush_get_option('option-name').
+<p>
+See the example drush script in `drush topic docs-examplescript`,
+and the list of drush error codes in `drush topic docs-errorcodes`.
diff --git a/sites/all/modules/drush/docs/upgrade.html b/sites/all/modules/drush/docs/upgrade.html
new file mode 100644
index 0000000000000000000000000000000000000000..4b05a7ad2369d847d5862d6bfa0fd8b732262105
--- /dev/null
+++ b/sites/all/modules/drush/docs/upgrade.html
@@ -0,0 +1,100 @@
+<h1>Using Drush to Upgrade Drupal 6.x to Drupal 7.x</h1>
+<p>
+The drush site-upgrade command supports upgrades from Drupal 6.x
+to Drupal 7.x.  Upgrades from Drupal 7.x to Drupal 8.x will be
+supported in the future.  Use the drush pm-update command to do minor verison
+updates for Drupal 5.x, 6.x and 7.x.
+<p>
+To begin, consult the UPGRADE.txt file from the root folder of the
+version of Drupal you are upgrading to.  Drush will handle some of
+the steps described there, but not all.  In particular, you should
+make sure that your current Drupal installation is running on the
+most recent minor version available.
+<p>
+n.b. At the time of this writing, Drupal 6.20 and Drupal 7.0 were
+the most recent versions available.  Always check primary sources
+prior to upgrading to see if anything may have changed.
+
+<h2>Upgrade a Copy of your Site</h2>
+<p>
+Drush will always upgrade <i>from</i> the specified Drupal site
+<i>to</i> an empty Drupal site.  It is necessary to create a
+site alias to describe the destination site.  Site aliases are
+described in `drush topic docs-aliases`.  A canonical site alias
+is adequate to define your target site for upgrade:
+<p>
+$aliases['onward'] = { <br>
+  'root' => '/path/to/upgraded/drupalroot',<br>
+  'uri' => 'http://onward.mysite.org',<br>
+}<br>
+<p>
+Optionally, you might also want to define 'db_url' to specify
+the name of your target database.  If you do not, drush will
+compose a database name for you based on the name of your site alias.
+<p>
+<h2>Running the `site-upgrade` Command</h2>
+<p>
+Drush will upgrade the current bootstrapped site, and will
+put the result in the target site specified by the argument
+to the command.  For example:
+<p>
+drush @from site-upgrade @onward
+<p>
+The site-upgrade command will perform the following operations:
+<ol>
+<li>Download the next major release of Drupal and store the files
+in the target site.</li>
+<li>Write a new settings.php file with an appropriate databases
+structure for the new target site.</li>
+<li>Make a copy of the SQL database for the new site.</li>
+<li>The default theme for the new site will be set to "garland",
+and the admin theme will be set to "seven".</li>
+<li>All non-core extensions will be disabled in the target database,
+and updatedb will be run on Drupal core.</li>
+<li>All of the modules disabled in the previous step will be
+downloaded again, if they have an appropriate version for the
+target Drupal site available.</li>
+<li>updatedb will be run again to update the non-core modules.</li>
+<li>All of the non-core modules will be enabled again.</li>
+</ol>
+<p>
+Before drush begins this process, it will first print out a list
+of warnings for any modules that may not be ready to upgrade yet.
+Please read all of these messages carefully before proceding.
+Here are some of the situations you may encounter.
+<ul>
+<li>If a module has no <i>recommended</i> release, then drush
+will continue, downloading an available release for the upgrade.</li>
+<li>If a module has no release at all, then drush will skip it.
+The module's data will remain in the database.</li>
+<li>You may discover that some modules, such as date_api, might
+cause the Drupal core updatedb to fail.  In this instance, you
+may use the --uninstall option to list the modules to uninstall
+prior to upgrade.  Modules uninstalled in this manner will have
+all of their data removed from the target database; the database
+of the source site is not affected.</li>
+</ul>
+<p>
+When drush is enabling the modules in the upgraded site, if there
+are any new dependencies, they will also be identified and downloaded
+if possible.  For example, views-7.x depends on the ctools module
+from the Chaos tool suite, whereas views-6 did not; drush will therefore
+download and enable ctools when upgrading the views module from
+Drupal 6 to Drupal 7.
+<p>
+There will still be some work left to do after the site-upgrade
+command has completed; for example, you will still need to port your
+theme and any custom modules to the new version of Drupal, and some
+contrib modules may require additional work to update their configuration
+settings.  Using site-upgrade will all the same save you a considerable
+amount of time.  There is no risk in trying it; if it does not work,
+you can always start over, or run it at a later date when more contrib
+modules have been updated.  If you do run site-upgrade a second time
+on the same site, drush will ask you if you want to replace the existing
+target site, effectively starting over from the beginning, or re-use
+the site that is already present.  In the later case, drush will use
+the existing code, but will re-copy the source database and run updatedb
+on it again.  This will all you to attempt to fix any non-working contrib
+modules yourself to get your site-upgrade working.
+<p>
+Enjoy!
diff --git a/sites/all/modules/drush/drush b/sites/all/modules/drush/drush
index 73c20d9c7ecc548c92f7ae43baf6b738c8b59964..50aa608a54ad7b164369705ebb5aa1e19c7f49f6 100755
--- a/sites/all/modules/drush/drush
+++ b/sites/all/modules/drush/drush
@@ -1,5 +1,5 @@
 #!/usr/bin/env sh
-# $Id: drush,v 1.25 2010/11/10 13:57:54 weitzman Exp $
+# $Id$
 #
 # This script is a simple wrapper that will run Drush with the most appropriate
 # php executable it can find.
@@ -65,7 +65,7 @@ fi
 
 # Check to see if the user has provided a php.ini file or drush.ini file in any conf dir
 # Last found wins, so search in reverse priority order
-for conf_dir in /etc/drush $HOME/.drush ; do
+for conf_dir in $(dirname "$SELF_PATH") /etc/drush $HOME/.drush ; do
   if [ -f $conf_dir/php.ini ] ; then
     drush_php_ini=$conf_dir/php.ini
   fi
diff --git a/sites/all/modules/drush/drush.info b/sites/all/modules/drush/drush.info
index 267f509747ea7a66aaaa0c454f3857c3b248b074..8c2178077e16d855acc571b8093788c5f369c36d 100644
--- a/sites/all/modules/drush/drush.info
+++ b/sites/all/modules/drush/drush.info
@@ -1,7 +1,8 @@
-drush_version=4.0-dev
+drush_version=4.5
 
-; Information added by drupal.org packaging script on 2010-12-02
-version = "All-Versions-HEAD"
+; Information added by drupal.org packaging script on 2011-08-12
+version = "7.x-4.5"
+core = "7.x"
 project = "drush"
-datestamp = "1291248601"
+datestamp = "1313123851"
 
diff --git a/sites/all/modules/drush/drush.php b/sites/all/modules/drush/drush.php
index f06f5895dd0c1811208933b4a7aa32feebf5f627..d296c5920ae9bc5688db7b1608a23e434bd22f3b 100755
--- a/sites/all/modules/drush/drush.php
+++ b/sites/all/modules/drush/drush.php
@@ -1,6 +1,5 @@
 #!/usr/bin/env php
 <?php
-// $Id: drush.php,v 1.91 2010/11/10 02:55:41 weitzman Exp $
 
 /**
  * @file
@@ -10,7 +9,7 @@
  */
 // Terminate immediately unless invoked as a command line script
 if (!drush_verify_cli()) {
-  die('drush.php is designed to run via the command line.');
+  die('drush is designed to run via the command line.');
 }
 
 // Check supported version of PHP.
@@ -92,6 +91,7 @@ function drush_main() {
         drush_enforce_requirement_bootstrap_phase($command);
         drush_enforce_requirement_core($command);
         drush_enforce_requirement_drupal_dependencies($command);
+        drush_enforce_requirement_drush_dependencies($command);
 
         if ($bootstrap_result && empty($command['bootstrap_errors'])) {
           drush_log(dt("Found command: !command (commandfile=!commandfile)", array('!command' => $command['command'], '!commandfile' => $command['commandfile'])), 'bootstrap');
@@ -100,7 +100,12 @@ function drush_main() {
           // Dispatch the command(s).
           $return = drush_dispatch($command);
 
-          if (drush_get_context('DRUSH_DEBUG')) {
+          // prevent a '1' at the end of the output
+          if ($return === TRUE) {
+            $return = '';
+          }
+
+          if (drush_get_context('DRUSH_DEBUG') && !drush_get_context('DRUSH_QUIET')) {
             drush_print_timers();
           }
           drush_log(dt('Peak memory usage was !peak', array('!peak' => drush_format_size(memory_get_peak_usage()))), 'memory');
@@ -232,10 +237,13 @@ function drush_drupal_login($drush_user) {
 
   if (empty($user)) {
     if (is_numeric($drush_user)) {
-      $message = dt('Could not login with user ID #%user.', array('%user' => $drush_user));
+      $message = dt('Could not login with user ID #!user.', array('!user' => $drush_user));
+      if ($drush_user === 0) {
+        $message .= ' ' . dt('This is typically caused by importing a MySQL database dump from a faulty tool which re-numbered the anonymous user ID in the users table. See !link for help recovering from this situation.', array('!link' => 'http://drupal.org/node/1029506'));
+      }
     }
     else {
-      $message = dt('Could not login with user account `%user\'.', array('%user' => $drush_user));
+      $message = dt('Could not login with user account `!user\'.', array('!user' => $drush_user));
     }
     return drush_set_error('DRUPAL_USER_LOGIN_FAILED', $message);
   }
diff --git a/sites/all/modules/drush/examples/example.aliases.drushrc.php b/sites/all/modules/drush/examples/example.aliases.drushrc.php
index 56ef90459b1f4c807582a476f12df4b9ed843d8e..c313833e15c234ac6e39e31e083e3bafa26fba1f 100644
--- a/sites/all/modules/drush/examples/example.aliases.drushrc.php
+++ b/sites/all/modules/drush/examples/example.aliases.drushrc.php
@@ -6,7 +6,7 @@
  *
  * Aliases are commonly used to define short names for
  * local or remote Drupal installations; however, an alias
- * is really nothing more than a collection of option sets.
+ * is really nothing more than a collection of options.
  * A canonical alias named "dev" that points to a local
  * Drupal site named "dev.mydrupalsite.com" looks like this: 
  *
@@ -125,7 +125,7 @@
  * - 'ssh-options': If the target requires special options, such as a non-
  *     standard port, alternative identity file, or alternative
  *     authentication method, ssh- options can contain a string of extra
- *     options  that are used with the ssh command, eg "-p 100"
+ *     options that are used with the ssh command, eg "-p 100"
  * - 'parent': The name of a parent alias (e.g. '@server') to use as a basis
  *     for this alias.  Any value of the parent will appear in the child
  *     unless overridden by an item with the same name in the child.
@@ -141,20 +141,35 @@
  *     record.  Drush will look up the 'databases' record if it is not specified.
  * - 'path-aliases': An array of aliases for common rsync targets.
  *   Relative aliases are always taken from the Drupal root.
- *     '%drush': The path to the folder where drush is stored.  Optional;
- *       defaults to the folder containing the running script.  Always be sure
- *       to set '%drush' if the path to drush is different on the remote server.
- *     '%drush-script': The path to the 'drush' script (used by backend invoke);
- *       default is 'drush' on remote machines, or the full path to drush.php on
- *       the local machine.  Note that you only need to define one of '%drush'
- *       or '%drush-script', as drush can infer one from the other.
+ *     '%drush-script': The path to the 'drush' script, or to 'drush.php' or
+ *       'drush.bat', as desired.  This is used by backend invoke when drush
+ *       runs a drush command.  The default is 'drush' on remote machines, or 
+ *       the full path to drush.php on the local machine.
+ *     '%drush': A read-only property: points to the folder that the drush script
+ *       is stored in.
  *     '%dump-dir': Path to directory that "drush sql-sync" should use to store
  *       sql-dump files. Helpful filenames are auto-generated.
  *     '%dump': Path to the file that "drush sql-sync" should use to store sql-dump file.
  *     '%files': Path to 'files' directory.  This will be looked up if not specified.
  *     '%root': A reference to the Drupal root defined in the 'root' item
  *       in the site alias record.
- *
+ * - 'command-specific': These options will only be set if the alias
+ *   is used with the specified command.  In the example below, the option
+ *   `--no-cache` will be selected whenever the @stage alias
+ *   is used in any of the following ways:
+ *      drush @stage sql-sync @self @live
+ *      drush sql-sync @stage @live
+ *      drush sql-sync @live @stage
+ *   In case of conflicting options, command-specific options in targets
+ *   (source and destination) take precedence over command-specific options
+ *   in the bootstrapped site, and command-specific options in a destination
+ *   alias will take precedence over those in a source alias.
+ * - 'source-command-specific' and 'target-command-specific': Behaves exactly
+ *   like the 'command-specific' option, but is applied only if the alias
+ *   is used as the source or target, respectively, of an rsync or sql-sync
+ *   command.  In the example below, `--skip-tables-list=comments` whenever
+ *   the alias @live is the target of an sql-sync command, but comments will
+ *   be included if @live is the source for the sql-sync command.
  * Some examples appear below.  Remove the leading hash signs to enable.
  */
 #$aliases['stage'] = array(
@@ -170,6 +185,11 @@
 #      '%files' => 'sites/mydrupalsite.com/files',
 #      '%custom' => '/my/custom/path',
 #     ),
+#     'command-specific' => array (
+#       'sql-sync' => array (
+#         'no-cache' => TRUE,
+#       ),
+#     ),
 #  );
 #$aliases['dev'] = array(
 #    'uri' => 'dev.mydrupalsite.com',
@@ -182,4 +202,9 @@
 #$aliases['live'] = array(
 #    'parent' => '@server,@dev',
 #    'uri' => 'mydrupalsite.com',
+#     'target-command-specific' => array (
+#       'sql-sync' => array (
+#         'skip-tables-list' => 'comments',
+#       ),
+#     ),
 #  );
diff --git a/sites/all/modules/drush/examples/example.bashrc b/sites/all/modules/drush/examples/example.bashrc
new file mode 100644
index 0000000000000000000000000000000000000000..d0f7a67b71555e5eac7dad4cbc00c585eb0ab55e
--- /dev/null
+++ b/sites/all/modules/drush/examples/example.bashrc
@@ -0,0 +1,20 @@
+# Examples of valid statements for a drush bashrc file. Use this file to cut down on
+# typing of options and avoid mistakes.
+#
+# Rename this file to .bashrc and optionally copy it to one of
+# four convenient places:
+#
+# 1. User's $HOME folder (i.e. ~/.bashrc).
+# 2. User's .drush folder (i.e. ~/.drush/.bashrc).
+# 3. System wide configuration folder (e.g. /etc/drush/.bashrc).
+# 4. System wide command folder (e.g. /usr/share/drush/command/.bashrc).
+# 5. Drush installation folder
+#
+# Drush will search for .bashrc files whenever the drush interactive
+# shell, i.e. `drush core-cli` is entered.   If a configuration file 
+# is found in any of the above locations, it will be sourced by bash 
+# and merged with other configuration files encountered.
+
+alias siwef='site-install wef --account-name=super --account-mail=me@wef'
+alias dump='sql-dump --structure-tables-key=wef --ordered-dump'
+alias cli-update='(drush core-cli --pipe > $HOME/.bash_aliases) && source $HOME/.bash_aliases'
diff --git a/sites/all/modules/drush/examples/example.drush.ini b/sites/all/modules/drush/examples/example.drush.ini
new file mode 100644
index 0000000000000000000000000000000000000000..eaf20972d87eb3b15574e458031a3497a38b8b74
--- /dev/null
+++ b/sites/all/modules/drush/examples/example.drush.ini
@@ -0,0 +1,70 @@
+;
+; Example of a drush php settings override file
+;
+; IMPORTANT:  Before following the instructions in
+; this file, first check to see that the cli version
+; of php is installed on your system.  (e.g. On
+; debian systems, `sudo apt-get install php5-cli`.)
+;
+; Use this file in instances when your system is
+; -not- configured to use separate php.ini files for
+; webserver and cli use.  You can determine which
+; php.ini file drush is using by running "drush status".
+; If the php.ini file shown is your webserver ini
+; file, then rename this file, example.drush.ini,
+; to drush.ini and copy it to one of the following 
+; locations:
+;
+; 1. Drush installation folder
+; 2. User's .drush folder (i.e. ~/.drush/drush.ini)
+; 3. System wide configuration folder (i.e. /etc/drush/drush.ini)
+;
+; When in use, the variables defined in this file
+; will override the setting values that appear in
+; your php.ini file.  See the examples below for
+; some values that may need to be set in order for
+; drush to work.
+;
+; NOTE:  There is a certain amount of overhead
+; required for each override, so drush.ini should
+; only be used for a relatively small number
+; of variables.  Comment out any variable that
+; has the same value as the webserver php.ini
+; to keep the size of the override list small.
+;
+; To fully specify the value of all php.ini variables, 
+; copy your webserver php.ini file to one of the 
+; locations mentioned above (e.g. /etc/drush/php.ini)
+; and edit it to suit.
+;
+; The options listed below are particularly relevant
+; to drush.
+; 
+
+;
+; drush needs as much memory as Drupal in order
+; to run; make the memory limit setting match
+; what you have in your webserver's php.ini.
+;
+memory_limit = 128M
+
+;
+; Show all errors and direct them to stderr
+; when running drush.
+;
+error_reporting = E_ALL | E_NOTICE | E_STRICT
+display_errors = stderr
+
+;
+; If your php.ini for your webserver is too
+; restrictive, you can re-enable functionality
+; for drush by adjusting values in this file.
+;
+; Here are some examples of settings that are
+; sometimes set to restrictive values in a
+; webserver's php.ini:
+;
+;safe_mode = 
+;open_basedir = 
+;disable_functions =
+;disable_classes =
diff --git a/sites/all/modules/drush/examples/example.drushrc.php b/sites/all/modules/drush/examples/example.drushrc.php
index 8d5ef3bac79ac19dac83d099b8abda37591ebeb4..307895edd6a984324e303c3af9cd90716e7df560 100644
--- a/sites/all/modules/drush/examples/example.drushrc.php
+++ b/sites/all/modules/drush/examples/example.drushrc.php
@@ -1,5 +1,4 @@
 <?php
-// $Id: example.drushrc.php,v 1.12 2010/12/01 04:46:08 greg1anderson Exp $
 
 /*
  * Examples of valid statements for a drushrc.php file. Use this file to cut down on
@@ -44,6 +43,9 @@
  * load the configuration file for the site specified by the
  * destination parameter, nor do they load configuration files
  * for remote sites.
+ *
+ * See `drush topic docs-bootstrap` for more information on how
+ * bootstrapping affects the loading of drush configuration files.
  */
 
 // Specify a particular multisite.
@@ -55,6 +57,23 @@
 // Load a drushrc.php configuration file from the current working directory.
 # $options['c'] = '.';
 
+// You should not use drush-4.x on Windows; upgrade to the 5.x branch.
+// If you are really sure that you want to ignore this advice, you may
+// still disable the warning by setting the 'check_os' setting to the
+// special value shown below.
+# $options['check_os'] = 'i-want-4.x';
+
+// Control automatically check for updates in pm-updatecode and drush version.
+// FALSE = never check for updates.  'head' = allow updates to drush-HEAD.
+// TRUE (default) = allow updates to latest stable release.
+# $options['self-update'] = FALSE;
+
+// By default, drush will download projects compatibile with the
+// current version of Drupal, or, if no Drupal site is specified,
+// then the Drupal-7 version of the project is downloaded.  Set
+// default-major to select a different default version.
+# $options['default-major'] = 6;
+
 // Specify CVS for checkouts
 # $options['package-handler'] = 'cvs';
 
@@ -124,6 +143,15 @@
 # $options['output_charset'] = 'KOI8-R//IGNORE';
 # $options['output_charset'] = 'ISO-8859-1//TRANSLIT';
 
+/*
+ * Multiple command execution options
+ */
+// By default, drush will prepend the name of the
+// site to the output of any multiple-site command 
+// execution.  To disable this behavior, set the
+// --no-label option
+# $options['no-label'] = TRUE;
+
 /*
  * Customize this associative array with your own tables. This is the list of
  * tables whose *data* is skipped by the 'sql-dump' and 'sql-sync' commands when
@@ -167,6 +195,23 @@ $options['skip-tables'] = array(
 // Separate by : (Unix-based systems) or ; (Windows).
 # $command_specific['script']['script-path'] = 'sites/all/scripts:profiles/myprofile/scripts';
 
+// Always show release notes when running pm-update or pm-updatecode
+# $command_specific['pm-update'] = array('notes' => TRUE);
+# $command_specific['pm-updatecode'] = array('notes' => TRUE);
+
+// List of drush commands or aliases that should override built-in 
+// shell functions and commands; otherwise, built-ins override drush 
+// commands. Default is help,dd,sa.
+// Warning:  bad things can happen if you put the wrong thing here
+// (e.g. eval, grep), so be cautious.
+// If a drush command overrides a built-in command (e.g. bash help),
+// then you can use the `builtin` operator to run the built-in version
+// (e.g. `builtin help` to show bash help instead of drush help.)
+// If a drush command overrides a shell command (e.g. grep), then
+// you can use the regular shell command by typing in the full path
+// to the command (e.g. /bin/grep).
+# $command_specific['core-cli'] = array('override' => 'help,dd,sa');
+
 /**
  * Variable overrides:
  *
diff --git a/sites/all/modules/drush/examples/helloworld.script b/sites/all/modules/drush/examples/helloworld.script
index 3db298815dd5c33aa8f448b38cb3392b798ce01c..07d079c98b9f923add6fb9999a15f55f1c555016 100644
--- a/sites/all/modules/drush/examples/helloworld.script
+++ b/sites/all/modules/drush/examples/helloworld.script
@@ -3,37 +3,10 @@
 //
 // This example demonstrates how to write a drush
 // "shebang" script.  These scripts start with the
-// line "#!/usr/bin/env drush", or perhaps just "!drush"
-// (although the latter is not supported on all flavors
-// of *nix).
+// line "#!/usr/bin/env drush" or "#!/full/path/to/drush".
 //
-// These scripts do not need to be named "*.script";
-// they can be named anything at all.  To run them,
-// make sure they are executable (chmod +x helloworld.script)
-// and then run them from the shell like any other
-// script.
+// See `drush topic docs-scripts` for more information.
 //
-// There are two big advantages to drush scripts over
-// bash scripts.
-//
-//  1. They are written in php
-//
-//  2. drush can bootstrap your Drupal site before
-//     running your script.
-// 
-// To bootstrap a Drupal site, provide an alias to
-// the site to bootstrap as the first commandline
-// argument.
-//
-// For example:
-//
-// $ helloworld.script @dev a b c
-//
-// If the first argument is a valid site alias, drush
-// will remove it from the arument list and bootstrap
-// that site.
-//
-
 drush_print("Hello world!");
 drush_print();
 drush_print("The arguments to this command were:");
diff --git a/sites/all/modules/drush/examples/policy.drush.inc b/sites/all/modules/drush/examples/policy.drush.inc
index 688725520a418a9f7171dfa725d8bc0d5d6d359a..ff411806579710f89788c0e572b34fafd7d49598 100644
--- a/sites/all/modules/drush/examples/policy.drush.inc
+++ b/sites/all/modules/drush/examples/policy.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: policy.drush.inc,v 1.4 2010/11/30 17:14:30 weitzman Exp $
 
 /**
  * @file
@@ -38,7 +37,7 @@ function drush_policy_sql_sync_validate($source = NULL, $destination = NULL) {
 function drush_policy_updatedb_validate() {
   // Check for a token in the request. In this case, we require --token=secret.
   if (!drush_get_option('token') == 'secret') {
-    drush_log('Per site policy, you must add a secret --token complete this command.', 'examples/policy.drush.inc');
+    drush_log(dt('Per site policy, you must add a secret --token complete this command. See examples/policy.drush.inc.  If you are running a version of drush prior to 4.3 and are not sure why you are seeing this message, please see http://drupal.org/node/1024824.'), 'warning');
     drush_set_context('DRUSH_AFFIRMATIVE', FALSE);
     drush_set_context('DRUSH_NEGATIVE', TRUE);
   }
diff --git a/sites/all/modules/drush/examples/sandwich-topic.txt b/sites/all/modules/drush/examples/sandwich-topic.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f0e0fa72aac45789019b2a714e7acec4f4c18c1d
--- /dev/null
+++ b/sites/all/modules/drush/examples/sandwich-topic.txt
@@ -0,0 +1,4 @@
+I have discovered a truly marvelous proof that it is impossible to 
+separate a sandwich into two cubes, or four sandwiches into two
+fourth of a sandwich, or in general, any sandwich larger than the 
+second into two like sandwiches. This text file is too narrow to contain it.
diff --git a/sites/all/modules/drush/examples/sandwich.drush.inc b/sites/all/modules/drush/examples/sandwich.drush.inc
index a9e8e3e4773af352951b3b342b3499768c14a0b4..c943992719606cfc5098d8b8eb7b71d4be873714 100644
--- a/sites/all/modules/drush/examples/sandwich.drush.inc
+++ b/sites/all/modules/drush/examples/sandwich.drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: sandwich.drush.inc,v 1.4 2010/10/28 23:20:48 greg1anderson Exp $
 
 /**
  * @file
@@ -8,7 +7,7 @@
  *   To run this *fun* command, execute `sudo drush --include=./examples mmas`
  *   from within your drush directory.
  *
- *   Shows how to make your own drush command.
+ *   See `drush topic docs-commands` for more information about command authoring. 
  *
  *   You can copy this file to any of the following
  *     1. A .drush folder in your HOME folder.
@@ -27,7 +26,7 @@
  * Notice how this structure closely resembles how
  * you define menu hooks.
  *
- * @See drush_parse_command() for a list of recognized keys.
+ * See `drush topic docs-commands` for a list of recognized keys.
  *
  * @return
  *   An associative array describing your command(s).
@@ -35,6 +34,7 @@
 function sandwich_drush_command() {
   $items = array();
 
+  // The 'make-me-a-sandwich' command
   $items['make-me-a-sandwich'] = array(
     'description' => "Makes a delicious sandwich.",
     'arguments' => array(
@@ -49,6 +49,18 @@ function sandwich_drush_command() {
     'aliases' => array('mmas'),
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap at all.
   );
+  
+  // Commandfiles may also add topics.  These will appear in
+  // the list of topics when `drush topic` is executed.
+  // To view this topic, run `drush --include=/full/path/to/examples topic`
+  $items['sandwich-exposition'] = array(
+    'description' => 'Ruminations on the true meaning and philosophy of sandwiches.',
+    'hidden' => TRUE,
+    'topic' => TRUE,
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
+    'callback' => 'drush_print_file',
+    'callback arguments' => array(dirname(__FILE__) . '/sandwich-topic.txt'),
+  );
 
   return $items;
 }
@@ -57,7 +69,11 @@ function sandwich_drush_command() {
  * Implementation of hook_drush_help().
  *
  * This function is called whenever a drush user calls
- * 'drush help <name-of-your-command>'
+ * 'drush help <name-of-your-command>'. This hook is optional. If a command
+ * does not implement this hook, the command's description is used instead.
+ *
+ * This hook is also used to look up help metadata, such as help
+ * category title and summary.  See the comments below for a description.
  *
  * @param
  *   A string with the help section (prepend with 'drush:')
@@ -69,11 +85,33 @@ function sandwich_drush_help($section) {
   switch ($section) {
     case 'drush:make-me-a-sandwich':
       return dt("This command will make you a delicious sandwich, just how you like it.");
+    // The 'title' meta item is used to name a group of
+    // commands in `drush help`.  If a title is not defined,
+    // the default is "All commands in ___", with the
+    // specific name of the commandfile (e.g. sandwich).
+    // Command files with less than four commands will 
+    // be placed in the "Other commands" section, _unless_
+    // they define a title.  It is therefore preferable
+    // to not define a title unless the file defines a lot
+    // of commands.
+    case 'meta:sandwich:title':
+      return dt("Sandwich commands");
+    // The 'summary' meta item is displayed in `drush help --filter`,
+    // and is used to give a general idea what the commands in this
+    // command file do, and what they have in common.
+    case 'meta:sandwich:summary':
+      return dt("Automates your sandwich-making business workflows.");
   }
 }
 
 /**
  * Implementation of drush_hook_COMMAND_validate().
+ *
+ * The validate command should exit with
+ * `return drush_set_error(...)` to stop execution of
+ * the command.  In practice, calling drush_set_error
+ * OR returning FALSE is sufficient.  See drush.api.php
+ * for more details.
  */
 function drush_sandwich_make_me_a_sandwich_validate() {
   $name = posix_getpwuid(posix_geteuid());
diff --git a/sites/all/modules/drush/examples/xkcd.drush.inc b/sites/all/modules/drush/examples/xkcd.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d17399a1d84b8fcfc3f177f6af96c0c5d38c3126
--- /dev/null
+++ b/sites/all/modules/drush/examples/xkcd.drush.inc
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * @file
+ *   Example drush command.
+ *
+ *   To run this *fun* command, execute `drush --include=./examples xkcd`
+ *   from within your drush directory.
+ *
+ *   See `drush topic docs-commands` for more information about command authoring. 
+ *
+ *   You can copy this file to any of the following
+ *     1. A .drush folder in your HOME folder.
+ *     2. Anywhere in a folder tree below an active module on your site.
+ *     3. /usr/share/drush/commands (configurable)
+ *     4. In an arbitrary folder specified with the --include option.
+ */
+
+/**
+ * Implementation of hook_drush_command().
+ *
+ * In this hook, you specify which commands your
+ * drush module makes available, what it does and
+ * description.
+ *
+ * Notice how this structure closely resembles how
+ * you define menu hooks.
+ *
+ * See `drush topic docs-commands` for a list of recognized keys.
+ *
+ * @return
+ *   An associative array describing your command(s).
+ */
+function xkcd_drush_command() {
+  $items = array();
+
+  // The 'xkcd' command
+  $items['xkcd-fetch'] = array(
+    'description' => "Retrieve and display xkcd cartoons.",
+    'arguments' => array(
+      'search' => 'Optional argument to retrive the cartoons matching an index number, keyword search or "random". If omitted the latest cartoon will be retrieved.',
+    ),
+    'options' => array(
+      'image-viewer' => 'Command to use to view images (e.g. xv, firefox). Defaults to "display" (from ImageMagick).',
+      'google-custom-search-api-key' => 'Google Custom Search API Key, available from https://code.google.com/apis/console/. Default key limited to 100 queries/day globally.',
+    ),
+    'examples' => array(
+      'drush xkcd' => 'Retrieve and display the latest cartoon.',
+      'drush xkcd sandwich' => 'Retrieve and display cartoons about sandwiches.',
+      'drush xkcd 123 --image-viewer=eog' => 'Retrieve and display cartoon #123 in eog.',
+      'drush xkcd random --image-viewer=firefox' => 'Retrieve and display a random cartoon in Firefox.',
+    ),
+    'aliases' => array('xkcd'),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap at all.
+  );
+
+  return $items;
+}
+
+/**
+ * Implementation of hook_drush_help().
+ *
+ * This function is called whenever a drush user calls
+ * 'drush help <name-of-your-command>'. This hook is optional. If a command
+ * does not implement this hook, the command's description is used instead.
+ *
+ * This hook is also used to look up help metadata, such as help
+ * category title and summary.  See the comments below for a description.
+ *
+ * @param
+ *   A string with the help section (prepend with 'drush:')
+ *
+ * @return
+ *   A string with the help text for your command.
+ */
+function xkcd_drush_help($section) {
+  switch ($section) {
+    case 'drush:xkcd-fetch':
+      return dt("A command line tool (1) for a web site tool (2), that emulates
+(badly) a web based tool (3) that emulates (badly) a command line tool (4) to
+access a web site (5) with awesome geek humor.\n
+(1) Drush
+(2) Drupal
+(3) http://uni.xkcd.com/
+(4) BASH
+(5) http://xkcd.com/");
+  }
+}
+
+/**
+ * Example drush command callback. This is where the action takes place.
+ *
+ * The function name should be same as command name but with dashes turned to
+ * underscores and 'drush_commandfile_' prepended, where 'commandfile' is
+ * taken from the file 'commandfile.drush.inc', which in this case is 'sandwich'.
+ * Note also that a simplification step is also done in instances where
+ * the commandfile name is the same as the beginning of the command name,
+ * "drush_example_example_foo" is simplified to just "drush_example_foo".
+ * To also implement a hook that is called before your command, implement
+ * "drush_hook_pre_example_foo".  For a list of all available hooks for a
+ * given command, run drush in --debug mode.
+ *
+ * If for some reason you do not want your hook function to be named
+ * after your command, you may define a 'callback' item in your command
+ * object that specifies the exact name of the function that should be
+ * called.  However, the specified callback function must still begin
+ * with "drush_commandfile_" (e.g. 'callback' => "drush_example_foo_execute")
+ * if you want that all hook functions are still called (e.g.
+ * drush_example_pre_foo_execute, and so on).
+ *
+ * In this function, all of Drupal's API is (usually) available, including
+ * any functions you have added in your own modules/themes.
+ *
+ * @see drush_invoke()
+ * @see drush.api.php
+ *
+ * @param
+ *   An optional string with search keyworks, cartoon ID or "random".
+ */
+function drush_xkcd_fetch($search = '') {
+  if (empty($search)) {
+    drush_xkcd_display('http://xkcd.com');
+  }
+  elseif (is_numeric($search)) {
+    drush_xkcd_display('http://xkcd.com/' . $search);
+  }
+  elseif ($search == 'random') {
+    $xkcd_response = @json_decode(file_get_contents('http://xkcd.com/info.0.json'));
+    if (!empty($xkcd_response->num)) {
+      drush_xkcd_display('http://xkcd.com/' . rand(1, $xkcd_response->num));
+    }
+  }
+  else {
+    // This uses an API key with a limited number of searches per 
+    $search_response = @json_decode(file_get_contents('https://www.googleapis.com/customsearch/v1?key=' . drush_get_option('google-custom-search-api-key', 'AIzaSyDpE01VDNNT73s6CEeJRdSg5jukoG244ek') . '&cx=012652707207066138651:zudjtuwe28q&q=' . $search));
+    if (!empty($search_response->items)) {
+      foreach ($search_response->items as $item) {
+        drush_xkcd_display($item->link);
+      }
+    }
+    else {
+      drush_set_error('DRUSH_XKCD_SEARCH_FAIL', dt('The search failed or produced no results.'));
+    }
+  }
+}
+
+/**
+ * Retrieve and display a table of metadata for an XKCD cartoon,
+ * then retrieve and display the cartoon using a specified image viewer.
+ *
+ * @param
+ *   A string with the URL of the cartoon to display.
+ */
+function drush_xkcd_display($url) {
+  $xkcd_response = @json_decode(file_get_contents($url . '/info.0.json'));
+  if (!empty($xkcd_response->num)) {
+    $data = (array)$xkcd_response;
+    $data['date'] = $data['year'] . '/' . $data['month'] . '/' . $data['day'];
+    unset($data['safe_title'], $data['news'], $data['link'], $data['year'], $data['month'], $data['day']);
+    drush_print_table(drush_key_value_to_array_table($data));
+    $img = realpath(_drush_download_file($data['img']));
+    drush_register_file_for_deletion($img);
+    drush_shell_exec(drush_get_option('image-viewer', 'display') . ' ' . $img);
+  }
+  else {
+    drush_set_error('DRUSH_XKCD_METADATA_FAIL', dt('Unable to retrieve cartoon metadata.'));
+  }
+}
diff --git a/sites/all/modules/drush/includes/.gitignore b/sites/all/modules/drush/includes/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ed285c052b1053d47dd30f4e4de787cbfbeb0b40
--- /dev/null
+++ b/sites/all/modules/drush/includes/.gitignore
@@ -0,0 +1 @@
+table.inc
\ No newline at end of file
diff --git a/sites/all/modules/drush/includes/backend.inc b/sites/all/modules/drush/includes/backend.inc
index b7bc048bd8eb41b2ca0bd36d953d230d703085db..fd4cb1fc84148f8f1998bedef034e4eb6af9207c 100644
--- a/sites/all/modules/drush/includes/backend.inc
+++ b/sites/all/modules/drush/includes/backend.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: backend.inc,v 1.33 2010/11/27 03:12:19 weitzman Exp $
 
 /**
  * @file Drush backend API
@@ -47,8 +46,14 @@
  * external servers through SSH pipes, simply by prepending, 'ssh username@server.com'
  * in front of the command.
  *
- * If the key-based ssh authentication has been set up between the servers, this will just
- * work, otherwise the user will be asked to enter a password.
+ * If the key-based ssh authentication has been set up between the servers,
+ * this will just work.  By default, drush is configured to disallow password
+ * authentication; if you would like to enter a password for every connection,
+ * then in your drushrc.php file, set $options['ssh-options'] so that it does NOT
+ * include '-o PasswordAuthentication=no'.  See examples/example.drushrc.php.
+ *
+ * The results from backend API calls can be fetched via a call to
+ * drush_backend_get_result().
  */
 
 /**
@@ -61,7 +66,43 @@ function drush_backend_set_result($value) {
     drush_set_context('BACKEND_RESULT', $value);
   }
 }
-
+/**
+ * Retrieves the results from the last call to backend_invoke.
+ *
+ * @returns array
+ *   An associative array containing information from the last
+ *   backend invoke.  The keys in the array include:
+ *
+ *     - output: This item contains the textual output of
+ *       the command that was executed.
+ *     - object: Contains the PHP object representation of the
+ *       result of the command.
+ *     - self: The self object contains the alias record that was
+ *       used to select the bootstrapped site when the command was
+ *       executed.
+ *     - error_status: This item returns the error status for the
+ *       command.  Zero means "no error".
+ *     - log: The log item contains an array of log messages from
+ *       the command execution ordered chronologically.  Each log
+ *       entery is an associative array.  A log entry contains
+ *       following items:
+ *         o  type: The type of log entry, such as 'notice' or 'warning'
+ *         o  message: The log message
+ *         o  timestamp: The time that the message was logged
+ *         o  memory: Available memory at the time that the message was logged
+ *         o  error: The error code associated with the log message
+ *            (only for log entries whose type is 'error')
+ *     - error_log: The error_log item contains another representation
+ *       of entries from the log.  Only log entries whose 'error' item
+ *       is set will appear in the error log.  The error log is an
+ *       associative array whose key is the error code, and whose value
+ *       is an array of messages--one message for every log entry with
+ *       the same error code.
+ *     - context: The context item contains a representation of all option
+ *       values that affected the operation of the command, including both
+ *       the command line options, options set in a drushrc.php configuration
+ *       files, and options set from the alias record used with the command.
+ */
 function drush_backend_get_result() {
   return drush_get_context('BACKEND_RESULT');
 }
@@ -84,6 +125,16 @@ function drush_backend_output() {
   // The error log is a more specific version of the log, and may be used by calling
   // scripts to check for specific errors that have occurred.
   $data['error_log'] = drush_get_error_log();
+  // If there is a @self record, then include it in the result
+  $self_record = drush_sitealias_get_record('@self');
+  if (!empty($self_record)) {
+    $site_context = drush_get_context('site', array());
+    unset($site_context['config-file']);
+    unset($site_context['context-path']);
+    unset($self_record['loaded-config']);
+    unset($self_record['#name']);
+    $data['self'] = array_merge($site_context, $self_record);
+  }
 
   // Return the options that were set at the end of the process.
   $data['context']  = drush_get_merged_options();
@@ -140,11 +191,12 @@ function drush_backend_parse_output($string, $integrate = TRUE) {
 function _drush_backend_integrate($data) {
   if (is_array($data['log'])) {
     foreach($data['log'] as $log) {
+      $message = is_array($log['message']) ? implode("\n", $log['message']) : $log['message'];
       if (!is_null($log['error'])) {
-        drush_set_error($log['error'], $log['message']);
+        drush_set_error($log['error'], $message);
       }
       else {
-        drush_log($log['message'], $log['type'], $log['error']);
+        drush_log($message, $log['type']);
       }
     }
   }
@@ -178,7 +230,10 @@ function _drush_proc_open($cmd, $data = NULL, $context = NULL) {
      1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
      2 => array("pipe", "w")   // stderr is a pipe the child will write to
   );
-
+  if (drush_get_context('DRUSH_SIMULATE')) {
+    drush_print('proc_open: ' . $cmd);
+    return FALSE;
+  }
   $process = proc_open($cmd, $descriptorspec, $pipes, null, null, array('context' => $context));
   if (is_resource($process)) {
     if ($data) {
@@ -210,7 +265,7 @@ function _drush_proc_open($cmd, $data = NULL, $context = NULL) {
     $code = proc_close($process);
     return array('cmd' => $cmd, 'output' => $string, 'code' => $code);
   }
-  return false;
+  return FALSE;
 }
 
 /**
@@ -242,6 +297,9 @@ function _drush_proc_open($cmd, $data = NULL, $context = NULL) {
  * @param username
  *    Optional. Defaults to the current user. If you specify this, you can choose which module to send.
  *
+ * @deprecated Command name includes arguments, and these are not quote-escaped in any way.
+ * @see drush_invoke_process("@self", $command, array($arg1, $arg2, ...), $data) for a better option.
+ *
  * @return
  *   If the command could not be completed successfully, FALSE.
  *   If the command was completed, this will return an associative array containing the data from drush_backend_output().
@@ -254,10 +312,62 @@ function drush_backend_invoke($command, $data = array(), $method = 'GET', $integ
 
 /**
  * A variant of drush_backend_invoke() which specifies command and arguments separately.
+ *
+ * @deprecated; do not call directly.
+ * @see drush_invoke_process("@self", $command, $args, $data) for a better option.
  */
 function drush_backend_invoke_args($command, $args, $data = array(), $method = 'GET', $integrate = TRUE, $drush_path = NULL, $hostname = NULL, $username = NULL, $ssh_options = NULL) {
   $cmd = _drush_backend_generate_command($command, $args, $data, $method, $drush_path, $hostname, $username, $ssh_options);
-  return _drush_backend_invoke($cmd, $data, $integrate);
+  return _drush_backend_invoke($cmd, $data, array_key_exists('#integrate', $data) ? $data['#integrate'] : $integrate);
+}
+
+/**
+ * Execute a new local or remote command in a new process.
+ *
+ * @param site_record
+ *   An array containing information used to generate the command.
+ *   'remote-host'
+ *      Optional. A remote host to execute the drush command on.
+ *   'remote-user'
+ *      Optional. Defaults to the current user. If you specify this, you can choose which module to send.
+ *   'ssh-options'
+ *      Optional.  Defaults to "-o PasswordAuthentication=no"
+ *   'path-aliases'
+ *      Optional; contains paths to folders and executables useful to the command.
+ *      '%drush-script'
+ *        Optional. Defaults to the current drush.php file on the local machine, and
+ *        to simply 'drush' (the drush script in the current PATH) on remote servers.
+ *        You may also specify a different drush.php script explicitly.  You will need
+ *        to set this when calling drush on a remote server if 'drush' is not in the
+ *        PATH on that machine.
+ * @param command
+ *    A defined drush command such as 'cron', 'status' or any of the available ones such as 'drush pm'.
+ * @param args
+ *    An array of 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.
+ *    This parameter is a reference, as any options that have been represented as either an option, or an argument will be removed.
+ *    This allows you to pass the left over options as a JSON encoded string, without duplicating data.
+ * @param method
+ *    Optional. Defaults to 'GET'.
+ *    If this parameter is set to 'POST', the $data array will be passed to the script being called as a JSON encoded string over
+ *    the STDIN pipe of that process. This is preferable if you have to pass sensitive data such as passwords and the like.
+ *    For any other value, the $data array will be collapsed down into a set of command line options to the script.
+ * @param integrate
+ *    Optional. Defaults to TRUE.
+ *    If TRUE, any error statuses or log messages will be integrated into the current process. This might not be what you want,
+ *    if you are writing a command that operates on multiple sites.
+ *
+ * @return
+ *   A text string representing a fully escaped command.
+ *
+ * @deprecated; do not call directly.
+ * @see drush_invoke_process($site_record, $command, $args, $data) for a better option.
+ */
+function drush_backend_invoke_sitealias($site_record, $command, $args, $data = array(), $method = 'GET', $integrate = TRUE) {
+  $cmd = _drush_backend_generate_command_sitealias($site_record, $command, $args, $data, $method);
+  return _drush_backend_invoke($cmd, $data, array_key_exists('#integrate', $data) ? $data['#integrate'] : $integrate);
 }
 
 /**
@@ -283,19 +393,25 @@ function drush_backend_invoke_args($command, $args, $data = array(), $method = '
  */
 function _drush_backend_invoke($cmd, $data = null, $integrate = TRUE) {
   drush_log(dt('Running: !cmd', array('!cmd' => $cmd)), 'command');
-  $proc = _drush_proc_open($cmd, $data);
-
-  if (($proc['code'] == DRUSH_APPLICATION_ERROR) && $integrate) {
-    drush_set_error('DRUSH_APPLICATION_ERROR', dt("The external command could not be executed due to an application error."));
+  if (array_key_exists('#interactive', $data)) {
+    drush_log(dt("executing !cmd", array('!cmd' => $cmd)));
+    return drush_op_system($cmd);
   }
+  else {
+    $proc = _drush_proc_open($cmd, $data);
 
-  if ($proc['output']) {
-    $values = drush_backend_parse_output($proc['output'], $integrate);
-    if (is_array($values)) {
-      return $values;
+    if (($proc['code'] == DRUSH_APPLICATION_ERROR) && $integrate) {
+      drush_set_error('DRUSH_APPLICATION_ERROR', dt("The external command could not be executed due to an application error."));
     }
-    else {
-      return drush_set_error('DRUSH_FRAMEWORK_ERROR', dt("The command could not be executed successfully (returned: !return, code: %code)", array("!return" => $proc['output'], "%code" =>  $proc['code'])));
+
+    if ($proc['output']) {
+      $values = drush_backend_parse_output($proc['output'], $integrate);
+      if (is_array($values)) {
+        return $values;
+      }
+      else {
+        return drush_set_error('DRUSH_FRAMEWORK_ERROR', dt("The command could not be executed successfully (returned: !return, code: %code)", array("!return" => $proc['output'], "%code" =>  $proc['code'])));
+      }
     }
   }
   return FALSE;
@@ -318,10 +434,6 @@ function _drush_backend_invoke($cmd, $data = null, $integrate = TRUE) {
  *    If this parameter is set to 'POST', the $data array will be passed to the script being called as a JSON encoded string over
  *    the STDIN pipe of that process. This is preferable if you have to pass sensitive data such as passwords and the like.
  *    For any other value, the $data array will be collapsed down into a set of command line options to the script.
- * @param integrate
- *    Optional. Defaults to TRUE.
- *    If TRUE, any error statuses or log messages will be integrated into the current process. This might not be what you want,
- *    if you are writing a command that operates on multiple sites.
  * @param drush_path
  *    Optional. Defaults to the current drush.php file on the local machine, and
  *    to simply 'drush' (the drush script in the current PATH) on remote servers.
@@ -335,12 +447,77 @@ function _drush_backend_invoke($cmd, $data = null, $integrate = TRUE) {
  *
  * @return
  *   A text string representing a fully escaped command.
+ *
+ * @deprecated Is not as flexible as recommended command.  @see _drush_backend_generate_command_sitealias().
  */
 function _drush_backend_generate_command($command, $args, &$data, $method = 'GET', $drush_path = null, $hostname = null, $username = null, $ssh_options = NULL) {
+  return _drush_backend_generate_command_sitealias(
+    array(
+      'remote-host' => $hostname,
+      'remote-user' => $username,
+      'ssh-options' => $ssh_options,
+      'path-aliases' => array(
+        '%drush-script' => $drush_path,
+      ),
+    ), $command, $args, $data, $method);
+}
+
+/**
+ * Generate a command to execute.
+ *
+ * @param site_record
+ *   An array containing information used to generate the command.
+ *   'remote-host'
+ *      Optional. A remote host to execute the drush command on.
+ *   'remote-user'
+ *      Optional. Defaults to the current user. If you specify this, you can choose which module to send.
+ *   'ssh-options'
+ *      Optional.  Defaults to "-o PasswordAuthentication=no"
+ *   'path-aliases'
+ *      Optional; contains paths to folders and executables useful to the command.
+ *      '%drush-script'
+ *        Optional. Defaults to the current drush.php file on the local machine, and
+ *        to simply 'drush' (the drush script in the current PATH) on remote servers.
+ *        You may also specify a different drush.php script explicitly.  You will need
+ *        to set this when calling drush on a remote server if 'drush' is not in the
+ *        PATH on that machine.
+ * @param command
+ *    A defined drush command such as 'cron', 'status' or any of the available ones such as 'drush pm'.
+ * @param args
+ *    An array of 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.
+ *    This parameter is a reference, as any options that have been represented as either an option, or an argument will be removed.
+ *    This allows you to pass the left over options as a JSON encoded string, without duplicating data.
+ * @param method
+ *    Optional. Defaults to 'GET'.
+ *    If this parameter is set to 'POST', the $data array will be passed to the script being called as a JSON encoded string over
+ *    the STDIN pipe of that process. This is preferable if you have to pass sensitive data such as passwords and the like.
+ *    For any other value, the $data array will be collapsed down into a set of command line options to the script.
+ *
+ * @return
+ *   A text string representing a fully escaped command.
+ */
+function _drush_backend_generate_command_sitealias($site_record, $command, $args, &$data, $method = 'GET') {
+  $drush_path = null;
+
+  $hostname = array_key_exists('remote-host', $site_record) ? $site_record['remote-host'] : null;
+  $username = array_key_exists('remote-user', $site_record) ? $site_record['remote-user'] : null;
+  $ssh_options = array_key_exists('ssh-options', $site_record) ? $site_record['ssh-options'] : null;
+  $os = drush_os($site_record);
+
+  $drush_path = NULL;
+  if (array_key_exists('path-aliases', $site_record)) {
+    if (array_key_exists('%drush-script', $site_record['path-aliases'])) {
+      $drush_path = $site_record['path-aliases']['%drush-script'];
+    }
+  }
+
   if (drush_is_local_host($hostname)) {
     $hostname = null;
   }
-  
+
   $drush_path = !is_null($drush_path) ? $drush_path : (is_null($hostname) ? DRUSH_COMMAND : 'drush'); // Call own drush.php file on local machines, or 'drush' on remote machines.
   $data['root'] = array_key_exists('root', $data) ? $data['root'] : drush_get_context('DRUSH_DRUPAL_ROOT');
   $data['uri'] = array_key_exists('uri', $data) ? $data['uri'] : drush_get_context('DRUSH_URI');
@@ -353,15 +530,19 @@ function _drush_backend_generate_command($command, $args, &$data, $method = 'GET
     }
   }
   foreach ($args as $arg) {
-    $command .= ' ' . escapeshellarg($arg);
+    $command .= ' ' . drush_escapeshellarg($arg);
   }
+  $interactive = ' ' . (empty($data['#interactive']) ? '' : ' > `tty`') . ' 2>&1';
   // @TODO: Implement proper multi platform / multi server support.
-  $cmd = escapeshellcmd($drush_path) . " " . $option_str . " " . $command . " --backend";
+  $cmd = escapeshellcmd($drush_path) . " " . $option_str . " " . $command . (empty($data['#interactive']) ? " --backend" : "");
 
   if (!is_null($hostname)) {
-    $username = (!is_null($username)) ? $username : get_current_user();
+    $username = (!is_null($username)) ? drush_escapeshellarg($username) . "@" : '';
     $ssh_options = (!is_null($ssh_options)) ? $ssh_options : drush_get_option('ssh-options', "-o PasswordAuthentication=no");
-    $cmd = "ssh " . $ssh_options . " " . escapeshellarg($username) . "@" . escapeshellarg($hostname) . " " . escapeshellarg($cmd);
+    $cmd = "ssh " . $ssh_options . " " . $username . drush_escapeshellarg($hostname) . " " . drush_escapeshellarg($cmd . ' 2>&1', $os) . $interactive;
+  }
+  else {
+    $cmd .= $interactive;
   }
 
   return $cmd;
@@ -381,8 +562,7 @@ function drush_backend_fork($command, $data, $drush_path = null, $hostname = nul
   $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);
+  drush_op_system($cmd);
 }
 
 /**
@@ -411,7 +591,7 @@ function _drush_backend_argument_string(&$data, $method = 'GET') {
       if (is_numeric($key)) {
         $args[$key] = $value;
       }
-      else {
+      elseif (substr($key,0,1) != '#') {
         $options[$key] = $value;
       }
     }
diff --git a/sites/all/modules/drush/includes/command.inc b/sites/all/modules/drush/includes/command.inc
index 6ff04fcf81de7546d9d525f02890d475cac92acd..de876c54b20fef97ff16ce42a536c3bbede08a6f 100644
--- a/sites/all/modules/drush/includes/command.inc
+++ b/sites/all/modules/drush/includes/command.inc
@@ -1,5 +1,375 @@
 <?php
-// $Id: command.inc,v 1.88 2010/11/10 02:55:41 weitzman Exp $
+
+/**
+ * @defgroup dispatching Command dispatching functions.
+ * @{
+ *
+ * These functions handle command dispatching, and can
+ * be used to programatically invoke drush commands in
+ * different ways.
+ */
+
+/**
+ * Invoke drush api calls.
+ *
+ * Executes the specified command with the specified arguments on the
+ * currently bootstrapped site using the current option contexts.
+ * Note that drush_invoke will not bootstrap any further than the
+ * current command has already bootstrapped; therefore, you should only invoke
+ * commands that have the same (or lower) bootstrap requirements.
+ *
+ * Call the correct hook for all the modules that implement it.
+ * Additionally, the ability to rollback when an error has been encountered is also provided.
+ * If at any point during execution, the drush_get_error() function returns anything but 0,
+ * drush_invoke() will trigger $hook_rollback for each of the hooks that implement it,
+ * in reverse order from how they were executed.  Rollbacks are also triggered any
+ * time a hook function returns FALSE.
+ *
+ * This function will also trigger pre_$hook and post_$hook variants of the hook
+ * and its rollbacks automatically.
+ *
+ * HOW DRUSH HOOK FUNCTIONS ARE NAMED:
+ *
+ * The name of the hook is composed from the name of the command and the name of
+ * the command file that the command definition is declared in.  The general
+ * form for the hook filename is:
+ *
+ *      drush_COMMANDFILE_COMMANDNAME
+ *
+ * In many cases, drush commands that are functionally part of a common collection
+ * of similar commands will all be declared in the same file, and every command
+ * defined in that file will start with the same command prefix.  For example, the
+ * command file "pm.drush.inc" defines commands such as "pm-enable" and "pm-disable".
+ * In the case of "pm-enable", the command file is "pm", and and command name is
+ * "pm-enable".  When the command name starts with the same sequence of characters
+ * as the command file, then the repeated sequence is dropped; thus, the command
+ * hook for "pm-enable" is "drush_pm_enable", not "drush_pm_pm_enable".
+ *
+ * @param command
+ *   The drush command to execute.
+ * @return
+ *   A boolean specifying whether or not the command was successfully completed.
+ */
+function drush_invoke($command) {
+  $args = func_get_args();
+  array_shift($args);
+
+  return drush_invoke_args($command, $args);
+}
+
+/**
+ * As drush_invoke, but args are passed in as an array
+ * rather than as individual function parameters.
+ *
+ * @see drush_invoke()
+ */
+function drush_invoke_args($command, $args) {
+  return _drush_invoke_args($command, $args, drush_get_commandfile_for_command($command));
+}
+
+/**
+ * Variant of _drush_invoke_args that allows the
+ * commandfile to be specified correctly; this allows
+ * the hook functions to be correctly determined for
+ * commands that provide a 'callback' function.
+ *
+ * This function should not be called directly; use
+ * @see drush_dispatch() and @see drush_invoke_args()
+ */
+function _drush_invoke_args($command, $args, $defined_in_commandfile) {
+  drush_command_include($command);
+  // Generate the base name for the hook by converting all
+  // dashes in the command name to underscores.
+  $hook = str_replace("-", "_", $command);
+
+  // Call the hook init function, if it exists.
+  // If a command needs to bootstrap, it is advisable
+  // to do so in _init; otherwise, new commandfiles
+  // will miss out on participating in any stage that
+  // has passed or started at the time it was discovered.
+  $func = 'drush_' . $hook . '_init';
+  if (function_exists($func)) {
+    drush_log(dt("Calling drush command init function: !func", array('!func' => $func)), 'bootstrap');
+    call_user_func_array($func, $args);
+    _drush_log_drupal_messages();
+    if (drush_get_error()) {
+      drush_log(dt('The command @command could not be initialized.', array('@command' => $command)), 'error');
+      return FALSE;
+    }
+  }
+
+  $rollback = FALSE;
+  $completed = array();
+  $available_rollbacks = array();
+  $all_available_hooks = array();
+
+  // Iterate through the different hook variations
+  $variations = array($hook . "_validate", "pre_$hook", $hook, "post_$hook");
+  foreach ($variations as $var_hook) {
+    // Get the list of command files.
+    // We re-fetch the list every time through
+    // the loop in case one of the hook function
+    // does something that will add additional
+    // commandfiles to the list (i.e. bootstrapping
+    // to a higher phase will do this).
+    $list = drush_commandfile_list();
+
+    $functions = array();
+
+    // Run all of the functions available for this variation
+    foreach ($list as $commandfile => $filename) {
+      $func = sprintf("drush_%s_%s", $commandfile, $var_hook);
+      if (($defined_in_commandfile == $commandfile) && ($commandfile . "_" == substr($var_hook . "_",0,strlen($commandfile)+ 1))) {
+        $oldfunc = $func;
+        $func = sprintf("drush_%s", $var_hook);
+        if (($oldfunc != $func) && (function_exists($oldfunc))) {
+          drush_log(dt("The drush command hook naming conventions changed in March 2010; the function !oldfunc must be renamed to !func in order to be called.", array('!oldfunc' => $oldfunc, '!func' => $func)), "error");
+        }
+      }
+      if (function_exists($func)) {
+        $functions[] = $func;
+        $all_available_hooks[] = $func . ' [* Defined in ' . $filename . ']';
+        $available_rollbacks[] = $func . '_rollback';
+        $completed[] = $func;
+        $result = call_user_func_array($func, $args);
+        _drush_log_drupal_messages();
+        if (drush_get_error() || ($result === FALSE)) {
+          $rollback = TRUE;
+          // break out of the foreach variations and foreach list
+          break 2;
+        }
+      }
+      else {
+        $all_available_hooks[] = $func;
+      }
+    }
+  }
+
+  // If no hook functions were found, print a warning.
+  if (empty($all_available_hooks)) {
+    drush_log(dt("No hook functions were found for !command.", array('!command' => $command)), 'warning');
+    drush_log(dt("Available drush_invoke() hooks for !command: !available", array('!command' => $command, '!available' => "\n" . implode("\n", $all_available_hooks))), 'warning');
+  }
+  elseif (drush_get_option('show-invoke')) {
+    // We show all available hooks up to and including the one that failed (or all, if there were no failures)
+    drush_log(dt("Available drush_invoke() hooks for !command: !available", array('!command' => $command, '!available' => "\n" . implode("\n", $all_available_hooks))), 'ok');
+  }
+  if (drush_get_option('show-invoke')) {
+    drush_log(dt("Available rollback hooks for !command: !rollback", array('!command' => $command, '!rollback' => "\n" . implode("\n", $available_rollbacks))), 'ok');
+  }
+
+  // something went wrong, we need to undo
+  if ($rollback) {
+    foreach (array_reverse($completed) as $func) {
+      $rb_func = $func . '_rollback';
+      if (function_exists($rb_func)) {
+        call_user_func_array($rb_func, $args);
+        _drush_log_drupal_messages();
+        drush_log(dt("Changes made in !func have been rolled back.", array('!func' => $func)), 'rollback');
+      }
+    }
+  }
+
+  return !$rollback;
+}
+
+/**
+ * Given a command record, dispatch it as if it were
+ * the original command.  Executes in the currently
+ * bootstrapped site using the current option contexts.
+ * Note that drush_dispatch will not bootstrap any further than the
+ * current command has already bootstrapped; therefore, you should only invoke
+ * commands that have the same (or lower) bootstrap requirements.
+ *
+ * @param command
+ *   A full $command such as returned by drush_get_commands().
+ * @param arguments
+ *   An array of argument values.
+ *
+ * @see drush_topic_docs_topic().
+ */
+function drush_dispatch($command, $arguments = array()) {
+  drush_set_command($command);
+  $return = FALSE;
+
+  // Set warning for Windows users. We have already loaded site-specific drushrc.
+  drush_environment_check_os();
+
+  if ($command) {
+    // Add arguments, if this has not already been done.
+    // (If the command was fetched from drush_parse_command,
+    // then you cannot provide arguments to drush_dispatch.)
+    if (empty($command['arguments'])) {
+      _drush_prepare_command($command, $arguments);
+    }
+
+    // Add command-specific options, if applicable
+    drush_command_default_options($command);
+
+    // Print a warning if someone tries to use a deprecated alias.
+    if (isset($command['deprecated'])) {
+      drush_log(dt('Warning: The command name "!deprecated" is deprecated.  Please use a recommended form instead (!recommended).', array('!deprecated' => $command['deprecated-name'], '!recommended' => implode(',', array_merge(array($command['command']), $command['aliases'])))), 'warning');
+    }
+    // Call the callback function of the active command.
+    $return = call_user_func_array($command['callback'], $command['arguments']);
+  }
+
+  // Add a final log entry, just so a timestamp appears.
+  drush_log(dt('Command dispatch complete'), 'notice');
+
+  return $return;
+}
+
+/**
+ * Invoke a command in a new process, targeting the site specified by
+ * the provided site alias record.
+ *
+ * @param array $site_alias_record
+ *  The site record to execute the command on.
+ * @param string $command_name
+ *  The command to invoke.
+ * @param array $commandline_args
+ *  The arguments to pass to the command.
+ * @param array $commandline_options
+ *  The options (e.g. --select) to provide to the command.
+ * @return
+ *   If the command could not be completed successfully, FALSE.
+ *   If the command was completed, this will return an associative
+ *   array containing the results of the API call.
+ *   @see drush_backend_get_result()
+ *
+ * This function may also be called via its deprecated function signature
+ * (drush-3.x compatible): drush_invoke_process($command_name, $arg1, $arg2, ...);
+ * Instead of this old form, prefer: drush_invoke_process("@self", $command_name, array($arg1, $arg2, ...));
+ */
+function drush_invoke_process($site_alias_record /*, $command_name, $commandline_args = array(), $commandline_options = array() */) {
+  if (is_array($site_alias_record)) {
+    $args = func_get_args();
+    array_shift($args);
+    $command_name = array_shift($args);
+    $commandline_args = empty($args) ? array() : array_shift($args);
+    $commandline_options = empty($args) ? array() : array_shift($args);
+    return drush_invoke_sitealias_args($site_alias_record, $command_name, $commandline_args, $commandline_options);
+  }
+  else {
+    $args = func_get_args();
+    $command_name = array_shift($args);
+    return drush_invoke_process_args($command_name, $args);
+  }
+}
+
+/**
+ * Invoke a command in a new process.
+ *
+ * @param command_name
+ *   The drush command to execute.
+ * @return
+ *   If the command could not be completed successfully, FALSE.
+ *   If the command was completed, this will return an associative
+ *   array containing the results of the API call.
+ *   @see drush_backend_get_result()
+ * @deprecated; @see drush_invoke_process("@self", $command_name, $commandline_args, $commandline_options) for a better option
+ */
+function drush_invoke_process_args($command_name, $commandline_args, $commandline_options = array()) {
+  return drush_backend_invoke_args($command_name, $commandline_args, $commandline_options);
+}
+
+/**
+ * Invoke a command in a new process, targeting the site specified by
+ * the provided site alias record.
+ *
+ * @param array $site_alias_record
+ *  The site record to execute the command on.
+ * @param string $command_name
+ *  The command to invoke.
+ * @return
+ *   If the command could not be completed successfully, FALSE.
+ *   If the command was completed, this will return an associative
+ *   array containing the results of the API call.
+ *   @see drush_backend_get_result()
+ * @deprecated; @see  drush_invoke_process($site_alias_record, $command_name, array($arg1, $arg2, ...)) for a better option
+ */
+function drush_invoke_sitealias($site_alias_record, $command_name) {
+  $args = func_get_args();
+  array_shift($args);
+  array_shift($args);
+
+  return drush_invoke_sitealias_args($site_alias_record, $command_name, $args);
+}
+
+/**
+ * Invoke a command in a new process, targeting the site specified by
+ * the provided site alias record.
+ *
+ * @param array $site_alias_record
+ *  The site record to execute the command on.
+ * @param string $command_name
+ *  The command to invoke.
+ * @param array $commandline_args
+ *  The arguments to pass to the command.
+ * @param array $commandline_options
+ *  The options (e.g. --select) to provide to the command.
+ * @return
+ *   If the command could not be completed successfully, FALSE.
+ *   If the command was completed, this will return an associative
+ *   array containing the results of the API call.
+ *   @see drush_backend_get_result()
+ * @deprecated; @see drush_invoke_process($site_alias_record, $command_name, $commandline_args, $commandline_options) for a better option
+ */
+function drush_invoke_sitealias_args($site_alias_record, $command_name, $commandline_args, $commandline_options = array()) {
+  // If the first parameter is not a site alias record,
+  // then presume it is an alias name, and try to look up
+  // the alias record.
+  if (!is_array($site_alias_record)) {
+    $site_alias_record = drush_sitealias_get_record($site_alias_record);
+  }
+  return drush_do_site_command($site_alias_record, $command_name, $commandline_args, $commandline_options);
+}
+
+/**
+ * Get the options that were passed to the current command.
+ *
+ * This function returns an array that contains all of the options
+ * that are appropriate for forwarding along to one of the drush_invoke_*_args
+ * functions.
+ *
+ * @return
+ *   An associative array of option key => value pairs.
+ */
+function drush_redispatch_get_options() {
+  // Start off by taking everything from the site alias and command line
+  // ('cli' context)
+  $options = array_merge(drush_get_context('alias'), drush_get_context('cli'));
+  $options = array_diff_key($options, array_flip(drush_sitealias_site_selection_keys()));
+  unset($options['command-specific']);
+  unset($options['path-aliases']);
+  // If we can parse the current command, then examine all contexts
+  // in order for any option that is directly related to the current command
+  $command = drush_parse_command();
+  if (is_array($command)) {
+    foreach ($command['options'] as $key => $value) {
+      // Strip leading --
+      $key = ltrim($key, '-');
+      $value = drush_get_option($key);
+      if (isset($value)) {
+        $options[$key] = $value;
+      }
+    }
+  }
+  // 'php', if needed, will be included in DRUSH_COMMAND.  If DRUSH_COMMAND
+  // is not used (e.g. when calling a remote instance of drush), then --php
+  // should not be passed along.
+  unset($options['php']);
+  // If --bootstrap-to-first-arg is specified, do not
+  // pass it along to remote commands.
+  unset($options['bootstrap-to-first-arg']);
+
+  return $options;
+}
+
+/**
+ * @} End of "defgroup dispatching".
+ */
 
 /**
  * @file
@@ -21,10 +391,10 @@ function drush_parse_args() {
   $args = drush_get_context('argv');
   // TODO: commandfiles should be able to extend this list.
   static $arg_opts = array('c', 'u', 'r', 'l', 'i');
-  
+
   // Check to see if we were executed via a "#!/usr/bin/env drush" script
   drush_adjust_args_if_shebang_script($args);
-    
+
   // Now process the command line arguments.  We will divide them
   // into options (starting with a '-') and arguments.
   $arguments = $options = array();
@@ -69,14 +439,43 @@ function drush_parse_args() {
       $arguments[] = $opt;
     }
   }
-  // If no arguments are specified, print the help screen.
-  $arguments = sizeof($arguments) ? $arguments : array('help');
-  
+  // If no arguments are specified, then the command will
+  // be either 'help' or 'version' (the later if --version is specified)
+  if (!sizeof($arguments)) {
+    if (array_key_exists('version', $options)) {
+      $arguments = array('version');
+    }
+    else {
+      $arguments = array('help');
+    }
+  }
+
   // Handle the "@shift" alias, if present
   drush_process_bootstrap_to_first_arg($arguments);
-  
+
   drush_set_arguments($arguments);
-  drush_set_context('options', $options);
+  drush_set_context('cli', $options);
+}
+
+/**
+ * Get the short commandfile name that matches the
+ * command.
+ *
+ * @param $command
+ *   The name of the command (e.g. search-index)
+ * @return String
+ *   The short commandfile name where that command was
+ *   defined (e.g. search, not search.drush.inc)
+ */
+function drush_get_commandfile_for_command($command) {
+  $commandfile = FALSE;
+
+  $commands = drush_get_commands();
+  if (array_key_exists($command, $commands)) {
+    $commandfile = $commands[$command]['commandfile'];
+  }
+
+  return $commandfile;
 }
 
 /**
@@ -116,7 +515,7 @@ function drush_shift() {
  *   /path/to/drush "--flag php-script" /path/to/script userArg1 userArg2 ...
  * (Note that execve does not split the parameters from
  * the shebang line on whitespace; see http://en.wikipedia.org/wiki/Shebang_%28Unix%29)
- * When drush is called via one of the "shebang" lines above, 
+ * When drush is called via one of the "shebang" lines above,
  * the first or second parameter will be the full path
  * to the "shebang" script file -- and if the path to the
  * script is in the second position, then we will expect that
@@ -130,7 +529,7 @@ function drush_adjust_args_if_shebang_script(&$args) {
   if (_drush_is_drush_shebang_script($args[1])) {
     // If $args[1] is a drush "shebang" script, we will insert
     // the option "--bootstrap-to-first-arg" and the command
-    // "php-script" at the beginning of  @args, so the command 
+    // "php-script" at the beginning of  @args, so the command
     // line args become:
     //   /path/to/drush --bootstrap-to-first-arg php-script /path/to/script userArg1 userArg2 ...
     drush_set_option('bootstrap-to-first-arg', TRUE);
@@ -139,7 +538,7 @@ function drush_adjust_args_if_shebang_script(&$args) {
   }
   elseif (((strpos($args[1], ' ') !== FALSE) || (!ctype_alnum($args[1][0]))) && (_drush_is_drush_shebang_script($args[2]))) {
     // If $args[2] is a drush "shebang" script, we will insert
-    // the space-exploded $arg[1] in place of $arg[1], so the 
+    // the space-exploded $arg[1] in place of $arg[1], so the
     // command line args become:
     //   /path/to/drush scriptArg1 scriptArg2 ... /path/to/script userArg1 userArg2 ...
     // If none of the script arguments look like a drush command,
@@ -161,10 +560,10 @@ function drush_adjust_args_if_shebang_script(&$args) {
 }
 
 /**
- * Process the --bootstrap-to-first-arg option, if it is present. 
+ * Process the --bootstrap-to-first-arg option, if it is present.
  *
  * This option checks to see if the first user-provided argument is an alias
- * or site specification; if it is, it will be shifted into the first arguement
+ * or site specification; if it is, it will be shifted into the first argument
  * position, where it will specify the site to bootstrap. The result of this
  * is that if your shebang line looks like this:
  *
@@ -192,10 +591,10 @@ function drush_process_bootstrap_to_first_arg(&$arguments) {
       $shifted_alias = $arguments[$shift_alias_pos];
       $alias_record = drush_sitealias_get_record($shifted_alias);
       if (!empty($alias_record)) {
-	// Move the alias we shifted from its current position
-	// in the argument list to the front of the list
-	array_splice($arguments, $shift_alias_pos, 1);
-	array_unshift($arguments, $shifted_alias);
+        // Move the alias we shifted from its current position
+        // in the argument list to the front of the list
+        array_splice($arguments, $shift_alias_pos, 1);
+        array_unshift($arguments, $shifted_alias);
       }
     }
   }
@@ -219,18 +618,22 @@ function drush_get_commands() {
       foreach ((array)$result as $key => $command) {
         // Add some defaults and normalize the command descriptor
         $command += drush_command_defaults($key, $commandfile, $path);
-        // If command callback is correctly named, then fix
-        // up the command entry so that drush_invoke will be
-        // called.
+        // Translate command.
+        drush_command_translate($command);
+        // If command callback function name begins with "drush_$commandfile_",
+        // then fix up the command entry so that drush_invoke will be
+        // called by way of drush_command.  This will cause all
+        // of the applicable hook functions to be called for the
+        // command when it is invoked.  If the callback function does
+        // -not- begin with its commandfile name, then it will be
+        // called directly by drush_dispatch, and no hook functions
+        // will be called (e.g. you cannot hook drush_print_file).
         if ($command['callback'] != 'drush_command') {
           $required_command_prefix = 'drush_' . $commandfile . '_';
           if ((substr($command['callback'], 0, strlen($required_command_prefix)) == $required_command_prefix)) {
             $command['command-hook'] = substr($command['callback'], strlen('drush_'));
             $command['callback'] = 'drush_command';
           }
-          else {
-            $command['callback-required-prefix'] = $required_command_prefix;
-          }
         }
 
         $commands[$key] = $command;
@@ -264,6 +667,7 @@ function drush_command_defaults($key, $commandfile, $path) {
     'command' => $key,
     'command-hook' => $key,
     'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
+    'callback arguments' => array(),
     'commandfile' => $commandfile,
     'path' => dirname($path),
     'engines' => array(), // Helpful for drush_show_help().
@@ -289,6 +693,32 @@ function drush_command_defaults($key, $commandfile, $path) {
   );
 }
 
+/**
+ * Translates description and other keys of a command definition.
+ *
+ * @param $command
+ *   A command definition.
+ */
+function drush_command_translate(&$command) {
+  $command['description'] = _drush_command_translate($command['description']);
+  $keys = array('arguments', 'options', 'examples', 'engines', 'sections');
+  foreach ($keys as $key) {
+    foreach ($command[$key] as $k => $v) {
+      $command[$key][$k] = _drush_command_translate($v);
+    }
+  }
+}
+
+/**
+ * Helper function for drush_command_translate().
+ *
+ * @param $source
+ *   String or array.
+ */
+function _drush_command_translate($source) {
+  return is_array($source)?call_user_func_array('dt', $source):dt($source);
+}
+
 /**
  * Matches a commands array, as returned by drush_get_arguments, with the
  * current command table.
@@ -298,13 +728,7 @@ function drush_command_defaults($key, $commandfile, $path) {
  * not available until after bootstrapping.
  *
  * drush_parse_command returns a normalized command descriptor, which
- * is an associative array with the following entries:
- * - callback: name of function to invoke for this command.  The callback
- *     function name _must_ begin with "drush_commandfile_", where commandfile
- *     is from the file "commandfile.drush.inc", which contains the
- *     commandfile_drush_command() function that returned this command.
- *     Note that the callback entry is optional; it is preferable to
- *     omit it, in which case drush_invoke() will generate the hook function name.
+ * is an associative array. Some of its entries are:
  * - callback arguments: an array of arguments to pass to the calback.
  * - description: description of the command.
  * - arguments: an array of arguments that are understood by the command. for help texts.
@@ -314,10 +738,7 @@ function drush_command_defaults($key, $commandfile, $path) {
  * - bootstrap: drupal bootstrap level (depends on Drupal major version). -1=no_bootstrap.
  * - core: Drupal major version required.
  * - drupal dependencies: drupal modules required for this command.
- * - drush dependencies: other drush command files required for this command (not yet implemented)
- *
- * @example
- *   drush_parse_command();
+ * - drush dependencies: other drush command files required for this command.
  *
  */
 function drush_parse_command() {
@@ -340,154 +761,26 @@ function drush_parse_command() {
       $command['arguments'] = $arguments;
     }
     else {
-      // 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);
-      }
+      _drush_prepare_command($command, $arguments);
     }
-    $command['arguments'] = $arguments;
     drush_set_command($command);
   }
   return $command;
 }
 
-/**
- * Invoke drush api calls.
- *
- * Call the correct hook for all the modules that implement it.
- * Additionally, the ability to rollback when an error has been encountered is also provided.
- * If at any point during execution, the drush_get_error() function returns anything but 0,
- * drush_invoke() will trigger $hook_rollback for each of the hooks that implement it,
- * in reverse order from how they were executed.
- *
- * This function will also trigger pre_$hook and post_$hook variants of the hook
- * and its rollbacks automatically.
- *
- * HOW DRUSH HOOK FUNCTIONS ARE NAMED:
- *
- * The name of the hook is composed from the name of the command and the name of
- * the command file that the command definition is declared in.  The general
- * form for the hook filename is:
- *
- *      drush_COMMANDFILE_COMMANDNAME
- *
- * In many cases, drush commands that are functionally part of a common collection
- * of similar commands will all be declared in the same file, and every command
- * defined in that file will start with the same command prefix.  For example, the
- * command file "pm.drush.inc" defines commands such as "pm-enable" and "pm-disable".
- * In the case of "pm-enable", the command file is "pm", and and command name is
- * "pm-enable".  When the command name starts with the same sequence of characters
- * as the command file, then the repeated sequence is dropped; thus, the command
- * hook for "pm-enable" is "drush_pm_enable", not "drush_pm_pm_enable".
- *
- * @param command
- *   The drush command to execute.
- * @return
- *   A boolean specifying whether or not the command was successfully completed.
- *
+/*
+ * Called by drush_parse_command.  If a command is dispatched
+ * directly by drush_dispatch, then drush_dispatch will call
+ * this function.
  */
-function drush_invoke($command) {
-  drush_command_include($command);
-  $args = func_get_args();
-  array_shift($args);
-
-  // Generate the base name for the hook by converting all
-  // dashes in the command name to underscores.
-  $hook = str_replace("-", "_", $command);
-
-  // Call the hook init function, if it exists.
-  // If a command needs to bootstrap, it is advisable
-  // to do so in _init; otherwise, new commandfiles
-  // will miss out on participating in any stage that
-  // has passed or started at the time it was discovered.
-  $func = 'drush_' . $hook . '_init';
-  if (function_exists($func)) {
-    drush_log(dt("Calling drush command init function: !func", array('!func' => $func)), 'bootstrap');
-    call_user_func_array($func, $args);
-    _drush_log_drupal_messages();
-    if (drush_get_error()) {
-      drush_log(dt('The command @command could not be initialized.', array('@command' => $command)), 'error');
-      return FALSE;
-    }
-  }
-
-  $rollback = FALSE;
-  $completed = array();
-  $available_rollbacks = array();
-  $all_available_hooks = array();
-
-  // Iterate through the different hook variations
-  $variations = array($hook . "_validate", "pre_$hook", $hook, "post_$hook");
-  foreach ($variations as $var_hook) {
-    // Get the list of command files.
-    // We re-fetch the list every time through
-    // the loop in case one of the hook function
-    // does something that will add additional
-    // commandfiles to the list (i.e. bootstrapping
-    // to a higher phase will do this).
-    $list = drush_commandfile_list();
-
-    $functions = array();
-
-    // Run all of the functions available for this variation
-    foreach ($list as $commandfile => $filename) {
-      $oldfunc = sprintf("drush_%s_%s", $commandfile, $var_hook);
-      $func = str_replace('drush_' . $commandfile . '_' . $commandfile, 'drush_' . $commandfile, $oldfunc);
-      if (($oldfunc != $func) && (function_exists($oldfunc))) {
-        drush_log(dt("The drush command hook naming conventions have changed; the function !oldfunc must be renamed to !func.  The old function will be called, but this will be removed shortly.", array('!oldfunc' => $oldfunc, '!func' => $func)), "error");
-        // TEMPORARY:  Allow the function to be called by its old name.
-        $functions[] = $oldfunc;
-      }
-      if (function_exists($func)) {
-        $functions[] = $func;
-        $all_available_hooks[] = $func . ' [*]';
-        $available_rollbacks[] = $func . '_rollback';
-        $completed[] = $func;
-        call_user_func_array($func, $args);
-        _drush_log_drupal_messages();
-        if (drush_get_error()) {
-          drush_log(dt('An error occurred at function : @func', array('@func' => $func)), 'error');
-          $rollback = TRUE;
-
-          // break out of the foreach variations and foreach list
-          break 2;
-        }
-      }
-      else {
-        $all_available_hooks[] = $func;
-      }
-    }
+function _drush_prepare_command(&$command, $arguments = array()) {
+  // 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);
   }
-
-  // If no hook functions were found, print a warning.
-  if (empty($all_available_hooks)) {
-    drush_log(dt("No hook functions were found for !command.", array('!command' => $command)), 'warning');
-    drush_log(dt("Available drush_invoke() hooks for !command: !available", array('!command' => $command, '!available' => "\n" . implode("\n", $all_available_hooks))), 'warning');
-  }
-  elseif (drush_get_option('show-invoke')) {
-    // We show all available hooks up to and including the one that failed (or all, if there were no failures)
-    drush_log(dt("Available drush_invoke() hooks for !command: !available", array('!command' => $command, '!available' => "\n" . implode("\n", $all_available_hooks))), 'internals');
-  }
-  if (drush_get_option('show-invoke')) {
-    drush_log(dt("Available rollback hooks for !command: !rollback", array('!command' => $command, '!rollback' => "\n" . implode("\n", $available_rollbacks))), 'internals');
-  }
-
-  // something went wrong, we need to undo
-  if ($rollback) {
-    foreach (array_reverse($completed) as $func) {
-      $rb_func = $func . '_rollback';
-      if (function_exists($rb_func)) {
-        call_user_func_array($rb_func, $args);
-        _drush_log_drupal_messages();
-        drush_log("Changes for $func module have been rolled back.", 'rollback');
-      }
-    }
-  }
-
-  return !$rollback;
+  $command['arguments'] = $arguments;
 }
 
-
 /**
  * Entry point for commands into the drush_invoke API
  *
@@ -510,7 +803,7 @@ function drush_command() {
   }
 
   if (!drush_get_error()) {
-    call_user_func_array('drush_invoke', array_merge(array($command['command-hook']), $args));
+    _drush_invoke_args($command['command-hook'], $args, $command['commandfile']);
   }
 
   if (!drush_get_error()) {
@@ -630,15 +923,10 @@ function drush_commandfile_list() {
 }
 
 function _drush_find_commandfiles($phase, $phase_max = FALSE) {
-  $cache =& drush_get_context('DRUSH_COMMAND_FILES', array());
-
   if (!$phase_max) {
     $phase_max = $phase;
   }
 
-  static $evaluated = array();
-  static $deferred = array();
-
   $searchpath = array();
   switch ($phase) {
     case DRUSH_BOOTSTRAP_DRUSH:
@@ -680,6 +968,18 @@ function _drush_find_commandfiles($phase, $phase_max = FALSE) {
         // Add all module paths, even disabled modules. Prefer speed over accuracy.
         $searchpath[] = 'sites/all/modules';
       }
+      $searchpath[] = 'sites/all/themes';
+      $searchpath[] = conf_path() . '/themes';
+      break;
+    case DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION:
+      // See comment above  regarding this if() condition.
+      if ($phase_max < DRUSH_BOOTSTRAP_DRUPAL_FULL) {
+        // You must define your install_profile in settings.php. The DB is not sufficient.
+        // Drupal core does not yet do that. See http://drupal.org/node/545452.
+        if ($profile = variable_get('install_profile', NULL)) {
+          $searchpath[] = "profiles/$profile/modules";
+        }
+      }
       break;
     case DRUSH_BOOTSTRAP_DRUPAL_FULL:
       // Add enabled module paths. Since we are bootstrapped,
@@ -691,6 +991,15 @@ function _drush_find_commandfiles($phase, $phase_max = FALSE) {
       break;
   }
 
+  _drush_add_commandfiles($searchpath, $phase);
+}
+
+function _drush_add_commandfiles($searchpath, $phase = NULL) {
+  $cache =& drush_get_context('DRUSH_COMMAND_FILES', array());
+
+  static $evaluated = array();
+  static $deferred = array();
+
   if (sizeof($searchpath)) {
     // Build a list of all of the modules to attempt to load.
     // Start with any modules deferred from a previous phase.
@@ -699,7 +1008,7 @@ function _drush_find_commandfiles($phase, $phase_max = FALSE) {
     // Scan for drush command files; add to list for consideration if found.
     foreach (array_unique($searchpath) as $path) {
       if (is_dir($path)) {
-        $files = drush_scan_directory($path, '/\.drush\.inc$/');
+        $files = drush_scan_directory($path, '/\.drush\.inc$/', array('.', '..', 'examples'));
         foreach ($files as $filename => $info) {
           $module = basename($filename, '.drush.inc');
           // Only try to bootstrap modules that we have never seen before, or that we
@@ -758,6 +1067,15 @@ function _drush_find_commandfiles($phase, $phase_max = FALSE) {
  * are present in each of the commandfile directories.
  */
 function drush_command_include($command) {
+  $include_files = drush_command_get_includes($command);
+  foreach($include_files as $filename => $commandfile) {
+    drush_log(dt('Including !filename', array('!filename' => $filename)), 'bootstrap');
+    include_once($filename);
+  }
+}
+
+function drush_command_get_includes($command) {
+  $include_files = array();
   $parts = explode('-', $command);
   $command = implode(".", array_reverse($parts));
 
@@ -766,10 +1084,10 @@ function drush_command_include($command) {
   foreach ($commandfiles as $commandfile => $file) {
     $filename = sprintf("%s/%s.inc", dirname($file), $command);
     if (file_exists($filename)) {
-      drush_log(dt('Including !filename', array('!filename' => $filename)), 'bootstrap');
-      include_once($filename);
+      $include_files[$filename] = $commandfile;
     }
   }
+  return $include_files;
 }
 
 /**
@@ -791,15 +1109,6 @@ function drush_command_default_options($command = NULL) {
         }
       }
     }
-    // Take the time here to clear out any options that may
-    // have "--no-xxx" overrides on the command line.
-    $commandline_options = drush_get_context('options');
-    foreach ($commandline_options as $key => $value) {
-      if (substr($key, 0, strlen("no-") ) == "no-") {
-        drush_unset_option(substr($key, strlen("no-")));
-        $options_were_set = TRUE;
-      }
-    }
     // If we set or cleared any options, go back and re-bootstrap any global
     // options such as -y and -v.
     if ($options_were_set) {
@@ -814,10 +1123,12 @@ function _drush_command_set_default_options($command) {
   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
-      // that is higher precidence than the various config file
+      // that is higher precedence than the various config file
       // context, but lower than command-line options.
-      drush_set_option($key, $value, 'specific');
-      $options_were_set = TRUE;
+      if (!drush_get_option('no-' . $key, FALSE)) {
+        drush_set_option($key, $value, 'specific');
+        $options_were_set = TRUE;
+      }
     }
   }
   return $options_were_set;
@@ -882,7 +1193,7 @@ function drush_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $c
   $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
   $files = array();
 
-  if (is_dir($dir) && $handle = opendir($dir)) {
+  if (is_string($dir) && is_dir($dir) && $handle = opendir($dir)) {
     while (FALSE !== ($file = readdir($handle))) {
       if (!in_array($file, $nomask) && (($include_dot_files && (!preg_match("/\.\+/",$file))) || ($file[0] != '.'))) {
         if (is_dir("$dir/$file") && (($recurse_max_depth === TRUE) || ($depth < $recurse_max_depth))) {
@@ -899,7 +1210,7 @@ function drush_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $c
           $files[$$key]->basename = $basename;
           $files[$$key]->name = $name;
           if ($callback) {
-            $callback($filename);
+            drush_op($callback, $filename);
           }
         }
       }
@@ -942,21 +1253,61 @@ function drush_enforce_requirement_bootstrap_phase(&$command) {
  *   TRUE if command is valid.
  */
 function drush_enforce_requirement_drupal_dependencies(&$command) {
-  if (empty($command['drupal dependencies'])) {
-    return TRUE;
+  // If the command bootstrap is DRUSH_BOOTSTRAP_MAX, then we will
+  // allow the requirements to pass if we have not successfully
+  // bootstrapped Drupal.  The combination of DRUSH_BOOTSTRAP_MAX
+  // and 'drupal dependencies' indicates that the drush command
+  // will use the dependent modules only if they are available.
+  if ($command['bootstrap'] == DRUSH_BOOTSTRAP_MAX) {
+    // If we have not bootstrapped, then let the dependencies pass;
+    // if we have bootstrapped, then enforce them.
+    if (drush_get_context('DRUSH_BOOTSTRAP_PHASE') < DRUSH_BOOTSTRAP_DRUPAL_FULL) {
+      return TRUE;
+    }
   }
-  else {
+  // If there are no drupal dependencies, then do nothing
+  if (!empty($command['drupal dependencies'])) {
     foreach ($command['drupal dependencies'] as $dependency) {
-      if (function_exists('module_exists') && module_exists($dependency)) {
-        return TRUE;
+      if(!function_exists('module_exists') || !module_exists($dependency)) {
+        $command['bootstrap_errors']['DRUSH_COMMAND_DEPENDENCY_ERROR'] = dt('Command !command needs the following modules installed/enabled to run: !dependencies.', array('!command' => $command['command'], '!dependencies' => implode(', ', $command['drupal dependencies'])));
+        return FALSE;
+      }
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Check that a command has its declared drush dependencies available or have no
+ * dependencies. Drush dependencies are helpful when a command is invoking
+ * another command, or implementing its API.
+ *
+ * @param $command
+ *   Command to check. Any errors  will be added to the 'bootstrap_errors' element.
+ * @return
+ *   TRUE if dependencies are met.
+ */
+function drush_enforce_requirement_drush_dependencies(&$command) {
+  // If there are no drush dependencies, then do nothing.
+  if (!empty($command['drush dependencies'])) {
+    $commandfiles = drush_commandfile_list();
+    foreach ($command['drush dependencies'] as $dependency) {
+      if (!isset($commandfiles[$dependency])) {
+        $dt_args = array(
+          '!command' => $command['command'],
+          '!dependency' => "$dependency.drush.inc",
+        );
+        $command['bootstrap_errors']['DRUSH_COMMAND_DEPENDENCY_ERROR'] = dt('Command !command needs the following drush command file to run: !dependency.', $dt_args);
+        return FALSE;
       }
     }
   }
-  $command['bootstrap_errors']['DRUSH_COMMAND_DEPENDENCY_ERROR'] = dt('Command !command needs the following modules installed/enabled to run: !dependencies.', array('!command' => $command['command'], '!dependencies' => implode(', ', $command['drupal dependencies'])));
+  return TRUE;
 }
 
 /**
- * Check that a command is valid for the current major version of core.
+ * Check that a command is valid for the current major version of core. Handles
+ * explicit version numbers and 'plus' numbers like 6+ (compatible with 6, 7 ...).
  *
  * @param $command
  *   Command to check. Any errors  will be added to the 'bootstrap_errors' element.
@@ -965,10 +1316,18 @@ function drush_enforce_requirement_drupal_dependencies(&$command) {
  *   TRUE if command is valid.
  */
 function drush_enforce_requirement_core(&$command) {
-  $core = $command['core'];
-  if (empty($core) || in_array(drush_drupal_major_version(), $core)) {
+  $major = drush_drupal_major_version();
+  if (!$core = $command['core']) {
     return TRUE;
   }
+  foreach ($core as $compat) {
+    if ($compat == $major) {
+      return TRUE;
+    }
+    elseif (substr($compat, -1) == '+' && $major >= substr($compat, 0, strlen($compat)-1)) {
+      return TRUE;
+    }
+  }
   $versions = array_pop($core);
   if (!empty($core)) {
     $versions = implode(', ', $core) . dt(' or ') . $versions;
diff --git a/sites/all/modules/drush/includes/context.inc b/sites/all/modules/drush/includes/context.inc
index 2a2fc05f1398225bd199f3205db032be509039e2..06daa73ec8d60f6fa88f854d1ac74822e8b8ee2e 100644
--- a/sites/all/modules/drush/includes/context.inc
+++ b/sites/all/modules/drush/includes/context.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: context.inc,v 1.35 2010/11/08 05:31:22 greg1anderson Exp $
 /**
  * @file
  * The Drush context API implementation.
@@ -53,12 +52,12 @@
  *
  *   Specified by the script itself :
  *     process  : Generated in the current process.
- *     options  : Passed as --option=value to the command line.
+ *     cli      : Passed as --option=value to the command line.
  *     stdin    : Passed as a JSON encoded string through stdin.
- *     alias    : Defined in an alias record, and set in the
- *                alias context whenever that alias is used.
  *     specific : Defined in a command-specific option record, and
  *                set in the command context whenever that command is used.
+ *     alias    : Defined in an alias record, and set in the
+ *                alias context whenever that alias is used.
  *
  *   Specified by config files :
  *     custom   : Loaded from the config file specified by --config or -c
@@ -74,7 +73,7 @@
  */
 function drush_context_names() {
   static $contexts = array(
-    'process', 'options', 'stdin', 'alias', 'specific',
+    'process', 'cli', 'stdin', 'specific', 'alias',
     'custom', 'site', 'drupal', 'user', 'home.drush', 'system',
     'drush', 'default');
 
@@ -84,13 +83,19 @@ function drush_context_names() {
 /**
  * Return a list of possible drushrc file locations.
  *
+ * @context
+ *   A valid drush context from drush_context_names().
+ * @prefix
+ *   Optional. Specify a prefix to prepend to ".drushrc.php" when looking
+ *   for config files. Most likely used by contrib commands.
  * @return
  *   An associative array containing possible config files to load
  *   The keys are the 'context' of the files, the values are the file
  *   system locations.
  */
-function _drush_config_file($context) {
+function _drush_config_file($context, $prefix = NULL) {
   $configs = array();
+  $config_file = $prefix ? $prefix . '.' . 'drushrc.php' : 'drushrc.php';
 
   // Did the user explicitly specify a config file?
   if ($config = drush_get_option(array('c', 'config'))) {
@@ -101,28 +106,28 @@ function _drush_config_file($context) {
   }
 
   if ($site_path = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
-    $configs['site'] = $site_path . "/drushrc.php";
+    $configs['site'] = $site_path . "/" . $config_file;
   }
 
   if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
-    $configs['drupal'] = $drupal_root . '/drushrc.php';
+    $configs['drupal'] = $drupal_root . '/' . $config_file;
   }
 
   // in the user home directory
   if (!is_null(drush_server_home())) {
-    $configs['user'] = drush_server_home() . '/.drushrc.php';
+    $configs['user'] = drush_server_home() . '/.' . $config_file;
   }
 
   // in $HOME/.drush directory
   if (!is_null(drush_server_home())) {
-    $configs['home.drush'] = drush_server_home() . '/.drush/drushrc.php';
+    $configs['home.drush'] = drush_server_home() . '/.drush/' . $config_file;
   }
 
   // In the system wide configuration folder.
-  $configs['system'] = drush_get_context('ETC_PREFIX', '') . '/etc/drush/drushrc.php';
+  $configs['system'] = drush_get_context('ETC_PREFIX', '') . '/etc/drush/' . $config_file;
 
   // in the drush installation folder
-  $configs['drush'] = dirname(__FILE__) . '/../drushrc.php';
+  $configs['drush'] = dirname(__FILE__) . '/../' . $config_file;
 
   return empty($configs[$context]) ? '' : $configs[$context];
 }
@@ -291,7 +296,7 @@ function drush_set_context($context, $value) {
  *   Otherwise only the requested context will be returned.
  *   If the context does not exist yet, it will be initialized to an empty array.
  */
-function &drush_get_context($context = null, $default = null) {
+function &drush_get_context($context = NULL, $default = NULL) {
   static $cache = array();
   if (!is_null($context)) {
     if (!isset($cache[$context])) {
@@ -309,8 +314,8 @@ function &drush_get_context($context = null, $default = null) {
  * This function will set the 'arguments' context of the current running script.
  *
  * When initially called by drush_parse_args, the entire list of arguments will
- * be populated, once the command is dispatched, this will be set to only the remaining
- * arguments to the command.
+ * be populated. Once the command is dispatched, this will be set to only the remaining
+ * arguments to the command (i.e. the command name is removed).
  *
  * @param arguments
  *   Command line arguments, as an array.
@@ -368,7 +373,7 @@ function drush_get_command() {
  *   Optional. The context to check for the option. If this is set, only this context will be searched.
  */
 function drush_get_option($option, $default = NULL, $context = NULL) {
-  $value = null;
+  $value = NULL;
 
   if ($context) {
     // We have a definite context to check for the presence of an option.
@@ -381,13 +386,13 @@ function drush_get_option($option, $default = NULL, $context = NULL) {
     foreach ($contexts as $context) {
       $value = _drush_get_option($option, drush_get_context($context));
 
-      if ($value !== null) {
+      if ($value !== NULL) {
         return $value;
       }
     }
   }
 
-  if ($value !== null) {
+  if ($value !== NULL) {
     return $value;
   }
 
@@ -395,7 +400,7 @@ function drush_get_option($option, $default = NULL, $context = NULL) {
 }
 
 /**
- * Get the value for an option and return it as a list.  If the 
+ * Get the value for an option and return it as a list.  If the
  * option in question is passed on the command line, its value should
  * be a comma-separated list (e.g. --flag=1,2,3).  If the option
  * was set in a drushrc.php file, then its value may be either a
@@ -410,11 +415,11 @@ function drush_get_option($option, $default = NULL, $context = NULL) {
  */
 function drush_get_option_list($option, $default = array(), $context = NULL) {
   $result = drush_get_option($option, $default, $context);
-  
+
   if (!is_array($result)) {
     $result = explode(',', $result);
   }
-  
+
   return $result;
 }
 
@@ -459,7 +464,7 @@ function drush_get_context_options($option, $flatten = FALSE) {
   foreach ($contexts as $context) {
     $value = _drush_get_option($option, drush_get_context($context));
 
-    if ($value !== null) {
+    if ($value !== NULL) {
       if ($flatten && is_array($value)) {
         $result = array_merge($value, $result);
       }
@@ -503,7 +508,7 @@ function _drush_get_option($option, $context) {
     return $context[$option];
   }
 
-  return null;
+  return NULL;
 }
 
 /**
@@ -584,9 +589,9 @@ function drush_save_config($context) {
       fwrite($fp, "\n");
       fclose($fp);
       drush_log(dt('Drushrc file (!filename) was written successfully', array('!filename' => $filename)));
-      return true;
+      return TRUE;
     }
 
   }
-  return false;
+  return FALSE;
 }
diff --git a/sites/all/modules/drush/includes/drush.inc b/sites/all/modules/drush/includes/drush.inc
index a087265d93633dc1ef2e9ba2bac3939dbd1dd65a..ce9ca7fa854a62195bf0d14ea146f91dd58656cb 100644
--- a/sites/all/modules/drush/includes/drush.inc
+++ b/sites/all/modules/drush/includes/drush.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: drush.inc,v 1.151 2010/12/01 21:02:21 jonhattan Exp $
 
 /**
  * @file
@@ -11,48 +10,6 @@
  */
 define('DRUSH_DRUPAL_KILOBYTE', 1024);
 
-
-/**
- * Dispatch a given set of commands.
- * Modules can add commands by implementing hook_drush_command().
- *
- * @param
- *   Command whose callback you want to call, defaults to current command.
- */
-function drush_dispatch($command = NULL) {
-  $command = ($command) ? $command : drush_get_command();
-  $return = FALSE;
-
-  if ($command) {
-    // Add command-specific options, if applicable
-    drush_command_default_options($command);
-
-    // Print a warning if someone tries to use a deprecated alias.
-    if (isset($command['deprecated'])) {
-      drush_log(dt('Warning: The command name "!deprecated" is deprecated.  Please use a recommended form instead (!recommended).', array('!deprecated' => $command['deprecated-name'], '!recommended' => implode(',', array_merge(array($command['command']), $command['aliases'])))), 'warning');
-    }
-    // Print a warning if a command callback function is misnamed
-    if (isset($command['callback-required-prefix'])) {
-      drush_log(dt('Warning: The command callback function !callback has a deprecated name.  It must begin with !requiredprefix.  Skipping hook functions.', array('!callback' => $command['callback'], '!requiredprefix' => $command['callback-required-prefix'])));
-    }
-    // Call the callback function of the active command.
-    // TODO:  If we make the required prefix actually required rather than just emitting a
-    // warning, then this could become a direct call to drush_command (all commands with
-    // the required prefix will now go through drush_command + drush_invoke).
-    $return = call_user_func_array($command['callback'], $command['arguments']);
-  }
-
-  // prevent a '1' at the end of the output
-  if ($return === TRUE) {
-    $return = '';
-  }
-
-  // Add a final log entry, just so a timestamp appears.
-  drush_log(dt('Command dispatch complete'), 'notice');
-
-  return $return;
-}
-
 /**
  * Include a file, selecting a version specific file if available.
  *
@@ -175,7 +132,7 @@ function drush_include_engine($type, $engine, $version = NULL, $path = NULL) {
     $path = $engines[$engine]['path'];
   }
   if (!$path) {
-    return drush_set_error('DRUSH_ENGINE INCLUDE_NO_PATH', dt('No !path was set for including the !type engine !engine.', array('!path' => $path, '!type' => $type, '!engine' => $engine)));
+    return drush_set_error('DRUSH_ENGINE INCLUDE_NO_PATH', dt('No path was set for including the !type engine !engine.', array('!type' => $type, '!engine' => $engine)));
   }
   if (drush_include($path, $engine, $version)) {
     return TRUE;
@@ -213,6 +170,121 @@ function drush_drupal_version($drupal_root = NULL) {
   return $version;
 }
 
+/**
+ * Check to see if a newer version of drush is available
+ *
+ * @return
+ *   TRUE - A new version is available.
+ *   FALSE - Error.
+ *   NULL - No release available.
+ */
+function drush_check_self_update() {
+  $error = "";
+
+  // Don't check unless we have a datestamp in drush.info
+  $drush_info = drush_read_drush_info();
+  if (($drush_info === FALSE) || (!array_key_exists('datestamp', $drush_info))) {
+    drush_log(dt('Cannot determine release date for drush'), 'notice');
+    return FALSE;
+  }
+
+  // Allow updates to the latest HEAD release if --self-update=head is specified.
+  // If we are called from `drush self-update`, then --dev will set --self-update=head.
+  $dev_ok = (drush_get_option('self-update') == 'head');
+  $is_dev = FALSE;
+
+  // Get release info for drush
+  $info = _drush_pm_get_releases(array('drush'));
+  // Check for newer releases based on the datestamp.
+  // We add 60 seconds to the drush.info date because of a drupal.org WTF. See http://drupal.org/node/1019356.
+  $version_date = $drush_info['datestamp'] + 60;
+  $newer_version = FALSE;
+  foreach ($info['drush']['releases'] as $version => $release_info) {
+    // We deliberately skip any dev releases unless the current release is a dev release.
+    if ($dev_ok || ((!array_key_exists('version_extra', $release_info) || ($release_info['version_extra'] != 'dev')))) {
+      if ($release_info['date'] > $version_date) {
+        $newer_version = $release_info['version'];
+        $version_date = $release_info['date'];
+        $is_dev = isset($release_info['version_extra']) && $release_info['version_extra'] == 'dev';
+        if ($is_dev) {
+          $newer_version .= " (" . date('Y-M-d', $version_date) . ")";
+        }
+      }
+    }
+  }
+
+  if ($newer_version) {
+    drush_print(dt('A newer version of drush, !version, is available.  You are currently running drush version !currentversion; to update, run `drush self-update`.  To disable this check, put "$options[\'self-update\'] = FALSE;" in your drushrc.php configuration file.' . "\n", array('!version' => $newer_version, '!currentversion' => DRUSH_VERSION)));
+    return TRUE;
+  }
+  else {
+    drush_log(dt("drush self-update check: drush !version is up-to-date.", array('!version' => DRUSH_VERSION)), 'notice');
+  }
+
+  return NULL;
+}
+
+/**
+ * Generate an .ini file. used by archive-dump."
+ *
+ * @param array $ini
+ *   A two dimensional associative array where top level are sections and
+ *   second level are key => value pairs.
+ *
+ * @return string
+ *   .ini formatted text.
+ */
+function drush_export_ini($ini) {
+  $output = '';
+  foreach ($ini as $section => $pairs) {
+    if ($section) {
+      $output .= "[$section]\n";
+    }
+
+    foreach ($pairs as $k => $v) {
+      if ($v) {
+        $output .= "$k = \"$v\"\n";
+      }
+    }
+  }
+  return $output;
+}
+
+/**
+ * Generate code friendly to the Drupal .info format from a structured array.
+ * Mostly copied from http://drupalcode.org/viewvc/drupal/contributions/modules/features/features.export.inc.
+ *
+ * @param $info
+ *   An array or single value to put in a module's .info file.
+ *
+ * @param boolean $integer_keys
+ *   Use integer in keys.
+ *
+ * @param $parents
+ *   Array of parent keys (internal use only).
+ *
+ * @return
+ *   A code string ready to be written to a module's .info file.
+ */
+function drush_export_info($info, $integer_keys = FALSE, $parents = array()) {
+  $output = '';
+  if (is_array($info)) {
+    foreach ($info as $k => $v) {
+      $child = $parents;
+      $child[] = $k;
+      $output .= drush_export_info($v, $integer_keys, $child);
+    }
+  }
+  else if (!empty($info) && count($parents)) {
+    $line = array_shift($parents);
+    foreach ($parents as $key) {
+      $line .= (!$integer_keys && is_numeric($key)) ? "[]" : "[{$key}]";
+    }
+    $line .=  " = \"{$info}\"\n";
+    return $line;
+  }
+  return $output;
+}
 
 function drush_drupal_cache_clear_all() {
   $prior = drush_get_context('DRUSH_AFFIRMATIVE');
@@ -236,809 +308,604 @@ function drush_drupal_major_version($drupal_root = NULL) {
 }
 
 /**
- * Replace named placeholders in a WHERE snippet.
- *
- * Helper function to allow the usage of Drupal 7 WHERE snippets
- * with named placeholders in code for Drupal 5 and 6.
+ * Convert a csv string, or an array of items which
+ * may contain csv strings, into an array of items.
  *
- * @param $where
- *   String with a WHERE snippet using named placeholders.
  * @param $args
- *   Array of placeholder values.
+ *   A simple csv string; e.g. 'a,b,c'
+ *   or a simple list of items; e.g. array('a','b','c')
+ *   or some combination; e.g. array('a,b','c') or array('a,','b,','c,')
+ *
+ * @returns array
+ *   A simple list of items (e.g. array('a','b','c')
+ */
+function _convert_csv_to_array($args) {
+  //
+  // Step 1: implode(',',$args) converts from, say, array('a,','b,','c,') to 'a,,b,,c,'
+  // Step 2: explode(',', ...) converts to array('a','','b','','c','')
+  // Step 3: array_filter(...) removes the empty items
+  //
+  return array_filter(explode(',', is_array($args) ? implode(',',$args) : $args));
+}
+
+/**
+ * Get the available global options. Used by help command. Command files may
+ * modify this list using hook_drush_help_alter().
+ *
+ * @param boolean $brief
+ *   Return a reduced set of important options. Used by help command.
+ *
  * @return
- *   String. $where filled with literals from $args.
+ *   An associative array containing the option definition as the key, and the description as the value,
+ *   for each of the available options.
  */
-function _drush_replace_query_placeholders($where, $args) {
-  foreach ($args as $key => $data) {
-    if (is_array($data)) {
-      $new_keys = array();
-      // $data can't have keys that are a prefix of other keys to
-      // prevent a corrupted result in the below calls to str_replace().
-      // To avoid this we will use a zero padded indexed array of the values of $data.
-      $pad_length = strlen((string)count(array_values($data)));
-      foreach (array_values($data) as $i => $value) {
-        if (!is_numeric($value)) {
-          $value = "'".$value."'";
-        }
-        $new_keys[$key . '_' . str_pad($i, $pad_length, '0', STR_PAD_LEFT)] = $value;
-      }
-      $where = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $where);
-      unset($args[$key]);
-      $args += $new_keys;
-    }
-    else if (!is_numeric($data)) {
-      $args[$key] = "'".$data."'";
-    }
+function drush_get_global_options($brief = FALSE) {
+  $options['root']               = array('short-form' => 'r', 'description' => dt("Drupal root directory to use (default: current directory)"), 'example-value' => '<path>');
+  $options['uri']                = array('short-form' => 'l', 'description' => dt('URI of the drupal site to use (only needed in multisite environments or when running on an alternate port)'), 'example-value' => 'http://example.com:8888');
+  $options['verbose']            = array('short-form' => 'v', 'description' => dt('Display extra information about the command.'));
+  $options['debug']              = array('short-form' => 'd', 'description' => dt('Display even more information, including internal messages.'));
+  $options['yes']                = array('short-form' => 'y', 'description' => dt("Assume 'yes' as answer to all prompts"));
+  $options['no']                 = array('short-form' => 'n', 'description' => dt("Assume 'no' as answer to all prompts"));
+  $options['simulate']           = array('short-form' => 's', 'description' => dt("Simulate all relevant actions (don't actually change the system)"));
+  $options['pipe']               = array('short-form' => 'p', 'description' => dt("Emit a compact representation of the command for scripting."));
+  $options['help']               = array('short-form' => 'h', 'description' => dt("This help system."));
+  $options['version']            = dt("Show drush version.");
+  $options['php']                = dt("The absolute path to your PHP intepreter, if not 'php' in the path.");
+
+  if (!$brief) {
+    $options['quiet']            = array('short-form' => 'q', 'description' => dt('Hide all output'));
+    $options['include']          = array('short-form' => 'i', 'description' => dt("A list of paths to search for drush commands"));
+    $options['config']           = array('short-form' => 'c', 'description' => dt("Specify a config file to use. See example.drushrc.php"));
+    $options['user']             = array('short-form' => 'u', 'description' => dt("Specify a user to login with. May be a name or a number."));
+    $options['backend']          = array('short-form' => 'b', 'description' => dt("Hide all output and return structured data (internal use only)."));
+    $options['choice']           = dt("Provide an answer to a multiple-choice prompt.");
+    $options['no-label']         = dt("Remove the site label that drush includes in multi-site command output(e.g. `drush @site1,@site2 status`).");
+    $options['nocolor']          = dt("Suppress color highlighting on log messages.");
+    $options['show-passwords']   = dt("Show database passwords in commands that display connection information.");
+    $options['show-invoke']      = dt("Show all function names which could have been called for the current command. See drush_invoke().");
+    $options['watchdog']         = dt("Control logging of Drupal's watchdog() to drush log. Recognized values are 'log', 'print', 'disabled'. Defaults to log. 'print' shows calls to admin but does not add them to the log.");
   }
+  return $options;
+}
 
-  foreach ($args as $key => $data) {
-    $where = str_replace($key, $data, $where);
+/**
+ * Prints out help for a given command.
+ */
+function drush_show_help($commandstring) {
+  // First check and see if the command can already be found.
+  $commands = drush_get_commands();
+  if (!array_key_exists($commandstring, $commands)) {
+    // If the command cannot be found, then bootstrap so that
+    // additional commands will be brought in.
+    // For speed, only bootstrap up to DRUSH_BOOTSTRAP_DRUPAL_SITE.
+    drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
+    $commands = drush_get_commands();
+  }
+  if (array_key_exists($commandstring, $commands)) {
+    $command = $commands[$commandstring];
+    drush_print_help($command);
+    return TRUE;
   }
-
-  return $where;
+  return drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => $commandstring)));
 }
 
 /**
- * A db_select() that works for any version of Drupal.
+ * Print the help for a single command to the screen.
  *
- * @param $table
- *   String. The table to operate on.
- * @param $fields
- *   Array or string. Fields affected in this operation. Valid string values are '*' or a single column name.
- * @param $where
- *   String. WHERE snippet for the operation. It uses named placeholders. see @_drush_replace_query_placeholders()
- * @param $args
- *   Array. Arguments for the WHERE snippet.
- * @param $start
- *   Int. Value for OFFSET.
- * @param $length
- *   Int. Value for LIMIT.
- * @param $order_by_field
- *   String. Database column to order by.
- * @param $order_by_direction
- *   ('ASC', 'DESC'). Ordering direction.
- * @return
- *   A database resource.
+ * @param array $command
+ *   A fully loaded $command array.
  */
-function drush_db_select($table, $fields = '*', $where = NULL, $args = NULL, $start = NULL, $length = NULL, $order_by_field = NULL, $order_by_direction = 'ASC') {
-  if (drush_drupal_major_version() >= 7) {
-    if (!is_array($fields)) {
-      if ($fields == '*') {
-        $fields = array();
-      }
-      else {
-        $fields = array($fields);
-      }
-    }
-    $query = db_select($table, $table)
-      ->fields($table, $fields);
-    if (!empty($where)) {
-      $query = $query->where($where, $args);
-    }
-    if (!is_null($order_by_field)) {
-      $query = $query->orderBy($order_by_field, $order_by_direction);
-    }
-    if (!is_null($length)) {
-      $query = $query->range($start, $length);
+function drush_print_help($command) {
+  // Merge in engine specific help.
+  foreach ($command['engines'] as $type => $description) {
+    $all_engines = drush_get_engines($type);
+    foreach ($all_engines as $name => $engine) {
+      $command = array_merge_recursive($command, $engine);
     }
-    return $query->execute();
   }
-  else {
-    if (is_array($fields)) {
-      $fields = implode(', ', $fields);
-    }
-    $query = "SELECT $fields FROM {{$table}}";
-    if (!empty($where)) {
-      $where = _drush_replace_query_placeholders($where, $args);
-      $query .= " WHERE ".$where;
-    }
-    if (!is_null($order_by_field)) {
-      $query .= " ORDER BY $order_by_field $order_by_direction";
-    }
-    if (!is_null($length)) {
-      $limit = " LIMIT $length";
-      if (!is_null($start)) {
-        $limit .= " OFFSET $start";
-      }
-      $query .= $limit;
+
+  if (!$help = drush_command_invoke_all('drush_help', 'drush:'. $command['command'])) {
+    $help = array($command['description']);
+  }
+
+  // Give commandfiles an opportunity to add examples and options to the command.
+  drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
+  drush_command_invoke_all_ref('drush_help_alter', $command);
+
+  drush_print(wordwrap(implode("\n", $help), drush_get_context('DRUSH_COLUMNS', 80)));
+  drush_print();
+
+  foreach ($command['sections'] as $key => $value) {
+    if (!empty($command[$key])) {
+      drush_print(dt($value) . ':');
+      $rows = drush_format_help_section($command, $key);
+      drush_print_table($rows, FALSE, array(40));
+      unset($rows);
+      drush_print();
     }
+  }
 
-    return db_query($query, $args);
+  // Append aliases if any.
+  if ($command['aliases']) {
+    drush_print(dt("Aliases: ") . implode(', ', $command['aliases']));
   }
 }
 
 /**
- * A db_delete() that works for any version of Drupal.
+ * Format one named help section from a command record
  *
- * @param $table
- *   String. The table to operate on.
- * @param $where
- *   String. WHERE snippet for the operation. It uses named placeholders. see @_drush_replace_query_placeholders()
- * @param $args
- *   Array. Arguments for the WHERE snippet.
- * @return
- *   Affected rows (except on D7+mysql without a WHERE clause - returns TRUE) or FALSE.
+ * @param $command
+ *   A command record with help information
+ * @param $section
+ *   The name of the section to format ('options', 'topic', etc.)
+ * @returns array
+ *   Formatted rows, suitable for printing via drush_print_table.
  */
-function drush_db_delete($table, $where = NULL, $args = NULL) {
-  if (drush_drupal_major_version() >= 7) {
-    if (!empty($where)) {
-      $query = db_delete($table)->where($where, $args);
-      return $query->execute();
+function drush_format_help_section($command, $section) {
+  $formatter = (function_exists('drush_help_section_formatter_' . $section)) ? 'drush_help_section_formatter_' . $section : 'drush_help_section_default_formatter';
+  foreach ($command[$section] as $name => $help_attributes) {
+    if (!is_array($help_attributes)) {
+      $help_attributes = array('description' => $help_attributes);
     }
-    else {
-      return db_truncate($table)->execute();
+    $help_attributes['label'] = $name;
+    call_user_func_array($formatter, array($command, &$help_attributes));
+    $rows[] = array($help_attributes['label'], $help_attributes['description']);
+
+    // Process the subsections too, if any
+    if (!empty($command['sub-' . $section]) && array_key_exists($name, $command['sub-' . $section])) {
+      $rows = array_merge($rows, _drush_format_help_subsection($command, $section, $name, $formatter));
     }
   }
-  else {
-    $query = "DELETE FROM {{$table}}";
-    if (!empty($where)) {
-      $where = _drush_replace_query_placeholders($where, $args);
-      $query .= ' WHERE '.$where;
+  return $rows;
+}
+
+/**
+ * Format one named portion of a subsection from a command record.
+ * Subsections allow related parts of a help record to be grouped
+ * together.  For example, in the 'options' section, sub-options that
+ * are related to a particular primary option are stored in a 'sub-options'
+ * section whose name == the name of the primary option.
+ *
+ * @param $command
+ *   A command record with help information
+ * @param $section
+ *   The name of the section to format ('options', 'topic', etc.)
+ * @param $subsection
+ *   The name of the subsection (e.g. the name of the primary option)
+ * @param $formatter
+ *   The name of a function to use to format the rows of the subsection
+ * @param $prefix
+ *   Characters to prefix to the front of the label (for indentation)
+ * @returns array
+ *   Formatted rows, suitable for printing via drush_print_table.
+ */
+function _drush_format_help_subsection($command, $section, $subsection, $formatter, $prefix = '  ') {
+  foreach ($command['sub-' . $section][$subsection] as $name => $help_attributes) {
+    if (!is_array($help_attributes)) {
+      $help_attributes = array('description' => $help_attributes);
     }
-    if (!db_query($query, $args)) {
-      return FALSE;
+    $help_attributes['label'] = $name;
+    call_user_func_array($formatter, array($command, &$help_attributes));
+    $rows[] = array($prefix . $help_attributes['label'], $help_attributes['description']);
+    // Process the subsections too, if any
+    if (!empty($command['sub-' . $section]) && array_key_exists($name, $command['sub-' . $section])) {
+      $rows = array_merge($rows, _drush_format_help_subsection($command, $section, $name, $formatter, $prefix . '  '));
     }
-    return db_affected_rows();
   }
+  return $rows;
 }
 
 /**
- * A db_result() that works consistently for any version of Drupal.
- *
- * @param
- *   A Database result object.
+ * The options section formatter.  Adds a "--" in front of each
+ * item label.  Also handles short-form and example-value
+ * components in the help attributes.
  */
-function drush_db_result($result) {
-  switch (drush_drupal_major_version()) {
-    case 5:
-      // In versions of Drupal <= 5, db_result only returns the first row no matter how
-      //  many times you call it. So instead of calling it here, we use db_fetch_array which
-      //  does increment the pointer to the next row (as db_result does on Drupal 6)
-      if ($array = db_fetch_array($result)) {
-        return array_shift($array); // return first element in array.
-      }
-      return FALSE;
-    case 6:
-      return db_result($result);
-    case 7:
-    default:
-      return $result->fetchField();
+function drush_help_section_formatter_options($command, &$help_attributes) {
+  if ($help_attributes['label'][0] == '-') {
+    drush_log(dt("Option '%option' of command %command should instead be declared as '%fixed'", array('%option' => $help_attributes['label'], '%command' => $command['command'], '%fixed' => preg_replace('/^--*/', '', $help_attributes['label']))), 'debug');
+  }
+  else {
+    $help_attributes['label'] = '--' . $help_attributes['label'];
+  }
+  if (array_key_exists('example-value', $help_attributes)) {
+    $help_attributes['label'] .= '=' . $help_attributes['example-value'];
+    if (array_key_exists('short-form', $help_attributes)) {
+      $help_attributes['short-form'] .= ' ' . $help_attributes['example-value'];
+    }
+  }
+  if (array_key_exists('short-form', $help_attributes)) {
+    $help_attributes['label'] = '-' . $help_attributes['short-form'] . ', ' . $help_attributes['label'];
   }
+  drush_help_section_default_formatter($command, $help_attributes);
 }
 
 /**
- * A db_fetch_object() that works for any version of Drupal.
- *
- * @param
- *   A Database result object.
+ * The default section formatter.  Replaces '[command]' with the
+ * command name.
  */
-function drush_db_fetch_object($result) {
-  return drush_drupal_major_version() >= 7 ? $result->fetchObject() : db_fetch_object($result);
+function drush_help_section_default_formatter($command, &$help_attributes) {
+  // '[command]' is a token representing the current command. @see pm_drush_engine_version_control().
+  $help_attributes['label'] = str_replace('[command]', $command['command'], $help_attributes['label']);
 }
 
 /**
- * Save a string to a temporary file. Does not depend on Drupal's API.
- * The temporary file will be automatically deleted when drush exits.
- *
- * @param string $data
- * @return string
- *   A path to the file.
+ * Exits with a message. In general, you should use drush_set_error() instead of
+ * this function. That lets drush proceed with other tasks.
+ * TODO: Exit with a correct status code.
  */
-function drush_save_data_to_temp_file($data) {
-  static $fp;
-
-  $fp = tmpfile();
-  fwrite($fp, $data);
-  $meta_data = stream_get_meta_data($fp);
-  $file = $meta_data['uri'];
-  drush_register_file_for_deletion($file);
-
-  return $file;
+function drush_die($msg = NULL, $status = NULL) {
+  die($msg ? "drush: $msg\n" : '');
 }
 
-/**
- * Returns the path to a temporary directory.
- *
- * This is a custom version of file_directory_path().
- * We can't directly rely on sys_get_temp_dir() as this
- * path is not valid in some setups for Mac.
+/*
+ * Check to see if the provided line is a "#!/usr/bin/env drush"
+ * "shebang" script line.
  */
-function drush_find_tmp() {
-  static $temporary_directory = NULL;
-
-  if (is_null($temporary_directory)) {
-    $directories = array();
-
-    // Operating system specific dirs.
-    if (substr(PHP_OS, 0, 3) == 'WIN') {
-      $directories[] = 'c:\\windows\\temp';
-      $directories[] = 'c:\\winnt\\temp';
-    }
-    else {
-      $directories[] = '/tmp';
-    }
-    // This function exists in PHP 5 >= 5.2.1, but drush
-    // requires PHP 5 >= 5.2.0, so we check for it.
-    if (function_exists('sys_get_temp_dir')) {
-      $directories[] = sys_get_temp_dir();
-    }
+function _drush_is_drush_shebang_line($line) {
+   return ((substr($line,0,2) == '#!') && (strstr($line, 'drush') !== FALSE));
+}
 
-    foreach ($directories as $directory) {
-      if (is_dir($directory) && is_writable($directory)) {
-        $temporary_directory = $directory;
-        break;
-      }
-    }
+/*
+ * Check to see if the provided script file is a "#!/usr/bin/env drush"
+ * "shebang" script line.
+ */
+function _drush_is_drush_shebang_script($script_filename) {
+  $result = FALSE;
 
-    if (empty($temporary_directory)) {
-      // If no directory has been found, create one in cwd.
-      $temporary_directory = drush_cwd() . '/tmp';
-      drush_mkdir($temporary_directory);
-      if (!is_dir($directory)) {
-        return drush_set_error('DRUSH_UNABLE_TO_CREATE_TMP_DIR', dt("Unable to create a temporary directory."));
-      }
-      drush_register_file_for_deletion($temporary_directory);
+  if (file_exists($script_filename)) {
+    $fp = fopen($script_filename, "r");
+    if ($fp !== FALSE) {
+      $line = fgets($fp);
+      $result = _drush_is_drush_shebang_line($line);
+      fclose($fp);
     }
   }
 
-  return $temporary_directory;
+  return $result;
 }
 
 /**
- * Creates a temporary file, and registers it so that
- * it will be deleted when drush exits.  Whenever possible,
- * drush_save_data_to_temp_file() should be used instead
- * of this function.
- */
-function drush_tempnam($pattern, $tmp_dir = NULL) {
-  if ($tmp_dir == NULL) {
-    $tmp_dir = drush_find_tmp();
-  }
-  $tmp_file = tempnam($tmp_dir, $pattern);
-  drush_register_file_for_deletion($tmp_file);
-
-  return $tmp_file;
-}
+ * @defgroup outputfunctions Process output text.
+ * @{
 
 /**
- * Creates a temporary directory and return its path.
+ * Prints a message with optional indentation. In general,
+ * drush_log($message, 'ok') is often a better choice than this function.
+ * That gets your confirmation message (for example) into the logs for this
+ * drush request. Consider that drush requests may be executed remotely and
+ * non interactively.
+ *
+ * @param $message
+ *   The message to print.
+ * @param $indent
+ *    The indentation (space chars)
+ * @param $handle
+ *    File handle to write to.  NULL will write
+ *    to standard output, STDERR will write to the standard
+ *    error.  See http://php.net/manual/en/features.commandline.io-streams.php
  */
-function drush_tempdir() {
-  $tmp_dir = rtrim(drush_find_tmp(), DIRECTORY_SEPARATOR);
-  $tmp_dir .= '/' . 'drush_tmp_' . time();
-
-  drush_mkdir($tmp_dir);
-  drush_register_file_for_deletion($tmp_dir);
-
-  return $tmp_dir;
+function drush_print($message = '', $indent = 0, $handle = NULL) {
+  $msg = str_repeat(' ', $indent) . (string)$message . "\n";
+  if (($charset = drush_get_option('output_charset')) && function_exists('iconv')) {
+    $msg = iconv('UTF-8', $charset, $msg);
+  }
+  if (isset($handle)) {
+    fwrite($handle, $msg);
+  }
+  else {
+    print $msg;
+  }
 }
 
 /**
- * Any file passed in to this function will be deleted
- * when drush exits.
+ * Stores a message which is printed during drush_shutdown() if in compact mode.
+ * @param $message
+ *   The message to print.  If $message is an array,
+ *   then each element of the array is printed on a
+ *   separate line.
  */
-function drush_register_file_for_deletion($file = NULL) {
-  static $registered_files = array();
-
-  if (isset($file)) {
-    if (empty($registered_files)) {
-      register_shutdown_function('_drush_delete_registered_files');
-    }
-    $registered_files[] = $file;
+function drush_print_pipe($message = '') {
+  $buffer = &drush_get_context('DRUSH_PIPE_BUFFER' , '');
+  if (is_array($message)) {
+    $message = implode("\n", $message) . "\n";
   }
-
-  return $registered_files;
+  $buffer .= $message;
 }
 
 /**
- * Delete all of the registered temporary files.
+ * Prints an array or string.
+ * @param $array
+ *   The array to print.
  */
-function _drush_delete_registered_files() {
-  $files_to_delete = drush_register_file_for_deletion();
-
-  foreach ($files_to_delete as $file) {
-    // We'll make sure that the file still exists, just
-    // in case someone came along and deleted it, even
-    // though they did not need to.
-    if (file_exists($file)) {
-      if (is_dir($file)) {
-        drush_delete_dir($file);
-      }
-      else {
-        unlink($file);
-      }
-    }
-  }
+function drush_print_r($array, $handle = NULL) {
+  drush_print(print_r($array, TRUE), 0, $handle);
 }
 
 /**
- * Deletes the provided file or folder and everything inside it.
+ * Rudimentary replacement for Drupal API t() function.
+ *
+ * @param string
+ *   String to process, possibly with replacement item.
+ * @param array
+ *  An associative array of replacement items.
  *
- * @param $dir
- *   The directory to delete
  * @return
- *   FALSE on failure, TRUE if everything was deleted
+ *   The processed string.
+ *
+ * @see t()
  */
-function drush_delete_dir($dir) {
-  if (!file_exists($dir)) {
-    return TRUE;
-  }
-  if (!is_dir($dir)) {
-    return unlink($dir);
+function dt($string, $args = array()) {
+  if (function_exists('t')) {
+    return t($string, $args);
   }
-  foreach (scandir($dir) as $item) {
-    if ($item == '.' || $item == '..') {
-      continue;
+  else {
+    if (!empty($args)) {
+      return strtr($string, $args);
     }
-    if (!drush_delete_dir($dir.'/'.$item)) {
-      return FALSE;
+    else {
+      return $string;
     }
   }
-  return rmdir($dir);
 }
 
 /**
- * Move $src to $dest.
+ * Convert html to readable text.  Compatible API to
+ * drupal_html_to_text, but less functional.  Caller
+ * might prefer to call drupal_html_to_text if there
+ * is a bootstrapped Drupal site available.
  *
- * If the php 'rename' function doesn't work, then we'll try mv and if
- * it also fails, rsync.
+ * @param string $html
+ *   The html text to convert.
  *
- * @param $src
- *   The directory to move.
- * @param $dest
- *   The destination to move the source to, including the new name of
- *   the directory.  To move directory "a" from "/b" to "/c", then
- *   $src = "/b/a" and $dest = "/c/a".  To move "a" to "/c" and rename
- *   it to "d", then $dest = "/c/d" (just like php rename function).
- * @param $overwrite
- *   If TRUE, the destination will be deleted if it exists.
- * @return
- *   TRUE on success, FALSE on failure.
+ * @return string
+ *   The plain-text representation of the input.
  */
-function drush_move_dir($src, $dest, $overwrite = FALSE) {
-  // Preflight based on $overwrite if $dest exists.
-  if (file_exists($dest)) {
-    if ($overwrite) {
-      drush_op('drush_delete_dir', $dest);
-    }
-    else {
-      return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
-    }
-  }
-  // $src readable?
-  if (!is_readable($src)) {
-    return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !dest is not readable or does not exist.', array('!src' => $src)));
-  }
-  // $dest writable?
-  if (!is_writable(dirname($dest))) {
-    return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
-  }
-  // Try rename. It will fail if $src and $dest are not in the same partition.
-  if (@drush_op('rename', $src, $dest)) {
-    return TRUE;
-  }
-  // Eventually it will create an empty file in $dest. See
-  // http://www.php.net/manual/es/function.rename.php#90025
-  elseif (is_file($dest)) {
-    drush_op('unlink', $dest);
-  }
+function drush_html_to_text($html, $allowed_tags = NULL) {
+  $replacements = array(
+    '<hr>' => '------------------------------------------------------------------------------',
+    '<li>' => '  * ',
+    '<h1>' => '===== ',
+    '</h1>' => ' =====',
+    '<h2>' => '---- ',
+    '</h2>' => ' ----',
+    '<h3>' => '::: ',
+    '</h3>' => ' :::',
+    '<br/>' => "\n",
+  );
+  $text = str_replace(array_keys($replacements), array_values($replacements), $html);
+  return html_entity_decode(preg_replace('/ *<[^>]*> */', ' ', $text));
+}
 
-  // Do it with mv.
-  if (drush_shell_exec('mv %s %s', $src, $dest)) {
-    return TRUE;
-  }
-
-  // Lastly try rsync.
-  drush_op('mkdir', $dest);
-  $exec = 'rsync -raz --remove-source-files ' . $src . '/ ' . $dest;
-  if (drush_shell_exec($exec)) {
-    // --remove-source-files deletes all of the files, but
-    // we still need to get rid of the directories.
-    drush_op('drush_delete_dir', $src);
-    return TRUE;
-  }
-
-  return drush_set_error('DRUSH_MOVE_DIR_FAILURE', dt('Unable to move !src to !dest.', array('src' => $src, 'dest' => $dest)));
-}
 
 /**
- * Calls a given function, passing through all arguments unchanged.
- *
- * This should be used when calling possibly mutative or destructive functions
- * (e.g. unlink() and other file system functions) so that can be suppressed
- * if the simulation mode is enabled.
+ * Print a formatted table.
  *
- * @param $function
- *   The name of the function. Any additional arguments are passed along.
- * @return
- *   The return value of the function, or TRUE if simulation mode is enabled.
- */
-function drush_op($function) {
-  $args = func_get_args();
-  array_shift($args); // Skip function name
+ * @param $rows
+ *   The rows to print.
+ * @param $header
+ *   If TRUE, the first line will be treated as table header.
+ * @param $widths
+ *   The widths of each column (in characters) to use - if not specified this
+ *   will be determined automatically, based on a "best fit" algorithm.
+ * @param $handle
+ *    File handle to write to.  NULL will write
+ *    to standard output, STDERR will write to the standard
+ *    error.  See http://php.net/manual/en/features.commandline.io-streams.php
+ * @return $tbl
+ *   Use $tbl->getTable() to get the output from the return value.
+ */
+function drush_print_table($rows, $header = FALSE, $widths = array(), $handle = NULL) {
+  $tbl = new Console_Table(CONSOLE_TABLE_ALIGN_LEFT , '');
 
-  if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
-     drush_print("Calling $function(". implode(", ", $args) .')');
+  $auto_widths = drush_table_column_autowidth($rows, $widths);
+
+  // Do wordwrap on all cells.
+  $newrows = array();
+  foreach ($rows as $rowkey => $row) {
+    foreach ($row as $col_num => $cell) {
+      $newrows[$rowkey][$col_num] = wordwrap($cell, $auto_widths[$col_num], "\n", TRUE);
+      if (isset($widths[$col_num])) {
+        $newrows[$rowkey][$col_num] = str_pad($newrows[$rowkey][$col_num], $widths[$col_num]);
+      }
+    }
+  }
+  if ($header) {
+    $headers = array_shift($newrows);
+    $tbl->setHeaders($headers);
   }
 
-  if (drush_get_context('DRUSH_SIMULATE')) {
-    return TRUE;
+  $tbl->addData($newrows);
+  $output = $tbl->getTable();
+  if (!stristr(PHP_OS, 'WIN')) {
+    $output = str_replace("\r\n", PHP_EOL, $output);
   }
 
-  return call_user_func_array($function, $args);
+  // Check if the handle argument is a string to preserve compatability with
+  // previous versions that accepted a filename instead.
+  if (is_string($handle)) {
+    file_put_contents($handle, $output, FILE_APPEND);
+  }
+  else {
+    drush_print($output, 0, $handle);
+  }
+  return $tbl;
 }
 
 /**
- * Rudimentary replacement for Drupal API t() function.
- *
- * @param string
- *   String to process, possibly with replacement item.
- * @param array
- *  An associative array of replacement items.
+ * Convert an associative array of key : value pairs into
+ * a table suitable for processing by drush_print_table.
  *
+ * @param $keyvalue_table
+ *    An associative array of key : value pairs.
  * @return
- *   The processed string.
- *
- * @see t()
+ *    An array of arrays, where the keys from the input
+ *    array are stored in the first column, and the values
+ *    are stored in the third.  A second colum is created
+ *    specifically to hold the ':' separator.
  */
-function dt($string, $args = array()) {
-  if (function_exists('t')) {
-    return t($string, $args);
-  }
-  else {
-    if (!empty($args)) {
-      return strtr($string, $args);
+function drush_key_value_to_array_table($keyvalue_table) {
+  $table = array();
+  foreach ($keyvalue_table as $key => $value) {
+    if (isset($value)) {
+      $table[] = array($key, ' :', $value);
     }
     else {
-      return $string;
+      $table[] = array($key . ':', '', '');
     }
   }
+  return $table;
 }
 
 /**
- * Convert a csv string, or an array of items which
- * may contain csv strings, into an array of items.
- *
- * @param $args
- *   A simple csv string; e.g. 'a,b,c'
- *   or a simple list of items; e.g. array('a','b','c')
- *   or some combination; e.g. array('a,b','c') or array('a,','b,','c,')
- *   
- * @returns array
- *   A simple list of items (e.g. array('a','b','c')
- */
-function _convert_csv_to_array($args) {
-  //
-  // Step 1: implode(',',$args) converts from, say, array('a,','b,','c,') to 'a,,b,,c,'
-  // Step 2: explode(',', ...) converts to array('a','','b','','c','')
-  // Step 3: array_filter(...) removes the empty items
-  //
-  return array_filter(explode(',', is_array($args) ? implode(',',$args) : $args));
-}
-
-/**
- * Get the available global options. Used by help command.
+ * Determine the best fit for column widths.
  *
- * @return
- *   An associative array containing the option definition as the key, and the description as the value,
- *   for each of the available options.
- */
-function drush_get_global_options() {
-  // TODO: Add a hook for this, to allow other modules to add their global options
-  $options['-r <path>, --root=<path>'] = dt("Drupal root directory to use (default: current directory)");
-  $options['-l <uri>, --uri=http://example.com']   = dt('URI of the drupal site to use (only needed in multisite environments)');
-  $options['-v, --verbose']            = dt('Display extra information about the command.');
-  $options['-d, --debug']              = dt('Display even more information, including internal messages.');
-  $options['-q, --quiet']              = dt('Hide all output');
-  $options['-y, --yes']                = dt("Assume 'yes' as answer to all prompts");
-  $options['-n, --no']                = dt("Assume 'no' as answer to all prompts");
-  $options['-s, --simulate']           = dt("Simulate all relevant actions (don't actually change the system)");
-  $options['-i, --include']            = dt("A list of paths to search for drush commands");
-  $options['-c, --config']             = dt("Specify a config file to use. See example.drushrc.php");
-  $options['-u, --user']               = dt("Specify a user to login with. May be a name or a number.");
-  $options['-b, --backend']            = dt("Hide all output and return structured data (internal use only).");
-  $options['-p, --pipe']               = dt("Emit a compact representation of the command for scripting.");
-  $options['--nocolor']                = dt("Suppress color highlighting on log messages.");
-  $options['--show-passwords']         = dt("Show database passwords in commands that display connection information.");
-  $options['-h, --help']               = dt("This help system.");
-  $options['--php']                    = dt("The absolute path to your PHP intepreter, if not 'php' in the path.");
-  return $options;
-}
-
-/**
- * Prints out help for a given command.
+ * @param $rows
+ *   The rows to use for calculations.
+ * @param $widths
+ *   Manually specified widths of each column (in characters) - these will be
+ *   left as is.
  */
-function drush_show_help($commandstring) {
-  $phases = _drush_bootstrap_phases();
+function drush_table_column_autowidth($rows, $widths) {
+  $auto_widths = $widths;
 
-  foreach ($phases as $phase_index) {
-    if ($validated = drush_bootstrap_validate($phase_index)) {
-      if ($phase_index > drush_get_context('DRUSH_BOOTSTRAP_PHASE')) {
-        drush_bootstrap($phase_index);
+  // First we determine the distribution of row lengths in each column.
+  // This is an array of descending character length keys (i.e. starting at
+  // the rightmost character column), with the value indicating the number
+  // of rows where that character column is present.
+  $col_dist = array();
+  foreach ($rows as $rowkey => $row) {
+    foreach ($row as $col_num => $cell) {
+      if (empty($widths[$col_num])) {
+        $length = strlen($cell);
+        while ($length > 0) {
+          if (!isset($col_dist[$col_num][$length])) {
+            $col_dist[$col_num][$length] = 0;
+          }
+          $col_dist[$col_num][$length]++;
+          $length--;
+        }
       }
     }
-    if (!drush_get_error()) {
-      $commands = drush_get_commands();
-      if (array_key_exists($commandstring, $commands)) {
-        $command = $commands[$commandstring];
-
-        if ($validated && $command['bootstrap'] > $phase_index) {
-          continue;
-        }
-
-        drush_print_help($command);
+  }
+  foreach ($col_dist as $col_num => $count) {
+    // Sort the distribution in decending key order.
+    krsort($col_dist[$col_num]);
+    // Initially we set all columns to their "ideal" longest width
+    // - i.e. the width of their longest column.
+    $auto_widths[$col_num] = max(array_keys($col_dist[$col_num]));
+  }
 
-        return TRUE;
+  // We determine what width we have available to use, and what width the
+  // above "ideal" columns take up.
+  $available_width = drush_get_context('DRUSH_COLUMNS', 80) - (count($auto_widths) * 2);
+  $auto_width_current = array_sum($auto_widths);
 
+  // If we need to reduce a column so that we can fit the space we use this
+  // loop to figure out which column will cause the "least wrapping",
+  // (relative to the other columns) and reduce the width of that column.
+  while ($auto_width_current > $available_width) {
+    $count = 0;
+    $width = 0;
+    foreach ($col_dist as $col_num => $counts) {
+      // If we are just starting out, select the first column.
+      if ($count == 0 ||
+         // OR: if this column would cause less wrapping than the currently
+         // selected column, then select it.
+         (current($counts) < $count) ||
+         // OR: if this column would cause the same amount of wrapping, but is
+         // longer, then we choose to wrap the longer column (proportionally
+         // less wrapping, and helps avoid triple line wraps).
+         (current($counts) == $count && key($counts) > $width)) {
+        // Select the column number, and record the count and current width
+        // for later comparisons.
+        $column = $col_num;
+        $count = current($counts);
+        $width = key($counts);
       }
     }
-    else {
+    if ($width <= 1) {
+      // If we have reached a width of 1 then give up, so wordwrap can still progress.
       break;
     }
+    // Reduce the width of the selected column.
+    $auto_widths[$column]--;
+    // Reduce our overall table width counter.
+    $auto_width_current--;
+    // Remove the corresponding data from the disctribution, so next time
+    // around we use the data for the row to the left.
+    unset($col_dist[$column][$width]);
   }
-  return drush_set_error('DRUSH_COMMAND_NOT_FOUND', dt('Invalid command !command.', array('!command' => $commandstring)));
+  return $auto_widths;
 }
 
 /**
- * Print the help for a single command to the screen.
+ * Print the contents of a file.
  *
- * @param array $command 
- *   A fully loaded $command array.
+ * @param string $file
+ *   Full path to a file.
  */
-function drush_print_help($command) {
-  // Merge in engine specific help.
-  foreach ($command['engines'] as $type => $description) {
-    $all_engines = drush_get_engines($type);
-    foreach ($all_engines as $name => $engine) {
-      $command = array_merge_recursive($command, $engine);
-    }
+function drush_print_file($file) {
+  // Don't even bother to print the file in --no mode
+  if (drush_get_context('DRUSH_NEGATIVE')) {
+    return;
   }
-
-  if (!$help = drush_command_invoke_all('drush_help', 'drush:'. $command['command'])) {
-    $help = array($command['description']);
+  if ((substr($file,-4) == ".htm") || (substr($file,-5) == ".html")) {
+    $tmp_file = drush_tempnam(basename($file));
+    file_put_contents($tmp_file, drush_html_to_text(file_get_contents($file)));
+    $file = $tmp_file;
   }
-
-  // Give commandfiles an opportunity to add examples and options to the command.
-  drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
-  drush_command_invoke_all_ref('drush_help_alter', $command);
-
-  drush_print(wordwrap(implode("\n", $help), drush_get_context('DRUSH_COLUMNS', 80)));
-  drush_print();
-
-  foreach ($command['sections'] as $key => $value) {
-    if (!empty($command[$key])) {
-      drush_print(dt($value) . ':');
-      foreach ($command[$key] as $name => $description) {
-        // '[command] is a token representing the current command. @see pm_drush_engine_version_control().
-        $rows[] = array(str_replace('[command]', $command['command'], $name), dt($description));
-        
-        // Process the subsections too, if any
-        if (!empty($command['sub-' . $key]) && array_key_exists($name, $command['sub-' . $key])) {
-          foreach ($command['sub-' . $key][$name] as $name => $description) {
-            $rows[] = array('  ' . str_replace('[command]', $command['command'], $name), dt($description));
-          }
-        }
-      }
-      drush_print_table($rows, FALSE, array(40));
-      unset($rows);
-      drush_print();
-    }
+  // Do not wait for user input in --yes or --pipe modes
+  if (drush_get_context('DRUSH_PIPE')) {
+    drush_print_pipe(file_get_contents($file));
   }
-
-  // Append aliases if any.
-  if ($command['aliases']) {
-    drush_print(dt("Aliases: ") . implode(', ', $command['aliases']));
+  elseif (drush_get_context('DRUSH_AFFIRMATIVE')) {
+    drush_print(file_get_contents($file));
+  }
+  elseif (drush_shell_exec_interactive("less %s", $file)) {
+    return;
+  }
+  elseif (drush_shell_exec_interactive("more %s", $file)) {
+    return;
+  }
+  else {
+    drush_print(file_get_contents($file));
   }
 }
 
-
 /**
- * Executes a shell command at a new working directory.
- * The old cwd is restored on exit.
+ * Converts a PHP variable into its Javascript equivalent.
  *
- * @param $effective_wd
- *   The new working directory to execute the shell command at.
- * @param $cmd
- *   The command to execute. May include placeholders used for sprintf.
- * @param ...
- *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
- * @return
- *   0 if success.
+ * We provide a copy of D7's drupal_json_encode since this function is
+ * unavailable on earlier versions of Drupal.
+ *
+ * @see drupal_json_decode()
+ * @ingroup php_wrappers
  */
-function drush_shell_cd_and_exec($effective_wd, $cmd) {
-  $args = func_get_args();
-  
-  $effective_wd = array_shift($args);
-  $cwd = getcwd();
-  drush_op('chdir', $effective_wd);
-  $result = call_user_func_array('drush_shell_exec', $args);
-  drush_op('chdir', $cwd);
-  return $result;
+function drush_json_encode($var) {
+  // json_encode() does not escape <, > and &, so we do it with str_replace().
+  return str_replace(array('<', '>', '&'), array('\u003c', '\u003e', '\u0026'), json_encode($var));
 }
 
 /**
- * Executes a shell command.
- * Output is only printed if in verbose mode.
- * Output is stored and can be retrieved using drush_shell_exec_output().
- * If in simulation mode, no action is taken.
+ * Converts an HTML-safe JSON string into its PHP equivalent.
  *
- * @param $cmd
- *   The command to execute. May include placeholders used for sprintf.
- * @param ...
- *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
- * @return
- *   0 if success.
- */
-function drush_shell_exec($cmd) {
-  return _drush_shell_exec(func_get_args());
-}
-
-/**
- * Executes a command in interactive mode.
- *
- * @see drush_shell_exec.
- */
-function drush_shell_exec_interactive($cmd) {
-  return _drush_shell_exec(func_get_args(), TRUE);
-}
-
-/**
- * Internal function: executes a shell command:
- *
- * @param $args
- *   The command and its arguments.
- * @param $interactive
- *   Whether to run in 
- *
- * @see drush_shell_exec.
- */
-function _drush_shell_exec($args, $interactive = FALSE) {
-  //do not change the command itself, just the parameters.
-  for ($x = 1; $x < sizeof($args); $x++) {
-    $args[$x] = escapeshellarg($args[$x]);
-  }
-  $command = call_user_func_array('sprintf', $args);
-
-  if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
-    drush_log('Executing: ' . $command);
-  }
-
-  if (!drush_get_context('DRUSH_SIMULATE')) {
-    exec($command . ($interactive ? '' : ' 2>&1'), $output, $result);
-    _drush_shell_exec_output_set($output);
-
-    if (drush_get_context('DRUSH_DEBUG')) {
-      foreach ($output as $line) {
-        drush_print($line, 2);
-      }
-    }
-
-    // Exit code 0 means success.
-    return ($result == 0);
-  }
-  else {
-    return 0;
-  }
-}
-
-/**
- * Stores output for the most recent shell command.
- * This should only be run from drush_shell_exec().
- *
- * @param $output
- *   The output of the most recent shell command.
- *   If this is not set the stored value will be returned.
- */
-function _drush_shell_exec_output_set($output = FALSE) {
-  static $stored_output;
-  if ($output === FALSE) return $stored_output;
-  $stored_output = $output;
-}
-
-/**
- * Returns the output of the most recent shell command as an array of lines.
- */
-function drush_shell_exec_output() {
-  return _drush_shell_exec_output_set();
-}
-
-/**
- * Exits with a message. In general, you should use drush_set_error() instead of
- * this function. That lets drush proceed with other tasks.
- * TODO: Exit with a correct status code.
- */
-function drush_die($msg = NULL, $status = NULL) {
-  die($msg ? "drush: $msg\n" : '');
-}
-
-/**
- * Exit due to user declining a confirmation prompt.
- */
-function drush_user_abort($msg = NULL, $status = NULL) {
-  drush_set_context('DRUSH_USER_ABORT', TRUE);
-  drush_die($msg ? $msg : 'Aborting.', $status);
-}
-
-/*
- * Check to see if the provided line is a "#!/usr/bin/env drush"
- * "shebang" script line.
- */
-function _drush_is_drush_shebang_line($line) {
-   return ((substr($line,0,2) == '#!') && (strstr($line, 'drush') !== FALSE));
-}
-
-/*
- * Check to see if the provided script file is a "#!/usr/bin/env drush"
- * "shebang" script line.
- */
-function _drush_is_drush_shebang_script($script_filename) {
-  $result = FALSE;
-  
-  if (file_exists($script_filename)) {
-    $fp = fopen($script_filename, "r");
-    if ($fp !== FALSE) {
-      $line = fgets($fp);
-      $result = _drush_is_drush_shebang_line($line);
-      fclose($fp);
-    }
-  }
-  
-  return $result;
-}
-
-/**
- * Prints a message with optional indentation. In general,
- * drush_log($message, 'ok') is often a better choice than this function.
- * That gets your confirmation message (for example) into the logs for this
- * drush request. Consider that drush requests may be executed remotely and
- * non interactively.
+ * We provide a copy of D7's drupal_json_decode since this function is
+ * unavailable on earlier versions of Drupal.
  *
- * @param $message
- *   The message to print.
- * @param $indent
- *    The indentation (space chars)
- */
-function drush_print($message = '', $indent = 0) {
-  $msg = str_repeat(' ', $indent) . (string)$message . "\n";
-  if ($charset = drush_get_option('output_charset') && function_exists('iconv')) {
-    $msg = iconv('UTF-8', $charset, $msg);
-  }
-  print $msg;
-}
-
-/**
- * Print the contents of a file.
- *
- * @param string $file 
- *   Full path to a file.
+ * @see drupal_json_encode()
+ * @ingroup php_wrappers
  */
-function drush_print_file($file) {
-  drush_print(file_get_contents($file));
+function drush_json_decode($var) {
+  return json_decode($var, TRUE);
 }
 
 /**
- * Stores a message which is printed during drush_shutdown() if in compact mode.
- * @param $message
- *   The message to print.  If $message is an array,
- *   then each element of the array is printed on a
- *   separate line.
+ * @} End of "defgroup outputfunctions".
  */
-function drush_print_pipe($message = '') {
-  $buffer = &drush_get_context('DRUSH_PIPE_BUFFER' , '');
-  if (is_array($message)) {
-    $message = implode("\n", $message) . "\n";
-  }
-  $buffer .= $message;
-}
 
 /**
- * Prints an array or string.
- * @param $array
- *   The array to print.
- */
-function drush_print_r($array) {
-  print_r($array);
-}
+ * @defgroup userinput Get input from the user.
+ * @{
 
 /**
  * Ask the user a basic yes/no question.
@@ -1103,28 +970,160 @@ function drush_confirm($msg, $indent = 0) {
 function drush_choice($options, $prompt = 'Enter a number.', $label = '!value') {
   print dt($prompt) . "\n";
 
-  drush_print('  [0] : Cancel');
+  // Preflight so that all rows will be padded out to the same number of columns
+  $array_pad = 0;
+  foreach ($options as $key => $option) {
+    if (is_array($option) && (count($option) > $array_pad)) {
+      $array_pad = count($option);
+    }
+  }
+
+  $rows[] = array_pad(array('[0]', ':', 'Cancel'), $array_pad + 2, '');
   $selection_number = 0;
   foreach ($options as $key => $option) {
     if ((substr($key, 0, 3) == '-- ') && (substr($key, -3) == ' --')) {
-      drush_print("  ".$option);
-      continue;
+      $rows[] = array_pad(array('', '', $option), $array_pad + 2, '');
+    }
+    else {
+      $selection_number++;
+      $row = array("[$selection_number]", ':');
+      if (is_array($option)) {
+        $row = array_merge($row, $option);
+      }
+      else {
+        $row[] = dt($label, array('!number' => $selection_number, '!key' => $key, '!value' => $option));
+      }
+      $rows[] = $row;
+      $selection_list[$selection_number] = $key;
+    }
+  }
+  drush_print_table($rows);
+  drush_print_pipe(array_keys($options));
+
+  // If the user specified --choice, then make an
+  // automatic selection.  Cancel if the choice is
+  // not an available option.
+  if (($choice = drush_get_option('choice', FALSE)) !== FALSE) {
+    // First check to see if $choice is one of the symbolic options
+    if (array_key_exists($choice, $options)) {
+      return $choice;
     }
-    $selection_number++;
-    $message = dt($label, array('!number' => $selection_number, '!key' => $key, '!value' => $option));
-    drush_print(dt("  [!number] : !message", array('!number' => $selection_number, '!message' => $message)));
-    $selection_list[$selection_number] = $key;
+    // Next handle numeric selections
+    elseif (array_key_exists($choice, $selection_list)) {
+      return $selection_list[$choice];
+    }
+    return FALSE;
   }
 
-  while ($line = trim(fgets(STDIN))) {
-    if (array_key_exists($line, $selection_list)) {
-      return $selection_list[$line];
+  // If the user specified --no, then cancel; also avoid
+  // getting hung up waiting for user input in --pipe and
+  // backend modes.  If none of these apply, then wait,
+  // for user input and return the selected result.
+  if (!drush_get_context('DRUSH_NEGATIVE') && !drush_get_context('DRUSH_AFFIRMATIVE') && !drush_get_context('DRUSH_PIPE')) {
+    while ($line = trim(fgets(STDIN))) {
+      if (array_key_exists($line, $selection_list)) {
+        return $selection_list[$line];
+      }
     }
   }
+  // We will allow --yes to confirm input if there is only
+  // one choice; otherwise, --yes will cancel to avoid ambiguity
+  if (drush_get_context('DRUSH_AFFIRMATIVE')  && (count($options) == 1)) {
+    return $selection_list[1];
+  }
   drush_print(dt('Cancelled'));
   return FALSE;
 }
 
+/**
+ * Ask the user to select multiple items from a list.
+ * This is a wrapper around drush_choice, that repeats the selection process,
+ * allowing users to toggle a number of items in a list. The number of values
+ * that can be constrained by both min and max: the user will only be allowed
+ * finalize selection once the minimum number has been selected, and the oldest
+ * selected value will "drop off" the list, if they exceed the maximum number.
+ *
+ * @param $options
+ *   Same as drush_choice() (see above).
+ * @param $defaults
+ *   This can take 3 forms:
+ *   - FALSE: (Default) All options are unselected by default.
+ *   - TRUE: All options are selected by default.
+ *   - Array of $options keys to be selected by default.
+ * @param $prompt
+ *   Same as drush_choice() (see above).
+ * @param $label
+ *   Same as drush_choice() (see above).
+ * @param $mark
+ *   Controls how selected values are marked.  Defaults to '!value (selected)'.
+ * @param $min
+ *   Constraint on minimum number of selections. Defaults to zero. When fewer
+ *   options than this are selected, no final options will be available.
+ * @param $max
+ *   Constraint on minimum number of selections. Defaults to NULL (unlimited).
+ *   If the a new selection causes this value to be exceeded, the oldest
+ *   previously selected value is automatically unselected.
+ * @param $final_options
+ *   An array of additional options in the same format as $options.
+ *   When the minimum number of selections is met, this array is merged into the
+ *   array of options. If the user selects one of these values and the
+ *   selection process will complete (the key for the final option is included
+ *   in the return value). If this is an empty array (default), then a built in
+ *   final option of "Done" will be added to the available options (in this case
+ *   no additional keys are added to the return value).
+ */
+function drush_choice_multiple($options, $defaults = FALSE, $prompt = 'Select some numbers.', $label = '!value', $mark = '!value (selected)', $min = 0, $max = NULL, $final_options = array()) {
+  $selections = array();
+  // Load default selections.
+  if (is_array($defaults)) {
+    $selections = $defaults;
+  }
+  elseif ($defaults === TRUE) {
+    $selections = array_keys($options);
+  }
+  $complete = FALSE;
+  $final_builtin = array();
+  if (empty($final_options)) {
+    $final_builtin['done'] = dt('Done');
+  }
+  $final_options_keys = array_keys($final_options);
+  while (TRUE) {
+    $current_options = $options;
+    // Mark selections.
+    foreach ($selections as $selection) {
+      $current_options[$selection] = dt($mark, array('!key' => $selection, '!value' => $options[$selection]));
+    }
+    // Add final options, if the minimum number of selections has been reached.
+    if (count($selections) >= $min) {
+      $current_options = array_merge($current_options, $final_options, $final_builtin);
+    }
+    $toggle = drush_choice($current_options, $prompt, $label);
+    if ($toggle === FALSE) {
+      return FALSE;
+    }
+    // Don't include the built in final option in the return value.
+    if (count($selections) >= $min && empty($final_options) && $toggle == 'done') {
+      return $selections;
+    }
+    // Toggle the selected value.
+    $item = array_search($toggle, $selections);
+    if ($item === FALSE) {
+      array_unshift($selections, $toggle);
+    }
+    else {
+      unset($selections[$item]);
+    }
+    // If the user selected one of the final options, return.
+    if (count($selections) >= $min && in_array($toggle, $final_options_keys)) {
+      return $selections;
+    }
+    // If the user selected too many options, drop the oldest selection.
+    if (count($selections) > $max) {
+      array_pop($selections);
+    }
+  }
+}
+
 /**
  * Prompt the user for input
  *
@@ -1135,12 +1134,12 @@ function drush_choice($options, $prompt = 'Enter a number.', $label = '!value')
  *   The text which is displayed to the user.
  * @param $default
  *   The default value of the input.
- * @param $optional
+ * @param $required
  *   If TRUE, user may continue even when no value is in the input.
  *
  * @see drush_confirm()
  */
-function drush_prompt($prompt, $default = NULL, $optional = FALSE) {
+function drush_prompt($prompt, $default = NULL, $required = TRUE) {
   if (!is_null($default)) {
     $prompt .= " [" . $default . "]";
   }
@@ -1159,176 +1158,946 @@ function drush_prompt($prompt, $default = NULL, $optional = FALSE) {
     if ($line === "") {
       $line = $default;
     }
-    if ($line || $optional) {
-      break;
+    if ($line || !$required) {
+      break;
+    }
+    print $prompt;
+  }
+  fclose($stdin);
+  return $line;
+}
+
+/**
+ * @} End of "defgroup userinput".
+ */
+
+/**
+ * @defgroup commandwrappers Functions to execute commands.
+ * @{
+ */
+
+/**
+ * Calls a given function, passing through all arguments unchanged.
+ *
+ * This should be used when calling possibly mutative or destructive functions
+ * (e.g. unlink() and other file system functions) so that can be suppressed
+ * if the simulation mode is enabled.
+ *
+ * Important:  Call @see drush_op_system() to execute a shell command,
+ * or @see drush_shell_exec() to execute a shell command and capture the
+ * shell output.
+ *
+ * @param $function
+ *   The name of the function. Any additional arguments are passed along.
+ * @return
+ *   The return value of the function, or TRUE if simulation mode is enabled.
+ *
+ */
+function drush_op($function) {
+  $args = func_get_args();
+  array_shift($args); // Skip function name
+  foreach ($args as $arg) {
+    $args_printed[] = is_scalar($arg) ? $arg : (is_array($arg) ? 'Array' : 'Object');
+  }
+
+  // Special checking for drush_op('system')
+  if ($function == 'system') {
+    drush_log(dt("Do not call drush_op('system'); use drush_op_system instead"), 'debug');
+  }
+
+  if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
+     drush_log(sprintf("Calling %s(%s)", $function, implode(", ", $args_printed)), 'debug');
+  }
+
+  if (drush_get_context('DRUSH_SIMULATE')) {
+    return TRUE;
+  }
+
+  return call_user_func_array($function, $args);
+}
+
+/**
+ * Calls 'system()' function, passing through all arguments unchanged.
+ *
+ * This should be used when calling possibly mutative or destructive functions
+ * (e.g. unlink() and other file system functions) so that can be suppressed
+ * if the simulation mode is enabled.
+ *
+ * @param $exec
+ *   The shell command to execute.  Parameters should already be escaped.
+ * @return
+ *   The result code from system():  0 == success.
+ *
+ * @see drush_shell_exec()
+ */
+function drush_op_system($exec) {
+  if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
+     drush_print("Calling system($exec);");
+  }
+
+  if (drush_get_context('DRUSH_SIMULATE')) {
+    return 0;
+  }
+
+  // Throw away output.  Use drush_shell_exec() to capture output.
+  system($exec, $result_code);
+
+  return $result_code;
+}
+
+/**
+ * Executes a shell command at a new working directory.
+ * The old cwd is restored on exit.
+ *
+ * @param $effective_wd
+ *   The new working directory to execute the shell command at.
+ * @param $cmd
+ *   The command to execute. May include placeholders used for sprintf.
+ * @param ...
+ *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
+ * @return
+ *   TRUE on success, FALSE on failure
+ */
+function drush_shell_cd_and_exec($effective_wd, $cmd) {
+  $args = func_get_args();
+
+  $effective_wd = array_shift($args);
+  $cwd = getcwd();
+  drush_op('chdir', $effective_wd);
+  $result = call_user_func_array('drush_shell_exec', $args);
+  drush_op('chdir', $cwd);
+  return $result;
+}
+
+/**
+ * Executes a shell command.
+ * Output is only printed if in verbose mode.
+ * Output is stored and can be retrieved using drush_shell_exec_output().
+ * If in simulation mode, no action is taken.
+ *
+ * @param $cmd
+ *   The command to execute. May include placeholders used for sprintf.
+ * @param ...
+ *   Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
+ * @return
+ *   TRUE on success, FALSE on failure
+ */
+function drush_shell_exec($cmd) {
+  return _drush_shell_exec(func_get_args());
+}
+
+/**
+ * Executes a command in interactive mode.
+ *
+ * @see drush_shell_exec.
+ */
+function drush_shell_exec_interactive($cmd) {
+  return _drush_shell_exec(func_get_args(), TRUE);
+}
+
+/**
+ * Internal function: executes a shell command on the
+ * local machine.  This function should not be used
+ * in instances where ssh is utilized to execute a
+ * command remotely; otherwise, remote operations would
+ * fail if executed from a Windows machine to a remote
+ * Linux server.
+ *
+ * @param $args
+ *   The command and its arguments.
+ * @param $interactive
+ *   Whether to run in
+ *
+ * @return
+ *   TRUE on success, FALSE on failure
+ *
+ * @see drush_shell_exec.
+ */
+function _drush_shell_exec($args, $interactive = FALSE) {
+  //do not change the command itself, just the parameters.
+  for ($x = 1; $x < sizeof($args); $x++) {
+    $args[$x] = drush_escapeshellarg($args[$x]);
+  }
+  $command = call_user_func_array('sprintf', $args);
+
+  if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
+    drush_print('Executing: ' . $command);
+  }
+
+  if (!drush_get_context('DRUSH_SIMULATE')) {
+    if ($interactive) {
+      $result = proc_open($command, array(0 => STDIN, 1 => STDOUT, 2 => STDERR), $pipes);
+      proc_close($result);
+      // proc_open returns FALSE on failure, or a resource on success.
+      return ($result === FALSE) ? FALSE : TRUE;
+    }
+    else {
+      exec($command . ' 2>&1', $output, $result);
+      _drush_shell_exec_output_set($output);
+
+      if (drush_get_context('DRUSH_DEBUG')) {
+        foreach ($output as $line) {
+          drush_print($line, 2);
+        }
+      }
+
+      // Exit code 0 means success.
+      return ($result == 0);
+    }
+  }
+  else {
+    return TRUE;
+  }
+}
+
+/**
+ * Determine the appropriate os value for the
+ * specified site record
+ *
+ * @returns
+ *   NULL for 'same as local machine', 'Windows' or 'Linux'.
+ */
+function drush_os($site_record = NULL) {
+  // Default to $os = NULL, meaning 'same as local machine'
+  $os = NULL;
+  // If the site record has an 'os' element, use it
+  if (isset($site_record) && array_key_exists('os', $site_record)) {
+    $os = $site_record['os'];
+  }
+  // Otherwise, we will assume that all remote machines are Linux
+  // (or whatever value 'remote-os' is set to in drushrc.php).
+  elseif (isset($site_record) && array_key_exists('remote-host', $site_record) && !empty($site_record['remote-host'])) {
+    $os = drush_get_option('remote-os', 'Linux');
+  }
+
+  return $os;
+}
+
+/**
+ * Platform-independent version of escapeshellarg().
+ * This only works for local commands.
+ * TODO: Make a unified drush_escapeshellarg
+ * that works on Linux and Windows.
+ */
+function drush_escapeshellarg($arg) {
+  if (drush_is_windows()) {
+    return _drush_escapeshellarg_windows($arg);
+  }
+  else {
+    return escapeshellarg($arg);
+  }
+}
+
+/**
+ * Check if the operating system is Windows.
+ */
+function drush_is_windows() {
+  if (substr(php_uname(), 0, 7) == 'Windows') {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Windows version of escapeshellarg().
+ *
+ * @deprecated escapeshellarg needs to be cross-platform,
+ * because drush does not always know in advance whether an
+ * escaped arg will be used locally or on a remote system.
+ * See http://drupal.org/node/766080
+ */
+function _drush_escapeshellarg_windows($arg) {
+  // Double the backslashes before any double quotes. Escape the double quotes.
+  // (\" => \\\") && (" => \") =
+  // (\" => \\") +
+  $arg = preg_replace('/\\\"/', '\\\\\\"', $arg);
+  // + (" => \")
+  $arg = preg_replace('/"/', '\\"', $arg);
+
+  // The same with single quotes.
+  // (\' => \\\') && (' => \') =
+  // (\' => \\') +
+  $arg = preg_replace('/\\\'/', '\\\\\\\'', $arg);
+  // + (' => \')
+  $arg = preg_replace('/\'/', '\\\'', $arg);
+
+  // Replace "\t", "\n", "\r", "\0", "\x0B" with a whitespace.
+  $arg = str_replace(array("\t", "\n", "\r", "\0", "\x0B"), ' ', $arg);
+
+  // Add surrounding quotes.
+  $arg = '"' . $arg . '"';
+
+  return $arg;
+}
+
+/**
+ * Stores output for the most recent shell command.
+ * This should only be run from drush_shell_exec().
+ *
+ * @param $output
+ *   The output of the most recent shell command.
+ *   If this is not set the stored value will be returned.
+ */
+function _drush_shell_exec_output_set($output = FALSE) {
+  static $stored_output;
+  if ($output === FALSE) return $stored_output;
+  $stored_output = $output;
+}
+
+/**
+ * Returns the output of the most recent shell command as an array of lines.
+ */
+function drush_shell_exec_output() {
+  return _drush_shell_exec_output_set();
+}
+
+/**
+ * Download a file using wget or curl.
+ *
+ * @param string $url
+ *   The path to the file to download
+ *
+ * @return string
+ *   The filename that was downloaded,
+ *   or NULL if the file could not be
+ *   downloaded.
+ */
+function _drush_download_file($url) {
+  $filename = explode('/', $url);
+  $filename = array_pop($filename);
+
+  if (!drush_shell_exec("wget %s", $url)) {
+    if(!drush_shell_exec("curl -O %s", $url)) {
+      return NULL;
+    }
+  }
+
+  return $filename;
+}
+
+/**
+ * Extract a tarball.
+ *
+ * @param string $path
+ *   The name of the .tar.gz or .tgz file to be extracted.
+ * @param string $destination
+ *   The destination directory the tarball should be extracted into.
+ *   Optional, if ommitted the tarball directory will be used as destination.
+ * @param boolean $listing
+ *   If TRUE, a listing of the tar contents will be returned on success.
+ *
+ * @return string
+ *   TRUE on success, FALSE on fail. If $listing is TRUE, a file listing of the
+ *   tarball is returned if the extraction reported success, instead of TRUE.
+ */
+function drush_tarball_extract($path, $destination = FALSE, $listing = FALSE) {
+  if (!file_exists($path)) {
+    return drush_set_error('TARBALL_EXTRACT_NOT_FOUND', dt('Tarball !path could not be found.', array('!path' => $path)));
+  }
+  $olddir = getcwd();
+  if (!$destination) {
+    $destination = dirname($path);
+  }
+  if (!is_writeable($destination)) {
+    return drush_set_error('TARBALL_EXTRACT_DESTINATION', dt('Extracting !path failed, as the destination directory !dest was not found or could not be written to.', array('!path' => $path, '!dest' => $dest)));
+  }
+  // If we are not on Windows, then try to do "tar" in a single operation.
+  if ((!drush_is_windows()) && (drush_shell_cd_and_exec(dirname($path), "tar -C %s -xzf %s", $destination, basename($path)))) {
+    if ($listing) {
+      // We use a separate tar -tf instead of -xvf above because
+      // the output is not the same in Mac.
+      drush_shell_cd_and_exec(dirname($path), "tar -tf %s", basename($path));
+      return drush_shell_exec_output();
+    }
+    return TRUE;
+  }
+  // If we could not get the single-op tar to work, do it in three steps.
+  // Copy the source tarball to the destination directory.  Rename to a temp name in case the destination directory == dirname($path)
+  $paths_basename = basename(basename($path, '.tar.gz'), '.tgz');
+  $tarball = drush_tempnam($paths_basename, $destination) . ".tar.gz";
+  drush_register_file_for_deletion($tarball);
+  drush_copy_dir($path, $tarball);
+  $unzipped = $destination . '/' . basename($tarball, ".tar.gz") . ".tar";
+  // We used to use gzip --decompress in --stdout > out, but the output redirection sometimes failed on Windows for some binary output
+  drush_shell_cd_and_exec(dirname($tarball), "gzip --decompress %s", $tarball);
+  if (file_exists($unzipped)) {
+    drush_register_file_for_deletion($unzipped);
+    if (drush_shell_cd_and_exec(dirname($unzipped), "tar -xf %s", basename($unzipped))) {
+      if ($listing) {
+        // We use a separate tar -tf instead of -xf above because
+        // the output is not the same in Mac.
+        drush_shell_cd_and_exec(dirname($unzipped), "tar -tf %s", basename($unzipped));
+        return drush_shell_exec_output();
+      }
+      return TRUE;
+    }
+    return drush_set_error('TARBALL_EXTRACT_TAR_FAIL', dt('Extracting !path using the tar command failed.', array('!path' => $path)));
+  }
+  else {
+    return drush_set_error('TARBALL_EXTRACT_GZIP_FAIL', dt('Uncompressing !path using  the gzip command failed.', array('!path' => $path)));
+  }
+}
+
+/**
+ * @} End of "defgroup commandwrappers".
+ */
+
+/**
+ * @defgroup filesystemfunctions Filesystem convenience functions.
+ * @{
+ */
+
+/**
+ * Deletes the provided file or folder and everything inside it.
+ *
+ * @param $dir
+ *   The directory to delete
+ * @return
+ *   FALSE on failure, TRUE if everything was deleted
+ */
+function drush_delete_dir($dir) {
+  if (!file_exists($dir)) {
+    return TRUE;
+  }
+  if (!is_dir($dir)) {
+    return unlink($dir);
+  }
+  foreach (scandir($dir) as $item) {
+    if ($item == '.' || $item == '..') {
+      continue;
+    }
+    if (!drush_delete_dir($dir.'/'.$item)) {
+      return FALSE;
+    }
+  }
+  return rmdir($dir);
+}
+
+/**
+ * Copy $src to $dest.
+ *
+ * @param $src
+ *   The directory to copy.
+ * @param $dest
+ *   The destination to copy the source to, including the new name of
+ *   the directory.  To copy directory "a" from "/b" to "/c", then
+ *   $src = "/b/a" and $dest = "/c/a".  To copy "a" to "/c" and rename
+ *   it to "d", then $dest = "/c/d".
+ * @param $overwrite
+ *   If TRUE, the destination will be deleted if it exists.
+ * @return
+ *   TRUE on success, FALSE on failure.
+ */
+function drush_copy_dir($src, $dest, $overwrite = FALSE) {
+  // Preflight based on $overwrite if $dest exists.
+  if (file_exists($dest)) {
+    if ($overwrite) {
+      drush_op('drush_delete_dir', $dest);
+    }
+    else {
+      return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
+    }
+  }
+  // $src readable?
+  if (!drush_op('is_readable', $src)) {
+    return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !src is not readable or does not exist.', array('!src' => $src)));
+  }
+  // $dest writable?
+  if (!drush_op('is_writable', dirname($dest))) {
+    return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
+  }
+  // Try to do a recursive copy.
+  if (@drush_op('_drush_recursive_copy', $src, $dest)) {
+    return TRUE;
+  }
+
+  return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Unable to copy !src to !dest.', array('src' => $src, 'dest' => $dest)));
+}
+
+/**
+ * Internal function called by drush_copy_dir; do not use directly.
+ */
+function _drush_recursive_copy($src, $dest) {
+  // all subdirectories and contents:
+  if(is_dir($src)) {
+    drush_mkdir($dest);
+    $dir_handle = opendir($src);
+    while($file = readdir($dir_handle)) {
+      if ($file != "." && $file != "..") {
+        if (_drush_recursive_copy("$src/$file", "$dest/$file") !== TRUE) {
+          return FALSE;
+        }
+      }
+    }
+    closedir($dir_handle);
+  }
+  elseif (drush_op('copy', $src, $dest) !== TRUE) {
+    return FALSE;
+  }
+
+  // Preserve permissions
+  if (!drush_is_windows()) {
+    chmod($dest, intval(fileperms($src), 8));
+  }
+
+  return TRUE;
+}
+
+/**
+ * Move $src to $dest.
+ *
+ * If the php 'rename' function doesn't work, then we'll do copy & delete.
+ *
+ * @param $src
+ *   The directory to move.
+ * @param $dest
+ *   The destination to move the source to, including the new name of
+ *   the directory.  To move directory "a" from "/b" to "/c", then
+ *   $src = "/b/a" and $dest = "/c/a".  To move "a" to "/c" and rename
+ *   it to "d", then $dest = "/c/d" (just like php rename function).
+ * @param $overwrite
+ *   If TRUE, the destination will be deleted if it exists.
+ * @return
+ *   TRUE on success, FALSE on failure.
+ */
+function drush_move_dir($src, $dest, $overwrite = FALSE) {
+  // Preflight based on $overwrite if $dest exists.
+  if (file_exists($dest)) {
+    if ($overwrite) {
+      drush_op('drush_delete_dir', $dest);
+    }
+    else {
+      return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
+    }
+  }
+  // $src readable?
+  if (!drush_op('is_readable', $src)) {
+    return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !src is not readable or does not exist.', array('!src' => $src)));
+  }
+  // $dest writable?
+  if (!drush_op('is_writable', dirname($dest))) {
+    return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
+  }
+  // Try rename. It will fail if $src and $dest are not in the same partition.
+  if (@drush_op('rename', $src, $dest)) {
+    return TRUE;
+  }
+  // Eventually it will create an empty file in $dest. See
+  // http://www.php.net/manual/es/function.rename.php#90025
+  elseif (is_file($dest)) {
+    drush_op('unlink', $dest);
+  }
+
+  // If 'rename' fails, then we will use copy followed
+  // by a delete of the source.
+  if (drush_copy_dir($src, $dest)) {
+    drush_op('drush_delete_dir', $src);
+    return TRUE;
+  }
+
+  return drush_set_error('DRUSH_MOVE_DIR_FAILURE', dt('Unable to move !src to !dest.', array('!src' => $src, '!dest' => $dest)));
+}
+
+/**
+ * Cross-platform compatible helper function to recursively create a directory tree.
+ * @see http://theserverpages.com/php/manual/en/function.mkdir.php#50383
+ */
+function drush_mkdir($path) {
+  return is_dir($path) || (drush_mkdir(dirname($path)) && drush_shell_exec('mkdir %s', $path));
+}
+
+/**
+ * Save a string to a temporary file. Does not depend on Drupal's API.
+ * The temporary file will be automatically deleted when drush exits.
+ *
+ * @param string $data
+ * @return string
+ *   A path to the file.
+ */
+function drush_save_data_to_temp_file($data) {
+  static $fp;
+
+  $fp = tmpfile();
+  fwrite($fp, $data);
+  $meta_data = stream_get_meta_data($fp);
+  $file = $meta_data['uri'];
+  drush_register_file_for_deletion($file);
+
+  return $file;
+}
+
+/**
+ * Returns the path to a temporary directory.
+ *
+ * This is a custom version of file_directory_path().
+ * We can't directly rely on sys_get_temp_dir() as this
+ * path is not valid in some setups for Mac.
+ */
+function drush_find_tmp() {
+  static $temporary_directory = NULL;
+
+  if (is_null($temporary_directory)) {
+    $directories = array();
+
+    // Operating system specific dirs.
+    if (substr(PHP_OS, 0, 3) == 'WIN') {
+      $directories[] = 'c:\\windows\\temp';
+      $directories[] = 'c:\\winnt\\temp';
+    }
+    else {
+      $directories[] = '/tmp';
+    }
+    // This function exists in PHP 5 >= 5.2.1, but drush
+    // requires PHP 5 >= 5.2.0, so we check for it.
+    if (function_exists('sys_get_temp_dir')) {
+      $directories[] = sys_get_temp_dir();
+    }
+
+    foreach ($directories as $directory) {
+      if (is_dir($directory) && is_writable($directory)) {
+        $temporary_directory = $directory;
+        break;
+      }
+    }
+
+    if (empty($temporary_directory)) {
+      // If no directory has been found, create one in cwd.
+      $temporary_directory = drush_cwd() . '/tmp';
+      drush_mkdir($temporary_directory);
+      if (!is_dir($directory)) {
+        return drush_set_error('DRUSH_UNABLE_TO_CREATE_TMP_DIR', dt("Unable to create a temporary directory."));
+      }
+      drush_register_file_for_deletion($temporary_directory);
+    }
+  }
+
+  return $temporary_directory;
+}
+
+/**
+ * Creates a temporary file, and registers it so that
+ * it will be deleted when drush exits.  Whenever possible,
+ * drush_save_data_to_temp_file() should be used instead
+ * of this function.
+ */
+function drush_tempnam($pattern, $tmp_dir = NULL) {
+  if ($tmp_dir == NULL) {
+    $tmp_dir = drush_find_tmp();
+  }
+  $tmp_file = tempnam($tmp_dir, $pattern);
+  drush_register_file_for_deletion($tmp_file);
+
+  return $tmp_file;
+}
+
+/**
+ * Creates a temporary directory and return its path.
+ */
+function drush_tempdir() {
+  $tmp_dir = rtrim(drush_find_tmp(), DIRECTORY_SEPARATOR);
+  $tmp_dir .= '/' . 'drush_tmp_' . time();
+
+  drush_mkdir($tmp_dir);
+  drush_register_file_for_deletion($tmp_dir);
+
+  return $tmp_dir;
+}
+
+/**
+ * Any file passed in to this function will be deleted
+ * when drush exits.
+ */
+function drush_register_file_for_deletion($file = NULL) {
+  static $registered_files = array();
+
+  if (isset($file)) {
+    if (empty($registered_files)) {
+      register_shutdown_function('_drush_delete_registered_files');
+    }
+    $registered_files[] = $file;
+  }
+
+  return $registered_files;
+}
+
+/**
+ * Delete all of the registered temporary files.
+ */
+function _drush_delete_registered_files() {
+  $files_to_delete = drush_register_file_for_deletion();
+
+  foreach ($files_to_delete as $file) {
+    // We'll make sure that the file still exists, just
+    // in case someone came along and deleted it, even
+    // though they did not need to.
+    if (file_exists($file)) {
+      if (is_dir($file)) {
+        drush_delete_dir($file);
+      }
+      else {
+        unlink($file);
+      }
+    }
+  }
+}
+
+/**
+ * Decide where our backup directory should go
+ *
+ * @param string $subdir
+ *   The name of the desired subdirectory(s) under drush-backups.
+ *   Usually a database name.
+ */
+function drush_preflight_backup_dir($subdir = NULL) {
+  $backup_dir = drush_get_context('DRUSH_BACKUP_DIR', drush_get_option('backup-location'));
+
+  if (empty($backup_dir)) {
+
+    // Try to use db name as subdir if none was provided.
+    if (empty($subdir)) {
+      $subdir = 'unknown';
+      if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
+        $subdir = $creds['name'];
+      }
+    }
+
+    // Save the date to be used in the backup directory's path name.
+    $date = gmdate('YmdHis', $_SERVER['REQUEST_TIME']);
+
+    $backup_dir = drush_get_option('backup-dir', drush_server_home() . '/' . 'drush-backups');
+    $backup_dir = rtrim($backup_dir, DIRECTORY_SEPARATOR) . '/' . $subdir . '/' . $date;
+    drush_set_context('DRUSH_BACKUP_DIR', $backup_dir);
+  }
+  return $backup_dir;
+}
+
+/**
+ * Prepare a backup directory
+ */
+function drush_prepare_backup_dir($subdir = NULL) {
+  $backup_dir = drush_preflight_backup_dir($subdir);
+  $backup_parent = dirname($backup_dir);
+
+  $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
+
+  if ((!empty($drupal_root)) && (strpos($backup_parent, $drupal_root) === 0)) {
+    return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('It\'s not allowed to store backups inside the Drupal root directory.'));
+  }
+  if (!file_exists($backup_parent)) {
+    if (!drush_mkdir($backup_parent)) {
+      return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Unable to create backup directory !dir.', array('!dir' => $backup_parent)));
+    }
+  }
+  if (!is_writable($backup_parent)) {
+    return drush_set_error('DRUSH_PM_BACKUP_FAILED', dt('Backup directory !dir is not writable.', array('!dir' => $backup_parent)));
+  }
+
+  drush_mkdir($backup_dir);
+  return $backup_dir;
+}
+
+/**
+ * @} End of "defgroup filesystemfunctions".
+ */
+
+/**
+ * @defgroup dbfunctions Database convenience functions.
+ * @{
+ */
+
+/**
+ * Replace named placeholders in a WHERE snippet.
+ *
+ * Helper function to allow the usage of Drupal 7 WHERE snippets
+ * with named placeholders in code for Drupal 5 and 6.
+ *
+ * @param $where
+ *   String with a WHERE snippet using named placeholders.
+ * @param $args
+ *   Array of placeholder values.
+ * @return
+ *   String. $where filled with literals from $args.
+ */
+function _drush_replace_query_placeholders($where, $args) {
+  foreach ($args as $key => $data) {
+    if (is_array($data)) {
+      $new_keys = array();
+      // $data can't have keys that are a prefix of other keys to
+      // prevent a corrupted result in the below calls to str_replace().
+      // To avoid this we will use a zero padded indexed array of the values of $data.
+      $pad_length = strlen((string)count(array_values($data)));
+      foreach (array_values($data) as $i => $value) {
+        if (!is_numeric($value)) {
+          $value = "'".$value."'";
+        }
+        $new_keys[$key . '_' . str_pad($i, $pad_length, '0', STR_PAD_LEFT)] = $value;
+      }
+      $where = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $where);
+      unset($args[$key]);
+      $args += $new_keys;
+    }
+    else if (!is_numeric($data)) {
+      $args[$key] = "'".$data."'";
+    }
+  }
+
+  foreach ($args as $key => $data) {
+    $where = str_replace($key, $data, $where);
+  }
+
+  return $where;
+}
+
+/**
+ * A db_select() that works for any version of Drupal.
+ *
+ * @param $table
+ *   String. The table to operate on.
+ * @param $fields
+ *   Array or string. Fields affected in this operation. Valid string values are '*' or a single column name.
+ * @param $where
+ *   String. WHERE snippet for the operation. It uses named placeholders. see @_drush_replace_query_placeholders()
+ * @param $args
+ *   Array. Arguments for the WHERE snippet.
+ * @param $start
+ *   Int. Value for OFFSET.
+ * @param $length
+ *   Int. Value for LIMIT.
+ * @param $order_by_field
+ *   String. Database column to order by.
+ * @param $order_by_direction
+ *   ('ASC', 'DESC'). Ordering direction.
+ * @return
+ *   A database resource.
+ */
+function drush_db_select($table, $fields = '*', $where = NULL, $args = NULL, $start = NULL, $length = NULL, $order_by_field = NULL, $order_by_direction = 'ASC') {
+  if (drush_drupal_major_version() >= 7) {
+    if (!is_array($fields)) {
+      if ($fields == '*') {
+        $fields = array();
+      }
+      else {
+        $fields = array($fields);
+      }
+    }
+    $query = db_select($table, $table)
+      ->fields($table, $fields);
+    if (!empty($where)) {
+      $query = $query->where($where, $args);
+    }
+    if (!is_null($order_by_field)) {
+      $query = $query->orderBy($order_by_field, $order_by_direction);
     }
-    print $prompt;
+    if (!is_null($length)) {
+      $query = $query->range($start, $length);
+    }
+    return $query->execute();
   }
-  fclose($stdin);
-  return $line;
-}
-
-/**
- * Print a formatted table.
- *
- * @param $rows
- *   The rows to print.
- * @param $header
- *   If TRUE, the first line will be treated as table header.
- * @param $widths
- *   The widths of each column (in characters) to use - if not specified this
- *   will be determined automatically, based on a "best fit" algorithm.
- */
-function drush_print_table($rows, $header = FALSE, $widths = array()) {
-  $tbl = new Console_Table(CONSOLE_TABLE_ALIGN_LEFT , '');
-
-  $auto_widths = drush_table_column_autowidth($rows, $widths);
-
-  // Do wordwrap on all cells.
-  $newrows = array();
-  foreach ($rows as $rowkey => $row) {
-    foreach ($row as $col_num => $cell) {
-      $newrows[$rowkey][$col_num] = wordwrap($cell, $auto_widths[$col_num], "\n", TRUE);
-      if (isset($widths[$col_num])) {
-        $newrows[$rowkey][$col_num] = str_pad($newrows[$rowkey][$col_num], $widths[$col_num]);
+  else {
+    if (is_array($fields)) {
+      $fields = implode(', ', $fields);
+    }
+    $query = "SELECT $fields FROM {{$table}}";
+    if (!empty($where)) {
+      $where = _drush_replace_query_placeholders($where, $args);
+      $query .= " WHERE ".$where;
+    }
+    if (!is_null($order_by_field)) {
+      $query .= " ORDER BY $order_by_field $order_by_direction";
+    }
+    if (!is_null($length)) {
+      $limit = " LIMIT $length";
+      if (!is_null($start)) {
+        $limit .= " OFFSET $start";
       }
+      $query .= $limit;
     }
-  }
-  if ($header) {
-    $headers = array_shift($newrows);
-    $tbl->setHeaders($headers);
-  }
 
-  $tbl->addData($newrows);
-  $output = $tbl->getTable();
-  if (!stristr(PHP_OS, 'WIN')) {
-    $output = str_replace("\r\n", PHP_EOL, $output);
+    return db_query($query, $args);
   }
-  drush_print($output);
-  return $tbl;
 }
 
 /**
- * Convert an associative array of key : value pairs into
- * a table suitable for processing by drush_print_table.
+ * A db_delete() that works for any version of Drupal.
  *
- * @param $keyvalue_table
- *    An associative array of key : value pairs.
+ * @param $table
+ *   String. The table to operate on.
+ * @param $where
+ *   String. WHERE snippet for the operation. It uses named placeholders. see @_drush_replace_query_placeholders()
+ * @param $args
+ *   Array. Arguments for the WHERE snippet.
  * @return
- *    An array of arrays, where the keys from the input
- *    array are stored in the first column, and the values
- *    are stored in the third.  A second colum is created
- *    specifically to hold the ':' separator.
+ *   Affected rows (except on D7+mysql without a WHERE clause - returns TRUE) or FALSE.
  */
-function drush_key_value_to_array_table($keyvalue_table) {
-  $table = array();
-  foreach ($keyvalue_table as $key => $value) {
-    if (isset($value)) {
-      $table[] = array($key, ' :', $value);
+function drush_db_delete($table, $where = NULL, $args = NULL) {
+  if (drush_drupal_major_version() >= 7) {
+    if (!empty($where)) {
+      $query = db_delete($table)->where($where, $args);
+      return $query->execute();
     }
     else {
-      $table[] = array($key . ':', '', '');
+      return db_truncate($table)->execute();
     }
   }
-  return $table;
+  else {
+    $query = "DELETE FROM {{$table}}";
+    if (!empty($where)) {
+      $where = _drush_replace_query_placeholders($where, $args);
+      $query .= ' WHERE '.$where;
+    }
+    if (!db_query($query, $args)) {
+      return FALSE;
+    }
+    return db_affected_rows();
+  }
 }
 
 /**
- * Determine the best fit for column widths.
+ * A db_result() that works consistently for any version of Drupal.
  *
- * @param $rows
- *   The rows to use for calculations.
- * @param $widths
- *   Manually specified widths of each column (in characters) - these will be
- *   left as is.
+ * @param
+ *   A Database result object.
  */
-function drush_table_column_autowidth($rows, $widths) {
-  $auto_widths = $widths;
-
-  // First we determine the distribution of row lengths in each column.
-  // This is an array of descending character length keys (i.e. starting at
-  // the rightmost character column), with the value indicating the number
-  // of rows where that character column is present.
-  $col_dist = array();
-  foreach ($rows as $rowkey => $row) {
-    foreach ($row as $col_num => $cell) {
-      if (empty($widths[$col_num])) {
-        $length = strlen($cell);
-        while ($length > 0) {
-          if (!isset($col_dist[$col_num][$length])) {
-            $col_dist[$col_num][$length] = 0;
-          }
-          $col_dist[$col_num][$length]++;
-          $length--;
-        }
-      }
-    }
-  }
-  foreach ($col_dist as $col_num => $count) {
-    // Sort the distribution in decending key order.
-    krsort($col_dist[$col_num]);
-    // Initially we set all columns to their "ideal" longest width
-    // - i.e. the width of their longest column.
-    $auto_widths[$col_num] = max(array_keys($col_dist[$col_num]));
-  }
-
-  // We determine what width we have available to use, and what width the
-  // above "ideal" columns take up.
-  $available_width = drush_get_context('DRUSH_COLUMNS', 80) - (count($auto_widths) * 2);
-  $auto_width_current = array_sum($auto_widths);
-
-  // If we need to reduce a column so that we can fit the space we use this
-  // loop to figure out which column will cause the "least wrapping",
-  // (relative to the other columns) and reduce the width of that column.
-  while ($auto_width_current > $available_width) {
-    $count = 0;
-    $width = 0;
-    foreach ($col_dist as $col_num => $counts) {
-      // If we are just starting out, select the first column.
-      if ($count == 0 ||
-         // OR: if this column would cause less wrapping than the currently
-         // selected column, then select it.
-         (current($counts) < $count) ||
-         // OR: if this column would cause the same amount of wrapping, but is
-         // longer, then we choose to wrap the longer column (proportionally
-         // less wrapping, and helps avoid triple line wraps).
-         (current($counts) == $count && key($counts) > $width)) {
-        // Select the column number, and record the count and current width
-        // for later comparisons.
-        $column = $col_num;
-        $count = current($counts);
-        $width = key($counts);
+function drush_db_result($result) {
+  switch (drush_drupal_major_version()) {
+    case 5:
+      // In versions of Drupal <= 5, db_result only returns the first row no matter how
+      //  many times you call it. So instead of calling it here, we use db_fetch_array which
+      //  does increment the pointer to the next row (as db_result does on Drupal 6)
+      if ($array = db_fetch_array($result)) {
+        return array_shift($array); // return first element in array.
       }
-    }
-    if ($width <= 1) {
-      // If we have reached a width of 1 then give up, so wordwrap can still progress.
-      break;
-    }
-    // Reduce the width of the selected column.
-    $auto_widths[$column]--;
-    // Reduce our overall table width counter.
-    $auto_width_current--;
-    // Remove the corresponding data from the disctribution, so next time
-    // around we use the data for the row to the left.
-    unset($col_dist[$column][$width]);
+      return FALSE;
+    case 6:
+      return db_result($result);
+    case 7:
+    default:
+      return $result->fetchField();
   }
-  return $auto_widths;
 }
 
 /**
- * Cross-platform compatible helper function to recursively create a directory tree.
- * @see http://theserverpages.com/php/manual/en/function.mkdir.php#50383
+ * A db_fetch_object() that works for any version of Drupal.
+ *
+ * @param
+ *   A Database result object.
  */
-function drush_mkdir($path) {
-  return is_dir($path) || (drush_mkdir(dirname($path)) && drush_shell_exec('mkdir %s', $path));
+function drush_db_fetch_object($result) {
+  return drush_drupal_major_version() >= 7 ? $result->fetchObject() : db_fetch_object($result);
 }
 
 /**
- * @defgroup dispatching Command dispatching functions.
+ * @} End of "defgroup dbfunctions".
+ */
+
+/**
+ * @defgroup commandprocessing Command processing functions.
  * @{
  *
- * These functions manage parameter and option manipulation
- * for calls to drush backend invoke.
+ * These functions manage command processing by the
+ * main function in drush.php.
  */
 
 /**
@@ -1360,23 +2129,50 @@ function drush_remote_command() {
     if (!is_array($site_list)) {
       $site_list = explode(',', $site_list);
     }
+    $site_list = drush_sitealias_resolve_sitespecs($site_list);
+    $site_list = drush_sitealias_simplify_names($site_list);
     $args = drush_get_arguments();
 
     if (!drush_get_context('DRUSH_SIMULATE')) {
       drush_print(dt("You are about to execute '!command' on all of the following targets:", array('!command' => implode(" ", $args))));
-      foreach ($site_list as $one_destination) {
+      foreach ($site_list as $one_destination => $one_record) {
         drush_print(dt('  !target', array('!target' => $one_destination)));
       }
 
       if (drush_confirm('Continue? ') === FALSE) {
-         drush_user_abort();
+        drush_user_abort();
+        return TRUE;
       }
     }
     $command = array_shift($args);
-
-    foreach ($site_list as $site_spec) {
-      $values = drush_do_site_command(_drush_sitealias_get_record($site_spec), $command, $args);
-      drush_print($values['output']);
+    $multi_options = drush_get_context('cli');
+
+    if (!drush_get_option('no-label', FALSE)) {
+      $label_separator = ' >> ';
+      $max_name_length = 0;
+      foreach ($site_list as $alias_name => $alias_record) {
+        if (strlen($alias_name) > $max_name_length) {
+          $max_name_length = strlen($alias_name);
+        }
+      }
+      $multi_options['reserve-margin'] = $max_name_length + strlen($label_separator);
+      foreach ($site_list as $alias_name => $alias_record) {
+        $values = drush_do_site_command($alias_record, $command, $args, $multi_options);
+        foreach (explode("\n", $values['output']) as $line) {
+          if (empty($line)) {
+            drush_print();
+          }
+          else {
+            drush_print(str_pad($alias_name, $max_name_length, " ") . $label_separator . $line);
+          }
+        }
+      }
+    }
+    else {
+      foreach ($site_list as $alias_name => $alias_record) {
+        $values = drush_do_site_command($alias_record, $command, $args, $multi_options);
+        drush_print($values['output']);
+      }
     }
     return TRUE;
   }
@@ -1422,7 +2218,7 @@ function drush_do_multiple_command($command, $source_record, $destination_record
       }
 
       if (drush_confirm('Continue? ') === FALSE) {
-         drush_user_abort();
+         return drush_user_abort();
       }
     }
 
@@ -1444,6 +2240,13 @@ function drush_do_multiple_command($command, $source_record, $destination_record
   return $is_multiple_command;
 }
 
+/**
+ * Run a command on the site specified by the provided command record.
+ *
+ * The standard function that provides this service is called
+ * drush_invoke_sitealias_args.  Please call the standard function
+ * unless you need to set $integrate = TRUE.
+ */
 function drush_do_site_command($site_record, $command, $args = array(), $data = array(), $integrate = FALSE) {
   $values = NULL;
   if (!empty($site_record)) {
@@ -1452,14 +2255,7 @@ function drush_do_site_command($site_record, $command, $args = array(), $data =
         $data[$key] = $site_record[$key];
       }
     }
-    
-    $drush_path = NULL;
-    if (array_key_exists('path-aliases', $site_record)) {
-      if (array_key_exists('%drush-script', $site_record['path-aliases'])) {
-        $drush_path = $site_record['path-aliases']['%drush-script'];
-      }
-    }
-    $values = drush_backend_invoke_args($command, $args, $data, 'GET', $integrate, $drush_path, array_key_exists('remote-host', $site_record) ? $site_record['remote-host'] : NULL, array_key_exists('remote-user', $site_record) ? $site_record['remote-user'] : NULL, array_key_exists('ssh-options', $site_record) ? $site_record['ssh-options'] : NULL);
+    $values = drush_backend_invoke_sitealias($site_record, $command, $args, $data, 'GET', $integrate);
   }
   return $values;
 }
@@ -1489,47 +2285,9 @@ function drush_do_command_redispatch($command, $args = array(), $remote_host = N
   return $values;
 }
 
-/**
- * Get the options for this command.
- *
- * This function returns an array that contains all of the options
- * that are appropriate for forwarding along to backend invoke.
- * Pass the result from this function to backend invoke in the $data
- * parameter when doing a redispatch.
- */
-function drush_redispatch_get_options() {
-  // Start off by taking everything from the site alias and command line
-  // ('options' context)
-  $options = array_merge(drush_get_context('alias'), drush_get_context('options'));
-  $options = array_diff_key($options, array_flip(drush_sitealias_site_selection_keys()));
-  unset($options['command-specific']);
-  unset($options['path-aliases']);
-  // If we can parse the current command, then examine all contexts
-  // in order for any option that is directly related to the current command
-  $command = drush_parse_command();
-  if (is_array($command)) {
-    foreach ($command['options'] as $key => $value) {
-      // Strip leading --
-      $key = ltrim($key, '-');
-      $value = drush_get_option($key);
-      if (isset($value)) {
-        $options[$key] = $value;
-      }
-    }
-  }
-  // 'php', if needed, will be included in DRUSH_COMMAND.  If DRUSH_COMMAND
-  // is not used (e.g. when calling a remote instance of drush), then --php
-  // should not be passed along.
-  unset($options['php']);
-  // If --bootstrap-to-first-arg is specified, do not
-  // pass it along to remote commands.
-  unset($options['bootstrap-to-first-arg']);
-  
-  return $options;
-}
 
 /**
- * @} End of "defgroup dispatching".
+ * @} End of "defgroup commandprocessing".
  */
 
 /**
@@ -1626,7 +2384,7 @@ function _drush_print_log($entry) {
   else {
     $red = "\033[31;40m\033[1m[%s]\033[0m";
     $yellow = "\033[1;33;40m\033[1m[%s]\033[0m";
-    $green = "\033[0;33;40m\033[1m[%s]\033[0m";
+    $green = "\033[1;32;40m\033[1m[%s]\033[0m";
   }
 
   $verbose = drush_get_context('DRUSH_VERBOSE');
@@ -1635,6 +2393,7 @@ function _drush_print_log($entry) {
   $return = TRUE;
   switch ($entry['type']) {
     case 'warning' :
+    case 'cancel' :
       $type_msg = sprintf($yellow, $entry['type']);
       break;
     case 'failed' :
@@ -1645,12 +2404,12 @@ function _drush_print_log($entry) {
     case 'ok' :
     case 'completed' :
     case 'success' :
+    case 'status':
       $type_msg = sprintf($green, $entry['type']);
       break;
     case 'notice' :
     case 'message' :
     case 'info' :
-    case 'status':
       if (!$verbose) {
         // print nothing. exit cleanly.
         return TRUE;
@@ -1667,8 +2426,9 @@ function _drush_print_log($entry) {
   }
 
   // When running in backend mode, log messages are not displayed, as they will
-  // be returned in the JSON encoded associative array.
-  if (drush_get_context('DRUSH_BACKEND')) {
+  // be returned in the JSON encoded associative array.  In quiet mode, we
+  // just drop log messages.
+  if (drush_get_context('DRUSH_BACKEND') || drush_get_context('DRUSH_QUIET')) {
     return $return;
   }
 
@@ -1690,7 +2450,7 @@ function _drush_print_log($entry) {
   $lines = explode("\n", $message);
   $lines[0] = sprintf($format, $lines[0], $type_msg);
   $message = implode("\n", $lines);
-  drush_print($message);
+  drush_print($message, 0, STDERR);
   return $return;
 }
 
@@ -1724,7 +2484,7 @@ function drush_print_timers() {
       }
       $table[] = array($name, $cum, $count, $avg);
     }
-    drush_print_table($table, TRUE);
+    drush_print_table($table, TRUE, array(), STDERR);
   }
 }
 
@@ -1828,9 +2588,28 @@ function system_watchdog($log_entry) {
   else {
     $message = $log_entry['message'];
   }
-  $message = strip_tags(decode_entities($message));
-  // Log it.
-  drush_log('WD '. $log_entry['type'] . ': '.$message, $severity);
+
+  // decode_entities() only loaded after FULL bootstrap.
+  if (function_exists('decode_entities')) {
+    $message = decode_entities($message);
+  }
+  $message = strip_tags($message);
+
+  // Log or print or ignore. Just printing saves memory but thats rarely needed.
+  switch (drush_get_option('watchdog', 'log')) {
+    case 'log':
+      drush_log('WD '. $log_entry['type'] . ': ' . $message, $severity);
+      break;
+    case 'print':
+      // Disable in backend mode since it logs output and the goal is to conserve memory.
+      // @see _drush_bootstrap_drush().
+      if (ob_get_length() === FALSE) {
+        drush_print('WD '. $severity . ' ' . $log_entry['type'] . ': ' . $message);
+      }
+      break;
+    default:
+      // Do nothing.
+  }
 }
 
 /**
@@ -1963,6 +2742,17 @@ function drush_cmp_error($error) {
   return array_key_exists($error, $error_log);
 }
 
+/**
+ * Exit due to user declining a confirmation prompt.
+ *
+ * Usage:  return drush_user_abort();
+ */
+function drush_user_abort($msg = NULL) {
+  drush_set_context('DRUSH_USER_ABORT', TRUE);
+  drush_log($msg ? $msg : dt('Aborting.'), 'cancel');
+  return FALSE;
+}
+
 /**
  * Turn PHP error handling off.
  *
@@ -2024,10 +2814,35 @@ function drush_memory_limit() {
  * data structure.
  */
 function drush_unset_recursive(&$data, $unset_key) {
-  unset($data[$unset_key]);
-  foreach ($data as $key => $value) {
-    if (is_array($value)) {
-      drush_unset_recursive($data[$key], $unset_key);
+  if (!empty($data) && is_array($data)) {
+    unset($data[$unset_key]);
+    foreach ($data as $key => $value) {
+      if (is_array($value)) {
+        drush_unset_recursive($data[$key], $unset_key);
+      }
     }
   }
 }
+
+/**
+ * Return a list of VCSs reserved files and directories.
+ */
+function drush_version_control_reserved_files() {
+  static $files = FALSE;
+
+  if (!$files) {
+    // Also support VCSs that are not drush vc engines.
+    $files = array('.git', '.gitignore', '.hg', '.hgignore', '.hgrags');
+    $vcs = array_keys(drush_get_engines('version_control'));
+    foreach ($vcs as $name) {
+      drush_include_engine('version_control', $name);
+      $class = 'drush_pm_version_control_' . $name;
+      // For php < 5.3 we can't access a static method by referencing the class
+      // using a variable.
+      $version_control = new $class();
+      $files = array_merge($files, $version_control->reserved_files());
+    }
+  }
+
+  return $files;
+}
diff --git a/sites/all/modules/drush/includes/environment.inc b/sites/all/modules/drush/includes/environment.inc
index b33465f82127ad66de7b6f5eb2ac000d2f80e316..5e04bb7d8c0e37e8f8fb4d942d6de1649a8bfbcd 100644
--- a/sites/all/modules/drush/includes/environment.inc
+++ b/sites/all/modules/drush/includes/environment.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: environment.inc,v 1.104 2010/12/01 15:53:15 jonhattan Exp $
 
 /**
  * @file
@@ -26,6 +25,15 @@ define('DRUSH_DRUPAL_BOOTSTRAP', 'includes/bootstrap.inc');
  */
 define('DRUSH_BOOTSTRAP_NONE', -1);
 
+/**
+ * Use drush_bootstrap_max instead of drush_bootstrap_to_phase
+ *
+ * This constant is only usable as the value of the 'bootstrap'
+ * item of a command object, or as the parameter to
+ * drush_bootstrap_to_phase.  It is not a real bootstrap state.
+ */
+define('DRUSH_BOOTSTRAP_MAX', -2);
+
 /**
  * Only bootstrap Drush, without any Drupal specific code.
  *
@@ -214,7 +222,7 @@ function drush_bootstrap($phase, $phase_max = FALSE) {
  */
 function drush_has_boostrapped($phase) {
   $phase_index = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
-  
+
   return isset($phase_index) && ($phase_index >= $phase);
 }
 
@@ -277,6 +285,15 @@ function drush_bootstrap_validate($phase) {
  *   Only attempt bootstrap to the specified level.
  */
 function drush_bootstrap_to_phase($max_phase_index) {
+  // If $max_phase_index is DRUSH_BOOTSTRAP_MAX, then
+  // we will bootstrap as far as we can.  drush_bootstrap_max
+  // is different than drush_bootstrap_to_phase in that
+  // it is not an error if DRUSH_BOOTSTRAP_LOGIN is not reached.
+  if ($max_phase_index == DRUSH_BOOTSTRAP_MAX) {
+    drush_bootstrap_max();
+    return TRUE;
+  }
+
   drush_log(dt("Bootstrap to phase !phase.", array('!phase' => $max_phase_index)), 'bootstrap');
   $phases = _drush_bootstrap_phases();
   $result = TRUE;
@@ -448,29 +465,64 @@ function _drush_postmortem() {
  * begins.  If the php environment is too restrictive, then
  * notify the user that a setting change is needed and abort.
  */
-function _drush_environment_preflight_checks() {
+function _drush_environment_check_php_ini() {
+  $ini_checks = array('safe_mode' => '', 'open_basedir' => '', 'disable_functions' => array('exec', 'system'), 'disable_classes' => '');
+
   // Test to insure that certain php ini restrictions have not been enabled
   $prohibited_list = array();
-  foreach (array('safe_mode', 'open_basedir', 'disable_functions', 'disable_classes') as $prohibited_mode) {
-    if (ini_get($prohibited_mode)) {
+  foreach ($ini_checks as $prohibited_mode => $disallowed_value) {
+    $ini_value = ini_get($prohibited_mode);
+    $invalid_value = FALSE;
+    if (empty($disallowed_value)) {
+      $invalid_value = !empty($ini_value);
+    }
+    else {
+      foreach ($disallowed_value as $test_value) {
+        if (strstr($ini_value, $test_value) !== FALSE) {
+          $invalid_value = TRUE;
+        }
+      }
+    }
+    if ($invalid_value) {
       $prohibited_list[] = $prohibited_mode;
     }
   }
   if (!empty($prohibited_list)) {
-    return drush_bootstrap_error('DRUSH_PHP_INI_RESTRICTIONS', dt('The following restricted PHP modes have non-empty values: !prohibited_list. This configuration is incompatible with drush.  !php_ini_msg', array('!prohibited_list' => implode(' and ', $prohibited_list), '!php_ini_msg' => _drush_php_ini_loaded_file_message())));
+    drush_log(dt('The following restricted PHP modes have non-empty values: !prohibited_list. This configuration is incompatible with drush.  !php_ini_msg', array('!prohibited_list' => implode(' and ', $prohibited_list), '!php_ini_msg' => _drush_php_ini_loaded_file_message())), 'error');
   }
-  
+
   return TRUE;
 }
 
 /**
- * Validate initial Drush bootstrap phase.
+ * Validate that Drush is running in a suitable environment.
  */
 function _drush_bootstrap_drush_validate() {
-  if (($preflight_result = _drush_environment_preflight_checks()) !== TRUE) {
-    return $preflight_result;
+  // @todo _drush_environment_php_ini_checks() always returns TRUE.
+  $return = _drush_environment_check_php_ini();
+  if ($return !== TRUE) {
+    return $return;
+  }
+
+  if (drush_environment_table_inc() === FALSE) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*
+ * To disable the warning about Windows support, set $options['check_os'] = FALSE
+ * in drushrc.php. See examples/example.drushrc.php.
+ */
+function drush_environment_check_os() {
+  if (substr(PHP_OS, 0, 3) == 'WIN' && (drush_get_option('check_os', TRUE) !== 'i-want-4.x')) {
+    $msg = 'Drush 4.x has significant limitations on Windows; it is not advisable to use on that platform. Substantial progress has been made towards supporing Windows on the 5.x branch; please upgrade. See http://drupal.org/project/drush for more information.';
+    drush_log(dt($msg), 'warning');
   }
-  
+}
+
+function drush_environment_table_inc() {
   // try using the PEAR installed version of Console_Table
   $tablefile = 'Console/Table.php';
   if (@file_get_contents($tablefile, FILE_USE_INCLUDE_PATH) === FALSE) {
@@ -489,6 +541,10 @@ function _drush_bootstrap_drush_validate() {
       }
       if (!file_exists($tablefile)) {
         drush_shell_exec("wget -q --timeout=30 -O $tablefile " . DRUSH_TABLE_URL);
+        // wget creates an empty file on timeout. We remove it here.
+        if (file_exists($tablefile) && !drush_file_not_empty($tablefile)) {
+          unlink($tablefile);
+        }
         if (!file_exists($tablefile)) {
           drush_shell_exec("curl -s  --connect-timeout 30 -o $tablefile " . DRUSH_TABLE_URL);
           if (!file_exists($tablefile)) {
@@ -499,8 +555,6 @@ function _drush_bootstrap_drush_validate() {
     }
   }
   require_once $tablefile;
-  
-  return TRUE;
 }
 
 /**
@@ -533,21 +587,42 @@ function _drush_bootstrap_drush() {
     // If stty failed, or we couldn't parse it's output, we assume 80 columns.
     if ($stty_status || !$stty_count) $columns = 80;
   }
+  // If a caller wants to reserve some room to add additional
+  // information to the drush output via post-processing, the
+  // --reserve-margin flag can be used to declare how much
+  // space to leave out.  This only affects drush functions
+  // such as drush_print_table that wrap the output.
+  $columns -= drush_get_option('reserve-margin', 0);
   drush_set_context('DRUSH_COLUMNS', $columns);
 
-  // statically define a way to call drush again
+  // Statically define a way to call drush again.
   define('DRUSH_COMMAND', drush_find_drush());
 
   $drush_info = drush_read_drush_info();
   define('DRUSH_VERSION', $drush_info['drush_version']);
 
+  // prime the CWD cache
+  drush_cwd();
+
+  /* Copy ETC_PREFIX and SHARE_PREFIX from environment variables if available.
+   * This alters where we check for server-wide config and alias files.
+   * Used by unit test suite to provide a clean environment.
+   */
+  if (getenv('ETC_PREFIX')) drush_set_context('ETC_PREFIX', getenv('ETC_PREFIX'));
+  if (getenv('SHARE_PREFIX')) drush_set_context('SHARE_PREFIX', getenv('SHARE_PREFIX'));
+
+  drush_set_context('DOC_PREFIX', DRUSH_BASE_PATH);
+  if (!file_exists(DRUSH_BASE_PATH . '/README.txt') && file_exists(drush_get_context('SHARE_PREFIX', '/usr') . '/share/doc/drush') . '/README.txt') {
+    drush_set_context('DOC_PREFIX', drush_get_context('SHARE_PREFIX', '/usr') . '/share/doc/drush');
+  }
+
   // Load a drushrc.php file in the drush.php's directory.
   drush_load_config('drush');
 
   // Load a drushrc.php file in the $ETC_PREFIX/etc/drush directory.
   drush_load_config('system');
 
-  // Load a drushrc.php file at ~/.drushrc.php
+  // Load a drushrc.php file at ~/.drushrc.php.
   drush_load_config('user');
 
   // Load a drushrc.php file in the ~/.drush directory.
@@ -599,9 +674,9 @@ function _drush_bootstrap_global_options() {
   drush_set_context('DRUSH_VERBOSE',     drush_get_option(array('v', 'verbose', 'd', 'debug'), FALSE));
   drush_set_context('DRUSH_DEBUG', drush_get_option(array('d', 'debug')));
 
-  // Backend implies affirmative
-  drush_set_context('DRUSH_AFFIRMATIVE', drush_get_option(array('y', 'yes', 'b', 'backend'), FALSE));
+  // Backend implies affirmative unless negative is explicitly specified
   drush_set_context('DRUSH_NEGATIVE',    drush_get_option(array('n', 'no'), FALSE));
+  drush_set_context('DRUSH_AFFIRMATIVE', drush_get_option(array('y', 'yes'), FALSE) || (drush_get_context('DRUSH_BACKEND') && !drush_get_context('DRUSH_NEGATIVE')));
   drush_set_context('DRUSH_SIMULATE',    drush_get_option(array('s', 'simulate'), FALSE));
 
   // Suppress colored logging if --nocolor option is explicitly given or if
@@ -656,9 +731,6 @@ function _drush_bootstrap_drupal_root() {
   $drupal_root = drush_set_context('DRUSH_DRUPAL_ROOT', drush_bootstrap_value('drupal_root'));
   define('DRUPAL_ROOT', $drupal_root);
 
-  // Save original working dir case some command wants it.
-  drush_set_context('DRUSH_OLDCWD', getcwd());
-
   chdir($drupal_root);
   drush_load_config('drupal');
   require_once DRUPAL_ROOT . '/' . DRUSH_DRUPAL_BOOTSTRAP;
@@ -689,7 +761,9 @@ function _drush_bootstrap_drupal_site_validate() {
   }
   $uri = 'http://'. $current;
 
-  $drush_uri = drush_bootstrap_value('drush_uri', drush_get_option(array('l', 'uri'), $uri, 'options'));
+  // UNL Change!
+  $drush_uri = drush_bootstrap_value('drush_uri', drush_get_option(array('l', 'uri'), $uri, 'cli'));
+  // End UNL Change!
 
   // Fake the necessary HTTP headers that Drupal needs:
   if ($drush_uri) {
@@ -704,8 +778,15 @@ function _drush_bootstrap_drupal_site_validate() {
     $drupal_base_url += array(
       'path' => NULL,
       'host' => NULL,
+      'port' => NULL,
     );
     $_SERVER['HTTP_HOST'] = $drupal_base_url['host'];
+
+    if ($drupal_base_url['port']) {
+      $_SERVER['HTTP_HOST'] .= ':' . $drupal_base_url['port'];
+    }
+    $_SERVER['SERVER_PORT'] = $drupal_base_url['port'];
+
     if (array_key_exists('path', $drupal_base_url)) {
       $_SERVER['PHP_SELF'] = $drupal_base_url['path'] . '/index.php';
     }
@@ -751,6 +832,7 @@ function _drush_bootstrap_do_drupal_site() {
 
   drush_log(dt("Initialized Drupal site !site at !site_root", array('!site' => $site, '!site_root' => $conf_path)));
   drush_load_config('site');
+
   _drush_bootstrap_global_options();
 }
 
@@ -813,6 +895,11 @@ function _drush_bootstrap_drupal_configuration() {
 
   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 
+  // Unset drupal error handler and restore drush's one.
+  if (drush_drupal_major_version() >= 7) {
+    restore_error_handler();
+  }
+
   // Overriding the $conf array from drupal CONFIGURATION bootstrap with the
   // Overrides we collected on the loaded config files on DRUSH_BOOTSTRAP_DRUSH
   $conf = is_array($conf) && is_array($drush_conf_override) ? array_merge($conf, $drush_conf_override) : $conf;
@@ -841,6 +928,14 @@ function _drush_bootstrap_drupal_configuration() {
      default:
        if (!empty($GLOBALS['databases']['default']['default'])) {
          $conn = $GLOBALS['databases']['default']['default'];
+         // Fill in defaults to prevent notices.
+         $conn += array(
+           'username' => NULL,
+           'host' => NULL,
+           'port' => NULL,
+           'password' => NULL,
+           'database' => NULL,
+         );
          $creds['driver'] = $conn['driver'];
          $creds['user'] = $conn['username'];
          $creds['host'] = $conn['host'];
@@ -884,6 +979,11 @@ function _drush_bootstrap_drupal_full() {
   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
   ob_end_clean();
 
+  // Unset drupal error handler and restore drush's one.
+  if (drush_drupal_major_version() == 6) {
+    restore_error_handler();
+  }
+
   // If needed, prod module_implements() to recognize our system_watchdog() implementation.
   $dogs = module_implements('watchdog');
   if (!in_array('system', $dogs)) {
@@ -909,9 +1009,13 @@ function _drush_bootstrap_drupal_login() {
 /**
  * Returns the current working directory.
  *
- * TODO: Could cache result, but it isn't really expensive.
+ * This is the directory as it was when drush was started, not the
+ * directory we are currently in. For that, use getcwd() directly.
  */
 function drush_cwd() {
+  if ($path = drush_get_context('DRUSH_OLDCWD')) {
+    return $path;
+  }
   // We use PWD if available because getcwd() resolves symlinks, which
   // could take us outside of the Drupal root, making it impossible to find.
   // $_SERVER['PWD'] isn't set on windows and generates a Notice.
@@ -923,6 +1027,9 @@ function drush_cwd() {
   // Convert windows paths.
   $path = _drush_convert_path($path);
 
+  // Save original working dir case some command wants it.
+  drush_set_context('DRUSH_OLDCWD', $path);
+
   return $path;
 }
 
@@ -1096,13 +1203,21 @@ function drush_valid_db_credentials() {
       // Verify connection settings.
       switch ($type) {
         case 'mysql':
-        case 'mysqli':
-          $connection = @mysql_connect($creds['host'], $creds['user'], $creds['pass']);
+          $hostspec = $creds['port'] ? $creds['host'] . ':' . $creds['port'] : $creds['host'];
+          $connection = @mysql_connect($hostspec, $creds['user'], $creds['pass']);
           if (!$connection || !mysql_select_db($creds['name'])) {
             drush_log(mysql_error(), 'bootstrap');
             return FALSE;
           }
           break;
+        case 'mysqli':
+          $connection = mysqli_init();
+          @mysqli_real_connect($connection, $creds['host'], $creds['user'], $creds['pass'], $creds['name'], (int)$creds['port']);
+          if (mysqli_connect_errno() > 0) {
+            drush_log(mysqli_connect_error(), 'bootstrap');
+            return FALSE;
+          }
+          break;
         case 'pgsql':
           $conn_string = sprintf("host=%s user=%s password=%s dbname=%s", $creds['host'], $creds['user'], $creds['pass'], $creds['name']);
           if (isset($creds['port'])) {
@@ -1240,8 +1355,23 @@ function drush_is_local_host($host) {
 }
 
 /**
- * Get complete information for all available extensions (modules and
- * themes).
+ * Return the user's home directory.
+ */
+function drush_server_home() {
+  $home = NULL;
+  // $_SERVER['HOME'] isn't set on windows and generates a Notice.
+  if (!empty($_SERVER['HOME'])) {
+    $home = $_SERVER['HOME'];
+  }
+  elseif (!empty($_SERVER['HOMEDRIVE']) && !empty($_SERVER['HOMEPATH'])) {
+    // home on windows
+    $home = $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
+  }
+  return $home;
+}
+
+/**
+ * Get complete information for all available extensions (modules and themes).
  *
  * @return
  *   An array containing info for all available extensions.
@@ -1252,23 +1382,11 @@ function drush_get_extensions() {
 }
 
 /**
- * Calculate a extension status based on current status and schema version.
  *
- * @param $extension
- *   Object of a single extension info.
- *
- * @return
- *   String describing extension status. Values: enabled|disabled|not installed
  */
-function drush_get_extension_status($extension) {
-  if (($extension->type == 'module')&&($extension->schema_version == -1)) {
-    $status = "not installed";
-  }
-  else {
-    $status = ($extension->status == 1)?'enabled':'disabled';
-  }
-
-  return $status;
+function drush_drupal_required_modules($modules) {
+  drush_include_engine('drupal', 'environment');
+  return _drush_drupal_required_modules($modules);
 }
 
 /**
@@ -1290,20 +1408,3 @@ function drush_theme_get_default() {
 function drush_theme_get_admin() {
   return variable_get('admin_theme', drush_theme_get_default());
 }
-
-/**
- * Return the user's home directory.
- */
-
-function drush_server_home() {
-  $home = NULL;
-  // $_SERVER['HOME'] isn't set on windows and generates a Notice.
-  if (!empty($_SERVER['HOME'])) {
-    $home = $_SERVER['HOME'];
-  }
-  elseif (!empty($_SERVER['HOMEDRIVE']) && !empty($_SERVER['HOMEPATH'])) {
-    // home on windows
-    $home = $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
-  }
-  return $home;
-}
diff --git a/sites/all/modules/drush/includes/sitealias.inc b/sites/all/modules/drush/includes/sitealias.inc
index 6934517630d3ea5cb514580833fc73b53c0621fb..e1ac25cc750063a1f57fdb6de944683857eadd76 100644
--- a/sites/all/modules/drush/includes/sitealias.inc
+++ b/sites/all/modules/drush/includes/sitealias.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: sitealias.inc,v 1.60 2010/12/01 15:45:53 weitzman Exp $
 
 /**
  * @file
@@ -34,6 +33,25 @@ function drush_sitealias_check_arg() {
   return FALSE;
 }
 
+/**
+ * Given a list of alias records, shorten the name used if possible
+ */
+function drush_sitealias_simplify_names($site_list) {
+  $result = array();
+  foreach ($site_list as $original_name => $alias_record) {
+    $adjusted_name = $alias_record['#name'];
+    $hashpos = strpos($original_name, '#');
+    if ($hashpos !== FALSE) {
+      $adjusted_name = substr($original_name, $hashpos);
+      if (array_key_exists('remote-host', $alias_record)) {
+        $adjusted_name = $alias_record['remote-host'] . $adjusted_name;
+      }
+    }
+    $result[$adjusted_name] = $alias_record;
+  }
+  return $result;
+}
+
 /**
  * Given an array of site specifications, resolve each one in turn and
  * return an array of alias records.  If you only want a single record,
@@ -101,10 +119,10 @@ function drush_sitealias_get_record($alias) {
     $alias_record = _drush_sitealias_get_record($alias);
   }
   if (!empty($alias_record)) {
-    if (!array_key_exists('name', $alias_record)) {
-      $alias_record['name'] = drush_sitealias_uri_to_site_dir($alias);
+    if (!array_key_exists('#name', $alias_record)) {
+      $alias_record['#name'] = drush_sitealias_uri_to_site_dir($alias);
     }
-    
+
     // Handle nested alias definitions and command-specific options.
     drush_set_config_special_contexts($alias_record);
   }
@@ -183,13 +201,15 @@ function _drush_sitealias_get_record($alias, $alias_context = NULL) {
         // then use it as a local site specification.
         $alias_record = _drush_sitealias_find_record_for_local_site($alias);
       }
-
     }
   }
 
   if (!empty($alias_record)) {
     // Load the drush config file if there is one associated with this alias
     if (!isset($alias_record['remote']) && !isset($alias_record['loaded-config'])) {
+      if (array_key_exists('root', $alias_record)) {
+        drush_sitealias_add_to_alias_path($alias_record['root']);
+      }
       $alias_site_dir = drush_sitealias_local_site_path($alias_record);
 
       if (isset($alias_site_dir)) {
@@ -262,6 +282,15 @@ function drush_sitealias_alias_path($alias_path_context = NULL) {
     // (nothing) to the path list, which is a no-op
     $site_paths = drush_sitealias_add_to_alias_path(NULL);
 
+    // If the user defined the root of a drupal site, then also
+    // look for alias files there.
+    $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
+    if (empty($drupal_root)) {
+      $drupal_root = drush_get_option(array('root', 'r'), NULL);
+    }
+    if (isset($drupal_root)) {
+      $site_paths[] = $drupal_root;
+    }
     $alias_path = (array) drush_get_option('alias-path', array());
     if (empty($alias_path)) {
       $alias_path[] = drush_get_context('ETC_PREFIX', '') . '/etc/drush';
@@ -272,7 +301,7 @@ function drush_sitealias_alias_path($alias_path_context = NULL) {
       }
     }
 
-    return array_merge($alias_path, $site_paths);
+    return array_unique(array_merge($alias_path, $site_paths));
   }
 }
 
@@ -289,7 +318,7 @@ function drush_sitealias_alias_path($alias_path_context = NULL) {
 function drush_sitealias_local_site_path($alias_record) {
   $result = NULL;
 
-  if (isset($alias_record['uri']) && isset($alias_record['root']) && !isset($alias_record['remote_host'])) {
+  if (isset($alias_record['uri']) && isset($alias_record['root']) && !isset($alias_record['remote-host'])) {
     $result = realpath($alias_record['root'] . '/sites/' . drush_sitealias_uri_to_site_dir($alias_record['uri']));
   }
 
@@ -323,7 +352,7 @@ function _drush_sitealias_load_alias($alias, $alias_path_context = NULL) {
       if (array_key_exists('inherited', $result)) {
         $result = array_merge($primary_record, $result);
       }
-      $result['name'] = $relative_alias;
+      $result['#name'] = $relative_alias;
       _drush_sitealias_cache_alias(substr($alias, 1), $result);
     }
   }
@@ -367,7 +396,7 @@ function drush_sitealias_load_all($resolve_parent = TRUE) {
  * and finds the specified alias record.
  *
  * @param $aliasname
- *   The name of the alias without the leading '@' (i.e. 'name')
+ *   The name of the alias without the leading '@' (i.e. '#name')
  *   or NULL to load every alias found in every alias file.
  * @param $alias_path_context
  *   When looking up a relative alias, the alias path context is
@@ -381,7 +410,7 @@ function drush_sitealias_load_all($resolve_parent = TRUE) {
  */
 function _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context = NULL) {
   $result = array();
-  
+
   // Special checking for '@sites' alias
   if ($aliasname == 'sites') {
     $drupal_root = NULL;
@@ -400,7 +429,7 @@ function _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context =
       drush_sitealias_create_sites_alias($drupal_root);
     }
   }
-  
+
   // The alias path is a list of folders to search for alias settings files
   $alias_path = drush_sitealias_alias_path($alias_path_context);
 
@@ -409,12 +438,12 @@ function _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context =
   // any folder in the alias path.  The directory scan
   // is not deep, though; only files immediately in the
   // search path are considered.
-  $alias_files = array('/.*aliases\.drushrc\.php/');
+  $alias_files = array('/.*aliases\.drushrc\.php$/');
   if ($aliasname == NULL) {
-    $alias_files[] = '/.*\.alias\.drushrc\.php/';
+    $alias_files[] = '/.*\.alias\.drushrc\.php$/';
   }
   else {
-    $alias_files[] = '/' . preg_quote($aliasname) . '\.alias\.drushrc\.php/';
+    $alias_files[] = '/' . preg_quote($aliasname, '/') . '\.alias\.drushrc\.php$/';
   }
 
   // Search each path in turn
@@ -430,7 +459,11 @@ function _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context =
     foreach ($alias_files_to_consider as $filename) {
       if (file_exists($filename)) {
         $aliases = $options = array();
-        include $filename;
+        // silently ignore files we can't include
+        if ((@include $filename) === FALSE) {
+          drush_log(dt('Cannot open alias file "!alias", ignoring.', array('!alias' => realpath($filename))), 'bootstrap');
+          continue;
+        }
         unset($options['site-aliases']); // maybe unnecessary
 
         // If $aliases are not set, but $options are, then define one alias named
@@ -515,7 +548,8 @@ function _drush_sitealias_add_inherited_values(&$aliases) {
       // Fetch and merge in each parent
       foreach (explode(',', $alias_value['parent']) as $parent) {
         $parent_record = drush_sitealias_get_record($parent);
-        unset($parent_record['name']);
+        unset($parent_record['#name']);
+        unset($parent_record['#hidden']);
         $array_based_keys = array_merge(drush_get_special_keys(), array('path-aliases'));
         foreach ($array_based_keys as $array_based_key) {
           if (isset($aliases[$alias_name][$array_based_key]) && isset($parent_record[$array_based_key])) {
@@ -537,6 +571,11 @@ function _drush_sitealias_add_inherited_values(&$aliases) {
  */
 function _drush_sitealias_cache_alias($alias_name, $alias_record) {
   $cache =& drush_get_context('site-aliases');
+  // If the alias already exists in the cache, then merge
+  // the new alias with the existing alias
+  if (array_key_exists("@$alias_name", $cache)) {
+    $alias_record = array_merge($cache["@$alias_name"], $alias_record);
+  }
   $cache["@$alias_name"] = $alias_record;
 
   // If the alias record points at a local site, make sure
@@ -563,7 +602,7 @@ function _drush_sitealias_cache_alias($alias_name, $alias_record) {
  */
 function drush_sitealias_add_db_url(&$alias_record) {
   if (!isset($alias_record['db-url']) && !isset($alias_record['databases']) && !isset($alias_record['site-list'])) {
-    $values = drush_do_site_command($alias_record, "sql-conf", array(), array('db-url' => TRUE));
+    $values = drush_invoke_sitealias_args($alias_record, "sql-conf", array(), array('db-url' => TRUE));
     if (isset($values['object']['db-url'])) {
       $alias_record['db-url'] = $values['object']['db-url'];
     }
@@ -601,21 +640,37 @@ function 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 (!isset($alias_record['db-url']) && !isset($alias_record['databases']) && !isset($alias_record['site-list'])) {
-    $values = drush_do_site_command($alias_record, "sql-conf", array(), array('all' => TRUE));
-    if (isset($values['object'])) {
-      $alias_record['databases'] = $values['object'];
+    $values = drush_invoke_sitealias_args($alias_record, "sql-conf", array(), array('all' => TRUE));
+    if (isset($values) && ($values['error_status'] == 0)) {
       $altered_record = TRUE;
-      // If the name is set, then re-cache the record after we fetch the databases
-      if (array_key_exists('name', $alias_record)) {
-        $all_site_aliases =& drush_get_context('site-aliases');
-        $all_site_aliases[$alias_record['name']] = $alias_record;
+      // If there are any special settings in the '@self' record returned by drush_invoke_sitealias_args,
+      // then add those into our altered record as well
+      if (array_key_exists('self', $values)) {
+        $alias_record = array_merge($values['self'], $alias_record);
       }
+      drush_sitealias_cache_db_settings($alias_record, $values['object']);
     }
   }
 
   return $altered_record;
 }
 
+function drush_sitealias_cache_db_settings(&$alias_record, $databases) {
+  if (!empty($databases)) {
+    $alias_record['databases'] = $databases;
+  }
+
+  // If the name is set, then re-cache the record after we fetch the databases
+  if (array_key_exists('#name', $alias_record)) {
+    $all_site_aliases =& drush_get_context('site-aliases');
+    $all_site_aliases[$alias_record['#name']] = $alias_record;
+    // Check and see if this record is a copy of 'self'
+    if (($alias_record['#name'] != 'self') && array_key_exists('@self', $all_site_aliases) && ($all_site_aliases['@self']['#name'] == $alias_record['#name'])) {
+      $all_site_aliases['@self'] = $alias_record;
+    }
+  }
+}
+
 /**
  * Check to see if we have already bootstrapped to a site.
  */
@@ -654,9 +709,9 @@ function drush_sitealias_resolve_path_references(&$alias_record, $test_string =
   foreach($test_array as $one_item) {
     if (substr($one_item,0,1) == '%') {
       $project_array[] = substr($one_item,1);
-    }    
+    }
   }
-  
+
   // If we already have a path in the path aliases, then
   // there is no need to search for it remotely; we can remove
   // it from the project array.
@@ -668,7 +723,7 @@ function drush_sitealias_resolve_path_references(&$alias_record, $test_string =
     }
   }
   $project_list = implode(',', $project_array);
-  
+
   if (!empty($project_array)) {
     // Optimization:  if we're already bootstrapped to the
     // site specified by $alias_record, then we can just
@@ -683,7 +738,7 @@ function drush_sitealias_resolve_path_references(&$alias_record, $test_string =
       $status_values = _core_site_status_table($project_list);
     }
     else {
-      $values = drush_do_site_command($alias_record, "status", array(), empty($project_list) ? array() : array('project' => $project_list));
+      $values = drush_invoke_sitealias_args($alias_record, "status", array(), empty($project_list) ? array() : array('project' => $project_list));
       $status_values = $values['object'];
     }
     if (isset($status_values['%paths'])) {
@@ -713,8 +768,8 @@ function drush_sitealias_resolve_sitelist($alias_record) {
         $result_list = array_merge($result_list, drush_sitealias_resolve_sitelist($one_result));
       }
     }
-    elseif (array_key_exists('name', $alias_record)) {
-      $result_list[$alias_record['name']] = $alias_record;
+    elseif (array_key_exists('#name', $alias_record)) {
+      $result_list[$alias_record['#name']] = $alias_record;
     }
   }
 
@@ -994,22 +1049,23 @@ function _drush_sitealias_find_local_sites($search_path) {
 function _drush_find_local_sites_at_root($a_drupal_root = '', $search_depth = 1) {
   $site_list = array();
   $base_path = (empty($a_drupal_root) ? drush_get_context('DRUSH_DRUPAL_ROOT') : $a_drupal_root );
-  if (drush_valid_drupal_root($base_path)) {
-    // If $a_drupal_root is in fact a valid drupal root, then return
-    // all of the sites found inside the 'sites' folder of this drupal instance.
-    $site_list = _drush_find_local_sites_in_sites_folder($base_path);
-  }
-  else {
-    $bootstrap_files = drush_scan_directory($base_path, '/' . basename(DRUSH_DRUPAL_BOOTSTRAP) . '/' , array('.', '..', 'CVS'), 0, drush_get_option('search-depth', $search_depth) + 1, 'filename', 1);
-    foreach ($bootstrap_files as $one_bootstrap => $info) {
-      $includes_dir = dirname($one_bootstrap);
-      if (basename($includes_dir) == basename(dirname(DRUSH_DRUPAL_BOOTSTRAP))) {
-        $drupal_root = dirname($includes_dir);
-        $site_list = array_merge(_drush_find_local_sites_in_sites_folder($drupal_root), $site_list);
+  if (!empty($base_path)) {
+    if (drush_valid_drupal_root($base_path)) {
+      // If $a_drupal_root is in fact a valid drupal root, then return
+      // all of the sites found inside the 'sites' folder of this drupal instance.
+      $site_list = _drush_find_local_sites_in_sites_folder($base_path);
+    }
+    else {
+      $bootstrap_files = drush_scan_directory($base_path, '/' . basename(DRUSH_DRUPAL_BOOTSTRAP) . '/' , array('.', '..', 'CVS'), 0, drush_get_option('search-depth', $search_depth) + 1, 'filename', 1);
+      foreach ($bootstrap_files as $one_bootstrap => $info) {
+        $includes_dir = dirname($one_bootstrap);
+        if (basename($includes_dir) == basename(dirname(DRUSH_DRUPAL_BOOTSTRAP))) {
+          $drupal_root = dirname($includes_dir);
+          $site_list = array_merge(_drush_find_local_sites_in_sites_folder($drupal_root), $site_list);
+        }
       }
     }
   }
-
   return $site_list;
 }
 
@@ -1095,6 +1151,25 @@ function _drush_sitealias_add_transient_defaults(&$alias_record) {
   }
 }
 
+/**
+ * Find the name of a local alias record that has the specified
+ * root and uri.
+ */
+function _drush_sitealias_find_local_alias_name($root, $uri) {
+  $result = '';
+  $all_site_aliases =& drush_get_context('site-aliases');
+
+  foreach ($all_site_aliases as $alias_name => $alias_values) {
+    if (!array_key_exists('remote-host', $alias_values) && array_key_exists('root', $alias_values) && array_key_exists('uri', $alias_values) && ($alias_name != '@self')) {
+      if (($root == $alias_values['root']) && ($uri == $alias_values['uri'])) {
+        $result = $alias_name;
+      }
+    }
+  }
+
+  return $result;
+}
+
 /**
  * If '$alias' is the name of a folder in the sites folder of the given drupal
  * root, then build an alias record for it
@@ -1175,9 +1250,10 @@ function drush_sitealias_uri_to_site_dir($uri) {
  * Convert from an old-style database URL to an array of database settings
  *
  * @param db_url
- *   A Drupal 6 db-url string to convert.
+ *   A Drupal 6 db-url string to convert, or an array with a 'default' element.
  * @return array
- *   An array of database values.
+ *   An array of database values containing only the 'default' element of
+ *   the db_url.
  */
 function drush_convert_db_from_db_url($db_url) {
   if (is_array($db_url)) {
@@ -1191,6 +1267,7 @@ function drush_convert_db_from_db_url($db_url) {
     'driver' => NULL,
     'user' => NULL,
     'pass' => NULL,
+    'host' => NULL,
     'port' => NULL,
     'database' => NULL,
   );
@@ -1207,20 +1284,24 @@ function drush_convert_db_from_db_url($db_url) {
   );
 }
 
+/**
+ * Convert from an old-style database URL to an array of database settings
+ *
+ * @param db_url
+ *   A Drupal 6 db-url string to convert, or an array with multiple db-urls.
+ * @return array
+ *   An array of database values.
+ */
 function drush_sitealias_convert_db_from_db_url($db_url) {
   $result = array();
 
-  if (is_array($db_url)) {
-    $default_db = array();
-
-    foreach ($db_url as $db_name => $db_urlstr) {
-      $default_db[$db_name] = drush_convert_db_from_db_url($db_urlstr);
-    }
-
-    $result['default'] = $default_db;
+  if (!is_array($db_url)) {
+    $result = array('default' => array('default' => drush_convert_db_from_db_url($db_url)));
   }
   else {
-    $result = array('default' => array('default' => drush_convert_db_from_db_url($db_url)));
+    foreach ($db_url as $one_name => $one_db_url) {
+      $result[$one_name] = array('default' => drush_convert_db_from_db_url($one_db_url));
+    }
   }
 
   return $result;
@@ -1265,7 +1346,7 @@ function _drush_sitealias_set_context_by_name($alias, $prefix = '') {
 /**
  * Given a site alias record, copy selected fields from it
  * into the drush 'alias' context.  The 'alias' context has
- * lower precedence than the 'options' context, so values
+ * lower precedence than the 'cli' context, so values
  * set by an alias record can be overridden by command-line
  * parameters.
  *
@@ -1290,17 +1371,39 @@ function drush_sitealias_set_alias_context($site_alias_settings, $prefix = '') {
     $skip_list[] = 'remote-host';
     $skip_list[] = 'remote-user';
   }
+  // If prefix is set, then copy from the 'prefix-' version
+  // of the drush special keys ('command-specific', 'path-aliases')
+  // into the ordinary version.  This will allow us to set
+  // 'source-command-specific' options that will only apply when
+  // the alias is used as the source option for rsync or sql-sync.
+  if (!empty($prefix)) {
+    $special_contexts = drush_get_special_keys();
+    foreach ($special_contexts as $option_name) {
+      if (array_key_exists($prefix . $option_name, $site_alias_settings)) {
+        $site_alias_settings[$option_name] = array_key_exists($option_name, $site_alias_settings) ? array_merge($site_alias_settings[$option_name], $site_alias_settings[$prefix . $option_name]) : $site_alias_settings[$prefix . $option_name];
+      }
+    }
+  }
   // Transfer all options from the site alias to the drush options
   // in the 'alias' context.
   foreach ($site_alias_settings as $key => $value) {
     // Special handling for path aliases:
     if ($key == "path-aliases") {
+      $path_aliases = $value;
       foreach (array('%drush-script', '%dump', '%dump-dir', '%include') as $path_key) {
-        if (array_key_exists($path_key, $value)) {
-          $options[$prefix . substr($path_key, 1)] = $value[$path_key];
+        if (array_key_exists($path_key, $path_aliases)) {
+          // Evaluate the path value, and substitute any path references found.
+          // ex: '%dump-dir' => '%root/dumps' will store sql-dumps in the folder
+          // 'dumps' in the Drupal root folder for the site.
+          $evaluated_path = str_replace(array_keys($path_aliases), array_values($path_aliases), $path_aliases[$path_key]);
+          $options[$prefix . substr($path_key, 1)] = $evaluated_path;
         }
       }
     }
+    // Special handling for command-specific
+    elseif ($key == "command-specific") {
+      $options[$key] = $value;
+    }
     elseif (!in_array($key, $skip_list)) {
       $options[$prefix . $key] = $value;
     }
@@ -1365,7 +1468,7 @@ function _drush_sitealias_preflight_path($path) {
  *   with the path to pass to rsync (including the machine specifier)
  *   in the 'evaluated-path' item.
  */
-function drush_sitealias_evaluate_path($path, &$additional_options) {
+function drush_sitealias_evaluate_path($path, &$additional_options, $local_only = FALSE) {
   $site_alias_settings = array();
   $path_aliases = array();
   $remote_user = '';
@@ -1374,16 +1477,20 @@ function drush_sitealias_evaluate_path($path, &$additional_options) {
   if (!isset($preflight)) {
     return NULL;
   }
-  
+
   $alias = $preflight['alias'];
   $path = $preflight['path'];
   $machine = $preflight['machine'];
-  
+
   if (isset($alias)) {
     $site_alias_settings = drush_sitealias_get_record($alias);
   }
-  
+
   if (!empty($site_alias_settings)) {
+    if ($local_only && array_key_exists('remote-host', $site_alias_settings)) {
+      return drush_set_error('DRUSH_REMOTE_SITE_IN_LOCAL_CONTEXT', dt("A remote site alias was used in a context where only a local alias is appropriate."));
+    }
+
     // Apply any options from this alias that might affect our rsync
     drush_sitealias_set_alias_context($site_alias_settings);
 
@@ -1457,7 +1564,7 @@ function drush_sitealias_evaluate_path($path, &$additional_options) {
     $drupal_root = $site_alias_settings['root'];
   }
   else {
-    drush_bootstrap_max();
+    drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
     $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
   }
   if (empty($drupal_root)) {
@@ -1470,11 +1577,11 @@ function drush_sitealias_evaluate_path($path, &$additional_options) {
   $full_path_aliases = $path_aliases;
   foreach ($full_path_aliases as $key => $value) {
     // Expand all relative path aliases to be based off of the Drupal root
-    if (($value[0] != '/') && ($key != '%root')) {
+    if ((substr($value, 0, 1) != '/') && ($key != '%root')) {
       $full_path_aliases[$key] = $drupal_root . $value;
     }
     // We do not want slashes on the end of our path aliases.
-    if ($value[strlen($value)-1] == '/') {
+    if (substr($value, 0, -1) == '/') {
       $full_path_aliases[$key] = substr($full_path_aliases[$key], -1);
     }
   }
@@ -1522,7 +1629,7 @@ function drush_sitealias_evaluate_path($path, &$additional_options) {
   $site_alias_settings['path-component'] = $path_component;
   $site_alias_settings['path'] = $path;
   $site_alias_settings['user-path'] = $preflight['path'];
-  
+
   return $site_alias_settings;
 }
 
@@ -1530,19 +1637,19 @@ function drush_sitealias_evaluate_path($path, &$additional_options) {
  * Option keys used for site selection.
  */
 function drush_sitealias_site_selection_keys() {
-  return array('remote-host', 'remote-user', 'ssh-options', 'name');
+  return array('remote-host', 'remote-user', 'ssh-options', '#name');
 }
 
 
 function sitealias_find_local_drupal_root($site_list) {
   $drupal_root = NULL;
-  
+
   foreach ($site_list as $site) {
     if (($drupal_root == NULL) && (array_key_exists('root', $site) && !array_key_exists('remote-host', $site))) {
       $drupal_root = $site['root'];
     }
   }
-  
+
   return $drupal_root;
 }
 
diff --git a/sites/all/modules/drush/tests/COVERAGE.txt b/sites/all/modules/drush/tests/COVERAGE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1c2e862f5ef2e0b2be0973f70dec6ac38a278287
--- /dev/null
+++ b/sites/all/modules/drush/tests/COVERAGE.txt
@@ -0,0 +1,73 @@
+COMMANDS (perhaps keep these notes in $command definition?)
+------------
+pm-download: GOOD.
+pm-updatecode: GOOD.
+pm-update
+pm-releasenotes
+pm-releases
+pm-enable: GOOD. testEnDisUnList().
+pm-disable: GOOD. testEnDisUnList().
+pm-uninstall: GOOD. testEnDisUnList().
+pm-list: GOOD. testEnDisUnList().
+pm-info:
+pm-refresh
+version-control: FAIR. See updatecode. To be deprecated all git workflow after git.drupal.org?
+package-hander:
+
+sql-cli:
+sql-connect:
+sql-query:
+sql-dump: FAIR. Implicitly tested by siteUpgradeTest.
+sql-sync: FAIR. Implicitly tested by siteUpgradeTest.
+sql-drop:
+
+
+updatedb: GOOD. Implicitly tested siteUpgradeTest.
+archive-dump: GOOD
+archive-restore: 
+help
+version: Good. Implicit by testStandaloneScript()
+self-update
+php-eval: GOOD. Implicitly tested by many tests (e.g. siteUpgradeTest).
+php-script: GOOD.
+drupal-directory: GOOD
+core-cli: FAIR
+cache-clear
+core-cron
+core-status: FAIR: Implicit test by contextTest.
+docs
+image
+core-rsync
+search-*
+site-install: FAIR. Implicit test by setUpDrupal().
+site-upgrade: GOOD.
+test-*
+topic
+variable-*: GOOD.
+watchdog-*
+
+user-*: GOOD.
+
+field-*: GOOD.
+
+INCLUDES
+------------
+backend: GOOD
+batch: FAIR. Implicit by siteUpgradeTest.
+command: FAIR
+context: FAIR
+drush: NONE.
+environment
+sitealias. FAIR. Explicit test for alias lists. Single aliases implicitly tested by contextTest.
+dbtng: Good. Implicit by variable-*.
+drupal
+exec: GOOD: Implicitly tested all over.
+filesystem
+output
+
+
+ROOT
+-------------
+drush
+drush.php
+drush.bat
diff --git a/sites/all/modules/drush/tests/README.txt b/sites/all/modules/drush/tests/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fa66f8b64cc2ae7b8281abd260d2a6f98d7882a2
--- /dev/null
+++ b/sites/all/modules/drush/tests/README.txt
@@ -0,0 +1,44 @@
+Drush's test suite based on phpunit (http://www.phpunit.de/).
+
+Usage
+--------
+- Install PHPUnit [*]
+- Optional. Copy phpunit.xml.dist to phpunit.xml and customize if needed.
+- From the /tests subdirectory, run `phpunit .` or `runner.php .`
+
+Advanced usage
+---------
+- Run only tests matching a regex: phpunit --filter=testVersionString .
+- XML results: phpunit --filter=testVersionString --log-junit results.xml .
+
+Notes
+----------
+- I have run tests within Netbeans and it works.
+- Speedup downloads with Squid as forward proxy - http://reluctanthacker.rollett.org/node/114.
+
+
+
+[*] Install PHPUnit:
+
+Drush requires PHPUnit 3.5 or later; installing with PEAR is easiest.
+ 
+On Linux:
+---------
+
+  sudo apt-get install php5-curl php-pear
+  sudo pear upgrade --force PEAR
+  sudo pear channel-discover pear.phpunit.de
+  sudo pear channel-discover components.ez.no
+  sudo pear channel-discover pear.symfony-project.com
+  sudo pear install --alldeps phpunit/PHPUnit
+
+On Windows:
+-----------
+
+Download and save from go-pear.phar http://pear.php.net/go-pear.phar
+
+  php -q go-pear.phar
+  pear channel-discover pear.phpunit.de
+  pear channel-discover components.ez.no
+  pear channel-discover pear.symfony-project.com
+  pear install --alldeps phpunit/PHPUnit
diff --git a/sites/all/modules/drush/tests/archiveDumpTest.php b/sites/all/modules/drush/tests/archiveDumpTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d949122dfad51b25ec6bec14441e3de5683afa75
--- /dev/null
+++ b/sites/all/modules/drush/tests/archiveDumpTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * @file
+ *   Tests for archive.drush.inc
+ */
+class archiveDumpCase extends Drush_TestCase {
+
+  /*
+   * Test dump and extraction.
+   */
+  public function testArchiveDump() {
+    $env = 'testarchivedump';
+    $this->setUpDrupal($env, TRUE, '6');
+    $root = $this->sites[$env]['root'];
+    $docroot = 'web';
+
+    // Create the alias for D7 site.
+    $aliases['archivedump'] = array(
+      'root' => UNISH_SANDBOX . '/' . $docroot,
+      'uri' => $env,
+    );
+    $contents = $this->file_aliases($aliases);
+    $alias_path = "$root/aliases.drushrc.php";
+    file_put_contents($alias_path, $contents);
+
+    $name = "example";
+    $dump_dest = "dump.tar.gz";
+    $options = array(
+      'root' => $root,
+      'uri' => $env,
+      'yes' => NULL,
+      'destination' => 'dump.tar.gz',
+    );
+    $this->drush('archive-dump', array('@archivedump'), $options);
+    $exec = sprintf('file %s/%s', UNISH_SANDBOX, $dump_dest);
+    $this->execute($exec);
+    $output = $this->getOutput();
+    $expected = UNISH_SANDBOX . "/dump.tar.gz: gzip compressed data, from Unix";
+    $this->assertEquals($expected, $output);
+
+    // Untar it, make sure it looks right.
+    $exec = sprintf('tar -xzf %s/%s', UNISH_SANDBOX, $dump_dest);
+    $untar_dest = UNISH_SANDBOX . '/untar';
+    $exec = sprintf('mkdir %s && cd %s && tar xzf %s/%s', $untar_dest, $untar_dest, UNISH_SANDBOX, $dump_dest);
+    $this->execute($exec);
+    $this->execute(sprintf('head %s/unish_%s.sql | grep "MySQL dump"', $untar_dest, $env));
+    $this->execute('test -f ' . $untar_dest . '/MANIFEST.ini');
+    $this->execute('test -d ' . $untar_dest . '/' . $docroot);
+  }
+}
diff --git a/sites/all/modules/drush/tests/backendTest.php b/sites/all/modules/drush/tests/backendTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..71ae619d1724baf9882ce38986b9b40ab83e0aec
--- /dev/null
+++ b/sites/all/modules/drush/tests/backendTest.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+* @file
+*  We choose to test the backend system in two parts.
+*    - Origin. These tests assure that we are generate a proper ssh command
+*        when a backend invoke is needed.
+*    - Target. These tests assure that drush generates a delimited JSON array
+*        when called with --backend option.
+*
+*  Advantages of this approach:
+*    - No network calls and thus more robust.
+*    - No network calls and thus faster.
+*/
+
+class backendCase extends Drush_TestCase {
+  const DRUSH_BACKEND_OUTPUT_DELIMITER = 'DRUSH_BACKEND_OUTPUT_START>>>%s<<<DRUSH_BACKEND_OUTPUT_END';
+
+  /*
+   * Covers the following origin responsibilities.
+   *   - A remote host is recognized in site specification.
+   *   - Generates expected ssh command.
+   *
+   * General handling of site aliases will be in sitealiasTest.php.
+   */
+  function testOrigin() {
+    $exec = sprintf('%s %s version --simulate --ssh-options=%s | grep ssh', self::escapeshellarg(UNISH_DRUSH), self::escapeshellarg('user@server/path/to/drupal#sitename'), self::escapeshellarg('-i mysite_dsa'));
+    $this->execute($exec);
+    // $expected might be different on non unix platforms. We shall see.
+    $expected = "proc_open: ssh -i mysite_dsa 'user'@'server' 'drush  --uri='\''sitename'\'' --root='\''/path/to/drupal'\'' --simulate version --backend 2>&1'  2>&1";
+    $output = $this->getOutput();
+    $this->assertEquals($expected, $output, 'Expected ssh command was built');
+  }
+
+  /*
+   * Covers the following target responsibilities.
+   *   - Interpret stdin as options as per REST API.
+   *   - Successfully execute specified command.
+   *   - JSON object has expected contents (including errors).
+   *   - JSON object is wrapped in expected delimiters.
+  */
+  function testTarget() {
+    $stdin = json_encode(array('filter'=>'sql'));
+    $exec = sprintf('echo %s | %s help --backend', self::escapeshellarg($stdin), self::escapeshellarg(UNISH_DRUSH));
+    $this->execute($exec);
+    $parsed = $this->parse($this->getOutput());
+    $this->assertTrue((bool) $parsed, 'Successfully parsed backend output');
+    $this->assertArrayHasKey('log', $parsed);
+    $this->assertArrayHasKey('output', $parsed);
+    $this->assertArrayHasKey('object', $parsed);
+    $this->assertEquals(self::EXIT_SUCCESS, $parsed['error_status']);
+    // This assertion shows that `help` was called and that stdin options were respected.
+    $this->assertStringStartsWith('SQL commands', $parsed['output']);
+    $this->assertEquals('Bootstrap to phase 0.', $parsed['log'][0]['message']);
+
+    // Check error propogation by requesting an invalid command (missing Drupal site).
+    $exec = sprintf('%s core-cron --backend 2>/dev/null', self::escapeshellarg(UNISH_DRUSH));
+    $this->execute($exec, self::EXIT_ERROR);
+    $parsed = $this->parse($this->getOutput());
+    $this->assertEquals(1, $parsed['error_status']);
+    $this->assertArrayHasKey('DRUSH_NO_DRUPAL_ROOT', $parsed['error_log']);
+  }
+
+  /*
+   * A slightly less functional copy of drush_backend_parse_output().
+   */
+  function parse($string) {
+    $regex = sprintf(self::DRUSH_BACKEND_OUTPUT_DELIMITER, '(.*)');
+    preg_match("/$regex/s", $string, $match);
+    if ($match[1]) {
+      // we have our JSON encoded string
+      $output = $match[1];
+      // remove the match we just made and any non printing characters
+      $string = trim(str_replace(sprintf(self::DRUSH_BACKEND_OUTPUT_DELIMITER, $match[1]), '', $string));
+    }
+
+    if ($output) {
+      $data = json_decode($output, TRUE);
+      if (is_array($data)) {
+        return $data;
+      }
+    }
+    return $string;
+  }
+}
diff --git a/sites/all/modules/drush/tests/commandTest.php b/sites/all/modules/drush/tests/commandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a5b86fcfd3bc0aaeb19708037a67b575d7792b4
--- /dev/null
+++ b/sites/all/modules/drush/tests/commandTest.php
@@ -0,0 +1,56 @@
+<?php
+
+class commandCase extends Drush_TestCase {
+  public function testInvoke() {
+    $expected = array(
+      'unit_drush_init',
+      'drush_unit_invoke_init',
+      'drush_unit_invoke_validate',
+      'drush_unit_pre_unit_invoke',
+      'drush_unit_invoke',
+      'drush_unit_post_unit_invoke',
+      'drush_unit_post_unit_invoke_rollback',
+      'drush_unit_pre_unit_invoke_rollback',
+      'drush_unit_invoke_validate_rollback',
+    );
+    
+    // We expect a return code of 1 so just call execute() directly.
+    $exec = sprintf('%s unit-invoke --include=%s', UNISH_DRUSH, self::escapeshellarg(dirname(__FILE__)));
+    $this->execute($exec, self::EXIT_ERROR);
+    $called = json_decode($this->getOutput());
+    $this->assertSame($expected, $called);
+  }
+  
+  
+  /*
+   * Assert that $command has interesting properties. Reference command by
+   * it's alias (dl) to assure that those aliases are built as expected.
+   */ 
+  public function testGetCommands() {
+    $eval = '$commands = drush_get_commands();';
+    $eval .= 'print json_encode($commands[\'dl\'])';
+    $this->drush('php-eval', array($eval));
+    $command = json_decode($this->getOutput());
+    
+    $this->assertEquals('dl', current($command->aliases));
+    $this->assertEquals('download', current($command->{'deprecated-aliases'}));
+    $this->assertObjectHasAttribute('version_control', $command->engines);
+    $this->assertObjectHasAttribute('package_handler', $command->engines);
+    $this->assertEquals('pm-download', $command->command);
+    $this->assertEquals('pm', $command->commandfile);
+    $this->assertEquals('drush_command', $command->callback);
+    $this->assertObjectHasAttribute('examples', $command->sections);
+    $this->assertTrue($command->is_alias);
+  }
+  
+  /*
+   * Assert that minimum bootstrap phase is honored.
+   *
+   * Not testing dependency on a module since that requires an installed Drupal.
+   * Too slow for little benefit.
+   */ 
+  public function testRequirementBootstrapPhase() {
+    // Assure that core-cron fails when run outside of a Drupal site.
+    $return = $this->execute(UNISH_DRUSH . ' core-cron --quiet', self::EXIT_ERROR);
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/contextTest.php b/sites/all/modules/drush/tests/contextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbbcd96bd866af61f172086f4eef33bff6052728
--- /dev/null
+++ b/sites/all/modules/drush/tests/contextTest.php
@@ -0,0 +1,150 @@
+<?php
+
+/*
+* @file
+*  Assure that context API behaves as designed. Mostly implicitly tested, but we
+*  do have some edges that need explicit testing.
+*
+*  @see drush/includes/context.inc.
+*/
+
+class contextCase extends Drush_TestCase {
+
+  function setUpPaths() {
+    $this->root = $this->sites[$this->env]['root'];
+    $this->site = $this->root . '/sites/' . $this->env;
+    $this->home = UNISH_SANDBOX . '/home';
+    $this->paths = array(
+      'custom' => UNISH_SANDBOX,
+      'site' =>  $this->site,
+      'drupal' => $this->root,
+      'user' => $this->home,
+      'home.drush' => $this->home . '/.drush',
+      'system' => UNISH_SANDBOX . '/etc/drush',
+      // We don't want to write a file into drush dir since it is not in the sandbox.
+      // 'drush' => dirname(realpath(UNISH_DRUSH)),
+    );
+    // Run each path through realpath() since the paths we'll compare against
+    // will have already run through drush_load_config_file().
+    foreach ($this->paths as $key => $path) $this->paths[$key] = realpath($path);
+  }
+
+  /*
+   * Try to write a tiny drushrc.php to each place that drush checks. Also
+   * write a sites/dev/aliases.drushrc.php file to the sandbox.
+   */
+  function setup() {
+    parent::setUp();
+
+    $this->env = 'dev';
+    $this->setUpDrupal($this->env, FALSE);
+    $this->setUpPaths();
+
+    // These files are only written to sandbox so get automatically cleaned up.
+    foreach ($this->paths as $key => $path) {
+      $contents = <<<EOD
+<?php
+// Written by Drush's contextCase::setup(). This file is safe to delete.
+
+\$options['contextConfig'] = '$key';
+\$command_specific['unit-eval']['contextConfig'] = '$key-specific';
+
+EOD;
+      $path .= $key == 'user' ? '/.drushrc.php' : '/drushrc.php';
+      if (file_put_contents($path, $contents)) {
+        $this->written[] = $path;
+      }
+    }
+
+    // Also write a site alias so we can test its supremacy in context hierarchy.
+    $path = $this->site . '/aliases.drushrc.php';
+    $aliases['contextAlias'] = array(
+      'contextConfig' => 'alias1',
+      'command-specific' => array (
+        'unit-eval' => array (
+          'contextConfig' => 'alias-specific',
+        ),
+      ),
+    );
+    $contents = $this->file_aliases($aliases);
+    $return = file_put_contents($path, $contents);
+  }
+
+  /*
+   * These should be two different tests but I could not work out how to do that
+   * without calling setup() twice. setupBeforeClass() did not work out (for MW).
+   */
+  function testContext() {
+    $this->ConfigFile();
+    $this->ContextHierarchy();
+  }
+
+  /*
+   * Assure that all possible config files get loaded.
+   */
+  function ConfigFile() {
+    $options = array(
+      'pipe' => NULL,
+      'config' => UNISH_SANDBOX,
+      'root' => $this->root,
+      'uri' => $this->env,
+    );
+    $this->drush('core-status', array('Drush configuration'), $options);
+    $output = trim($this->getOutput());
+    $loaded = explode(' ', $output);
+    $this->assertSame($this->written, $loaded);
+  }
+
+  /*
+   * Assure that options are loaded into right context and hierarchy is
+   * respected by drush_get_option().
+   *
+   * Stdin context not exercised here. See backendCase::testTarget().
+   */
+  function ContextHierarchy() {
+    // The 'custom' config file has higher priority than cli and regular config files.
+    $eval =  '$contextConfig = drush_get_option("contextConfig", "n/a");';
+    $eval .= '$cli1 = drush_get_option("cli1");';
+    $eval .= 'print json_encode(get_defined_vars());';
+    $config = UNISH_SANDBOX . '/drushrc.php';
+    $options = array(
+      'cli1' => NULL,
+      'config' => $config,
+      'root' => $this->root,
+      'uri' => $this->env,
+    );
+    $this->drush('php-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $actuals = json_decode(trim($output));
+    $this->assertEquals('custom', $actuals->contextConfig);
+    $this->assertTrue($actuals->cli1);
+
+    // Site alias trumps 'custom'.
+    $eval =  '$contextConfig = drush_get_option("contextConfig", "n/a");';
+    $eval .= 'print json_encode(get_defined_vars());';
+    $options = array(
+      'config' => $config,
+      'root' => $this->root,
+      'uri' => $this->env,
+    );
+    $this->drush('php-eval', array($eval), $options, '@contextAlias');
+    $output = $this->getOutput();
+    $actuals = json_decode(trim($output));
+    $this->assertEquals('alias1', $actuals->contextConfig);
+
+    // Command specific wins over non-specific. If it did not, $expected would
+    // be 'site'. Note we call unit-eval command in order not to purturb
+    // php-eval with options in config file.
+    $eval =  '$contextConfig = drush_get_option("contextConfig", "n/a");';
+    $eval .= 'print json_encode(get_defined_vars());';
+    $options = array(
+      'root' => $this->root,
+      'uri' => $this->env,
+      'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
+    );
+    $this->drush('unit-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $actuals = json_decode(trim($output));
+    $this->assertEquals('site-specific', $actuals->contextConfig);
+  }
+}
diff --git a/sites/all/modules/drush/tests/coreTest.php b/sites/all/modules/drush/tests/coreTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..514673a7f1651d1c72ad32363e1c606895d1c6ec
--- /dev/null
+++ b/sites/all/modules/drush/tests/coreTest.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * @file
+ *   Tests for core commands.
+ */
+class coreCase extends Drush_TestCase {
+
+  /*
+   * Test standalone php-script scripts. Assure that script args and options work.
+   */
+  public function testStandaloneScript() {
+    $this->drush('version', array('drush_version'), array('pipe' => NULL));
+    $standard = $this->getOutput();
+
+    // Write out a hellounish.script into the sandbox. The correct /path/to/drush
+    // is in the shebang line.
+    $filename = 'hellounish.script';
+    $data = '#!/usr/bin/env [PATH-TO-DRUSH]
+
+$arg = drush_shift();
+drush_invoke("version", $arg);
+';
+    $data = str_replace('[PATH-TO-DRUSH]', UNISH_DRUSH, $data);
+    $script = UNISH_SANDBOX . '/' . $filename;
+    file_put_contents($script, $data);
+    chmod($script, 0755);
+    $this->execute("$script drush_version --pipe");
+    $standalone = $this->getOutput();
+    $this->assertEquals($standard, $standalone);
+  }
+
+  function testDrupalDirectory() {
+    $this->setUpDrupal('dev', TRUE);
+    $root = $this->sites['dev']['root'];
+    $options = array(
+      'root' => $root,
+      'uri' => 'dev',
+      'verbose' => NULL,
+      'yes' => NULL,
+    );
+    $this->drush('pm-download', array('devel-7.x-1.0'), $options);
+    $this->drush('pm-enable', array('menu', 'devel'), $options);
+
+    $this->drush('drupal-directory', array('devel'), $options);
+    $output = $this->getOutput();
+    $this->assertEquals($root . '/sites/all/modules/devel', $output);
+
+    $this->drush('drupal-directory', array('%files'), $options);
+    $output = $this->getOutput();
+    $this->assertEquals($root . '/sites/dev/files', $output);
+
+    $this->drush('drupal-directory', array('%modules'), $options);
+    $output = $this->getOutput();
+    $this->assertEquals($root . '/sites/all/modules', $output);
+  }
+
+  function testCoreCLI() {
+    /*
+     * @todo
+     *   - BASHRC_PATH. Same file cleanup woes as contextTest.
+     *   - DRUSH_CLI
+     *   - INITIAL_SITE
+     *   - PS1. Hard to test in non interactive session?
+     *   - on
+     *   - use
+     *   - cd, cdd, lsd
+     *   - override, contextual
+     */
+
+    // Exercise core-cli's interactive mode.
+    // Include unit.drush.inc commandfile.
+    $options = array(
+      'include' => dirname(__FILE__),
+    );
+    // These commands will throw a failure if they return non-zero exit code.
+    // Assure that we create a bash function for command names.
+    $options['unit-extra'] = 'core-status;exit';
+    $this->drush('core-cli', array(), $options);
+    // Assure that we create a bash function for command aliases.
+    $options['unit-extra'] = 'st;exit';
+    $this->drush('core-cli', array(), $options);
+
+    // Assure that we create a bash alias for site aliases.
+    // First, write an alias file to the sandbox.
+    $path = UNISH_SANDBOX . '/aliases.drushrc.php';
+    $aliases['cliAlias'] = array(
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+    );
+    $contents = $this->file_aliases($aliases);
+    $return = file_put_contents($path, $contents);
+    // Append a bash command which starts with alias name (i.e. @cliAlias).
+    $options['unit-extra'] = sprintf('@cliAlias core-status --alias-path=%s;exit', UNISH_SANDBOX);
+    $options['alias-path'] = UNISH_SANDBOX;
+    $this->drush('core-cli', array(), $options);
+
+    // $this->markTestIncomplete('In progress below.');
+    // Exercise core-cli's non-interactive mode.
+    // We spawn our own bash session using the --pipe feature of core-cli.
+    //$options = array(
+    //  'pipe' => NULL,
+    //  'alias-path' => UNISH_SANDBOX,
+    //);
+    //$this->drush('core-cli', array(), $options);
+    //$bashrc_data = $this->getOutput();
+    //$bashrc_file = UNISH_SANDBOX . '/.bashrc';
+    //$extra = 'cd @cliAlias;exit;';
+    //$return = file_put_contents($bashrc_file, $bashrc_data . $extra);
+    //$this->setUpDrupal('dev', FALSE);
+    //$this->execute('bash --rcfile ' . $bashrc_file);
+    //$output = $this->getOutput();
+    //$this->assertContains('????', $output);
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/devel.xml b/sites/all/modules/drush/tests/devel.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb12be8801f59eee88e7137e3634843dd3b29c67
--- /dev/null
+++ b/sites/all/modules/drush/tests/devel.xml
@@ -0,0 +1,1101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project xmlns:dc="http://purl.org/dc/elements/1.1/">
+<title>Devel</title>
+<short_name>devel</short_name>
+<dc:creator>moshe weitzman</dc:creator>
+<api_version>6.x</api_version>
+<!--MW: Changed to 2 for testing.-->
+<recommended_major>2</recommended_major> 
+<supported_majors>1,2</supported_majors>
+<default_major>2</default_major>
+<project_status>published</project_status>
+
+<link>http://drupal.org/project/devel</link>
+  <terms>
+   <term><name>Projects</name><value>Modules</value></term>
+   <term><name>Projects</name><value>Administration</value></term>
+   <term><name>Projects</name><value>Developer</value></term>
+   <term><name>Projects</name><value>Utility</value></term>
+
+   <term><name>Projects</name><value>Drush</value></term>
+   <term><name>Maintenance status</name><value>Actively maintained</value></term>
+  </terms>
+  
+ <releases>
+  
+  <!-- Start 3 releases added by MW-->
+ <release>
+  <name>devel 6.x-2.2</name>
+  <version>6.x-2.2</version>
+
+  <tag>DRUPAL-6--2-2</tag>
+  <version_major>2</version_major>
+  <version_patch>2</version_patch>
+  <status>unpublished</status>
+  <release_link>http://drupal.org/node/990464</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-2.2.tar.gz</download_link>
+
+  <date>1291650063</date>
+  <mdhash>07251c1cd56daf7d402fb5aea7dcfe48</mdhash>
+  <filesize>172845</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.2.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+
+    <md5>07251c1cd56daf7d402fb5aea7dcfe48</md5>
+    <size>172845</size>
+    <filedate>1291650063</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.2.zip</url>
+    <archive_type>zip</archive_type>
+
+    <md5>086412aa4c02ced793455486b48261e9</md5>
+    <size>219993</size>
+    <filedate>1293230730</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ 
+ <release>
+  <name>devel 6.x-2.2-rc1</name>
+  <version>6.x-2.2-rc1</version>
+
+  <tag>DRUPAL-6--2-2-RC1</tag>
+  <version_major>2</version_major>
+  <version_extra>rc1</version_extra>
+  <version_patch>2</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/990464</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-2.2-rc1.tar.gz</download_link>
+
+  <date>1291650063</date>
+  <mdhash>07251c1cd56daf7d402fb5aea7dcfe48</mdhash>
+  <filesize>172845</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.2-rc1.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+
+    <md5>07251c1cd56daf7d402fb5aea7dcfe48</md5>
+    <size>172845</size>
+    <filedate>1291650063</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.2-rc1.zip</url>
+    <archive_type>zip</archive_type>
+
+    <md5>086412aa4c02ced793455486b48261e9</md5>
+    <size>219993</size>
+    <filedate>1293230730</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ 
+ <release>
+  <name>devel 6.x-2.1</name>
+  <version>6.x-2.1</version>
+
+  <tag>DRUPAL-6--2-1</tag>
+  <version_major>2</version_major>
+  <version_patch>1</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/990464</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-2.1.tar.gz</download_link>
+
+  <date>1291650063</date>
+  <mdhash>07251c1cd56daf7d402fb5aea7dcfe48</mdhash>
+  <filesize>172845</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.1.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+
+    <md5>07251c1cd56daf7d402fb5aea7dcfe48</md5>
+    <size>172845</size>
+    <filedate>1291650063</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-2.1.zip</url>
+    <archive_type>zip</archive_type>
+
+    <md5>086412aa4c02ced793455486b48261e9</md5>
+    <size>219993</size>
+    <filedate>1293230730</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <!--End added by MW-->
+ 
+ <release>
+  <name>devel 6.x-1.23</name>
+  <version>6.x-1.23</version>
+
+  <tag>DRUPAL-6--1-23</tag>
+  <version_major>1</version_major>
+  <version_patch>23</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/990464</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.23.tar.gz</download_link>
+
+  <date>1291650063</date>
+  <mdhash>07251c1cd56daf7d402fb5aea7dcfe48</mdhash>
+  <filesize>172845</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.23.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+
+    <md5>07251c1cd56daf7d402fb5aea7dcfe48</md5>
+    <size>172845</size>
+    <filedate>1291650063</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.23.zip</url>
+    <archive_type>zip</archive_type>
+
+    <md5>086412aa4c02ced793455486b48261e9</md5>
+    <size>219993</size>
+    <filedate>1293230730</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ 
+ 
+ <release>
+  <name>devel 6.x-1.22</name>
+  <version>6.x-1.22</version>
+  <tag>DRUPAL-6--1-22</tag>
+
+  <version_major>1</version_major>
+  <version_patch>22</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/882460</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.22.tar.gz</download_link>
+  <date>1281718291</date>
+
+  <mdhash>a8a87cae8f101c4aad46688524ab7583</mdhash>
+  <filesize>175140</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.22.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>a8a87cae8f101c4aad46688524ab7583</md5>
+
+    <size>175140</size>
+    <filedate>1281718291</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.22.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>cc207ab34421975216e6ee424c595001</md5>
+
+    <size>222352</size>
+    <filedate>1293230727</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+
+ </release>
+ <release>
+  <name>devel 6.x-1.21</name>
+  <version>6.x-1.21</version>
+  <tag>DRUPAL-6--1-21</tag>
+  <version_major>1</version_major>
+  <version_patch>21</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/874116</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.21.tar.gz</download_link>
+  <date>1280961079</date>
+  <mdhash>15bf95b8c3fbe3f570f3f7b590f52ded</mdhash>
+  <filesize>175008</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.21.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>15bf95b8c3fbe3f570f3f7b590f52ded</md5>
+    <size>175008</size>
+    <filedate>1280961079</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.21.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>f19fe1188a2774b383f146aee228a083</md5>
+    <size>222217</size>
+    <filedate>1293230734</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Security update</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.20</name>
+
+  <version>6.x-1.20</version>
+  <tag>DRUPAL-6--1-20</tag>
+  <version_major>1</version_major>
+  <version_patch>20</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/777998</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.20.tar.gz</download_link>
+  <date>1271886306</date>
+  <mdhash>b605d6a42e430660ef3418541d711c1c</mdhash>
+  <filesize>174042</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.20.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>b605d6a42e430660ef3418541d711c1c</md5>
+    <size>174042</size>
+    <filedate>1271886306</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.20.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>ff11ac877bdbbb29fa9dba024871e3bc</md5>
+    <size>221132</size>
+    <filedate>1293230727</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.19</name>
+  <version>6.x-1.19</version>
+  <tag>DRUPAL-6--1-19</tag>
+
+  <version_major>1</version_major>
+  <version_patch>19</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/746888</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.19.tar.gz</download_link>
+  <date>1268976904</date>
+
+  <mdhash>375c3b79e9e74fb636bf8a6d2fde87d6</mdhash>
+  <filesize>173570</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.19.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>375c3b79e9e74fb636bf8a6d2fde87d6</md5>
+
+    <size>173570</size>
+    <filedate>1268976904</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.19.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>b9da9992305f2aa8e26bd9550c119189</md5>
+
+    <size>220677</size>
+    <filedate>1293230724</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.18</name>
+  <version>6.x-1.18</version>
+  <tag>DRUPAL-6--1-18</tag>
+  <version_major>1</version_major>
+
+  <version_patch>18</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/585982</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.18.tar.gz</download_link>
+  <date>1253731829</date>
+  <mdhash>5f2b9e5f4b74beec35a1d1cff379ab5c</mdhash>
+
+  <filesize>165785</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.18.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>5f2b9e5f4b74beec35a1d1cff379ab5c</md5>
+    <size>165785</size>
+
+    <filedate>1253731829</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.18.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>2e2808ec65aaa44d23f2a96c6af8bfbb</md5>
+
+    <size>216330</size>
+    <filedate>1293230728</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+   <term><name>Release type</name><value>Security update</value></term>
+
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.17</name>
+  <version>6.x-1.17</version>
+  <tag>DRUPAL-6--1-17</tag>
+  <version_major>1</version_major>
+
+  <version_patch>17</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/554032</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.17.tar.gz</download_link>
+  <date>1250713853</date>
+  <mdhash>31b2cbea82226a729b11bbc91920a7cd</mdhash>
+
+  <filesize>163024</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.17.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>31b2cbea82226a729b11bbc91920a7cd</md5>
+    <size>163024</size>
+
+    <filedate>1250713853</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.17.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>5e2a367f2e43c90de1e676e3037e1570</md5>
+    <size>213291</size>
+
+    <filedate>1293230731</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.16</name>
+  <version>6.x-1.16</version>
+  <tag>DRUPAL-6--1-16</tag>
+  <version_major>1</version_major>
+
+  <version_patch>16</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/430072</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.16.tar.gz</download_link>
+  <date>1239375932</date>
+  <mdhash>6dc83de5de101460f8eee2db3ea4b7d9</mdhash>
+
+  <filesize>163998</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.16.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>6dc83de5de101460f8eee2db3ea4b7d9</md5>
+    <size>163998</size>
+
+    <filedate>1239375932</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.16.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>65ad91bc0308b10a9d11107f2d35bc2f</md5>
+    <size>215213</size>
+
+    <filedate>1293230728</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+
+ <release>
+  <name>devel 6.x-1.15</name>
+  <version>6.x-1.15</version>
+  <tag>DRUPAL-6--1-15</tag>
+  <version_major>1</version_major>
+  <version_patch>15</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/419014</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.15.tar.gz</download_link>
+  <date>1238471715</date>
+  <mdhash>e7cd175671ed62a95bab7093c636e663</mdhash>
+  <filesize>163945</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.15.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>e7cd175671ed62a95bab7093c636e663</md5>
+    <size>163945</size>
+    <filedate>1238471715</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.15.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>f0719bb64bdeb1d3c2f327457351b9d1</md5>
+    <size>215342</size>
+    <filedate>1293230731</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+
+ <release>
+  <name>devel 6.x-1.14</name>
+  <version>6.x-1.14</version>
+  <tag>DRUPAL-6--1-14</tag>
+  <version_major>1</version_major>
+  <version_patch>14</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/368174</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.14.tar.gz</download_link>
+  <date>1233610814</date>
+  <mdhash>11af2d7fa3050febfe3def770683f173</mdhash>
+  <filesize>162780</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.14.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>11af2d7fa3050febfe3def770683f173</md5>
+    <size>162780</size>
+    <filedate>1233610814</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.14.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>c691c6d03d1f605493807cf7dad7dce1</md5>
+    <size>214014</size>
+    <filedate>1293230725</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.13</name>
+
+  <version>6.x-1.13</version>
+  <tag>DRUPAL-6--1-13</tag>
+  <version_major>1</version_major>
+  <version_patch>13</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/353382</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.13.tar.gz</download_link>
+  <date>1230872109</date>
+  <mdhash>669870433908fccd31e7de9b57434c64</mdhash>
+  <filesize>161893</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.13.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>669870433908fccd31e7de9b57434c64</md5>
+    <size>161893</size>
+    <filedate>1230872109</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.13.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>06ed93306fe8476af6aa62aac763afa4</md5>
+    <size>212645</size>
+    <filedate>1293230728</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.12</name>
+
+  <version>6.x-1.12</version>
+  <tag>DRUPAL-6--1-12</tag>
+  <version_major>1</version_major>
+  <version_patch>12</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/319216</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.12.tar.gz</download_link>
+  <date>1223583012</date>
+  <mdhash>69b345c09ece34812b04e7ccbc2cdf23</mdhash>
+  <filesize>146188</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.12.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>69b345c09ece34812b04e7ccbc2cdf23</md5>
+    <size>146188</size>
+    <filedate>1223583012</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.12.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>8c66e91fc8c64388facf8e7e7054e58a</md5>
+    <size>197116</size>
+    <filedate>1293230726</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.11</name>
+
+  <version>6.x-1.11</version>
+  <tag>DRUPAL-6--1-11</tag>
+  <version_major>1</version_major>
+  <version_patch>11</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/310335</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.11.tar.gz</download_link>
+  <date>1221759046</date>
+  <mdhash>93bc2cc8da26d759e46b24f1b9d4e3e2</mdhash>
+  <filesize>145693</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.11.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>93bc2cc8da26d759e46b24f1b9d4e3e2</md5>
+    <size>145693</size>
+    <filedate>1221759046</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.11.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>3c1063443d81927e3b90e129bc169a24</md5>
+    <size>196477</size>
+    <filedate>1293230729</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.10</name>
+
+  <version>6.x-1.10</version>
+  <tag>DRUPAL-6--1-10</tag>
+  <version_major>1</version_major>
+  <version_patch>10</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/283183</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.10.tar.gz</download_link>
+  <date>1216171206</date>
+  <mdhash>688ed33b3a2a63bc1bce9da3c2d104de</mdhash>
+  <filesize>145188</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.10.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>688ed33b3a2a63bc1bce9da3c2d104de</md5>
+    <size>145188</size>
+    <filedate>1216171206</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.10.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>c9e85aac38d3c2f18015c820ec325206</md5>
+    <size>195931</size>
+    <filedate>1293230732</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.9</name>
+
+  <version>6.x-1.9</version>
+  <tag>DRUPAL-6--1-9</tag>
+  <version_major>1</version_major>
+  <version_patch>9</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/270064</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.9.tar.gz</download_link>
+  <date>1213331113</date>
+  <mdhash>8b88659f45e31d8c05fd6990c491ea2a</mdhash>
+  <filesize>145153</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.9.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>8b88659f45e31d8c05fd6990c491ea2a</md5>
+    <size>145153</size>
+    <filedate>1213331113</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.9.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>0d934dafa2cedd0d1bc5ec450cc9570f</md5>
+    <size>195856</size>
+    <filedate>1293230729</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.8</name>
+
+  <version>6.x-1.8</version>
+  <tag>DRUPAL-6--1-8</tag>
+  <version_major>1</version_major>
+  <version_patch>8</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/259615</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.8.tar.gz</download_link>
+  <date>1211039106</date>
+  <mdhash>d8d8f4ee8dd61ccad625443ebafbe421</mdhash>
+  <filesize>76796</filesize>
+  <files>
+   <file>
+
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.8.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>d8d8f4ee8dd61ccad625443ebafbe421</md5>
+    <size>76796</size>
+    <filedate>1211039106</filedate>
+   </file>
+
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.8.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>72b3468d765e1f9e827d9399f2d7218c</md5>
+    <size>92505</size>
+    <filedate>1293230732</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+
+ <release>
+  <name>devel 6.x-1.7</name>
+  <version>6.x-1.7</version>
+  <tag>DRUPAL-6--1-7</tag>
+  <version_major>1</version_major>
+  <version_patch>7</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/237840</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.7.tar.gz</download_link>
+  <date>1206300306</date>
+  <mdhash>b63eba9e1588baa2f8031589897eb376</mdhash>
+  <filesize>72504</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.7.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>b63eba9e1588baa2f8031589897eb376</md5>
+    <size>72504</size>
+    <filedate>1206300306</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.7.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>9e4711ebace4e7cf0d7dc4e4a1386be3</md5>
+    <size>87847</size>
+    <filedate>1293230726</filedate>
+
+   </file>
+  </files>
+ </release>
+ <release>
+  <name>devel 6.x-1.6</name>
+  <version>6.x-1.6</version>
+  <tag>DRUPAL-6--1-6</tag>
+
+  <version_major>1</version_major>
+  <version_patch>6</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/229249</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.6.tar.gz</download_link>
+  <date>1204515005</date>
+
+  <mdhash>dc2fd4030922e17258a0fa886557aa9f</mdhash>
+  <filesize>72109</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.6.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>dc2fd4030922e17258a0fa886557aa9f</md5>
+
+    <size>72109</size>
+    <filedate>1204515005</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.6.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>65cf489c56834571eaf43a30e87a25ef</md5>
+
+    <size>87441</size>
+    <filedate>1293230732</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+
+ </release>
+ <release>
+  <name>devel 6.x-1.5</name>
+  <version>6.x-1.5</version>
+  <tag>DRUPAL-6--1-5</tag>
+  <version_major>1</version_major>
+  <version_patch>5</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/227742</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.5.tar.gz</download_link>
+  <date>1204163705</date>
+  <mdhash>4755dc85712f86c24a7615c83bf2d587</mdhash>
+  <filesize>72424</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.5.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>4755dc85712f86c24a7615c83bf2d587</md5>
+    <size>72424</size>
+    <filedate>1204163705</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.5.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>3def5895dcd04439f2e7c69e33ae3ef7</md5>
+    <size>87108</size>
+    <filedate>1293230729</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.4</name>
+
+  <version>6.x-1.4</version>
+  <tag>DRUPAL-6--1-4</tag>
+  <version_major>1</version_major>
+  <version_patch>4</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/224889</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.4.tar.gz</download_link>
+  <date>1203609008</date>
+  <mdhash>9361284333474368c49b807943e7eb09</mdhash>
+  <filesize>72289</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.4.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>9361284333474368c49b807943e7eb09</md5>
+    <size>72289</size>
+    <filedate>1203609008</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.4.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>0ee1899e32edcdb56ac13b067c8bb2aa</md5>
+    <size>86956</size>
+    <filedate>1293230733</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.3</name>
+  <version>6.x-1.3</version>
+  <tag>DRUPAL-6--1-3</tag>
+
+  <version_major>1</version_major>
+  <version_patch>3</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/223052</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.3.tar.gz</download_link>
+  <date>1203291304</date>
+
+  <mdhash>5dbb78276404810a219395d790bb349d</mdhash>
+  <filesize>72231</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.3.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>5dbb78276404810a219395d790bb349d</md5>
+
+    <size>72231</size>
+    <filedate>1203291304</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.3.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>293c305a758cd84b1a5b1e0f56c6883f</md5>
+
+    <size>86893</size>
+    <filedate>1293230727</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+
+ </release>
+ <release>
+  <name>devel 6.x-1.2</name>
+  <version>6.x-1.2</version>
+  <tag>DRUPAL-6--1-2</tag>
+  <version_major>1</version_major>
+  <version_patch>2</version_patch>
+
+  <status>published</status>
+  <release_link>http://drupal.org/node/223032</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.2.tar.gz</download_link>
+  <date>1203288005</date>
+  <mdhash>ec2d609a553289636f2388c54fc69e8b</mdhash>
+  <filesize>72232</filesize>
+
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.2.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>ec2d609a553289636f2388c54fc69e8b</md5>
+    <size>72232</size>
+    <filedate>1203288005</filedate>
+
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.2.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>5855930a3427fdc2c3449aebf8ad68f9</md5>
+    <size>86895</size>
+    <filedate>1293230730</filedate>
+
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.1</name>
+
+  <version>6.x-1.1</version>
+  <tag>DRUPAL-6--1-1</tag>
+  <version_major>1</version_major>
+  <version_patch>1</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/222919</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.1.tar.gz</download_link>
+  <date>1203267606</date>
+  <mdhash>2d1065298518decda8eb0d0473851ed1</mdhash>
+  <filesize>72225</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.1.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>2d1065298518decda8eb0d0473851ed1</md5>
+    <size>72225</size>
+    <filedate>1203267606</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.1.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>f72a6870d67d929970c78151f7737ebc</md5>
+    <size>86896</size>
+    <filedate>1293230733</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>New features</value></term>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.0</name>
+
+  <version>6.x-1.0</version>
+  <tag>DRUPAL-6--1-0</tag>
+  <version_major>1</version_major>
+  <version_patch>0</version_patch>
+  <status>published</status>
+  <release_link>http://drupal.org/node/208665</release_link>
+
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.0.tar.gz</download_link>
+  <date>1200012604</date>
+  <mdhash>3dbd3cd4c15f001c1ac7067ca58c74ff</mdhash>
+  <filesize>53802</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.0.tar.gz</url>
+
+    <archive_type>tar.gz</archive_type>
+    <md5>3dbd3cd4c15f001c1ac7067ca58c74ff</md5>
+    <size>53802</size>
+    <filedate>1200012604</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.0.zip</url>
+
+    <archive_type>zip</archive_type>
+    <md5>10600179cfa8a301784839983fb49397</md5>
+    <size>64756</size>
+    <filedate>1293230727</filedate>
+   </file>
+  </files>
+  <terms>
+
+   <term><name>Release type</name><value>Security update</value></term>
+  </terms>
+ </release>
+ <release>
+  <name>devel 6.x-1.x-dev</name>
+  <version>6.x-1.x-dev</version>
+  <tag>DRUPAL-6--1</tag>
+
+  <version_major>1</version_major>
+  <version_extra>dev</version_extra>
+  <status>published</status>
+  <release_link>http://drupal.org/node/224617</release_link>
+  <download_link>http://ftp.drupal.org/files/projects/devel-6.x-1.x-dev.tar.gz</download_link>
+  <date>1295179817</date>
+
+  <mdhash>fec92fdc9dd40f34b2e7f9876fd44014</mdhash>
+  <filesize>126254</filesize>
+  <files>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.x-dev.tar.gz</url>
+    <archive_type>tar.gz</archive_type>
+    <md5>fec92fdc9dd40f34b2e7f9876fd44014</md5>
+
+    <size>126254</size>
+    <filedate>1295179817</filedate>
+   </file>
+   <file>
+    <url>http://ftp.drupal.org/files/projects/devel-6.x-1.x-dev.zip</url>
+    <archive_type>zip</archive_type>
+    <md5>91255187be4c5cd7bacf7112e6b0189b</md5>
+
+    <size>171436</size>
+    <filedate>1295179818</filedate>
+   </file>
+  </files>
+ </release>
+ <release>
+  <name>devel 6.x-0.2</name>
+
+  <version>6.x-0.2</version>
+  <tag>DRUPAL-6--0-2</tag>
+  <version_major>0</version_major>
+  <version_patch>2</version_patch>
+  <status>unpublished</status>
+  <date>1203287704</date>
+
+  <mdhash>a071278bf76df5acf5320086f80ff4f5</mdhash>
+  <filesize>72235</filesize>
+  <files>
+   <file>
+    <archive_type>tar.gz</archive_type>
+    <md5>a071278bf76df5acf5320086f80ff4f5</md5>
+    <size>72235</size>
+
+    <filedate>1203287704</filedate>
+   </file>
+  </files>
+  <terms>
+   <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+
+</releases>
+</project>
diff --git a/sites/all/modules/drush/tests/drush_testcase.inc b/sites/all/modules/drush/tests/drush_testcase.inc
new file mode 100644
index 0000000000000000000000000000000000000000..9da78aeb12c14384dc313bcdd340555f6a4a4303
--- /dev/null
+++ b/sites/all/modules/drush/tests/drush_testcase.inc
@@ -0,0 +1,340 @@
+<?php
+
+/*
+ * @file
+ *   Initialize a sandboxed environment. Starts with call unish_init() at bottom.
+ */
+
+abstract class Drush_TestCase extends PHPUnit_Framework_TestCase {
+
+  // Unix exit codes.
+  const EXIT_SUCCESS  = 0;
+  const EXIT_ERROR = 1;
+
+  /*
+   * An array of Drupal sites that are setup in the drush-sandbox.
+   */
+  var $sites;
+
+  function __construct() {
+    $this->_output = false;
+  }
+
+  /**
+   * Assure that each class starts with an empty sandbox directory and
+   * a clean environment - http://drupal.org/node/1103568.
+   */
+  public static function setUpBeforeClass() {
+    $sandbox = UNISH_SANDBOX;
+    if (file_exists($sandbox)) {
+      unish_file_delete_recursive($sandbox);
+    }
+    $ret = mkdir($sandbox, 0777, TRUE);
+    chdir(UNISH_SANDBOX);
+
+    mkdir(getenv('HOME') . '/.drush', 0777, TRUE);
+    mkdir($sandbox . '/etc/drush', 0777, TRUE);
+    mkdir($sandbox . '/share/drush/commands', 0777, TRUE);
+  }
+
+  /**
+   * Runs after each test case. Remove sandbox directory.
+   */
+  public static function tearDownAfterClass() {
+    if (file_exists(UNISH_SANDBOX)) {
+      unish_file_delete_recursive(UNISH_SANDBOX);
+    }
+  }
+
+  public static function is_windows() {
+    return (strtoupper(substr(PHP_OS, 0, 3)) == "WIN");
+  }
+
+  public static function escapeshellarg($arg) {
+    // Short-circuit escaping for simple params (keep stuff readable)
+    if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) {
+      return $arg;
+    }
+    elseif (self::is_windows()) {
+      return self::_escapeshellarg_windows($arg);
+    }
+    else {
+      return escapeshellarg($arg);
+    }
+  }
+
+  public static function _escapeshellarg_windows($arg) {
+    // Double up existing backslashes
+    $arg = preg_replace('/\\\/', '\\\\\\\\', $arg);
+
+    // Escape double quotes.
+    $arg = preg_replace('/"/', '\\"', $arg);
+
+    // Escape single quotes.
+    $arg = preg_replace('/\'/', '\\\'', $arg);
+
+    // Add surrounding quotes.
+    $arg = '"' . $arg . '"';
+
+    return $arg;
+  }
+
+  /**
+   * Actually runs the command. Does not trap the error stream output as this
+   * need PHP 4.3+.
+   *
+   * @param string $command
+   *   The actual command line to run.
+   * @return integer
+   *   Exit code. Usually self::EXIT_ERROR or self::EXIT_SUCCESS.
+   */
+  function execute($command, $expected_return = self::EXIT_SUCCESS) {
+    $this->_output = FALSE;
+    // todo check verbose level from phpunit.
+    if (TRUE) {
+      print "\nExecuting: $command \n";
+    }
+    exec($command, $this->_output, $return);
+    $this->assertEquals($expected_return, $return, 'Unexpected exit code: ' .  $command);
+    return $return;
+  }
+
+  /**
+   * Invoke drush in via execute().
+   *
+   * @param command
+    *   A defined drush command such as 'cron', 'status' or any of the available ones such as 'drush pm'.
+    * @param args
+    *   Command arguments.
+    * @param $options
+    *   An associative array containing options.
+    * @param $site_specification
+    *   A site alias or site specification. Include the '@' at start of a site alias.
+    * @param $cd
+    *   A directory to change into before executing.
+    * @return integer
+    *   An exit code.
+    */
+  function drush($command, array $args = array(), array $options = array(), $site_specification = NULL, $cd = NULL) {
+    $cmd[] = $cd ? sprintf('cd %s;', self::escapeshellarg($cd)) : NULL;
+    $cmd[] = UNISH_DRUSH;
+    $cmd[] = empty($site_specification) ? NULL : self::escapeshellarg($site_specification);
+    $cmd[] = $command;
+    if (in_array('--verbose', $_SERVER['argv'])) $args[] = '--verbose';
+    if (in_array('--debug', $_SERVER['argv'])) $args[] = '--debug';
+
+    foreach ($args as $arg) {
+      $cmd[] = self::escapeshellarg($arg);
+    }
+    $options['nocolor'] = NULL;
+    foreach ($options as $key => $value) {
+      if (is_null($value)) {
+        $cmd[] = "--$key";
+      }
+      else {
+        $cmd[] = "--$key=" . self::escapeshellarg($value);
+      }
+    }
+    $exec = array_filter($cmd, 'strlen'); // Remove NULLs
+    return $this->execute(implode(' ', $exec));
+  }
+
+  /**
+   *    Accessor for the last output.
+   *    @return string        Output as text.
+   *    @access public
+   */
+  function getOutput() {
+    return implode("\n", $this->_output);
+  }
+
+  /**
+   *    Accessor for the last output.
+   *    @return array         Output as array of lines.
+   *    @access public
+   */
+  function getOutputAsList() {
+    return $this->_output;
+  }
+
+  function setUpDrupal($env = 'dev', $install = FALSE, $version_string = '7.x', $profile = NULL) {
+    $root = UNISH_SANDBOX . '/web';
+    $this->sites[$env]['root'] = $root;
+    $site = "$root/sites/$env";
+    if (is_null($profile)) {
+      $profile = substr($version_string, 0, 1) >= 7 ? 'testing' : 'default';
+    }
+
+    // Download Drupal if not already present.
+    if (!file_exists($root)) {
+      $options = array(
+        'destination' => UNISH_SANDBOX,
+        'drupal-project-rename' => 'web',
+        'yes' => NULL,
+        'quiet' => NULL,
+      );
+      $this->drush('pm-download', array("drupal-$version_string"), $options);
+    }
+
+    // If specified, install Drupal as a multi-site.
+    if ($install) {
+      $options = array(
+        'root' => $root,
+        'db-url' => UNISH_DB_URL . '/unish_' . $env,
+        'sites-subdir' => $env,
+        'yes' => NULL,
+        'quiet' => NULL,
+      );
+      $this->drush('site-install', array($profile), $options);
+      // Give us our write perms back.
+      $ret = chmod($site, 0777);
+
+      // Stash the db_url for this site.
+      $this->sites[$env]['db_url'] = UNISH_DB_URL . '/unish_' . $env;
+    }
+    else {
+      mkdir($site);
+      touch("$site/settings.php");
+    }
+    // Make an alias for the site
+    $alias_definition = array($env => array('root' => $root,  'uri' => $env));
+    file_put_contents(UNISH_SANDBOX . '/etc/drush/' . $env . '.alias.drushrc.php', $this->file_aliases($alias_definition));
+  }
+
+  // Copied from D7 - profiles/standard/standard.install
+  function create_node_types_php() {
+    $php = "
+      \$types = array(
+        array(
+          'type' => 'page',
+          'name' => 'Basic page',
+          'base' => 'node_content',
+          'description' => 'Use <em>basic pages</em> for your static content, such as an \'About us\' page.',
+          'custom' => 1,
+          'modified' => 1,
+          'locked' => 0,
+        ),
+        array(
+          'type' => 'article',
+          'name' => 'Article',
+          'base' => 'node_content',
+          'description' => 'Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.',
+          'custom' => 1,
+          'modified' => 1,
+          'locked' => 0,
+        ),
+      );
+
+      foreach (\$types as \$type) {
+        \$type = node_type_set_defaults(\$type);
+        node_type_save(\$type);
+        node_add_body_field(\$type);
+      }
+    ";
+    return $php;
+  }
+
+  /*
+   * Prepare the contents of an aliases file.
+   */
+  function file_aliases($aliases) {
+    foreach ($aliases as $name => $alias) {
+      $records[] = sprintf('$aliases[\'%s\'] = %s;', $name, var_export($alias, TRUE));
+    }
+    $contents = "<?php\n\n" . implode("\n\n", $records);
+    return $contents;
+  }
+
+  /**
+   * Same code as drush_delete_dir().
+   * @see drush_delete_dir()
+   *
+   * @param string $dir
+   * @return boolean
+   */
+  function file_delete_recursive($dir) {
+    if (!file_exists($dir)) {
+      return TRUE;
+    }
+    if (!is_dir($dir)) {
+      @chmod($dir, 0777); // Make file writeable
+      return unlink($dir);
+    }
+    foreach (scandir($dir) as $item) {
+      if ($item == '.' || $item == '..') {
+        continue;
+      }
+      if (!self::file_delete_recursive($dir.'/'.$item)) {
+        return FALSE;
+      }
+    }
+    return rmdir($dir);
+  }
+}
+
+/*
+ * Initialize our environment at he start of each run (i.e. suite).
+ */
+function unish_init() {
+  // We read from globals here because env can be empty and ini did not work in quick test.
+  define('UNISH_DB_URL', getenv('UNISH_DB_URL') ? getenv('UNISH_DB_URL') : !empty($GLOBALS['UNISH_DB_URL']) ? $GLOBALS['UNISH_DB_URL'] : 'mysql://root:@127.0.0.1');
+
+  // UNISH_DRUSH value can come from phpunit.xml or `which drush`.
+  if (!defined('UNISH_DRUSH')) {
+    // Let the UNISH_DRUSH environment variable override if set.
+    $unish_drush = isset($_SERVER['UNISH_DRUSH']) ? $_SERVER['UNISH_DRUSH'] : NULL;
+    $unish_drush = isset($GLOBALS['UNISH_DRUSH']) ? $GLOBALS['UNISH_DRUSH'] : $unish_drush;
+    if (empty($unish_drush)) {
+      $unish_drush = Drush_TestCase::is_windows() ? exec('for %i in (drush) do @echo.   %~$PATH:i') : trim(`which drush`);
+    }
+    define('UNISH_DRUSH', $unish_drush);
+  }
+
+  define('UNISH_TMP', getenv('UNISH_TMP') ? getenv('UNISH_TMP') : (isset($GLOBALS['UNISH_TMP']) ? $GLOBALS['UNISH_TMP'] : sys_get_temp_dir()));
+  define('UNISH_SANDBOX', UNISH_TMP . '/drush-sandbox');
+
+  $home = UNISH_SANDBOX . '/home';
+  putenv("HOME=$home");
+  putenv("HOMEDRIVE=$home");
+
+  putenv('ETC_PREFIX=' . UNISH_SANDBOX);
+  putenv('SHARE_PREFIX=' . UNISH_SANDBOX);
+
+  // Cache dir lives outside the sandbox so that we get persistence across classes.
+  $cache = UNISH_TMP . '/drush_cache';
+  putenv("CACHE_PREFIX=" . $cache);
+  // Wipe at beginning of run.
+  if (file_exists($cache)) {
+    unish_file_delete_recursive($cache);
+  }
+}
+
+/**
+  * Same code as drush_delete_dir().
+  * @see drush_delete_dir()
+  *
+  * @param string $dir
+  * @return boolean
+  */
+ function unish_file_delete_recursive($dir) {
+   if (!file_exists($dir)) {
+     return TRUE;
+   }
+   if (!is_dir($dir)) {
+     @chmod($dir, 0777); // Make file writeable
+     return unlink($dir);
+   }
+   foreach (scandir($dir) as $item) {
+     if ($item == '.' || $item == '..') {
+       continue;
+     }
+     if (!unish_file_delete_recursive($dir.'/'.$item)) {
+       return FALSE;
+     }
+   }
+   return rmdir($dir);
+ }
+
+ // This code is in global scope.
+ // TODO: I would rather this code at top of file, but I get Fatal error: Class 'Drush_TestCase' not found
+ unish_init();
diff --git a/sites/all/modules/drush/tests/fieldTest.php b/sites/all/modules/drush/tests/fieldTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..00414ea1d3702a3106b582d61176d3bd43bea7c1
--- /dev/null
+++ b/sites/all/modules/drush/tests/fieldTest.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * @file
+ *   Tests for field.drush.inc
+ */
+class fieldCase extends Drush_TestCase {
+
+  public function testField() {
+    $this->setUpDrupal('dev', TRUE);
+    $options = array(
+      'yes' => NULL,
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+    );
+    // Create two field instances on article content type.
+    $this->drush('field-create', array('user', 'city,text,text_textfield', 'subtitle,text,text_textfield'), $options + array('entity_type' => 'user'));
+    $output = $this->getOutput();
+    list($city, $subtitle) = explode(' ', $output);
+    $url = parse_url($subtitle);
+    $this->assertEquals('/admin/config/people/accounts/fields/subtitle', $url['path']);
+
+    // Assure that the second field instance was created correctly (subtitle).
+    $this->verifyInstance('subtitle', $options);
+
+    // Assure that field update URL looks correct.
+    $this->drush('field-update', array('subtitle'), $options);
+    $output = $this->getOutput();
+    $url = parse_url($this->getOutput());
+    $this->assertEquals('/admin/config/people/accounts/fields/subtitle', $url['path']);
+
+    // Assure that field-clone actually clones.
+    $this->drush('field-clone', array('subtitle', 'subtitlecloned'), $options);
+    $this->verifyInstance('subtitlecloned', $options);
+
+    // Assure that delete works.
+    $this->drush('field-delete', array('subtitlecloned'), $options);
+    $this->verifyInstance('subtitlecloned', $options, FALSE);
+  }
+
+  function verifyInstance($name, $options, $expected = TRUE) {
+    $this->drush('field-info', array('fields'), $options + array('pipe' => NULL));
+    $output = $this->getOutputAsList();
+    $found = FALSE;
+    foreach($output as $row) {
+      $columns = explode(',', $row);
+      if ($columns[0] == $name) {
+        $this->assertEquals('text', $columns[1], $name . ' field is of type=text.');
+        $this->assertEquals('user', $columns[2], $name . ' field was added to user bundle.');
+        $found = TRUE;
+        break;
+      }
+    }
+    if ($expected) {
+      $this->assertTrue($found, $name . ' field was created.');
+    }
+    else {
+      $this->assertFalse($found, $name . ' field was not present.');
+    }
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/phpunit.xml.dist b/sites/all/modules/drush/tests/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..45d27c1080faf6d30e2d200895ccb84a42d6eaf2
--- /dev/null
+++ b/sites/all/modules/drush/tests/phpunit.xml.dist
@@ -0,0 +1,23 @@
+<!-- Copy and rename to phpunit.xml. Customize as needed. -->
+<phpunit backupGlobals="false"
+    backupStaticAttributes="false"
+    syntaxCheck="false"
+    bootstrap="drush_testcase.inc">
+  <php>
+    <!-- These variables may alternatively be set as bash environment variables. -->
+
+    <!--Uncomment and edit one of the lines below depending on DB platform.-->
+    <!--DB User must have create/drop permissions-->
+    <!-- <var name="UNISH_DB_URL" value="mysql://root:@127.0.0.1"/> -->
+    <!-- <var name="UNISH_DB_URL" value="pgsql://postgres:@localhost"/>-->
+
+    <!--User must have write permissions to this directory.-->
+    <!--If not supplied, defaults to sys_get_tmp_dir().-->
+    <!-- <var name="UNISH_TMP" value="/tmp"/> -->
+
+    <!--Uncomment the line below if your path to drush differs from `which drush`. Use absolute path.-->
+    <!--<var name="UNISH_DRUSH" value="/Users/mw/bin/drush"/>-->
+
+    <includePath>.</includePath>
+  </php>
+</phpunit>
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/pmDownloadTest.php b/sites/all/modules/drush/tests/pmDownloadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..449a1827f72902a4ec422e40f76f095fcaa41ce9
--- /dev/null
+++ b/sites/all/modules/drush/tests/pmDownloadTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+  * pm-download testing
+  */  
+class pmDownloadCase extends Drush_TestCase {
+  public function testPmDownload() {
+    $this->drush('pm-download', array('devel'));
+    $this->assertFileExists(UNISH_SANDBOX . '/devel/README.txt');
+  }
+
+  /*
+   * Parse Drupal version and release from command argument.
+   *
+   * --dev option bypasses the logic tested here.
+   * 
+   * @see pm_parse_project_version().
+   */ 
+  public function testVersionString() {
+    $eval = 'print json_encode(pm_parse_project_version(array("devel-6.x-1.18")));';
+    $this->drush('php-eval', array($eval));
+    $request_data = json_decode($this->getOutput());
+    $this->assertObjectHasAttribute('devel', $request_data);
+    $this->assertEquals($request_data->devel->drupal_version, '6.x');
+    $this->assertEquals($request_data->devel->project_version, '1.18');
+  }
+
+  /*
+   * Pick right release from the XML (dev, latest published+recommended, ...).
+   */ 
+  public function testReleaseXML() {
+    // Use a local, static XML file because live files change over time.
+    $xml = dirname(__FILE__). '/devel.xml';
+    
+    // Pick specific release.
+    $request_data = array(
+      'name' => 'devel',
+      'drupal_version' => '6.x',
+      'project_version' => '1.18',
+      'version' => '6.x-1.18',
+    );
+    // Build an $eval string for use with php-eval in a subprocess.
+    $eval = '$request_data = ' . var_export($request_data, TRUE) . ";\n";
+    $eval .= '$release = pm_parse_release($request_data, simplexml_load_file(\'' . $xml . "'));\n";
+    $eval .= 'print json_encode($release);';
+    $this->drush('php-eval', array($eval));
+    $release = json_decode($this->getOutput());
+    $this->assertEquals($release->version, '6.x-1.18');
+    
+    // Pick latest recommended+published with no further specification.
+    // 6.x-2.2 is skipped because it is unpublished.
+    // 6.x-2.2-rc1 is skipped because it is not a stable release.
+    // Remove unwanted $request_data items.
+    $eval = str_replace(array("'project_version' => '1.18',\n", "'version' => '6.x-1.18',\n"), NULL, $eval);
+    $this->drush('php-eval', array($eval));
+    $release = json_decode($this->getOutput());
+    $this->assertEquals($release->version, '6.x-2.1');
+  }
+  
+  // @todo Test pure drush commandfile projects. They get special destination.
+  public function testDestination() {
+    // Setup first Drupal site. Skip install for speed.
+    $this->setUpDrupal('dev', FALSE);
+    $root = $this->sites['dev']['root'];
+
+    // Default to sites/all
+    $this->drush('pm-download', array('devel'), array('root' => $root));
+    $this->assertFileExists($root . '/sites/all/modules/devel/README.txt');
+
+    // If we are in site specific dir, then download belongs there.
+    // Setup a second site. Skip install for speed.
+    $this->setUpDrupal('stage', FALSE);
+    $path_stage = "$root/sites/stage";
+    mkdir("$path_stage/modules");
+    $this->drush('pm-download', array('devel'), array(), NULL, $path_stage);
+    $this->assertFileExists($path_stage . '/modules/devel/README.txt');
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/pmEnDisUnListTest.php b/sites/all/modules/drush/tests/pmEnDisUnListTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f12395c2bde25b79feb3cc6310c07f6a89eee66
--- /dev/null
+++ b/sites/all/modules/drush/tests/pmEnDisUnListTest.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * @file
+ *   Tests for enable, disable, uninstall, pm-list commands.
+ */
+
+class EnDisUnListCase extends Drush_TestCase {
+
+  public function testEnDisUnList() {
+    $this->setUpDrupal('dev', TRUE);
+    $options = array(
+      'yes' => NULL,
+      'pipe' => NULL,
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+    );
+    $this->drush('pm-download', array('devel-7.x-1.0'), $options);
+    $this->drush('pm-list', array(), $options + array('no-core' => NULL, 'status' => 'not installed'));
+    $list = $this->getOutputAsList();
+    $this->assertTrue(in_array('devel', $list));
+
+    $this->drush('pm-enable', array('menu', 'devel'), $options);
+    $this->drush('pm-list', array(), $options + array('status' => 'enabled'));
+    $list = $this->getOutputAsList();
+    $this->assertTrue(in_array('devel', $list));
+    $this->assertTrue(in_array('bartik', $list), 'Themes are in the pm-list');
+
+    $this->drush('pm-list', array(), $options + array('package' => 'Core'));
+    $list = $this->getOutputAsList();
+    $this->assertFalse(in_array('devel', $list), 'Devel is not part of core package');
+
+    // For testing uninstall later.
+    $this->drush('variable-set', array('devel_query_display', 1), $options);
+
+    $this->drush('pm-disable', array('devel'), $options);
+    $this->drush('pm-list', array(), $options + array('status' => 'disabled'));
+    $list = $this->getOutputAsList();
+    $this->assertTrue(in_array('devel', $list));
+
+    $this->drush('pm-uninstall', array('devel'), $options);
+    $this->drush('pm-list', array(), $options + array('status' => 'not installed', 'type' => 'module'));
+    $list = $this->getOutputAsList();
+    $this->assertTrue(in_array('devel', $list));
+
+
+    // We expect an exit code of 1 so just call execute() directly.
+    $exec = sprintf('%s variable-get %s --pipe --root=%s --uri=%s', UNISH_DRUSH, 'devel_query_display', $options['root'], $options['uri']);
+    $this->execute($exec, self::EXIT_ERROR);
+    $output = $this->getOutput();
+    $this->assertEmpty($output, 'Devel variable was uninstalled.');
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/pmUpdateCodeTest.php b/sites/all/modules/drush/tests/pmUpdateCodeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..36ae085cef893539faab9d82485f049e70fcab04
--- /dev/null
+++ b/sites/all/modules/drush/tests/pmUpdateCodeTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+  * @file
+  *   Prepare a codebase and upgrade it in several stages, exercising
+  *   updatecode's filters.
+  *   @todo test security-only once one of these modules or core gets a security release.
+  */
+
+class pmUpdateCode extends Drush_TestCase {
+
+  /*
+   * Download old core and older contrib releases which will always need updating.
+   */
+  public function setUp() {
+    $this->setUpDrupal('dev', TRUE, '7.0-rc3');
+    $options = array(
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+      'yes' => NULL,
+      'quiet' => NULL,
+    );
+    $this->drush('pm-download', array('devel-7.x-1.0-rc1,webform-7.x-3.4-beta1'), $options);
+    $this->drush('pm-enable', array('menu', 'devel', 'webform'), $options);
+  }
+
+  function testUpdateCode() {
+    $options = array(
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+      'yes' => NULL,
+      'backup-dir' => UNISH_SANDBOX . '/backups',
+      'self-update' => 0, // Don't try update Drush.
+    );
+
+    // Try to upgrade a specific module.
+    $this->drush('pm-updatecode', array('devel'), $options + array());
+    // Assure that devel was upgraded and webform was not.
+    $this->drush('pm-updatecode', array(), $options + array('pipe' => NULL));
+    $all = $this->getOutput();
+    $this->assertNotContains('devel', $all);
+    $this->assertContains('webform', $all);
+
+    // Lock webform, and update core.
+    $this->drush('pm-updatecode', array(), $options + array('lock' => 'webform'));
+    $list = $this->getOutputAsList(); // For debugging.
+    $this->drush('pm-updatecode', array(), $options + array('pipe' => NULL));
+    $all = $this->getOutput();
+    $this->assertNotContains('drupal', $all, 'Core was updated');
+    $this->assertContains('webform', $all, 'Webform was skipped.');
+
+    // Unlock webform, update, and check.
+    $this->drush('pm-updatecode', array(), $options + array('unlock' => 'webform', 'no-backup' => NULL));
+    $list = $this->getOutputAsList();
+    $this->drush('pm-updatecode', array(), $options + array('pipe' => NULL));
+    $all = $this->getOutput();
+    $this->assertNotContains('webform', $all, 'Webform was updated');
+
+    // Verify that we keep backups as instructed.
+    $pattern = 'find %s -iname %s';
+    $backup_dir = UNISH_SANDBOX . '/backups';
+    $cmd = sprintf($pattern, self::escapeshellarg($backup_dir), escapeshellarg('devel.module'));
+    $this->execute($cmd);
+    $output = $this->getOutput();
+    $this->assertNotEmpty($output);
+
+    $cmd = sprintf($pattern, self::escapeshellarg($backup_dir), escapeshellarg('webform.module'));
+    $this->execute($cmd);
+    $output = $this->getOutput();
+    $this->assertEmpty($output);
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/runner.php b/sites/all/modules/drush/tests/runner.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c269fed5eb887ac464133dd9622983174ee345e
--- /dev/null
+++ b/sites/all/modules/drush/tests/runner.php
@@ -0,0 +1,25 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * @file
+ *   A nearly verbatim copy of phpunit script that ships with PEAR's PHPUnit.
+ */
+
+require_once 'PHP/CodeCoverage/Filter.php';
+PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'PHPUNIT');
+
+if (extension_loaded('xdebug')) {
+  // Drush comments out the following line for easier debugging.
+  // xdebug_disable();
+}
+
+if (strpos('/usr/bin/php', '@php_bin') === 0) {
+    set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
+}
+
+require_once 'PHPUnit/Autoload.php';
+
+define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main');
+
+PHPUnit_TextUI_Command::main();
diff --git a/sites/all/modules/drush/tests/siteAliasTest.php b/sites/all/modules/drush/tests/siteAliasTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..edfe78141353fa6fc0d9ad5e5989778aad7f6d68
--- /dev/null
+++ b/sites/all/modules/drush/tests/siteAliasTest.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * @file
+ *   Tests for sitealias.inc
+ */
+class saCase extends Drush_TestCase {
+
+  /*
+   * Assure that site lists work as expected.
+   * @todo Use --backend for structured return data. Depends on http://drupal.org/node/1043922
+   */
+  public function testSAList() {
+    $this->setUpDrupal('dev');
+    $this->setUpDrupal('stage');
+    $eval = 'print "bon";';
+    $options = array(
+      'yes' => NULL,
+      'root' => $this->sites['dev']['root'],
+    );
+    $this->drush('php-eval', array($eval), $options, "#dev,#stage");
+    $expected = "You are about to execute 'php-eval print \"bon\";' on all of the following targets:
+  #dev
+  #stage
+Continue?  (y/n): y
+#dev   >> bon
+#stage >> bon";
+    $this->assertEquals($expected, $this->getOutput());
+  }
+}
diff --git a/sites/all/modules/drush/tests/siteUpgradeTest.php b/sites/all/modules/drush/tests/siteUpgradeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..55094ecbeb049759eb26cf69b935aac91f6ac75d
--- /dev/null
+++ b/sites/all/modules/drush/tests/siteUpgradeTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * @file
+ *   Programmatically upgrade a site from Drupal 6 to Druapl 7.
+ *
+ *   We also implicitly test:
+ *     - pm-download
+ *     - site-install for D6
+ *     - user-create
+ *     - sql-sync
+ *     - updatedb and batch.inc
+ */
+
+class siteUpgradeCase extends Drush_TestCase {
+  function testUpgrade() {
+    $env = 'testupgrade';
+    $this->setUpDrupal($env, TRUE, '6.x');
+    $root = $this->sites[$env]['root'];
+
+    // Create the alias for D7 site.
+    $aliases['target'] = array(
+      'root' => UNISH_SANDBOX . '/target',
+      'uri' => $env,
+      'db-url' => UNISH_DB_URL . '/unish_target',
+    );
+    $contents = $this->file_aliases($aliases);
+    $alias_path = "$root/aliases.drushrc.php";
+    file_put_contents($alias_path, $contents);
+
+    // Create a user in D6.
+    $name = "example";
+    $options = array(
+      'mail' => "example@example.com",
+      'password' => 'password',
+      'root' => $root,
+      'uri' => $env,
+    );
+    $this->drush('user-create', array($name), $options);
+
+    // Perform the upgrade.
+    $options = array(
+      'yes' => NULL,
+      'root' => $root,
+      'uri' => $env,
+    );
+    $this->drush('site-upgrade', array('@target'), $options);
+
+    // Assert that the D7 site bootstraps.
+    // We don't specify @target alias since that file is in the root of the *source* site.
+    $options = array(
+      'pipe' => NULL,
+      'root' => $aliases['target']['root'],
+      'uri' => $aliases['target']['uri'],
+    );
+    $return = $this->drush('core-status', array('drupal_bootstrap'), $options);
+    $this->assertEquals('Successful', $this->getOutput(), 'The target site bootstraps successfully');
+
+    // Assures that a updatedb and batch updates work properly. See user_update_7001().
+    $options = array(
+      'root' => $aliases['target']['root'],
+      'uri' => $aliases['target']['uri'],
+    );
+    $eval = "require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');";
+    $eval .= "\$account = user_load_by_name('example');";
+    $eval .= "print (string) user_check_password('password', \$account)";
+    $this->drush('php-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $this->assertSame('1', $output, 'User was updated to new password format.');
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/sqlSyncTest.php b/sites/all/modules/drush/tests/sqlSyncTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..352b2682248db46c47533964ba222f4d9ea137f1
--- /dev/null
+++ b/sites/all/modules/drush/tests/sqlSyncTest.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+* @file
+*  For now we only test sql-sync in simulated mode.
+*
+*  Future: Using two copies of Drupal, we could test 
+*  overwriting one site with another.
+*/
+
+class sqlSyncTest extends Drush_TestCase {
+
+  /*
+   * Covers the following responsibilities.
+   *   - A user created on the source site is copied to the destination site.
+   *   - The email address of the copied user is sanitized on the destination site.
+   *
+   * General handling of site aliases will be in sitealiasTest.php.
+   */
+  public function testLocalSqlSync() {
+    $this->setUpDrupal('dev', TRUE);
+    $this->setUpDrupal('stage', TRUE);
+    $dump_dir = UNISH_SANDBOX . "/dump-dir";
+    mkdir($dump_dir);
+
+    // Create a user in the staging site
+    $name = 'joe.user';
+    $mail = "joe.user@myhome.com";
+    $options = array(
+      'root' => $this->sites['stage']['root'],
+      'uri' => 'stage',
+      'yes' => NULL,
+    );
+    $this->drush('user-create', array($name), $options + array('password' => 'password', 'mail' => $mail));
+
+    // Copy stage to dev with --sanitize
+    $sync_options = array(
+      'sanitize' => NULL,
+      'yes' => NULL,
+      'dump-dir' => $dump_dir
+    );
+    $this->drush('sql-sync', array('@stage', '@dev'), $sync_options);
+    
+    // Confirm that the sample user has the correct email address on the staging site
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $uid = $row[1];
+    $this->assertEquals($mail, $row[2], 'email address is unchanged on source site.');
+    $this->assertEquals($name, $row[0]);
+    
+    $options = array(
+      'root' => $this->sites['dev']['root'],
+      'uri' => 'dev',
+      'yes' => NULL,
+    );
+    // Confirm that the sample user's email address has been sanitized on the dev site
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $uid = $row[1];
+    $this->assertEquals("user+2@localhost", $row[2], 'email address was sanitized on destination site.');
+    $this->assertEquals($name, $row[0]);    
+  }
+}
diff --git a/sites/all/modules/drush/tests/unit.drush.inc b/sites/all/modules/drush/tests/unit.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2f0fac0bcca3d80a74e36d1b5c41b43cd67bbf0e
--- /dev/null
+++ b/sites/all/modules/drush/tests/unit.drush.inc
@@ -0,0 +1,76 @@
+<?php
+// $Id$
+
+/*
+ * @file
+ *   Commands which are useful for unit tests.
+ */
+
+/**
+ * Implementation of hook_drush_command().
+ */
+function unit_drush_command() {
+  $items['unit-eval'] = array(
+    'description' => 'Works like php-eval. Used for testing $command_specific context.',
+    'bootstrap' => DRUSH_BOOTSTRAP_MAX,
+    'callback' => 'drush_core_php_eval', // Note - no invoke hooks.
+  );
+  $items['unit-invoke'] = array(
+    'description' => 'Return an array indicating which invoke hooks got called.',
+    'bootstrap' => DRUSH_BOOTSTRAP_NONE,
+  );
+  return $items;
+}
+
+/*
+ * Dynamically append custom bash code to the generated .bashrc.
+ *
+ * @see coreCase::testCoreCLI().
+ */
+function unit_cli_bashrc($drush_command, $interactive_mode) {
+  return drush_get_option('unit-extra');
+}
+
+// Implement each invoke hook with the same single line of code.
+// That line records that the hook was called.
+function drush_unit_invoke_init() {unit_invoke_log(__FUNCTION__);}
+function drush_unit_invoke_validate() {unit_invoke_log(__FUNCTION__);}
+function drush_unit_pre_unit_invoke() {unit_invoke_log(__FUNCTION__);}
+function drush_unit_invoke() {unit_invoke_log(__FUNCTION__);}
+function drush_unit_pre_unit_invoke_rollback() {unit_invoke_log(__FUNCTION__);}
+function drush_unit_post_unit_invoke_rollback() {unit_invoke_log(__FUNCTION__);}
+
+// Record that hook_drush_init() fired.
+function unit_drush_init() {
+  $command = drush_get_command();
+  if ($command['command'] == 'unit-invoke') {
+    unit_invoke_log(__FUNCTION__);
+  }
+}
+
+function drush_unit_post_unit_invoke() {
+  // Record that this hook was called.
+  unit_invoke_log(__FUNCTION__);
+
+  // Make sure we enter into rollback.
+  drush_set_error('');
+}
+
+/*
+ * The final invoke hook. Emit the call history.
+ * Cannot use 'exit' as it does not fire in rollback scenario.
+ */
+function drush_unit_invoke_validate_rollback() {
+  unit_invoke_log(__FUNCTION__);
+  print json_encode(unit_invoke_log());
+}
+
+function unit_invoke_log($function = NULL) {
+  static $called = array();
+  if ($function) {
+    $called[] = $function;
+  }
+  else {
+    return $called;
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/userTest.php b/sites/all/modules/drush/tests/userTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a3defbe9681942f926fe7b36f79bc7f7b080cfdf
--- /dev/null
+++ b/sites/all/modules/drush/tests/userTest.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * @file
+ *   Tests for user.drush.inc
+ */
+class userCase extends Drush_TestCase {
+
+  /*
+   * Create, edit, block, and cancel users.
+   */
+  public function testUser() {
+    // user-create
+    $env = 'dev';
+    $this->setUpDrupal($env, TRUE);
+    $root = $this->sites[$env]['root'];
+    $name = "example";
+    $options = array(
+      'root' => $root,
+      'uri' => $env,
+      'yes' => NULL,
+    );
+    $this->drush('user-create', array($name), $options + array('password' => 'password', 'mail' => "example@example.com"));
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $uid = $row[1];
+    $this->assertEquals('example@example.com', $row[2]);
+    $this->assertEquals($name, $row[0]);
+    $this->assertEquals(1, $row[3], 'Newly created user is Active.');
+    $this->assertEquals('authenticated user', $row[4], 'Newly created user has one role.');
+
+    // user-block
+    $this->drush('user-block', array($name), $options);
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $this->assertEquals(0, $row[3], 'User is blocked.');
+
+    // user-unblock
+    $this->drush('user-unblock', array($name), $options);
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $this->assertEquals(1, $row[3], 'User is unblocked.');
+
+    // user-add-role
+    // first, create the fole since we use testing install profile.
+    $eval = "user_role_save((object)array('name' => 'administrator'))";
+    $this->drush('php-eval', array($eval), $options);
+    $this->drush('user-add-role', array('administrator', $name), $options);
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $this->assertEquals('authenticated user, administrator', $row[4], 'User has administrator role.');
+
+    // user-remove-role
+    $this->drush('user-remove-role', array('administrator', $name), $options);
+    $this->drush('user-information', array($name), $options + array('pipe' => NULL));
+    $output = $this->getOutput();
+    $row  = str_getcsv($output);
+    $this->assertEquals('authenticated user', $row[4], 'User removed administrator role.');
+
+    // user-password
+    $newpass = 'newpass';
+    $this->drush('user-password', array($name), $options + array('password' => $newpass));
+    $eval = "require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');";
+    $eval .= "\$account = user_load_by_name('example');";
+    $eval .= "print (string) user_check_password('$newpass', \$account)";
+    $this->drush('php-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $this->assertEquals('1', $output, 'User can login with new password.');
+
+    // user-login
+    $this->drush('user-login', array($name), $options);
+    $output = $this->getOutput();
+    $url = parse_url($output);
+    $this->assertStringStartsWith('/user/reset/' . $uid, $url['path'], 'Login returned a valid reset URL');
+
+    // user-cancel
+    // create content
+    $eval = $this->create_node_types_php();
+    $this->drush('php-eval', array($eval), $options);
+    $eval = "
+      \$node = (object) array(
+        'title' => 'foo',
+        'uid' => 2,
+        'type' => 'page',
+      );
+      node_save(\$node);
+    ";
+    $this->drush('php-eval', array($eval), $options);
+    $this->drush('user-cancel', array($name), $options + array('delete-content' => NULL));
+    $eval = 'print (string) user_load(2)';
+    $this->drush('php-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $this->assertEmpty($output, 'User was deleted');
+    $eval = 'print (string) node_load(2)';
+    $this->drush('php-eval', array($eval), $options);
+    $output = $this->getOutput();
+    $this->assertEmpty($output, 'Content was deleted');
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/drush/tests/variableTest.php b/sites/all/modules/drush/tests/variableTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd9a51501ed2c0002db0a5ea49f2d5ccecf08306
--- /dev/null
+++ b/sites/all/modules/drush/tests/variableTest.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * @file
+ *   Tests for enable, disable, uninstall, pm-list commands.
+ */
+class VariableCase extends Drush_TestCase {
+
+  function testVariable() {
+    $env = 'dev';
+    $this->setUpDrupal($env, TRUE);
+    $options = array(
+      'yes' => NULL,
+      'pipe' => NULL,
+      'root' => $this->sites[$env]['root'],
+      'uri' => $env,
+    );
+
+    $this->drush('variable-set', array('date_default_timezone', 'US/Mountain'), $options);
+    $this->drush('variable-get', array('date_default_timezone'), $options); // Wildcard get.
+    $var_export = $this->getOutput();
+    eval($var_export);
+    $this->assertEquals('US/Mountain', $variables['date_default_timezone'], 'Variable was successfully set and get.');
+    
+    $this->drush('variable-set', array('site_name', 'unish'), $options + array('always-set' => NULL));
+    $this->drush('variable-get', array('site_name'), $options);
+    $var_export = $this->getOutput();
+    eval($var_export);
+    $this->assertEquals('unish', $variables['site_name'], '--always-set option works as expected.');
+
+    $this->drush('variable-delete', array('site_name'), $options);
+    $output = $this->getOutput();
+    $this->assertEmpty($output, 'Variable was successfully deleted.');
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/unl/cron.php b/sites/all/modules/unl/cron.php
index dcad3ae526633963b4e59111cb8a32cf95e000a8..2e8965ece68c09f55f94bbd0cbd6c8f8e5b59b98 100644
--- a/sites/all/modules/unl/cron.php
+++ b/sites/all/modules/unl/cron.php
@@ -211,7 +211,7 @@ function unl_add_site($site_path, $uri, $clean_url, $db_prefix, $site_id) {
   $db_prefix = escapeshellarg($db_prefix);
   $site_mail    = escapeshellarg(variable_get('site_mail'));
 
-  $command = "$php_path sites/all/modules/drush/drush.php -y --uri=$uri site-install unl_profile --sites-subdir=$sites_subdir --db-url=$db_url --db-prefix=$db_prefix --clean-url=$clean_url";
+  $command = "$php_path sites/all/modules/drush/drush.php -y --uri=$uri site-install unl_profile --sites-subdir=$sites_subdir --db-url=$db_url --db-prefix=$db_prefix --clean-url=$clean_url 2>&1";
   if ($site_mail) {
     $command .= " --site-mail=$site_mail";
   }
diff --git a/sites/all/modules/unl/unl_site_creation.php b/sites/all/modules/unl/unl_site_creation.php
index 7c3fd4bd809e613e74e98134146e5dc7464b706d..1a1e3f06d396d08236d872c97c2be63db50cce1c 100644
--- a/sites/all/modules/unl/unl_site_creation.php
+++ b/sites/all/modules/unl/unl_site_creation.php
@@ -215,8 +215,13 @@ function unl_site_updates_submit($form, &$form_state) {
 function unl_site_updates_step($site_uri, &$context) {
   $uri = escapeshellarg($site_uri);
   $root = escapeshellarg(DRUPAL_ROOT);
-  $command = "sites/all/modules/drush/drush.php -y --token=secret --root={$root} --uri={$uri} updatedb";
-  drupal_set_message('Messages from ' . $site_uri . ':<br />' . PHP_EOL . '<pre>' . shell_exec($command) . '</pre>', 'status');
+  $output = '';
+  $command = "sites/all/modules/drush/drush.php -y --token=secret --root={$root} --uri={$uri} updatedb 2>&1";
+  $output .= shell_exec($command);
+  $command = "sites/all/modules/drush/drush.php -y --root={$root} --uri={$uri} cc all 2>&1";
+  $output .= shell_exec($command);
+  
+  drupal_set_message('Messages from ' . $site_uri . ':<br />' . PHP_EOL . '<pre>' . $output . '</pre>', 'status');
 }
 
 function unl_site_email_settings($form, &$form_state) {