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