/[Frey]/trunk/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

Contents of /trunk/lib/Frey/SVN.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1013 - (show annotations)
Sat Jan 24 19:35:41 2009 UTC (15 years, 3 months ago) by dpavlin
File size: 5302 byte(s)
set width of files to longest one in ex to align it to left,
count path usage and display as it title with fixed
link to all revisions of that file
1 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 #with 'Frey::Storage';
12
13 use XML::Simple;
14 use DateTimeX::Easy;
15
16 has repository => (
17 is => 'rw',
18 isa => 'Str',
19 required => 1,
20 default => 'file:///home/dpavlin/private/svn/Frey',
21 );
22
23 has path => (
24 is => 'rw',
25 isa => 'Str'
26 );
27
28 has limit => (
29 is => 'rw',
30 isa => 'Int',
31 default => 50,
32 );
33
34 sub iterator {
35 my ($self,$coderef) = @_;
36
37 sub sh_regex($$) {
38 my ($cmd,$regex) = @_;
39 open(my $sh, $cmd . ' |') || die "sh_regex failed on $cmd: $!";
40 while(my $l = <$sh>) {
41 chomp($l);
42 if ($l =~ $regex) {
43 if ($1 && $2) {
44 return ($1,$2);
45 } elsif ($1) {
46 return $1;
47 } else {
48 return $l;
49 }
50 }
51 }
52 #warn "can't find $regex in output of $cmd\n";
53 return;
54 }
55
56 my $path = $self->repository . $self->path;
57 warn "# path $path\n";
58
59 my $cmd;
60 if ($path =~ m#file://# || -e "$path/.svn") {
61 $cmd = "svn log -v --xml $path";
62 } else {
63 my $svn_path = sh_regex('svk info', qr#Mirrored From:\s+([^,]+)#i);
64
65 if (! $svn_path) {
66
67 my $svk_depot = sh_regex('svk info', qr#Depot Path: (/.+)#i);
68
69 my $depot = $svk_depot;
70 my $rel_path;
71
72 my $path = sh_regex('svk depot --list', qr/^$depot\s+(\S+)/i);
73
74 while (! $path && $depot =~ s{^(/.*/)([^/]+)/?$}{$1} ) {
75 $rel_path = "$2/$rel_path";
76 $path = sh_regex('svk depot --list', qr/^$depot\s+(\S+)/i);
77 }
78
79 die "can't find depot path '$svk_depot' in svk depot --list\n" unless ($path);
80 $svn_path = "file:///$path/$rel_path";
81 }
82
83 $cmd = "svn log -v --xml $svn_path";
84 }
85
86 $cmd .= " --limit " . $self->limit if $self->limit;
87
88 warn "# $cmd\n";
89 open(my $fh, $cmd .' |') || die "failed $cmd: $!";
90 my $log;
91 while(<$fh>) {
92 $log .= $_;
93 }
94 close($fh);
95
96 my $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);
97
98 foreach my $e (@{$xml->{'logentry'}}) {
99 warn "# e = ",$self->dump( $e ) if $self->debug;
100 $coderef->($e);
101 }
102 }
103
104 sub as_markup {
105 my ($self) = @_;
106
107 # extract svk revision: r113@athlon (orig r999): dpavlin | 2005-09-01 20:38:07 +0200
108 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*';
109
110 sub encode {
111 my $foo = shift;
112 $foo =~ s/$svk_rev_re//gsm;
113 $foo =~ s/</&lt;/g;
114 $foo =~ s/>/&gt;/g;
115 $foo =~ s/"/&quot;/g;
116 # $foo =~ s/([\n\r][\n\r]+)/$1<br\/>/gis;
117 $foo =~ s/([\n\r]+)([\-\*]\s+)/$1<br\/>$2/gis;
118 $foo =~ s/([\n\r]+)(r\d+:\s+)/$1<br\/>$2/gis;
119 $foo =~ s/([\n\r]+)(\s+r\d+@)/$1<br\/>$2/gis; # svk
120 return $foo;
121 }
122
123 my $repository = $self->repository;
124 my $path = $self->path;
125
126 our $html = qq|
127 <h1><a href="?repository=$repository">$repository</a></h1>
128 <h2>$path</h2>
129 |;
130
131 $self->add_css(qq|
132 .commit {
133 clear: both;
134 padding-top: 1em;
135 padding-bottom: 1em;
136 border-top: 1px dashed #ccc;
137 }
138 .files {
139 color: #888;
140 font-family: monospace;
141 font-size: 80%;
142 float: right;
143 padding-bottom: 1.2em; /* fix 80% back to original 1em */
144 }
145 .files a {
146 text-decoration: none;
147 color: #888;
148 }
149 .date, .revision { color: #666; }
150 .message {
151 padding-top: 0.5em;
152 padding-left: 2em; /* like blockquote */
153 white-space: pre-wrap;
154 }
155
156 ins { color: #8c8 }
157 del { color: #c88 }
158 |);
159
160 my $max_path_len = 0;
161 my $path_count;
162
163 $self->iterator( sub {
164 my $e = shift;
165
166 my $rev = $e->{'revision'};
167 my $date = $e->{'date'};
168
169 $date =~ s/T/ /;
170 $date =~ s/\.\d+Z$//;
171
172 my $msg = $e->{'msg'};
173 $msg = '' if ref($msg); # FIXME why do I need this, dammit?
174 if ( $msg ) {
175 $msg = encode( $msg );
176 $msg = qq|<div class="message">$msg</div>|;
177 }
178
179 my @files;
180
181 foreach my $p (@{$e->{'paths'}->{'path'}}) {
182 my ($action,$path) = ($p->{'action'},$p->{'content'});
183
184 if ($action eq "A") {
185 push @files, "<ins>$path</ins>";
186 } elsif ($action eq "D") {
187 push @files, "<del>$path</del>";
188 } else {
189 push @files, $path;
190 }
191
192 $max_path_len = length $path if length $path > $max_path_len;
193 $path_count->{$path}++;
194 }
195
196 $html .= qq|
197 <div class="commit">
198 <span class="date">$date</span>
199 <em>$e->{author}</em>
200 <span class="revision">$e->{revision}</span>
201 <div class="files">\n
202 |
203 . join("<br>\n",
204 map {
205 my $path = $_;
206 $path =~ s{<[^>]+>}{}g;
207 qq|<a href="?repository=$repository;path=$path" title="$path ##">$_</a>|
208 } @files
209 )
210 . qq|
211 </div>
212 $msg
213 </div>
214 |;
215
216 });
217
218 $self->add_css(qq|
219 .files {
220 width: ${max_path_len}ex;
221 }
222 |);
223
224 $html =~ s[title="(\S+) ##"]['title="' . $path_count->{$1} . '"']gse;
225
226 return $html;
227 }
228
229 sub codeswarm_as_markup {
230 my ($self) = @_;
231
232 $self->content_type('text/xml');
233
234 my $file_events = '';
235
236 $self->iterator( sub {
237 my $e = shift;
238
239 my $rev = $e->{'revision'};
240 my $date = DateTimeX::Easy->new( $e->{'date'} )->epoch . '000'; # ms
241 my $author = $e->{'author'};
242
243 foreach my $p (@{$e->{'paths'}->{'path'}}) {
244 my ($action,$path) = ($p->{'action'},$p->{'content'});
245 $file_events .= qq|\t<event filename="$path" date="$date" author="$author" />\n|;
246 }
247
248 });
249
250 return qq|<?xml version="1.0"?>
251 <!-- One commit per day for one month by a documenter and programmer. -->
252 <file_events>
253 $file_events
254 </file_events>
255 |;
256
257 }
258
259 1;

  ViewVC Help
Powered by ViewVC 1.1.26