? includes/table.inc
Index: commands/core/core.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/core.drush.inc,v
retrieving revision 1.92
diff -u -p -r1.92 core.drush.inc
--- commands/core/core.drush.inc	13 Apr 2010 20:02:04 -0000	1.92
+++ commands/core/core.drush.inc	14 Apr 2010 02:57:13 -0000
@@ -165,7 +165,7 @@ function core_drush_command() {
       'cd `drush cd devel`' => 'Navigate into the devel module directory',
       'cd `drush cd` ' => 'Navigate to the root of your Drupal site',
       'cd `drush cd files`' => 'Navigate to the files directory.',
-      'edit `drush cd devel`' => "Open devel directory in your editor (customize 'edit' for your editor)",
+      'edit `drush cd devel`/devel.module' => "Open devel module in your editor (customize 'edit' for your editor)",
       'cdd devel' => 'Navigate to devel directory. See required function above,',
     ),
     'aliases' => array('cd'),
@@ -371,16 +371,21 @@ function _core_site_credential_list($sta
   return $credentials;
 }
 
-function _core_site_status_table() {
+function _core_site_status_table($project = '') {
   $phase = drush_get_context('DRUSH_BOOTSTRAP_PHASE');
   if ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT')) {
-    $status_table['Drupal Root'] = $drupal_root;
+    $paths['%root'] = $drupal_root;
+    $status_table['Drupal Root'] = $paths['%root'];
     $status_table['Drupal Version'] = drush_drupal_version();
     if ($site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT')) {
-      $status_table['Site Path'] = $site_root;
+      $paths['%site'] = $site_root;
+      $paths['%modules'] = $site_root . '/sites/all/modules';
+      $paths['%themes'] = $site_root . '/sites/all/themes';
+      $status_table['Site Path'] = $paths['%site'];
       $status_table['Site URI'] = drush_get_context('DRUSH_URI');
       if (function_exists('file_directory_path')) {
-        $status_table['File Directory Path'] = file_directory_path();
+        $paths['%files'] = file_directory_path();
+        $status_table['File Directory Path'] = $paths['%files'];
       }
       if ($creds = drush_get_context('DRUSH_DB_CREDENTIALS')) {
         $status_table['Database Driver'] = $creds['driver'];
@@ -402,6 +407,17 @@ function _core_site_status_table() {
           }
         }
       }
+      // If the 'project' parameter was specified, then search
+      // for a project (or a few) and add its path to the path list
+      if (!empty($project)) {
+        foreach(explode(',', $project) as $target) {
+          $path = drush_core_find_project_path($target);
+          if(isset($path)) {
+            $paths['%' . $target] = $path;
+            $status_table['Project ' . $target] = $path;
+          }
+        }
+      }
     }
     $status_table['Default theme'] = drush_theme_get_default();
     $status_table['Administration theme'] = drush_theme_get_admin();
@@ -413,6 +429,12 @@ function _core_site_status_table() {
   }
   $status_table['Drush Version'] = DRUSH_VERSION;
   $status_table['Drush configuration'] = implode(' ', drush_get_context_options('context-path', TRUE));
+  
+  // Store the paths into the '%paths' index; this will be
+  // used by other code, but will not be included in the output
+  // of the drush status command.
+  $status_table['%paths'] = $paths;
+  
   return $status_table;
 }
 
