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   1368692 use strict;
  134         442  
  134         12692  
4 134     134   929 use HTML::Entities;
  134         259  
  134         13970  
5 134     134   114074 use SVN::Notify::HTML ();
  134         366  
  134         306253  
6              
7             $SVN::Notify::HTML::ColorDiff::VERSION = '2.84';
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 29398 my ($self, $out, $diff) = @_;
91 145 100       2029 if ( $self->filters_for('diff') ) {
92 14         938 return $self->SUPER::output_diff($out, $diff);
93             }
94 131 50       5695 $self->_dbpnt( "Outputting colorized HTML diff") if $self->verbose > 1;
95              
96 131         721 my $in_div;
97 131         1338 my $in_span = '';
98 131         3128 print $out qq{\n
\n

Diff

\n};
99 131         789 my ($length, %seen) = 0;
100 131         4684 my $max = $self->max_diff_length;
101              
102 131         489718449 while (my $line = <$diff>) {
103 3271         38954 $line =~ s/[\n\r]+$//;
104 3271 100       8859 next unless $line;
105 3054 100 100     62531 if ( $max && ( $length += length $line ) >= $max ) {
106 8 50       168 print $out "" if $in_span;
107 8         184 print $out qq{\@\@ Diff output truncated at $max characters. \@\@\n};
108 8         120 $in_span = '';
109 8         96 last;
110             } else {
111 3046 100 100     21333 if ($line =~ /^(Modified|Added|Deleted|Copied): (.*)/) {
    100          
    100          
    100          
112 250         3319 my $class = $types{my $action = $1};
113 250         2808 ++$seen{$2};
114 250         5026 my $file = encode_entities($2, '<>&"');
115 250         46248 (my $id = $file) =~ s/[^\w_]//g;
116              
117 250 100       2246 print $out "" if $in_span;
118 250 100       1371 print $out "\n" if $in_div;
119              
120             # Dump line, but check it's content.
121 250 100       2671 if (<$diff> !~ /^=/) {
122             # Looks like they used --no-diff-added or --no-diff-deleted.
123 35         665 ($in_span, $in_div) = '';
124 35         560 print $out qq{\n
},
125             qq{

$action: $file

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

},

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

$action: $file},

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

Property changes: $file

\n
\n}; 
167 31         78 $in_div = 1;
168 31         274 $in_span = '';
169             } elsif ($line =~ /^\@\@/) {
170 300 100       1179 print $out "" if $in_span;
171 300         1174 print $out (
172             qq{},
173             encode_entities($line, '<>&"'),
174             "\n",
175             );
176 300         16903 $in_span = '';
177             } elsif ($line =~ /^([-+])/) {
178 576 100       2542 my $type = $1 eq '+' ? 'ins' : 'del';
179 576 100       1333 if ($in_span eq $type) {
180 170         738 print $out encode_entities($line, '<>&"'), "\n";
181             } else {
182 406 100       1791 print $out "" if $in_span;
183 406         1946 print $out (
184             qq{<$type>},
185             encode_entities($line, '<>&"'),
186             "\n",
187             );
188 406         24980 $in_span = $type;
189             }
190             } else {
191 1889 50       3562 if ($in_span eq 'cx') {
192 0         0 print $out encode_entities($line, '<>&"'), "\n";
193             } else {
194 1889 100       10947 print $out "" if $in_span;
195 1889         6131 print $out (
196             qq{},
197             encode_entities($line, '<>&"'),
198             "\n",
199             );
200 1889         141600 $in_span = 'span';
201             }
202             }
203             }
204             }
205 131 100       2138 print $out "" if $in_span;
206 131 100       803 print $out "\n\n" if $in_div;
207 131         417 print $out "\n";
208              
209 131 50       17100 close $diff or warn "Child process exited: $?\n";
210 131         1106 return $self;
211             }
212              
213             ##############################################################################
214              
215             sub _css {
216 394     394   51779 my $css = shift->SUPER::_css;
217 394         13540 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         1847 return $css;
236             }
237              
238             1;
239             __END__