File Coverage

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   289546 use strict;
  134         214  
  134         3282  
4 134     134   422 use HTML::Entities;
  134         194  
  134         6032  
5 134     134   22688 use SVN::Notify::HTML ();
  134         154  
  134         123842  
6              
7             $SVN::Notify::HTML::ColorDiff::VERSION = '2.86';
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 in 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 sends HTML formatted
32             email messages for Subversion activity, and if the C parameter is
33             specified (but not C), then a pretty colorized version of the
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 in SVN::Notify, but when using F,
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 filters, this method will do no HTML formatting, but
76             redispatch to L. See
77             L for details on
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 1152 my ($self, $out, $diff) = @_;
91 145 100       1416 if ( $self->filters_for('diff') ) {
92 14         728 return $self->SUPER::output_diff($out, $diff);
93             }
94 131 50       2191 $self->_dbpnt( "Outputting colorized HTML diff") if $self->verbose > 1;
95              
96 131         314 my $in_div;
97 131         811 my $in_span = '';
98 131         1158 print $out qq{\n
\n

Diff

\n};
99 131         542 my ($length, %seen) = 0;
100 131         2792 my $max = $self->max_diff_length;
101              
102 131         89271899 while (my $line = <$diff>) {
103 3271         24375 $line =~ s/[\n\r]+$//;
104 3271 100       5780 next unless $line;
105 3054 100 100     5842 if ( $max && ( $length += length $line ) >= $max ) {
106 8 50       104 print $out "" if $in_span;
107 8         48 print $out qq{\@\@ Diff output truncated at $max characters. \@\@\n};
108 8         72 $in_span = '';
109 8         16 last;
110             } else {
111 3046 100 100     14049 if ($line =~ /^(Modified|Added|Deleted|Copied): (.*)/) {
    100          
    100          
    100          
112 250         1691 my $class = $types{my $action = $1};
113 250         1682 ++$seen{$2};
114 250         1505 my $file = encode_entities($2, '<>&"');
115 250         16257 (my $id = $file) =~ s/[^\w_]//g;
116              
117 250 100       1031 print $out "" if $in_span;
118 250 100       962 print $out "\n" if $in_div;
119              
120             # Dump line, but check it's content.
121 250 100       1907 if (<$diff> !~ /^=/) {
122             # Looks like they used --no-diff-added or --no-diff-deleted.
123 35         315 ($in_span, $in_div) = '';
124 35         490 print $out qq{\n
},
125             qq{

$action: $file

\n};
126 35         560 next;
127             }
128              
129             # Get the revision numbers.
130 215         627 my $before = <$diff>;
131 215         1441 $before =~ s/[\n\r]+$//;
132              
133 215 100       870 if ($before =~ /^\(Binary files differ\)/) {
134             # Just output the whole file div.
135 1         12 print $out qq{\n

},

136             qq{$action: $file\n
\n}, 
137             qq{$before\n\n};
138 1         5 ($in_span, $in_div) = '';
139 1         4 next;
140             }
141              
142 214         1330 my ($rev1) = $before =~ /\(rev (\d+)\)$/;
143 214         600 my $after = <$diff>;
144 214         1253 $after =~ s/[\n\r]+$//;
145 214         1149 my ($rev2) = $after =~ /\(rev (\d+)\)$/;
146              
147             # Output the headers.
148 214         2591 print $out qq{\n

$action: $file},

149             " ($rev1 => $rev2)\n";
150 214         3217 print $out qq{
\n}; 
151 214         343 $in_div = 1;
152 214         1082 print $out encode_entities($_, '<>&"'), "\n" for ($before, $after);
153 214         14834 print $out "";
154 214         997 $in_span = '';
155             } elsif ($line =~ /^Property changes on: (.*)/ && !$seen{$1}) {
156             # It's just property changes.
157 31         182 my $file = encode_entities($1, '<>&"');
158 31         1173 (my $id = $file) =~ s/[^\w_]//g;
159             # Dump line.
160 31         77 <$diff>;
161              
162             # Output the headers.
163 31 100       183 print $out "" if $in_span;
164 31 100       183 print $out "\n" if $in_div;
165 31         156 print $out qq{\n
},
166             qq{

Property changes: $file

\n
\n}; 
167 31         46 $in_div = 1;
168 31         78 $in_span = '';
169             } elsif ($line =~ /^\@\@/) {
170 300 100       833 print $out "" if $in_span;
171 300         816 print $out (
172             qq{},
173             encode_entities($line, '<>&"'),
174             "\n",
175             );
176 300         9149 $in_span = '';
177             } elsif ($line =~ /^([-+])/) {
178 576 100       1451 my $type = $1 eq '+' ? 'ins' : 'del';
179 576 100       910 if ($in_span eq $type) {
180 170         520 print $out encode_entities($line, '<>&"'), "\n";
181             } else {
182 406 100       1633 print $out "" if $in_span;
183 406         1335 print $out (
184             qq{<$type>},
185             encode_entities($line, '<>&"'),
186             "\n",
187             );
188 406         15638 $in_span = $type;
189             }
190             } else {
191 1889 50       2337 if ($in_span eq 'cx') {
192 0         0 print $out encode_entities($line, '<>&"'), "\n";
193             } else {
194 1889 100       4819 print $out "" if $in_span;
195 1889         4214 print $out (
196             qq{},
197             encode_entities($line, '<>&"'),
198             "\n",
199             );
200 1889         59215 $in_span = 'span';
201             }
202             }
203             }
204             }
205 131 100       674 print $out "" if $in_span;
206 131 100       1215 print $out "\n\n" if $in_div;
207 131         281 print $out "\n";
208              
209 131 50       8117 close $diff or warn "Child process exited: $?\n";
210 131         752 return $self;
211             }
212              
213             ##############################################################################
214              
215             sub _css {
216 394     394   3367 my $css = shift->SUPER::_css;
217 394         4152 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         1171 return $css;
236             }
237              
238             1;
239             __END__