@@ -442,7 +464,7 @@ function drush_core_cron() {
  */
 function drush_core_status() {
   drush_bootstrap_max();
-  $status_table = _core_site_status_table();
+  $status_table = _core_site_status_table(drush_get_option('project',''));
   // If args are specified, filter out any entry that is not named
   // (in other words, only show lines named by one of the arg values)
   $args = func_get_args();
@@ -454,6 +476,7 @@ function drush_core_status() {
     }
   }
   drush_backend_set_result($status_table);
+  unset($status_table['%paths']);
   // Print either an ini-format list or a formatted ASCII table
   if (drush_get_option('pipe')) {
     if (count($status_table) == 1) {
@@ -562,30 +585,41 @@ function drush_core_updatedb_batch_proce
   _update_batch_command($id);
 }
 
-function drush_core_directory($target = 'root') {
+function _drush_core_directory($target = 'root') {
   // Normalize to a sitealias in the target.
-  if (substr($target, 0, 1) != '/' && substr($target, 0, 1) != '@') {
+  $normalized_target = $target;
+  if (strpos($target, ':') === FALSE) {
     // @self makes no sense before 'site' level.
-    if (drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) {
-      $additional_options = array();
-      $path = drush_sitealias_evaluate_path('@self:%' . $target, $additional_options);
-    }
-    else {
-      return drush_set_error(dt('!target not found.', array('!target' => $target)));
+    if(!drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) {
+      return FALSE;
     }
+    $normalized_target = '@self:%' . $target;
   }
 
-  if (isset($path['path-aliases']['%' . $target])) {
-    // Hurray, we found the destination quickly.
-    drush_print($path['rsync-path']);
-    return;
+  $additional_options = array();
+  $values = drush_sitealias_evaluate_path($normalized_target, $additional_options);
+
+  if (isset($values['path'])) {
+    // Hurray, we found the destination
+    return $values['path'];
   }
+  return NULL;
+}
+
+function drush_core_directory($target = 'root') {
+  $path = _drush_core_directory($target);
 
-  // We need to know which site is active in order to add its masks.
-  if (!drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE)) {
-    return drush_set_error(dt('!target not found.', array('!target' => $target)));
+  if (isset($path)) {
+    drush_print($path);
   }
+  else {
+    return drush_set_error(dt('Core directory path !target not found.', array('!target' => $target)));
+  }
+   
+  return TRUE;
+}
 
+function drush_core_find_project_path($target) {
   $theme_suffix = drush_drupal_major_version() >= 6 ? '.info' : '/style.css';
   $masks = array(
     conf_path() . '/modules' => "/$target.module/",
@@ -600,8 +634,9 @@ function drush_core_directory($target = 
     if ($files = drush_scan_directory("$key", $mask, array('..', '.', 'CVS', '.svn', '.bzr'), 0, TRUE, 'name')) {
       // Just use the first match.
       $file = reset($files);
-      drush_print(drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename));
-      return;
+      return drush_get_context('DRUSH_DRUPAL_ROOT') . '/' . dirname($file->filename);
     }
   }
+  
+  return NULL;
 }
Index: commands/core/rsync.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/rsync.inc,v
retrieving revision 1.15
diff -u -p -r1.15 rsync.inc
--- commands/core/rsync.inc	13 Apr 2010 05:11:39 -0000	1.15
+++ commands/core/rsync.inc	14 Apr 2010 02:57:14 -0000
@@ -21,13 +21,21 @@ function drush_core_rsync($source, $dest
   // After preflight, evaluate file paths
   $source_settings = drush_sitealias_evaluate_path($source, $additional_options);
   $destination_settings = drush_sitealias_evaluate_path($destination, $additional_options);
-  $source_path = $source_settings['rsync-path'];
-  $destination_path = $destination_settings['rsync-path'];
+  $source_path = $source_settings['evaluated-path'];
+  $destination_path = $destination_settings['evaluated-path'];
 
   // Check to see if this is an rsync multiple command (multiple sources and multiple destinations)
   $is_multiple = drush_do_multiple_command('rsync', $source_settings, $destination_settings, TRUE);
 
   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
+    // rsync paths work, and put on the trailing '/' if you want it.
+    if ($source_settings['user-path'] == $destination_settings['user-path']) {
+      $source_path .= '/';
+    }
+    
     // Prompt for confirmation. This is destructive.
     if (!drush_get_context('DRUSH_SIMULATE')) {
       drush_print(dt("You will destroy data from !target and replace with data from !source", array('!source' => $source_path, '!target' => $destination_path)));
Index: includes/sitealias.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/sitealias.inc,v
retrieving revision 1.39
diff -u -p -r1.39 sitealias.inc
--- includes/sitealias.inc	13 Apr 2010 05:11:39 -0000	1.39
+++ includes/sitealias.inc	14 Apr 2010 02:57:17 -0000
@@ -568,6 +568,24 @@ function drush_sitealias_add_db_settings
 }
 
 /**
+ * Check to see if we have already bootstrapped to a site.
+ */
+function drush_sitealias_is_bootstrapped_site($alias_record) {
+  if (!isset($alias_record['remote-host'])) {
+    $self_record = drush_sitealias_get_record("@self");
+    if (empty($self_record)) {
+      // TODO:  If we have not bootstrapped to a site yet, we could
+      // perhaps bootstrap to $alias_record here.
+      return FALSE;
+    }
+    elseif(($alias_record['root'] == $self_record['root']) && ($alias_record['uri'] == $self_record['uri'])) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
  * Walk through the path aliases and find any paths that begin with a '@'.
  * If found, query the 'status' function for the local or remote
  * site and use the result returned to populate the value of the
@@ -587,6 +605,20 @@ function drush_sitealias_add_db_settings
  */
 function drush_sitealias_resolve_path_references(&$alias_record, $test_string = '') {
   $resolution_needed = FALSE;
+  
+//  drush_print('test string is ' . $test_string);
+  // Convert the test string into an array of items, and
+  // from this make a comma-separated list of projects
+  // that we can pass to 'drush status'.
+  $test_array = explode('/', $test_string);
+  $project_array = array();
+  foreach($test_array as $one_item) {
+    if (substr($one_item,0,1) == '%') {
+      $project_array[] = substr($one_item,1);
+    }    
+  }
+//  drush_print_r($project_array);
+  
   // Check to see if we have any path values that begin with '@'
   // that also exist in the test string
   if (array_key_exists('path-aliases', $alias_record)) {
@@ -596,19 +628,45 @@ function drush_sitealias_resolve_path_re
           $resolution_needed = TRUE;
         }
       }
+      // 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.
+      if (substr($key,0,1) == '%') {
+        unset($project_array['%' . substr($key,1)]);
+      }
     }
   }
-
-  if ($resolution_needed) {
-    $values = drush_do_site_command($alias_record, "status");
-    $status_values = $values['object'];
-    if (isset($status_values)) {
-      foreach ($alias_record['path-aliases'] as $key => $value) {
-        if (substr($value,0,1) == '@') {
-          $status_key = strtr(substr($value,1), '-_', '  ');
+  $project_list = implode(',', $project_array);
+  
+  if ($resolution_needed || !empty($project_array)) {
+    // Optimization:  if we're already bootstrapped to the
+    // site specified by $alias_record, then we can just
+    // call _core_site_status_table() rather than use backend invoke.
+    if (drush_sitealias_is_bootstrapped_site($alias_record)) {
+      // DRUSH_BOOTSTRAP_DRUPAL_DATABASE isn't far enough; we need
+      // to bootstrap all the way to FULL to get %files.
+      drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
+      $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));
+      $status_values = $values['object'];
+    }
+    if (isset($status_values['%paths'])) {
+      foreach ($status_values['%paths'] as $key => $path) {
+        $alias_record['path-aliases'][$key] = $path;
+      }
+    }
+    // TODO:  Remove this old code, which is only useful when talking to old (remote) versions of drush-3.0-rc3 and earlier
+    if (isset($status_values['paths'])) {
+      foreach ($alias_record['path-aliases'] as $key => $path_alias_key) {
+        if (substr($path_alias_key,0,1) == '@') {
+          $status_key = strtr(substr($path_alias_key,1), '-_', '  ');
           if (array_key_exists($status_key, $status_values)) {
             $alias_record['path-aliases'][$key] = $status_values[$status_key];
-            drush_log(dt('Resolved path !key to !value', array('!key' => $status_key, '!value' => $status_values[$status_key])));
+          }
+          elseif (array_key_exists('%paths',$status_values) && array_key_exists($path_alias_key, $status_values['%paths'])) {
+            $alias_record['path-aliases'][$key] = $status_values['%paths'][$path_alias_key];
           }
           else {
             unset($alias_record['path-aliases'][$key]);
@@ -1252,7 +1310,7 @@ function drush_sitealias_set_alias_conte
  * @return
  *   The site record for the machine specified in the path, if any,
  *   with the path to pass to rsync (including the machine specifier)
- *   in the 'rsync-path' item.
+ *   in the 'evaluated-path' item.
  */
 function drush_sitealias_evaluate_path($path, &$additional_options) {
   $site_alias_settings = array();
@@ -1278,7 +1336,9 @@ function drush_sitealias_evaluate_path($
       $path = '';
     }
   }
-
+  // Record the path minus the machine / alias part in $user_path
+  $user_path = $path;
+  
   if (!empty($site_alias_settings)) {
     // Apply any options from this alias that might affect our rsync
     drush_sitealias_set_alias_context($site_alias_settings);
@@ -1369,14 +1429,9 @@ function drush_sitealias_evaluate_path($
     if (($value[0] != '/') && ($key != '%root')) {
       $full_path_aliases[$key] = $drupal_root . $value;
     }
-    // Rsync is very particular about the meaning of paths that
-    // end with a '/' compared to those that do not.  In order to
-    // copy from !path to !path without creating an extra spurrious
-    // directory, the path alias must end with a '/'.  Therefore
-    // we will add a slash to the end of any alias that does not
-    // already have one.
-    if ($value[strlen($value)-1] != '/') {
-      $full_path_aliases[$key] = $full_path_aliases[$key] . '/';
+    // We do not want slashes on the end of our path aliases.
+    if ($value[strlen($value)-1] == '/') {
+      $full_path_aliases[$key] = substr($full_path_aliases[$key], -1);
     }
   }
 
@@ -1402,13 +1457,27 @@ function drush_sitealias_evaluate_path($
 
   // If there is a $machine component, to the path, then
   // add it to the beginning
+  $evaluated_path = $path;
   if (!empty($machine)) {
-    $path = $machine . ':' . $path;
+    $evaluated_path = $machine . ':' . $path;
   }
 
-  // TODO: Rename this key.
-  $site_alias_settings['rsync-path'] = $path;
+  //
+  // Add our result paths:
+  //
+  //	evaluated-path:		machine:/path
+  //	server-component:	machine
+  //	path-component:		:/path
+  //	path:			/path
+  //	user-path:		path (as specified in input parameter)
+  //
+  $site_alias_settings['evaluated-path'] = $evaluated_path;
+  if (!empty($machine)) {
+    $site_alias_settings['server-component'] = $machine;
+  }
   $site_alias_settings['path-component'] = $path_component;
+  $site_alias_settings['path'] = $path;
+  $site_alias_settings['user-path'] = $user_path;
 
   return $site_alias_settings;
 }
