]>
Commit | Line | Data |
---|---|---|
efaa2289 ER |
1 | Index: cvsspam.conf |
2 | =================================================================== | |
83963645 ER |
3 | --- cvsspam.conf (.../tags/RELEASE-0_2_12) (revision 277) |
4 | +++ cvsspam.conf (.../trunk) (revision 277) | |
efaa2289 ER |
5 | @@ -34,11 +34,19 @@ |
6 | # | |
7 | # When $jiraURL is given, text of the form 'project-1234' will be linked | |
8 | # to this issue in JIRA. | |
9 | +# | |
10 | +# When $xplannerStoryURL, $xplannerIterationURL and $xplannerProjectURL are | |
11 | +# given, text of the form XS1234 will be linked to XPlanner stories; text of | |
12 | +# the form XI1234 will be linked to XPlanner iterations; and text of the form | |
13 | +# XP1234 will be linked to XPlanner projects. | |
14 | ||
15 | #$bugzillaURL = "http://bugzilla.mozilla.org/show_bug.cgi?id=%s" | |
16 | ||
17 | #$jiraURL = "http://jira.atlassian.com/secure/ViewIssue.jspa?key=%s" | |
18 | ||
19 | +#$xplannerStoryURL = "http://www.example.com/xplanner/do/view/userstory?oid=%s" | |
20 | +#$xplannerIterationURL = "http://www.example.com/xplanner/do/view/iteration?oid=%s" | |
21 | +#$xplannerProjectURL = "http://www.example.com/xplanner/do/view/project?oid=%s" | |
22 | ||
23 | # Link to Wiki systems | |
24 | # | |
ca77e894 ER |
25 | @@ -71,6 +79,7 @@ |
26 | ||
27 | #$cvswebURL = "http://localhost/cgi-bin/cvsweb.cgi" | |
28 | ||
29 | +#$tracURL = "http://localhost/trac/project" | |
30 | ||
31 | ||
32 | # Additional SMTP Headers (Optional) | |
83963645 ER |
33 | @@ -116,15 +125,32 @@ |
34 | ||
35 | ||
36 | ||
37 | -# cvsdiff keyword ignoring (Default: show changes in keywords) | |
38 | +# cvsdiff keyword ignoring (Default: show changes in keywords) | |
d895f970 ER |
39 | # |
40 | # Changes in CVS keywords can be distracting. For instance, the | |
40f465db | 41 | -# $Revision: 1.12 $ keyword will change on each commit. Set this value to true |
d895f970 ER |
42 | +# $Revision$ keyword will change on each commit. Set this value to true |
43 | # to exclude changes in keyword fields (adds the -kk option to cvs diff). | |
44 | ||
efaa2289 ER |
45 | #$diff_ignore_keywords = true |
46 | ||
47 | ||
83963645 | 48 | +# cvsdiff whitespace ignoring (Default: show whitespace-only changes) |
efaa2289 ER |
49 | +# |
50 | +# Whitespace-only changes can distract from the rest of a diff. Set this | |
51 | +# value to true to exclude changes in the amount of whitespace (adds the -b | |
52 | +# option to cvs diff). | |
53 | + | |
54 | +$diff_ignore_whitespace = true | |
55 | + | |
83963645 ER |
56 | + |
57 | +# cvs diff files ignoring (Default: empty) | |
58 | +# | |
59 | +# Make CVSspam ignore certain files. | |
60 | +# | |
61 | +# Can contain file masks, separated by whitespace. | |
62 | + | |
63 | +#$ignore_files = "*.al *.gif" | |
efaa2289 ER |
64 | + |
65 | # $no_removed_file_diff and $no_added_file_diff | |
66 | # | |
67 | # Set both these options, and emails will only include diffs for files | |
83963645 ER |
68 | @@ -132,7 +158,7 @@ |
69 | # deleted... | |
70 | ||
71 | ||
72 | -# Don't show diff for removed files (Default: show file's contents) | |
73 | +# Don't show diff for removed files (Default: show file's contents) | |
74 | # | |
75 | # If you aren't interested in seeing the contents of a file that was | |
76 | # removed, set this option to true. The files will still appear in the index | |
77 | @@ -166,14 +192,46 @@ | |
ca77e894 ER |
78 | # Allows the specification of a character set for all generated emails. |
79 | # The files CVS is dealing with should already be in the character set you | |
80 | # specify -- no transcoding is done. | |
81 | +# | |
82 | +# Note that you can override this with --charset argument per module, etc. | |
83 | ||
84 | #$charset="ISO-8859-1" | |
85 | ||
86 | ||
87 | ||
88 | +# Users file (Default: $CVSROOT/CVSROOT/users) | |
89 | +# | |
90 | +# Specify users file to lookup From addresses for commites | |
91 | + | |
92 | +#$users_file = "/srv/svn/users" | |
93 | + | |
94 | +# Users file charset (Default: $charset) | |
95 | +# | |
96 | +# If the users file is encoded differently than $charset, You can override | |
97 | +# it here. Especially useful if you use --charset argument. See above. | |
98 | + | |
99 | +#$users_file_charset = "ISO-8859-1" | |
100 | + | |
101 | + | |
102 | # File names in Subject (Default: no filenames in Subject) | |
103 | # | |
104 | # Some people like file names to appear in the email subject. To make | |
efaa2289 ER |
105 | # them happy, you can say $files_in_subject = true here. |
106 | ||
107 | #$files_in_subject = false | |
108 | + | |
109 | + | |
ca77e894 ER |
110 | +# Module Path email header (Default: no X-CVSspam-Module-Path header) |
111 | +# | |
112 | +# Sets 'X-CVSspam-Module-Path' header to contain common path of files commited. | |
113 | +# Useful for server side mail filtering. | |
114 | + | |
115 | +#$cvsroot_email_header = true | |
efaa2289 ER |
116 | + |
117 | +# Email size limit (Default: around 2MB) | |
118 | +# | |
119 | +# When large changes are committed, large CVSspam emails can result. Here | |
120 | +# you can set the size of email that CVSspam is not allowed to append any | |
121 | +# more diffs onto. Specify the number of bytes. | |
122 | + | |
123 | +#$mail_size_limit = 2097152 | |
ca77e894 ER |
124 | |
125 | Property changes on: cvsspam.conf | |
126 | ___________________________________________________________________ | |
127 | Deleted: svn:executable | |
128 | - * | |
d895f970 ER |
129 | Modified: svn:keywords |
130 | - Author Date Id Revision | |
131 | + Author Date Id | |
ca77e894 | 132 | |
efaa2289 ER |
133 | Index: collect_diffs.rb |
134 | =================================================================== | |
83963645 ER |
135 | --- collect_diffs.rb (.../tags/RELEASE-0_2_12) (revision 277) |
136 | +++ collect_diffs.rb (.../trunk) (revision 277) | |
137 | @@ -26,7 +26,18 @@ | |
138 | $tmpdir = ENV["TMPDIR"] || "/tmp" | |
f34e4066 ER |
139 | $dirtemplate = "#cvsspam.#{Process.getpgrp}.#{Process.uid}" |
140 | ||
83963645 ER |
141 | +def shell_mask2regex(mask) |
142 | + '^' + mask.gsub('.', '\.').gsub('?', '.').gsub('*', '.*') + '$' | |
143 | +end | |
144 | + | |
f34e4066 ER |
145 | def find_data_dir |
146 | + if $from_address | |
147 | + safe_from = make_fromaddr_safe_for_filename($from_address) | |
148 | + Dir["#{$tmpdir}/#{$dirtemplate}.#{safe_from}-*"].each do |dir| | |
149 | + stat = File.stat(dir) | |
150 | + return dir if stat.owned? | |
151 | + end | |
152 | + end | |
153 | Dir["#{$tmpdir}/#{$dirtemplate}-*"].each do |dir| | |
154 | stat = File.stat(dir) | |
155 | return dir if stat.owned? | |
83963645 | 156 | @@ -35,6 +46,14 @@ |
f34e4066 ER |
157 | end |
158 | ||
159 | ||
160 | +# transform any special / unexpected characters appearing in the argument to | |
161 | +# --from so that they will not cause problems if the value is inserted into | |
162 | +# a file or directory name | |
163 | +def make_fromaddr_safe_for_filename(addr) | |
164 | + addr.gsub(/[^a-zA-Z0-1.,_-]/, "_") | |
165 | +end | |
166 | + | |
167 | + | |
168 | def blah(msg) | |
169 | if $debug | |
170 | $stderr.puts "collect_diffs.rb: #{msg}" | |
83963645 ER |
171 | @@ -81,11 +100,11 @@ |
172 | File.open("#{$datadir}/commitinfo-tags") do |file| | |
173 | $commitinfo_tags = Hash.new | |
174 | file.each_line do |line| | |
175 | - line =~ /([^\t]+)\t(.+)/ | |
176 | - key = $2 | |
177 | - val = $1 | |
178 | - key.sub!(/^#{ENV['CVSROOT']}\//, '') | |
179 | - $commitinfo_tags[key] = val | |
180 | + line =~ /([^\t]+)\t(.+)/ | |
181 | + key = $2 | |
182 | + val = $1 | |
183 | + key.sub!(/^#{ENV['CVSROOT']}\//, '') | |
184 | + $commitinfo_tags[key] = val | |
185 | end | |
186 | end | |
187 | end | |
188 | @@ -129,7 +148,14 @@ | |
f34e4066 ER |
189 | changes = Array.new |
190 | i = 0 | |
191 | while i < cvs_info.length | |
192 | - changes << ChangeInfo.new(cvs_info[i], cvs_info[i+=1], cvs_info[i+=1]) | |
193 | + change_file = cvs_info[i] | |
194 | + # It's been reported, | |
195 | + # http://lists.badgers-in-foil.co.uk/pipermail/cvsspam-devel/2005-September/000380.html | |
196 | + # that sometimes the second revision number that CVS gives us contains a | |
197 | + # trailing newline character, so we strip ws from these values before use, | |
198 | + change_from = cvs_info[i+=1].strip | |
199 | + change_to = cvs_info[i+=1].strip | |
200 | + changes << ChangeInfo.new(change_file, change_from, change_to) | |
201 | i+=1 | |
202 | end | |
203 | return changes | |
83963645 ER |
204 | @@ -194,6 +220,8 @@ |
205 | ||
206 | changes.each do |change| | |
207 | ||
208 | + next if $ignore_file_regexes and $ignore_file_regexes.any?{|r| change.file =~ /#{r}/} | |
209 | + | |
210 | # record version information | |
211 | file.puts "#V #{change.fromVer},#{change.toVer}" | |
212 | ||
213 | @@ -202,7 +230,7 @@ | |
214 | # note if the file is on a branch | |
215 | tag = nil | |
216 | if change.isRemoval | |
217 | - tag = get_commitinfo_tag("#{$repository_path}/#{change.file}") | |
218 | + tag = get_commitinfo_tag("#{$repository_path}/#{change.file}") | |
219 | else | |
220 | status = nil | |
221 | safer_popen($cvs_prog, "-nq", "status", change.file) do |io| | |
222 | @@ -210,18 +238,19 @@ | |
223 | end | |
224 | fail "couldn't get cvs status: #{$!} (exited with #{$?})" unless ($?>>8)==0 | |
225 | ||
226 | - if status =~ /^\s*Sticky Tag:\s*(.+) \(branch: +/m | |
227 | - tag = $1 | |
228 | - end | |
229 | + if status =~ /^\s*Sticky Tag:\s*(.+) \(branch: +/m | |
230 | + tag = $1 | |
231 | + end | |
232 | ||
233 | - if status =~ /^\s*Sticky Options:\s*-kb/m | |
234 | - binary_file = true | |
235 | - end | |
236 | + if status =~ /^\s*Sticky Options:\s*-kb/m | |
237 | + binary_file = true | |
238 | + end | |
239 | end | |
240 | file.puts "#T #{tag}" unless tag.nil? | |
f34e4066 ER |
241 | |
242 | diff_cmd = Array.new << $cvs_prog << "-nq" << "diff" << "-Nu" | |
243 | diff_cmd << "-kk" if $diff_ignore_keywords | |
244 | + diff_cmd << "-b" if $diff_ignore_whitespace | |
245 | ||
246 | if change.isAddition | |
247 | file.write "#A " | |
83963645 ER |
248 | @@ -240,24 +269,24 @@ |
249 | file.puts "#{$repository_path}/#{change.file}" | |
250 | diff_cmd << change.file | |
251 | if binary_file | |
252 | - blah("not diffing #{change.file}; has -kb set") | |
253 | - # fake diff lines that will cause cvsspam.rb to consider this a binary | |
254 | - # file, | |
255 | - file.puts "#U diff x x" | |
256 | - file.puts "#U Binary files x and y differ" | |
257 | + blah("not diffing #{change.file}; has -kb set") | |
258 | + # fake diff lines that will cause cvsspam.rb to consider this a binary | |
259 | + # file, | |
260 | + file.puts "#U diff x x" | |
261 | + file.puts "#U Binary files x and y differ" | |
262 | else | |
263 | - # do a cvs diff and place the output into our temp file | |
264 | - blah("about to run #{diff_cmd.join(' ')}") | |
265 | - safer_popen(*diff_cmd) do |pipe| | |
266 | - # skip over cvs-diff's preamble | |
267 | - pipe.each do |line| | |
268 | - break if line =~ /^diff / | |
269 | - end | |
270 | - file.puts "#U #{line}" | |
271 | - pipe.each do |line| | |
272 | - file.puts "#U #{line}" | |
273 | - end | |
274 | - end | |
275 | + # do a cvs diff and place the output into our temp file | |
276 | + blah("about to run #{diff_cmd.join(' ')}") | |
277 | + safer_popen(*diff_cmd) do |pipe| | |
278 | + # skip over cvs-diff's preamble | |
279 | + pipe.each do |line| | |
280 | + break if line =~ /^diff / | |
281 | + end | |
282 | + file.puts "#U #{line}" | |
283 | + pipe.each do |line| | |
284 | + file.puts "#U #{line}" | |
285 | + end | |
286 | + end | |
287 | end | |
288 | # TODO: don't how to do this reliably on different systems... | |
289 | #fail "cvsdiff did not give exit status 1 for invocation: #{diff_cmd.join(' ')}" unless ($?>>8)==1 | |
290 | @@ -333,10 +362,13 @@ | |
f34e4066 ER |
291 | end |
292 | ||
293 | $config = nil | |
294 | +$from_address = nil | |
295 | $cvs_prog = "cvs" | |
296 | $debug = false | |
297 | $diff_ignore_keywords = false | |
298 | +$diff_ignore_whitespace = false | |
299 | $task_keywords = [] | |
83963645 | 300 | +$ignore_file_regexes = nil |
f34e4066 ER |
301 | |
302 | unless ENV.has_key?('CVSROOT') | |
83963645 ER |
303 | fail "$CVSROOT not defined. It should be when I am invoked from CVSROOT/loginfo" |
304 | @@ -387,6 +419,7 @@ | |
f34e4066 ER |
305 | end |
306 | $config = arg if opt=="--config" | |
307 | $debug = true if opt == "--debug" | |
308 | + $from_address = arg if opt == "--from" | |
309 | end | |
310 | ||
311 | blah("CVSROOT is #{ENV['CVSROOT']}") | |
83963645 ER |
312 | @@ -426,6 +459,9 @@ |
313 | class GUESS | |
314 | end | |
315 | load $config | |
316 | + if $ignore_files | |
317 | + $ignore_file_regexes = $ignore_files.split(/\s+/).map{|i| shell_mask2regex(i)} | |
318 | + end | |
319 | else | |
320 | blah("Config file '#{$config}' not found, ignoring") | |
321 | end | |
322 | @@ -447,3 +483,5 @@ | |
323 | process_log(ARGV[0]) | |
324 | end | |
325 | mailtest | |
326 | + | |
327 | +# vim:et:ts=2:sw=2 | |
efaa2289 ER |
328 | Index: record_lastdir.rb |
329 | =================================================================== | |
83963645 ER |
330 | --- record_lastdir.rb (.../tags/RELEASE-0_2_12) (revision 277) |
331 | +++ record_lastdir.rb (.../trunk) (revision 277) | |
efaa2289 ER |
332 | @@ -4,7 +4,6 @@ |
333 | # http://www.badgers-in-foil.co.uk/projects/cvsspam/ | |
334 | # Copyright (c) David Holroyd | |
335 | ||
336 | -$repositorydir = ARGV.shift | |
337 | ||
338 | $tmpdir = ENV["TMPDIR"] || "/tmp" | |
339 | ||
340 | @@ -19,6 +18,36 @@ | |
341 | nil | |
342 | end | |
343 | ||
344 | + | |
345 | +# transform any special / unexpected characters appearing in the argument to | |
346 | +# --from so that they will not cause problems if the value is inserted into | |
347 | +# a file or directory name | |
348 | +def make_fromaddr_safe_for_filename(addr) | |
349 | + addr.gsub(/[^a-zA-Z0-1.,_-]/, "_") | |
350 | +end | |
351 | + | |
352 | +# Option processing doesn't use GetoptLong (for the moment) bacause arguments | |
353 | +# given to this script by CVS include the names of committed files. It | |
354 | +# seems quite possible that one of those file names could begin with a '-' | |
355 | +# and therefore be treated by GetoptLong as a value which requires processing. | |
356 | +# This would probably result in an error. | |
357 | +# | |
358 | +# [That could be worked around by placing a '--' option (which tells GetoptLong | |
359 | +# to stop processing option arguments) at the very end of the arguments to | |
360 | +# record_lastdir.rb in commitinfo, but that's very easily forgotten, and isn't | |
361 | +# really backwards compatable with the behaviour of older CVSspam releases.] | |
362 | +if ARGV.first == "--from" | |
363 | + # we could, of course, be tricked, if the first committed file in the list | |
364 | + # happened to be named '--from' :S | |
365 | + | |
366 | + # drop the "--from" | |
367 | + ARGV.shift | |
368 | + # and use the value which was given following the option, | |
369 | + $dirtemplate << "." << make_fromaddr_safe_for_filename(ARGV.shift) | |
370 | +end | |
371 | + | |
372 | +$repositorydir = ARGV.shift | |
373 | + | |
374 | $datadir = find_data_dir() | |
375 | ||
376 | if $datadir==nil | |
83963645 ER |
377 | @@ -78,5 +107,7 @@ |
378 | # email yet. | |
379 | ||
380 | File.open("#{$datadir}/lastdir", "w") { |file| | |
381 | - file.write $repositorydir | |
382 | + file.write $repositorydir | |
383 | } | |
384 | + | |
385 | +# vim:et:ts=2:sw=2 | |
ca77e894 ER |
386 | |
387 | Property changes on: TODO | |
388 | ___________________________________________________________________ | |
389 | Deleted: svn:executable | |
390 | - * | |
391 | ||
efaa2289 ER |
392 | Index: project.xml |
393 | =================================================================== | |
d895f970 ER |
394 | Index: svn_post_commit_hook.rb |
395 | =================================================================== | |
396 | --- svn_post_commit_hook.rb (.../tags/RELEASE-0_2_12) (revision 0) | |
83963645 ER |
397 | +++ svn_post_commit_hook.rb (.../trunk) (revision 277) |
398 | @@ -0,0 +1,412 @@ | |
d895f970 ER |
399 | +#!/usr/bin/ruby -w |
400 | + | |
401 | +$svnlook_exe = "svnlook" # default assumes the program is in $PATH | |
402 | + | |
403 | +def usage(msg) | |
404 | + $stderr.puts(msg) | |
405 | + exit(1) | |
406 | +end | |
407 | + | |
408 | +def blah(msg) | |
409 | + if $debug | |
410 | + $stderr.puts "svn_post_commit_hook.rb: #{msg}" | |
411 | + end | |
412 | +end | |
413 | + | |
414 | +$debug = false | |
415 | +$tmpdir = ENV["TMPDIR"] || "/tmp" | |
416 | +$dirtemplate = "#svnspam.#{Process.getpgrp}.#{Process.uid}" | |
417 | +# arguments to pass though to 'cvsspam.rb' | |
418 | +$passthrough_args = [] | |
419 | + | |
420 | +def make_data_dir | |
421 | + dir = "#{$tmpdir}/#{$dirtemplate}-#{rand(99999999)}" | |
422 | + Dir.mkdir(dir, 0700) | |
423 | + dir | |
424 | +end | |
425 | + | |
426 | +def init | |
427 | + $datadir = make_data_dir | |
428 | + | |
429 | + # set PWD so that svnlook can create its .svnlook directory | |
430 | + Dir.chdir($datadir) | |
431 | +end | |
432 | + | |
433 | +def cleanup | |
434 | + unless $debug | |
83963645 ER |
435 | + File.unlink("#{$datadir}/logfile") |
436 | + Dir.rmdir($datadir) | |
d895f970 ER |
437 | + end |
438 | +end | |
439 | + | |
440 | +def send_email | |
441 | + cmd = File.dirname($0) + "/cvsspam.rb" | |
442 | + unless system(cmd,"--svn","#{$datadir}/logfile", *$passthrough_args) | |
443 | + fail "problem running '#{cmd}'" | |
444 | + end | |
445 | +end | |
446 | + | |
447 | +# Like IO.popen, but accepts multiple arguments like Kernel.exec | |
448 | +# (So no need to escape shell metacharacters) | |
449 | +def safer_popen(*args) | |
450 | + IO.popen("-") do |pipe| | |
451 | + if pipe==nil | |
452 | + exec(*args) | |
453 | + else | |
454 | + yield pipe | |
455 | + end | |
456 | + end | |
457 | +end | |
458 | + | |
459 | + | |
460 | +# Process the command-line arguments in the given list | |
461 | +def process_args | |
462 | + require 'getoptlong' | |
463 | + | |
464 | + opts = GetoptLong.new( | |
465 | + [ "--to", "-t", GetoptLong::REQUIRED_ARGUMENT ], | |
466 | + [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ], | |
467 | + [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], | |
468 | + [ "--from", "-u", GetoptLong::REQUIRED_ARGUMENT ], | |
469 | + [ "--charset", GetoptLong::REQUIRED_ARGUMENT ] | |
470 | + ) | |
471 | + | |
472 | + opts.each do |opt, arg| | |
473 | + if ["--to", "--config", "--from", "--charset"].include?(opt) | |
474 | + $passthrough_args << opt << arg | |
475 | + end | |
476 | + if ["--debug"].include?(opt) | |
477 | + $passthrough_args << opt | |
478 | + end | |
479 | + $config = arg if opt=="--config" | |
480 | + $debug = true if opt == "--debug" | |
481 | + end | |
482 | + | |
483 | + $repository = ARGV[0] | |
484 | + $revision = ARGV[1] | |
485 | + | |
486 | + unless $revision =~ /^\d+$/ | |
487 | + usage("revision must be an integer: #{revision.inspect}") | |
488 | + end | |
489 | + $revision = $revision.to_i | |
490 | + | |
491 | + unless FileTest.directory?($repository) | |
492 | + usage("no such directory: #{$repository.inspect}") | |
493 | + end | |
494 | +end | |
495 | + | |
496 | +# runs the given svnlook subcommand | |
497 | +def svnlook(cmd, revision, *args) | |
498 | + rev = revision.to_s | |
499 | + safer_popen($svnlook_exe, cmd, $repository, "-r", rev, *args) do |io| | |
500 | + yield io | |
501 | + end | |
502 | +end | |
503 | + | |
504 | +class Change | |
505 | + def initialize(filechange, propchange, path) | |
506 | + @filechange = filechange | |
507 | + @propchange = propchange | |
508 | + @path = path | |
509 | + end | |
510 | + | |
511 | + attr_accessor :filechange, :propchange, :path | |
512 | + | |
513 | + def property_change? | |
514 | + @propchange != " " | |
515 | + end | |
516 | + | |
517 | + def file_change? | |
518 | + @filechange != "_" | |
519 | + end | |
520 | + | |
521 | + def addition? | |
522 | + @filechange == "A" | |
523 | + end | |
524 | + | |
525 | + def deletion? | |
526 | + @filechange == "D" | |
527 | + end | |
528 | +end | |
529 | + | |
530 | + | |
531 | + | |
532 | +# Line-oriented access to an underlying IO object. Remembers 'current' line | |
533 | +# for lookahead during parsing. | |
534 | +class LineReader | |
535 | + def initialize(io) | |
536 | + @io = io | |
537 | + end | |
538 | + | |
539 | + def current | |
540 | + @line | |
541 | + end | |
542 | + | |
543 | + def next_line | |
544 | + (@line = @io.gets) != nil | |
545 | + end | |
546 | + | |
547 | + def assert_current(re) | |
548 | + raise "unexpected #{current.inspect}" unless @line =~ re | |
549 | + $~ | |
550 | + end | |
551 | + | |
552 | + def assert_next(re=nil) | |
553 | + raise "unexpected end of text" unless next_line | |
554 | + unless re.nil? | |
555 | + raise "unexpected #{current.inspect}" unless @line =~ re | |
556 | + end | |
557 | + $~ | |
558 | + end | |
559 | +end | |
560 | + | |
561 | + | |
562 | +def read_modified_diff(out, lines, path) | |
563 | + lines.assert_next(/^=+$/) | |
564 | + lines.assert_next | |
565 | + if lines.current =~ /\(Binary files differ\)/ | |
566 | + process_modified_binary_diff(out, lines, path) | |
567 | + else | |
568 | + process_modified_text_diff(out, lines, path) | |
569 | + end | |
570 | +end | |
571 | + | |
572 | + | |
573 | +def process_modified_binary_diff(out, lines, path) | |
574 | + prev_rev= $revision-1 | |
575 | + next_rev= $revision | |
576 | + out.puts "#V #{prev_rev},#{next_rev}" | |
577 | + out.puts "#M #{path}" | |
578 | + out.puts "#U diff x x" | |
579 | + out.puts "#U Binary files x and y differ" | |
580 | +end | |
581 | + | |
582 | + | |
583 | +def process_modified_text_diff(out, lines, path) | |
584 | + m = lines.assert_current(/^---.*\(rev (\d+)\)$/) | |
585 | + prev_rev = m[1].to_i | |
586 | + diff1 = lines.current | |
587 | + m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/) | |
588 | + next_rev = m[1].to_i | |
589 | + diff2 = lines.current | |
590 | + out.puts "#V #{prev_rev},#{next_rev}" | |
591 | + out.puts "#M #{path}" | |
592 | + out.puts "#U #{diff1}" | |
593 | + out.puts "#U #{diff2}" | |
594 | + while lines.next_line && lines.current =~ /^[-\+ @\\]/ | |
595 | + out.puts "#U #{lines.current}" | |
596 | + end | |
597 | +end | |
598 | + | |
599 | +def read_added_diff(out, lines, path) | |
600 | + lines.assert_next(/^=+$/) | |
601 | + lines.assert_next | |
602 | + if lines.current =~ /\(Binary files differ\)/ | |
603 | + process_added_binary_diff(out, lines, path) | |
604 | + else | |
605 | + process_added_text_diff(out, lines, path) | |
606 | + end | |
607 | +end | |
608 | + | |
609 | +def process_added_binary_diff(out, lines, path) | |
610 | + next_rev= $revision | |
611 | + out.puts "#V NONE,#{next_rev}" | |
612 | + out.puts "#A #{path}" | |
613 | + out.puts "#U diff x x" | |
614 | + out.puts "#U Binary file x added" | |
615 | +end | |
616 | + | |
617 | +def process_added_text_diff(out, lines, path) | |
618 | + m = lines.assert_current(/^---.*\(rev (\d+)\)$/) | |
619 | + prev_rev = m[1].to_i | |
620 | + diff1 = lines.current | |
621 | + m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/) | |
622 | + next_rev = m[1].to_i | |
623 | + diff2 = lines.current | |
624 | + out.puts "#V NONE,#{next_rev}" | |
625 | + out.puts "#A #{path}" | |
626 | + out.puts "#U #{diff1}" | |
627 | + out.puts "#U #{diff2}" | |
628 | + while lines.next_line && lines.current =~ /^[-\+ @\\]/ | |
629 | + out.puts "#U #{lines.current}" | |
630 | + end | |
631 | +end | |
632 | + | |
633 | +def read_deleted_diff(out, lines, path) | |
634 | + lines.assert_next(/^=+$/) | |
635 | + m = lines.assert_next(/^---.*\(rev (\d+)\)$/) | |
636 | + prev_rev = m[1].to_i | |
637 | + diff1 = lines.current | |
638 | + m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/) | |
639 | + next_rev = m[1].to_i | |
640 | + diff2 = lines.current | |
641 | + out.puts "#V #{prev_rev},NONE" | |
642 | + out.puts "#R #{path}" | |
643 | + out.puts "#U #{diff1}" | |
644 | + out.puts "#U #{diff2}" | |
645 | + while lines.next_line && lines.current =~ /^[-\+ @\\]/ | |
646 | + out.puts "#U #{lines.current}" | |
647 | + end | |
648 | +end | |
649 | + | |
650 | +def read_property_lines(path, prop_name, revision) | |
651 | + lines = [] | |
652 | + svnlook("propget", revision, prop_name, path) do |io| | |
653 | + io.each_line do |line| | |
654 | + lines << line.chomp | |
655 | + end | |
656 | + end | |
657 | + lines | |
658 | +end | |
659 | + | |
660 | +def assert_prop_match(a, b) | |
661 | + if !b.nil? && a != b | |
662 | + raise "property mismatch: #{a.inspect}!=#{b.inspect}" | |
663 | + end | |
664 | +end | |
665 | + | |
666 | +# We need to read the property change from the output of svnlook, but have | |
667 | +# a difficulty in that there's no unambiguous delimiter marking the end of | |
668 | +# a potentially multi-line property value. Therefore, we do a seperate | |
669 | +# svn propget on the given file to get the value of the property on its own, | |
670 | +# and then use that value as a guide as to how much data to read from the | |
671 | +# svnlook output. | |
672 | +def munch_prop_text(path, prop_name, revision, lines, line0) | |
673 | + prop = read_property_lines(path, prop_name, revision) | |
674 | + if prop.empty? | |
675 | + assert_prop_match(line0, "") | |
676 | + return | |
677 | + end | |
678 | + assert_prop_match(line0, prop.shift) | |
679 | + prop.each do |prop_line| | |
680 | + lines.assert_next | |
681 | + assert_prop_match(lines.current.chomp, prop_line) | |
682 | + end | |
683 | +end | |
684 | + | |
685 | +def read_properties_changed(out, lines, path) | |
686 | + prev_rev= $revision-1 | |
687 | + next_rev= $revision | |
688 | + lines.assert_next(/^_+$/) | |
689 | + return unless lines.next_line | |
690 | + out.puts "#V #{prev_rev},#{next_rev}" | |
691 | + out.puts "#P #{path}" | |
692 | +# The first three get consumed and not highlighted | |
693 | + out.puts "#U " | |
694 | + out.puts "#U Property changes:" | |
695 | + out.puts "#U " | |
696 | + | |
697 | + while true | |
698 | + break unless lines.current =~ /^(?:Name|Added|Deleted): (.+)$/ | |
699 | + | |
700 | + prop_name = $1 | |
701 | + m = lines.assert_next(/^ ([-+]) (.*)/) | |
702 | + op = m[1] | |
703 | + line0 = m[2] | |
704 | + if op == "-" | |
705 | + munch_prop_text(path, prop_name, $revision-1, lines, line0) | |
706 | + if lines.next_line && lines.current =~ /^ \+ (.*)/ | |
83963645 ER |
707 | + munch_prop_text(path, prop_name, $revision, lines, $1) |
708 | + lines.next_line | |
d895f970 ER |
709 | + end |
710 | + else # op == "+" | |
711 | + munch_prop_text(path, prop_name, $revision, lines, line0) | |
712 | + lines.next_line | |
713 | + end | |
714 | + out.puts "#U #{m[1]} #{prop_name}:#{m[2]}" | |
715 | + end | |
716 | + out.puts "#U " | |
717 | +end | |
718 | + | |
719 | +def handle_copy(out, lines, path, from_ref, from_file) | |
720 | + prev_rev= $revision-1 | |
721 | + next_rev= $revision | |
722 | + out.puts "#V #{from_file}:#{prev_rev},#{next_rev}" | |
723 | + out.puts "#C #{path}" | |
724 | + if lines.next_line && lines.current =~ /^=+$/ | |
725 | + m = lines.assert_next(/^---.*\(rev (\d+)\)$/) | |
726 | + prev_rev = m[1].to_i | |
727 | + diff1 = lines.current | |
728 | + m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/) | |
729 | + next_rev = m[1].to_i | |
730 | + diff2 = lines.current | |
731 | + out.puts "#U #{diff1}" | |
732 | + out.puts "#U #{diff2}" | |
733 | + while lines.next_line && lines.current =~ /^[-\+ @\\]/ | |
734 | + out.puts "#U #{lines.current}" | |
735 | + end | |
736 | + else | |
737 | + out.puts "#U " | |
738 | + out.puts "#U Copied from #{from_file}:#{from_ref}" | |
739 | + out.puts "#U " | |
740 | + end | |
741 | +end | |
742 | + | |
743 | +def svnlook_author | |
744 | + svnlook("author", $revision) do |io| | |
745 | + return io.readline.chomp | |
746 | + end | |
747 | + nil | |
748 | +end | |
749 | + | |
750 | +def find_author | |
751 | + return if $passthrough_args.include?("--from") | |
752 | + author = svnlook_author | |
753 | + if author | |
754 | + blah("Author from svnlook: '#{author}'") | |
755 | + $passthrough_args << "--from" << author | |
756 | + end | |
757 | +end | |
758 | + | |
759 | +def process_svnlook_log(file) | |
760 | + svnlook("log", $revision) do |io| | |
761 | + io.each_line do |line| | |
762 | + file.puts("#> #{line}") | |
763 | + end | |
764 | + end | |
765 | +end | |
766 | + | |
767 | +def process_svnlook_diff(file) | |
768 | + svnlook("diff", $revision) do |io| | |
769 | + lines = LineReader.new(io) | |
770 | + while lines.next_line | |
771 | + if lines.current =~ /^Modified:\s+(.*)/ | |
83963645 | 772 | + read_modified_diff(file, lines, $1) |
d895f970 | 773 | + elsif lines.current =~ /^Added:\s+(.*)/ |
83963645 | 774 | + read_added_diff(file, lines, $1) |
d895f970 | 775 | + elsif lines.current =~ /^Copied:\s+(.*) \(from rev (\d+), (.*)\)$/ |
83963645 | 776 | + handle_copy(file, lines, $1, $2, $3) |
d895f970 | 777 | + elsif lines.current =~ /^Deleted:\s+(.*)/ |
83963645 | 778 | + read_deleted_diff(file, lines, $1) |
d895f970 | 779 | + elsif lines.current =~ /^Property changes on:\s+(.*)/ |
83963645 | 780 | + read_properties_changed(file, lines, $1) |
d895f970 | 781 | + elsif lines.current == "\n" |
83963645 | 782 | + # ignore |
d895f970 | 783 | + else |
83963645 | 784 | + raise "unable to parse line '#{lines.current.inspect}'" |
d895f970 ER |
785 | + end |
786 | + end | |
787 | + end | |
788 | +end | |
789 | + | |
790 | +def process_commit() | |
791 | + File.open("#{$datadir}/logfile", File::WRONLY|File::CREAT) do |file| | |
792 | + process_svnlook_log(file) | |
793 | + process_svnlook_diff(file) | |
794 | + end | |
795 | +end | |
796 | + | |
797 | + | |
798 | +def main | |
799 | + init() | |
800 | + process_args() | |
801 | + find_author() | |
802 | + process_commit() | |
803 | + send_email() | |
804 | + cleanup() | |
805 | +end | |
806 | + | |
807 | + | |
808 | +main | |
83963645 ER |
809 | + |
810 | +# vim:et:ts=2:sw=2 | |
d895f970 ER |
811 | |
812 | Property changes on: svn_post_commit_hook.rb | |
813 | ___________________________________________________________________ | |
814 | Added: svn:mergeinfo | |
815 | Added: svn:executable | |
816 | + * | |
817 | ||
ca77e894 ER |
818 | |
819 | Property changes on: COPYING | |
820 | ___________________________________________________________________ | |
821 | Deleted: svn:executable | |
822 | - * | |
823 | ||
efaa2289 ER |
824 | Index: CREDITS |
825 | =================================================================== | |
83963645 ER |
826 | --- CREDITS (.../tags/RELEASE-0_2_12) (revision 277) |
827 | +++ CREDITS (.../trunk) (revision 277) | |
efaa2289 ER |
828 | @@ -29,3 +29,10 @@ |
829 |