]> git.pld-linux.org Git - packages/cvsspam.git/blame - cvsspam-branch.diff
- old patch recovered (2009-04-23)
[packages/cvsspam.git] / cvsspam-branch.diff
CommitLineData
efaa2289
ER
1Index: 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
104Property changes on: cvsspam.conf
105___________________________________________________________________
106Deleted: svn:executable
107 - *
d895f970
ER
108Modified: svn:keywords
109 - Author Date Id Revision
110 + Author Date Id
ca77e894 111
efaa2289
ER
112Index: 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
189Index: 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
239Property changes on: TODO
240___________________________________________________________________
241Deleted: svn:executable
242 - *
243
efaa2289
ER
244Index: project.xml
245===================================================================
d895f970
ER
246Index: 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
662Property changes on: svn_post_commit_hook.rb
663___________________________________________________________________
664Added: svn:mergeinfo
665Added: svn:executable
666 + *
667
ca77e894
ER
668
669Property changes on: COPYING
670___________________________________________________________________
671Deleted: svn:executable
672 - *
673
efaa2289
ER
674Index: 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