]> sipb.mit.edu Git - ikiwiki.git/blob - IkiWiki/Rcs/bzr.pm
historyurl can be undef
[ikiwiki.git] / IkiWiki / Rcs / bzr.pm
1 #!/usr/bin/perl
2
3 package IkiWiki;
4
5 use warnings;
6 use strict;
7 use IkiWiki;
8 use Encode;
9 use open qw{:utf8 :std};
10
11 hook(type => "getsetup", id => "bzr", call => sub { #{{{
12         return
13                 historyurl => {
14                         type => "string",
15                         default => "",
16                         #example => "", # FIXME add example
17                         description => "url to show file history, using loggerhead ([[file]] substituted)",
18                         safe => 1,
19                         rebuild => 1,
20                 },
21                 diffurl => {
22                         type => "string",
23                         default => "",
24                         example => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s",
25                         description => "url to view a diff, using loggerhead ([[file]] and [[r2]] substituted)",
26                         safe => 1,
27                         rebuild => 1,
28                 },
29 }); #}}}
30
31 sub bzr_log ($) { #{{{
32         my $out = shift;
33         my @infos = ();
34         my $key = undef;
35
36         while (<$out>) {
37                 my $line = $_;
38                 my ($value);
39                 if ($line =~ /^message:/) {
40                         $key = "message";
41                         $infos[$#infos]{$key} = "";
42                 }
43                 elsif ($line =~ /^(modified|added|renamed|renamed and modified|removed):/) {
44                         $key = "files";
45                         unless (defined($infos[$#infos]{$key})) { $infos[$#infos]{$key} = ""; }
46                 }
47                 elsif (defined($key) and $line =~ /^  (.*)/) {
48                         $infos[$#infos]{$key} .= "$1\n";
49                 }
50                 elsif ($line eq "------------------------------------------------------------\n") {
51                         $key = undef;
52                         push (@infos, {});
53                 }
54                 else {
55                         chomp $line;
56                                 ($key, $value) = split /: +/, $line, 2;
57                         $infos[$#infos]{$key} = $value;
58                 } 
59         }
60         close $out;
61
62         return @infos;
63 } #}}}
64
65 sub rcs_update () { #{{{
66         my @cmdline = ("bzr", "update", "--quiet", $config{srcdir});
67         if (system(@cmdline) != 0) {
68                 warn "'@cmdline' failed: $!";
69         }
70 } #}}}
71
72 sub rcs_prepedit ($) { #{{{
73         return "";
74 } #}}}
75
76 sub bzr_author ($$) { #{{{
77         my ($user, $ipaddr) = @_;
78
79         if (defined $user) {
80                 return possibly_foolish_untaint($user);
81         }
82         elsif (defined $ipaddr) {
83                 return "Anonymous from ".possibly_foolish_untaint($ipaddr);
84         }
85         else {
86                 return "Anonymous";
87         }
88 } #}}}
89
90 sub rcs_commit ($$$;$$) { #{{{
91         my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
92
93         $user = bzr_author($user, $ipaddr);
94
95         $message = possibly_foolish_untaint($message);
96         if (! length $message) {
97                 $message = "no message given";
98         }
99
100         my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
101                        $config{srcdir}."/".$file);
102         if (system(@cmdline) != 0) {
103                 warn "'@cmdline' failed: $!";
104         }
105
106         return undef; # success
107 } #}}}
108
109 sub rcs_commit_staged ($$$) {
110         # Commits all staged changes. Changes can be staged using rcs_add,
111         # rcs_remove, and rcs_rename.
112         my ($message, $user, $ipaddr)=@_;
113
114         $user = bzr_author($user, $ipaddr);
115
116         $message = possibly_foolish_untaint($message);
117         if (! length $message) {
118                 $message = "no message given";
119         }
120
121         my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
122                        $config{srcdir});
123         if (system(@cmdline) != 0) {
124                 warn "'@cmdline' failed: $!";
125         }
126
127         return undef; # success
128 } #}}}
129
130 sub rcs_add ($) { # {{{
131         my ($file) = @_;
132
133         my @cmdline = ("bzr", "add", "--quiet", "$config{srcdir}/$file");
134         if (system(@cmdline) != 0) {
135                 warn "'@cmdline' failed: $!";
136         }
137 } #}}}
138
139 sub rcs_remove ($) { # {{{
140         my ($file) = @_;
141
142         my @cmdline = ("bzr", "rm", "--force", "--quiet", "$config{srcdir}/$file");
143         if (system(@cmdline) != 0) {
144                 warn "'@cmdline' failed: $!";
145         }
146 } #}}}
147
148 sub rcs_rename ($$) { # {{{
149         my ($src, $dest) = @_;
150
151         my $parent = dirname($dest);
152         if (system("bzr", "add", "--quiet", "$config{srcdir}/$parent") != 0) {
153                 warn("bzr add $parent failed\n");
154         }
155
156         my @cmdline = ("bzr", "mv", "--quiet", "$config{srcdir}/$src", "$config{srcdir}/$dest");
157         if (system(@cmdline) != 0) {
158                 warn "'@cmdline' failed: $!";
159         }
160 } #}}}
161
162 sub rcs_recentchanges ($) { #{{{
163         my ($num) = @_;
164
165         my @cmdline = ("bzr", "log", "-v", "--show-ids", "--limit", $num, 
166                            $config{srcdir});
167         open (my $out, "@cmdline |");
168
169         eval q{use Date::Parse};
170         error($@) if $@;
171
172         my @ret;
173         foreach my $info (bzr_log($out)) {
174                 my @pages = ();
175                 my @message = ();
176         
177                 foreach my $msgline (split(/\n/, $info->{message})) {
178                         push @message, { line => $msgline };
179                 }
180
181                 foreach my $file (split(/\n/, $info->{files})) {
182                         my ($filename, $fileid) = ($file =~ /^(.*?) +([^ ]+)$/);
183
184                         # Skip directories
185                         next if ($filename =~ /\/$/);
186
187                         # Skip source name in renames
188                         $filename =~ s/^.* => //;
189
190                         my $diffurl = $config{'diffurl'};
191                         $diffurl =~ s/\[\[file\]\]/$filename/go;
192                         $diffurl =~ s/\[\[file-id\]\]/$fileid/go;
193                         $diffurl =~ s/\[\[r2\]\]/$info->{revno}/go;
194
195                         push @pages, {
196                                 page => pagename($filename),
197                                 diffurl => $diffurl,
198                         };
199                 }
200
201                 my $user = $info->{"committer"};
202                 if (defined($info->{"author"})) { $user = $info->{"author"}; }
203                 $user =~ s/\s*<.*>\s*$//;
204                 $user =~ s/^\s*//;
205
206                 push @ret, {
207                         rev        => $info->{"revno"},
208                         user       => $user,
209                         committype => "bzr",
210                         when       => time - str2time($info->{"timestamp"}),
211                         message    => [@message],
212                         pages      => [@pages],
213                 };
214         }
215
216         return @ret;
217 } #}}}
218
219 sub rcs_getctime ($) { #{{{
220         my ($file) = @_;
221
222         # XXX filename passes through the shell here, should try to avoid
223         # that just in case
224         my @cmdline = ("bzr", "log", "--limit", '1', "$config{srcdir}/$file");
225         open (my $out, "@cmdline |");
226
227         my @log = bzr_log($out);
228
229         if (length @log < 1) {
230                 return 0;
231         }
232
233         eval q{use Date::Parse};
234         error($@) if $@;
235         
236         my $ctime = str2time($log[0]->{"timestamp"});
237         return $ctime;
238 } #}}}
239
240 1