Index: drush_pm/drush_pm.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/drush_pm/drush_pm.module,v
retrieving revision 1.18.2.1
diff -u -r1.18.2.1 drush_pm.module
--- drush_pm/drush_pm.module	13 Apr 2008 15:30:14 -0000	1.18.2.1
+++ drush_pm/drush_pm.module	13 May 2008 01:49:55 -0000
@@ -153,6 +153,7 @@
       elseif ($package_handler($project_name, $release, $modulepath)) {
         drush_print(t("Project !project successfully installed (version !version).",
           array('!project' => $project_name, '!version' => $release['version'])));
+        module_invoke_all('drush_pm_post_install', $project_name, $release, $modulepath);
       }
     }
     else {
@@ -254,14 +255,10 @@
   foreach($updateable as $project) {
     drush_verbose(t('Starting to update !project ...', array('!project' => $project['title'])));
     
-    $svn = FALSE;
     $source = DRUSH_DRUPAL_ROOT .'/' . $project['path'];
-    if (file_exists($source. '/.svn')) {
-      // Skip backup since we need all .svn  directories. Assuming admin can use svn revert if new project is bad.
-      drush_verbose(t('Backup skipped because .svn directory was detected. Use Subversion to revert if needed.'));
-      $svn = TRUE;
-    }
-    else {
+    
+    $skip_backup = module_invoke_all('drush_pm_skip_backup', $source);
+    if (!count($skip_backup)) {
       $date = date('Ymd');
       $backup_dir = DRUSH_DRUPAL_ROOT. "/backup/modules/$date";
       drush_op('mkdir', $backup_dir, 0777, TRUE);
@@ -279,22 +276,24 @@
     array_pop($basepath);
     $project_parent_path = DRUSH_DRUPAL_ROOT. '/'. implode('/', $basepath). '/';
     if (!$package_handler($project['name'], $project['releases'][$project['candidate_version']], $project_parent_path)) {
-      drush_error(t('Updating project !project failed. Restoring previously installed version.', array('!project' => $project['name'])));
-      drush_op('rename', $backup_target, $source);
+      if (!count($skip_backup)) {
+        drush_error(t('Updating project !project failed. Restoring previously installed version.', array('!project' => $project['name'])));
+        drush_op('rename', $backup_target, $source);
+      }
+      else {
+        drush_error(t('Updating project !project failed. Please revert to the previously installed version.', array('!project' => $project['name'])));
+      }
     }
     else {
       drush_print(t('Project !project was updated successfully. Installed version is now !version.', array('!project' => $project['name'], '!version' => $project['candidate_version'])));
+      module_invoke_all('drush_pm_post_update', $project['name'], $project['releases'][$project['candidate_version']], $project_parent_path);
+    }
   }
-  
-  if ($svn) {
-    drush_print(t('You should consider committing the new code to your Subversion repository. If this version becomes undesireable, use \'svn revert\' to roll back.'));
-  }
-  else {
-    drush_print(t("Backups were saved into 'backup' directory.")); 
+  if ($backup_dir) {
+    drush_print(t("Backups were saved into the directory !backup_dir.", array('!backup_dir' => $backup_dir))); 
   }
   drush_print(t("You should now run update.php through your browser."));
 }
-}
 
 /**
  * Find a module handler
Index: drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/drush.inc,v
retrieving revision 1.15
diff -u -r1.15 drush.inc
--- drush.inc	1 Feb 2008 21:56:08 -0000	1.15
+++ drush.inc	13 May 2008 01:49:55 -0000
@@ -90,6 +90,7 @@
 /**
  * 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
@@ -107,6 +108,8 @@
   }
 
   exec($cmd . ' 2>&1', $output, $result);
+  
+  _drush_shell_exec_output_set($output);
 
   if (DRUSH_VERBOSE) {
     foreach ($output as $line) {
@@ -119,6 +122,27 @@
 }
 
 /**
+ * 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) 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.
  * TODO: Exit with a correct status code.
  */
Index: drush_pm_svn/drush_pm_svn.info
===================================================================
RCS file: drush_pm_svn/drush_pm_svn.info
diff -N drush_pm_svn/drush_pm_svn.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ drush_pm_svn/drush_pm_svn.info	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,6 @@
+; $Id:$
+name = drush Package Manager SVN Support
+description = Allows drush to manage a site sandbox using SVN.
+package = drush
+dependencies = update_status drush drush_pm
+
Index: drush_pm_svn/drush_pm_svn.module
===================================================================
RCS file: drush_pm_svn/drush_pm_svn.module
diff -N drush_pm_svn/drush_pm_svn.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ drush_pm_svn/drush_pm_svn.module	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,120 @@
+<?php
+// $Id:$
+
+/**
+ * Implementation of hook_help().
+ */
+function drush_pm_svn_help($section) {
+  $help = '';
+  switch ($section) {
+    case 'drush:pm update':
+    case 'drush:pm install':
+      $help .= t("--svnsync - automatically add new files to the Subversion repository and
+remove deleted files. Use this with caution, especially if you leave files in
+project directories that you don't want to be marked for addition, or you
+have deleted a non-project file that you don't want to be marked in svn as a
+deletion.\n
+--svncommit - automatically commit project install or update changes to the
+sites Subversion repository. You can only use this option if you are also
+using the --svnsync option, because committing without first adding new and
+removing deleted files will cause unpredictable results.\n 
+--svnmessage - Override the commit message from the default, which is:
+'Drush automatic commit: ', and the drush command line used.\n
+--svnstatusparams - add options to the 'svn status' command
+--svnaddparams - add options to the 'svn add' command
+--svnremoveparams - add options to the 'svn remove' command
+--svncommitparams - add options to the 'svn commit' command
+e.g. --svncommitparams=\"--username joe\" (note that quotes are required) will
+commit changes as the user 'joe'.\n");
+    return $help;
+  }
+}
+
+/**
+ * Implementation of hook_drush_pm_skip_backup().
+ */
+function drush_pm_svn_drush_pm_skip_backup($source) {
+  if (file_exists($source. '/.svn')) {
+    // Skip backup since we need all .svn  directories. Assuming admin can use svn revert if new project is bad.
+    drush_verbose(t('Backup skipped because .svn directory was detected. Use Subversion to revert if needed.'));
+    return TRUE;
+  }
+}
+
+/**
+ * Implementation of hook_drush_pm_post_update().
+ */
+function drush_pm_svn_drush_pm_post_update($project, $info, $path = '.') {
+  if (drush_pm_svn_sync($project, $info, $path)) {
+    // Only attempt commit on a sucessful sync
+    drush_pm_svn_commit($project, $info, $path);
+  }
+}
+
+/**
+ * Implementation of hook_drush_pm_post_install().
+ */
+function drush_pm_svn_drush_pm_post_install($project, $info, $path = '.') {
+  if (drush_pm_svn_sync($project, $info, $path)) {
+    // Only attempt commit on a sucessful sync
+    drush_pm_svn_commit($project, $info, $path);
+  }
+}
+
+/**
+ * Automatically add any unversioned files to Subversion and remove any files
+ * that have been deleted on the file system
+ */
+function drush_pm_svn_sync($project, $info, $path = '.') {
+  if (drush_get_option('svnsync')) {
+    $errors = '';
+    if (drush_shell_exec('svn status '. drush_get_option('svnstatusparams') .' '. $project)) {
+      $output = drush_shell_exec_output();
+      foreach ($output as $line) {
+        if (preg_match('/^\? *(.*)/', $line, $matches)) {
+          if (!drush_shell_exec('svn add '. drush_get_option('svnaddparams') .' '. $matches[1])) {
+            $errors .= implode("\n", drush_shell_exec_output());
+          }
+        }
+        if (preg_match('/^\! *(.*)/', $line, $matches)) {
+          if (!drush_shell_exec('svn remove '. drush_get_option('svnremoveparams') .' '. $matches[1])) {
+            $errors .= implode("\n", drush_shell_exec_output());
+          }
+        }
+      }
+      if (!empty($errors)) {
+        drush_print(t("Problems were encountered adding or removing files to/from subversion.\nThe specific errors are below:"));
+        drush_print($errors);
+        return FALSE;
+      }
+    }
+    else {
+      drush_print(t("Drush was unable to get the svn status. Check that you have Subversion \ninstalled and that the site is a subversion working copy.\nThe specific errors are below:"));
+      drush_print(implode("\n", drush_shell_exec_output()));
+      return FALSE;
+    }
+    return TRUE;
+  }
+}
+
+/**
+ * Automatically commit changes to the repository
+ */
+function drush_pm_svn_commit($project, $info, $path = '.') {
+  if (drush_get_option('svncommit')) {
+    $message = drush_get_option('svnmessage');
+    if (empty($message)) {
+      $message = t("Drush automatic commit: \n") . implode(' ', $_SERVER['argv']);
+    }
+    if (drush_shell_exec('svn commit '. drush_get_option('svncommitparams') .' -m "'. $message .'" '. $project)) {
+      drush_print(t('Project committed to Subversion successfully'));
+    }
+    else {
+      drush_print(t("'Problems were encountered committing your changes to Subversion.\nThe specific errors are below:"));
+      drush_print(implode("\n", drush_shell_exec_output()));
+    }
+  }
+  else {
+    drush_print(t("You should consider committing the new code to your Subversion repository.\nIf this version becomes undesireable, use Subversion to roll back."));
+  }
+}
