? pm-info.patch
? includes/table.inc
Index: commands/core/drupal/environment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/drupal/environment.inc,v
retrieving revision 1.3
diff -u -r1.3 environment.inc
--- commands/core/drupal/environment.inc	11 Nov 2009 19:02:54 -0000	1.3
+++ commands/core/drupal/environment.inc	17 Jan 2010 20:46:40 -0000
@@ -26,5 +26,5 @@
  *   An array containing theme info for all installed themes.
  */
 function _drush_get_themes() {
-  return _system_theme_data();
-}
\ No newline at end of file
+  return list_themes();
+}
Index: commands/core/drupal/environment_7.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/drupal/environment_7.inc,v
retrieving revision 1.3
diff -u -r1.3 environment_7.inc
--- commands/core/drupal/environment_7.inc	31 Dec 2009 21:54:21 -0000	1.3
+++ commands/core/drupal/environment_7.inc	17 Jan 2010 20:46:40 -0000
@@ -37,5 +37,5 @@
  *   An array containing theme info for all installed themes.
  */
 function _drush_get_themes() {
-  return _system_get_theme_data();
+  return list_themes();
 }
Index: commands/pm/pm.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/pm.drush.inc,v
retrieving revision 1.73
diff -u -r1.73 pm.drush.inc
--- commands/pm/pm.drush.inc	11 Jan 2010 05:22:02 -0000	1.73
+++ commands/pm/pm.drush.inc	17 Jan 2010 20:46:41 -0000
@@ -42,6 +42,8 @@
       return dt('Enable one or more modules. Enables dependant modules as well.');
     case 'drush:pm-disable':
       return dt('Disable one or more modules. Disables dependant modules as well.');
+    case 'drush:pm-info':
+      return dt('Show detailed info for one or more projects.');
     case 'drush:pm-uninstall':
       return dt('Uninstall one or more modules. Modules must be disabled first.');
     case 'drush:pm-list':
@@ -90,6 +92,12 @@
     'aliases' => array('dis'),
     'deprecated-aliases' => array('disable'),
   );
+  $items['pm-info'] = array(
+    'description' => 'Show info for one or more projects.',
+    'arguments' => array(
+      'projects' => 'A space delimited list of projects.',
+    ),
+  );  
   // Install command is reserved for the download and enable of projects including dependencies.
   // @see http://drupal.org/node/112692 for more information.
   // $items['install'] = array(
@@ -196,6 +204,134 @@
 }
 
 /**
+ * Command callback. Show detailed info for one or more projects.
+ */
+function drush_pm_info() {
+  $project_names = func_get_args();
+  $modules  = drush_get_modules();
+  $themes   = drush_get_themes();
+  $projects = array_merge($modules, $themes);
+  
+  foreach ($project_names as $project_name) {
+    if (isset($projects[$project_name])) {
+      $info = $projects[$project_name];
+    }
+    else {
+      drush_log(dt("Project !project is not a module or theme in your system.", array('!project' => $project_name)), 'error');
+      continue;
+    }
+    if ($info->type == 'module') {
+      $output = _drush_pm_info_module($info);
+    }
+    else {
+      $output = _drush_pm_info_theme($info);
+    }
+    
+    print $output."\n";
+  }
+}
+
+/**
+ * Return a string with general info of a project (module or theme).
+ */
+function _drush_pm_info_project($info) {
+  $major_version = drush_drupal_major_version();
+
+  $output  = "";
+  $output .= drush_sprint('Project', $info->name);
+  $output .= drush_sprint('Type', $info->type);
+  if (($info->type == 'module')||($major_version >= 6)) {
+    $output .= drush_sprint('Title', $info->info['name']);
+    $output .= drush_sprint('Description', $info->info['description']);
+    $output .= drush_sprint('Version', $info->info['version']);
+  }
+  $output .= ($major_version >= 6)?drush_sprint('Core', $info->info['core']):'';
+  $output .= ($major_version == 6)?drush_sprint('PHP', $info->info['php']):'';
+  $status = ($info->status == 1)?'enabled':'disabled';
+  $output .= drush_sprint('Status', $status);
+  $path = (($info->type == 'module')&&($major_version == 7))?$info->uri:$info->filename;
+  $path = substr($path, 0, strrpos($path, '/'));
+  $output .= drush_sprint('Path', $path);
+
+  return $output;
+}
+
+/**
+ * Return a string with info of a module.
+ */
+function _drush_pm_info_module($info) {
+  $major_version = drush_drupal_major_version();
+
+  $output = _drush_pm_info_project($info);
+  $package = (isset($info->info['package']))?$info->info['package']:"none";
+  $output .= drush_sprint('Package', $package);
+  if ($info->schema_version > 0) {
+    $schema_version = $info->schema_version;
+  }
+  elseif ($info->schema_version == -1) {
+    $schema_version = "no schema installed";
+  }
+  else {
+      $schema_version = "module has no schema";
+  }
+  $output .= drush_sprint('Schema version', $schema_version);
+  $output .= ($major_version == 7)?drush_sprint('Files', implode(', ', $info->info['files'])):'';
+  if (count($info->info['dependencies']) > 0) {
+    $requires = implode(', ', $info->info['dependencies']);
+  }
+  else {
+    $requires = "none";
+  }
+  $output .= drush_sprint('Requires', $requires);
+  
+  if ($major_version == 6) {
+    if (count($info->info['dependents']) > 0) {
+      $requiredby = implode(', ', $info->info['dependents']);
+    }
+    else {
+      $requiredby = "none";
+    }
+    $output .= drush_sprint('Required by', $requiredby);
+  }
+
+  return $output;
+}
+
+/**
+ * Return a string with info of a module.
+ */
+function _drush_pm_info_theme($info) {
+  $major_version = drush_drupal_major_version();
+
+  $output = _drush_pm_info_project($info);
+  if ($major_version == 5) {
+    $output .= drush_sprint('Engine', $info->description);
+  }
+  else {
+    $output .= drush_sprint('Core', $info->info['core']);
+    $output .= drush_sprint('PHP', $info->info['php']);
+    $output .= drush_sprint('Engine', $info->info['engine']);
+    $regions = implode(', ', $info->info['regions']);
+    $output .= drush_sprint('Regions', $regions);
+    $features = implode(', ', $info->info['features']);
+    $output .= drush_sprint('Features', $features);
+    if (count($info->info['stylesheets']) > 0) {
+      $output .= sprintf("  %-18s:\n", 'Stylesheets');
+      foreach ($info->info['stylesheets'] as $media => $files) {
+        $files = implode(', ', array_keys($files));
+        $output .= drush_sprint('media '.$media, $files, 6, 14);
+      }
+    }
+    if (count($info->info['scripts']) > 0) {
+      $scripts = implode(', ', array_keys($info->info['scripts']));
+      $output .= drush_sprint('Scripts', $scripts);
+    }
+  }
+
+  return $output;
+}
+
+/**
  * Command callback. Uninstall one or more modules.
  * // TODO: Use drupal_execute on system_modules_uninstall_confirm_form so that input is validated.
  */
