incorporated --size-limit feature
authorbuild <build@41d37cc5-eb28-0410-a9bf-d37491348ade>
Mon, 12 Mar 2007 15:05:42 +0000 (15:05 +0000)
committerbuild <build@41d37cc5-eb28-0410-a9bf-d37491348ade>
Mon, 12 Mar 2007 15:05:42 +0000 (15:05 +0000)
tunings-myplc-devel/commit-email.pl

index 03e3b61..9d0ef92 100755 (executable)
@@ -26,6 +26,9 @@
 # history and logs, available at http://subversion.tigris.org/.
 # ====================================================================
 
+# Modified by Branden Robinson, Peter Samuelson, and Mark Hymers
+# September 2004 to add $size_limit support.
+
 # Turn on warnings the best way depending on the Perl version.
 BEGIN {
   if ( $] >= 5.006_000)
@@ -40,6 +43,9 @@ use Carp;
 ######################################################################
 # Configuration section.
 
+# Body of the message to be sent
+my @body;
+
 # Sendmail path.
 my $sendmail = "/usr/sbin/sendmail";
 
@@ -50,12 +56,12 @@ my $svnlook = "/usr/bin/svnlook";
 # prints the entire contents of the file.  If you want to save space
 # in the log and email messages by not printing the file, then set
 # $no_diff_deleted to 1.
-my $no_diff_deleted = 0;
+my $no_diff_deleted = 1;
 # By default, when a file is added to the repository, svnlook diff
 # prints the entire contents of the file.  If you want to save space
 # in the log and email messages by not printing the file, then set
 # $no_diff_added to 1.
-my $no_diff_added = 0;
+my $no_diff_added = 1;
 
 # End of Configuration section.
 ######################################################################
@@ -102,6 +108,7 @@ my $rev;
 
 # Use the reference to the first project to populate.
 my $current_project = $project_settings_list[0];
+my $size_limit = 0;
 
 # This hash matches the command line option to the hash key in the
 # project.  If a key exists but has a false value (''), then the
@@ -111,7 +118,8 @@ my %opt_to_hash_key = ('--from' => 'from_address',
                        '-l'     => 'log_file',
                        '-m'     => '',
                        '-r'     => 'reply_to',
-                       '-s'     => 'subject_prefix');
+                       '-s'     => 'subject_prefix',
+                 '--size-limit' => '');
 
 while (@ARGV)
   {
@@ -136,14 +144,28 @@ while (@ARGV)
           }
         else
           {
-            # Here handle -m.
-            unless ($arg eq '-m')
+            # Handle -m and --size-limit here.
+            if ($arg eq '-m')
+              {
+                $current_project                = &new_project;
+                $current_project->{match_regex} = $value;
+                push(@project_settings_list, $current_project);
+              }
+            elsif ($arg eq '--size-limit')
               {
-                die "$0: internal error: should only handle -m here.\n";
+                $size_limit = $value;
+                # Validate the specified diff size limit.
+                if ($size_limit ne '' and $size_limit ne -1 and $size_limit !~ /^\d+$/)
+                  {
+                    die "$0: --size-limit takes only a positive integer or -1"
+                        . " argument; \"$size_limit\" is neither\n";
+                  }
+              }
+            else
+              {
+                die "$0: internal error: should only handle -m and --size-limit"
+                    . "here.\n";
               }
-            $current_project                = &new_project;
-            $current_project->{match_regex} = $value;
-            push(@project_settings_list, $current_project);
           }
       }
     elsif ($arg =~ /^-/)
@@ -226,15 +248,22 @@ chdir($tmp_dir)
   or die "$0: cannot chdir `$tmp_dir': $!\n";
 
 # Get the author, date, and log from svnlook.
-my @svnlooklines = &read_from_process($svnlook, 'info', $repos, '-r', $rev);
+my ($lines_size, @svnlooklines) = &read_from_process(0, $svnlook, 'info',
+                                                     $repos, '-r', $rev);
 my $author = shift @svnlooklines;
 my $date = shift @svnlooklines;
 shift @svnlooklines;
 my @log = map { "$_\n" } @svnlooklines;
 
