hgbook

view en/ch14-hgext.xml @ 629:bae6d1503482

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