Index: includes/drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/drush.inc,v
retrieving revision 1.76
diff -u -r1.76 drush.inc
--- includes/drush.inc	11 Jan 2010 01:22:46 -0000	1.76
+++ includes/drush.inc	17 Jan 2010 20:46:41 -0000
@@ -533,6 +533,86 @@
 }
 
 /**
+ * Compounds a string of the form "key:value".
+ *
+ * It supports indentation and alignment of the 
+ *
+ * @param $key
+ *   The left part of the resulting string
+ * @param $value
+ *   The right part of the resulting string
+ * @param $separator
+ *   The separator in the resulting string
+ * @param $indent
+ *   The indentation of the resulting string (space chars)
+ * @param $width
+ *   $key will grow with spaces to fit $width.
+ * @return
+ *   A string of the form "key:value", indented and wordwrapped.
+ */
+function drush_sprint($key, $value, $indent = 2, $width = 18, $separator = ": ") {
+  $columns = drush_get_context('DRUSH_COLUMNS');
+  $len_left = $indent+$width+strlen($separator);
+  $len_right = $columns - $len_left;
+  $len_value  = strlen($value);
+
+  // left side
+  $output = str_repeat(' ', $indent).sprintf("%-".$width."s".$separator, $key);
+
+  // right side
+  if ($len_value < $len_right) {
+    $output .= $value."\n";
+  }
+  else { //needs wordwrap
+    $margin_left = str_repeat(' ', $len_left);
+    $offset = 0;
+    while ($offset < $len_value) {
+      // ltrim
+      while (strpos($value, ' ', $offset) === $offset) {
+        $offset++;
+      }
+      // last chunk ?
+      if (($len_value - $offset) < $len_right) {
+        $output .= substr($value, $offset)."\n";
+        $offset = $len_value;
+      }
+      else {
+        // wrap to rightmost space within the max lenght, if possible
+        $pos = strrpos($value, ' ', $offset + $len_right - $len_value - 1);
+        if (($pos === FALSE)||($pos < $offset)) {
+          $pos = $offset + $len_right;
+        }
+        $output .= substr($value, $offset, $pos - $offset)."\n";
+        $offset += $pos - $offset;
+        $output .= $margin_left;
+      }
+    }
+
+/*
+    while ($offset < $length) {
+      // find where to cut
+      $pos = 0;
+      do {
+        $cut = $pos;
+        print "cut: $cut\n";
+        $pos = strpos($value, ' ', $offset+$cut);
+        print "pos: $pos\n";
+        // if there's no ' ' then cut to max length
+        if ($pos === FALSE) {
+          $cut = $pos = $len_right;
+        }
+      } while ($pos <= $len_right);
+      $line = substr($value, $offset, $cut);
+      $offset += $cut;
+      $output .= $line."\n";
+    }
+*/
+  }
+
+  return $output;
+}
+
+/**
  * Ask the user a basic yes/no question.
  *
  * @param $msg The question to ask
