| 1 |
#! /usr/bin/perl |
| 2 |
|
| 3 |
# Usage: cvs-commitmail [-u user] [[-m mailto] ...] [-s] [-V] 'dirname file ...' |
| 4 |
# |
| 5 |
# -u user - $USER passed from loginfo |
| 6 |
# -m mailto - for each user to receive cvs log reports |
| 7 |
# (multiple -m's permitted) |
| 8 |
# -s - to prevent "cvs status -v" messages |
| 9 |
# -V - without '-s', don't pass '-v' to cvs status |
| 10 |
# -d - attatch diffs. |
| 11 |
# |
| 12 |
# On CVSROOT/loginfo |
| 13 |
# |
| 14 |
# # for cvs version 1.11.x or former |
| 15 |
# modulename /usr/bin/cvs-commitmail -d -m user@example.com %{sVv} |
| 16 |
# |
| 17 |
# # for cvs version 1.12.x or later |
| 18 |
# modulename /usr/bin/cvs-commitmail -d -m user@example.com "%p %{sVv}" |
| 19 |
# |
| 20 |
|
| 21 |
# here is what the output looks like: |
| 22 |
# |
| 23 |
# From: commituser@cvs.example.com |
| 24 |
# Subject: CVS update: modulename |
| 25 |
# |
| 26 |
# Date: Wednesday November 23, 1994 @ 14:15 |
| 27 |
# Author: woods |
| 28 |
# |
| 29 |
# Update of /cvsroot/modulename |
| 30 |
# In directory cvs:/tmp/cvs-serv0001 |
| 31 |
# |
| 32 |
# Modified Files: |
| 33 |
# test3 |
| 34 |
# Added Files: |
| 35 |
# test6 |
| 36 |
# Removed Files: |
| 37 |
# test4 |
| 38 |
# Log Message: |
| 39 |
# - wow, what a test |
| 40 |
# |
| 41 |
# (and for each file the "cvs status -v" output is appended unless -s is used) |
| 42 |
# |
| 43 |
# ================================================================== |
| 44 |
# File: test3 Status: Up-to-date |
| 45 |
# |
| 46 |
# Working revision: 1.41 Wed Nov 23 14:15:59 1994 |
| 47 |
# Repository revision: 1.41 /cvsroot/modulename/test3,v |
| 48 |
# Sticky Options: -ko |
| 49 |
# |
| 50 |
# Existing Tags: |
| 51 |
# local-v2 (revision: 1.7) |
| 52 |
# local-v1 (revision: 1.1.1.2) |
| 53 |
# CVS-1_4A2 (revision: 1.1.1.2) |
| 54 |
# local-v0 (revision: 1.2) |
| 55 |
# CVS-1_4A1 (revision: 1.1.1.1) |
| 56 |
# CVS (branch: 1.1.1) |
| 57 |
|
| 58 |
use strict; |
| 59 |
use IO::File; |
| 60 |
use POSIX; |
| 61 |
use Jcode; |
| 62 |
|
| 63 |
umask(002); |
| 64 |
|
| 65 |
`cvs --version` =~ /(\d+\.\d+\.\d+)/; |
| 66 |
my $cvsversion = $1; |
| 67 |
|
| 68 |
my $cvsroot = $ENV{'CVSROOT'}; |
| 69 |
my $dostatus = 1; |
| 70 |
my $showstatus = 1; |
| 71 |
my $verbosestatus = 1; |
| 72 |
my @users; |
| 73 |
my $showdiff = 0; |
| 74 |
my $showurl = 0; |
| 75 |
my $login; |
| 76 |
my $donefiles; |
| 77 |
my $logfile; |
| 78 |
my @files; |
| 79 |
my $cvsweb_url = 'http://cvs.sourceforge.jp/cgi-bin/viewcvs.cgi/samurai-graph/'; |
| 80 |
|
| 81 |
# turn off setgid |
| 82 |
$) = $(; |
| 83 |
|
| 84 |
# parse command line arguments |
| 85 |
while (@ARGV) { |
| 86 |
my $arg = shift @ARGV; |
| 87 |
|
| 88 |
if ($arg eq '-m') { |
| 89 |
push(@users, shift @ARGV); |
| 90 |
} elsif ($arg eq '-u') { |
| 91 |
$login = shift @ARGV; |
| 92 |
} elsif ($arg eq '-f') { |
| 93 |
($logfile) && die "Too many '-f' args"; |
| 94 |
$logfile = shift @ARGV; |
| 95 |
} elsif ($arg eq '-s') { |
| 96 |
$showstatus = 0; |
| 97 |
} elsif ($arg eq '-V') { |
| 98 |
$verbosestatus = 0; |
| 99 |
} elsif ($arg eq '-d') { |
| 100 |
$showdiff = 1; |
| 101 |
} elsif ($arg eq '-c') { |
| 102 |
$showurl = 1; |
| 103 |
} else { |
| 104 |
($donefiles) && die "Too many arguments!\n"; |
| 105 |
$donefiles = 1; |
| 106 |
@files = split(/ /, $arg); |
| 107 |
} |
| 108 |
} |
| 109 |
|
| 110 |
# the first argument is the module location relative to $CVSROOT |
| 111 |
my $modulepath = shift @files; |
| 112 |
my $subject = "CVS update: $modulepath"; |
| 113 |
my $str = ""; |
| 114 |
my $diffstr = ""; |
| 115 |
|
| 116 |
# get a login name for the guy doing the commit.... |
| 117 |
if ($login eq '') { |
| 118 |
$login = getlogin || (getpwuid($<))[0] || "nobody"; |
| 119 |
} |
| 120 |
|
| 121 |
$str .= strftime("Date:\t%A %B %d, %Y @ %H:%M\n", localtime); |
| 122 |
$str .= "Author:\t$login\n\n"; |
| 123 |
|
| 124 |
# print the stuff from logmsg that comes in on stdin to the logfile |
| 125 |
my $infh = new IO::File "< -"; |
| 126 |
foreach ($infh->getlines) { |
| 127 |
$str .= Jcode->new($_)->h2z->jis; |
| 128 |
} |
| 129 |
undef $infh; |
| 130 |
$str .= "\n"; |
| 131 |
|
| 132 |
# after log information, do an 'cvs -Qq status -v' on each file in the arguments. |
| 133 |
if ($dostatus != 0) { |
| 134 |
while (@files) { |
| 135 |
my $newrev = ''; |
| 136 |
my $oldrev = ''; |
| 137 |
my $file = ''; |
| 138 |
if ($showdiff || $showurl) { |
| 139 |
if ($cvsversion =~ /^1\.11\./) { |
| 140 |
my @filenames = split(/,/, shift @files); |
| 141 |
$newrev = pop(@filenames); |
| 142 |
$oldrev = pop(@filenames); |
| 143 |
$file = join(',', @filenames); |
| 144 |
undef @filenames; |
| 145 |
} else { |
| 146 |
$file = shift @files; |
| 147 |
$oldrev = shift @files; |
| 148 |
$newrev = shift @files; |
| 149 |
} |
| 150 |
} else { |
| 151 |
$file = shift @files; |
| 152 |
} |
| 153 |
if ($file eq "-") { |
| 154 |
$str .= "[input file was '-']\n"; |
| 155 |
last; |
| 156 |
} |
| 157 |
|
| 158 |
if ($showstatus) { |
| 159 |
my $rcsfh = new IO::File; |
| 160 |
my $pid = $rcsfh->open ("-|"); |
| 161 |
if ( !defined $pid ) |
| 162 |
{ |
| 163 |
die "fork failed: $!"; |
| 164 |
} |
| 165 |
if ($pid == 0) |
| 166 |
{ |
| 167 |
my @command = ('cvs', '-nQq', 'status'); |
| 168 |
if ($verbosestatus) |
| 169 |
{ |
| 170 |
push @command, '-v'; |
| 171 |
} |
| 172 |
push @command, $file; |
| 173 |
exec @command; |
| 174 |
die "cvs exec failed: $!"; |
| 175 |
} |
| 176 |
my $line; |
| 177 |
while ($line = $rcsfh->getline) { |
| 178 |
$str .= $line; |
| 179 |
} |
| 180 |
undef $rcsfh; |
| 181 |
undef $pid; |
| 182 |
} |
| 183 |
|
| 184 |
# added cvsweb url |
| 185 |
if ($showurl) { |
| 186 |
$str .= "$modulepath/$file $oldrev -> $newrev ("; |
| 187 |
if ($oldrev eq 'NONE') { |
| 188 |
$str .= 'added'; |
| 189 |
} elsif ($newrev eq 'NONE') { |
| 190 |
$str .= 'removed'; |
| 191 |
} else { |
| 192 |
$str .= 'modified'; |
| 193 |
} |
| 194 |
$str .= ")\n"; |
| 195 |
$str .= "$cvsweb_url$modulepath/$file"; |
| 196 |
if ($oldrev eq 'NONE' || $newrev eq 'NONE') { |
| 197 |
$str .= "?rev="; |
| 198 |
if ($oldrev eq 'NONE'){ |
| 199 |
$str .= "$newrev"; |
| 200 |
} else { |
| 201 |
$str .= "$oldrev"; |
| 202 |
} |
| 203 |
$str .= '&content-type=text/vnd.viewcvs-markup'; |
| 204 |
$str .= "\n"; |
| 205 |
} else { |
| 206 |
$str .= ".diff?r1=$oldrev&r2=$newrev\n"; |
| 207 |
} |
| 208 |
} |
| 209 |
|
| 210 |
if ($showdiff) { |
| 211 |
my $rcsfh = new IO::File; |
| 212 |
my $pid = $rcsfh->open ("-|"); |
| 213 |
if ( !defined $pid ) { |
| 214 |
die "fork failed: $!"; |
| 215 |
} |
| 216 |
if ($pid == 0) { |
| 217 |
my @command = ('cvs', '-nQq', 'rdiff', '-u'); |
| 218 |
if ($oldrev eq "NONE") { |
| 219 |
push @command, "-r0"; |
| 220 |
} else { |
| 221 |
push @command, "-r${oldrev}"; |
| 222 |
} |
| 223 |
push @command, "-r${newrev}" |
| 224 |
if ($newrev ne "NONE"); |
| 225 |
push @command, "${modulepath}/${file}"; |
| 226 |
exec @command; |
| 227 |
die "cvs exec failed: $!"; |
| 228 |
} |
| 229 |
my $line; |
| 230 |
while ($line = $rcsfh->getline) { |
| 231 |
$diffstr .= $line; |
| 232 |
} |
| 233 |
undef $rcsfh; |
| 234 |
} |
| 235 |
} |
| 236 |
} |
| 237 |
|
| 238 |
my @mailcmd = ('mime-construct', '--to', join(',', @users), '--subject', $subject, '--type', 'text/plain', '--encoding' , '7bit', '--string', $str); |
| 239 |
if ($showdiff) { |
| 240 |
push(@mailcmd, '--type', 'text/plain', '--encoding', '8bit', '--string', $diffstr); |
| 241 |
} |
| 242 |
system(@mailcmd); |
| 243 |
|
| 244 |
exit 0; |