? 797190.patch
? drush-797190.patch
? includes/table.inc
Index: commands/pm/pm.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/pm.drush.inc,v
retrieving revision 1.200
diff -u -r1.200 pm.drush.inc
--- commands/pm/pm.drush.inc	5 Jan 2011 06:41:42 -0000	1.200
+++ commands/pm/pm.drush.inc	5 Jan 2011 10:56:31 -0000
@@ -1772,6 +1772,24 @@
         ),
       ),
     ),
+    'git' => array(
+      'signature' => 'cd %s; git rev-parse',
+      'options' => array(
+        'version-control=git' => 'Quickly add/remove/commit your project changes to Git.',
+      ),
+      'sub-options' => array(
+        'version-control=git' => array(
+          'gitsync' => 'Automatically add new files to the Git repository and remove deleted files. Caution.',
+          'gitcommit' => 'Automatically commit changes to Git repository. You must also usw the --gitsync option.',
+        ),
+        'gitcommit' => array(
+          'gitmessage' => 'Override default commit message which is: Drush automatic commit. Project <name> <type> Command: <the drush command line used>',
+        ),
+      ),
+      'examples' => array(
+        'drush dl cck --version-control=git --gitsync --gitcommit' =>  'Download the cck project and then add it and commit it to Git.'
+      ),
+    ),
     'bzr' => array(
       'signature' => 'bzr root %s',
       'options' => array(
Index: commands/pm/updatecode.pm.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/updatecode.pm.inc,v
retrieving revision 1.42
diff -u -r1.42 updatecode.pm.inc
--- commands/pm/updatecode.pm.inc	5 Jan 2011 06:28:44 -0000	1.42
+++ commands/pm/updatecode.pm.inc	5 Jan 2011 10:56:31 -0000
@@ -240,6 +240,16 @@
     return drush_set_error('DRUSH_PATH_NO_WRITABLE', dt('Drupal root path is not writable.'));
   }
 
+  if (!$version_control = drush_pm_include_version_control($drupal_root)) {
+    return FALSE;
+  }
+
+  $project['full_project_path'] = $drupal_root;
+  // Check we have a version control system, and it clears its pre-flight.
+  if (!$version_control->pre_update($project)) {
+    return FALSE;
+  }
+
   // Create a directory 'core' if it does not already exist.
   $project['path'] = 'drupal-' . $project['candidate_version'];
   $project['full_project_path'] = $drupal_root . '/' . $project['path'];
@@ -250,12 +260,10 @@
   // Create a list of directories to exclude from the update process.
   $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);
-  foreach (array_keys($items_to_test) as $item) {
+  $files = drush_scan_directory($drupal_root, '/.*/', array_merge(array('.', '..'), $skip_list), 0, FALSE, 'basename', 0, TRUE);
+  foreach (array_keys($files) as $item) {
     if (is_dir($item) && !is_writable($item)) {
       $skip_list[] = $item;
-      unset($items_to_test[$item]);
     }
   }
   $project['skip_list'] = $skip_list;
@@ -268,15 +276,7 @@
   // the _pm_update_move_files above.
   drush_set_context('DRUSH_PM_DRUPAL_CORE', $project);
 
-  if (!$version_control = drush_pm_include_version_control($project['full_project_path'])) {
-    return FALSE;
-  }
-
   $project['base_project_path'] = dirname($project['full_project_path']);
-  // Check we have a version control system, and it clears its pre-flight.
-  if (!$version_control->pre_update($project, $items_to_test)) {
-    return FALSE;
-  }
 
   // Package handlers want the project directory in project_dir.
   $project['project_dir'] = $project['path'];
Index: commands/pm/version_control/bzr.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/version_control/bzr.inc,v
retrieving revision 1.12
diff -u -r1.12 bzr.inc
--- commands/pm/version_control/bzr.inc	4 Jan 2011 09:27:46 -0000	1.12
+++ commands/pm/version_control/bzr.inc	5 Jan 2011 10:56:31 -0000
@@ -12,20 +12,16 @@
    *
    * 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.
-    $args = array_keys($items_to_test);
-    array_unshift($args, 'bzr status --short ' . str_repeat('%s ', count($items_to_test)));
-    array_unshift($args, $project['full_project_path']);
-    if (call_user_func_array('drush_shell_cd_and_exec', $args)) {
+  public function pre_update(&$project) {
+    // Check the project directory looks clean.
+    if (drush_shell_cd_and_exec($project['full_project_path'], 'bzr status --short')) {
       $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 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_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status on !path. Check that you have Bazaar \ninstalled and that this directory is a Bazaar 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_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
     }
     return TRUE;
   }
@@ -41,7 +37,7 @@
       }
     }
     else {
-      return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the Bazaar status on !path. Check that you have Bazaar \ninstalled and that this directory is a Bazaar 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_BZR_NOT_FOUND', dt("Drush was unable to revert the Bazaar working copy on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
     }
   }
 
