hgbook

view fr/ch14-hgext.xml @ 979:64475a75365b

Merged from rpelisse
author Jean-Marie Clément <JeanMarieClement@web.de>
date Fri Sep 04 18:24:06 2009 +0200 (2009-09-04)
parents
children 6f8c48362758
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter>
4 <title>Adding functionality with extensions</title>
5 <para>\label{chap:hgext}</para>
7 <para>While the core of Mercurial is quite complete from a functionality
8 standpoint, it's deliberately shorn of fancy features. This approach
9 of preserving simplicity keeps the software easy to deal with for both
10 maintainers and users.</para>
12 <para>However, Mercurial doesn't box you in with an inflexible command set:
13 you can add features to it as <emphasis>extensions</emphasis> (sometimes known as
14 <emphasis>plugins</emphasis>). We've already discussed a few of these extensions in
15 earlier chapters.</para>
16 <itemizedlist>
17 <listitem><para>Section <xref linkend="sec:tour-merge:fetch"/> covers the <literal role="hg-ext">fetch</literal>
18 extension; this combines pulling new changes and merging them with
19 local changes into a single command, <command role="hg-ext-fetch">fetch</command>.</para>
20 </listitem>
21 <listitem><para>In chapter <xref linkend="chap:hook"/>, we covered several extensions that
22 are useful for hook-related functionality: <literal role="hg-ext">acl</literal> adds access
23 control lists; <literal role="hg-ext">bugzilla</literal> adds integration with the Bugzilla
24 bug tracking system; and <literal role="hg-ext">notify</literal> sends notification emails on
25 new changes.</para>
26 </listitem>
27 <listitem><para>The Mercurial Queues patch management extension is so invaluable
28 that it merits two chapters and an appendix all to itself.
29 Chapter <xref linkend="chap:mq"/> covers the basics;
30 chapter <xref linkend="chap:mq-collab"/> discusses advanced topics; and
31 appendix <xref linkend="chap:mqref"/> goes into detail on each command.</para>
32 </listitem></itemizedlist>
34 <para>In this chapter, we'll cover some of the other extensions that are
35 available for Mercurial, and briefly touch on some of the machinery
36 you'll need to know about if you want to write an extension of your
37 own.</para>
38 <itemizedlist>
39 <listitem><para>In section <xref linkend="sec:hgext:inotify"/>, we'll discuss the
40 possibility of <emphasis>huge</emphasis> performance improvements using the
41 <literal role="hg-ext">inotify</literal> extension.</para>
42 </listitem></itemizedlist>
44 <sect1>
45 <title>Improve performance with the <literal role="hg-ext">inotify</literal> extension</title>
46 <para>\label{sec:hgext:inotify}
47 </para>
49 <para>Are you interested in having some of the most common Mercurial
50 operations run as much as a hundred times faster? Read on!
51 </para>
53 <para>Mercurial has great performance under normal circumstances. For
54 example, when you run the <command role="hg-cmd">hg status</command> command, Mercurial has to
55 scan almost every directory and file in your repository so that it can
56 display file status. Many other Mercurial commands need to do the
57 same work behind the scenes; for example, the <command role="hg-cmd">hg diff</command> command
58 uses the status machinery to avoid doing an expensive comparison
59 operation on files that obviously haven't changed.
60 </para>
62 <para>Because obtaining file status is crucial to good performance, the
63 authors of Mercurial have optimised this code to within an inch of its
64 life. However, there's no avoiding the fact that when you run
65 <command role="hg-cmd">hg status</command>, Mercurial is going to have to perform at least one
66 expensive system call for each managed file to determine whether it's
67 changed since the last time Mercurial checked. For a sufficiently
68 large repository, this can take a long time.
69 </para>
71 <para>To put a number on the magnitude of this effect, I created a
72 repository containing 150,000 managed files. I timed <command role="hg-cmd">hg status</command>
73 as taking ten seconds to run, even when <emphasis>none</emphasis> of those files had
74 been modified.
75 </para>
77 <para>Many modern operating systems contain a file notification facility.
78 If a program signs up to an appropriate service, the operating system
79 will notify it every time a file of interest is created, modified, or
80 deleted. On Linux systems, the kernel component that does this is
81 called <literal>inotify</literal>.
82 </para>
84 <para>Mercurial's <literal role="hg-ext">inotify</literal> extension talks to the kernel's
85 <literal>inotify</literal> component to optimise <command role="hg-cmd">hg status</command> commands. The
86 extension has two components. A daemon sits in the background and
87 receives notifications from the <literal>inotify</literal> subsystem. It also
88 listens for connections from a regular Mercurial command. The
89 extension modifies Mercurial's behaviour so that instead of scanning
90 the filesystem, it queries the daemon. Since the daemon has perfect
91 information about the state of the repository, it can respond with a
92 result instantaneously, avoiding the need to scan every directory and
93 file in the repository.
94 </para>
96 <para>Recall the ten seconds that I measured plain Mercurial as taking to
97 run <command role="hg-cmd">hg status</command> on a 150,000 file repository. With the
98 <literal role="hg-ext">inotify</literal> extension enabled, the time dropped to 0.1 seconds, a
99 factor of <emphasis>one hundred</emphasis> faster.
100 </para>
102 <para>Before we continue, please pay attention to some caveats.
103 </para>
104 <itemizedlist>
105 <listitem><para>The <literal role="hg-ext">inotify</literal> extension is Linux-specific. Because it
106 interfaces directly to the Linux kernel's <literal>inotify</literal>
107 subsystem, it does not work on other operating systems.
108 </para>
109 </listitem>
110 <listitem><para>It should work on any Linux distribution that was released after
111 early 2005. Older distributions are likely to have a kernel that
112 lacks <literal>inotify</literal>, or a version of <literal>glibc</literal> that does not
113 have the necessary interfacing support.
114 </para>
115 </listitem>
116 <listitem><para>Not all filesystems are suitable for use with the
117 <literal role="hg-ext">inotify</literal> extension. Network filesystems such as NFS are a
118 non-starter, for example, particularly if you're running Mercurial
119 on several systems, all mounting the same network filesystem. The
120 kernel's <literal>inotify</literal> system has no way of knowing about changes
121 made on another system. Most local filesystems (e.g. ext3, XFS,
122 ReiserFS) should work fine.
123 </para>
124 </listitem></itemizedlist>
126 <para>The <literal role="hg-ext">inotify</literal> extension is not yet shipped with Mercurial as of
127 May 2007, so it's a little more involved to set up than other
128 extensions. But the performance improvement is worth it!
129 </para>
131 <para>The extension currently comes in two parts: a set of patches to the
132 Mercurial source code, and a library of Python bindings to the
133 <literal>inotify</literal> subsystem.
134 </para>
135 <note>
136 <para> There are <emphasis>two</emphasis> Python <literal>inotify</literal> binding libraries. One
137 of them is called <literal>pyinotify</literal>, and is packaged by some Linux
138 distributions as <literal>python-inotify</literal>. This is <emphasis>not</emphasis> the
139 one you'll need, as it is too buggy and inefficient to be practical.
140 </para>
141 </note>
142 <para>To get going, it's best to already have a functioning copy of
143 Mercurial installed.
144 </para>
145 <note>
146 <para> If you follow the instructions below, you'll be <emphasis>replacing</emphasis> and
147 overwriting any existing installation of Mercurial that you might
148 already have, using the latest <quote>bleeding edge</quote> Mercurial code.
149 Don't say you weren't warned!
150 </para>
151 </note>
152 <orderedlist>
153 <listitem><para>Clone the Python <literal>inotify</literal> binding repository. Build and
154 install it.
155 </para>
156 </listitem><programlisting>
157 <listitem><para> hg clone http://hg.kublai.com/python/inotify
158 cd inotify
159 python setup.py build --force
160 sudo python setup.py install --skip-build
161 </para>
162 </listitem></programlisting>
163 </para>
164 </listitem>
165 <listitem><para>Clone the <filename class="directory">crew</filename> Mercurial repository. Clone the
166 <literal role="hg-ext">inotify</literal> patch repository so that Mercurial Queues will be
167 able to apply patches to your cope of the <filename class="directory">crew</filename> repository.
168 </para>
169 </listitem><programlisting>
170 <listitem><para> hg clone http://hg.intevation.org/mercurial/crew
171 hg clone crew inotify
172 hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches
173 </para>
174 </listitem></programlisting>
175 </para>
176 </listitem>
177 <listitem><para>Make sure that you have the Mercurial Queues extension,
178 <literal role="hg-ext">mq</literal>, enabled. If you've never used MQ, read
179 section <xref linkend="sec:mq:start"/> to get started quickly.
180 </para>
181 </listitem>
182 <listitem><para>Go into the <filename class="directory">inotify</filename> repo, and apply all of the
183 <literal role="hg-ext">inotify</literal> patches using the <option role="hg-ext-mq-cmd-qpush-opt">-a</option> option to
184 the <command role="hg-ext-mq">qpush</command> command.
185 </para>
186 </listitem><programlisting>
187 <listitem><para> cd inotify
188 hg qpush -a
189 </para>
190 </listitem></programlisting>
191 <listitem><para> If you get an error message from <command role="hg-ext-mq">qpush</command>, you should not
192 continue. Instead, ask for help.
193 </para>
194 </listitem>
195 <listitem><para>Build and install the patched version of Mercurial.
196 </para>
197 </listitem><programlisting>
198 <listitem><para> python setup.py build --force
199 sudo python setup.py install --skip-build
200 </para>
201 </listitem></programlisting>
202 </orderedlist>
203 <para>Once you've build a suitably patched version of Mercurial, all you
204 need to do to enable the <literal role="hg-ext">inotify</literal> extension is add an entry to
205 your <filename role="special"> /.hgrc</filename>.
206 </para>
207 <programlisting>
208 <para> [extensions]
209 inotify =
210 </para>
211 </programlisting>
212 <para>When the <literal role="hg-ext">inotify</literal> extension is enabled, Mercurial will
213 automatically and transparently start the status daemon the first time
214 you run a command that needs status in a repository. It runs one
215 status daemon per repository.
216 </para>
218 <para>The status daemon is started silently, and runs in the background. If
219 you look at a list of running processes after you've enabled the
220 <literal role="hg-ext">inotify</literal> extension and run a few commands in different
221 repositories, you'll thus see a few <literal>hg</literal> processes sitting
222 around, waiting for updates from the kernel and queries from
223 Mercurial.
224 </para>
226 <para>The first time you run a Mercurial command in a repository when you
227 have the <literal role="hg-ext">inotify</literal> extension enabled, it will run with about the
228 same performance as a normal Mercurial command. This is because the
229 status daemon needs to perform a normal status scan so that it has a
230 baseline against which to apply later updates from the kernel.
231 However, <emphasis>every</emphasis> subsequent command that does any kind of status
232 check should be noticeably faster on repositories of even fairly
233 modest size. Better yet, the bigger your repository is, the greater a
234 performance advantage you'll see. The <literal role="hg-ext">inotify</literal> daemon makes
235 status operations almost instantaneous on repositories of all sizes!
236 </para>
238 <para>If you like, you can manually start a status daemon using the
239 <command role="hg-ext-inotify">inserve</command> command. This gives you slightly finer
240 control over how the daemon ought to run. This command will of course
241 only be available when the <literal role="hg-ext">inotify</literal> extension is enabled.
242 </para>
244 <para>When you're using the <literal role="hg-ext">inotify</literal> extension, you should notice
245 <emphasis>no difference at all</emphasis> in Mercurial's behaviour, with the sole
246 exception of status-related commands running a whole lot faster than
247 they used to. You should specifically expect that commands will not
248 print different output; neither should they give different results.
249 If either of these situations occurs, please report a bug.
250 </para>
252 </sect1>
253 <sect1>
254 <title>Flexible diff support with the <literal role="hg-ext">extdiff</literal> extension</title>
255 <para>\label{sec:hgext:extdiff}
256 </para>
258 <para>Mercurial's built-in <command role="hg-cmd">hg diff</command> command outputs plaintext unified
259 diffs.
260 <!-- &interaction.extdiff.diff; -->
261 If you would like to use an external tool to display modifications,
262 you'll want to use the <literal role="hg-ext">extdiff</literal> extension. This will let you
263 use, for example, a graphical diff tool.
264 </para>
266 <para>The <literal role="hg-ext">extdiff</literal> extension is bundled with Mercurial, so it's easy
267 to set up. In the <literal role="rc-extensions">extensions</literal> section of your <filename role="special"> /.hgrc</filename>,
268 simply add a one-line entry to enable the extension.
269 </para>
270 <programlisting>
271 <para> [extensions]
272 extdiff =
273 </para>
274 </programlisting>
275 <para>This introduces a command named <command role="hg-ext-extdiff">extdiff</command>, which by
276 default uses your system's <command>diff</command> command to generate a
277 unified diff in the same form as the built-in <command role="hg-cmd">hg diff</command> command.
278 <!-- &interaction.extdiff.extdiff; -->
279 The result won't be exactly the same as with the built-in <command role="hg-cmd">hg diff</command>
280 variations, because the output of <command>diff</command> varies from one
281 system to another, even when passed the same options.
282 </para>
284 <para>As the <quote><literal>making snapshot</literal></quote> lines of output above imply, the
285 <command role="hg-ext-extdiff">extdiff</command> command works by creating two snapshots of
286 your source tree. The first snapshot is of the source revision; the
287 second, of the target revision or working directory. The
288 <command role="hg-ext-extdiff">extdiff</command> command generates these snapshots in a
289 temporary directory, passes the name of each directory to an external
290 diff viewer, then deletes the temporary directory. For efficiency, it
291 only snapshots the directories and files that have changed between the
292 two revisions.
293 </para>
295 <para>Snapshot directory names have the same base name as your repository.
296 If your repository path is <filename class="directory">/quux/bar/foo</filename>, then <filename class="directory">foo</filename>
297 will be the name of each snapshot directory. Each snapshot directory
298 name has its changeset ID appended, if appropriate. If a snapshot is
299 of revision <literal>a631aca1083f</literal>, the directory will be named
300 <filename class="directory">foo.a631aca1083f</filename>. A snapshot of the working directory won't
301 have a changeset ID appended, so it would just be <filename class="directory">foo</filename> in
302 this example. To see what this looks like in practice, look again at
303 the <command role="hg-ext-extdiff">extdiff</command> example above. Notice that the diff has
304 the snapshot directory names embedded in its header.
305 </para>
307 <para>The <command role="hg-ext-extdiff">extdiff</command> command accepts two important options.
308 The <option role="hg-ext-extdiff-cmd-extdiff-opt">-p</option> option lets you choose a program to
309 view differences with, instead of <command>diff</command>. With the
310 <option role="hg-ext-extdiff-cmd-extdiff-opt">-o</option> option, you can change the options that
311 <command role="hg-ext-extdiff">extdiff</command> passes to the program (by default, these
312 options are <quote><literal>-Npru</literal></quote>, which only make sense if you're
313 running <command>diff</command>). In other respects, the
314 <command role="hg-ext-extdiff">extdiff</command> command acts similarly to the built-in
315 <command role="hg-cmd">hg diff</command> command: you use the same option names, syntax, and
316 arguments to specify the revisions you want, the files you want, and
317 so on.
318 </para>
320 <para>As an example, here's how to run the normal system <command>diff</command>
321 command, getting it to generate context diffs (using the
322 <option role="cmd-opt-diff">-c</option> option) instead of unified diffs, and five lines of
323 context instead of the default three (passing <literal>5</literal> as the
324 argument to the <option role="cmd-opt-diff">-C</option> option).
325 <!-- &interaction.extdiff.extdiff-ctx; -->
326 </para>
328 <para>Launching a visual diff tool is just as easy. Here's how to launch
329 the <command>kdiff3</command> viewer.
330 </para>
331 <programlisting>
332 <para> hg extdiff -p kdiff3 -o </quote>
333 </para>
334 </programlisting>
336 <para>If your diff viewing command can't deal with directories, you can
337 easily work around this with a little scripting. For an example of
338 such scripting in action with the <literal role="hg-ext">mq</literal> extension and the
339 <command>interdiff</command> command, see
340 section <xref linkend="mq-collab:tips:interdiff"/>.
341 </para>
343 <sect2>
344 <title>Defining command aliases</title>
346 <para>It can be cumbersome to remember the options to both the
347 <command role="hg-ext-extdiff">extdiff</command> command and the diff viewer you want to use,
348 so the <literal role="hg-ext">extdiff</literal> extension lets you define <emphasis>new</emphasis> commands
349 that will invoke your diff viewer with exactly the right options.
350 </para>
352 <para>All you need to do is edit your <filename role="special"> /.hgrc</filename>, and add a section named
353 <literal role="rc-extdiff">extdiff</literal>. Inside this section, you can define multiple
354 commands. Here's how to add a <literal>kdiff3</literal> command. Once you've
355 defined this, you can type <quote><literal>hg kdiff3</literal></quote> and the
356 <literal role="hg-ext">extdiff</literal> extension will run <command>kdiff3</command> for you.
357 </para>
358 <programlisting>
359 <para> [extdiff]
360 cmd.kdiff3 =
361 </para>
362 </programlisting>
363 <para>If you leave the right hand side of the definition empty, as above,
364 the <literal role="hg-ext">extdiff</literal> extension uses the name of the command you defined
365 as the name of the external program to run. But these names don't
366 have to be the same. Here, we define a command named <quote>\texttt{hg
367 wibble}</quote>, which runs <command>kdiff3</command>.
368 </para>
369 <programlisting>
370 <para> [extdiff]
371 cmd.wibble = kdiff3
372 </para>
373 </programlisting>
375 <para>You can also specify the default options that you want to invoke your
376 diff viewing program with. The prefix to use is <quote><literal>opts.</literal></quote>,
377 followed by the name of the command to which the options apply. This
378 example defines a <quote><literal>hg vimdiff</literal></quote> command that runs the
379 <command>vim</command> editor's <literal>DirDiff</literal> extension.
380 </para>
381 <programlisting>
382 <para> [extdiff]
383 cmd.vimdiff = vim
384 opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'
385 </para>
386 </programlisting>
388 </sect2>
389 </sect1>
390 <sect1>
391 <title>Cherrypicking changes with the <literal role="hg-ext">transplant</literal> extension</title>
392 <para>\label{sec:hgext:transplant}
393 </para>
395 <para>Need to have a long chat with Brendan about this.
396 </para>
398 </sect1>
399 <sect1>
400 <title>Send changes via email with the <literal role="hg-ext">patchbomb</literal> extension</title>
401 <para>\label{sec:hgext:patchbomb}
402 </para>
404 <para>Many projects have a culture of <quote>change review</quote>, in which people
405 send their modifications to a mailing list for others to read and
406 comment on before they commit the final version to a shared
407 repository. Some projects have people who act as gatekeepers; they
408 apply changes from other people to a repository to which those others
409 don't have access.
410 </para>
412 <para>Mercurial makes it easy to send changes over email for review or
413 application, via its <literal role="hg-ext">patchbomb</literal> extension. The extension is so
414 namd because changes are formatted as patches, and it's usual to send
415 one changeset per email message. Sending a long series of changes by
416 email is thus much like <quote>bombing</quote> the recipient's inbox, hence
417 <quote>patchbomb</quote>.
418 </para>
420 <para>As usual, the basic configuration of the <literal role="hg-ext">patchbomb</literal> extension
421 takes just one or two lines in your <filename role="special"> /.hgrc</filename>.
422 </para>
423 <programlisting>
424 <para> [extensions]
425 patchbomb =
426 </para>
427 </programlisting>
428 <para>Once you've enabled the extension, you will have a new command
429 available, named <command role="hg-ext-patchbomb">email</command>.
430 </para>
432 <para>The safest and best way to invoke the <command role="hg-ext-patchbomb">email</command>
433 command is to <emphasis>always</emphasis> run it first with the
434 <option role="hg-ext-patchbomb-cmd-email-opt">-n</option> option. This will show you what the
435 command <emphasis>would</emphasis> send, without actually sending anything. Once
436 you've had a quick glance over the changes and verified that you are
437 sending the right ones, you can rerun the same command, with the
438 <option role="hg-ext-patchbomb-cmd-email-opt">-n</option> option removed.
439 </para>
441 <para>The <command role="hg-ext-patchbomb">email</command> command accepts the same kind of
442 revision syntax as every other Mercurial command. For example, this
443 command will send every revision between 7 and <literal>tip</literal>,
444 inclusive.
445 </para>
446 <programlisting>
447 <para> hg email -n 7:tip
448 </para>
449 </programlisting>
450 <para>You can also specify a <emphasis>repository</emphasis> to compare with. If you
451 provide a repository but no revisions, the <command role="hg-ext-patchbomb">email</command>
452 command will send all revisions in the local repository that are not
453 present in the remote repository. If you additionally specify
454 revisions or a branch name (the latter using the
455 <option role="hg-ext-patchbomb-cmd-email-opt">-b</option> option), this will constrain the
456 revisions sent.
457 </para>
459 <para>It's perfectly safe to run the <command role="hg-ext-patchbomb">email</command> command
460 without the names of the people you want to send to: if you do this,
461 it will just prompt you for those values interactively. (If you're
462 using a Linux or Unix-like system, you should have enhanced
463 <literal>readline</literal>-style editing capabilities when entering those
464 headers, too, which is useful.)
465 </para>
467 <para>When you are sending just one revision, the <command role="hg-ext-patchbomb">email</command>
468 command will by default use the first line of the changeset
469 description as the subject of the single email message it sends.
470 </para>
472 <para>If you send multiple revisions, the <command role="hg-ext-patchbomb">email</command> command
473 will usually send one message per changeset. It will preface the
474 series with an introductory message, in which you should describe the
475 purpose of the series of changes you're sending.
476 </para>
478 <sect2>
479 <title>Changing the behaviour of patchbombs</title>
481 <para>Not every project has exactly the same conventions for sending changes
482 in email; the <literal role="hg-ext">patchbomb</literal> extension tries to accommodate a
483 number of variations through command line options.
484 </para>
485 <itemizedlist>
486 <listitem><para>You can write a subject for the introductory message on the
487 command line using the <option role="hg-ext-patchbomb-cmd-email-opt">-s</option> option. This
488 takes one argument, the text of the subject to use.
489 </para>
490 </listitem>
491 <listitem><para>To change the email address from which the messages originate,
492 use the <option role="hg-ext-patchbomb-cmd-email-opt">-f</option> option. This takes one
493 argument, the email address to use.
494 </para>
495 </listitem>
496 <listitem><para>The default behaviour is to send unified diffs (see
497 section <xref linkend="sec:mq:patch"/> for a description of the format), one per
498 message. You can send a binary bundle instead with the
499 <option role="hg-ext-patchbomb-cmd-email-opt">-b</option> option.
500 </para>
501 </listitem>
502 <listitem><para>Unified diffs are normally prefaced with a metadata header. You
503 can omit this, and send unadorned diffs, with the
504 <option role="hg-ext-patchbomb-cmd-email-opt">--plain</option> option.
505 </para>
506 </listitem>
507 <listitem><para>Diffs are normally sent <quote>inline</quote>, in the same body part as the
508 description of a patch. This makes it easiest for the largest
509 number of readers to quote and respond to parts of a diff, as some
510 mail clients will only quote the first MIME body part in a message.
511 If you'd prefer to send the description and the diff in separate
512 body parts, use the <option role="hg-ext-patchbomb-cmd-email-opt">-a</option> option.
513 </para>
514 </listitem>
515 <listitem><para>Instead of sending mail messages, you can write them to an
516 <literal>mbox</literal>-format mail folder using the
517 <option role="hg-ext-patchbomb-cmd-email-opt">-m</option> option. That option takes one
518 argument, the name of the file to write to.
519 </para>
520 </listitem>
521 <listitem><para>If you would like to add a <command>diffstat</command>-format summary to
522 each patch, and one to the introductory message, use the
523 <option role="hg-ext-patchbomb-cmd-email-opt">-d</option> option. The <command>diffstat</command>
524 command displays a table containing the name of each file patched,
525 the number of lines affected, and a histogram showing how much each
526 file is modified. This gives readers a qualitative glance at how
527 complex a patch is.
528 </para>
529 </listitem></itemizedlist>
531 </sect2>
532 </sect1>
533 </chapter>
535 <!--
536 local variables:
537 sgml-parent-document: ("00book.xml" "book" "chapter")
538 end:
539 -->