+# Add header to body
+push(@body, "Author: $author\n");
+push(@body, "Date: $date\n");
+push(@body, "New Revision: $rev\n");
+push(@body, "\n");
+
 # Figure out what directories have changed using svnlook.
-my @dirschanged = &read_from_process($svnlook, 'dirs-changed', $repos, 
-                                     '-r', $rev);
+my ($dirs_size, @dirschanged) = &read_from_process(0, $svnlook, 'dirs-changed',
+                                                   $repos, '-r', $rev);
 
 # Lose the trailing slash in the directory names if one exists, except
 # in the case of '/'.
@@ -252,7 +281,9 @@ for (my $i=0; $i<@dirschanged; ++$i)
   }
 
 # Figure out what files have changed using svnlook.
-@svnlooklines = &read_from_process($svnlook, 'changed', $repos, '-r', $rev);
+my $look_size;
+($look_size, @svnlooklines) = &read_from_process(0, $svnlook, 'changed', $repos,
+                                                 '-r', $rev);
 
 # Parse the changed nodes.
 my @adds;
@@ -285,13 +316,69 @@ foreach my $line (@svnlooklines)
       }
   }
 
-# Get the diff from svnlook.
-my @no_diff_deleted = $no_diff_deleted ? ('--no-diff-deleted') : ();
-my @no_diff_added = $no_diff_added ? ('--no-diff-added') : ();
-my @difflines = &read_from_process($svnlook, 'diff', $repos,
-                                   '-r', $rev, @no_diff_deleted,
-                                   @no_diff_added);
+# Add the adds, dels and mods to the body of the message.
+if (@adds)
+  {
+    @adds = sort @adds;
+    push(@body, "Added:\n");
+    push(@body, map { "   $_\n" } @adds);
+  }
+if (@dels)
+  {
+    @dels = sort @dels;
+    push(@body, "Removed:\n");
+    push(@body, map { "   $_\n" } @dels);
+  }
+if (@mods)
+  {
+    @mods = sort @mods;
+    push(@body, "Modified:\n");
+    push(@body, map { "   $_\n" } @mods);
+  }
+
+my @difflines;
+my $diff_howto = "Use \"svn diff" . " -r " . ($rev - 1) . ":$rev\" to view"
+                 . " diff.\n";
+
+# Work out how many bytes we have available for the diff.
+my $size_avail = 0;
+if ($size_limit > 0)
+  {
+    my $bodylen = 0;
+    for (@body) { $bodylen += length($_); }
+    $size_avail = $size_limit - $bodylen;
+
+    warn "sl= $size_limit -- sa = $size_avail";
+
+    if ($size_avail <= 0)
+      {
+        @difflines = ( "Diff skipped; message reached limit of $size_limit"
+                       . " bytes with list of changed paths.\n$diff_howto" );
+      }
+}
 
+# A $size_limit of -1 means we do not include a diff.
+if ($size_limit ne -1)
+  {
+    # Get the diff from svnlook.
+    my @no_diff_deleted = $no_diff_deleted ? ('--no-diff-deleted') : ();
+    my @no_diff_added = $no_diff_added ? ('--no-diff-added') : ();
+    my $numbytes;
+    ($numbytes, @difflines) = &read_from_process($size_avail, $svnlook, 'diff',
+                                                 $repos, '-r', $rev,
+                                                 @no_diff_deleted, @no_diff_added);
+    # If the diff is larger than the remaining size limit, we must discard
+    # it.
+    if ($numbytes == -1) {
+      @difflines = ( "Including diff would make mail exceed size limit of"
+                     . " $size_limit bytes.\n$diff_howto" );
+      }
+  }
+else
+  {
+    @difflines = ( $diff_howto );
+  }
+  
 ######################################################################
 # Modified directory name collapsing.
 
@@ -342,33 +429,6 @@ if (!$rootchanged and @dirschanged > 1)
   }
 my $dirlist = join(' ', @dirschanged);
 
