blib/lib/SVN/Notify/HTML/ColorDiff.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 82 | 83 | 98.8 |
branch | 44 | 48 | 91.6 |
condition | 6 | 6 | 100.0 |
subroutine | 5 | 5 | 100.0 |
pod | 1 | 1 | 100.0 |
total | 138 | 143 | 96.5 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package SVN::Notify::HTML::ColorDiff; | ||||||
2 | |||||||
3 | 134 | 134 | 546544 | use strict; | |||
134 | 477 | ||||||
134 | 4779 | ||||||
4 | 134 | 134 | 932 | use HTML::Entities; | |||
134 | 337 | ||||||
134 | 9486 | ||||||
5 | 134 | 134 | 28566 | use SVN::Notify::HTML (); | |||
134 | 401 | ||||||
134 | 175110 | ||||||
6 | |||||||
7 | $SVN::Notify::HTML::ColorDiff::VERSION = '2.87'; | ||||||
8 | @SVN::Notify::HTML::ColorDiff::ISA = qw(SVN::Notify::HTML); | ||||||
9 | |||||||
10 | =head1 Name | ||||||
11 | |||||||
12 | SVN::Notify::HTML::ColorDiff - Subversion activity HTML notification with colorized diff | ||||||
13 | |||||||
14 | =head1 Synopsis | ||||||
15 | |||||||
16 | Use F |
||||||
17 | |||||||
18 | svnnotify --repos-path "$1" --revision "$2" \ | ||||||
19 | --to developers@example.com --handler HTML::ColorDiff [options] | ||||||
20 | |||||||
21 | Use the class in a custom script: | ||||||
22 | |||||||
23 | use SVN::Notify::HTML::ColorDiff; | ||||||
24 | |||||||
25 | my $notifier = SVN::Notify::HTML::ColorDiff->new(%params); | ||||||
26 | $notifier->prepare; | ||||||
27 | $notifier->execute; | ||||||
28 | |||||||
29 | =head1 Description | ||||||
30 | |||||||
31 | This subclass of L |
||||||
32 | email messages for Subversion activity, and if the C |
||||||
33 | specified (but not C |
||||||
34 | diff will be included, rather than the plain text diff output by | ||||||
35 | SVN::Notify::HTML. | ||||||
36 | |||||||
37 | =head1 Usage | ||||||
38 | |||||||
39 | To use SVN::Notify::HTML::ColorDiff, simply follow the | ||||||
40 | L |
||||||
41 | specify C<--handler HTML::ColorDiff>. | ||||||
42 | |||||||
43 | =cut | ||||||
44 | |||||||
45 | ############################################################################## | ||||||
46 | |||||||
47 | =head1 Instance Interface | ||||||
48 | |||||||
49 | =head2 Instance Methods | ||||||
50 | |||||||
51 | =head3 output_css | ||||||
52 | |||||||
53 | $notifier->output_css($file_handle); | ||||||
54 | |||||||
55 | This method starts outputs the CSS for the HTML message. | ||||||
56 | SVN::Notify::HTML::ColorDiff adds extra CSS to its output so that it can | ||||||
57 | nicely style the diff. | ||||||
58 | |||||||
59 | =cut | ||||||
60 | |||||||
61 | # We use _css() so that ColorDiff can override it and the filters then applied | ||||||
62 | # only one to all of the CSS. | ||||||
63 | |||||||
64 | ############################################################################## | ||||||
65 | |||||||
66 | =head3 output_diff | ||||||
67 | |||||||
68 | $notifier->output_diff($out_file_handle, $diff_file_handle); | ||||||
69 | |||||||
70 | Reads the diff data from C<$diff_file_handle> and prints it to | ||||||
71 | C<$out_file_handle> for inclusion in the notification message. The diff is | ||||||
72 | output with nice colorized HTML markup. Each line of the diff file is escaped | ||||||
73 | by C |
||||||
74 | |||||||
75 | If there are any C |
||||||
76 | redispatch to L |
||||||
77 | L |
||||||
78 | filters. | ||||||
79 | |||||||
80 | =cut | ||||||
81 | |||||||
82 | my %types = ( | ||||||
83 | Modified => 'modfile', | ||||||
84 | Added => 'addfile', | ||||||
85 | Deleted => 'delfile', | ||||||
86 | Copied => 'copfile', | ||||||
87 | ); | ||||||
88 | |||||||
89 | sub output_diff { | ||||||
90 | 145 | 145 | 1 | 3817 | my ($self, $out, $diff) = @_; | ||
91 | 145 | 100 | 2477 | if ( $self->filters_for('diff') ) { | |||
92 | 14 | 1218 | return $self->SUPER::output_diff($out, $diff); | ||||
93 | } | ||||||
94 | 131 | 50 | 3067 | $self->_dbpnt( "Outputting colorized HTML diff") if $self->verbose > 1; | |||
95 | |||||||
96 | 131 | 358 | my $in_div; | ||||
97 | 131 | 1380 | my $in_span = ''; | ||||
98 | 131 | 2095 | print $out qq{\n \n Diff\n}; |
||||
99 | 131 | 629 | my ($length, %seen) = 0; | ||||
100 | 131 | 3981 | my $max = $self->max_diff_length; | ||||
101 | |||||||
102 | 131 | 92658148 | while (my $line = <$diff>) { | ||||
103 | 3271 | 30375 | $line =~ s/[\n\r]+$//; | ||||
104 | 3271 | 100 | 8206 | next unless $line; | |||
105 | 3054 | 100 | 100 | 7870 | if ( $max && ( $length += length $line ) >= $max ) { | ||
106 | 8 | 50 | 232 | print $out "$in_span>" if $in_span; | |||
107 | 8 | 152 | print $out qq{\@\@ Diff output truncated at $max characters. \@\@\n}; | ||||
108 | 8 | 72 | $in_span = ''; | ||||
109 | 8 | 96 | last; | ||||
110 | } else { | ||||||
111 | 3046 | 100 | 100 | 22014 | if ($line =~ /^(Modified|Added|Deleted|Copied): (.*)/) { | ||
100 | |||||||
100 | |||||||
100 | |||||||
112 | 250 | 3110 | my $class = $types{my $action = $1}; | ||||
113 | 250 | 3911 | ++$seen{$2}; | ||||
114 | 250 | 2824 | my $file = encode_entities($2, '<>&"'); | ||||
115 | 250 | 23992 | (my $id = $file) =~ s/[^\w_]//g; | ||||
116 | |||||||
117 | 250 | 100 | 1989 | print $out "$in_span>" if $in_span; | |||
118 | 250 | 100 | 1102 | print $out "\n" if $in_div; | |||
119 | |||||||
120 | # Dump line, but check it's content. | ||||||
121 | 250 | 100 | 3151 | if (<$diff> !~ /^=/) { | |||
122 | # Looks like they used --no-diff-added or --no-diff-deleted. | ||||||
123 | 35 | 700 | ($in_span, $in_div) = ''; | ||||
124 | 35 | 700 | print $out qq{\n }, |
||||
125 | qq{$action: $file\n}; |
||||||
126 | 35 | 840 | next; | ||||
127 | } | ||||||
128 | |||||||
129 | # Get the revision numbers. | ||||||
130 | 215 | 1268 | my $before = <$diff>; | ||||
131 | 215 | 2342 | $before =~ s/[\n\r]+$//; | ||||
132 | |||||||
133 | 215 | 100 | 1322 | if ($before =~ /^\(Binary files differ\)/) { | |||
134 | # Just output the whole file div. | ||||||
135 | 1 | 25 | print $out qq{\n}, |
||||
136 | qq{$action: $file\n\n}, |
||||||
137 | qq{$before\n\n}; | ||||||
138 | 1 | 9 | ($in_span, $in_div) = ''; | ||||
139 | 1 | 10 | next; | ||||
140 | } | ||||||
141 | |||||||
142 | 214 | 2291 | my ($rev1) = $before =~ /\(rev (\d+)\)$/; | ||||
143 | 214 | 958 | my $after = <$diff>; | ||||
144 | 214 | 2097 | $after =~ s/[\n\r]+$//; | ||||
145 | 214 | 2298 | my ($rev2) = $after =~ /\(rev (\d+)\)$/; | ||||
146 | |||||||
147 | # Output the headers. | ||||||
148 | 214 | 4517 | print $out qq{\n$action: $file}, |
||||
149 | " ($rev1 => $rev2)\n"; | ||||||
150 | 214 | 4779 | print $out qq{\n}; |
||||
151 | 214 | 663 | $in_div = 1; | ||||
152 | 214 | 1591 | print $out encode_entities($_, '<>&"'), "\n" for ($before, $after); | ||||
153 | 214 | 17054 | print $out ""; | ||||
154 | 214 | 1620 | $in_span = ''; | ||||
155 | } elsif ($line =~ /^Property changes on: (.*)/ && !$seen{$1}) { | ||||||
156 | # It's just property changes. | ||||||
157 | 31 | 618 | my $file = encode_entities($1, '<>&"'); | ||||
158 | 31 | 1851 | (my $id = $file) =~ s/[^\w_]//g; | ||||
159 | # Dump line. | ||||||
160 | 31 | 364 | <$diff>; | ||||
161 | |||||||
162 | # Output the headers. | ||||||
163 | 31 | 100 | 513 | print $out "$in_span>" if $in_span; | |||
164 | 31 | 100 | 408 | print $out "\n" if $in_div; | |||
165 | 31 | 431 | print $out qq{\n }, |
||||
166 | qq{Property changes: $file\n\n}; |
||||||
167 | 31 | 198 | $in_div = 1; | ||||
168 | 31 | 273 | $in_span = ''; | ||||
169 | } elsif ($line =~ /^\@\@/) { | ||||||
170 | 300 | 100 | 1321 | print $out "$in_span>" if $in_span; | |||
171 | 300 | 1389 | print $out ( | ||||
172 | qq{}, | ||||||
173 | encode_entities($line, '<>&"'), | ||||||
174 | "\n", | ||||||
175 | ); | ||||||
176 | 300 | 12077 | $in_span = ''; | ||||
177 | } elsif ($line =~ /^([-+])/) { | ||||||
178 | 576 | 100 | 1883 | my $type = $1 eq '+' ? 'ins' : 'del'; | |||
179 | 576 | 100 | 1407 | if ($in_span eq $type) { | |||
180 | 170 | 4777 | print $out encode_entities($line, '<>&"'), "\n"; | ||||
181 | } else { | ||||||
182 | 406 | 100 | 2151 | print $out "$in_span>" if $in_span; | |||
183 | 406 | 1961 | print $out ( | ||||
184 | qq{<$type>}, | ||||||
185 | encode_entities($line, '<>&"'), | ||||||
186 | "\n", | ||||||
187 | ); | ||||||
188 | 406 | 17006 | $in_span = $type; | ||||
189 | } | ||||||
190 | } else { | ||||||
191 | 1889 | 50 | 4610 | if ($in_span eq 'cx') { | |||
192 | 0 | 0 | print $out encode_entities($line, '<>&"'), "\n"; | ||||
193 | } else { | ||||||
194 | 1889 | 100 | 6702 | print $out "$in_span>" if $in_span; | |||
195 | 1889 | 6025 | print $out ( | ||||
196 | qq{}, | ||||||
197 | encode_entities($line, '<>&"'), | ||||||
198 | "\n", | ||||||
199 | ); | ||||||
200 | 1889 | 79309 | $in_span = 'span'; | ||||
201 | } | ||||||
202 | } | ||||||
203 | } | ||||||
204 | } | ||||||
205 | 131 | 100 | 2835 | print $out "$in_span>" if $in_span; | |||
206 | 131 | 100 | 1012 | print $out "\n\n" if $in_div; | |||
207 | 131 | 544 | print $out "\n"; | ||||
208 | |||||||
209 | 131 | 50 | 7770 | close $diff or warn "Child process exited: $?\n"; | |||
210 | 131 | 1122 | return $self; | ||||
211 | } | ||||||
212 | |||||||
213 | ############################################################################## | ||||||
214 | |||||||
215 | sub _css { | ||||||
216 | 394 | 394 | 7254 | my $css = shift->SUPER::_css; | |||
217 | 394 | 8428 | push @$css, | ||||
218 | qq(#patch h4 {font-family: verdana,arial,helvetica,sans-serif;), | ||||||
219 | qq(font-size:10pt;padding:8px;background:#369;color:#fff;), | ||||||
220 | qq(margin:0;}\n), | ||||||
221 | qq(#patch .propset h4, #patch .binary h4 {margin:0;}\n), | ||||||
222 | qq(#patch pre {padding:0;line-height:1.2em;margin:0;}\n), | ||||||
223 | qq(#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;), | ||||||
224 | qq(overflow:auto;}\n), | ||||||
225 | qq(#patch .propset .diff, #patch .binary .diff {padding:10px 0;}\n), | ||||||
226 | qq(#patch span {display:block;padding:0 10px;}\n), | ||||||
227 | qq(#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, ), | ||||||
228 | qq(#patch .binary, #patch .copfile {border:1px solid #ccc;), | ||||||
229 | qq(margin:10px 0;}\n), | ||||||
230 | qq(#patch ins {background:#dfd;text-decoration:none;display:block;), | ||||||
231 | qq(padding:0 10px;}\n), | ||||||
232 | qq(#patch del {background:#fdd;text-decoration:none;display:block;), | ||||||
233 | qq(padding:0 10px;}\n), | ||||||
234 | qq(#patch .lines, .info {color:#888;background:#fff;}\n); | ||||||
235 | 394 | 3893 | return $css; | ||||
236 | } | ||||||
237 | |||||||
238 | 1; | ||||||
239 | __END__ |