]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - doc/patchqueue/darcs.mdwn
web commit by hb: new version 2.1 on the front
[git.ikiwiki.info.git] / doc / patchqueue / darcs.mdwn
index c54582daa16da8d00b77231c39955215edeea2a2..13bd82513b9ee680e8aaef3df4909f6f1d921ccd 100644 (file)
@@ -201,3 +201,264 @@ Here's Thomas Schwinge unfinished darcs support for ikiwiki.
        
        1
 """]]
+
+This is my ([bma](bma@bmalee.eu)) darcs.pm - it's messy (my Perl isn't up to much) but seems to work. It uses just one repo, like the mercurial plugin (unlike the above version, which AIUI uses two).
+
+`rcs_commit()` uses backticks instead of `system()`, to prevent darcs' output being sent to the browser and mucking with the HTTP headers (`darcs record` has no --quiet option). And `rcs_recentchanges()` uses regexes rather than parsing darcs' XML output.
+
+[[toggle text="show" id="bma"]]
+[[toggleable id="bma" text="""
+
+       #!/usr/bin/perl
+       
+       use warnings;
+       use strict;
+       use IkiWiki;
+       use Date::Parse;
+       use open qw{:utf8 :std};
+       
+       package IkiWiki;
+       
+       sub rcs_update () { #{{{
+               # Do nothing - there's nowhere to update *from*.
+       } #}}}
+       
+       sub rcs_prepedit ($) { #{{{
+       } #}}}
+       
+       sub rcs_commit ($$$;$$) { #{{{
+               my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+       
+               # $user should probably be a name and an email address, by darcs
+               # convention.
+               if (defined $user) {
+                       $user = possibly_foolish_untaint($user);
+               }
+               elsif (defined $ipaddr) {
+                       $user = "Anonymous from $ipaddr";
+               }
+               else {
+                       $user = "Anonymous";
+               }
+       
+               $message = possibly_foolish_untaint($message);
+               
+               # BUG: this outputs one line of text, and there's not a -q or --quiet
+               # option. Redirecting output to /dev/null works, but I still get the
+               # HTTP status and location headers displayed in the browser - is that
+               # darcs' fault or ikiwiki's?
+               # Doing it in backticks *works*, but I'm sure it could be done better.
+               my @cmdline = ("darcs", "record", "--repodir", "$config{srcdir}",
+                              "-a", "-m", "$message", "--author", "$user", $file);
+               `darcs record --repodir "$config{srcdir}" -a -m "$message" --author "$user" $file`; # Return value? Output? Who needs 'em?
+               #if (system(@cmdline) != 0) {
+               #       warn "'@cmdline' failed: $!";
+               #}
+       
+               return undef; # success
+               
+       sub rcs_add ($) { # {{{
+               my ($file) = @_;
+       
+               my @cmdline = ("darcs", "add", "--repodir", "$config{srcdir}", "-a", "-q", "$file");
+               if (system(@cmdline) != 0) {
+                       warn "'@cmdline' failed: $!";
+               }
+       } #}}}
+       
+       sub rcs_recentchanges ($) { #{{{
+               # TODO: This is horrible code. It doesn't work perfectly, and uses regexes
+               # rather than parsing Darcs' XML output.
+               my $num=shift;
+               my @ret;
+               
+               return unless -d "$config{srcdir}/_darcs";
+       
+               my $changelog = `darcs changes --xml --summary --repodir "$config{srcdir}"`;
+               $changelog = join("", split(/\s*\n\s*/, $changelog));
+               my @changes = split(/<\/patch>.*?<patch/m, $changelog);
+       
+       
+               foreach my $change (@changes) {
+                       $change =~ m/hash='(.*?)'/;
+                       my $rev = $1;
+                       $change =~ m/author='(.*?)'/;
+                       my $user = $1."\n";
+                       my $committype = "web";
+                       if($user =~ m/&lt;/) {
+                               # Author fields generated by darcs include an email address: look for the "<".
+                               $committype = "darcs";
+                               use HTML::Entities;
+                               $user = decode_entities $user;
+                       }
+                       $change =~ m/local_date='(.*?)'/;
+                       my $when = $1;
+                       $when=time - str2time($when, 'UTC');
+                       $change =~ m/<name>(.*?)<\/name>/g;
+                       my @message = {line => $1};
+                       foreach my $match ($change =~ m/<comment>(.*?)<\/comment>/gm) {
+                               push @message, {line => $1};
+                       }
+
+                       my @pages;
+                       foreach my $match ($change =~ m/<.*?_(file|directory)>(.*?)(<(added|removed)_lines.*\/>)*<\/.*?_(file|directory)>/g) {
+                               # My perl-fu is weak. I'm probably going about this all wrong, anyway.
+                               push @pages, {page => pagename($match)} if ( -f $config{srcdir}."/".$match || -d $config{srcdir}."/".$match) and not $match =~ m/^$/;
+                       }
+                       push @ret, { rev => $rev,
+                                       user => $user,
+                                       committype => $committype,
+                                       when => $when,
+                                       message => [@message],
+                                       pages => [@pages],
+                               }
+               }
+               return @ret;
+       } #}}}
+       
+       sub rcs_notify () { #{{{
+               # TODO
+       } #}}}
+       
+       sub rcs_getctime ($) { #{{{
+               error gettext("getctime not implemented");
+       } #}}}
+       
+       1
+
+
+
+"""]]
+
+---
+
+Well, here's my version too. It only does getctime -- using a real XML parser, instead of regexp ugliness -- and maybe recentchanges, but that may be bitrotted, or maybe I never finished it, as I only need the getctime. As for actual commits, I have previously voiced my opinion, that this should be done by the plugin generating a patch bundle, and forwarding it to darcs in some way (`darcs apply` or even email to another host, possibly moderated), instead of the hacky direct modification of a working copy. It could also be faster to getctime in a batch. Just reading in all the changes the first time they're needed, might not be a big improvement in many cases, but if we got a batch request from ikiwiki, we could keep reaing the changes until all the files in this batch request have been met.  --[[tuomov]]
+
+[[toggle text="show" id="tuomov"]]
+[[toggleable id="tuomov" text="""
+<pre>
+#!/usr/bin/perl
+# Stubs for no revision control.
+
+use warnings;
+use strict;
+use IkiWiki;
+
+package IkiWiki;
+
+sub rcs_update () {
+}
+
+sub rcs_prepedit ($) {
+       return ""
+}
+
+sub rcs_commit ($$$) {
+       return undef # success
+}
+
+sub rcs_add ($) {
+}
+
+sub rcs_recentchanges ($) {
+       my $num=shift;
+       my @ret;
+       
+       eval q{use Date::Parse};
+       eval q{use XML::Simple};
+       
+       my $repodir=$config{srcdir};
+       
+       if (-d "$config{srcdir}/_darcs") {
+               my $child = open(LOG, "-|");
+               if (! $child) {
+                       exec("darcs", "changes", "--xml", 
+                            "--repodir", "$repodir",
+                            "--last", "$num")
+                       || error("darcs changes failed to run");
+               }
+               my $data=<LOG>;
+               close LOG;
+               
+               my $log = XMLin($data, ForceArray => 1);
+               
+               foreach my $patch ($log->{patch}) {
+                       my $date=$patch->{local_date};
+                       my $hash=$patch->{hash};
+                       my $when=concise(ago(time - str2time($date)));
+                       my @pages;
+                       
+                       my $child = open(SUMMARY, "-|");
+                       if (! $child) {
+                               exec("darcs", "annotate", "-s", "--xml", 
+                                    "--match", "hash: $hash",
+                                    "--repodir", "$repodir")
+                               || error("darcs annotate failed to run");
+                       }
+                       my $data=<SUMMARY>;
+                       close SUMMARY;
+               
+                       my $summary = XMLin("<lame>$data</lame>", ForceArray => 1);
+
+                       # TODO: find @pages
+                       
+                       push @ret, {
+                               #rev => $rev,
+                               user => $patch->{author},
+                               #committype => $committype,
+                               when => $when, 
+                               #message => [@message],
+                               pages => [@pages],
+                       }; # if @pages;
+                       return @ret if @ret >= $num;
+               }
+       }
+       
+       return @ret;
+}
+
+sub rcs_notify () {
+}
+
+sub rcs_getctime ($) {
+       my $file=shift;
+       
+       eval q{use Date::Parse};
+       eval q{use XML::Simple};
+       local $/=undef;
+       
+       # Sigh... doing things the hard way again
+       my $repodir=$config{srcdir};
+       
+       my $filer=substr($file, length($repodir));
+       $filer =~ s:^[/]+::;
+       
+       my $child = open(LOG, "-|");
+       if (! $child) {
+               exec("darcs", "changes", "--xml", "--reverse",
+                    "--repodir", "$repodir", "$filer")
+               || error("darcs changes $filer failed to run");
+       }
+       
+       my $data=<LOG>;
+       close LOG;
+       
+       my $log = XMLin($data, ForceArray => 1);
+       
+       my $datestr=$log->{patch}[0]->{local_date};
+       
+       if (! defined $datestr) {
+               warn "failed to get ctime for $filer";
+               return 0;
+       }
+       
+       my $date=str2time($datestr);
+       
+       debug("found ctime ".localtime($date)." for $file");
+       
+       return $date;
+}
+
+1
+</pre>
+"""]]