Merge branch 'ready/trail-sort'
[ikiwiki] / doc / todo / Auto-setup_and_maintain_Mercurial_wrapper_hooks.mdwn
1 Attempt to fix a `TODO` in `Automator.pm` in combination with the Mercurial backend.
2
3 1. To define hooks, Mercurial uses paths given in the config file `.hg/hgrc`. To enable Mercurial to call `ikiwiki-wrapper` automatically after blog/wiki setup, ikiwiki thus needs to create `hgrc`.
4 2. To reflect changes in `$config{srcdir}` and/or `$config{mercurial_wrapper}`, relevant lines in `hgrc` need to be updated on wrapper creation.
5
6 ikiwiki can keep track of lines in `hgrc` for which it is responsible by adding a `.ikiwiki` suffix to its hooks. This is correct and recommended markup, Mercurial-wise.
7
8 Two ways follow below. I prefer the long one. --[[Daniel Andersson]]
9
10 > I comment myself: this can probably be solved without adding ad-hoc hooks and stuff (maybe not as "correct" as changing the config file only directly after wrappers have been generated, but good enough). I have a large rewrite of `mercurial.pm` ready, currently under local testing before I upload it for comments, trying to make it equal in function to `git.pm`. Comments below are of course welcome, but I will look into other ways of solving it later. Maybe `rcs_checkconfig` or `rcs_genwrapper` should host the `hgrc`-changing code. --[[Daniel Andersson]]
11
12 >> Having a hook that runs after a wrapper is generated may well be a good
13 >> thing anyway. In ikiwiki-hosting, there are some genwrapper hooks
14 >> that don't add any code to the wrapper, but are there only to run at,
15 >> essentially, that time.
16 >> 
17 >> With that said, here it seems like unnecessary complexity.
18 >> Why is `mercurial_wrapper` configurable at all? Why not just always
19 >> write it to a specific place relative to the srcdir, and always make
20 >> the hgrc look there?
21 >> 
22 >> (Other rcs plugins have good reasons to make their wrappers
23 >> configurable, because one might want the wrapper to run as a git
24 >> post-update or post-commit hook.) --[[Joey]]
25
26 Compact way (addresses only point 1)
27 ------------------------------------
28 [This patch at pastebin](http://pastebin.com/by9f4dwX) ([raw version](http://pastebin.com/raw.php?i=by9f4dwX)).
29
30 Set default `ikiwiki-wrapper` path.
31
32         diff -r 8faf136ca94f Setup/Automator.pm
33         --- a/Setup/Automator.pm        Tue Jul 19 21:04:13 2011 +0200
34         +++ b/Setup/Automator.pm        Wed Jul 20 15:33:21 2011 +0200
35         @@ -75,8 +75,7 @@
36                                 print STDERR "warning: do not know how to set up the bzr_wrapper hook!\n";
37                         }
38                         elsif ($config{rcs} eq 'mercurial') {
39         -                       # TODO
40         -                       print STDERR "warning: do not know how to set up the mercurial_wrapper hook!\n";
41         +                       $config{mercurial_wrapper}=$config{srcdir}."/.hg/ikiwiki-wrapper";
42                         }
43                         elsif ($config{rcs} eq 'tla') {
44                                 # TODO
45
46 Create `$config{srcdir}/.hg/hgrc` with hook info during auto-installation script. Use relative paths to not require manual `hgrc` intervention if `$config{srcdir}` is changed. If `$config{mercurial_wrapper}` is changed, manual edit of `hgrc` is needed to catch the new wrapper path.
47
48 (Is there a security risk with relative paths?)
49
50 > The code seems to assume that hg will be run from within the srcdir,
51 > specifically the top of the srcdir. If it's run from somewhere else,
52 > even a subdirectory, this will fail to find the wrapper, or could
53 > run some other program. Unless mercurial always interprets these paths
54 > as relative to the top of the repository? --[[Joey]]
55
56         @@ -187,6 +186,22 @@
57                         die "ikiwiki --wrappers --setup $config{dumpsetup} failed";
58                 }
59          
60         +       # Setup initial config file for Mercurial to hook up the wrapper.
61         +       if ($config{rcs} eq 'mercurial' && exists $config{mercurial_wrapper}
62         +               && length $config{mercurial_wrapper}) {
63         +               # Use a relative path to avoid having to manually change the
64         +               # autogenerated hgrc if the user changes $config{srcdir}.
65         +               use File::Spec;
66         +               my $mercurial_wrapper_relpath=File::Spec->abs2rel($config{mercurial_wrapper}, $config{srcdir});
67         +               open (HGRC, '>', $config{srcdir}.'/.hg/hgrc');
68         +               print HGRC <<EOF;
69         +[hooks]
70         +post-commit.ikiwiki = $mercurial_wrapper_relpath
71         +incoming.ikiwiki = $mercurial_wrapper_relpath
72         +EOF
73         +               close (HGRC);
74         +       }
75         +
76                 # Add it to the wikilist.
77                 mkpath("$ENV{HOME}/.ikiwiki");
78                 open (WIKILIST, ">>$ENV{HOME}/.ikiwiki/wikilist") || die "$ENV{HOME}/.ikiwiki/wikilist: $!";
79
80
81 Less compact but more robust way (addresses point 1 and 2)
82 ----------------------------------------------------------
83 [This complete patch at pastebin](http://pastebin.com/AcDHjbK6) ([raw version](http://pastebin.com/raw.php?i=AcDHjbK6)).
84
85 This way leaks onto additional files and adds general functionality that may or may not be wanted. The main part of the extra code is contained within `mercurial.pm`, though.
86
87 Set default `ikiwiki-wrapper` path.
88
89         diff -r b08179653c00 IkiWiki/Setup/Automator.pm
90         --- a/IkiWiki/Setup/Automator.pm        Wed Jul 20 16:56:09 2011 +0200
91         +++ b/IkiWiki/Setup/Automator.pm        Wed Jul 20 19:28:21 2011 +0200
92         @@ -75,8 +75,7 @@
93                                 print STDERR "warning: do not know how to set up the bzr_wrapper hook!\n";
94                         }
95                         elsif ($config{rcs} eq 'mercurial') {
96         -                       # TODO
97         -                       print STDERR "warning: do not know how to set up the mercurial_wrapper hook!\n";
98         +                       $config{mercurial_wrapper}=$config{srcdir}."/.hg/ikiwiki-wrapper";
99                         }
100                         elsif ($config{rcs} eq 'tla') {
101                                 # TODO
102
103 Create `$config{srcdir}/.hg/hgrc` during auto-installation with hook info.
104
105         @@ -182,6 +181,19 @@
106                         }
107                 }
108                 
109         +       # Setup initial config file for Mercurial to hook up the wrapper. The
110         +       # path to the wrapper will be automatically added when it is generated.
111         +       if ($config{rcs} eq 'mercurial' && exists $config{mercurial_wrapper}
112         +               && length $config{mercurial_wrapper}) {
113         +               open (HGRC, '>', $config{srcdir}.'/.hg/hgrc');
114         +               print HGRC <<EOF;
115         +[hooks]
116         +post-commit.ikiwiki = 
117         +incoming.ikiwiki = 
118         +EOF
119         +               close (HGRC);
120         +       }
121         +
122                 # Add wrappers, make live.
123                 if (system("ikiwiki", "--wrappers", "--setup", $config{dumpsetup}) != 0) {
124                         die "ikiwiki --wrappers --setup $config{dumpsetup} failed";
125
126 `hgrc` is setup initially. Below follows code to keep `hgrc` updated.
127
128 Add backend specific function `rcs_wrapper_postcall()` for later call in `Wrappers.pm`.
129
130         diff -r b08179653c00 IkiWiki/Plugin/mercurial.pm
131         --- a/IkiWiki/Plugin/mercurial.pm       Wed Jul 20 16:56:09 2011 +0200
132         +++ b/IkiWiki/Plugin/mercurial.pm       Wed Jul 20 19:28:21 2011 +0200
133         @@ -21,6 +21,7 @@
134                 hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
135                 hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
136                 hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime);
137         +       hook(type => "rcs", id => "rcs_wrapper_postcall", call => \&rcs_wrapper_postcall);
138          }
139          
140          sub checkconfig () {
141
142 Pass variable to `gen_wrapper()` to decide if `rcs_wrapper_postcall()` should run. Default is `1` to update `hgrc`, since it is done non-intrusive (won't create `hgrc` if it doesn't exist, won't overwrite anything unless it is set by ikiwiki itself).
143
144         @@ -28,6 +29,7 @@
145                         push @{$config{wrappers}}, {
146                                 wrapper => $config{mercurial_wrapper},
147                                 wrappermode => (defined $config{mercurial_wrappermode} ? $config{mercurial_wrappermode} : "06755"),
148         +                       wrapper_postcall => (defined $config{mercurial_wrapper_hgrc_update} ? $config{mercurial_wrapper_hgrc_update} : "1"),
149                         };
150                 }
151          }
152
153 Include default configuration value and comment.
154
155         @@ -53,6 +55,13 @@
156                                 safe => 0,
157                                 rebuild => 0,
158                         },
159         +               mercurial_wrapper_hgrc_update => {
160         +                       type => "string",
161         +                       example => "1",
162         +                       description => "updates existing hgrc to reflect path changes for mercurial_wrapper",
163         +                       safe => 0,
164         +                       rebuild => 0,
165         +               },
166                         historyurl => {
167                                 type => "string",
168                                 example => "http://example.com:8000/log/tip/\[[file]]",
169
170 `hgrc` should be updated to point to the new wrapper path. The regexp transforms lines as e.g.
171
172         post-commit.ikiwiki = /home/daniel/blog/.hg/ikiwiki-wrapper-oldpath
173         incoming.ikiwiki = /home/daniel/blog/.hg/ikiwiki-wrapper-oldpath
174
175 to
176
177         post-commit.ikiwiki = $config{mercurial_wrapper}
178         incoming.ikiwiki = $config{mercurial_wrapper}
179
180 with absolute paths.
181
182         @@ -402,4 +411,23 @@
183                 return findtimes($file, 0);
184          }
185          
186         +sub rcs_wrapper_postcall($) {
187         +       # Update hgrc if it exists. Change post-commit/incoming hooks with the
188         +       # .ikiwiki suffix to point to the wrapper path given in the setup file.
189         +       # Work with a tempfile to not delete hgrc if the loop is interrupted
190         +       # midway.
191         +       my $hgrc=$config{srcdir}.'/.hg/hgrc';
192         +       my $backup_suffix='.ikiwiki.bak';
193         +       if (-e $hgrc) {
194         +               use File::Spec;
195         +               my $mercurial_wrapper_abspath=File::Spec->rel2abs($config{mercurial_wrapper}, $config{srcdir});
196         +               local ($^I, @ARGV)=($backup_suffix, $hgrc);
197         +               while (<>) {
198         +                       s/^(post-commit|incoming)(\.ikiwiki[ \t]*=[ \t]*).*$/$1$2$mercurial_wrapper_abspath/;
199         +                       print;
200         +               }
201         +               unlink($hgrc.$backup_suffix);
202         +       }
203         +}
204         +
205          1
206
207 `rcs_wrapper_postcall` is made available.
208
209         diff -r b08179653c00 IkiWiki.pm
210         --- a/IkiWiki.pm        Wed Jul 20 16:56:09 2011 +0200
211         +++ b/IkiWiki.pm        Wed Jul 20 19:28:21 2011 +0200
212         @@ -2059,6 +2059,10 @@
213                 $hooks{rcs}{rcs_getmtime}{call}->(@_);
214          }
215          
216         +sub rcs_wrapper_postcall (@) {
217         +       $hooks{rcs}{rcs_wrapper_postcall}{call}->(@_);
218         +}
219         +
220          sub rcs_receive () {
221                 $hooks{rcs}{rcs_receive}{call}->();
222          }
223
224
225 `rcs_wrapper_postcall` is called if $config{wrapper_postcall} is true, which it should only be for Mercurial at the moment.
226
227         diff -r b08179653c00 IkiWiki/Wrapper.pm
228         --- a/IkiWiki/Wrapper.pm        Wed Jul 20 16:56:09 2011 +0200
229         +++ b/IkiWiki/Wrapper.pm        Wed Jul 20 19:28:21 2011 +0200
230         @@ -238,6 +238,10 @@
231                 }
232                 #translators: The parameter is a filename.
233                 debug(sprintf(gettext("successfully generated %s"), $wrapper));
234         +
235         +       if (defined $config{wrapper_postcall} && $config{wrapper_postcall} ) {
236         +               IkiWiki::rcs_wrapper_postcall();
237         +       }
238          }
239          
240          1