@@ -98,7 +94,7 @@
         }
       }
       else {
-        return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status. Check that you have Bazaar \ninstalled and that the site is a Bazaar working copy.\nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output()))));
+        return drush_set_error('DRUSH_PM_BZR_NOT_FOUND', dt("Drush was unable to get the bzr status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
       }
       return TRUE;
     }
Index: commands/pm/version_control/git.inc
===================================================================
RCS file: commands/pm/version_control/git.inc
diff -N commands/pm/version_control/git.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ commands/pm/version_control/git.inc	5 Jan 2011 10:56:31 -0000
@@ -0,0 +1,136 @@
+<?php
+// $Id$
+
+/**
+ * @file Drush pm Git extension
+ */
+
+class drush_pm_version_control_git implements drush_pm_version_control {
+
+  /**
+   * Implementation of pre_update().
+   */
+  public function pre_update(&$project) {
+    // Check the project directory looks clean.
+    if (drush_shell_cd_and_exec($project['full_project_path'], 'git status --short')) {
+      // git status doesn't provide an exit code for this usecase.
+      // We need to test $output is not empty.
+      $output = drush_shell_exec_output();
+      if (!empty($output)) {
+        $output = preg_grep('/^[ ADR?][ MC?]/', drush_shell_exec_output());
+        if (!empty($output)) {
+          return drush_set_error('DRUSH_PM_GIT_LOCAL_CHANGES', dt("The Git 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_GIT_NOT_FOUND', dt("Drush was unable to get the git status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
+    }
+    return TRUE;
+  }
+
+  /**
+   * Implementation of rollback().
+   */
+  public function rollback($project) {
+    if (drush_shell_exec('git checkout %s', $project['full_project_path'])) {
+      $output = drush_shell_exec_output();
+      if (!empty($output)) {
+        return drush_set_error('DRUSH_PM_GIT_LOCAL_CHANGES', dt("The Git 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_GIT_NOT_FOUND', dt("Drush was unable to revert the Git working copy on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
+    }
+  }
+
+  /**
+   * Implementation of post_update().
+   */
+  public function post_update($project) {
+    if ($this->sync($project)) {
+      // Only attempt commit on a sucessful sync
+      $this->commit($project);
+    }
+  }
+
+  /**
+   * Implementation of post_download().
+   */
+  public function post_download($project) {
+    if ($this->sync($project)) {
+      // Only attempt commit on a sucessful sync
+      $this->commit($project);
+    }
+  }
+
+  /**
+   * Automatically add any unversioned files to Git and remove any files
+   * that have been deleted on the file system
+   */
+  private function sync($project) {
+    if (drush_get_option('gitsync')) {
+      if (drush_shell_cd_and_exec($project['full_project_path'], 'git status --short')) {
+        // git status doesn't provide an exit code for this usecase.
+        // We need to test $output is not empty.
+        $output = drush_shell_exec_output();
+        if (!empty($output)) {
+          $errors = '';
+          // All paths returned by git status are relative to the cwd so let's
+          // temporary change to the project directory.
+          $olddir = getcwd();
+          drush_op('chdir', $project['full_project_path']);
+          foreach ($output as $line) {
+            // git add untracked files
+            if (preg_match('/^\?\?\s(.*)/', $line, $matches)) {
+              $path = $matches[1];
+              if (!drush_shell_exec('git add %s', $path)) {
+                $errors .= implode("\n", drush_shell_exec_output());
+              }
+            }
+            // git rm deleted files
+            else if (preg_match('/^\sD\s(.*)/', $line, $matches)) {
+              $path = $matches[1];
+              if (!drush_shell_exec('git rm %s', $path)) {
+                $errors .= implode("\n", drush_shell_exec_output());
+              }
+            }
+          }
+          drush_op('chdir', $olddir);
+          if (!empty($errors)) {
+            return drush_set_error('DRUSH_PM_GIT_SYNC_PROBLEMS', dt("Problems were encountered adding or removing files to/from Bazaar.\nThe specific errors are below:\n!errors", array('!errors' => $errors)));
+          }
+        }
+      }
+      else {
+        return drush_set_error('DRUSH_PM_GIT_NOT_FOUND', dt("Drush was unable to get the git status on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
+      }
+      return TRUE;
+    }
+  }
+
+  /**
+   * Automatically commit changes to the repository
+   */
+  private function commit($project) {
+    if (drush_get_option('gitcommit')) {
+      $message = drush_get_option('gitmessage');
+      if (empty($message)) {
+        $message = dt("Drush automatic commit.\nProject: @name @type\nCommand: @arguments", array('@name' => $project['name'], '@type' => $project['project_type'], '@arguments' => implode(' ', $_SERVER['argv'])));
+      }
+      if (drush_shell_exec('git commit --message=%s %s', $message, $project['full_project_path'])) {
+        drush_log(dt('Project !name committed to Git successfully', array('!name' => $project['name'])), 'ok');
+      }
+      else {
+        drush_set_error('DRUSH_PM_GIT_COMMIT_PROBLEMS', dt("Problems were encountered committing your changes to Git.\nThe specific errors are below:\n!errors", array('!errors' => implode("\n", drush_shell_exec_output()))));
+      }
+    }
+    else {
+      drush_print(dt("You should consider committing the new code to your Git repository.\nIf this version becomes undesireable, use Git to roll back."));
+    }
+  }
+
+  public static function reserved_files() {
+    return array('.git', '.gitignore');
+  }
+}
Index: commands/pm/version_control/svn.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/version_control/svn.inc,v
retrieving revision 1.16
diff -u -r1.16 svn.inc
--- commands/pm/version_control/svn.inc	7 Dec 2010 16:35:09 -0000	1.16
+++ commands/pm/version_control/svn.inc	5 Jan 2011 10:56:31 -0000
@@ -10,12 +10,8 @@
   /**
    * Implementation of pre_update().
    */
-  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
+  public function pre_update(&$project) {
+    // Check the project directory looks clean.
     if (drush_shell_cd_and_exec($project['full_project_path'], 'svn status '. drush_get_option('svnstatusparams') .' '. $status_files)) {
       $output = preg_grep('/^[ ACDMRX?!~][ CM][ L][ +][ SX][ K]/', drush_shell_exec_output());
       if (!empty($output)) {
@@ -26,8 +22,8 @@
       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)) {
+    // Check for incoming updates.
+    if (drush_shell_cd_and_exec($project['full_project_path'], 'svn status -u '. drush_get_option('svnstatusparams'))) {
       $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))));
@@ -50,7 +46,7 @@
       }
     }
     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 revert the svn working copy on !path.\nThe specific errors are below:\n!errors", array('!path' => $project['full_project_path'], '!errors' => implode("\n", drush_shell_exec_output()))));
     }
   }
 
@@ -100,7 +96,7 @@
         }
       }
       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()))));
       }
       return TRUE;
     }
@@ -113,7 +109,7 @@
     if (drush_get_option('svncommit')) {
       $message = drush_get_option('svnmessage');
       if (empty($message)) {
-        $message = dt("Drush automatic commit: \n") . implode(' ', $_SERVER['argv']);
+        $message = dt("Drush automatic commit.\nProject: @name @type\nCommand: @arguments", array('@name' => $project['name'], '@type' => $project['project_type'], '@arguments' => implode(' ', $_SERVER['argv'])));
       }
       if (drush_shell_exec('svn commit '. drush_get_option('svncommitparams') .' -m "'. $message .'" '. $project['full_project_path'])) {
         drush_log(dt('Project committed to Subversion successfully'), 'ok');
