]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blob - doc/todo/Attempt_to_extend_Mercurial_backend_support.mdwn
review
[git.ikiwiki.info.git] / doc / todo / Attempt_to_extend_Mercurial_backend_support.mdwn
1 Using the Mercurial backend, the lack of `rcs_commit_staged` is noticed
2 frequently. I couldn't find any tries to update `mercurial.pm`, so not
3 letting lack of Mercurial AND Perl knowledge bring me down, I copy-pasted
4 from `git.pm` to mimic its behaviour from a Mercurial perspective. I hope
5 it can be a foundation for development by those more proficient in
6 ikiwiki's inner workings. I have doubts that I personally will be able to
7 revise it more, based on my Perl skills.
9 I've tested it briefly. `ikiwiki-calendar` and posting of comments now
10 works with automatic commits, i.e. the `rcs_commit_staged` function works
11 in those cases. Under my current setup, I don't know where else to expect
12 it to work. I would be flabberghasted if there wasn't any problems with it,
13 though.
15 > Absolutely, the [[rcs]] chart shows mercurial is lagging behind
16 > nearly everything. 
17
18 > I don't think this stuff is hard, or unlikely to work, familiarity with
19 > the rcs's particular details is the main thing. --[[Joey]] 
21 Diff follows, for anyone to annotate. Code is also available at [my hg-repo](http://510x.se/hg/program/ikiwiki/file/e741fcfd800f/Plugin/mercurial.pm).
23         diff -r 20c61288d7bd Plugin/mercurial.pm
24         --- a/Plugin/mercurial.pm       Fri Jul 15 02:55:12 2011 +0200
25         +++ b/Plugin/mercurial.pm       Fri Jul 15 03:29:10 2011 +0200
26         @@ -7,6 +7,8 @@
27          use Encode;
28          use open qw{:utf8 :std};
29          
30         +my $hg_dir=undef;
31         +
32          sub import {
33                 hook(type => "checkconfig", id => "mercurial", call => \&checkconfig);
34                 hook(type => "getsetup", id => "mercurial", call => \&getsetup);
36 A corresponding variable is declared for git. It is unused as of yet for
37 Mercurial, but when more advanced merge features become available for
38 `mercurial.pm`, I think it will come into play.
40 > Maybe.. I'd rather avoid unused cruft though. --[[Joey]]
42         @@ -69,6 +71,62 @@
43                         },
44          }
45          
46         +sub safe_hg (&@) {
47         +       # Start a child process safely without resorting to /bin/sh.
48         +       # Returns command output (in list content) or success state
49         +       # (in scalar context), or runs the specified data handler.
50         +
51         +       my ($error_handler, $data_handler, @cmdline) = @_;
52         +
53         +       my $pid = open my $OUT, "-|";
54         +
55         +       error("Cannot fork: $!") if !defined $pid;
56         +
57         +       if (!$pid) {
58         +               # In child.
59         +               # hg commands want to be in wc.
60         +               if (! defined $hg_dir) {
61         +                       chdir $config{srcdir}
62         +                           or error("cannot chdir to $config{srcdir}: $!");
63         +               }
64         +               else {
65         +                       chdir $hg_dir
66         +                           or error("cannot chdir to $hg_dir: $!");
67         +               }
69 > How can this possibly work, since `$hg_dir` is not set? The code
70 > that is being replaced seems to use `-R` to make hg use the right
71 > directory. If it worked for you without specifying the directory,
72 > it's quite likely this is the place the patch fails in some
73 > unusual circumstance.. but I think it could easily use `-R` here.
75         +               exec @cmdline or error("Cannot exec '@cmdline': $!");
76         +       }
77         +       # In parent.
78         +
79         +       # hg output is probably utf-8 encoded, but may contain
80         +       # other encodings or invalidly encoded stuff. So do not rely
81         +       # on the normal utf-8 IO layer, decode it by hand.
82         +       binmode($OUT);
84 > Is this actually true for hg?
86         +       my @lines;
87         +       while (<$OUT>) {
88         +               $_=decode_utf8($_, 0);
89         +
90         +               chomp;
91         +
92         +               if (! defined $data_handler) {
93         +                       push @lines, $_;
94         +               }
95         +               else {
96         +                       last unless $data_handler->($_);
97         +               }
98         +       }
99         +
100         +       close $OUT;
101         +
102         +       $error_handler->("'@cmdline' failed: $!") if $? && $error_handler;
103         +
104         +       return wantarray ? @lines : ($? == 0);
105         +}
106         +# Convenient wrappers.
107         +sub run_or_die ($@) { safe_hg(\&error, undef, @_) }
108         +sub run_or_cry ($@) { safe_hg(sub { warn @_ }, undef, @_) }
109         +sub run_or_non ($@) { safe_hg(undef, undef, @_) }
110         +
111          sub mercurial_log ($) {
112                 my $out = shift;
113                 my @infos;
114         @@ -116,10 +174,7 @@
115          }
116          
117          sub rcs_update () {
118         -       my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update");
119         -       if (system(@cmdline) != 0) {
120         -               warn "'@cmdline' failed: $!";
121         -       }
122         +       run_or_cry('hg', '-q', 'update');
123          }
124          
125          sub rcs_prepedit ($) {
127 With the `run_or_{die,cry,non}()` functions defined as in `git.pm`, some old Mercurial functions can be rewritten more compactly.
129         @@ -129,6 +184,14 @@
130          sub rcs_commit (@) {
131                 my %params=@_;
132          
133         +       return rcs_commit_helper(@_);
134         +}
135         +
136         +sub rcs_commit_helper (@) {
137         +       my %params=@_;
138         +
139         +       my %env=%ENV;
141 > This `%env` stash is unused; `%ENV` is never modified.
143         +
144                 my $user="Anonymous";
145                 if (defined $params{session}) {
146                         if (defined $params{session}->param("name")) {
148 Here comes the `rcs_commit{,_staged}` part. It is modeled on a `rcs_commit_helper` function, as in `git.pm`.
150 Some old `mercurial.pm` logic concerning commiter name is kept instead of transplanting the more elaborate logic from `git.pm`. Maybe it is better to "steal" that as well.
152 > Exactly how to encode the nickname from openid in the commit metadata,
153 > and get it back out in `rcs_recentchanges`, would probably vary from git.
155         @@ -143,43 +206,45 @@
156                         $params{message} = "no message given";
157                 }
158          
159         -       my @cmdline = ("hg", "-q", "-R", $config{srcdir}, "commit", 
160         -                      "-m", IkiWiki::possibly_foolish_untaint($params{message}),
161         -                      "-u", IkiWiki::possibly_foolish_untaint($user));
162         -       if (system(@cmdline) != 0) {
163         -               warn "'@cmdline' failed: $!";
164         +       $params{message} = IkiWiki::possibly_foolish_untaint($params{message});
165         +
166         +       my @opts;
167         +       
168         +       if (exists $params{file}) {
169         +               push @opts, '--', $params{file};
170                 }
171         -
172         +       # hg commit returns non-zero if nothing really changed.
173         +       # So we should ignore its exit status (hence run_or_non).
174         +       run_or_non('hg', 'commit', '-m', $params{message}, '-q', @opts);
175         +       
176         +       %ENV=%env;
177                 return undef; # success
178          }
179          
180          sub rcs_commit_staged (@) {
181                 # Commits all staged changes. Changes can be staged using rcs_add,
182                 # rcs_remove, and rcs_rename.
183         -       my %params=@_;
184         -       
185         -       error("rcs_commit_staged not implemented for mercurial"); # TODO
186         +       return rcs_commit_helper(@_);
187          }
188          
189          sub rcs_add ($) {
190                 my ($file) = @_;
191          
192         -       my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "add", "$config{srcdir}/$file");
193         -       if (system(@cmdline) != 0) {
194         -               warn "'@cmdline' failed: $!";
195         -       }
196         +       run_or_cry('hg', 'add', $file);
197          }
198          
199          sub rcs_remove ($) {
200         +       # Remove file from archive.
201         +
202                 my ($file) = @_;
203          
204         -       error("rcs_remove not implemented for mercurial"); # TODO
205         +       run_or_cry('hg', 'remove', '-f', $file);
206          }
207          
208          sub rcs_rename ($$) {
209                 my ($src, $dest) = @_;
210          
211         -       error("rcs_rename not implemented for mercurial"); # TODO
212         +       run_or_cry('hg', 'rename', '-f', $src, $dest);
213          }
214          
215          sub rcs_recentchanges ($) {
217 > Remainder seems ok to me. Should probably test that the remove plugin 
218 > works, since this implements `rcs_remove` too and you didn't mention
219 > any tests that would run that code path. --[[Joey]]