/[Frey]/branches/zimbardo/lib/Frey/SVN.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /branches/zimbardo/lib/Frey/SVN.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1067 - (hide annotations)
Mon Apr 27 19:55:32 2009 UTC (15 years ago) by dpavlin
Original Path: trunk/lib/Frey/SVN.pm
File size: 6605 byte(s)
add weight = removed + ( added * 2 ) to codesword
1 dpavlin 769 package Frey::SVN;
2     use Moose;
3    
4     # Convert output from svn log to html page (with some formatting of
5     # commit messages)
6     #
7     # 2004-04-28 Dobrica Pavlinusic <dpavlin@rot13.org>
8    
9     extends 'Frey';
10     with 'Frey::Web';
11 dpavlin 1066 with 'Frey::Storage';
12     with 'Frey::HTML::Diff';
13 dpavlin 769
14     use XML::Simple;
15 dpavlin 807 use DateTimeX::Easy;
16 dpavlin 1066 use Text::Diff::Parser;
17 dpavlin 769
18     has repository => (
19     is => 'rw',
20     isa => 'Str',
21     required => 1,
22     default => 'file:///home/dpavlin/private/svn/Frey',
23     );
24    
25 dpavlin 987 has path => (
26     is => 'rw',
27     isa => 'Str'
28     );
29    
30 dpavlin 770 has limit => (
31     is => 'rw',
32     isa => 'Int',
33     default => 50,
34     );
35    
36 dpavlin 1066 has include_diff => (
37     is => 'ro',
38     isa => 'Bool',
39     default => 1,
40     );
41    
42 dpavlin 1067 has file_stats => (
43     is => 'ro',
44     isa => 'Bool',
45     default => 1,
46     );
47    
48 dpavlin 804 sub iterator {
49     my ($self,$coderef) = @_;
50    
51 dpavlin 769 sub sh_regex($$) {
52     my ($cmd,$regex) = @_;
53     open(my $sh, $cmd . ' |') || die "sh_regex failed on $cmd: $!";
54     while(my $l = <$sh>) {
55     chomp($l);
56     if ($l =~ $regex) {
57     if ($1 && $2) {
58     return ($1,$2);
59     } elsif ($1) {
60     return $1;
61     } else {
62     return $l;
63     }
64     }
65     }
66     #warn "can't find $regex in output of $cmd\n";
67     return;
68     }
69    
70 dpavlin 987 my $path = $self->repository . $self->path;
71 dpavlin 769 warn "# path $path\n";
72    
73     my $cmd;
74 dpavlin 1066 my $svn_path = $path;
75    
76 dpavlin 769 if ($path =~ m#file://# || -e "$path/.svn") {
77     $cmd = "svn log -v --xml $path";
78     } else {
79 dpavlin 1066 $svn_path = sh_regex('svk info', qr#Mirrored From:\s+([^,]+)#i);
80 dpavlin 769
81     if (! $svn_path) {
82    
83     my $svk_depot = sh_regex('svk info', qr#Depot Path: (/.+)#i);
84    
85     my $depot = $svk_depot;
86     my $rel_path;
87    
88     my $path = sh_regex('svk depot --list', qr/^$depot\s+(\S+)/i);
89    
90     while (! $path && $depot =~ s{^(/.*/)([^/]+)/?$}{$1} ) {
91     $rel_path = "$2/$rel_path";
92     $path = sh_regex('svk depot --list', qr/^$depot\s+(\S+)/i);
93     }
94    
95     die "can't find depot path '$svk_depot' in svk depot --list\n" unless ($path);
96     $svn_path = "file:///$path/$rel_path";
97     }
98    
99     $cmd = "svn log -v --xml $svn_path";
100     }
101    
102 dpavlin 770 $cmd .= " --limit " . $self->limit if $self->limit;
103    
104 dpavlin 769 warn "# $cmd\n";
105     open(my $fh, $cmd .' |') || die "failed $cmd: $!";
106     my $log;
107     while(<$fh>) {
108     $log .= $_;
109     }
110     close($fh);
111    
112     my $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);
113    
114 dpavlin 804 foreach my $e (@{$xml->{'logentry'}}) {
115 dpavlin 875 warn "# e = ",$self->dump( $e ) if $self->debug;
116 dpavlin 1066
117 dpavlin 1067 if ( $self->include_diff || $self->file_stats ) {
118 dpavlin 1066 my $rev = $e->{'revision'};
119     my $file = $svn_path;
120     $file =~ s{^\w+:/+}{};
121 dpavlin 1067 my $file = "var/svn/$file/$rev.diff";
122 dpavlin 1066 my $diff = $self->load( $file );
123     if ( ! $diff ) {
124     $diff = `svn diff -c $rev $svn_path`;
125     $self->store( $file, $diff );
126     }
127 dpavlin 1067
128     $e->{diff} .= $diff if $self->include_diff;
129    
130     $e->{diff_paths}->{rev} = $rev; # XXX debug
131    
132     my $diff_path;
133     foreach my $line ( split(/[\n\r]/, $diff ) ) {
134     if ( $line =~ m{^\+\+\+ (\S+)} ) {
135     $diff_path = "/$1"; # subversion paths start with /
136     } elsif ( $line =~ m{^\+} ) {
137     $e->{diff_paths}->{$diff_path}->{added}++;
138     } elsif ( $line =~ m{^-} ) {
139     $e->{diff_paths}->{$diff_path}->{removed}++;
140     }
141     }
142 dpavlin 1066 }
143    
144 dpavlin 804 $coderef->($e);
145     }
146     }
147    
148     sub as_markup {
149     my ($self) = @_;
150    
151     # extract svk revision: r113@athlon (orig r999): dpavlin | 2005-09-01 20:38:07 +0200
152     our $svk_rev_re = '\s+(r\d+@\w+(\s+\(orig\s+r\d+\))*:\s+\w+\s+\|\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s+\+\d+)\s*';
153    
154     sub encode {
155     my $foo = shift;
156     $foo =~ s/$svk_rev_re//gsm;
157     $foo =~ s/</&lt;/g;
158     $foo =~ s/>/&gt;/g;
159     $foo =~ s/"/&quot;/g;
160 dpavlin 909 # $foo =~ s/([\n\r][\n\r]+)/$1<br\/>/gis;
161 dpavlin 804 $foo =~ s/([\n\r]+)([\-\*]\s+)/$1<br\/>$2/gis;
162     $foo =~ s/([\n\r]+)(r\d+:\s+)/$1<br\/>$2/gis;
163     $foo =~ s/([\n\r]+)(\s+r\d+@)/$1<br\/>$2/gis; # svk
164     return $foo;
165     }
166    
167 dpavlin 987 my $repository = $self->repository;
168     my $path = $self->path;
169 dpavlin 769
170 dpavlin 987 our $html = qq|
171     <h1><a href="?repository=$repository">$repository</a></h1>
172     <h2>$path</h2>
173     |;
174    
175 dpavlin 852 $self->add_css(qq|
176 dpavlin 909 .commit {
177     clear: both;
178     padding-top: 1em;
179     padding-bottom: 1em;
180     border-top: 1px dashed #ccc;
181     }
182     .files {
183     color: #888;
184     font-family: monospace;
185     font-size: 80%;
186     float: right;
187     padding-bottom: 1.2em; /* fix 80% back to original 1em */
188     }
189 dpavlin 987 .files a {
190     text-decoration: none;
191     color: #888;
192     }
193 dpavlin 852 .date, .revision { color: #666; }
194 dpavlin 909 .message {
195     padding-top: 0.5em;
196     padding-left: 2em; /* like blockquote */
197     white-space: pre-wrap;
198     }
199 dpavlin 852
200     ins { color: #8c8 }
201     del { color: #c88 }
202     |);
203    
204 dpavlin 1013 my $max_path_len = 0;
205     my $path_count;
206    
207 dpavlin 804 $self->iterator( sub {
208     my $e = shift;
209    
210 dpavlin 769 my $rev = $e->{'revision'};
211     my $date = $e->{'date'};
212    
213     $date =~ s/T/ /;
214     $date =~ s/\.\d+Z$//;
215    
216 dpavlin 852 my $msg = $e->{'msg'};
217     $msg = '' if ref($msg); # FIXME why do I need this, dammit?
218     if ( $msg ) {
219     $msg = encode( $msg );
220     $msg = qq|<div class="message">$msg</div>|;
221     }
222    
223 dpavlin 769 my @files;
224    
225     foreach my $p (@{$e->{'paths'}->{'path'}}) {
226     my ($action,$path) = ($p->{'action'},$p->{'content'});
227    
228     if ($action eq "A") {
229     push @files, "<ins>$path</ins>";
230     } elsif ($action eq "D") {
231     push @files, "<del>$path</del>";
232 dpavlin 851 } else {
233 dpavlin 769 push @files, $path;
234     }
235 dpavlin 1013
236     $max_path_len = length $path if length $path > $max_path_len;
237     $path_count->{$path}++;
238 dpavlin 769 }
239    
240 dpavlin 1066 my $diff = $self->html_diff( $e->{diff} ) if $e->{diff};
241    
242 dpavlin 1067 $html .= $self->dump( $e->{diff_paths} );
243    
244 dpavlin 909 $html .= qq|
245     <div class="commit">
246 dpavlin 987 <span class="date">$date</span>
247     <em>$e->{author}</em>
248     <span class="revision">$e->{revision}</span>
249     <div class="files">\n
250     |
251     . join("<br>\n",
252     map {
253 dpavlin 1013 my $path = $_;
254     $path =~ s{<[^>]+>}{}g;
255     qq|<a href="?repository=$repository;path=$path" title="$path ##">$_</a>|
256 dpavlin 987 } @files
257     )
258     . qq|
259     </div>
260     $msg
261 dpavlin 1066 $diff
262 dpavlin 909 </div>
263     |;
264 dpavlin 769
265 dpavlin 804 });
266 dpavlin 769
267 dpavlin 1013 $self->add_css(qq|
268     .files {
269     width: ${max_path_len}ex;
270     }
271     |);
272    
273     $html =~ s[title="(\S+) ##"]['title="' . $path_count->{$1} . '"']gse;
274    
275 dpavlin 769 return $html;
276     }
277    
278 dpavlin 805 sub codeswarm_as_markup {
279     my ($self) = @_;
280    
281     $self->content_type('text/xml');
282    
283     my $file_events = '';
284    
285     $self->iterator( sub {
286     my $e = shift;
287    
288     my $rev = $e->{'revision'};
289 dpavlin 807 my $date = DateTimeX::Easy->new( $e->{'date'} )->epoch . '000'; # ms
290 dpavlin 805 my $author = $e->{'author'};
291    
292     foreach my $p (@{$e->{'paths'}->{'path'}}) {
293     my ($action,$path) = ($p->{'action'},$p->{'content'});
294 dpavlin 1067 my $weight = '';
295     if ( defined $e->{diff_paths}->{$path} ) {
296     $weight = $e->{diff_paths}->{$path}->{removed};
297     $weight += $e->{diff_paths}->{$path}->{added} * 2;
298     $weight = qq| weight="$weight" |;
299     }
300     $file_events .= qq|\t<event filename="$path" date="$date" author="$author"$weight/>\n|;
301 dpavlin 805 }
302    
303     });
304    
305     return qq|<?xml version="1.0"?>
306     <!-- One commit per day for one month by a documenter and programmer. -->
307     <file_events>
308     $file_events
309     </file_events>
310     |;
311    
312     }
313    
314 dpavlin 769 1;

  ViewVC Help
Powered by ViewVC 1.1.26