]> git.pld-linux.org Git - packages/cvsspam.git/blame - cvsspam-svnspam-branch.diff
- up to r269
[packages/cvsspam.git] / cvsspam-svnspam-branch.diff
CommitLineData
9c3cf735 1--- svn_post_commit_hook.rb (.../trunk) (revision 0)
ca77e894
ER
2+++ svn_post_commit_hook.rb (.../branches/svn_support) (revision 269)
3@@ -0,0 +1,412 @@
9c3cf735
ER
4+#!/usr/bin/ruby -w
5+
6+$svnlook_exe = "svnlook" # default assumes the program is in $PATH
7+
8+def usage(msg)
9+ $stderr.puts(msg)
10+ exit(1)
11+end
12+
13+def blah(msg)
14+ if $debug
15+ $stderr.puts "svn_post_commit_hook.rb: #{msg}"
16+ end
17+end
18+
ca77e894 19+$debug = false
9c3cf735
ER
20+$tmpdir = ENV["TMPDIR"] || "/tmp"
21+$dirtemplate = "#svnspam.#{Process.getpgrp}.#{Process.uid}"
22+# arguments to pass though to 'cvsspam.rb'
23+$passthrough_args = []
24+
25+def make_data_dir
26+ dir = "#{$tmpdir}/#{$dirtemplate}-#{rand(99999999)}"
27+ Dir.mkdir(dir, 0700)
28+ dir
29+end
30+
31+def init
32+ $datadir = make_data_dir
33+
34+ # set PWD so that svnlook can create its .svnlook directory
35+ Dir.chdir($datadir)
36+end
37+
38+def cleanup
39+ unless $debug
40+ File.unlink("#{$datadir}/logfile")
41+ Dir.rmdir($datadir)
42+ end
43+end
44+
45+def send_email
46+ cmd = File.dirname($0) + "/cvsspam.rb"
47+ unless system(cmd,"--svn","#{$datadir}/logfile", *$passthrough_args)
48+ fail "problem running '#{cmd}'"
49+ end
50+end
51+
52+# Like IO.popen, but accepts multiple arguments like Kernel.exec
53+# (So no need to escape shell metacharacters)
54+def safer_popen(*args)
55+ IO.popen("-") do |pipe|
56+ if pipe==nil
57+ exec(*args)
58+ else
59+ yield pipe
60+ end
61+ end
62+end
63+
64+
65+# Process the command-line arguments in the given list
66+def process_args
67+ require 'getoptlong'
68+
69+ opts = GetoptLong.new(
70+ [ "--to", "-t", GetoptLong::REQUIRED_ARGUMENT ],
71+ [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
72+ [ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
73+ [ "--from", "-u", GetoptLong::REQUIRED_ARGUMENT ],
74+ [ "--charset", GetoptLong::REQUIRED_ARGUMENT ]
75+ )
76+
77+ opts.each do |opt, arg|
78+ if ["--to", "--config", "--from", "--charset"].include?(opt)
79+ $passthrough_args << opt << arg
80+ end
81+ if ["--debug"].include?(opt)
82+ $passthrough_args << opt
83+ end
84+ $config = arg if opt=="--config"
85+ $debug = true if opt == "--debug"
86+ end
87+
88+ $repository = ARGV[0]
89+ $revision = ARGV[1]
90+
91+ unless $revision =~ /^\d+$/
92+ usage("revision must be an integer: #{revision.inspect}")
93+ end
94+ $revision = $revision.to_i
95+
96+ unless FileTest.directory?($repository)
97+ usage("no such directory: #{$repository.inspect}")
98+ end
99+ $repository =~ /([^\/]+$)/
100+ $shortrepo = $1
101+end
102+
103+# runs the given svnlook subcommand
104+def svnlook(cmd, revision, *args)
105+ rev = revision.to_s
106+ safer_popen($svnlook_exe, cmd, $repository, "-r", rev, *args) do |io|
107+ yield io
108+ end
109+end
110+
111+class Change
112+ def initialize(filechange, propchange, path)
113+ @filechange = filechange
114+ @propchange = propchange
115+ @path = path
116+ end
117+
118+ attr_accessor :filechange, :propchange, :path
119+
120+ def property_change?
121+ @propchange != " "
122+ end
123+
124+ def file_change?
125+ @filechange != "_"
126+ end
127+
128+ def addition?
129+ @filechange == "A"
130+ end
131+
132+ def deletion?
133+ @filechange == "D"
134+ end
135+end
136+
137+
138+
139+# Line-oriented access to an underlying IO object. Remembers 'current' line
140+# for lookahead during parsing.
141+class LineReader
142+ def initialize(io)
143+ @io = io
144+ end
145+
146+ def current
147+ @line
148+ end
149+
150+ def next_line
151+ (@line = @io.gets) != nil
152+ end
153+
154+ def assert_current(re)
155+ raise "unexpected #{current.inspect}" unless @line =~ re
156+ $~
157+ end
158+
159+ def assert_next(re=nil)
160+ raise "unexpected end of text" unless next_line
161+ unless re.nil?
162+ raise "unexpected #{current.inspect}" unless @line =~ re
163+ end
164+ $~
165+ end
166+end
167+
168+
169+def read_modified_diff(out, lines, path)
170+ lines.assert_next(/^=+$/)
171+ lines.assert_next
172+ if lines.current =~ /\(Binary files differ\)/
173+ process_modified_binary_diff(out, lines, path)
174+ else
175+ process_modified_text_diff(out, lines, path)
176+ end
177+end
178+
179+
180+def process_modified_binary_diff(out, lines, path)
181+ prev_rev= $revision-1
182+ next_rev= $revision
183+ out.puts "#V #{prev_rev},#{next_rev}"
184+ out.puts "#M #{$shortrepo}/#{path}"
185+ out.puts "#U diff x x"
186+ out.puts "#U Binary files x and y differ"
187+end
188+
189+
190+def process_modified_text_diff(out, lines, path)
191+ m = lines.assert_current(/^---.*\(rev (\d+)\)$/)
192+ prev_rev = m[1].to_i
193+ diff1 = lines.current
194+ m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/)
195+ next_rev = m[1].to_i
196+ diff2 = lines.current
197+ out.puts "#V #{prev_rev},#{next_rev}"
198+ out.puts "#M #{$shortrepo}/#{path}"
199+ out.puts "#U #{diff1}"
200+ out.puts "#U #{diff2}"
201+ while lines.next_line && lines.current =~ /^[-\+ @\\]/
202+ out.puts "#U #{lines.current}"
203+ end
204+end
205+
206+def read_added_diff(out, lines, path)
207+ lines.assert_next(/^=+$/)
208+ lines.assert_next
209+ if lines.current =~ /\(Binary files differ\)/
210+ process_added_binary_diff(out, lines, path)
211+ else
212+ process_added_text_diff(out, lines, path)
213+ end
214+end
215+
216+def process_added_binary_diff(out, lines, path)
217+ next_rev= $revision
218+ out.puts "#V NONE,#{next_rev}"
219+ out.puts "#A #{$shortrepo}/#{path}"
220+ out.puts "#U diff x x"
221+ out.puts "#U Binary file x added"
222+end
223+
224+def process_added_text_diff(out, lines, path)
225+ m = lines.assert_current(/^---.*\(rev (\d+)\)$/)
226+ prev_rev = m[1].to_i
227+ diff1 = lines.current
228+ m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/)
229+ next_rev = m[1].to_i
230+ diff2 = lines.current
231+ out.puts "#V NONE,#{next_rev}"
232+ out.puts "#A #{$shortrepo}/#{path}"
233+ out.puts "#U #{diff1}"
234+ out.puts "#U #{diff2}"
235+ while lines.next_line && lines.current =~ /^[-\+ @\\]/
236+ out.puts "#U #{lines.current}"
237+ end
238+end
239+
240+def read_deleted_diff(out, lines, path)
241+ lines.assert_next(/^=+$/)
242+ m = lines.assert_next(/^---.*\(rev (\d+)\)$/)
243+ prev_rev = m[1].to_i
244+ diff1 = lines.current
245+ m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/)
246+ next_rev = m[1].to_i
247+ diff2 = lines.current
248+ out.puts "#V #{prev_rev},NONE"
249+ out.puts "#R #{$shortrepo}/#{path}"
250+ out.puts "#U #{diff1}"
251+ out.puts "#U #{diff2}"
252+ while lines.next_line && lines.current =~ /^[-\+ @\\]/
253+ out.puts "#U #{lines.current}"
254+ end
255+end
256+
257+def read_property_lines(path, prop_name, revision)
258+ lines = []
259+ svnlook("propget", revision, prop_name, path) do |io|
260+ io.each_line do |line|
261+ lines << line.chomp
262+ end
263+ end
264+ lines
265+end
266+
267+def assert_prop_match(a, b)
268+ if !b.nil? && a != b
269+ raise "property mismatch: #{a.inspect}!=#{b.inspect}"
270+ end
271+end
272+
273+# We need to read the property change from the output of svnlook, but have
274+# a difficulty in that there's no unambiguous delimiter marking the end of
275+# a potentially multi-line property value. Therefore, we do a seperate
276+# svn propget on the given file to get the value of the property on its own,
277+# and then use that value as a guide as to how much data to read from the
278+# svnlook output.
279+def munch_prop_text(path, prop_name, revision, lines, line0)
280+ prop = read_property_lines(path, prop_name, revision)
281+ if prop.empty?
282+ assert_prop_match(line0, "")
283+ return
284+ end
285+ assert_prop_match(line0, prop.shift)
286+ prop.each do |prop_line|
287+ lines.assert_next
288+ assert_prop_match(lines.current.chomp, prop_line)
289+ end
290+end
291+
292+def read_properties_changed(out, lines, path)
293+ prev_rev= $revision-1
294+ next_rev= $revision
295+ lines.assert_next(/^_+$/)
296+ return unless lines.next_line
297+ out.puts "#V #{prev_rev},#{next_rev}"
298+ out.puts "#P #{$shortrepo}/#{path}"
299+# The first three get consumed and not highlighted
300+ out.puts "#U "
301+ out.puts "#U Property changes:"
302+ out.puts "#U "
ca77e894 303+
9c3cf735 304+ while true
ca77e894
ER
305+ break unless lines.current =~ /^(?:Name|Added|Deleted): (.+)$/
306+
9c3cf735
ER
307+ prop_name = $1
308+ m = lines.assert_next(/^ ([-+]) (.*)/)
309+ op = m[1]
310+ line0 = m[2]
311+ if op == "-"
312+ munch_prop_text(path, prop_name, $revision-1, lines, line0)
313+ if lines.next_line && lines.current =~ /^ \+ (.*)/
314+ munch_prop_text(path, prop_name, $revision, lines, $1)
315+ lines.next_line
316+ end
317+ else # op == "+"
318+ munch_prop_text(path, prop_name, $revision, lines, line0)
319+ lines.next_line
320+ end
321+ out.puts "#U #{m[1]} #{prop_name}:#{m[2]}"
322+ end
323+ out.puts "#U "
324+end
325+
326+def handle_copy(out, lines, path, from_ref, from_file)
327+ prev_rev= $revision-1
328+ next_rev= $revision
329+ out.puts "#V #{$shortrepo}/#{from_file}:#{prev_rev},#{next_rev}"
330+ out.puts "#C #{$shortrepo}/#{path}"
331+ if lines.next_line && lines.current =~ /^=+$/
332+ m = lines.assert_next(/^---.*\(rev (\d+)\)$/)
333+ prev_rev = m[1].to_i
334+ diff1 = lines.current
335+ m = lines.assert_next(/^\+\+\+.*\(rev (\d+)\)$/)
336+ next_rev = m[1].to_i
337+ diff2 = lines.current
338+ out.puts "#U #{diff1}"
339+ out.puts "#U #{diff2}"
340+ while lines.next_line && lines.current =~ /^[-\+ @\\]/
341+ out.puts "#U #{lines.current}"
342+ end
343+ else
344+ out.puts "#U "
345+ out.puts "#U Copied from #{$shortrepo}/#{from_file}:#{from_ref}"
346+ out.puts "#U "
347+ end
348+end
349+
350+def svnlook_author
351+ svnlook("author", $revision) do |io|
352+ return io.readline.chomp
353+ end
354+ nil
355+end
356+
357+def find_author
358+ return if $passthrough_args.include?("--from")
359+ author = svnlook_author
360+ if author
361+ blah("Author from svnlook: '#{author}'")
362+ $passthrough_args << "--from" << author
363+ end
364+end
365+
366+def process_svnlook_log(file)
367+ svnlook("log", $revision) do |io|
368+ io.each_line do |line|
369+ file.puts("#> #{line}")
370+ end
371+ end
372+end
373+
374+def process_svnlook_diff(file)
375+ svnlook("diff", $revision) do |io|
376+ lines = LineReader.new(io)
377+ while lines.next_line
378+ if lines.current =~ /^Modified:\s+(.*)/
379+ read_modified_diff(file, lines, $1)
380+ elsif lines.current =~ /^Added:\s+(.*)/
381+ read_added_diff(file, lines, $1)
382+ elsif lines.current =~ /^Copied:\s+(.*) \(from rev (\d+), (.*)\)$/
383+ handle_copy(file, lines, $1, $2, $3)
384+ elsif lines.current =~ /^Deleted:\s+(.*)/
385+ read_deleted_diff(file, lines, $1)
386+ elsif lines.current =~ /^Property changes on:\s+(.*)/
387+ read_properties_changed(file, lines, $1)
388+ elsif lines.current == "\n"
389+ # ignore
390+ else
ca77e894 391+ raise "unable to parse line '#{lines.current.inspect}'"
9c3cf735
ER
392+ end
393+ end
394+ end
395+end
396+
397+def process_commit()
398+ File.open("#{$datadir}/logfile", File::WRONLY|File::CREAT) do |file|
399+ process_svnlook_log(file)
400+ process_svnlook_diff(file)
401+ end
402+end
403+
404+
405+def main
406+ init()
407+ process_args()
408+ find_author()
409+ process_commit()
410+ send_email()
411+ cleanup()
412+end
413+
414+
415+main
ca77e894
ER
416--- cvsspam.rb (.../trunk) (revision 269)
417+++ cvsspam.rb (.../branches/svn_support) (revision 269)
9c3cf735 418@@ -398,7 +398,7 @@
3eeef56f
ER
419
420 # the full path and filename within the repository
421 attr_accessor :path
422- # the type of change committed 'M'=modified, 'A'=added, 'R'=removed
423+ # the type of change committed 'M'=modified, 'A'=added, 'R'=removed, 'P'=properties, 'C'=copied
424 attr_accessor :type
425 # records number of 'addition' lines in diff output, once counted
426 attr_accessor :lineAdditions
9c3cf735 427@@ -453,17 +453,28 @@
3eeef56f
ER
428 def removal?
429 @type == "R"
430 end
431-
432+
433 # was this file added during the commit?
434 def addition?
435 @type == "A"
436 end
437
438+ # was this file copied during the commit?
439+ def copied?
440+ @type == "C"
441+ end
442+
443 # was this file simply modified during the commit?
444 def modification?
445 @type == "M"
446 end
447+
448+ # was this file simply modified during the commit?
449+ def modifiedprops?
450+ @type == "P"
451+ end
3eeef56f 452
9c3cf735 453+
3eeef56f
ER
454 # passing true, this object remembers that a diff will appear in the email,
455 # passing false, this object remembers that no diff will appear in the email.
9c3cf735
ER
456 # Once the value is set, it will not be changed
457@@ -889,6 +900,15 @@
3eeef56f
ER
458 end
459 end
460
461+# Note when LogReader finds record of a file that was copied in this commit
462+class CopiedFileHandler < FileHandler
463+ def handleFile(file)
464+ file.type="C"
465+ file.fromVer=$fromVer
466+ file.toVer=$toVer
467+ end
468+end
469+
470 # Note when LogReader finds record of a file that was modified in this commit
471 class ModifiedFileHandler < FileHandler
472 def handleFile(file)
9c3cf735 473@@ -898,7 +918,16 @@
3eeef56f
ER
474 end
475 end
476
477+# Note when LogReader finds record of a file whose properties were modified in this commit
478+class ModifiedPropsFileHandler < FileHandler
479+ def handleFile(file)
480+ file.type="P"
481+ file.fromVer=$fromVer
482+ file.toVer=$toVer
483+ end
484+end
3eeef56f 485
9c3cf735 486+
3eeef56f
ER
487 # Used by UnifiedDiffHandler to record the number of added and removed lines
488 # appearing in a unidiff.
9c3cf735
ER
489 class UnifiedDiffStats
490@@ -1064,11 +1093,21 @@
3eeef56f
ER
491 print($frontend.path($file.basedir, $file.tag))
492 println("</span><br />")
493 println("<div class=\"fileheader\" id=\"removed\"><big><b>#{htmlEncode($file.file)}</b></big> <small id=\"info\">removed after #{$frontend.version($file.path,$file.fromVer)}</small></div>")
494+ when "C"
495+ print("<span class=\"pathname\" id=\"copied\">")
496+ print($frontend.path($file.basedir, $file.tag))
497+ println("</span><br />")
498+ println("<div class=\"fileheader\" id=\"copied\"><big><b>#{htmlEncode($file.file)}</b></big> <small id=\"info\">copied from #{$frontend.version($file.path,$file.fromVer)}</small></div>")
499 when "M"
500 print("<span class=\"pathname\">")
501 print($frontend.path($file.basedir, $file.tag))
502 println("</span><br />")
503 println("<div class=\"fileheader\"><big><b>#{htmlEncode($file.file)}</b></big> <small id=\"info\">#{$frontend.version($file.path,$file.fromVer)} #{$frontend.diff($file)} #{$frontend.version($file.path,$file.toVer)}</small></div>")
504+ when "P"
505+ print("<span class=\"pathname\">")
506+ print($frontend.path($file.basedir, $file.tag))
507+ println("</span><br />")
508+ println("<div class=\"fileheader\"><big><b>#{htmlEncode($file.file)}</b></big> <small id=\"info\">#{$frontend.version($file.path,$file.fromVer)} #{$frontend.diff($file)} #{$frontend.version($file.path,$file.toVer)}</small></div>")
509 end
510 print("<pre class=\"diff\"><small id=\"info\">")
511 lines.each do |line|
9c3cf735
ER
512@@ -1329,6 +1368,7 @@
513 $users_file_charset = nil
3eeef56f
ER
514
515 $debug = false
516+$svn = false
517 $recipients = Array.new
518 $sendmail_prog = "/usr/sbin/sendmail"
9c3cf735
ER
519 $hostname = ENV['HOSTNAME'] || 'localhost'
520@@ -1366,6 +1406,7 @@
3eeef56f
ER
521 [ "--to", "-t", GetoptLong::REQUIRED_ARGUMENT ],
522 [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ],
523 [ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
524+ [ "--svn", "-s", GetoptLong::NO_ARGUMENT ],
525 [ "--from", "-u", GetoptLong::REQUIRED_ARGUMENT ],
526 [ "--charset", GetoptLong::REQUIRED_ARGUMENT ]
527 )
9c3cf735 528@@ -1374,6 +1415,7 @@
3eeef56f
ER
529 $recipients << EmailAddress.new(arg) if opt=="--to"
530 $config = arg if opt=="--config"
531 $debug = true if opt=="--debug"
532+ $svn = true if opt=="--svn"
533 $from_address = EmailAddress.new(arg) if opt=="--from"
534 # must use different variable as the config is readed later.
535 $arg_charset = arg if opt == "--charset"
9c3cf735 536@@ -1386,7 +1428,7 @@
3eeef56f
ER
537 else
538 $stderr.puts "missing required file argument"
539 end
540- puts "Usage: cvsspam.rb [ --to <email> ] [ --config <file> ] <collect_diffs file>"
541+ puts "Usage: cvsspam.rb [ --svn ] [ --to <email> ] [ --config <file> ] <collect_diffs file>"
542 exit(-1)
543 end
544
9c3cf735 545@@ -1495,12 +1537,16 @@
3eeef56f
ER
546 "T" => tagHandler,
547 "A" => AddedFileHandler.new,
548 "R" => RemovedFileHandler.new,
549+ "C" => CopiedFileHandler.new,
550 "M" => ModifiedFileHandler.new,
551+ "P" => ModifiedPropsFileHandler.new,
552 "V" => VersionHandler.new]
553
554 $handlers["A"].setTagHandler(tagHandler)
555 $handlers["R"].setTagHandler(tagHandler)
556+$handlers["C"].setTagHandler(tagHandler)
557 $handlers["M"].setTagHandler(tagHandler)
558+$handlers["P"].setTagHandler(tagHandler)
559
560 $fileEntries = Array.new
561 $task_list = Array.new
9c3cf735 562@@ -1525,7 +1571,11 @@
3eeef56f
ER
563 end
564
565 if $subjectPrefix == nil
9c3cf735 566- $subjectPrefix = "[CVS #{Repository.array.join(',')}]"
3eeef56f
ER
567+ if $svn
568+ $subjectPrefix = "[SVN #{Repository.array.join(',')}]"
569+ else
570+ $subjectPrefix = "[CVS #{Repository.array.join(',')}]"
571+ end
572 end
573
574 if $files_in_subject
9c3cf735 575@@ -1572,6 +1622,8 @@
3eeef56f
ER
576 #removed {background-color:#ffdddd;}
577 #removedchars {background-color:#ff9999;font-weight:bolder;}
578 tr.alt #removed {background-color:#f7cccc;}
579+ #copied {background-color:#ccccff;}
580+ tr.alt #copied {background-color:#bbbbf7;}
581 #info {color:#888888;}
582 #context {background-color:#eeeeee;}
583 td {padding-left:.3em;padding-right:.3em;}
9c3cf735 584@@ -1604,7 +1656,9 @@
3eeef56f
ER
585
586 filesAdded = 0
587 filesRemoved = 0
588+ filesCopied = 0
589 filesModified = 0
590+ filesModifiedProps = 0
591 totalLinesAdded = 0
592 totalLinesRemoved = 0
593 file_count = 0
9c3cf735 594@@ -1613,24 +1667,26 @@
3eeef56f
ER
595 $fileEntries.each do |file|
596 unless file.repository == last_repository
597 last_repository = file.repository
598- mail.print("<tr class=\"head\"><td colspan=\"#{last_repository.has_multiple_tags ? 5 : 4}\">")
599+ mail.print("<tr class=\"head\"><td colspan=\"#{last_repository.has_multiple_tags ? 6 : 5}\">")
600 if last_repository.has_multiple_tags
601 mail.print("Mixed-tag commit")
602 else
603 mail.print("Commit")
604 end
605 mail.print(" in <b><tt>#{htmlEncode(last_repository.common_prefix)}</tt></b>")
606- if last_repository.trunk_only?
607- mail.print("<span id=\"info\"> on MAIN</span>")
608- else
609- mail.print(" on ")
610- tagCount = 0
611- last_repository.each_tag do |tag|
612- tagCount += 1
613- if tagCount > 1
614- mail.print tagCount<last_repository.tag_count ? ", " : " &amp; "
615+ if !$svn
616+ if last_repository.trunk_only?
617+ mail.print("<span id=\"info\"> on MAIN</span>")
618+ else
619+ mail.print(" on ")
620+ tagCount = 0
621+ last_repository.each_tag do |tag|
622+ tagCount += 1
623+ if tagCount > 1
624+ mail.print tagCount<last_repository.tag_count ? ", " : " &amp; "
625+ end
626+ mail.print tag ? htmlEncode(tag) : "<span id=\"info\">MAIN</span>"
627 end
628- mail.print tag ? htmlEncode(tag) : "<span id=\"info\">MAIN</span>"
629 end
630 end
631 mail.puts("</td></tr>")
9c3cf735 632@@ -1645,8 +1701,12 @@
3eeef56f
ER
633 filesAdded += 1
634 elsif file.removal?
635 filesRemoved += 1
636+ elsif file.copied?
637+ filesCopied += 1
638 elsif file.modification?
639 filesModified += 1
640+ elsif file.modifiedprops?
641+ filesModifiedProps += 1
642 end
643 name = htmlEncode(file.name_after_common_prefix)
644 slashPos = name.rindex("/")
9c3cf735 645@@ -1666,6 +1726,8 @@
3eeef56f
ER
646 name = "<span id=\"added\">#{name}</span>"
647 elsif file.removal?
648 name = "<span id=\"removed\">#{name}</span>"
649+ elsif file.copied?
650+ name = "<span id=\"copied\">#{name}</span>"
651 end
9c3cf735 652 mail.print("<td>")
3eeef56f 653 if file.has_diff?
9c3cf735 654@@ -1675,11 +1737,18 @@
3eeef56f 655 end
9c3cf735
ER
656 mail.print(" #{$frontend.log(file)}")
657 mail.print("</td>")
3eeef56f
ER
658- if file.isEmpty
659- mail.print("<td colspan=\"2\" align=\"center\"><small id=\"info\">[empty]</small></td>")
3eeef56f
ER
660+ if file.copied?
661+ mail.print("<td colspan=\"3\" align=\"center\"><small id=\"info\">[copied]</small></td>")
662+ elsif file.isEmpty
663+ mail.print("<td colspan=\"3\" align=\"center\"><small id=\"info\">[empty]</small></td>")
664 elsif file.isBinary
665- mail.print("<td colspan=\"2\" align=\"center\"><small id=\"info\">[binary]</small></td>")
666+ mail.print("<td colspan=\"3\" align=\"center\"><small id=\"info\">[binary]</small></td>")
667 else
668+ if file.modifiedprops?
669+ mail.print("<td align=\"right\"><small id=\"info\">[props]</small></td>")
670+ else
671+ mail.print("<td></td>")
672+ end
673 if file.lineAdditions>0
674 totalLinesAdded += file.lineAdditions
675 mail.print("<td align=\"right\" id=\"added\">+#{file.lineAdditions}</td>")
9c3cf735 676@@ -1706,15 +1775,19 @@
3eeef56f
ER
677 mail.print("<td nowrap=\"nowrap\" align=\"right\">added #{$frontend.version(file.path,file.toVer)}</td>")
678 elsif file.removal?
679 mail.print("<td nowrap=\"nowrap\">#{$frontend.version(file.path,file.fromVer)} removed</td>")
680+ elsif file.copied?
681+ mail.print("<td nowrap=\"nowrap\" align=\"center\">#{$frontend.version(file.path,file.fromVer)} #{$frontend.diff(file)} #{$frontend.version(file.path,file.toVer)}</td>")
682 elsif file.modification?
683 mail.print("<td nowrap=\"nowrap\" align=\"center\">#{$frontend.version(file.path,file.fromVer)} #{$frontend.diff(file)} #{$frontend.version(file.path,file.toVer)}</td>")
684+ elsif file.modifiedprops?
685+ mail.print("<td nowrap=\"nowrap\" align=\"center\">#{$frontend.version(file.path,file.fromVer)} #{$frontend.diff(file)} #{$frontend.version(file.path,file.toVer)}</td>")
686 end
687
688 mail.puts("</tr>")
689 end
690 if $fileEntries.size>1 && (totalLinesAdded+totalLinesRemoved)>0
691 # give total number of lines added/removed accross all files
692- mail.print("<tr><td></td>")
693+ mail.print("<tr><td></td><td></td>")
694 if totalLinesAdded>0
695 mail.print("<td align=\"right\" id=\"added\">+#{totalLinesAdded}</td>")
696 else
9c3cf735 697@@ -1731,7 +1804,7 @@
3eeef56f
ER
698
699 mail.puts("</table>")
700
701- totalFilesChanged = filesAdded+filesRemoved+filesModified
702+ totalFilesChanged = filesAdded+filesRemoved+filesCopied+filesModified+filesModifiedProps
703 if totalFilesChanged > 1
704 mail.print("<small id=\"info\">")
705 changeKind = 0
9c3cf735 706@@ -1744,11 +1817,21 @@
3eeef56f
ER
707 mail.print("#{filesRemoved} removed")
708 changeKind += 1
709 end
710+ if filesCopied>0
711+ mail.print(" + ") if changeKind>0
712+ mail.print("#{filesCopied} copied")
713+ changeKind += 1
714+ end
715 if filesModified>0
716 mail.print(" + ") if changeKind>0
717 mail.print("#{filesModified} modified")
718 changeKind += 1
719 end
720+ if filesModifiedProps>0
721+ mail.print(" + ") if changeKind>0
722+ mail.print("#{filesModifiedProps} modified properties")
723+ changeKind += 1
724+ end
725 mail.print(", total #{totalFilesChanged}") if changeKind > 1
726 mail.puts(" files</small><br />")
727 end
This page took 0.177028 seconds and 4 git commands to generate.