hgbook

annotate en/ch10-hook.xml @ 890:2887b61fa4fe

Change fields to fieldsets in the Comment admin model. The 'date'
field isn't working properly for an unknown reason, so it has been
removed from the interface temporarily.
author dukebody <dukebody@gmail.com>
date Sun Oct 11 21:12:46 2009 +0200 (2009-10-11)
parents 477d6a3e5023
children
rev   line source
bos@559 1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
bos@559 2
bos@559 3 <chapter id="chap:hook">
bos@572 4 <?dbhtml filename="handling-repository-events-with-hooks.html"?>
bos@559 5 <title>Handling repository events with hooks</title>
bos@559 6
bos@584 7 <para id="x_1e6">Mercurial offers a powerful mechanism to let you perform
bos@559 8 automated actions in response to events that occur in a
bos@559 9 repository. In some cases, you can even control Mercurial's
bos@559 10 response to those events.</para>
bos@559 11
bos@584 12 <para id="x_1e7">The name Mercurial uses for one of these actions is a
bos@559 13 <emphasis>hook</emphasis>. Hooks are called
bos@559 14 <quote>triggers</quote> in some revision control systems, but the
bos@559 15 two names refer to the same idea.</para>
bos@559 16
bos@559 17 <sect1>
bos@559 18 <title>An overview of hooks in Mercurial</title>
bos@559 19
bos@592 20 <para id="x_1e8">Here is a brief list of the hooks that Mercurial
bos@592 21 supports. We will revisit each of these hooks in more detail
bos@592 22 later, in <xref linkend="sec:hook:ref"/>.</para>
bos@559 23
bos@701 24 <para id="x_1f6">Each of the hooks whose description begins with the word
bos@701 25 <quote>Controlling</quote> has the ability to determine whether
bos@701 26 an activity can proceed. If the hook succeeds, the activity may
bos@701 27 proceed; if it fails, the activity is either not permitted or
bos@701 28 undone, depending on the hook.</para>
bos@701 29
bos@559 30 <itemizedlist>
bos@584 31 <listitem><para id="x_1e9"><literal role="hook">changegroup</literal>: This
bos@559 32 is run after a group of changesets has been brought into the
bos@559 33 repository from elsewhere.</para>
bos@559 34 </listitem>
bos@584 35 <listitem><para id="x_1ea"><literal role="hook">commit</literal>: This is
bos@559 36 run after a new changeset has been created in the local
bos@559 37 repository.</para>
bos@559 38 </listitem>
bos@584 39 <listitem><para id="x_1eb"><literal role="hook">incoming</literal>: This is
bos@559 40 run once for each new changeset that is brought into the
bos@559 41 repository from elsewhere. Notice the difference from
bos@559 42 <literal role="hook">changegroup</literal>, which is run
bos@559 43 once per <emphasis>group</emphasis> of changesets brought
bos@559 44 in.</para>
bos@559 45 </listitem>
bos@584 46 <listitem><para id="x_1ec"><literal role="hook">outgoing</literal>: This is
bos@559 47 run after a group of changesets has been transmitted from
bos@559 48 this repository.</para>
bos@559 49 </listitem>
bos@584 50 <listitem><para id="x_1ed"><literal role="hook">prechangegroup</literal>:
bos@559 51 This is run before starting to bring a group of changesets
bos@559 52 into the repository.
bos@559 53 </para>
bos@559 54 </listitem>
bos@584 55 <listitem><para id="x_1ee"><literal role="hook">precommit</literal>:
bos@559 56 Controlling. This is run before starting a commit.
bos@559 57 </para>
bos@559 58 </listitem>
bos@584 59 <listitem><para id="x_1ef"><literal role="hook">preoutgoing</literal>:
bos@559 60 Controlling. This is run before starting to transmit a group
bos@559 61 of changesets from this repository.
bos@559 62 </para>
bos@559 63 </listitem>
bos@584 64 <listitem><para id="x_1f0"><literal role="hook">pretag</literal>:
bos@559 65 Controlling. This is run before creating a tag.
bos@559 66 </para>
bos@559 67 </listitem>
bos@584 68 <listitem><para id="x_1f1"><literal
bos@559 69 role="hook">pretxnchangegroup</literal>: Controlling. This
bos@559 70 is run after a group of changesets has been brought into the
bos@559 71 local repository from another, but before the transaction
bos@559 72 completes that will make the changes permanent in the
bos@559 73 repository.
bos@559 74 </para>
bos@559 75 </listitem>
bos@584 76 <listitem><para id="x_1f2"><literal role="hook">pretxncommit</literal>:
bos@559 77 Controlling. This is run after a new changeset has been
bos@559 78 created in the local repository, but before the transaction
bos@559 79 completes that will make it permanent.
bos@559 80 </para>
bos@559 81 </listitem>
bos@584 82 <listitem><para id="x_1f3"><literal role="hook">preupdate</literal>:
bos@559 83 Controlling. This is run before starting an update or merge
bos@559 84 of the working directory.
bos@559 85 </para>
bos@559 86 </listitem>
bos@584 87 <listitem><para id="x_1f4"><literal role="hook">tag</literal>: This is run
bos@559 88 after a tag is created.
bos@559 89 </para>
bos@559 90 </listitem>
bos@584 91 <listitem><para id="x_1f5"><literal role="hook">update</literal>: This is
bos@559 92 run after an update or merge of the working directory has
bos@559 93 finished.
bos@559 94 </para>
bos@559 95 </listitem></itemizedlist>
bos@559 96
bos@559 97 </sect1>
bos@559 98 <sect1>
bos@559 99 <title>Hooks and security</title>
bos@559 100
bos@559 101 <sect2>
bos@559 102 <title>Hooks are run with your privileges</title>
bos@559 103
bos@584 104 <para id="x_1f7">When you run a Mercurial command in a repository, and the
bos@559 105 command causes a hook to run, that hook runs on
bos@559 106 <emphasis>your</emphasis> system, under
bos@559 107 <emphasis>your</emphasis> user account, with
bos@559 108 <emphasis>your</emphasis> privilege level. Since hooks are
bos@559 109 arbitrary pieces of executable code, you should treat them
bos@559 110 with an appropriate level of suspicion. Do not install a hook
bos@559 111 unless you are confident that you know who created it and what
bos@559 112 it does.
bos@559 113 </para>
bos@559 114
bos@584 115 <para id="x_1f8">In some cases, you may be exposed to hooks that you did
bos@559 116 not install yourself. If you work with Mercurial on an
bos@559 117 unfamiliar system, Mercurial will run hooks defined in that
bos@580 118 system's global <filename role="special">~/.hgrc</filename>
bos@559 119 file.
bos@559 120 </para>
bos@559 121
bos@584 122 <para id="x_1f9">If you are working with a repository owned by another
bos@559 123 user, Mercurial can run hooks defined in that user's
bos@559 124 repository, but it will still run them as <quote>you</quote>.
bos@559 125 For example, if you <command role="hg-cmd">hg pull</command>
bos@559 126 from that repository, and its <filename
bos@559 127 role="special">.hg/hgrc</filename> defines a local <literal
bos@559 128 role="hook">outgoing</literal> hook, that hook will run
bos@559 129 under your user account, even though you don't own that
bos@559 130 repository.
bos@559 131 </para>
bos@559 132
bos@559 133 <note>
bos@584 134 <para id="x_1fa"> This only applies if you are pulling from a repository
bos@559 135 on a local or network filesystem. If you're pulling over
bos@559 136 http or ssh, any <literal role="hook">outgoing</literal>
bos@559 137 hook will run under whatever account is executing the server
bos@559 138 process, on the server.
bos@559 139 </para>
bos@559 140 </note>
bos@559 141
bos@701 142 <para id="x_1fb">To see what hooks are defined in a repository,
bos@701 143 use the <command role="hg-cmd">hg showconfig hooks</command>
bos@701 144 command. If you are working in one repository, but talking to
bos@701 145 another that you do not own (e.g. using <command
bos@701 146 role="hg-cmd">hg pull</command> or <command role="hg-cmd">hg
bos@559 147 incoming</command>), remember that it is the other
bos@559 148 repository's hooks you should be checking, not your own.
bos@559 149 </para>
bos@682 150 </sect2>
bos@682 151
bos@559 152 <sect2>
bos@559 153 <title>Hooks do not propagate</title>
bos@559 154
bos@584 155 <para id="x_1fc">In Mercurial, hooks are not revision controlled, and do
bos@559 156 not propagate when you clone, or pull from, a repository. The
bos@559 157 reason for this is simple: a hook is a completely arbitrary
bos@559 158 piece of executable code. It runs under your user identity,
bos@559 159 with your privilege level, on your machine.
bos@559 160 </para>
bos@559 161
bos@584 162 <para id="x_1fd">It would be extremely reckless for any distributed
bos@559 163 revision control system to implement revision-controlled
bos@559 164 hooks, as this would offer an easily exploitable way to
bos@559 165 subvert the accounts of users of the revision control system.
bos@559 166 </para>
bos@559 167
bos@584 168 <para id="x_1fe">Since Mercurial does not propagate hooks, if you are
bos@559 169 collaborating with other people on a common project, you
bos@559 170 should not assume that they are using the same Mercurial hooks
bos@559 171 as you are, or that theirs are correctly configured. You
bos@559 172 should document the hooks you expect people to use.
bos@559 173 </para>
bos@559 174
bos@584 175 <para id="x_1ff">In a corporate intranet, this is somewhat easier to
bos@559 176 control, as you can for example provide a
bos@559 177 <quote>standard</quote> installation of Mercurial on an NFS
bos@580 178 filesystem, and use a site-wide <filename role="special">~/.hgrc</filename> file to define hooks that all users will
bos@559 179 see. However, this too has its limits; see below.
bos@559 180 </para>
bos@682 181 </sect2>
bos@682 182
bos@559 183 <sect2>
bos@559 184 <title>Hooks can be overridden</title>
bos@559 185
bos@584 186 <para id="x_200">Mercurial allows you to override a hook definition by
bos@559 187 redefining the hook. You can disable it by setting its value
bos@672 188 to the empty string, or change its behavior as you wish.
bos@559 189 </para>
bos@559 190
bos@584 191 <para id="x_201">If you deploy a system- or site-wide <filename
bos@580 192 role="special">~/.hgrc</filename> file that defines some
bos@559 193 hooks, you should thus understand that your users can disable
bos@559 194 or override those hooks.
bos@559 195 </para>
bos@682 196 </sect2>
bos@682 197
bos@559 198 <sect2>
bos@559 199 <title>Ensuring that critical hooks are run</title>
bos@559 200
bos@584 201 <para id="x_202">Sometimes you may want to enforce a policy that you do not
bos@559 202 want others to be able to work around. For example, you may
bos@559 203 have a requirement that every changeset must pass a rigorous
bos@559 204 set of tests. Defining this requirement via a hook in a
bos@580 205 site-wide <filename role="special">~/.hgrc</filename> won't
bos@559 206 work for remote users on laptops, and of course local users
bos@559 207 can subvert it at will by overriding the hook.
bos@559 208 </para>
bos@559 209
bos@584 210 <para id="x_203">Instead, you can set up your policies for use of Mercurial
bos@559 211 so that people are expected to propagate changes through a
bos@559 212 well-known <quote>canonical</quote> server that you have
bos@559 213 locked down and configured appropriately.
bos@559 214 </para>
bos@559 215
bos@584 216 <para id="x_204">One way to do this is via a combination of social
bos@559 217 engineering and technology. Set up a restricted-access
bos@559 218 account; users can push changes over the network to
bos@559 219 repositories managed by this account, but they cannot log into
bos@559 220 the account and run normal shell commands. In this scenario,
bos@559 221 a user can commit a changeset that contains any old garbage
bos@559 222 they want.
bos@559 223 </para>
bos@559 224
bos@584 225 <para id="x_205">When someone pushes a changeset to the server that
bos@559 226 everyone pulls from, the server will test the changeset before
bos@559 227 it accepts it as permanent, and reject it if it fails to pass
bos@559 228 the test suite. If people only pull changes from this
bos@559 229 filtering server, it will serve to ensure that all changes
bos@559 230 that people pull have been automatically vetted.
bos@559 231 </para>
bos@559 232
bos@559 233 </sect2>
bos@559 234 </sect1>
bos@682 235
bos@559 236 <sect1 id="sec:hook:simple">
bos@559 237 <title>A short tutorial on using hooks</title>
bos@559 238
bos@584 239 <para id="x_212">It is easy to write a Mercurial hook. Let's start with a
bos@559 240 hook that runs when you finish a <command role="hg-cmd">hg
bos@559 241 commit</command>, and simply prints the hash of the changeset
bos@559 242 you just created. The hook is called <literal
bos@559 243 role="hook">commit</literal>.
bos@559 244 </para>
bos@559 245
bos@584 246 <para id="x_213">All hooks follow the pattern in this example.</para>
bos@559 247
bos@567 248 &interaction.hook.simple.init;
bos@559 249
bos@584 250 <para id="x_214">You add an entry to the <literal
bos@559 251 role="rc-hooks">hooks</literal> section of your <filename
bos@580 252 role="special">~/.hgrc</filename>. On the left is the name of
bos@559 253 the event to trigger on; on the right is the action to take. As
bos@559 254 you can see, you can run an arbitrary shell command in a hook.
bos@559 255 Mercurial passes extra information to the hook using environment
bos@559 256 variables (look for <envar>HG_NODE</envar> in the example).
bos@559 257 </para>
bos@559 258
bos@559 259 <sect2>
bos@559 260 <title>Performing multiple actions per event</title>
bos@559 261
bos@584 262 <para id="x_215">Quite often, you will want to define more than one hook
bos@559 263 for a particular kind of event, as shown below.</para>
bos@559 264
bos@567 265 &interaction.hook.simple.ext;
bos@559 266
bos@584 267 <para id="x_216">Mercurial lets you do this by adding an
bos@559 268 <emphasis>extension</emphasis> to the end of a hook's name.
bos@559 269 You extend a hook's name by giving the name of the hook,
bos@559 270 followed by a full stop (the
bos@559 271 <quote><literal>.</literal></quote> character), followed by
bos@559 272 some more text of your choosing. For example, Mercurial will
bos@559 273 run both <literal>commit.foo</literal> and
bos@559 274 <literal>commit.bar</literal> when the
bos@559 275 <literal>commit</literal> event occurs.
bos@559 276 </para>
bos@559 277
bos@584 278 <para id="x_217">To give a well-defined order of execution when there are
bos@559 279 multiple hooks defined for an event, Mercurial sorts hooks by
bos@559 280 extension, and executes the hook commands in this sorted
bos@559 281 order. In the above example, it will execute
bos@559 282 <literal>commit.bar</literal> before
bos@559 283 <literal>commit.foo</literal>, and <literal>commit</literal>
bos@559 284 before both.
bos@559 285 </para>
bos@559 286
bos@592 287 <para id="x_218">It is a good idea to use a somewhat descriptive
bos@592 288 extension when you define a new hook. This will help you to
bos@592 289 remember what the hook was for. If the hook fails, you'll get
bos@592 290 an error message that contains the hook name and extension, so
bos@592 291 using a descriptive extension could give you an immediate hint
bos@592 292 as to why the hook failed (see <xref
bos@559 293 linkend="sec:hook:perm"/> for an example).
bos@559 294 </para>
bos@559 295
bos@559 296 </sect2>
bos@559 297 <sect2 id="sec:hook:perm">
bos@559 298 <title>Controlling whether an activity can proceed</title>
bos@559 299
bos@584 300 <para id="x_219">In our earlier examples, we used the <literal
bos@559 301 role="hook">commit</literal> hook, which is run after a
bos@559 302 commit has completed. This is one of several Mercurial hooks
bos@559 303 that run after an activity finishes. Such hooks have no way
bos@559 304 of influencing the activity itself.
bos@559 305 </para>
bos@559 306
bos@584 307 <para id="x_21a">Mercurial defines a number of events that occur before an
bos@559 308 activity starts; or after it starts, but before it finishes.
bos@559 309 Hooks that trigger on these events have the added ability to
bos@559 310 choose whether the activity can continue, or will abort.
bos@559 311 </para>
bos@559 312
bos@584 313 <para id="x_21b">The <literal role="hook">pretxncommit</literal> hook runs
bos@559 314 after a commit has all but completed. In other words, the
bos@559 315 metadata representing the changeset has been written out to
bos@559 316 disk, but the transaction has not yet been allowed to
bos@559 317 complete. The <literal role="hook">pretxncommit</literal>
bos@559 318 hook has the ability to decide whether the transaction can
bos@559 319 complete, or must be rolled back.
bos@559 320 </para>
bos@559 321
bos@584 322 <para id="x_21c">If the <literal role="hook">pretxncommit</literal> hook
bos@559 323 exits with a status code of zero, the transaction is allowed
bos@559 324 to complete; the commit finishes; and the <literal
bos@559 325 role="hook">commit</literal> hook is run. If the <literal
bos@559 326 role="hook">pretxncommit</literal> hook exits with a
bos@559 327 non-zero status code, the transaction is rolled back; the
bos@559 328 metadata representing the changeset is erased; and the
bos@559 329 <literal role="hook">commit</literal> hook is not run.
bos@559 330 </para>
bos@559 331
bos@567 332 &interaction.hook.simple.pretxncommit;
bos@559 333
bos@584 334 <para id="x_21d">The hook in the example above checks that a commit comment
bos@559 335 contains a bug ID. If it does, the commit can complete. If
bos@559 336 not, the commit is rolled back.
bos@559 337 </para>
bos@559 338
bos@559 339 </sect2>
bos@559 340 </sect1>
bos@559 341 <sect1>
bos@559 342 <title>Writing your own hooks</title>
bos@559 343
bos@584 344 <para id="x_21e">When you are writing a hook, you might find it useful to run
bos@559 345 Mercurial either with the <option
bos@559 346 role="hg-opt-global">-v</option> option, or the <envar
bos@559 347 role="rc-item-ui">verbose</envar> config item set to
bos@559 348 <quote>true</quote>. When you do so, Mercurial will print a
bos@559 349 message before it calls each hook.
bos@559 350 </para>
bos@559 351
bos@559 352 <sect2 id="sec:hook:lang">
bos@559 353 <title>Choosing how your hook should run</title>
bos@559 354
bos@584 355 <para id="x_21f">You can write a hook either as a normal
bos@559 356 program&emdash;typically a shell script&emdash;or as a Python
bos@559 357 function that is executed within the Mercurial process.
bos@559 358 </para>
bos@559 359
bos@584 360 <para id="x_220">Writing a hook as an external program has the advantage
bos@559 361 that it requires no knowledge of Mercurial's internals. You
bos@559 362 can call normal Mercurial commands to get any added
bos@559 363 information you need. The trade-off is that external hooks
bos@559 364 are slower than in-process hooks.
bos@559 365 </para>
bos@559 366
bos@584 367 <para id="x_221">An in-process Python hook has complete access to the
bos@559 368 Mercurial API, and does not <quote>shell out</quote> to
bos@559 369 another process, so it is inherently faster than an external
bos@559 370 hook. It is also easier to obtain much of the information
bos@559 371 that a hook requires by using the Mercurial API than by
bos@559 372 running Mercurial commands.
bos@559 373 </para>
bos@559 374
bos@584 375 <para id="x_222">If you are comfortable with Python, or require high
bos@559 376 performance, writing your hooks in Python may be a good
bos@559 377 choice. However, when you have a straightforward hook to
bos@559 378 write and you don't need to care about performance (probably
bos@559 379 the majority of hooks), a shell script is perfectly fine.
bos@559 380 </para>
bos@559 381
bos@559 382 </sect2>
bos@559 383 <sect2 id="sec:hook:param">
bos@559 384 <title>Hook parameters</title>
bos@559 385
bos@584 386 <para id="x_223">Mercurial calls each hook with a set of well-defined
bos@559 387 parameters. In Python, a parameter is passed as a keyword
bos@559 388 argument to your hook function. For an external program, a
bos@559 389 parameter is passed as an environment variable.
bos@559 390 </para>
bos@559 391
bos@584 392 <para id="x_224">Whether your hook is written in Python or as a shell
bos@559 393 script, the hook-specific parameter names and values will be
bos@559 394 the same. A boolean parameter will be represented as a
bos@559 395 boolean value in Python, but as the number 1 (for
bos@559 396 <quote>true</quote>) or 0 (for <quote>false</quote>) as an
bos@559 397 environment variable for an external hook. If a hook
bos@559 398 parameter is named <literal>foo</literal>, the keyword
bos@559 399 argument for a Python hook will also be named
bos@559 400 <literal>foo</literal>, while the environment variable for an
bos@559 401 external hook will be named <literal>HG_FOO</literal>.
bos@559 402 </para>
bos@682 403 </sect2>
bos@682 404
bos@559 405 <sect2>
bos@559 406 <title>Hook return values and activity control</title>
bos@559 407
bos@584 408 <para id="x_225">A hook that executes successfully must exit with a status
bos@559 409 of zero if external, or return boolean <quote>false</quote> if
bos@559 410 in-process. Failure is indicated with a non-zero exit status
bos@559 411 from an external hook, or an in-process hook returning boolean
bos@559 412 <quote>true</quote>. If an in-process hook raises an
bos@559 413 exception, the hook is considered to have failed.
bos@559 414 </para>
bos@559 415
bos@584 416 <para id="x_226">For a hook that controls whether an activity can proceed,
bos@559 417 zero/false means <quote>allow</quote>, while
bos@559 418 non-zero/true/exception means <quote>deny</quote>.
bos@559 419 </para>
bos@682 420 </sect2>
bos@682 421
bos@559 422 <sect2>
bos@559 423 <title>Writing an external hook</title>
bos@559 424
bos@584 425 <para id="x_227">When you define an external hook in your <filename
bos@580 426 role="special">~/.hgrc</filename> and the hook is run, its
bos@559 427 value is passed to your shell, which interprets it. This
bos@559 428 means that you can use normal shell constructs in the body of
bos@559 429 the hook.
bos@559 430 </para>
bos@559 431
bos@584 432 <para id="x_228">An executable hook is always run with its current
bos@559 433 directory set to a repository's root directory.
bos@559 434 </para>
bos@559 435
bos@584 436 <para id="x_229">Each hook parameter is passed in as an environment
bos@559 437 variable; the name is upper-cased, and prefixed with the
bos@559 438 string <quote><literal>HG_</literal></quote>.
bos@559 439 </para>
bos@559 440
bos@584 441 <para id="x_22a">With the exception of hook parameters, Mercurial does not
bos@559 442 set or modify any environment variables when running a hook.
bos@559 443 This is useful to remember if you are writing a site-wide hook
bos@559 444 that may be run by a number of different users with differing
bos@559 445 environment variables set. In multi-user situations, you
bos@559 446 should not rely on environment variables being set to the
bos@559 447 values you have in your environment when testing the hook.
bos@559 448 </para>
bos@682 449 </sect2>
bos@682 450
bos@559 451 <sect2>
bos@559 452 <title>Telling Mercurial to use an in-process hook</title>
bos@559 453
bos@584 454 <para id="x_22b">The <filename role="special">~/.hgrc</filename> syntax
bos@559 455 for defining an in-process hook is slightly different than for
bos@559 456 an executable hook. The value of the hook must start with the
bos@559 457 text <quote><literal>python:</literal></quote>, and continue
bos@559 458 with the fully-qualified name of a callable object to use as
bos@559 459 the hook's value.
bos@559 460 </para>
bos@559 461
bos@584 462 <para id="x_22c">The module in which a hook lives is automatically imported
bos@559 463 when a hook is run. So long as you have the module name and
bos@559 464 <envar>PYTHONPATH</envar> right, it should <quote>just
bos@559 465 work</quote>.
bos@559 466 </para>
bos@559 467
bos@584 468 <para id="x_22d">The following <filename role="special">~/.hgrc</filename>
bos@559 469 example snippet illustrates the syntax and meaning of the
bos@559 470 notions we just described.
bos@559 471 </para>
bos@580 472 <programlisting>[hooks]
bos@580 473 commit.example = python:mymodule.submodule.myhook</programlisting>
bos@584 474 <para id="x_22e">When Mercurial runs the <literal>commit.example</literal>
bos@559 475 hook, it imports <literal>mymodule.submodule</literal>, looks
bos@559 476 for the callable object named <literal>myhook</literal>, and
bos@559 477 calls it.
bos@559 478 </para>
bos@682 479 </sect2>
bos@682 480
bos@559 481 <sect2>
bos@559 482 <title>Writing an in-process hook</title>
bos@559 483
bos@584 484 <para id="x_22f">The simplest in-process hook does nothing, but illustrates
bos@559 485 the basic shape of the hook API:
bos@559 486 </para>
bos@559 487 <programlisting>def myhook(ui, repo, **kwargs):
bos@580 488 pass</programlisting>
bos@584 489 <para id="x_230">The first argument to a Python hook is always a <literal
bos@559 490 role="py-mod-mercurial.ui">ui</literal> object. The second
bos@559 491 is a repository object; at the moment, it is always an
bos@559 492 instance of <literal
bos@559 493 role="py-mod-mercurial.localrepo">localrepository</literal>.
bos@559 494 Following these two arguments are other keyword arguments.
bos@559 495 Which ones are passed in depends on the hook being called, but
bos@559 496 a hook can ignore arguments it doesn't care about by dropping
bos@559 497 them into a keyword argument dict, as with
bos@559 498 <literal>**kwargs</literal> above.
bos@559 499 </para>
bos@559 500
bos@559 501 </sect2>
bos@559 502 </sect1>
bos@559 503 <sect1>
bos@559 504 <title>Some hook examples</title>
bos@559 505
bos@559 506 <sect2>
bos@559 507 <title>Writing meaningful commit messages</title>
bos@559 508
bos@584 509 <para id="x_231">It's hard to imagine a useful commit message being very
bos@559 510 short. The simple <literal role="hook">pretxncommit</literal>
bos@559 511 hook of the example below will prevent you from committing a
bos@559 512 changeset with a message that is less than ten bytes long.
bos@559 513 </para>
bos@559 514
bos@567 515 &interaction.hook.msglen.go;
bos@682 516 </sect2>
bos@682 517
bos@559 518 <sect2>
bos@559 519 <title>Checking for trailing whitespace</title>
bos@559 520
bos@584 521 <para id="x_232">An interesting use of a commit-related hook is to help you
bos@559 522 to write cleaner code. A simple example of <quote>cleaner
bos@559 523 code</quote> is the dictum that a change should not add any
bos@559 524 new lines of text that contain <quote>trailing
bos@559 525 whitespace</quote>. Trailing whitespace is a series of
bos@559 526 space and tab characters at the end of a line of text. In
bos@559 527 most cases, trailing whitespace is unnecessary, invisible
bos@559 528 noise, but it is occasionally problematic, and people often
bos@559 529 prefer to get rid of it.
bos@559 530 </para>
bos@559 531
bos@584 532 <para id="x_233">You can use either the <literal
bos@559 533 role="hook">precommit</literal> or <literal
bos@559 534 role="hook">pretxncommit</literal> hook to tell whether you
bos@559 535 have a trailing whitespace problem. If you use the <literal
bos@559 536 role="hook">precommit</literal> hook, the hook will not know
bos@559 537 which files you are committing, so it will have to check every
bos@559 538 modified file in the repository for trailing white space. If
bos@559 539 you want to commit a change to just the file
bos@559 540 <filename>foo</filename>, but the file
bos@559 541 <filename>bar</filename> contains trailing whitespace, doing a
bos@559 542 check in the <literal role="hook">precommit</literal> hook
bos@559 543 will prevent you from committing <filename>foo</filename> due
bos@559 544 to the problem with <filename>bar</filename>. This doesn't
bos@559 545 seem right.
bos@559 546 </para>
bos@559 547
bos@584 548 <para id="x_234">Should you choose the <literal
bos@559 549 role="hook">pretxncommit</literal> hook, the check won't
bos@559 550 occur until just before the transaction for the commit
bos@559 551 completes. This will allow you to check for problems only the
bos@559 552 exact files that are being committed. However, if you entered
bos@559 553 the commit message interactively and the hook fails, the
bos@559 554 transaction will roll back; you'll have to re-enter the commit
bos@559 555 message after you fix the trailing whitespace and run <command
bos@559 556 role="hg-cmd">hg commit</command> again.
bos@559 557 </para>
bos@559 558
bos@694 559 &interaction.ch09-hook.ws.simple;
bos@559 560
bos@584 561 <para id="x_235">In this example, we introduce a simple <literal
bos@559 562 role="hook">pretxncommit</literal> hook that checks for
bos@559 563 trailing whitespace. This hook is short, but not very
bos@559 564 helpful. It exits with an error status if a change adds a
bos@559 565 line with trailing whitespace to any file, but does not print
bos@559 566 any information that might help us to identify the offending
bos@559 567 file or line. It also has the nice property of not paying
bos@559 568 attention to unmodified lines; only lines that introduce new
bos@559 569 trailing whitespace cause problems.
bos@559 570 </para>
bos@559 571
bos@694 572 &ch09-check_whitespace.py.lst;
bos@694 573
bos@584 574 <para id="x_236">The above version is much more complex, but also more
bos@559 575 useful. It parses a unified diff to see if any lines add
bos@559 576 trailing whitespace, and prints the name of the file and the
bos@559 577 line number of each such occurrence. Even better, if the
bos@559 578 change adds trailing whitespace, this hook saves the commit
bos@559 579 comment and prints the name of the save file before exiting
bos@559 580 and telling Mercurial to roll the transaction back, so you can
bos@559 581 use the <option role="hg-opt-commit">-l filename</option>
bos@559 582 option to <command role="hg-cmd">hg commit</command> to reuse
bos@559 583 the saved commit message once you've corrected the problem.
bos@559 584 </para>
bos@559 585
bos@694 586 &interaction.ch09-hook.ws.better;
bos@559 587
bos@701 588 <para id="x_237">As a final aside, note in the example above the
bos@701 589 use of <command>sed</command>'s in-place editing feature to
bos@701 590 get rid of trailing whitespace from a file. This is concise
bos@701 591 and useful enough that I will reproduce it here (using
bos@701 592 <command>perl</command> for good measure).</para>
bos@559 593 <programlisting>perl -pi -e 's,\s+$,,' filename</programlisting>
bos@559 594
bos@559 595 </sect2>
bos@559 596 </sect1>
bos@559 597 <sect1>
bos@559 598 <title>Bundled hooks</title>
bos@559 599
bos@584 600 <para id="x_238">Mercurial ships with several bundled hooks. You can find
bos@559 601 them in the <filename class="directory">hgext</filename>
bos@559 602 directory of a Mercurial source tree. If you are using a
bos@559 603 Mercurial binary package, the hooks will be located in the
bos@559 604 <filename class="directory">hgext</filename> directory of
bos@559 605 wherever your package installer put Mercurial.
bos@559 606 </para>
bos@559 607
bos@559 608 <sect2>
bos@559 609 <title><literal role="hg-ext">acl</literal>&emdash;access
bos@559 610 control for parts of a repository</title>
bos@559 611
bos@584 612 <para id="x_239">The <literal role="hg-ext">acl</literal> extension lets
bos@559 613 you control which remote users are allowed to push changesets
bos@559 614 to a networked server. You can protect any portion of a
bos@559 615 repository (including the entire repo), so that a specific
bos@559 616 remote user can push changes that do not affect the protected
bos@559 617 portion.
bos@559 618 </para>
bos@559 619
bos@584 620 <para id="x_23a">This extension implements access control based on the
bos@559 621 identity of the user performing a push,
bos@559 622 <emphasis>not</emphasis> on who committed the changesets
bos@559 623 they're pushing. It makes sense to use this hook only if you
bos@559 624 have a locked-down server environment that authenticates
bos@559 625 remote users, and you want to be sure that only specific users
bos@559 626 are allowed to push changes to that server.
bos@559 627 </para>
bos@559 628
bos@559 629 <sect3>
bos@559 630 <title>Configuring the <literal role="hook">acl</literal>
bos@559 631 hook</title>
bos@559 632
bos@584 633 <para id="x_23b">In order to manage incoming changesets, the <literal
bos@559 634 role="hg-ext">acl</literal> hook must be used as a
bos@559 635 <literal role="hook">pretxnchangegroup</literal> hook. This
bos@559 636 lets it see which files are modified by each incoming
bos@559 637 changeset, and roll back a group of changesets if they
bos@559 638 modify <quote>forbidden</quote> files. Example:
bos@559 639 </para>
bos@580 640 <programlisting>[hooks]
bos@580 641 pretxnchangegroup.acl = python:hgext.acl.hook</programlisting>
bos@559 642
bos@584 643 <para id="x_23c">The <literal role="hg-ext">acl</literal> extension is
bos@559 644 configured using three sections.
bos@559 645 </para>
bos@559 646
bos@584 647 <para id="x_23d">The <literal role="rc-acl">acl</literal> section has
bos@559 648 only one entry, <envar role="rc-item-acl">sources</envar>,
bos@559 649 which lists the sources of incoming changesets that the hook
bos@559 650 should pay attention to. You don't normally need to
bos@559 651 configure this section.
bos@559 652 </para>
bos@559 653 <itemizedlist>
bos@584 654 <listitem><para id="x_23e"><envar role="rc-item-acl">serve</envar>:
bos@559 655 Control incoming changesets that are arriving from a
bos@559 656 remote repository over http or ssh. This is the default
bos@559 657 value of <envar role="rc-item-acl">sources</envar>, and
bos@559 658 usually the only setting you'll need for this
bos@559 659 configuration item.
bos@559 660 </para>
bos@559 661 </listitem>
bos@584 662 <listitem><para id="x_23f"><envar role="rc-item-acl">pull</envar>:
bos@559 663 Control incoming changesets that are arriving via a pull
bos@559 664 from a local repository.
bos@559 665 </para>
bos@559 666 </listitem>
bos@584 667 <listitem><para id="x_240"><envar role="rc-item-acl">push</envar>:
bos@559 668 Control incoming changesets that are arriving via a push
bos@559 669 from a local repository.
bos@559 670 </para>
bos@559 671 </listitem>
bos@584 672 <listitem><para id="x_241"><envar role="rc-item-acl">bundle</envar>:
bos@559 673 Control incoming changesets that are arriving from
bos@559 674 another repository via a bundle.
bos@559 675 </para>
bos@559 676 </listitem></itemizedlist>
bos@559 677
bos@584 678 <para id="x_242">The <literal role="rc-acl.allow">acl.allow</literal>
bos@559 679 section controls the users that are allowed to add
bos@559 680 changesets to the repository. If this section is not
bos@559 681 present, all users that are not explicitly denied are
bos@559 682 allowed. If this section is present, all users that are not
bos@559 683 explicitly allowed are denied (so an empty section means
bos@559 684 that all users are denied).
bos@559 685 </para>
bos@559 686
bos@584 687 <para id="x_243">The <literal role="rc-acl.deny">acl.deny</literal>
bos@559 688 section determines which users are denied from adding
bos@559 689 changesets to the repository. If this section is not
bos@559 690 present or is empty, no users are denied.
bos@559 691 </para>
bos@559 692
bos@584 693 <para id="x_244">The syntaxes for the <literal
bos@559 694 role="rc-acl.allow">acl.allow</literal> and <literal
bos@559 695 role="rc-acl.deny">acl.deny</literal> sections are
bos@559 696 identical. On the left of each entry is a glob pattern that
bos@559 697 matches files or directories, relative to the root of the
bos@559 698 repository; on the right, a user name.
bos@559 699 </para>
bos@559 700
bos@584 701 <para id="x_245">In the following example, the user
bos@559 702 <literal>docwriter</literal> can only push changes to the
bos@559 703 <filename class="directory">docs</filename> subtree of the
bos@559 704 repository, while <literal>intern</literal> can push changes
bos@559 705 to any file or directory except <filename
bos@559 706 class="directory">source/sensitive</filename>.
bos@559 707 </para>
bos@580 708 <programlisting>[acl.allow]
bos@580 709 docs/** = docwriter
bos@580 710 [acl.deny]
bos@580 711 source/sensitive/** = intern</programlisting>
bos@559 712
bos@559 713 </sect3>
bos@559 714 <sect3>
bos@559 715 <title>Testing and troubleshooting</title>
bos@559 716
bos@584 717 <para id="x_246">If you want to test the <literal
bos@559 718 role="hg-ext">acl</literal> hook, run it with Mercurial's
bos@559 719 debugging output enabled. Since you'll probably be running
bos@559 720 it on a server where it's not convenient (or sometimes
bos@559 721 possible) to pass in the <option
bos@559 722 role="hg-opt-global">--debug</option> option, don't forget
bos@559 723 that you can enable debugging output in your <filename
bos@580 724 role="special">~/.hgrc</filename>:
bos@580 725 </para>
bos@580 726 <programlisting>[ui]
bos@580 727 debug = true</programlisting>
bos@584 728 <para id="x_247">With this enabled, the <literal
bos@559 729 role="hg-ext">acl</literal> hook will print enough
bos@559 730 information to let you figure out why it is allowing or
bos@559 731 forbidding pushes from specific users.
bos@559 732 </para>
bos@559 733
bos@682 734 </sect3> </sect2>
bos@682 735
bos@559 736 <sect2>
bos@559 737 <title><literal
bos@559 738 role="hg-ext">bugzilla</literal>&emdash;integration with
bos@559 739 Bugzilla</title>
bos@559 740
bos@584 741 <para id="x_248">The <literal role="hg-ext">bugzilla</literal> extension
bos@559 742 adds a comment to a Bugzilla bug whenever it finds a reference
bos@559 743 to that bug ID in a commit comment. You can install this hook
bos@559 744 on a shared server, so that any time a remote user pushes
bos@559 745 changes to this server, the hook gets run.
bos@559 746 </para>
bos@559 747
bos@584 748 <para id="x_249">It adds a comment to the bug that looks like this (you can
bos@559 749 configure the contents of the comment&emdash;see below):
bos@559 750 </para>
bos@559 751 <programlisting>Changeset aad8b264143a, made by Joe User
bos@559 752 &lt;joe.user@domain.com&gt; in the frobnitz repository, refers
bos@559 753 to this bug. For complete details, see
bos@559 754 http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a
bos@559 755 Changeset description: Fix bug 10483 by guarding against some
bos@559 756 NULL pointers</programlisting>
bos@584 757 <para id="x_24a">The value of this hook is that it automates the process of
bos@559 758 updating a bug any time a changeset refers to it. If you
bos@559 759 configure the hook properly, it makes it easy for people to
bos@559 760 browse straight from a Bugzilla bug to a changeset that refers
bos@559 761 to that bug.
bos@559 762 </para>
bos@559 763
bos@584 764 <para id="x_24b">You can use the code in this hook as a starting point for
bos@559 765 some more exotic Bugzilla integration recipes. Here are a few
bos@559 766 possibilities:
bos@559 767 </para>
bos@559 768 <itemizedlist>
bos@584 769 <listitem><para id="x_24c">Require that every changeset pushed to the
bos@559 770 server have a valid bug ID in its commit comment. In this
bos@559 771 case, you'd want to configure the hook as a <literal
bos@559 772 role="hook">pretxncommit</literal> hook. This would
bos@559 773 allow the hook to reject changes that didn't contain bug
bos@559 774 IDs.
bos@559 775 </para>
bos@559 776 </listitem>
bos@584 777 <listitem><para id="x_24d">Allow incoming changesets to automatically
bos@559 778 modify the <emphasis>state</emphasis> of a bug, as well as
bos@559 779 simply adding a comment. For example, the hook could
bos@559 780 recognise the string <quote>fixed bug 31337</quote> as
bos@559 781 indicating that it should update the state of bug 31337 to
bos@559 782 <quote>requires testing</quote>.
bos@559 783 </para>
bos@559 784 </listitem></itemizedlist>
bos@559 785
bos@559 786 <sect3 id="sec:hook:bugzilla:config">
bos@559 787 <title>Configuring the <literal role="hook">bugzilla</literal>
bos@559 788 hook</title>
bos@559 789
bos@584 790 <para id="x_24e">You should configure this hook in your server's
bos@580 791 <filename role="special">~/.hgrc</filename> as an <literal
bos@559 792 role="hook">incoming</literal> hook, for example as
bos@559 793 follows:
bos@559 794 </para>
bos@580 795 <programlisting>[hooks]
bos@580 796 incoming.bugzilla = python:hgext.bugzilla.hook</programlisting>
bos@559 797
bos@584 798 <para id="x_24f">Because of the specialised nature of this hook, and
bos@559 799 because Bugzilla was not written with this kind of
bos@559 800 integration in mind, configuring this hook is a somewhat
bos@559 801 involved process.
bos@559 802 </para>
bos@559 803
bos@584 804 <para id="x_250">Before you begin, you must install the MySQL bindings
bos@559 805 for Python on the host(s) where you'll be running the hook.
bos@559 806 If this is not available as a binary package for your
bos@559 807 system, you can download it from
bos@559 808 <citation>web:mysql-python</citation>.
bos@559 809 </para>
bos@559 810
bos@584 811 <para id="x_251">Configuration information for this hook lives in the
bos@559 812 <literal role="rc-bugzilla">bugzilla</literal> section of
bos@580 813 your <filename role="special">~/.hgrc</filename>.
bos@559 814 </para>
bos@559 815 <itemizedlist>
bos@584 816 <listitem><para id="x_252"><envar
bos@559 817 role="rc-item-bugzilla">version</envar>: The version
bos@559 818 of Bugzilla installed on the server. The database
bos@559 819 schema that Bugzilla uses changes occasionally, so this
bos@701 820 hook has to know exactly which schema to use.</para>
bos@559 821 </listitem>
bos@584 822 <listitem><para id="x_253"><envar role="rc-item-bugzilla">host</envar>:
bos@559 823 The hostname of the MySQL server that stores your
bos@559 824 Bugzilla data. The database must be configured to allow
bos@559 825 connections from whatever host you are running the
bos@559 826 <literal role="hook">bugzilla</literal> hook on.
bos@559 827 </para>
bos@559 828 </listitem>
bos@584 829 <listitem><para id="x_254"><envar role="rc-item-bugzilla">user</envar>:
bos@559 830 The username with which to connect to the MySQL server.
bos@559 831 The database must be configured to allow this user to
bos@559 832 connect from whatever host you are running the <literal
bos@559 833 role="hook">bugzilla</literal> hook on. This user
bos@559 834 must be able to access and modify Bugzilla tables. The
bos@559 835 default value of this item is <literal>bugs</literal>,
bos@559 836 which is the standard name of the Bugzilla user in a
bos@559 837 MySQL database.
bos@559 838 </para>
bos@559 839 </listitem>
bos@584 840 <listitem><para id="x_255"><envar
bos@559 841 role="rc-item-bugzilla">password</envar>: The MySQL
bos@559 842 password for the user you configured above. This is
bos@559 843 stored as plain text, so you should make sure that
bos@559 844 unauthorised users cannot read the <filename
bos@580 845 role="special">~/.hgrc</filename> file where you
bos@559 846 store this information.
bos@559 847 </para>
bos@559 848 </listitem>
bos@584 849 <listitem><para id="x_256"><envar role="rc-item-bugzilla">db</envar>:
bos@559 850 The name of the Bugzilla database on the MySQL server.
bos@559 851 The default value of this item is
bos@559 852 <literal>bugs</literal>, which is the standard name of
bos@559 853 the MySQL database where Bugzilla stores its data.
bos@559 854 </para>
bos@559 855 </listitem>
bos@584 856 <listitem><para id="x_257"><envar
bos@559 857 role="rc-item-bugzilla">notify</envar>: If you want
bos@559 858 Bugzilla to send out a notification email to subscribers
bos@559 859 after this hook has added a comment to a bug, you will
bos@559 860 need this hook to run a command whenever it updates the
bos@559 861 database. The command to run depends on where you have
bos@559 862 installed Bugzilla, but it will typically look something
bos@559 863 like this, if you have Bugzilla installed in <filename
bos@559 864 class="directory">/var/www/html/bugzilla</filename>:
bos@559 865 </para>
bos@559 866 <programlisting>cd /var/www/html/bugzilla &amp;&amp;
bos@559 867 ./processmail %s nobody@nowhere.com</programlisting>
bos@559 868 </listitem>
bos@584 869 <listitem><para id="x_258"> The Bugzilla
bos@559 870 <literal>processmail</literal> program expects to be
bos@559 871 given a bug ID (the hook replaces
bos@559 872 <quote><literal>%s</literal></quote> with the bug ID)
bos@559 873 and an email address. It also expects to be able to
bos@559 874 write to some files in the directory that it runs in.
bos@559 875 If Bugzilla and this hook are not installed on the same
bos@559 876 machine, you will need to find a way to run
bos@559 877 <literal>processmail</literal> on the server where
bos@559 878 Bugzilla is installed.
bos@559 879 </para>
bos@559 880 </listitem></itemizedlist>
bos@559 881
bos@559 882 </sect3>
bos@559 883 <sect3>
bos@559 884 <title>Mapping committer names to Bugzilla user names</title>
bos@559 885
bos@584 886 <para id="x_259">By default, the <literal
bos@559 887 role="hg-ext">bugzilla</literal> hook tries to use the
bos@559 888 email address of a changeset's committer as the Bugzilla
bos@559 889 user name with which to update a bug. If this does not suit
bos@559 890 your needs, you can map committer email addresses to
bos@559 891 Bugzilla user names using a <literal
bos@559 892 role="rc-usermap">usermap</literal> section.
bos@559 893 </para>
bos@559 894
bos@584 895 <para id="x_25a">Each item in the <literal
bos@559 896 role="rc-usermap">usermap</literal> section contains an
bos@559 897 email address on the left, and a Bugzilla user name on the
bos@559 898 right.
bos@559 899 </para>
bos@580 900 <programlisting>[usermap]
bos@580 901 jane.user@example.com = jane</programlisting>
bos@584 902 <para id="x_25b">You can either keep the <literal
bos@559 903 role="rc-usermap">usermap</literal> data in a normal
bos@559 904 <filename role="special">~/.hgrc</filename>, or tell the
bos@559 905 <literal role="hg-ext">bugzilla</literal> hook to read the
bos@559 906 information from an external <filename>usermap</filename>
bos@559 907 file. In the latter case, you can store
bos@559 908 <filename>usermap</filename> data by itself in (for example)
bos@559 909 a user-modifiable repository. This makes it possible to let
bos@559 910 your users maintain their own <envar
bos@559 911 role="rc-item-bugzilla">usermap</envar> entries. The main
bos@580 912 <filename role="special">~/.hgrc</filename> file might look
bos@559 913 like this:
bos@559 914 </para>
bos@580 915 <programlisting># regular hgrc file refers to external usermap file
bos@580 916 [bugzilla]
bos@580 917 usermap = /home/hg/repos/userdata/bugzilla-usermap.conf</programlisting>
bos@584 918 <para id="x_25c">While the <filename>usermap</filename> file that it
bos@559 919 refers to might look like this:
bos@559 920 </para>
bos@580 921 <programlisting># bugzilla-usermap.conf - inside a hg repository
bos@580 922 [usermap] stephanie@example.com = steph</programlisting>
bos@559 923
bos@559 924 </sect3>
bos@559 925 <sect3>
bos@559 926 <title>Configuring the text that gets added to a bug</title>
bos@559 927
bos@584 928 <para id="x_25d">You can configure the text that this hook adds as a
bos@559 929 comment; you specify it in the form of a Mercurial template.
bos@580 930 Several <filename role="special">~/.hgrc</filename> entries
bos@559 931 (still in the <literal role="rc-bugzilla">bugzilla</literal>
bos@672 932 section) control this behavior.
bos@559 933 </para>
bos@559 934 <itemizedlist>
bos@584 935 <listitem><para id="x_25e"><literal>strip</literal>: The number of
bos@559 936 leading path elements to strip from a repository's path
bos@559 937 name to construct a partial path for a URL. For example,
bos@559 938 if the repositories on your server live under <filename
bos@559 939 class="directory">/home/hg/repos</filename>, and you
bos@559 940 have a repository whose path is <filename
bos@559 941 class="directory">/home/hg/repos/app/tests</filename>,
bos@559 942 then setting <literal>strip</literal> to
bos@559 943 <literal>4</literal> will give a partial path of
bos@559 944 <filename class="directory">app/tests</filename>. The
bos@559 945 hook will make this partial path available when
bos@559 946 expanding a template, as <literal>webroot</literal>.
bos@559 947 </para>
bos@559 948 </listitem>
bos@584 949 <listitem><para id="x_25f"><literal>template</literal>: The text of the
bos@559 950 template to use. In addition to the usual
bos@559 951 changeset-related variables, this template can use
bos@559 952 <literal>hgweb</literal> (the value of the
bos@559 953 <literal>hgweb</literal> configuration item above) and
bos@559 954 <literal>webroot</literal> (the path constructed using
bos@559 955 <literal>strip</literal> above).
bos@559 956 </para>
bos@559 957 </listitem></itemizedlist>
bos@559 958
bos@584 959 <para id="x_260">In addition, you can add a <envar
bos@559 960 role="rc-item-web">baseurl</envar> item to the <literal
bos@559 961 role="rc-web">web</literal> section of your <filename
bos@580 962 role="special">~/.hgrc</filename>. The <literal
bos@559 963 role="hg-ext">bugzilla</literal> hook will make this
bos@559 964 available when expanding a template, as the base string to
bos@559 965 use when constructing a URL that will let users browse from
bos@559 966 a Bugzilla comment to view a changeset. Example:
bos@559 967 </para>
bos@580 968 <programlisting>[web]
bos@580 969 baseurl = http://hg.domain.com/</programlisting>
bos@559 970
bos@584 971 <para id="x_261">Here is an example set of <literal
bos@559 972 role="hg-ext">bugzilla</literal> hook config information.
bos@559 973 </para>
bos@580 974
bos@580 975 &ch10-bugzilla-config.lst;
bos@559 976
bos@559 977 </sect3>
bos@559 978 <sect3>
bos@559 979 <title>Testing and troubleshooting</title>
bos@559 980
bos@584 981 <para id="x_262">The most common problems with configuring the <literal
bos@559 982 role="hg-ext">bugzilla</literal> hook relate to running
bos@559 983 Bugzilla's <filename>processmail</filename> script and
bos@559 984 mapping committer names to user names.
bos@559 985 </para>
bos@559 986
bos@592 987 <para id="x_263">Recall from <xref
bos@559 988 linkend="sec:hook:bugzilla:config"/> above that the user
bos@559 989 that runs the Mercurial process on the server is also the
bos@559 990 one that will run the <filename>processmail</filename>
bos@559 991 script. The <filename>processmail</filename> script
bos@559 992 sometimes causes Bugzilla to write to files in its
bos@559 993 configuration directory, and Bugzilla's configuration files
bos@559 994 are usually owned by the user that your web server runs
bos@559 995 under.
bos@559 996 </para>
bos@559 997
bos@584 998 <para id="x_264">You can cause <filename>processmail</filename> to be run
bos@559 999 with the suitable user's identity using the
bos@559 1000 <command>sudo</command> command. Here is an example entry
bos@559 1001 for a <filename>sudoers</filename> file.
bos@559 1002 </para>
bos@580 1003 <programlisting>hg_user = (httpd_user)
bos@580 1004 NOPASSWD: /var/www/html/bugzilla/processmail-wrapper %s</programlisting>
bos@584 1005 <para id="x_265">This allows the <literal>hg_user</literal> user to run a
bos@559 1006 <filename>processmail-wrapper</filename> program under the
bos@559 1007 identity of <literal>httpd_user</literal>.
bos@559 1008 </para>
bos@559 1009
bos@584 1010 <para id="x_266">This indirection through a wrapper script is necessary,
bos@559 1011 because <filename>processmail</filename> expects to be run
bos@559 1012 with its current directory set to wherever you installed
bos@559 1013 Bugzilla; you can't specify that kind of constraint in a
bos@559 1014 <filename>sudoers</filename> file. The contents of the
bos@559 1015 wrapper script are simple:
bos@559 1016 </para>
bos@580 1017 <programlisting>#!/bin/sh
bos@580 1018 cd `dirname $0` &amp;&amp; ./processmail "$1" nobody@example.com</programlisting>
bos@584 1019 <para id="x_267">It doesn't seem to matter what email address you pass to
bos@559 1020 <filename>processmail</filename>.
bos@559 1021 </para>
bos@559 1022
bos@584 1023 <para id="x_268">If your <literal role="rc-usermap">usermap</literal> is
bos@559 1024 not set up correctly, users will see an error message from
bos@559 1025 the <literal role="hg-ext">bugzilla</literal> hook when they
bos@559 1026 push changes to the server. The error message will look
bos@559 1027 like this:
bos@559 1028 </para>
bos@580 1029 <programlisting>cannot find bugzilla user id for john.q.public@example.com</programlisting>
bos@584 1030 <para id="x_269">What this means is that the committer's address,
bos@559 1031 <literal>john.q.public@example.com</literal>, is not a valid
bos@559 1032 Bugzilla user name, nor does it have an entry in your
bos@559 1033 <literal role="rc-usermap">usermap</literal> that maps it to
bos@559 1034 a valid Bugzilla user name.
bos@559 1035 </para>
bos@559 1036
bos@682 1037 </sect3> </sect2>
bos@682 1038
bos@559 1039 <sect2>
bos@559 1040 <title><literal role="hg-ext">notify</literal>&emdash;send email
bos@559 1041 notifications</title>
bos@559 1042
bos@584 1043 <para id="x_26a">Although Mercurial's built-in web server provides RSS
bos@559 1044 feeds of changes in every repository, many people prefer to
bos@559 1045 receive change notifications via email. The <literal
bos@559 1046 role="hg-ext">notify</literal> hook lets you send out
bos@559 1047 notifications to a set of email addresses whenever changesets
bos@559 1048 arrive that those subscribers are interested in.
bos@559 1049 </para>
bos@559 1050
bos@584 1051 <para id="x_26b">As with the <literal role="hg-ext">bugzilla</literal>
bos@559 1052 hook, the <literal role="hg-ext">notify</literal> hook is
bos@559 1053 template-driven, so you can customise the contents of the
bos@559 1054 notification messages that it sends.
bos@559 1055 </para>
bos@559 1056
bos@584 1057 <para id="x_26c">By default, the <literal role="hg-ext">notify</literal>
bos@559 1058 hook includes a diff of every changeset that it sends out; you
bos@559 1059 can limit the size of the diff, or turn this feature off
bos@559 1060 entirely. It is useful for letting subscribers review changes
bos@559 1061 immediately, rather than clicking to follow a URL.
bos@559 1062 </para>
bos@559 1063
bos@559 1064 <sect3>
bos@559 1065 <title>Configuring the <literal role="hg-ext">notify</literal>
bos@559 1066 hook</title>
bos@559 1067
bos@584 1068 <para id="x_26d">You can set up the <literal
bos@559 1069 role="hg-ext">notify</literal> hook to send one email
bos@559 1070 message per incoming changeset, or one per incoming group of
bos@559 1071 changesets (all those that arrived in a single pull or
bos@559 1072 push).
bos@559 1073 </para>
bos@580 1074 <programlisting>[hooks]
bos@580 1075 # send one email per group of changes
bos@580 1076 changegroup.notify = python:hgext.notify.hook
bos@580 1077 # send one email per change
bos@580 1078 incoming.notify = python:hgext.notify.hook</programlisting>
bos@559 1079
bos@584 1080 <para id="x_26e">Configuration information for this hook lives in the
bos@559 1081 <literal role="rc-notify">notify</literal> section of a
bos@580 1082 <filename role="special">~/.hgrc</filename> file.
bos@559 1083 </para>
bos@559 1084 <itemizedlist>
bos@584 1085 <listitem><para id="x_26f"><envar role="rc-item-notify">test</envar>:
bos@559 1086 By default, this hook does not send out email at all;
bos@559 1087 instead, it prints the message that it
bos@559 1088 <emphasis>would</emphasis> send. Set this item to
bos@559 1089 <literal>false</literal> to allow email to be sent. The
bos@559 1090 reason that sending of email is turned off by default is
bos@559 1091 that it takes several tries to configure this extension
bos@559 1092 exactly as you would like, and it would be bad form to
bos@559 1093 spam subscribers with a number of <quote>broken</quote>
bos@559 1094 notifications while you debug your configuration.
bos@559 1095 </para>
bos@559 1096 </listitem>
bos@584 1097 <listitem><para id="x_270"><envar role="rc-item-notify">config</envar>:
bos@559 1098 The path to a configuration file that contains
bos@559 1099 subscription information. This is kept separate from
bos@580 1100 the main <filename role="special">~/.hgrc</filename> so
bos@559 1101 that you can maintain it in a repository of its own.
bos@559 1102 People can then clone that repository, update their
bos@559 1103 subscriptions, and push the changes back to your server.
bos@559 1104 </para>
bos@559 1105 </listitem>
bos@584 1106 <listitem><para id="x_271"><envar role="rc-item-notify">strip</envar>:
bos@559 1107 The number of leading path separator characters to strip
bos@559 1108 from a repository's path, when deciding whether a
bos@559 1109 repository has subscribers. For example, if the
bos@559 1110 repositories on your server live in <filename
bos@559 1111 class="directory">/home/hg/repos</filename>, and
bos@559 1112 <literal role="hg-ext">notify</literal> is considering a
bos@559 1113 repository named <filename
bos@559 1114 class="directory">/home/hg/repos/shared/test</filename>,
bos@559 1115 setting <envar role="rc-item-notify">strip</envar> to
bos@559 1116 <literal>4</literal> will cause <literal
bos@559 1117 role="hg-ext">notify</literal> to trim the path it
bos@559 1118 considers down to <filename
bos@559 1119 class="directory">shared/test</filename>, and it will
bos@559 1120 match subscribers against that.
bos@559 1121 </para>
bos@559 1122 </listitem>
bos@584 1123 <listitem><para id="x_272"><envar
bos@559 1124 role="rc-item-notify">template</envar>: The template
bos@559 1125 text to use when sending messages. This specifies both
bos@559 1126 the contents of the message header and its body.
bos@559 1127 </para>
bos@559 1128 </listitem>
bos@584 1129 <listitem><para id="x_273"><envar
bos@559 1130 role="rc-item-notify">maxdiff</envar>: The maximum
bos@559 1131 number of lines of diff data to append to the end of a
bos@559 1132 message. If a diff is longer than this, it is
bos@559 1133 truncated. By default, this is set to 300. Set this to
bos@559 1134 <literal>0</literal> to omit diffs from notification
bos@559 1135 emails.
bos@559 1136 </para>
bos@559 1137 </listitem>
bos@584 1138 <listitem><para id="x_274"><envar
bos@559 1139 role="rc-item-notify">sources</envar>: A list of
bos@559 1140 sources of changesets to consider. This lets you limit
bos@559 1141 <literal role="hg-ext">notify</literal> to only sending
bos@559 1142 out email about changes that remote users pushed into
bos@592 1143 this repository via a server, for example. See
bos@592 1144 <xref linkend="sec:hook:sources"/> for the sources you
bos@592 1145 can specify here.
bos@559 1146 </para>
bos@559 1147 </listitem></itemizedlist>
bos@559 1148
bos@584 1149 <para id="x_275">If you set the <envar role="rc-item-web">baseurl</envar>
bos@559 1150 item in the <literal role="rc-web">web</literal> section,
bos@559 1151 you can use it in a template; it will be available as
bos@559 1152 <literal>webroot</literal>.
bos@559 1153 </para>
bos@559 1154
bos@584 1155 <para id="x_276">Here is an example set of <literal
bos@559 1156 role="hg-ext">notify</literal> configuration information.
bos@559 1157 </para>
bos@580 1158
bos@580 1159 &ch10-notify-config.lst;
bos@559 1160
bos@584 1161 <para id="x_277">This will produce a message that looks like the
bos@559 1162 following:
bos@559 1163 </para>
bos@580 1164
bos@580 1165 &ch10-notify-config-mail.lst;
bos@559 1166
bos@559 1167 </sect3>
bos@559 1168 <sect3>
bos@559 1169 <title>Testing and troubleshooting</title>
bos@559 1170
bos@584 1171 <para id="x_278">Do not forget that by default, the <literal
ori@561 1172 role="hg-ext">notify</literal> extension <emphasis>will not
ori@561 1173 send any mail</emphasis> until you explicitly configure it to do so,
bos@559 1174 by setting <envar role="rc-item-notify">test</envar> to
bos@559 1175 <literal>false</literal>. Until you do that, it simply
bos@559 1176 prints the message it <emphasis>would</emphasis> send.
bos@559 1177 </para>
bos@559 1178
bos@559 1179 </sect3>
bos@559 1180 </sect2>
bos@559 1181 </sect1>
bos@559 1182 <sect1 id="sec:hook:ref">
bos@559 1183 <title>Information for writers of hooks</title>
bos@559 1184
bos@559 1185 <sect2>
bos@559 1186 <title>In-process hook execution</title>
bos@559 1187
bos@584 1188 <para id="x_279">An in-process hook is called with arguments of the
bos@559 1189 following form:
bos@559 1190 </para>
bos@580 1191 <programlisting>def myhook(ui, repo, **kwargs): pass</programlisting>
bos@584 1192 <para id="x_27a">The <literal>ui</literal> parameter is a <literal
bos@559 1193 role="py-mod-mercurial.ui">ui</literal> object. The
bos@559 1194 <literal>repo</literal> parameter is a <literal
bos@559 1195 role="py-mod-mercurial.localrepo">localrepository</literal>
bos@559 1196 object. The names and values of the
bos@559 1197 <literal>**kwargs</literal> parameters depend on the hook
bos@559 1198 being invoked, with the following common features:
bos@559 1199 </para>
bos@559 1200 <itemizedlist>
bos@584 1201 <listitem><para id="x_27b">If a parameter is named
bos@559 1202 <literal>node</literal> or <literal>parentN</literal>, it
bos@559 1203 will contain a hexadecimal changeset ID. The empty string
bos@559 1204 is used to represent <quote>null changeset ID</quote>
bos@559 1205 instead of a string of zeroes.
bos@559 1206 </para>
bos@559 1207 </listitem>
bos@584 1208 <listitem><para id="x_27c">If a parameter is named
bos@559 1209 <literal>url</literal>, it will contain the URL of a
bos@559 1210 remote repository, if that can be determined.
bos@559 1211 </para>
bos@559 1212 </listitem>
bos@584 1213 <listitem><para id="x_27d">Boolean-valued parameters are represented as
bos@559 1214 Python <literal>bool</literal> objects.
bos@559 1215 </para>
bos@559 1216 </listitem></itemizedlist>
bos@559 1217
bos@584 1218 <para id="x_27e">An in-process hook is called without a change to the
bos@559 1219 process's working directory (unlike external hooks, which are
bos@559 1220 run in the root of the repository). It must not change the
bos@559 1221 process's working directory, or it will cause any calls it
bos@559 1222 makes into the Mercurial API to fail.
bos@559 1223 </para>
bos@559 1224
bos@584 1225 <para id="x_27f">If a hook returns a boolean <quote>false</quote> value, it
bos@559 1226 is considered to have succeeded. If it returns a boolean
bos@559 1227 <quote>true</quote> value or raises an exception, it is
bos@559 1228 considered to have failed. A useful way to think of the
bos@559 1229 calling convention is <quote>tell me if you fail</quote>.
bos@559 1230 </para>
bos@559 1231
bos@584 1232 <para id="x_280">Note that changeset IDs are passed into Python hooks as
bos@559 1233 hexadecimal strings, not the binary hashes that Mercurial's
bos@559 1234 APIs normally use. To convert a hash from hex to binary, use
bos@580 1235 the <literal>bin</literal> function.
bos@559 1236 </para>
bos@682 1237 </sect2>
bos@682 1238
bos@559 1239 <sect2>
bos@559 1240 <title>External hook execution</title>
bos@559 1241
bos@584 1242 <para id="x_281">An external hook is passed to the shell of the user
bos@559 1243 running Mercurial. Features of that shell, such as variable
bos@559 1244 substitution and command redirection, are available. The hook
bos@559 1245 is run in the root directory of the repository (unlike
bos@559 1246 in-process hooks, which are run in the same directory that
bos@559 1247 Mercurial was run in).
bos@559 1248 </para>
bos@559 1249
bos@584 1250 <para id="x_282">Hook parameters are passed to the hook as environment
bos@559 1251 variables. Each environment variable's name is converted in
bos@559 1252 upper case and prefixed with the string
bos@559 1253 <quote><literal>HG_</literal></quote>. For example, if the
bos@559 1254 name of a parameter is <quote><literal>node</literal></quote>,
bos@559 1255 the name of the environment variable representing that
bos@559 1256 parameter will be <quote><literal>HG_NODE</literal></quote>.
bos@559 1257 </para>
bos@559 1258
bos@584 1259 <para id="x_283">A boolean parameter is represented as the string
bos@559 1260 <quote><literal>1</literal></quote> for <quote>true</quote>,
bos@559 1261 <quote><literal>0</literal></quote> for <quote>false</quote>.
bos@559 1262 If an environment variable is named <envar>HG_NODE</envar>,
bos@559 1263 <envar>HG_PARENT1</envar> or <envar>HG_PARENT2</envar>, it
bos@559 1264 contains a changeset ID represented as a hexadecimal string.
bos@559 1265 The empty string is used to represent <quote>null changeset
bos@559 1266 ID</quote> instead of a string of zeroes. If an environment
bos@559 1267 variable is named <envar>HG_URL</envar>, it will contain the
bos@559 1268 URL of a remote repository, if that can be determined.
bos@559 1269 </para>
bos@559 1270
bos@584 1271 <para id="x_284">If a hook exits with a status of zero, it is considered to
bos@559 1272 have succeeded. If it exits with a non-zero status, it is
bos@559 1273 considered to have failed.
bos@559 1274 </para>
bos@682 1275 </sect2>
bos@682 1276
bos@559 1277 <sect2>
bos@559 1278 <title>Finding out where changesets come from</title>
bos@559 1279
bos@584 1280 <para id="x_285">A hook that involves the transfer of changesets between a
bos@559 1281 local repository and another may be able to find out
bos@559 1282 information about the <quote>far side</quote>. Mercurial
bos@559 1283 knows <emphasis>how</emphasis> changes are being transferred,
bos@559 1284 and in many cases <emphasis>where</emphasis> they are being
bos@559 1285 transferred to or from.
bos@559 1286 </para>
bos@559 1287
bos@559 1288 <sect3 id="sec:hook:sources">
bos@559 1289 <title>Sources of changesets</title>
bos@559 1290
bos@584 1291 <para id="x_286">Mercurial will tell a hook what means are, or were, used
bos@559 1292 to transfer changesets between repositories. This is
bos@559 1293 provided by Mercurial in a Python parameter named
bos@559 1294 <literal>source</literal>, or an environment variable named
bos@559 1295 <envar>HG_SOURCE</envar>.
bos@559 1296 </para>
bos@559 1297
bos@559 1298 <itemizedlist>
bos@584 1299 <listitem><para id="x_287"><literal>serve</literal>: Changesets are
bos@559 1300 transferred to or from a remote repository over http or
bos@559 1301 ssh.
bos@559 1302 </para>
bos@559 1303 </listitem>
bos@584 1304 <listitem><para id="x_288"><literal>pull</literal>: Changesets are
bos@559 1305 being transferred via a pull from one repository into
bos@559 1306 another.
bos@559 1307 </para>
bos@559 1308 </listitem>
bos@584 1309 <listitem><para id="x_289"><literal>push</literal>: Changesets are
bos@559 1310 being transferred via a push from one repository into
bos@559 1311 another.
bos@559 1312 </para>
bos@559 1313 </listitem>
bos@584 1314 <listitem><para id="x_28a"><literal>bundle</literal>: Changesets are
bos@559 1315 being transferred to or from a bundle.
bos@559 1316 </para>
bos@559 1317 </listitem></itemizedlist>
bos@559 1318 </sect3>
bos@682 1319
bos@559 1320 <sect3 id="sec:hook:url">
bos@559 1321 <title>Where changes are going&emdash;remote repository
bos@559 1322 URLs</title>
bos@559 1323
bos@584 1324 <para id="x_28b">When possible, Mercurial will tell a hook the location
bos@559 1325 of the <quote>far side</quote> of an activity that transfers
bos@559 1326 changeset data between repositories. This is provided by
bos@559 1327 Mercurial in a Python parameter named
bos@559 1328 <literal>url</literal>, or an environment variable named
bos@559 1329 <envar>HG_URL</envar>.
bos@559 1330 </para>
bos@559 1331
bos@584 1332 <para id="x_28c">This information is not always known. If a hook is
bos@559 1333 invoked in a repository that is being served via http or
bos@559 1334 ssh, Mercurial cannot tell where the remote repository is,
bos@559 1335 but it may know where the client is connecting from. In
bos@559 1336 such cases, the URL will take one of the following forms:
bos@559 1337 </para>
bos@559 1338 <itemizedlist>
bos@584 1339 <listitem><para id="x_28d"><literal>remote:ssh:1.2.3.4</literal>&emdash;remote
bos@559 1340 ssh client, at the IP address
bos@559 1341 <literal>1.2.3.4</literal>.
bos@559 1342 </para>
bos@559 1343 </listitem>
bos@584 1344 <listitem><para id="x_28e"><literal>remote:http:1.2.3.4</literal>&emdash;remote
bos@559 1345 http client, at the IP address
bos@559 1346 <literal>1.2.3.4</literal>. If the client is using SSL,
bos@559 1347 this will be of the form
bos@559 1348 <literal>remote:https:1.2.3.4</literal>.
bos@559 1349 </para>
bos@559 1350 </listitem>
bos@584 1351 <listitem><para id="x_28f">Empty&emdash;no information could be
bos@559 1352 discovered about the remote client.
bos@559 1353 </para>
bos@559 1354 </listitem></itemizedlist>
bos@559 1355 </sect3>
bos@559 1356 </sect2>
bos@559 1357 </sect1>
bos@559 1358 <sect1>
bos@559 1359 <title>Hook reference</title>
bos@559 1360
bos@559 1361 <sect2 id="sec:hook:changegroup">
bos@559 1362 <title><literal role="hook">changegroup</literal>&emdash;after
bos@559 1363 remote changesets added</title>
bos@559 1364
bos@584 1365 <para id="x_290">This hook is run after a group of pre-existing changesets
bos@559 1366 has been added to the repository, for example via a <command
bos@559 1367 role="hg-cmd">hg pull</command> or <command role="hg-cmd">hg
bos@559 1368 unbundle</command>. This hook is run once per operation
bos@559 1369 that added one or more changesets. This is in contrast to the
bos@559 1370 <literal role="hook">incoming</literal> hook, which is run
bos@559 1371 once per changeset, regardless of whether the changesets
bos@559 1372 arrive in a group.
bos@559 1373 </para>
bos@559 1374
bos@584 1375 <para id="x_291">Some possible uses for this hook include kicking off an
bos@559 1376 automated build or test of the added changesets, updating a
bos@559 1377 bug database, or notifying subscribers that a repository
bos@559 1378 contains new changes.
bos@559 1379 </para>
bos@559 1380
bos@584 1381 <para id="x_292">Parameters to this hook:
bos@559 1382 </para>
bos@559 1383 <itemizedlist>
bos@584 1384 <listitem><para id="x_293"><literal>node</literal>: A changeset ID. The
bos@559 1385 changeset ID of the first changeset in the group that was
bos@559 1386 added. All changesets between this and
bos@580 1387 <literal role="tag">tip</literal>, inclusive, were added by a single
bos@580 1388 <command role="hg-cmd">hg pull</command>, <command
bos@559 1389 role="hg-cmd">hg push</command> or <command
bos@559 1390 role="hg-cmd">hg unbundle</command>.
bos@559 1391 </para>
bos@559 1392 </listitem>
bos@592 1393 <listitem><para id="x_294"><literal>source</literal>: A
bos@592 1394 string. The source of these changes. See <xref
bos@559 1395 linkend="sec:hook:sources"/> for details.
bos@559 1396 </para>
bos@559 1397 </listitem>
bos@592 1398 <listitem><para id="x_295"><literal>url</literal>: A URL. The
bos@592 1399 location of the remote repository, if known. See <xref
bos@592 1400 linkend="sec:hook:url"/> for more information.
bos@559 1401 </para>
bos@559 1402 </listitem></itemizedlist>
bos@559 1403
bos@592 1404 <para id="x_296">See also: <literal
bos@592 1405 role="hook">incoming</literal> (<xref
bos@592 1406 linkend="sec:hook:incoming"/>), <literal
bos@592 1407 role="hook">prechangegroup</literal> (<xref
bos@559 1408 linkend="sec:hook:prechangegroup"/>), <literal
bos@592 1409 role="hook">pretxnchangegroup</literal> (<xref
bos@559 1410 linkend="sec:hook:pretxnchangegroup"/>)
bos@559 1411 </para>
bos@682 1412 </sect2>
bos@682 1413
bos@559 1414 <sect2 id="sec:hook:commit">
bos@559 1415 <title><literal role="hook">commit</literal>&emdash;after a new
bos@559 1416 changeset is created</title>
bos@559 1417
bos@584 1418 <para id="x_297">This hook is run after a new changeset has been created.
bos@584 1419 </para>
bos@584 1420
bos@584 1421 <para id="x_298">Parameters to this hook:
bos@559 1422 </para>
bos@559 1423 <itemizedlist>
bos@584 1424 <listitem><para id="x_299"><literal>node</literal>: A changeset ID. The
bos@559 1425 changeset ID of the newly committed changeset.
bos@559 1426 </para>
bos@559 1427 </listitem>
bos@584 1428 <listitem><para id="x_29a"><literal>parent1</literal>: A changeset ID.
bos@559 1429 The changeset ID of the first parent of the newly
bos@559 1430 committed changeset.
bos@559 1431 </para>
bos@559 1432 </listitem>
bos@584 1433 <listitem><para id="x_29b"><literal>parent2</literal>: A changeset ID.
bos@559 1434 The changeset ID of the second parent of the newly
bos@559 1435 committed changeset.
bos@559 1436 </para>
bos@559 1437 </listitem></itemizedlist>
bos@559 1438
bos@592 1439 <para id="x_29c">See also: <literal
bos@592 1440 role="hook">precommit</literal> (<xref
bos@592 1441 linkend="sec:hook:precommit"/>), <literal
bos@592 1442 role="hook">pretxncommit</literal> (<xref
bos@559 1443 linkend="sec:hook:pretxncommit"/>)
bos@559 1444 </para>
bos@682 1445 </sect2>
bos@682 1446
bos@559 1447 <sect2 id="sec:hook:incoming">
bos@559 1448 <title><literal role="hook">incoming</literal>&emdash;after one
bos@559 1449 remote changeset is added</title>
bos@559 1450
bos@584 1451 <para id="x_29d">This hook is run after a pre-existing changeset has been
bos@559 1452 added to the repository, for example via a <command
bos@559 1453 role="hg-cmd">hg push</command>. If a group of changesets
bos@559 1454 was added in a single operation, this hook is called once for
bos@559 1455 each added changeset.
bos@559 1456 </para>
bos@559 1457
bos@592 1458 <para id="x_29e">You can use this hook for the same purposes as
bos@592 1459 the <literal role="hook">changegroup</literal> hook (<xref
bos@592 1460 linkend="sec:hook:changegroup"/>); it's simply more
bos@592 1461 convenient sometimes to run a hook once per group of
bos@559 1462 changesets, while other times it's handier once per changeset.
bos@559 1463 </para>
bos@559 1464
bos@584 1465 <para id="x_29f">Parameters to this hook:
bos@559 1466 </para>
bos@559 1467 <itemizedlist>
bos@584 1468 <listitem><para id="x_2a0"><literal>node</literal>: A changeset ID. The
bos@559 1469 ID of the newly added changeset.
bos@559 1470 </para>
bos@559 1471 </listitem>
bos@592 1472 <listitem><para id="x_2a1"><literal>source</literal>: A
bos@592 1473 string. The source of these changes. See <xref
bos@559 1474 linkend="sec:hook:sources"/> for details.
bos@559 1475 </para>
bos@559 1476 </listitem>
bos@592 1477 <listitem><para id="x_2a2"><literal>url</literal>: A URL. The
bos@592 1478 location of the remote repository, if known. See <xref
bos@592 1479 linkend="sec:hook:url"/> for more information.
bos@559 1480 </para>
bos@559 1481 </listitem></itemizedlist>
bos@559 1482
bos@592 1483 <para id="x_2a3">See also: <literal
bos@592 1484 role="hook">changegroup</literal> (<xref
bos@592 1485 linkend="sec:hook:changegroup"/>) <literal
bos@592 1486 role="hook">prechangegroup</literal> (<xref
bos@559 1487 linkend="sec:hook:prechangegroup"/>), <literal
bos@592 1488 role="hook">pretxnchangegroup</literal> (<xref
bos@559 1489 linkend="sec:hook:pretxnchangegroup"/>)
bos@559 1490 </para>
bos@682 1491 </sect2>
bos@682 1492
bos@559 1493 <sect2 id="sec:hook:outgoing">
bos@559 1494 <title><literal role="hook">outgoing</literal>&emdash;after
bos@559 1495 changesets are propagated</title>
bos@559 1496
bos@584 1497 <para id="x_2a4">This hook is run after a group of changesets has been
bos@559 1498 propagated out of this repository, for example by a <command
bos@559 1499 role="hg-cmd">hg push</command> or <command role="hg-cmd">hg
bos@559 1500 bundle</command> command.
bos@559 1501 </para>
bos@559 1502
bos@584 1503 <para id="x_2a5">One possible use for this hook is to notify administrators
bos@559 1504 that changes have been pulled.
bos@559 1505 </para>
bos@559 1506
bos@584 1507 <para id="x_2a6">Parameters to this hook:
bos@559 1508 </para>
bos@559 1509 <itemizedlist>
bos@584 1510 <listitem><para id="x_2a7"><literal>node</literal>: A changeset ID. The
bos@559 1511 changeset ID of the first changeset of the group that was
bos@559 1512 sent.
bos@559 1513 </para>
bos@559 1514 </listitem>
bos@584 1515 <listitem><para id="x_2a8"><literal>source</literal>: A string. The
bos@592 1516 source of the of the operation (see <xref
bos@559 1517 linkend="sec:hook:sources"/>). If a remote
bos@559 1518 client pulled changes from this repository,
bos@559 1519 <literal>source</literal> will be
bos@559 1520 <literal>serve</literal>. If the client that obtained
bos@559 1521 changes from this repository was local,
bos@559 1522 <literal>source</literal> will be
bos@559 1523 <literal>bundle</literal>, <literal>pull</literal>, or
bos@559 1524 <literal>push</literal>, depending on the operation the
bos@559 1525 client performed.
bos@559 1526 </para>
bos@559 1527 </listitem>
bos@592 1528 <listitem><para id="x_2a9"><literal>url</literal>: A URL. The
bos@592 1529 location of the remote repository, if known. See <xref
bos@592 1530 linkend="sec:hook:url"/> for more information.
bos@559 1531 </para>
bos@559 1532 </listitem></itemizedlist>
bos@559 1533
bos@592 1534 <para id="x_2aa">See also: <literal
bos@592 1535 role="hook">preoutgoing</literal> (<xref
bos@592 1536 linkend="sec:hook:preoutgoing"/>)
bos@559 1537 </para>
bos@682 1538 </sect2>
bos@682 1539
bos@559 1540 <sect2 id="sec:hook:prechangegroup">
bos@559 1541 <title><literal
bos@559 1542 role="hook">prechangegroup</literal>&emdash;before starting
bos@559 1543 to add remote changesets</title>
bos@559 1544
bos@584 1545 <para id="x_2ab">This controlling hook is run before Mercurial begins to
bos@559 1546 add a group of changesets from another repository.
bos@559 1547 </para>
bos@559 1548
bos@584 1549 <para id="x_2ac">This hook does not have any information about the
bos@559 1550 changesets to be added, because it is run before transmission
bos@559 1551 of those changesets is allowed to begin. If this hook fails,
bos@559 1552 the changesets will not be transmitted.
bos@559 1553 </para>
bos@559 1554
bos@584 1555 <para id="x_2ad">One use for this hook is to prevent external changes from
bos@559 1556 being added to a repository. For example, you could use this
bos@559 1557 to <quote>freeze</quote> a server-hosted branch temporarily or
bos@559 1558 permanently so that users cannot push to it, while still
bos@559 1559 allowing a local administrator to modify the repository.
bos@559 1560 </para>
bos@559 1561
bos@584 1562 <para id="x_2ae">Parameters to this hook:
bos@559 1563 </para>
bos@559 1564 <itemizedlist>
bos@584 1565 <listitem><para id="x_2af"><literal>source</literal>: A string. The
bos@592 1566 source of these changes. See <xref
bos@559 1567 linkend="sec:hook:sources"/> for details.
bos@559 1568 </para>
bos@559 1569 </listitem>
bos@592 1570 <listitem><para id="x_2b0"><literal>url</literal>: A URL. The
bos@592 1571 location of the remote repository, if known. See <xref
bos@592 1572 linkend="sec:hook:url"/> for more information.
bos@559 1573 </para>
bos@559 1574 </listitem></itemizedlist>
bos@559 1575
bos@592 1576 <para id="x_2b1">See also: <literal
bos@592 1577 role="hook">changegroup</literal> (<xref
bos@592 1578 linkend="sec:hook:changegroup"/>), <literal
bos@592 1579 role="hook">incoming</literal> (<xref
bos@592 1580 linkend="sec:hook:incoming"/>), <literal
bos@592 1581 role="hook">pretxnchangegroup</literal> (<xref
bos@559 1582 linkend="sec:hook:pretxnchangegroup"/>)
bos@559 1583 </para>
bos@682 1584 </sect2>
bos@682 1585
bos@559 1586 <sect2 id="sec:hook:precommit">
bos@559 1587 <title><literal role="hook">precommit</literal>&emdash;before
bos@559 1588 starting to commit a changeset</title>
bos@559 1589
bos@584 1590 <para id="x_2b2">This hook is run before Mercurial begins to commit a new
bos@559 1591 changeset. It is run before Mercurial has any of the metadata
bos@559 1592 for the commit, such as the files to be committed, the commit
bos@559 1593 message, or the commit date.
bos@559 1594 </para>
bos@559 1595
bos@584 1596 <para id="x_2b3">One use for this hook is to disable the ability to commit
bos@559 1597 new changesets, while still allowing incoming changesets.
bos@559 1598 Another is to run a build or test, and only allow the commit
bos@559 1599 to begin if the build or test succeeds.
bos@559 1600 </para>
bos@559 1601
bos@584 1602 <para id="x_2b4">Parameters to this hook:
bos@559 1603 </para>
bos@559 1604 <itemizedlist>
bos@584 1605 <listitem><para id="x_2b5"><literal>parent1</literal>: A changeset ID.
bos@559 1606 The changeset ID of the first parent of the working
bos@559 1607 directory.
bos@559 1608 </para>
bos@559 1609 </listitem>
bos@584 1610 <listitem><para id="x_2b6"><literal>parent2</literal>: A changeset ID.
bos@559 1611 The changeset ID of the second parent of the working
bos@559 1612 directory.
bos@559 1613 </para>
bos@559 1614 </listitem></itemizedlist>
bos@584 1615 <para id="x_2b7">If the commit proceeds, the parents of the working
bos@559 1616 directory will become the parents of the new changeset.
bos@559 1617 </para>
bos@559 1618
bos@592 1619 <para id="x_2b8">See also: <literal role="hook">commit</literal>
bos@592 1620 (<xref linkend="sec:hook:commit"/>), <literal
bos@592 1621 role="hook">pretxncommit</literal> (<xref
bos@559 1622 linkend="sec:hook:pretxncommit"/>)
bos@559 1623 </para>
bos@682 1624 </sect2>
bos@682 1625
bos@559 1626 <sect2 id="sec:hook:preoutgoing">
bos@559 1627 <title><literal role="hook">preoutgoing</literal>&emdash;before
bos@559 1628 starting to propagate changesets</title>
bos@559 1629
bos@584 1630 <para id="x_2b9">This hook is invoked before Mercurial knows the identities
bos@559 1631 of the changesets to be transmitted.
bos@559 1632 </para>
bos@559 1633
bos@584 1634 <para id="x_2ba">One use for this hook is to prevent changes from being
bos@559 1635 transmitted to another repository.
bos@559 1636 </para>
bos@559 1637
bos@584 1638 <para id="x_2bb">Parameters to this hook:
bos@559 1639 </para>
bos@559 1640 <itemizedlist>
bos@592 1641 <listitem><para id="x_2bc"><literal>source</literal>: A
bos@592 1642 string. The source of the operation that is attempting to
bos@592 1643 obtain changes from this repository (see <xref
bos@559 1644 linkend="sec:hook:sources"/>). See the documentation
bos@559 1645 for the <literal>source</literal> parameter to the
bos@592 1646 <literal role="hook">outgoing</literal> hook, in
bos@559 1647 <xref linkend="sec:hook:outgoing"/>, for possible values
bos@592 1648 of this parameter.
bos@592 1649 </para>
bos@592 1650 </listitem>
bos@592 1651 <listitem><para id="x_2bd"><literal>url</literal>: A URL. The
bos@592 1652 location of the remote repository, if known. See <xref
bos@592 1653 linkend="sec:hook:url"/> for more information.
bos@559 1654 </para>
bos@559 1655 </listitem></itemizedlist>
bos@559 1656
bos@592 1657 <para id="x_2be">See also: <literal
bos@592 1658 role="hook">outgoing</literal> (<xref
bos@592 1659 linkend="sec:hook:outgoing"/>)
bos@559 1660 </para>
bos@682 1661 </sect2>
bos@682 1662
bos@559 1663 <sect2 id="sec:hook:pretag">
bos@559 1664 <title><literal role="hook">pretag</literal>&emdash;before
bos@559 1665 tagging a changeset</title>
bos@559 1666
bos@584 1667 <para id="x_2bf">This controlling hook is run before a tag is created. If
bos@559 1668 the hook succeeds, creation of the tag proceeds. If the hook
bos@559 1669 fails, the tag is not created.
bos@559 1670 </para>
bos@559 1671
bos@584 1672 <para id="x_2c0">Parameters to this hook:
bos@559 1673 </para>
bos@559 1674 <itemizedlist>
bos@584 1675 <listitem><para id="x_2c1"><literal>local</literal>: A boolean. Whether
bos@559 1676 the tag is local to this repository instance (i.e. stored
bos@559 1677 in <filename role="special">.hg/localtags</filename>) or
bos@559 1678 managed by Mercurial (stored in <filename
bos@559 1679 role="special">.hgtags</filename>).
bos@559 1680 </para>
bos@559 1681 </listitem>
bos@584 1682 <listitem><para id="x_2c2"><literal>node</literal>: A changeset ID. The
bos@559 1683 ID of the changeset to be tagged.
bos@559 1684 </para>
bos@559 1685 </listitem>
bos@584 1686 <listitem><para id="x_2c3"><literal>tag</literal>: A string. The name of
bos@559 1687 the tag to be created.
bos@559 1688 </para>
bos@559 1689 </listitem></itemizedlist>
bos@559 1690
bos@592 1691 <para id="x_2c4">If the tag to be created is
bos@592 1692 revision-controlled, the <literal
bos@592 1693 role="hook">precommit</literal> and <literal
bos@592 1694 role="hook">pretxncommit</literal> hooks (<xref
bos@559 1695 linkend="sec:hook:commit"/> and <xref
bos@559 1696 linkend="sec:hook:pretxncommit"/>) will also be run.
bos@559 1697 </para>
bos@559 1698
bos@592 1699 <para id="x_2c5">See also: <literal role="hook">tag</literal>
bos@592 1700 (<xref linkend="sec:hook:tag"/>)
bos@559 1701 </para>
bos@559 1702 </sect2>
bos@682 1703
bos@559 1704 <sect2 id="sec:hook:pretxnchangegroup">
bos@559 1705 <title><literal
bos@559 1706 role="hook">pretxnchangegroup</literal>&emdash;before
bos@559 1707 completing addition of remote changesets</title>
bos@559 1708
bos@584 1709 <para id="x_2c6">This controlling hook is run before a
bos@559 1710 transaction&emdash;that manages the addition of a group of new
bos@559 1711 changesets from outside the repository&emdash;completes. If
bos@559 1712 the hook succeeds, the transaction completes, and all of the
bos@559 1713 changesets become permanent within this repository. If the
bos@559 1714 hook fails, the transaction is rolled back, and the data for
bos@559 1715 the changesets is erased.
bos@559 1716 </para>
bos@559 1717
bos@584 1718 <para id="x_2c7">This hook can access the metadata associated with the
bos@559 1719 almost-added changesets, but it should not do anything
bos@559 1720 permanent with this data. It must also not modify the working
bos@559 1721 directory.
bos@559 1722 </para>
bos@559 1723
bos@584 1724 <para id="x_2c8">While this hook is running, if other Mercurial processes
bos@559 1725 access this repository, they will be able to see the
bos@559 1726 almost-added changesets as if they are permanent. This may
bos@559 1727 lead to race conditions if you do not take steps to avoid
bos@559 1728 them.
bos@559 1729 </para>
bos@559 1730
bos@584 1731 <para id="x_2c9">This hook can be used to automatically vet a group of
bos@559 1732 changesets. If the hook fails, all of the changesets are
bos@559 1733 <quote>rejected</quote> when the transaction rolls back.
bos@559 1734 </para>
bos@559 1735
bos@584 1736 <para id="x_2ca">Parameters to this hook:
bos@559 1737 </para>
bos@559 1738 <itemizedlist>
bos@584 1739 <listitem><para id="x_2cb"><literal>node</literal>: A changeset ID. The
bos@559 1740 changeset ID of the first changeset in the group that was
bos@559 1741 added. All changesets between this and
bos@580 1742 <literal role="tag">tip</literal>,
bos@559 1743 inclusive, were added by a single <command
bos@559 1744 role="hg-cmd">hg pull</command>, <command
bos@559 1745 role="hg-cmd">hg push</command> or <command
bos@559 1746 role="hg-cmd">hg unbundle</command>.
bos@559 1747 </para>
bos@559 1748 </listitem>
bos@592 1749 <listitem><para id="x_2cc"><literal>source</literal>: A
bos@592 1750 string. The source of these changes. See <xref
bos@559 1751 linkend="sec:hook:sources"/> for details.
bos@559 1752 </para>
bos@559 1753 </listitem>
bos@592 1754 <listitem><para id="x_2cd"><literal>url</literal>: A URL. The
bos@592 1755 location of the remote repository, if known. See <xref
bos@592 1756 linkend="sec:hook:url"/> for more information.
bos@559 1757 </para>
bos@559 1758 </listitem></itemizedlist>
bos@559 1759
bos@592 1760 <para id="x_2ce">See also: <literal
bos@592 1761 role="hook">changegroup</literal> (<xref
bos@592 1762 linkend="sec:hook:changegroup"/>), <literal
bos@592 1763 role="hook">incoming</literal> (<xref
bos@559 1764 linkend="sec:hook:incoming"/>), <literal
bos@592 1765 role="hook">prechangegroup</literal> (<xref
bos@559 1766 linkend="sec:hook:prechangegroup"/>)
bos@559 1767 </para>
bos@682 1768 </sect2>
bos@682 1769
bos@559 1770 <sect2 id="sec:hook:pretxncommit">
bos@559 1771 <title><literal role="hook">pretxncommit</literal>&emdash;before
bos@559 1772 completing commit of new changeset</title>
bos@559 1773
bos@584 1774 <para id="x_2cf">This controlling hook is run before a
bos@559 1775 transaction&emdash;that manages a new commit&emdash;completes.
bos@559 1776 If the hook succeeds, the transaction completes and the
bos@559 1777 changeset becomes permanent within this repository. If the
bos@559 1778 hook fails, the transaction is rolled back, and the commit
bos@559 1779 data is erased.
bos@559 1780 </para>
bos@559 1781
bos@584 1782 <para id="x_2d0">This hook can access the metadata associated with the
bos@559 1783 almost-new changeset, but it should not do anything permanent
bos@559 1784 with this data. It must also not modify the working
bos@559 1785 directory.
bos@559 1786 </para>
bos@559 1787
bos@584 1788 <para id="x_2d1">While this hook is running, if other Mercurial processes
bos@559 1789 access this repository, they will be able to see the
bos@559 1790 almost-new changeset as if it is permanent. This may lead to
bos@559 1791 race conditions if you do not take steps to avoid them.
bos@559 1792 </para>
bos@559 1793
bos@682 1794 <para id="x_2d2">Parameters to this hook:</para>
bos@682 1795
bos@559 1796 <itemizedlist>
bos@584 1797 <listitem><para id="x_2d3"><literal>node</literal>: A changeset ID. The
bos@559 1798 changeset ID of the newly committed changeset.
bos@559 1799 </para>
bos@559 1800 </listitem>
bos@584 1801 <listitem><para id="x_2d4"><literal>parent1</literal>: A changeset ID.
bos@559 1802 The changeset ID of the first parent of the newly
bos@559 1803 committed changeset.
bos@559 1804 </para>
bos@559 1805 </listitem>
bos@584 1806 <listitem><para id="x_2d5"><literal>parent2</literal>: A changeset ID.
bos@559 1807 The changeset ID of the second parent of the newly
bos@559 1808 committed changeset.
bos@559 1809 </para>
bos@559 1810 </listitem></itemizedlist>
bos@559 1811
bos@592 1812 <para id="x_2d6">See also: <literal
bos@592 1813 role="hook">precommit</literal> (<xref
bos@592 1814 linkend="sec:hook:precommit"/>)
bos@559 1815 </para>
bos@682 1816 </sect2>
bos@682 1817
bos@559 1818 <sect2 id="sec:hook:preupdate">
bos@559 1819 <title><literal role="hook">preupdate</literal>&emdash;before
bos@559 1820 updating or merging working directory</title>
bos@559 1821
bos@592 1822 <para id="x_2d7">This controlling hook is run before an update
bos@592 1823 or merge of the working directory begins. It is run only if
bos@592 1824 Mercurial's normal pre-update checks determine that the update
bos@592 1825 or merge can proceed. If the hook succeeds, the update or
bos@592 1826 merge may proceed; if it fails, the update or merge does not
bos@592 1827 start.
bos@559 1828 </para>
bos@559 1829
bos@584 1830 <para id="x_2d8">Parameters to this hook:
bos@559 1831 </para>
bos@559 1832 <itemizedlist>
bos@592 1833 <listitem><para id="x_2d9"><literal>parent1</literal>: A
bos@592 1834 changeset ID. The ID of the parent that the working
bos@592 1835 directory is to be updated to. If the working directory
bos@592 1836 is being merged, it will not change this parent.
bos@592 1837 </para>
bos@592 1838 </listitem>
bos@592 1839 <listitem><para id="x_2da"><literal>parent2</literal>: A
bos@592 1840 changeset ID. Only set if the working directory is being
bos@592 1841 merged. The ID of the revision that the working directory
bos@592 1842 is being merged with.
bos@559 1843 </para>
bos@559 1844 </listitem></itemizedlist>
bos@559 1845
bos@592 1846 <para id="x_2db">See also: <literal role="hook">update</literal>
bos@592 1847 (<xref linkend="sec:hook:update"/>)</para>
bos@682 1848 </sect2>
bos@682 1849
bos@559 1850 <sect2 id="sec:hook:tag">
bos@559 1851 <title><literal role="hook">tag</literal>&emdash;after tagging a
bos@559 1852 changeset</title>
bos@559 1853
bos@584 1854 <para id="x_2dc">This hook is run after a tag has been created.
bos@584 1855 </para>
bos@584 1856
bos@584 1857 <para id="x_2dd">Parameters to this hook:
bos@559 1858 </para>
bos@559 1859 <itemizedlist>
bos@584 1860 <listitem><para id="x_2de"><literal>local</literal>: A boolean. Whether
bos@559 1861 the new tag is local to this repository instance (i.e.
bos@559 1862 stored in <filename
bos@559 1863 role="special">.hg/localtags</filename>) or managed by
bos@559 1864 Mercurial (stored in <filename
bos@559 1865 role="special">.hgtags</filename>).
bos@559 1866 </para>
bos@559 1867 </listitem>
bos@584 1868 <listitem><para id="x_2df"><literal>node</literal>: A changeset ID. The
bos@559 1869 ID of the changeset that was tagged.
bos@559 1870 </para>
bos@559 1871 </listitem>
bos@584 1872 <listitem><para id="x_2e0"><literal>tag</literal>: A string. The name of
bos@559 1873 the tag that was created.
bos@559 1874 </para>
bos@559 1875 </listitem></itemizedlist>
bos@559 1876
bos@584 1877 <para id="x_2e1">If the created tag is revision-controlled, the <literal
bos@559 1878 role="hook">commit</literal> hook (section <xref
bos@559 1879 linkend="sec:hook:commit"/>) is run before this hook.
bos@559 1880 </para>
bos@559 1881
bos@592 1882 <para id="x_2e2">See also: <literal role="hook">pretag</literal>
bos@592 1883 (<xref linkend="sec:hook:pretag"/>)
bos@559 1884 </para>
bos@682 1885 </sect2>
bos@682 1886
bos@559 1887 <sect2 id="sec:hook:update">
bos@559 1888 <title><literal role="hook">update</literal>&emdash;after
bos@559 1889 updating or merging working directory</title>
bos@559 1890
bos@584 1891 <para id="x_2e3">This hook is run after an update or merge of the working
bos@559 1892 directory completes. Since a merge can fail (if the external
bos@559 1893 <command>hgmerge</command> command fails to resolve conflicts
bos@559 1894 in a file), this hook communicates whether the update or merge
bos@559 1895 completed cleanly.
bos@559 1896 </para>
bos@559 1897
bos@559 1898 <itemizedlist>
bos@584 1899 <listitem><para id="x_2e4"><literal>error</literal>: A boolean.
bos@559 1900 Indicates whether the update or merge completed
bos@559 1901 successfully.
bos@559 1902 </para>
bos@559 1903 </listitem>
bos@584 1904 <listitem><para id="x_2e5"><literal>parent1</literal>: A changeset ID.
bos@559 1905 The ID of the parent that the working directory was
bos@559 1906 updated to. If the working directory was merged, it will
bos@559 1907 not have changed this parent.
bos@559 1908 </para>
bos@559 1909 </listitem>
bos@584 1910 <listitem><para id="x_2e6"><literal>parent2</literal>: A changeset ID.
bos@559 1911 Only set if the working directory was merged. The ID of
bos@559 1912 the revision that the working directory was merged with.
bos@559 1913 </para>
bos@559 1914 </listitem></itemizedlist>
bos@559 1915
bos@584 1916 <para id="x_2e7">See also: <literal role="hook">preupdate</literal>
bos@592 1917 (<xref linkend="sec:hook:preupdate"/>)
bos@559 1918 </para>
bos@559 1919
bos@559 1920 </sect2>
bos@559 1921 </sect1>
bos@559 1922 </chapter>
bos@559 1923
bos@559 1924 <!--
bos@559 1925 local variables:
bos@559 1926 sgml-parent-document: ("00book.xml" "book" "chapter")
bos@559 1927 end:
bos@559 1928 -->