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   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 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 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 "" 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 "" 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 "" 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 "" 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 "" 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 "" 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 "" 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__