-######################################################################
-# Assembly of log message.
-
-# Put together the body of the log message.
-my @body;
-push(@body, "Author: $author\n");
-push(@body, "Date: $date\n");
-push(@body, "New Revision: $rev\n");
-push(@body, "\n");
-if (@adds)
-  {
-    @adds = sort @adds;
-    push(@body, "Added:\n");
-    push(@body, map { "   $_\n" } @adds);
-  }
-if (@dels)
-  {
-    @dels = sort @dels;
-    push(@body, "Removed:\n");
-    push(@body, map { "   $_\n" } @dels);
-  }
-if (@mods)
-  {
-    @mods = sort @mods;
-    push(@body, "Modified:\n");
-    push(@body, map { "   $_\n" } @mods);
-  }
 push(@body, "Log:\n");
 push(@body, @log);
 push(@body, "\n");
@@ -393,7 +453,6 @@ foreach my $project (@project_settings_list)
 
     my @email_addresses = @{$project->{email_addresses}};
     my $userlist        = join(' ', @email_addresses);
-    my $to              = join(', ', @email_addresses);
     my $from_address    = $project->{from_address};
     my $hostname        = $project->{hostname};
     my $log_file        = $project->{log_file};
@@ -425,7 +484,7 @@ foreach my $project (@project_settings_list)
       }
 
     my @head;
-    push(@head, "To: $to\n");
+    push(@head, "To: $userlist\n");
     push(@head, "From: $mail_from\n");
     push(@head, "Subject: $subject\n");
     push(@head, "Reply-to: $reply_to\n") if $reply_to;
@@ -505,6 +564,9 @@ sub usage
       "  -m regex              Regular expression to match committed path\n",
       "  -r email_address      Email address for 'Reply-To:'\n",
       "  -s subject_prefix     Subject line prefix\n",
+      "  --size-limit limit    Message size limit in bytes (positive\n",
+      "                        integer); if message exceeds limit, diff is\n",
+      "                        omitted; if set to -1, diff is never sent\n",
       "\n",
       "This script supports a single repository with multiple projects,\n",
       "where each project receives email only for commits that modify that\n",
@@ -540,6 +602,10 @@ sub new_project
 }
 
 # Start a child process safely without using /bin/sh.
+#
+# We take a parameter, $limit, which if greater than zero will limit the
+# amount we read -- this is a hack to avoid OOM errors.   If we return
+# $read_size == -1, we exceeded the limit.
 sub safe_read_from_pipe
 {
   unless (@_)
@@ -547,6 +613,7 @@ sub safe_read_from_pipe
       croak "$0: safe_read_from_pipe passed no arguments.\n";
     }
 
+  my $limit = shift @_;
   my $pid = open(SAFE_READ, '-|');
   unless (defined $pid)
     {
@@ -560,9 +627,17 @@ sub safe_read_from_pipe
         or die "$0: cannot exec `@_': $!\n";
     }
   my @output;
+  my $read_size = 0;
   while (<SAFE_READ>)
     {
       s/[\r\n]+$//;
+      $read_size += length;
+      if (($limit > 0) and ($read_size > $limit))
+      {
+        $read_size = -1;
+        @output = ("output size exceeds specified limit of " . $limit);
+        last;
+      }
       push(@output, $_);
     }
   close(SAFE_READ);
@@ -576,7 +651,7 @@ sub safe_read_from_pipe
     }
   if (wantarray)
     {
-      return ($result, @output);
+      return ($result, $read_size, @output);
     }
   else
     {
@@ -586,20 +661,20 @@ sub safe_read_from_pipe
 
 # Use safe_read_from_pipe to start a child process safely and return
 # the output if it succeeded or an error message followed by the output
-# if it failed.
+# if it failed.  Returns number of bytes read and the output.
 sub read_from_process
 {
   unless (@_)
     {
       croak "$0: read_from_process passed no arguments.\n";
     }
-  my ($status, @output) = &safe_read_from_pipe(@_);
-  if ($status)
+  my ($status, $read_size, @output) = &safe_read_from_pipe(@_);
+  if ($read_size >= 0 and $status)
     {
       return ("$0: `@_' failed with this output:", @output);
     }
   else
     {
-      return @output;
+      return ($read_size, @output);
     }
 }