Mercurial > hgbook
annotate en/hook.tex @ 38:b49a7dd4e564
More content for hook chapter.
Overview of hooks.
Description of hook security implications.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Wed, 19 Jul 2006 00:06:21 -0700 |
parents | 9fd0c59b009a |
children | 576fef93bb49 |
rev | line source |
---|---|
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
1 \chapter{Handling repository events with hooks} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
2 \label{chap:hook} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
3 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
4 Mercurial offers a powerful mechanism to let you perform automated |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
5 actions in response to events that occur in a repository. In some |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
6 cases, you can even control Mercurial's response to those events. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
7 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
8 The name Mercurial uses for one of these actions is a \emph{hook}. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
9 Hooks are called ``triggers'' in some revision control systems, but |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
10 the two names refer to the same idea. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
11 |
38
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
12 \section{An overview of hooks in Mercurial} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
13 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
14 Here is a brief list of the hooks that Mercurial supports. For each |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
15 hook, we indicate when it is run, and a few examples of common tasks |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
16 you can use it for. We will revisit each of these hooks in more |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
17 detail later. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
18 \begin{itemize} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
19 \item[\small\hook{changegroup}] This is run after a group of |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
20 changesets has been brought into the repository from elsewhere. In |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
21 other words, it is run after a \hgcmd{pull} or \hgcmd{push} into a |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
22 repository, but not after a \hgcmd{commit}. You can use this for |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
23 performing an action once for the entire group of newly arrived |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
24 changesets. For example, you could use this hook to send out email |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
25 notifications, or kick off an automated build or test. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
26 \item[\small\hook{commit}] This is run after a new changeset has been |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
27 created in the local repository, typically using the \hgcmd{commit} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
28 command. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
29 \item[\small\hook{incoming}] This is run once for each new changeset |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
30 that is brought into the repository from elsewhere. Notice the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
31 difference from \hook{changegroup}, which is run once per |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
32 \emph{group} of changesets brought in. You can use this for the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
33 same purposes as the \hook{changegroup} hook; it's simply more |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
34 convenient sometimes to run a hook once per group of changesets, |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
35 while othher times it's handier once per changeset. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
36 \item[\small\hook{outgoing}] This is run after a group of changesets |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
37 has been transmitted from this repository to another. You can use |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
38 this, for example, to notify subscribers every time changes are |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
39 cloned or pulled from the repository. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
40 \item[\small\hook{prechangegroup}] This is run before starting to |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
41 bring a group of changesets into the repository. It cannot see the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
42 actual changesets, because they have not yet been transmitted. If |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
43 it fails, the changesets will not be transmitted. You can use this |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
44 hook to ``lock down'' a repository against incoming changes. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
45 \item[\small\hook{precommit}] This is run before starting a commit. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
46 It cannot tell what files are included in the commit, or any other |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
47 information about the commit. If it fails, the commit will not be |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
48 allowed to start. You can use this to perform a build and require |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
49 it to complete successfully before a commit can proceed, or |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
50 automatically enforce a requirement that modified files pass your |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
51 coding style guidelines. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
52 \item[\small\hook{preoutgoing}] This is run before starting to |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
53 transmit a group of changesets from this repository. You can use |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
54 this to lock a repository against clones or pulls from remote |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
55 clients. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
56 \item[\small\hook{pretag}] This is run before creating a tag. If it |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
57 fails, the tag will not be created. You can use this to enforce a |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
58 uniform tag naming convention. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
59 \item[\small\hook{pretxnchangegroup}] This is run after a group of |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
60 changesets has been brought into the local repository from another, |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
61 but before the transaction completes that will make the changes |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
62 permanent in the repository. If it fails, the transaction will be |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
63 rolled back and the changes will disappear from the local |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
64 repository. You can use this to automatically check newly arrived |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
65 changes and, for example, roll them back if the group as a whole |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
66 does not build or pass your test suite. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
67 \item[\small\hook{pretxncommit}] This is run after a new changeset has |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
68 been created in the local repository, but before the transaction |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
69 completes that will make it permanent. Unlike the \hook{precommit} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
70 hook, this hook can see which changes are present in the changeset, |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
71 and it can also see all other changeset metadata, such as the commit |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
72 message. You can use this to require that a commit message follows |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
73 your local conventions, or that a changeset builds cleanly. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
74 \item[\small\hook{preupdate}] This is run before starting an update or |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
75 merge of the working directory. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
76 \item[\small\hook{tag}] This is run after a tag is created. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
77 \item[\small\hook{update}] This is run after an update or merge of the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
78 working directory has finished. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
79 \end{itemize} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
80 Each of the hooks with a ``\texttt{pre}'' prefix has the ability to |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
81 \emph{control} an activity. If the hook succeeds, the activity may |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
82 proceed; if it fails, the activity is either not permitted or undone, |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
83 depending on the hook. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
84 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
85 \section{Hooks and security} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
86 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
87 \subsection{Hooks are run with your privileges} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
88 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
89 When you run a Mercurial command in a repository, and the command |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
90 causes a hook to run, that hook runs on your system, under your user |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
91 account, with your privilege level. Since hooks are arbitrary pieces |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
92 of executable code, you should treat them with an appropriate level of |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
93 suspicion. Do not install a hook unless you are confident that you |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
94 know who created it and what it does. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
95 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
96 In some cases, you may be exposed to hooks that you did not install |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
97 yourself. If you work with Mercurial on an unfamiliar system, |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
98 Mercurial will run hooks defined in that system's global \hgrc\ file. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
99 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
100 If you are working with a repository owned by another user, Mercurial |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
101 will run hooks defined in that repository. For example, if you |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
102 \hgcmd{pull} from that repository, and its \sfilename{.hg/hgrc} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
103 defines a local \hook{outgoing} hook, that hook will run under your |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
104 user account, even though you don't own that repository. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
105 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
106 \begin{note} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
107 This only applies if you are pulling from a repository on a local or |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
108 network filesystem. If you're pulling over http or ssh, any |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
109 \hook{outgoing} hook will run under the account of the server |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
110 process, on the server. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
111 \end{note} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
112 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
113 XXX To see what hooks are defined in a repository, use the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
114 \hgcmdargs{config}{hooks} command. If you are working in one |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
115 repository, but talking to another that you do not own (e.g.~using |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
116 \hgcmd{pull} or \hgcmd{incoming}), remember that it is the other |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
117 repository's hooks you should be checking, not your own. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
118 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
119 \subsection{Hooks do not propagate} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
120 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
121 In Mercurial, hooks are not revision controlled, and do not propagate |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
122 when you clone, or pull from, a repository. The reason for this is |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
123 simple: a hook is a completely arbitrary piece of executable code. It |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
124 runs under your user identity, with your privilege level, on your |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
125 machine. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
126 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
127 It would be extremely reckless for any distributed revision control |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
128 system to implement revision-controlled hooks, as this would offer an |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
129 easily exploitable way to subvert the accounts of users of the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
130 revision control system. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
131 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
132 Since Mercurial does not propagate hooks, if you are collaborating |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
133 with other people on a common project, you should not assume that they |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
134 are using the same Mercurial hooks as you are, or that theirs are |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
135 correctly configured. You should document the hooks you expect people |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
136 to use. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
137 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
138 In a corporate intranet, this is somewhat easier to control, as you |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
139 can for example provide a ``standard'' installation of Mercurial on an |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
140 NFS filesystem, and use a site-wide \hgrc\ file to define hooks that |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
141 all users will see. However, this too has its limits; see below. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
142 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
143 \subsection{Hooks can be overridden} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
144 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
145 Mercurial allows you to override a hook definition by redefining the |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
146 hook. You can disable it by setting its value to the empty string, or |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
147 change its behaviour as you wish. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
148 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
149 If you deploy a system-~or site-wide \hgrc\ file that defines some |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
150 hooks, you should thus understand that your users can disable or |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
151 override those hooks. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
152 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
153 \subsection{Ensuring that critical hooks are run} |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
154 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
155 Sometimes you may want to enforce a policy that you do not want others |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
156 to be able to work around. For example, you may have a requirement |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
157 that every changeset must pass a rigorous set of tests. Defining this |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
158 requirement via a hook in a site-wide \hgrc\ won't work for remote |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
159 users on laptops, and of course local users can subvert it at will by |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
160 overriding the hook. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
161 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
162 Instead, you can set up your policies for use of Mercurial so that |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
163 people are expected to propagate changes through a well-known |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
164 ``canonical'' server that you have locked down and configured |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
165 appropriately. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
166 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
167 One way to do this is via a combination of social engineering and |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
168 technology. Set up a restricted-access account; users can push |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
169 changes over the network to repositories managed by this account, but |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
170 they cannot log into the account and run normal shell commands. In |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
171 this scenario, a user can commit a changeset that contains any old |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
172 garbage they want. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
173 |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
174 When someone pushes a changeset to the server that everyone pulls |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
175 from, the server will test the changeset before it accepts it as |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
176 permanent, and reject it if it fails to pass the test suite. If |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
177 people only pull changes from this filtering server, it will serve to |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
178 ensure that all changes that people pull have been automatically |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
179 vetted. |
b49a7dd4e564
More content for hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
37
diff
changeset
|
180 |
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
181 \section{A short tutorial on using hooks} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
182 \label{sec:hook:simple} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
183 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
184 It is easy to write a Mercurial hook. Let's start with a hook that |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
185 runs when you finish a \hgcmd{commit}, and simply prints the hash of |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
186 the changeset you just created. The hook is called \hook{commit}. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
187 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
188 \begin{figure}[ht] |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
189 \interaction{hook.simple.init} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
190 \caption{A simple hook that runs when a changeset is committed} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
191 \label{ex:hook:init} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
192 \end{figure} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
193 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
194 All hooks follow the pattern in example~\ref{ex:hook:init}. You add |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
195 an entry to the \rcsection{hooks} section of your \hgrc\. On the left |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
196 is the name of the event to trigger on; on the right is the action to |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
197 take. As you can see, you can run an arbitrary shell command in a |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
198 hook. Mercurial passes extra information to the hook using |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
199 environment variables (look for \envar{HG\_NODE} in the example). |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
200 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
201 \subsection{Performing multiple actions per event} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
202 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
203 Quite often, you will want to define more than one hook for a |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
204 particular kind of event, as shown in example~\ref{ex:hook:ext}. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
205 Mercurial lets you do this by adding an \emph{extension} to the end of |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
206 a hook's name. You extend a hook's name by giving the name of the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
207 hook, followed by a full stop (the ``\texttt{.}'' character), followed |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
208 by some more text of your choosing. For example, Mercurial will run |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
209 both \texttt{commit.foo} and \texttt{commit.bar} when the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
210 \texttt{commit} event occurs. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
211 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
212 \begin{figure}[ht] |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
213 \interaction{hook.simple.ext} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
214 \caption{Defining a second \hook{commit} hook} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
215 \label{ex:hook:ext} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
216 \end{figure} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
217 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
218 To give a well-defined order of execution when there are multiple |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
219 hooks defined for an event, Mercurial sorts hooks by extension, and |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
220 executes the hook commands in this sorted order. In the above |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
221 example, it will execute \texttt{commit.bar} before |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
222 \texttt{commit.foo}, and \texttt{commit} before both. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
223 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
224 It is a good idea to use a somewhat descriptive extension when you |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
225 define a new hook. This will help you to remember what the hook was |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
226 for. If the hook fails, you'll get an error message that contains the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
227 hook name and extension, so using a descriptive extension could give |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
228 you an immediate hint as to why the hook failed (see |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
229 section~\ref{sec:hook:perm} for an example). |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
230 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
231 \subsection{Controlling whether an activity can proceed} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
232 \label{sec:hook:perm} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
233 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
234 In our earlier examples, we used the \hook{commit} hook, which is |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
235 run after a commit has completed. This is one of several Mercurial |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
236 hooks that run after an activity finishes. Such hooks have no way of |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
237 influencing the activity itself. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
238 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
239 Mercurial defines a number of events that occur before an activity |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
240 starts; or after it starts, but before it finishes. Hooks that |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
241 trigger on these events have the added ability to choose whether the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
242 activity can continue, or will abort. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
243 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
244 The \hook{pretxncommit} hook runs after a commit has all but |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
245 completed. In other words, the metadata representing the changeset |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
246 has been written out to disk, but the transaction has not yet been |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
247 allowed to complete. The \hook{pretxncommit} hook has the ability to |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
248 decide whether the transaction can complete, or must be rolled back. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
249 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
250 If the \hook{pretxncommit} hook exits with a status code of zero, the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
251 transaction is allowed to complete; the commit finishes; and the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
252 \hook{commit} hook is run. If the \hook{pretxncommit} hook exits with |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
253 a non-zero status code, the transaction is rolled back; the metadata |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
254 representing the changeset is erased; and the \hook{commit} hook is |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
255 not run. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
256 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
257 \begin{figure}[ht] |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
258 \interaction{hook.simple.pretxncommit} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
259 \caption{Using the \hook{pretxncommit} hook to control commits} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
260 \label{ex:hook:pretxncommit} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
261 \end{figure} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
262 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
263 The hook in example~\ref{ex:hook:pretxncommit} checks that a commit |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
264 comment contains a bug ID. If it does, the commit can complete. If |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
265 not, the commit is rolled back. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
266 |
37 | 267 \section{Writing your own hooks} |
268 | |
269 When you are writing a hook, you might find it useful to run Mercurial | |
270 either with the \hggopt{-v} option, or the \rcitem{ui}{verbose} config | |
271 item set to ``true''. When you do so, Mercurial will print a message | |
272 before it calls each hook. | |
273 | |
274 \subsection{Choosing how your hook should run} | |
275 \label{sec:hook:lang} | |
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
276 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
277 You can write a hook either as a normal program---typically a shell |
37 | 278 script---or as a Python function that is executed within the Mercurial |
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
279 process. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
280 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
281 Writing a hook as an external program has the advantage that it |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
282 requires no knowledge of Mercurial's internals. You can call normal |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
283 Mercurial commands to get any added information you need. The |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
284 trade-off is that external hooks are slower than in-process hooks. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
285 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
286 An in-process Python hook has complete access to the Mercurial API, |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
287 and does not ``shell out'' to another process, so it is inherently |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
288 faster than an external hook. It is also easier to obtain much of the |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
289 information that a hook requires by using the Mercurial API than by |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
290 running Mercurial commands. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
291 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
292 If you are comfortable with Python, or require high performance, |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
293 writing your hooks in Python may be a good choice. However, when you |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
294 have a straightforward hook to write and you don't need to care about |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
295 performance (probably the majority of hooks), a shell script is |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
296 perfectly fine. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
297 |
37 | 298 \subsection{Hook parameters} |
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
299 \label{sec:hook:param} |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
300 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
301 Mercurial calls each hook with a set of well-defined parameters. In |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
302 Python, a parameter is passed as a keyword argument to your hook |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
303 function. For an external program, a parameter is passed as an |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
304 environment variable. |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
305 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
306 Whether your hook is written in Python or as a shell script, the |
37 | 307 hook-specific parameter names and values will be the same. A boolean |
308 parameter will be represented as a boolean value in Python, but as the | |
309 number 1 (for ``true'') or 0 (for ``false'') as an environment | |
310 variable for an external hook. If a hook parameter is named | |
311 \texttt{foo}, the keyword argument for a Python hook will also be | |
312 named \texttt{foo} Python, while the environment variable for an | |
313 external hook will be named \texttt{HG\_FOO}. | |
314 | |
315 \subsection{Hook return values and activity control} | |
316 | |
317 A hook that executes successfully must exit with a status of zero if | |
318 external, or return boolean ``false'' if in-process. Failure is | |
319 indicated with a non-zero exit status from an external hook, or an | |
320 in-process hook returning boolean ``true''. If an in-process hook | |
321 raises an exception, the hook is considered to have failed. | |
322 | |
323 For a hook that controls whether an activity can proceed, zero/false | |
324 means ``allow'', while non-zero/true/exception means ``deny''. | |
325 | |
326 \subsection{Writing an external hook} | |
327 | |
328 When you define an external hook in your \hgrc\ and the hook is run, | |
329 its value is passed to your shell, which interprets it. This means | |
330 that you can use normal shell constructs in the body of the hook. | |
331 | |
332 An executable hook is always run with its current directory set to a | |
333 repository's root directory. | |
334 | |
335 Each hook parameter is passed in as an environment variable; the name | |
336 is upper-cased, and prefixed with the string ``\texttt{HG\_}''. | |
337 | |
338 With the exception of hook parameters, Mercurial does not set or | |
339 modify any environment variables when running a hook. This is useful | |
340 to remember if you are writing a site-wide hook that may be run by a | |
341 number of different users with differing environment variables set. | |
342 In multi-user situations, you should not rely on environment variables | |
343 being set to the values you have in your environment when testing the | |
344 hook. | |
345 | |
346 \subsection{Telling Mercurial to use an in-process hook} | |
347 | |
348 The \hgrc\ syntax for defining an in-process hook is slightly | |
349 different than for an executable hook. The value of the hook must | |
350 start with the text ``\texttt{python:}'', and continue with the | |
351 fully-qualified name of a callable object to use as the hook's value. | |
352 | |
353 The module in which a hook lives is automatically imported when a hook | |
354 is run. So long as you have the module name and \envar{PYTHONPATH} | |
355 right, it should ``just work''. | |
356 | |
357 The following \hgrc\ example snippet illustrates the syntax and | |
358 meaning of the notions we just described. | |
359 \begin{codesample2} | |
360 [hooks] | |
361 commit.example = python:mymodule.submodule.myhook | |
362 \end{codesample2} | |
363 When Mercurial runs the \texttt{commit.example} hook, it imports | |
364 \texttt{mymodule.submodule}, looks for the callable object named | |
365 \texttt{myhook}, and calls it. | |
366 | |
367 \subsection{Writing an in-process hook} | |
368 | |
369 The simplest in-process hook does nothing, but illustrates the basic | |
370 shape of the hook API: | |
371 \begin{codesample2} | |
372 def myhook(ui, repo, **kwargs): | |
373 pass | |
374 \end{codesample2} | |
375 The first argument to a Python hook is always a | |
376 \pymodclass{mercurial.ui}{ui} object. The second is a repository object; | |
377 at the moment, it is always an instance of | |
378 \pymodclass{mercurial.localrepo}{localrepository}. Following these two | |
379 arguments are other keyword arguments. Which ones are passed in | |
380 depends on the hook being called, but a hook can ignore arguments it | |
381 doesn't care about by dropping them into a keyword argument dict, as | |
382 with \texttt{**kwargs} above. | |
34
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
383 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
384 |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
385 %%% Local Variables: |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
386 %%% mode: latex |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
387 %%% TeX-master: "00book" |
c0979ed1eabd
Get started on hook chapter.
Bryan O'Sullivan <bos@serpentine.com>
parents:
diff
changeset
|
388 %%% End: |