##// END OF EJS Templates
dispatch: add generic pre- and post-command hooks
Matt Mackall -
r4630:e6d105a5 default
parent child Browse files
Show More
@@ -1,556 +1,566
1 HGRC(5)
1 HGRC(5)
2 =======
2 =======
3 Bryan O'Sullivan <bos@serpentine.com>
3 Bryan O'Sullivan <bos@serpentine.com>
4
4
5 NAME
5 NAME
6 ----
6 ----
7 hgrc - configuration files for Mercurial
7 hgrc - configuration files for Mercurial
8
8
9 SYNOPSIS
9 SYNOPSIS
10 --------
10 --------
11
11
12 The Mercurial system uses a set of configuration files to control
12 The Mercurial system uses a set of configuration files to control
13 aspects of its behaviour.
13 aspects of its behaviour.
14
14
15 FILES
15 FILES
16 -----
16 -----
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 The names of these files depend on the system on which Mercurial is
19 The names of these files depend on the system on which Mercurial is
20 installed.
20 installed.
21
21
22 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
22 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
23 (Unix) <install-root>/etc/mercurial/hgrc::
23 (Unix) <install-root>/etc/mercurial/hgrc::
24 Per-installation configuration files, searched for in the
24 Per-installation configuration files, searched for in the
25 directory where Mercurial is installed. For example, if installed
25 directory where Mercurial is installed. For example, if installed
26 in /shared/tools, Mercurial will look in
26 in /shared/tools, Mercurial will look in
27 /shared/tools/etc/mercurial/hgrc. Options in these files apply to
27 /shared/tools/etc/mercurial/hgrc. Options in these files apply to
28 all Mercurial commands executed by any user in any directory.
28 all Mercurial commands executed by any user in any directory.
29
29
30 (Unix) /etc/mercurial/hgrc.d/*.rc::
30 (Unix) /etc/mercurial/hgrc.d/*.rc::
31 (Unix) /etc/mercurial/hgrc::
31 (Unix) /etc/mercurial/hgrc::
32 (Windows) C:\Mercurial\Mercurial.ini::
32 (Windows) C:\Mercurial\Mercurial.ini::
33 Per-system configuration files, for the system on which Mercurial
33 Per-system configuration files, for the system on which Mercurial
34 is running. Options in these files apply to all Mercurial
34 is running. Options in these files apply to all Mercurial
35 commands executed by any user in any directory. Options in these
35 commands executed by any user in any directory. Options in these
36 files override per-installation options.
36 files override per-installation options.
37
37
38 (Unix) $HOME/.hgrc::
38 (Unix) $HOME/.hgrc::
39 (Windows) C:\Documents and Settings\USERNAME\Mercurial.ini::
39 (Windows) C:\Documents and Settings\USERNAME\Mercurial.ini::
40 (Windows) $HOME\Mercurial.ini::
40 (Windows) $HOME\Mercurial.ini::
41 Per-user configuration file, for the user running Mercurial.
41 Per-user configuration file, for the user running Mercurial.
42 Options in this file apply to all Mercurial commands executed by
42 Options in this file apply to all Mercurial commands executed by
43 any user in any directory. Options in this file override
43 any user in any directory. Options in this file override
44 per-installation and per-system options.
44 per-installation and per-system options.
45 On Windows system, one of these is chosen exclusively according
45 On Windows system, one of these is chosen exclusively according
46 to definition of HOME environment variable.
46 to definition of HOME environment variable.
47
47
48 (Unix, Windows) <repo>/.hg/hgrc::
48 (Unix, Windows) <repo>/.hg/hgrc::
49 Per-repository configuration options that only apply in a
49 Per-repository configuration options that only apply in a
50 particular repository. This file is not version-controlled, and
50 particular repository. This file is not version-controlled, and
51 will not get transferred during a "clone" operation. Options in
51 will not get transferred during a "clone" operation. Options in
52 this file override options in all other configuration files.
52 this file override options in all other configuration files.
53 On Unix, most of this file will be ignored if it doesn't belong
53 On Unix, most of this file will be ignored if it doesn't belong
54 to a trusted user or to a trusted group. See the documentation
54 to a trusted user or to a trusted group. See the documentation
55 for the trusted section below for more details.
55 for the trusted section below for more details.
56
56
57 SYNTAX
57 SYNTAX
58 ------
58 ------
59
59
60 A configuration file consists of sections, led by a "[section]" header
60 A configuration file consists of sections, led by a "[section]" header
61 and followed by "name: value" entries; "name=value" is also accepted.
61 and followed by "name: value" entries; "name=value" is also accepted.
62
62
63 [spam]
63 [spam]
64 eggs=ham
64 eggs=ham
65 green=
65 green=
66 eggs
66 eggs
67
67
68 Each line contains one entry. If the lines that follow are indented,
68 Each line contains one entry. If the lines that follow are indented,
69 they are treated as continuations of that entry.
69 they are treated as continuations of that entry.
70
70
71 Leading whitespace is removed from values. Empty lines are skipped.
71 Leading whitespace is removed from values. Empty lines are skipped.
72
72
73 The optional values can contain format strings which refer to other
73 The optional values can contain format strings which refer to other
74 values in the same section, or values in a special DEFAULT section.
74 values in the same section, or values in a special DEFAULT section.
75
75
76 Lines beginning with "#" or ";" are ignored and may be used to provide
76 Lines beginning with "#" or ";" are ignored and may be used to provide
77 comments.
77 comments.
78
78
79 SECTIONS
79 SECTIONS
80 --------
80 --------
81
81
82 This section describes the different sections that may appear in a
82 This section describes the different sections that may appear in a
83 Mercurial "hgrc" file, the purpose of each section, its possible
83 Mercurial "hgrc" file, the purpose of each section, its possible
84 keys, and their possible values.
84 keys, and their possible values.
85
85
86 decode/encode::
86 decode/encode::
87 Filters for transforming files on checkout/checkin. This would
87 Filters for transforming files on checkout/checkin. This would
88 typically be used for newline processing or other
88 typically be used for newline processing or other
89 localization/canonicalization of files.
89 localization/canonicalization of files.
90
90
91 Filters consist of a filter pattern followed by a filter command.
91 Filters consist of a filter pattern followed by a filter command.
92 Filter patterns are globs by default, rooted at the repository
92 Filter patterns are globs by default, rooted at the repository
93 root. For example, to match any file ending in ".txt" in the root
93 root. For example, to match any file ending in ".txt" in the root
94 directory only, use the pattern "*.txt". To match any file ending
94 directory only, use the pattern "*.txt". To match any file ending
95 in ".c" anywhere in the repository, use the pattern "**.c".
95 in ".c" anywhere in the repository, use the pattern "**.c".
96
96
97 The filter command can start with a specifier, either "pipe:" or
97 The filter command can start with a specifier, either "pipe:" or
98 "tempfile:". If no specifier is given, "pipe:" is used by default.
98 "tempfile:". If no specifier is given, "pipe:" is used by default.
99
99
100 A "pipe:" command must accept data on stdin and return the
100 A "pipe:" command must accept data on stdin and return the
101 transformed data on stdout.
101 transformed data on stdout.
102
102
103 Pipe example:
103 Pipe example:
104
104
105 [encode]
105 [encode]
106 # uncompress gzip files on checkin to improve delta compression
106 # uncompress gzip files on checkin to improve delta compression
107 # note: not necessarily a good idea, just an example
107 # note: not necessarily a good idea, just an example
108 *.gz = pipe: gunzip
108 *.gz = pipe: gunzip
109
109
110 [decode]
110 [decode]
111 # recompress gzip files when writing them to the working dir (we
111 # recompress gzip files when writing them to the working dir (we
112 # can safely omit "pipe:", because it's the default)
112 # can safely omit "pipe:", because it's the default)
113 *.gz = gzip
113 *.gz = gzip
114
114
115 A "tempfile:" command is a template. The string INFILE is replaced
115 A "tempfile:" command is a template. The string INFILE is replaced
116 with the name of a temporary file that contains the data to be
116 with the name of a temporary file that contains the data to be
117 filtered by the command. The string OUTFILE is replaced with the
117 filtered by the command. The string OUTFILE is replaced with the
118 name of an empty temporary file, where the filtered data must be
118 name of an empty temporary file, where the filtered data must be
119 written by the command.
119 written by the command.
120
120
121 NOTE: the tempfile mechanism is recommended for Windows systems,
121 NOTE: the tempfile mechanism is recommended for Windows systems,
122 where the standard shell I/O redirection operators often have
122 where the standard shell I/O redirection operators often have
123 strange effects. In particular, if you are doing line ending
123 strange effects. In particular, if you are doing line ending
124 conversion on Windows using the popular dos2unix and unix2dos
124 conversion on Windows using the popular dos2unix and unix2dos
125 programs, you *must* use the tempfile mechanism, as using pipes will
125 programs, you *must* use the tempfile mechanism, as using pipes will
126 corrupt the contents of your files.
126 corrupt the contents of your files.
127
127
128 Tempfile example:
128 Tempfile example:
129
129
130 [encode]
130 [encode]
131 # convert files to unix line ending conventions on checkin
131 # convert files to unix line ending conventions on checkin
132 **.txt = tempfile: dos2unix -n INFILE OUTFILE
132 **.txt = tempfile: dos2unix -n INFILE OUTFILE
133
133
134 [decode]
134 [decode]
135 # convert files to windows line ending conventions when writing
135 # convert files to windows line ending conventions when writing
136 # them to the working dir
136 # them to the working dir
137 **.txt = tempfile: unix2dos -n INFILE OUTFILE
137 **.txt = tempfile: unix2dos -n INFILE OUTFILE
138
138
139 defaults::
139 defaults::
140 Use the [defaults] section to define command defaults, i.e. the
140 Use the [defaults] section to define command defaults, i.e. the
141 default options/arguments to pass to the specified commands.
141 default options/arguments to pass to the specified commands.
142
142
143 The following example makes 'hg log' run in verbose mode, and
143 The following example makes 'hg log' run in verbose mode, and
144 'hg status' show only the modified files, by default.
144 'hg status' show only the modified files, by default.
145
145
146 [defaults]
146 [defaults]
147 log = -v
147 log = -v
148 status = -m
148 status = -m
149
149
150 The actual commands, instead of their aliases, must be used when
150 The actual commands, instead of their aliases, must be used when
151 defining command defaults. The command defaults will also be
151 defining command defaults. The command defaults will also be
152 applied to the aliases of the commands defined.
152 applied to the aliases of the commands defined.
153
153
154 diff::
154 diff::
155 Settings used when displaying diffs. They are all boolean and
155 Settings used when displaying diffs. They are all boolean and
156 defaults to False.
156 defaults to False.
157 git;;
157 git;;
158 Use git extended diff format.
158 Use git extended diff format.
159 nodates;;
159 nodates;;
160 Don't include dates in diff headers.
160 Don't include dates in diff headers.
161 showfunc;;
161 showfunc;;
162 Show which function each change is in.
162 Show which function each change is in.
163 ignorews;;
163 ignorews;;
164 Ignore white space when comparing lines.
164 Ignore white space when comparing lines.
165 ignorewsamount;;
165 ignorewsamount;;
166 Ignore changes in the amount of white space.
166 Ignore changes in the amount of white space.
167 ignoreblanklines;;
167 ignoreblanklines;;
168 Ignore changes whose lines are all blank.
168 Ignore changes whose lines are all blank.
169
169
170 email::
170 email::
171 Settings for extensions that send email messages.
171 Settings for extensions that send email messages.
172 from;;
172 from;;
173 Optional. Email address to use in "From" header and SMTP envelope
173 Optional. Email address to use in "From" header and SMTP envelope
174 of outgoing messages.
174 of outgoing messages.
175 to;;
175 to;;
176 Optional. Comma-separated list of recipients' email addresses.
176 Optional. Comma-separated list of recipients' email addresses.
177 cc;;
177 cc;;
178 Optional. Comma-separated list of carbon copy recipients'
178 Optional. Comma-separated list of carbon copy recipients'
179 email addresses.
179 email addresses.
180 bcc;;
180 bcc;;
181 Optional. Comma-separated list of blind carbon copy
181 Optional. Comma-separated list of blind carbon copy
182 recipients' email addresses. Cannot be set interactively.
182 recipients' email addresses. Cannot be set interactively.
183 method;;
183 method;;
184 Optional. Method to use to send email messages. If value is
184 Optional. Method to use to send email messages. If value is
185 "smtp" (default), use SMTP (see section "[smtp]" for
185 "smtp" (default), use SMTP (see section "[smtp]" for
186 configuration). Otherwise, use as name of program to run that
186 configuration). Otherwise, use as name of program to run that
187 acts like sendmail (takes "-f" option for sender, list of
187 acts like sendmail (takes "-f" option for sender, list of
188 recipients on command line, message on stdin). Normally, setting
188 recipients on command line, message on stdin). Normally, setting
189 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
189 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
190 sendmail to send messages.
190 sendmail to send messages.
191
191
192 Email example:
192 Email example:
193
193
194 [email]
194 [email]
195 from = Joseph User <joe.user@example.com>
195 from = Joseph User <joe.user@example.com>
196 method = /usr/sbin/sendmail
196 method = /usr/sbin/sendmail
197
197
198 extensions::
198 extensions::
199 Mercurial has an extension mechanism for adding new features. To
199 Mercurial has an extension mechanism for adding new features. To
200 enable an extension, create an entry for it in this section.
200 enable an extension, create an entry for it in this section.
201
201
202 If you know that the extension is already in Python's search path,
202 If you know that the extension is already in Python's search path,
203 you can give the name of the module, followed by "=", with nothing
203 you can give the name of the module, followed by "=", with nothing
204 after the "=".
204 after the "=".
205
205
206 Otherwise, give a name that you choose, followed by "=", followed by
206 Otherwise, give a name that you choose, followed by "=", followed by
207 the path to the ".py" file (including the file name extension) that
207 the path to the ".py" file (including the file name extension) that
208 defines the extension.
208 defines the extension.
209
209
210 Example for ~/.hgrc:
210 Example for ~/.hgrc:
211
211
212 [extensions]
212 [extensions]
213 # (the mq extension will get loaded from mercurial's path)
213 # (the mq extension will get loaded from mercurial's path)
214 hgext.mq =
214 hgext.mq =
215 # (this extension will get loaded from the file specified)
215 # (this extension will get loaded from the file specified)
216 myfeature = ~/.hgext/myfeature.py
216 myfeature = ~/.hgext/myfeature.py
217
217
218 format::
218 format::
219
219
220 usestore;;
220 usestore;;
221 Enable or disable the "store" repository format which improves
221 Enable or disable the "store" repository format which improves
222 compatibility with systems that fold case or otherwise mangle
222 compatibility with systems that fold case or otherwise mangle
223 filenames. Enabled by default. Disabling this option will allow
223 filenames. Enabled by default. Disabling this option will allow
224 you to store longer filenames in some situations at the expense of
224 you to store longer filenames in some situations at the expense of
225 compatibility.
225 compatibility.
226
226
227 hooks::
227 hooks::
228 Commands or Python functions that get automatically executed by
228 Commands or Python functions that get automatically executed by
229 various actions such as starting or finishing a commit. Multiple
229 various actions such as starting or finishing a commit. Multiple
230 hooks can be run for the same action by appending a suffix to the
230 hooks can be run for the same action by appending a suffix to the
231 action. Overriding a site-wide hook can be done by changing its
231 action. Overriding a site-wide hook can be done by changing its
232 value or setting it to an empty string.
232 value or setting it to an empty string.
233
233
234 Example .hg/hgrc:
234 Example .hg/hgrc:
235
235
236 [hooks]
236 [hooks]
237 # do not use the site-wide hook
237 # do not use the site-wide hook
238 incoming =
238 incoming =
239 incoming.email = /my/email/hook
239 incoming.email = /my/email/hook
240 incoming.autobuild = /my/build/hook
240 incoming.autobuild = /my/build/hook
241
241
242 Most hooks are run with environment variables set that give added
242 Most hooks are run with environment variables set that give added
243 useful information. For each hook below, the environment variables
243 useful information. For each hook below, the environment variables
244 it is passed are listed with names of the form "$HG_foo".
244 it is passed are listed with names of the form "$HG_foo".
245
245
246 changegroup;;
246 changegroup;;
247 Run after a changegroup has been added via push, pull or
247 Run after a changegroup has been added via push, pull or
248 unbundle. ID of the first new changeset is in $HG_NODE. URL from
248 unbundle. ID of the first new changeset is in $HG_NODE. URL from
249 which changes came is in $HG_URL.
249 which changes came is in $HG_URL.
250 commit;;
250 commit;;
251 Run after a changeset has been created in the local repository.
251 Run after a changeset has been created in the local repository.
252 ID of the newly created changeset is in $HG_NODE. Parent
252 ID of the newly created changeset is in $HG_NODE. Parent
253 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
253 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
254 incoming;;
254 incoming;;
255 Run after a changeset has been pulled, pushed, or unbundled into
255 Run after a changeset has been pulled, pushed, or unbundled into
256 the local repository. The ID of the newly arrived changeset is in
256 the local repository. The ID of the newly arrived changeset is in
257 $HG_NODE. URL that was source of changes came is in $HG_URL.
257 $HG_NODE. URL that was source of changes came is in $HG_URL.
258 outgoing;;
258 outgoing;;
259 Run after sending changes from local repository to another. ID of
259 Run after sending changes from local repository to another. ID of
260 first changeset sent is in $HG_NODE. Source of operation is in
260 first changeset sent is in $HG_NODE. Source of operation is in
261 $HG_SOURCE; see "preoutgoing" hook for description.
261 $HG_SOURCE; see "preoutgoing" hook for description.
262 prechangegroup;;
262 prechangegroup;;
263 Run before a changegroup is added via push, pull or unbundle.
263 Run before a changegroup is added via push, pull or unbundle.
264 Exit status 0 allows the changegroup to proceed. Non-zero status
264 Exit status 0 allows the changegroup to proceed. Non-zero status
265 will cause the push, pull or unbundle to fail. URL from which
265 will cause the push, pull or unbundle to fail. URL from which
266 changes will come is in $HG_URL.
266 changes will come is in $HG_URL.
267 precommit;;
267 precommit;;
268 Run before starting a local commit. Exit status 0 allows the
268 Run before starting a local commit. Exit status 0 allows the
269 commit to proceed. Non-zero status will cause the commit to fail.
269 commit to proceed. Non-zero status will cause the commit to fail.
270 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
270 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
271 preoutgoing;;
271 preoutgoing;;
272 Run before computing changes to send from the local repository to
272 Run before computing changes to send from the local repository to
273 another. Non-zero status will cause failure. This lets you
273 another. Non-zero status will cause failure. This lets you
274 prevent pull over http or ssh. Also prevents against local pull,
274 prevent pull over http or ssh. Also prevents against local pull,
275 push (outbound) or bundle commands, but not effective, since you
275 push (outbound) or bundle commands, but not effective, since you
276 can just copy files instead then. Source of operation is in
276 can just copy files instead then. Source of operation is in
277 $HG_SOURCE. If "serve", operation is happening on behalf of
277 $HG_SOURCE. If "serve", operation is happening on behalf of
278 remote ssh or http repository. If "push", "pull" or "bundle",
278 remote ssh or http repository. If "push", "pull" or "bundle",
279 operation is happening on behalf of repository on same system.
279 operation is happening on behalf of repository on same system.
280 pretag;;
280 pretag;;
281 Run before creating a tag. Exit status 0 allows the tag to be
281 Run before creating a tag. Exit status 0 allows the tag to be
282 created. Non-zero status will cause the tag to fail. ID of
282 created. Non-zero status will cause the tag to fail. ID of
283 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
283 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
284 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
284 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
285 pretxnchangegroup;;
285 pretxnchangegroup;;
286 Run after a changegroup has been added via push, pull or unbundle,
286 Run after a changegroup has been added via push, pull or unbundle,
287 but before the transaction has been committed. Changegroup is
287 but before the transaction has been committed. Changegroup is
288 visible to hook program. This lets you validate incoming changes
288 visible to hook program. This lets you validate incoming changes
289 before accepting them. Passed the ID of the first new changeset
289 before accepting them. Passed the ID of the first new changeset
290 in $HG_NODE. Exit status 0 allows the transaction to commit.
290 in $HG_NODE. Exit status 0 allows the transaction to commit.
291 Non-zero status will cause the transaction to be rolled back and
291 Non-zero status will cause the transaction to be rolled back and
292 the push, pull or unbundle will fail. URL that was source of
292 the push, pull or unbundle will fail. URL that was source of
293 changes is in $HG_URL.
293 changes is in $HG_URL.
294 pretxncommit;;
294 pretxncommit;;
295 Run after a changeset has been created but the transaction not yet
295 Run after a changeset has been created but the transaction not yet
296 committed. Changeset is visible to hook program. This lets you
296 committed. Changeset is visible to hook program. This lets you
297 validate commit message and changes. Exit status 0 allows the
297 validate commit message and changes. Exit status 0 allows the
298 commit to proceed. Non-zero status will cause the transaction to
298 commit to proceed. Non-zero status will cause the transaction to
299 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
299 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
300 IDs are in $HG_PARENT1 and $HG_PARENT2.
300 IDs are in $HG_PARENT1 and $HG_PARENT2.
301 preupdate;;
301 preupdate;;
302 Run before updating the working directory. Exit status 0 allows
302 Run before updating the working directory. Exit status 0 allows
303 the update to proceed. Non-zero status will prevent the update.
303 the update to proceed. Non-zero status will prevent the update.
304 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
304 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
305 of second new parent is in $HG_PARENT2.
305 of second new parent is in $HG_PARENT2.
306 tag;;
306 tag;;
307 Run after a tag is created. ID of tagged changeset is in
307 Run after a tag is created. ID of tagged changeset is in
308 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
308 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
309 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
309 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
310 update;;
310 update;;
311 Run after updating the working directory. Changeset ID of first
311 Run after updating the working directory. Changeset ID of first
312 new parent is in $HG_PARENT1. If merge, ID of second new parent
312 new parent is in $HG_PARENT1. If merge, ID of second new parent
313 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
313 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
314 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
314 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
315 pre-<command>;;
316 Run before executing the associated command. The contents of the
317 command line are passed as $HG_ARGS. If the hook returns failure,
318 the command doesn't execute and Mercurial returns the failure code.
319 post-<command>;;
320 Run after successful invocations of the associated command. The
321 contents of the command line are passed as $HG_ARGS and the result
322 code in $HG_RESULT. Hook failure is ignored.
315
323
316 Note: In earlier releases, the names of hook environment variables
324 Note: it is generally better to use standard hooks rather than the
317 did not have a "HG_" prefix. The old unprefixed names are no longer
325 generic pre- and post- command hooks as they are guaranteed to be
318 provided in the environment.
326 called in the appropriate contexts for influencing transactions.
327 Also, hooks like "commit" will be called in all contexts that
328 generate a commit (eg. tag) and not just the commit command.
319
329
320 The syntax for Python hooks is as follows:
330 The syntax for Python hooks is as follows:
321
331
322 hookname = python:modulename.submodule.callable
332 hookname = python:modulename.submodule.callable
323
333
324 Python hooks are run within the Mercurial process. Each hook is
334 Python hooks are run within the Mercurial process. Each hook is
325 called with at least three keyword arguments: a ui object (keyword
335 called with at least three keyword arguments: a ui object (keyword
326 "ui"), a repository object (keyword "repo"), and a "hooktype"
336 "ui"), a repository object (keyword "repo"), and a "hooktype"
327 keyword that tells what kind of hook is used. Arguments listed as
337 keyword that tells what kind of hook is used. Arguments listed as
328 environment variables above are passed as keyword arguments, with no
338 environment variables above are passed as keyword arguments, with no
329 "HG_" prefix, and names in lower case.
339 "HG_" prefix, and names in lower case.
330
340
331 If a Python hook returns a "true" value or raises an exception, this
341 If a Python hook returns a "true" value or raises an exception, this
332 is treated as failure of the hook.
342 is treated as failure of the hook.
333
343
334 http_proxy::
344 http_proxy::
335 Used to access web-based Mercurial repositories through a HTTP
345 Used to access web-based Mercurial repositories through a HTTP
336 proxy.
346 proxy.
337 host;;
347 host;;
338 Host name and (optional) port of the proxy server, for example
348 Host name and (optional) port of the proxy server, for example
339 "myproxy:8000".
349 "myproxy:8000".
340 no;;
350 no;;
341 Optional. Comma-separated list of host names that should bypass
351 Optional. Comma-separated list of host names that should bypass
342 the proxy.
352 the proxy.
343 passwd;;
353 passwd;;
344 Optional. Password to authenticate with at the proxy server.
354 Optional. Password to authenticate with at the proxy server.
345 user;;
355 user;;
346 Optional. User name to authenticate with at the proxy server.
356 Optional. User name to authenticate with at the proxy server.
347
357
348 smtp::
358 smtp::
349 Configuration for extensions that need to send email messages.
359 Configuration for extensions that need to send email messages.
350 host;;
360 host;;
351 Host name of mail server, e.g. "mail.example.com".
361 Host name of mail server, e.g. "mail.example.com".
352 port;;
362 port;;
353 Optional. Port to connect to on mail server. Default: 25.
363 Optional. Port to connect to on mail server. Default: 25.
354 tls;;
364 tls;;
355 Optional. Whether to connect to mail server using TLS. True or
365 Optional. Whether to connect to mail server using TLS. True or
356 False. Default: False.
366 False. Default: False.
357 username;;
367 username;;
358 Optional. User name to authenticate to SMTP server with.
368 Optional. User name to authenticate to SMTP server with.
359 If username is specified, password must also be specified.
369 If username is specified, password must also be specified.
360 Default: none.
370 Default: none.
361 password;;
371 password;;
362 Optional. Password to authenticate to SMTP server with.
372 Optional. Password to authenticate to SMTP server with.
363 If username is specified, password must also be specified.
373 If username is specified, password must also be specified.
364 Default: none.
374 Default: none.
365 local_hostname;;
375 local_hostname;;
366 Optional. It's the hostname that the sender can use to identify itself
376 Optional. It's the hostname that the sender can use to identify itself
367 to the MTA.
377 to the MTA.
368
378
369 paths::
379 paths::
370 Assigns symbolic names to repositories. The left side is the
380 Assigns symbolic names to repositories. The left side is the
371 symbolic name, and the right gives the directory or URL that is the
381 symbolic name, and the right gives the directory or URL that is the
372 location of the repository. Default paths can be declared by
382 location of the repository. Default paths can be declared by
373 setting the following entries.
383 setting the following entries.
374 default;;
384 default;;
375 Directory or URL to use when pulling if no source is specified.
385 Directory or URL to use when pulling if no source is specified.
376 Default is set to repository from which the current repository
386 Default is set to repository from which the current repository
377 was cloned.
387 was cloned.
378 default-push;;
388 default-push;;
379 Optional. Directory or URL to use when pushing if no destination
389 Optional. Directory or URL to use when pushing if no destination
380 is specified.
390 is specified.
381
391
382 server::
392 server::
383 Controls generic server settings.
393 Controls generic server settings.
384 uncompressed;;
394 uncompressed;;
385 Whether to allow clients to clone a repo using the uncompressed
395 Whether to allow clients to clone a repo using the uncompressed
386 streaming protocol. This transfers about 40% more data than a
396 streaming protocol. This transfers about 40% more data than a
387 regular clone, but uses less memory and CPU on both server and
397 regular clone, but uses less memory and CPU on both server and
388 client. Over a LAN (100Mbps or better) or a very fast WAN, an
398 client. Over a LAN (100Mbps or better) or a very fast WAN, an
389 uncompressed streaming clone is a lot faster (~10x) than a regular
399 uncompressed streaming clone is a lot faster (~10x) than a regular
390 clone. Over most WAN connections (anything slower than about
400 clone. Over most WAN connections (anything slower than about
391 6Mbps), uncompressed streaming is slower, because of the extra
401 6Mbps), uncompressed streaming is slower, because of the extra
392 data transfer overhead. Default is False.
402 data transfer overhead. Default is False.
393
403
394 trusted::
404 trusted::
395 For security reasons, Mercurial will not use the settings in
405 For security reasons, Mercurial will not use the settings in
396 the .hg/hgrc file from a repository if it doesn't belong to a
406 the .hg/hgrc file from a repository if it doesn't belong to a
397 trusted user or to a trusted group. The main exception is the
407 trusted user or to a trusted group. The main exception is the
398 web interface, which automatically uses some safe settings, since
408 web interface, which automatically uses some safe settings, since
399 it's common to serve repositories from different users.
409 it's common to serve repositories from different users.
400
410
401 This section specifies what users and groups are trusted. The
411 This section specifies what users and groups are trusted. The
402 current user is always trusted. To trust everybody, list a user
412 current user is always trusted. To trust everybody, list a user
403 or a group with name "*".
413 or a group with name "*".
404
414
405 users;;
415 users;;
406 Comma-separated list of trusted users.
416 Comma-separated list of trusted users.
407 groups;;
417 groups;;
408 Comma-separated list of trusted groups.
418 Comma-separated list of trusted groups.
409
419
410 ui::
420 ui::
411 User interface controls.
421 User interface controls.
412 debug;;
422 debug;;
413 Print debugging information. True or False. Default is False.
423 Print debugging information. True or False. Default is False.
414 editor;;
424 editor;;
415 The editor to use during a commit. Default is $EDITOR or "vi".
425 The editor to use during a commit. Default is $EDITOR or "vi".
416 fallbackencoding;;
426 fallbackencoding;;
417 Encoding to try if it's not possible to decode the changelog using
427 Encoding to try if it's not possible to decode the changelog using
418 UTF-8. Default is ISO-8859-1.
428 UTF-8. Default is ISO-8859-1.
419 ignore;;
429 ignore;;
420 A file to read per-user ignore patterns from. This file should be in
430 A file to read per-user ignore patterns from. This file should be in
421 the same format as a repository-wide .hgignore file. This option
431 the same format as a repository-wide .hgignore file. This option
422 supports hook syntax, so if you want to specify multiple ignore
432 supports hook syntax, so if you want to specify multiple ignore
423 files, you can do so by setting something like
433 files, you can do so by setting something like
424 "ignore.other = ~/.hgignore2". For details of the ignore file
434 "ignore.other = ~/.hgignore2". For details of the ignore file
425 format, see the hgignore(5) man page.
435 format, see the hgignore(5) man page.
426 interactive;;
436 interactive;;
427 Allow to prompt the user. True or False. Default is True.
437 Allow to prompt the user. True or False. Default is True.
428 logtemplate;;
438 logtemplate;;
429 Template string for commands that print changesets.
439 Template string for commands that print changesets.
430 style;;
440 style;;
431 Name of style to use for command output.
441 Name of style to use for command output.
432 merge;;
442 merge;;
433 The conflict resolution program to use during a manual merge.
443 The conflict resolution program to use during a manual merge.
434 Default is "hgmerge".
444 Default is "hgmerge".
435 patch;;
445 patch;;
436 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
446 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
437 unset.
447 unset.
438 quiet;;
448 quiet;;
439 Reduce the amount of output printed. True or False. Default is False.
449 Reduce the amount of output printed. True or False. Default is False.
440 remotecmd;;
450 remotecmd;;
441 remote command to use for clone/push/pull operations. Default is 'hg'.
451 remote command to use for clone/push/pull operations. Default is 'hg'.
442 slash;;
452 slash;;
443 Display paths using a slash ("/") as the path separator. This only
453 Display paths using a slash ("/") as the path separator. This only
444 makes a difference on systems where the default path separator is not
454 makes a difference on systems where the default path separator is not
445 the slash character (e.g. Windows uses the backslash character ("\")).
455 the slash character (e.g. Windows uses the backslash character ("\")).
446 Default is False.
456 Default is False.
447 ssh;;
457 ssh;;
448 command to use for SSH connections. Default is 'ssh'.
458 command to use for SSH connections. Default is 'ssh'.
449 strict;;
459 strict;;
450 Require exact command names, instead of allowing unambiguous
460 Require exact command names, instead of allowing unambiguous
451 abbreviations. True or False. Default is False.
461 abbreviations. True or False. Default is False.
452 timeout;;
462 timeout;;
453 The timeout used when a lock is held (in seconds), a negative value
463 The timeout used when a lock is held (in seconds), a negative value
454 means no timeout. Default is 600.
464 means no timeout. Default is 600.
455 username;;
465 username;;
456 The committer of a changeset created when running "commit".
466 The committer of a changeset created when running "commit".
457 Typically a person's name and email address, e.g. "Fred Widget
467 Typically a person's name and email address, e.g. "Fred Widget
458 <fred@example.com>". Default is $EMAIL or username@hostname.
468 <fred@example.com>". Default is $EMAIL or username@hostname.
459 If the username in hgrc is empty, it has to be specified manually or
469 If the username in hgrc is empty, it has to be specified manually or
460 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
470 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
461 in the system hgrc).
471 in the system hgrc).
462 verbose;;
472 verbose;;
463 Increase the amount of output printed. True or False. Default is False.
473 Increase the amount of output printed. True or False. Default is False.
464
474
465
475
466 web::
476 web::
467 Web interface configuration.
477 Web interface configuration.
468 accesslog;;
478 accesslog;;
469 Where to output the access log. Default is stdout.
479 Where to output the access log. Default is stdout.
470 address;;
480 address;;
471 Interface address to bind to. Default is all.
481 Interface address to bind to. Default is all.
472 allow_archive;;
482 allow_archive;;
473 List of archive format (bz2, gz, zip) allowed for downloading.
483 List of archive format (bz2, gz, zip) allowed for downloading.
474 Default is empty.
484 Default is empty.
475 allowbz2;;
485 allowbz2;;
476 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
486 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
477 Default is false.
487 Default is false.
478 allowgz;;
488 allowgz;;
479 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
489 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
480 Default is false.
490 Default is false.
481 allowpull;;
491 allowpull;;
482 Whether to allow pulling from the repository. Default is true.
492 Whether to allow pulling from the repository. Default is true.
483 allow_push;;
493 allow_push;;
484 Whether to allow pushing to the repository. If empty or not set,
494 Whether to allow pushing to the repository. If empty or not set,
485 push is not allowed. If the special value "*", any remote user
495 push is not allowed. If the special value "*", any remote user
486 can push, including unauthenticated users. Otherwise, the remote
496 can push, including unauthenticated users. Otherwise, the remote
487 user must have been authenticated, and the authenticated user name
497 user must have been authenticated, and the authenticated user name
488 must be present in this list (separated by whitespace or ",").
498 must be present in this list (separated by whitespace or ",").
489 The contents of the allow_push list are examined after the
499 The contents of the allow_push list are examined after the
490 deny_push list.
500 deny_push list.
491 allowzip;;
501 allowzip;;
492 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
502 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
493 Default is false. This feature creates temporary files.
503 Default is false. This feature creates temporary files.
494 baseurl;;
504 baseurl;;
495 Base URL to use when publishing URLs in other locations, so
505 Base URL to use when publishing URLs in other locations, so
496 third-party tools like email notification hooks can construct URLs.
506 third-party tools like email notification hooks can construct URLs.
497 Example: "http://hgserver/repos/"
507 Example: "http://hgserver/repos/"
498 contact;;
508 contact;;
499 Name or email address of the person in charge of the repository.
509 Name or email address of the person in charge of the repository.
500 Default is "unknown".
510 Default is "unknown".
501 deny_push;;
511 deny_push;;
502 Whether to deny pushing to the repository. If empty or not set,
512 Whether to deny pushing to the repository. If empty or not set,
503 push is not denied. If the special value "*", all remote users
513 push is not denied. If the special value "*", all remote users
504 are denied push. Otherwise, unauthenticated users are all denied,
514 are denied push. Otherwise, unauthenticated users are all denied,
505 and any authenticated user name present in this list (separated by
515 and any authenticated user name present in this list (separated by
506 whitespace or ",") is also denied. The contents of the deny_push
516 whitespace or ",") is also denied. The contents of the deny_push
507 list are examined before the allow_push list.
517 list are examined before the allow_push list.
508 description;;
518 description;;
509 Textual description of the repository's purpose or contents.
519 Textual description of the repository's purpose or contents.
510 Default is "unknown".
520 Default is "unknown".
511 errorlog;;
521 errorlog;;
512 Where to output the error log. Default is stderr.
522 Where to output the error log. Default is stderr.
513 ipv6;;
523 ipv6;;
514 Whether to use IPv6. Default is false.
524 Whether to use IPv6. Default is false.
515 name;;
525 name;;
516 Repository name to use in the web interface. Default is current
526 Repository name to use in the web interface. Default is current
517 working directory.
527 working directory.
518 maxchanges;;
528 maxchanges;;
519 Maximum number of changes to list on the changelog. Default is 10.
529 Maximum number of changes to list on the changelog. Default is 10.
520 maxfiles;;
530 maxfiles;;
521 Maximum number of files to list per changeset. Default is 10.
531 Maximum number of files to list per changeset. Default is 10.
522 port;;
532 port;;
523 Port to listen on. Default is 8000.
533 Port to listen on. Default is 8000.
524 push_ssl;;
534 push_ssl;;
525 Whether to require that inbound pushes be transported over SSL to
535 Whether to require that inbound pushes be transported over SSL to
526 prevent password sniffing. Default is true.
536 prevent password sniffing. Default is true.
527 staticurl;;
537 staticurl;;
528 Base URL to use for static files. If unset, static files (e.g.
538 Base URL to use for static files. If unset, static files (e.g.
529 the hgicon.png favicon) will be served by the CGI script itself.
539 the hgicon.png favicon) will be served by the CGI script itself.
530 Use this setting to serve them directly with the HTTP server.
540 Use this setting to serve them directly with the HTTP server.
531 Example: "http://hgserver/static/"
541 Example: "http://hgserver/static/"
532 stripes;;
542 stripes;;
533 How many lines a "zebra stripe" should span in multiline output.
543 How many lines a "zebra stripe" should span in multiline output.
534 Default is 1; set to 0 to disable.
544 Default is 1; set to 0 to disable.
535 style;;
545 style;;
536 Which template map style to use.
546 Which template map style to use.
537 templates;;
547 templates;;
538 Where to find the HTML templates. Default is install path.
548 Where to find the HTML templates. Default is install path.
539
549
540
550
541 AUTHOR
551 AUTHOR
542 ------
552 ------
543 Bryan O'Sullivan <bos@serpentine.com>.
553 Bryan O'Sullivan <bos@serpentine.com>.
544
554
545 Mercurial was written by Matt Mackall <mpm@selenic.com>.
555 Mercurial was written by Matt Mackall <mpm@selenic.com>.
546
556
547 SEE ALSO
557 SEE ALSO
548 --------
558 --------
549 hg(1), hgignore(5)
559 hg(1), hgignore(5)
550
560
551 COPYING
561 COPYING
552 -------
562 -------
553 This manual page is copyright 2005 Bryan O'Sullivan.
563 This manual page is copyright 2005 Bryan O'Sullivan.
554 Mercurial is copyright 2005, 2006 Matt Mackall.
564 Mercurial is copyright 2005, 2006 Matt Mackall.
555 Free use of this software is granted under the terms of the GNU General
565 Free use of this software is granted under the terms of the GNU General
556 Public License (GPL).
566 Public License (GPL).
@@ -1,1208 +1,1217
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
11 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
11 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
12 import fancyopts, revlog, version, extensions
12 import fancyopts, revlog, version, extensions, hook
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
19 """Exception raised if command shortcut matches more than one command."""
20 class ParseError(Exception):
20 class ParseError(Exception):
21 """Exception raised on errors in parsing the command line."""
21 """Exception raised on errors in parsing the command line."""
22
22
23 def runcatch(ui, args):
23 def runcatch(ui, args):
24 def catchterm(*args):
24 def catchterm(*args):
25 raise util.SignalInterrupt
25 raise util.SignalInterrupt
26
26
27 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
27 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
28 num = getattr(signal, name, None)
28 num = getattr(signal, name, None)
29 if num: signal.signal(num, catchterm)
29 if num: signal.signal(num, catchterm)
30
30
31 try:
31 try:
32 try:
32 try:
33 # enter the debugger before command execution
33 # enter the debugger before command execution
34 if '--debugger' in args:
34 if '--debugger' in args:
35 pdb.set_trace()
35 pdb.set_trace()
36 try:
36 try:
37 return dispatch(ui, args)
37 return dispatch(ui, args)
38 finally:
38 finally:
39 ui.flush()
39 ui.flush()
40 except:
40 except:
41 # enter the debugger when we hit an exception
41 # enter the debugger when we hit an exception
42 if '--debugger' in args:
42 if '--debugger' in args:
43 pdb.post_mortem(sys.exc_info()[2])
43 pdb.post_mortem(sys.exc_info()[2])
44 ui.print_exc()
44 ui.print_exc()
45 raise
45 raise
46
46
47 except ParseError, inst:
47 except ParseError, inst:
48 if inst.args[0]:
48 if inst.args[0]:
49 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
49 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
50 commands.help_(ui, inst.args[0])
50 commands.help_(ui, inst.args[0])
51 else:
51 else:
52 ui.warn(_("hg: %s\n") % inst.args[1])
52 ui.warn(_("hg: %s\n") % inst.args[1])
53 commands.help_(ui, 'shortlist')
53 commands.help_(ui, 'shortlist')
54 except AmbiguousCommand, inst:
54 except AmbiguousCommand, inst:
55 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
55 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
56 (inst.args[0], " ".join(inst.args[1])))
56 (inst.args[0], " ".join(inst.args[1])))
57 except UnknownCommand, inst:
57 except UnknownCommand, inst:
58 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
58 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
59 commands.help_(ui, 'shortlist')
59 commands.help_(ui, 'shortlist')
60 except hg.RepoError, inst:
60 except hg.RepoError, inst:
61 ui.warn(_("abort: %s!\n") % inst)
61 ui.warn(_("abort: %s!\n") % inst)
62 except lock.LockHeld, inst:
62 except lock.LockHeld, inst:
63 if inst.errno == errno.ETIMEDOUT:
63 if inst.errno == errno.ETIMEDOUT:
64 reason = _('timed out waiting for lock held by %s') % inst.locker
64 reason = _('timed out waiting for lock held by %s') % inst.locker
65 else:
65 else:
66 reason = _('lock held by %s') % inst.locker
66 reason = _('lock held by %s') % inst.locker
67 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
67 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
68 except lock.LockUnavailable, inst:
68 except lock.LockUnavailable, inst:
69 ui.warn(_("abort: could not lock %s: %s\n") %
69 ui.warn(_("abort: could not lock %s: %s\n") %
70 (inst.desc or inst.filename, inst.strerror))
70 (inst.desc or inst.filename, inst.strerror))
71 except revlog.RevlogError, inst:
71 except revlog.RevlogError, inst:
72 ui.warn(_("abort: %s!\n") % inst)
72 ui.warn(_("abort: %s!\n") % inst)
73 except util.SignalInterrupt:
73 except util.SignalInterrupt:
74 ui.warn(_("killed!\n"))
74 ui.warn(_("killed!\n"))
75 except KeyboardInterrupt:
75 except KeyboardInterrupt:
76 try:
76 try:
77 ui.warn(_("interrupted!\n"))
77 ui.warn(_("interrupted!\n"))
78 except IOError, inst:
78 except IOError, inst:
79 if inst.errno == errno.EPIPE:
79 if inst.errno == errno.EPIPE:
80 if ui.debugflag:
80 if ui.debugflag:
81 ui.warn(_("\nbroken pipe\n"))
81 ui.warn(_("\nbroken pipe\n"))
82 else:
82 else:
83 raise
83 raise
84 except socket.error, inst:
84 except socket.error, inst:
85 ui.warn(_("abort: %s\n") % inst[1])
85 ui.warn(_("abort: %s\n") % inst[1])
86 except IOError, inst:
86 except IOError, inst:
87 if hasattr(inst, "code"):
87 if hasattr(inst, "code"):
88 ui.warn(_("abort: %s\n") % inst)
88 ui.warn(_("abort: %s\n") % inst)
89 elif hasattr(inst, "reason"):
89 elif hasattr(inst, "reason"):
90 try: # usually it is in the form (errno, strerror)
90 try: # usually it is in the form (errno, strerror)
91 reason = inst.reason.args[1]
91 reason = inst.reason.args[1]
92 except: # it might be anything, for example a string
92 except: # it might be anything, for example a string
93 reason = inst.reason
93 reason = inst.reason
94 ui.warn(_("abort: error: %s\n") % reason)
94 ui.warn(_("abort: error: %s\n") % reason)
95 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
95 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
96 if ui.debugflag:
96 if ui.debugflag:
97 ui.warn(_("broken pipe\n"))
97 ui.warn(_("broken pipe\n"))
98 elif getattr(inst, "strerror", None):
98 elif getattr(inst, "strerror", None):
99 if getattr(inst, "filename", None):
99 if getattr(inst, "filename", None):
100 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
100 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
101 else:
101 else:
102 ui.warn(_("abort: %s\n") % inst.strerror)
102 ui.warn(_("abort: %s\n") % inst.strerror)
103 else:
103 else:
104 raise
104 raise
105 except OSError, inst:
105 except OSError, inst:
106 if getattr(inst, "filename", None):
106 if getattr(inst, "filename", None):
107 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
107 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
108 else:
108 else:
109 ui.warn(_("abort: %s\n") % inst.strerror)
109 ui.warn(_("abort: %s\n") % inst.strerror)
110 except util.UnexpectedOutput, inst:
110 except util.UnexpectedOutput, inst:
111 ui.warn(_("abort: %s") % inst[0])
111 ui.warn(_("abort: %s") % inst[0])
112 if not isinstance(inst[1], basestring):
112 if not isinstance(inst[1], basestring):
113 ui.warn(" %r\n" % (inst[1],))
113 ui.warn(" %r\n" % (inst[1],))
114 elif not inst[1]:
114 elif not inst[1]:
115 ui.warn(_(" empty string\n"))
115 ui.warn(_(" empty string\n"))
116 else:
116 else:
117 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
117 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
118 except util.Abort, inst:
118 except util.Abort, inst:
119 ui.warn(_("abort: %s\n") % inst)
119 ui.warn(_("abort: %s\n") % inst)
120 except SystemExit, inst:
120 except SystemExit, inst:
121 # Commands shouldn't sys.exit directly, but give a return code.
121 # Commands shouldn't sys.exit directly, but give a return code.
122 # Just in case catch this and and pass exit code to caller.
122 # Just in case catch this and and pass exit code to caller.
123 return inst.code
123 return inst.code
124 except:
124 except:
125 ui.warn(_("** unknown exception encountered, details follow\n"))
125 ui.warn(_("** unknown exception encountered, details follow\n"))
126 ui.warn(_("** report bug details to "
126 ui.warn(_("** report bug details to "
127 "http://www.selenic.com/mercurial/bts\n"))
127 "http://www.selenic.com/mercurial/bts\n"))
128 ui.warn(_("** or mercurial@selenic.com\n"))
128 ui.warn(_("** or mercurial@selenic.com\n"))
129 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
129 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
130 % version.get_version())
130 % version.get_version())
131 raise
131 raise
132
132
133 return -1
133 return -1
134
134
135 def findpossible(ui, cmd):
135 def findpossible(ui, cmd):
136 """
136 """
137 Return cmd -> (aliases, command table entry)
137 Return cmd -> (aliases, command table entry)
138 for each matching command.
138 for each matching command.
139 Return debug commands (or their aliases) only if no normal command matches.
139 Return debug commands (or their aliases) only if no normal command matches.
140 """
140 """
141 choice = {}
141 choice = {}
142 debugchoice = {}
142 debugchoice = {}
143 for e in commands.table.keys():
143 for e in commands.table.keys():
144 aliases = e.lstrip("^").split("|")
144 aliases = e.lstrip("^").split("|")
145 found = None
145 found = None
146 if cmd in aliases:
146 if cmd in aliases:
147 found = cmd
147 found = cmd
148 elif not ui.config("ui", "strict"):
148 elif not ui.config("ui", "strict"):
149 for a in aliases:
149 for a in aliases:
150 if a.startswith(cmd):
150 if a.startswith(cmd):
151 found = a
151 found = a
152 break
152 break
153 if found is not None:
153 if found is not None:
154 if aliases[0].startswith("debug") or found.startswith("debug"):
154 if aliases[0].startswith("debug") or found.startswith("debug"):
155 debugchoice[found] = (aliases, commands.table[e])
155 debugchoice[found] = (aliases, commands.table[e])
156 else:
156 else:
157 choice[found] = (aliases, commands.table[e])
157 choice[found] = (aliases, commands.table[e])
158
158
159 if not choice and debugchoice:
159 if not choice and debugchoice:
160 choice = debugchoice
160 choice = debugchoice
161
161
162 return choice
162 return choice
163
163
164 def findcmd(ui, cmd):
164 def findcmd(ui, cmd):
165 """Return (aliases, command table entry) for command string."""
165 """Return (aliases, command table entry) for command string."""
166 choice = findpossible(ui, cmd)
166 choice = findpossible(ui, cmd)
167
167
168 if choice.has_key(cmd):
168 if choice.has_key(cmd):
169 return choice[cmd]
169 return choice[cmd]
170
170
171 if len(choice) > 1:
171 if len(choice) > 1:
172 clist = choice.keys()
172 clist = choice.keys()
173 clist.sort()
173 clist.sort()
174 raise AmbiguousCommand(cmd, clist)
174 raise AmbiguousCommand(cmd, clist)
175
175
176 if choice:
176 if choice:
177 return choice.values()[0]
177 return choice.values()[0]
178
178
179 raise UnknownCommand(cmd)
179 raise UnknownCommand(cmd)
180
180
181 def findrepo():
181 def findrepo():
182 p = os.getcwd()
182 p = os.getcwd()
183 while not os.path.isdir(os.path.join(p, ".hg")):
183 while not os.path.isdir(os.path.join(p, ".hg")):
184 oldp, p = p, os.path.dirname(p)
184 oldp, p = p, os.path.dirname(p)
185 if p == oldp:
185 if p == oldp:
186 return None
186 return None
187
187
188 return p
188 return p
189
189
190 def parse(ui, args):
190 def parse(ui, args):
191 options = {}
191 options = {}
192 cmdoptions = {}
192 cmdoptions = {}
193
193
194 try:
194 try:
195 args = fancyopts.fancyopts(args, commands.globalopts, options)
195 args = fancyopts.fancyopts(args, commands.globalopts, options)
196 except fancyopts.getopt.GetoptError, inst:
196 except fancyopts.getopt.GetoptError, inst:
197 raise ParseError(None, inst)
197 raise ParseError(None, inst)
198
198
199 if args:
199 if args:
200 cmd, args = args[0], args[1:]
200 cmd, args = args[0], args[1:]
201 aliases, i = findcmd(ui, cmd)
201 aliases, i = findcmd(ui, cmd)
202 cmd = aliases[0]
202 cmd = aliases[0]
203 defaults = ui.config("defaults", cmd)
203 defaults = ui.config("defaults", cmd)
204 if defaults:
204 if defaults:
205 args = shlex.split(defaults) + args
205 args = shlex.split(defaults) + args
206 c = list(i[1])
206 c = list(i[1])
207 else:
207 else:
208 cmd = None
208 cmd = None
209 c = []
209 c = []
210
210
211 # combine global options into local
211 # combine global options into local
212 for o in commands.globalopts:
212 for o in commands.globalopts:
213 c.append((o[0], o[1], options[o[1]], o[3]))
213 c.append((o[0], o[1], options[o[1]], o[3]))
214
214
215 try:
215 try:
216 args = fancyopts.fancyopts(args, c, cmdoptions)
216 args = fancyopts.fancyopts(args, c, cmdoptions)
217 except fancyopts.getopt.GetoptError, inst:
217 except fancyopts.getopt.GetoptError, inst:
218 raise ParseError(cmd, inst)
218 raise ParseError(cmd, inst)
219
219
220 # separate global options back out
220 # separate global options back out
221 for o in commands.globalopts:
221 for o in commands.globalopts:
222 n = o[1]
222 n = o[1]
223 options[n] = cmdoptions[n]
223 options[n] = cmdoptions[n]
224 del cmdoptions[n]
224 del cmdoptions[n]
225
225
226 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
226 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
227
227
228 def parseconfig(config):
228 def parseconfig(config):
229 """parse the --config options from the command line"""
229 """parse the --config options from the command line"""
230 parsed = []
230 parsed = []
231 for cfg in config:
231 for cfg in config:
232 try:
232 try:
233 name, value = cfg.split('=', 1)
233 name, value = cfg.split('=', 1)
234 section, name = name.split('.', 1)
234 section, name = name.split('.', 1)
235 if not section or not name:
235 if not section or not name:
236 raise IndexError
236 raise IndexError
237 parsed.append((section, name, value))
237 parsed.append((section, name, value))
238 except (IndexError, ValueError):
238 except (IndexError, ValueError):
239 raise util.Abort(_('malformed --config option: %s') % cfg)
239 raise util.Abort(_('malformed --config option: %s') % cfg)
240 return parsed
240 return parsed
241
241
242 def earlygetopt(aliases, args):
242 def earlygetopt(aliases, args):
243 if "--" in args:
243 if "--" in args:
244 args = args[:args.index("--")]
244 args = args[:args.index("--")]
245 for opt in aliases:
245 for opt in aliases:
246 if opt in args:
246 if opt in args:
247 return args[args.index(opt) + 1]
247 return args[args.index(opt) + 1]
248 return None
248 return None
249
249
250 def dispatch(ui, args):
250 def dispatch(ui, args):
251 # check for cwd first
251 # check for cwd first
252 cwd = earlygetopt(['--cwd'], args)
252 cwd = earlygetopt(['--cwd'], args)
253 if cwd:
253 if cwd:
254 os.chdir(cwd)
254 os.chdir(cwd)
255
255
256 # read the local repository .hgrc into a local ui object
256 # read the local repository .hgrc into a local ui object
257 # this will trigger its extensions to load
257 # this will trigger its extensions to load
258 path = earlygetopt(["-R", "--repository", "--repo"], args)
258 path = earlygetopt(["-R", "--repository", "--repo"], args)
259 if not path:
259 if not path:
260 path = findrepo() or ""
260 path = findrepo() or ""
261 lui = ui
261 lui = ui
262 if path:
262 if path:
263 try:
263 try:
264 lui = commands.ui.ui(parentui=ui)
264 lui = commands.ui.ui(parentui=ui)
265 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
265 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
266 except IOError:
266 except IOError:
267 pass
267 pass
268
268
269 extensions.loadall(lui)
269 extensions.loadall(lui)
270 # check for fallback encoding
270 # check for fallback encoding
271 fallback = lui.config('ui', 'fallbackencoding')
271 fallback = lui.config('ui', 'fallbackencoding')
272 if fallback:
272 if fallback:
273 util._fallbackencoding = fallback
273 util._fallbackencoding = fallback
274
274
275 fullargs = args
275 cmd, func, args, options, cmdoptions = parse(ui, args)
276 cmd, func, args, options, cmdoptions = parse(ui, args)
276
277
277 if options["encoding"]:
278 if options["encoding"]:
278 util._encoding = options["encoding"]
279 util._encoding = options["encoding"]
279 if options["encodingmode"]:
280 if options["encodingmode"]:
280 util._encodingmode = options["encodingmode"]
281 util._encodingmode = options["encodingmode"]
281 if options["time"]:
282 if options["time"]:
282 def get_times():
283 def get_times():
283 t = os.times()
284 t = os.times()
284 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
285 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
285 t = (t[0], t[1], t[2], t[3], time.clock())
286 t = (t[0], t[1], t[2], t[3], time.clock())
286 return t
287 return t
287 s = get_times()
288 s = get_times()
288 def print_time():
289 def print_time():
289 t = get_times()
290 t = get_times()
290 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
291 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
291 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
292 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
292 atexit.register(print_time)
293 atexit.register(print_time)
293
294
294 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
295 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
295 not options["noninteractive"], options["traceback"],
296 not options["noninteractive"], options["traceback"],
296 parseconfig(options["config"]))
297 parseconfig(options["config"]))
297
298
298 if options['help']:
299 if options['help']:
299 return commands.help_(ui, cmd, options['version'])
300 return commands.help_(ui, cmd, options['version'])
300 elif options['version']:
301 elif options['version']:
301 return commands.version_(ui)
302 return commands.version_(ui)
302 elif not cmd:
303 elif not cmd:
303 return commands.help_(ui, 'shortlist')
304 return commands.help_(ui, 'shortlist')
304
305
306 repo = None
305 if cmd not in commands.norepo.split():
307 if cmd not in commands.norepo.split():
306 repo = None
307 try:
308 try:
308 repo = hg.repository(ui, path=path)
309 repo = hg.repository(ui, path=path)
309 ui = repo.ui
310 ui = repo.ui
310 if not repo.local():
311 if not repo.local():
311 raise util.Abort(_("repository '%s' is not local") % path)
312 raise util.Abort(_("repository '%s' is not local") % path)
312 except hg.RepoError:
313 except hg.RepoError:
313 if cmd not in commands.optionalrepo.split():
314 if cmd not in commands.optionalrepo.split():
314 raise
315 raise
315 d = lambda: func(ui, repo, *args, **cmdoptions)
316 d = lambda: func(ui, repo, *args, **cmdoptions)
316 else:
317 else:
317 d = lambda: func(ui, *args, **cmdoptions)
318 d = lambda: func(ui, *args, **cmdoptions)
318
319
319 return runcommand(ui, options, cmd, d)
320 # run pre-hook, and abort if it fails
321 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
322 if ret:
323 return ret
324 ret = runcommand(ui, options, cmd, d)
325 # run post-hook, passing command result
326 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
327 result = ret)
328 return ret
320
329
321 def runcommand(ui, options, cmd, cmdfunc):
330 def runcommand(ui, options, cmd, cmdfunc):
322 def checkargs():
331 def checkargs():
323 try:
332 try:
324 return cmdfunc()
333 return cmdfunc()
325 except TypeError, inst:
334 except TypeError, inst:
326 # was this an argument error?
335 # was this an argument error?
327 tb = traceback.extract_tb(sys.exc_info()[2])
336 tb = traceback.extract_tb(sys.exc_info()[2])
328 if len(tb) != 2: # no
337 if len(tb) != 2: # no
329 raise
338 raise
330 raise ParseError(cmd, _("invalid arguments"))
339 raise ParseError(cmd, _("invalid arguments"))
331
340
332 if options['profile']:
341 if options['profile']:
333 import hotshot, hotshot.stats
342 import hotshot, hotshot.stats
334 prof = hotshot.Profile("hg.prof")
343 prof = hotshot.Profile("hg.prof")
335 try:
344 try:
336 try:
345 try:
337 return prof.runcall(checkargs)
346 return prof.runcall(checkargs)
338 except:
347 except:
339 try:
348 try:
340 ui.warn(_('exception raised - generating '
349 ui.warn(_('exception raised - generating '
341 'profile anyway\n'))
350 'profile anyway\n'))
342 except:
351 except:
343 pass
352 pass
344 raise
353 raise
345 finally:
354 finally:
346 prof.close()
355 prof.close()
347 stats = hotshot.stats.load("hg.prof")
356 stats = hotshot.stats.load("hg.prof")
348 stats.strip_dirs()
357 stats.strip_dirs()
349 stats.sort_stats('time', 'calls')
358 stats.sort_stats('time', 'calls')
350 stats.print_stats(40)
359 stats.print_stats(40)
351 elif options['lsprof']:
360 elif options['lsprof']:
352 try:
361 try:
353 from mercurial import lsprof
362 from mercurial import lsprof
354 except ImportError:
363 except ImportError:
355 raise util.Abort(_(
364 raise util.Abort(_(
356 'lsprof not available - install from '
365 'lsprof not available - install from '
357 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
366 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
358 p = lsprof.Profiler()
367 p = lsprof.Profiler()
359 p.enable(subcalls=True)
368 p.enable(subcalls=True)
360 try:
369 try:
361 return checkargs()
370 return checkargs()
362 finally:
371 finally:
363 p.disable()
372 p.disable()
364 stats = lsprof.Stats(p.getstats())
373 stats = lsprof.Stats(p.getstats())
365 stats.sort()
374 stats.sort()
366 stats.pprint(top=10, file=sys.stderr, climit=5)
375 stats.pprint(top=10, file=sys.stderr, climit=5)
367 else:
376 else:
368 return checkargs()
377 return checkargs()
369
378
370 def bail_if_changed(repo):
379 def bail_if_changed(repo):
371 modified, added, removed, deleted = repo.status()[:4]
380 modified, added, removed, deleted = repo.status()[:4]
372 if modified or added or removed or deleted:
381 if modified or added or removed or deleted:
373 raise util.Abort(_("outstanding uncommitted changes"))
382 raise util.Abort(_("outstanding uncommitted changes"))
374
383
375 def logmessage(opts):
384 def logmessage(opts):
376 """ get the log message according to -m and -l option """
385 """ get the log message according to -m and -l option """
377 message = opts['message']
386 message = opts['message']
378 logfile = opts['logfile']
387 logfile = opts['logfile']
379
388
380 if message and logfile:
389 if message and logfile:
381 raise util.Abort(_('options --message and --logfile are mutually '
390 raise util.Abort(_('options --message and --logfile are mutually '
382 'exclusive'))
391 'exclusive'))
383 if not message and logfile:
392 if not message and logfile:
384 try:
393 try:
385 if logfile == '-':
394 if logfile == '-':
386 message = sys.stdin.read()
395 message = sys.stdin.read()
387 else:
396 else:
388 message = open(logfile).read()
397 message = open(logfile).read()
389 except IOError, inst:
398 except IOError, inst:
390 raise util.Abort(_("can't read commit message '%s': %s") %
399 raise util.Abort(_("can't read commit message '%s': %s") %
391 (logfile, inst.strerror))
400 (logfile, inst.strerror))
392 return message
401 return message
393
402
394 def setremoteconfig(ui, opts):
403 def setremoteconfig(ui, opts):
395 "copy remote options to ui tree"
404 "copy remote options to ui tree"
396 if opts.get('ssh'):
405 if opts.get('ssh'):
397 ui.setconfig("ui", "ssh", opts['ssh'])
406 ui.setconfig("ui", "ssh", opts['ssh'])
398 if opts.get('remotecmd'):
407 if opts.get('remotecmd'):
399 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
408 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
400
409
401 def parseurl(url, revs):
410 def parseurl(url, revs):
402 '''parse url#branch, returning url, branch + revs'''
411 '''parse url#branch, returning url, branch + revs'''
403
412
404 if '#' not in url:
413 if '#' not in url:
405 return url, (revs or None)
414 return url, (revs or None)
406
415
407 url, rev = url.split('#', 1)
416 url, rev = url.split('#', 1)
408 return url, revs + [rev]
417 return url, revs + [rev]
409
418
410 def revpair(repo, revs):
419 def revpair(repo, revs):
411 '''return pair of nodes, given list of revisions. second item can
420 '''return pair of nodes, given list of revisions. second item can
412 be None, meaning use working dir.'''
421 be None, meaning use working dir.'''
413
422
414 def revfix(repo, val, defval):
423 def revfix(repo, val, defval):
415 if not val and val != 0 and defval is not None:
424 if not val and val != 0 and defval is not None:
416 val = defval
425 val = defval
417 return repo.lookup(val)
426 return repo.lookup(val)
418
427
419 if not revs:
428 if not revs:
420 return repo.dirstate.parents()[0], None
429 return repo.dirstate.parents()[0], None
421 end = None
430 end = None
422 if len(revs) == 1:
431 if len(revs) == 1:
423 if revrangesep in revs[0]:
432 if revrangesep in revs[0]:
424 start, end = revs[0].split(revrangesep, 1)
433 start, end = revs[0].split(revrangesep, 1)
425 start = revfix(repo, start, 0)
434 start = revfix(repo, start, 0)
426 end = revfix(repo, end, repo.changelog.count() - 1)
435 end = revfix(repo, end, repo.changelog.count() - 1)
427 else:
436 else:
428 start = revfix(repo, revs[0], None)
437 start = revfix(repo, revs[0], None)
429 elif len(revs) == 2:
438 elif len(revs) == 2:
430 if revrangesep in revs[0] or revrangesep in revs[1]:
439 if revrangesep in revs[0] or revrangesep in revs[1]:
431 raise util.Abort(_('too many revisions specified'))
440 raise util.Abort(_('too many revisions specified'))
432 start = revfix(repo, revs[0], None)
441 start = revfix(repo, revs[0], None)
433 end = revfix(repo, revs[1], None)
442 end = revfix(repo, revs[1], None)
434 else:
443 else:
435 raise util.Abort(_('too many revisions specified'))
444 raise util.Abort(_('too many revisions specified'))
436 return start, end
445 return start, end
437
446
438 def revrange(repo, revs):
447 def revrange(repo, revs):
439 """Yield revision as strings from a list of revision specifications."""
448 """Yield revision as strings from a list of revision specifications."""
440
449
441 def revfix(repo, val, defval):
450 def revfix(repo, val, defval):
442 if not val and val != 0 and defval is not None:
451 if not val and val != 0 and defval is not None:
443 return defval
452 return defval
444 return repo.changelog.rev(repo.lookup(val))
453 return repo.changelog.rev(repo.lookup(val))
445
454
446 seen, l = {}, []
455 seen, l = {}, []
447 for spec in revs:
456 for spec in revs:
448 if revrangesep in spec:
457 if revrangesep in spec:
449 start, end = spec.split(revrangesep, 1)
458 start, end = spec.split(revrangesep, 1)
450 start = revfix(repo, start, 0)
459 start = revfix(repo, start, 0)
451 end = revfix(repo, end, repo.changelog.count() - 1)
460 end = revfix(repo, end, repo.changelog.count() - 1)
452 step = start > end and -1 or 1
461 step = start > end and -1 or 1
453 for rev in xrange(start, end+step, step):
462 for rev in xrange(start, end+step, step):
454 if rev in seen:
463 if rev in seen:
455 continue
464 continue
456 seen[rev] = 1
465 seen[rev] = 1
457 l.append(rev)
466 l.append(rev)
458 else:
467 else:
459 rev = revfix(repo, spec, None)
468 rev = revfix(repo, spec, None)
460 if rev in seen:
469 if rev in seen:
461 continue
470 continue
462 seen[rev] = 1
471 seen[rev] = 1
463 l.append(rev)
472 l.append(rev)
464
473
465 return l
474 return l
466
475
467 def make_filename(repo, pat, node,
476 def make_filename(repo, pat, node,
468 total=None, seqno=None, revwidth=None, pathname=None):
477 total=None, seqno=None, revwidth=None, pathname=None):
469 node_expander = {
478 node_expander = {
470 'H': lambda: hex(node),
479 'H': lambda: hex(node),
471 'R': lambda: str(repo.changelog.rev(node)),
480 'R': lambda: str(repo.changelog.rev(node)),
472 'h': lambda: short(node),
481 'h': lambda: short(node),
473 }
482 }
474 expander = {
483 expander = {
475 '%': lambda: '%',
484 '%': lambda: '%',
476 'b': lambda: os.path.basename(repo.root),
485 'b': lambda: os.path.basename(repo.root),
477 }
486 }
478
487
479 try:
488 try:
480 if node:
489 if node:
481 expander.update(node_expander)
490 expander.update(node_expander)
482 if node and revwidth is not None:
491 if node and revwidth is not None:
483 expander['r'] = (lambda:
492 expander['r'] = (lambda:
484 str(repo.changelog.rev(node)).zfill(revwidth))
493 str(repo.changelog.rev(node)).zfill(revwidth))
485 if total is not None:
494 if total is not None:
486 expander['N'] = lambda: str(total)
495 expander['N'] = lambda: str(total)
487 if seqno is not None:
496 if seqno is not None:
488 expander['n'] = lambda: str(seqno)
497 expander['n'] = lambda: str(seqno)
489 if total is not None and seqno is not None:
498 if total is not None and seqno is not None:
490 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
499 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
491 if pathname is not None:
500 if pathname is not None:
492 expander['s'] = lambda: os.path.basename(pathname)
501 expander['s'] = lambda: os.path.basename(pathname)
493 expander['d'] = lambda: os.path.dirname(pathname) or '.'
502 expander['d'] = lambda: os.path.dirname(pathname) or '.'
494 expander['p'] = lambda: pathname
503 expander['p'] = lambda: pathname
495
504
496 newname = []
505 newname = []
497 patlen = len(pat)
506 patlen = len(pat)
498 i = 0
507 i = 0
499 while i < patlen:
508 while i < patlen:
500 c = pat[i]
509 c = pat[i]
501 if c == '%':
510 if c == '%':
502 i += 1
511 i += 1
503 c = pat[i]
512 c = pat[i]
504 c = expander[c]()
513 c = expander[c]()
505 newname.append(c)
514 newname.append(c)
506 i += 1
515 i += 1
507 return ''.join(newname)
516 return ''.join(newname)
508 except KeyError, inst:
517 except KeyError, inst:
509 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
518 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
510 inst.args[0])
519 inst.args[0])
511
520
512 def make_file(repo, pat, node=None,
521 def make_file(repo, pat, node=None,
513 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
522 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
514 if not pat or pat == '-':
523 if not pat or pat == '-':
515 return 'w' in mode and sys.stdout or sys.stdin
524 return 'w' in mode and sys.stdout or sys.stdin
516 if hasattr(pat, 'write') and 'w' in mode:
525 if hasattr(pat, 'write') and 'w' in mode:
517 return pat
526 return pat
518 if hasattr(pat, 'read') and 'r' in mode:
527 if hasattr(pat, 'read') and 'r' in mode:
519 return pat
528 return pat
520 return open(make_filename(repo, pat, node, total, seqno, revwidth,
529 return open(make_filename(repo, pat, node, total, seqno, revwidth,
521 pathname),
530 pathname),
522 mode)
531 mode)
523
532
524 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
533 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
525 cwd = repo.getcwd()
534 cwd = repo.getcwd()
526 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
535 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
527 opts.get('exclude'), globbed=globbed,
536 opts.get('exclude'), globbed=globbed,
528 default=default)
537 default=default)
529
538
530 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
539 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
531 default=None):
540 default=None):
532 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
541 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
533 default=default)
542 default=default)
534 exact = dict.fromkeys(files)
543 exact = dict.fromkeys(files)
535 cwd = repo.getcwd()
544 cwd = repo.getcwd()
536 for src, fn in repo.walk(node=node, files=files, match=matchfn,
545 for src, fn in repo.walk(node=node, files=files, match=matchfn,
537 badmatch=badmatch):
546 badmatch=badmatch):
538 yield src, fn, repo.pathto(fn, cwd), fn in exact
547 yield src, fn, repo.pathto(fn, cwd), fn in exact
539
548
540 def findrenames(repo, added=None, removed=None, threshold=0.5):
549 def findrenames(repo, added=None, removed=None, threshold=0.5):
541 '''find renamed files -- yields (before, after, score) tuples'''
550 '''find renamed files -- yields (before, after, score) tuples'''
542 if added is None or removed is None:
551 if added is None or removed is None:
543 added, removed = repo.status()[1:3]
552 added, removed = repo.status()[1:3]
544 ctx = repo.changectx()
553 ctx = repo.changectx()
545 for a in added:
554 for a in added:
546 aa = repo.wread(a)
555 aa = repo.wread(a)
547 bestname, bestscore = None, threshold
556 bestname, bestscore = None, threshold
548 for r in removed:
557 for r in removed:
549 rr = ctx.filectx(r).data()
558 rr = ctx.filectx(r).data()
550
559
551 # bdiff.blocks() returns blocks of matching lines
560 # bdiff.blocks() returns blocks of matching lines
552 # count the number of bytes in each
561 # count the number of bytes in each
553 equal = 0
562 equal = 0
554 alines = mdiff.splitnewlines(aa)
563 alines = mdiff.splitnewlines(aa)
555 matches = bdiff.blocks(aa, rr)
564 matches = bdiff.blocks(aa, rr)
556 for x1,x2,y1,y2 in matches:
565 for x1,x2,y1,y2 in matches:
557 for line in alines[x1:x2]:
566 for line in alines[x1:x2]:
558 equal += len(line)
567 equal += len(line)
559
568
560 lengths = len(aa) + len(rr)
569 lengths = len(aa) + len(rr)
561 if lengths:
570 if lengths:
562 myscore = equal*2.0 / lengths
571 myscore = equal*2.0 / lengths
563 if myscore >= bestscore:
572 if myscore >= bestscore:
564 bestname, bestscore = r, myscore
573 bestname, bestscore = r, myscore
565 if bestname:
574 if bestname:
566 yield bestname, a, bestscore
575 yield bestname, a, bestscore
567
576
568 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
577 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
569 similarity=None):
578 similarity=None):
570 if dry_run is None:
579 if dry_run is None:
571 dry_run = opts.get('dry_run')
580 dry_run = opts.get('dry_run')
572 if similarity is None:
581 if similarity is None:
573 similarity = float(opts.get('similarity') or 0)
582 similarity = float(opts.get('similarity') or 0)
574 add, remove = [], []
583 add, remove = [], []
575 mapping = {}
584 mapping = {}
576 for src, abs, rel, exact in walk(repo, pats, opts):
585 for src, abs, rel, exact in walk(repo, pats, opts):
577 target = repo.wjoin(abs)
586 target = repo.wjoin(abs)
578 if src == 'f' and repo.dirstate.state(abs) == '?':
587 if src == 'f' and repo.dirstate.state(abs) == '?':
579 add.append(abs)
588 add.append(abs)
580 mapping[abs] = rel, exact
589 mapping[abs] = rel, exact
581 if repo.ui.verbose or not exact:
590 if repo.ui.verbose or not exact:
582 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
591 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
583 if repo.dirstate.state(abs) != 'r' and not util.lexists(target):
592 if repo.dirstate.state(abs) != 'r' and not util.lexists(target):
584 remove.append(abs)
593 remove.append(abs)
585 mapping[abs] = rel, exact
594 mapping[abs] = rel, exact
586 if repo.ui.verbose or not exact:
595 if repo.ui.verbose or not exact:
587 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
596 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
588 if not dry_run:
597 if not dry_run:
589 repo.add(add, wlock=wlock)
598 repo.add(add, wlock=wlock)
590 repo.remove(remove, wlock=wlock)
599 repo.remove(remove, wlock=wlock)
591 if similarity > 0:
600 if similarity > 0:
592 for old, new, score in findrenames(repo, add, remove, similarity):
601 for old, new, score in findrenames(repo, add, remove, similarity):
593 oldrel, oldexact = mapping[old]
602 oldrel, oldexact = mapping[old]
594 newrel, newexact = mapping[new]
603 newrel, newexact = mapping[new]
595 if repo.ui.verbose or not oldexact or not newexact:
604 if repo.ui.verbose or not oldexact or not newexact:
596 repo.ui.status(_('recording removal of %s as rename to %s '
605 repo.ui.status(_('recording removal of %s as rename to %s '
597 '(%d%% similar)\n') %
606 '(%d%% similar)\n') %
598 (oldrel, newrel, score * 100))
607 (oldrel, newrel, score * 100))
599 if not dry_run:
608 if not dry_run:
600 repo.copy(old, new, wlock=wlock)
609 repo.copy(old, new, wlock=wlock)
601
610
602 def service(opts, parentfn=None, initfn=None, runfn=None):
611 def service(opts, parentfn=None, initfn=None, runfn=None):
603 '''Run a command as a service.'''
612 '''Run a command as a service.'''
604
613
605 if opts['daemon'] and not opts['daemon_pipefds']:
614 if opts['daemon'] and not opts['daemon_pipefds']:
606 rfd, wfd = os.pipe()
615 rfd, wfd = os.pipe()
607 args = sys.argv[:]
616 args = sys.argv[:]
608 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
617 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
609 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
618 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
610 args[0], args)
619 args[0], args)
611 os.close(wfd)
620 os.close(wfd)
612 os.read(rfd, 1)
621 os.read(rfd, 1)
613 if parentfn:
622 if parentfn:
614 return parentfn(pid)
623 return parentfn(pid)
615 else:
624 else:
616 os._exit(0)
625 os._exit(0)
617
626
618 if initfn:
627 if initfn:
619 initfn()
628 initfn()
620
629
621 if opts['pid_file']:
630 if opts['pid_file']:
622 fp = open(opts['pid_file'], 'w')
631 fp = open(opts['pid_file'], 'w')
623 fp.write(str(os.getpid()) + '\n')
632 fp.write(str(os.getpid()) + '\n')
624 fp.close()
633 fp.close()
625
634
626 if opts['daemon_pipefds']:
635 if opts['daemon_pipefds']:
627 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
636 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
628 os.close(rfd)
637 os.close(rfd)
629 try:
638 try:
630 os.setsid()
639 os.setsid()
631 except AttributeError:
640 except AttributeError:
632 pass
641 pass
633 os.write(wfd, 'y')
642 os.write(wfd, 'y')
634 os.close(wfd)
643 os.close(wfd)
635 sys.stdout.flush()
644 sys.stdout.flush()
636 sys.stderr.flush()
645 sys.stderr.flush()
637 fd = os.open(util.nulldev, os.O_RDWR)
646 fd = os.open(util.nulldev, os.O_RDWR)
638 if fd != 0: os.dup2(fd, 0)
647 if fd != 0: os.dup2(fd, 0)
639 if fd != 1: os.dup2(fd, 1)
648 if fd != 1: os.dup2(fd, 1)
640 if fd != 2: os.dup2(fd, 2)
649 if fd != 2: os.dup2(fd, 2)
641 if fd not in (0, 1, 2): os.close(fd)
650 if fd not in (0, 1, 2): os.close(fd)
642
651
643 if runfn:
652 if runfn:
644 return runfn()
653 return runfn()
645
654
646 class changeset_printer(object):
655 class changeset_printer(object):
647 '''show changeset information when templating not requested.'''
656 '''show changeset information when templating not requested.'''
648
657
649 def __init__(self, ui, repo, patch, buffered):
658 def __init__(self, ui, repo, patch, buffered):
650 self.ui = ui
659 self.ui = ui
651 self.repo = repo
660 self.repo = repo
652 self.buffered = buffered
661 self.buffered = buffered
653 self.patch = patch
662 self.patch = patch
654 self.header = {}
663 self.header = {}
655 self.hunk = {}
664 self.hunk = {}
656 self.lastheader = None
665 self.lastheader = None
657
666
658 def flush(self, rev):
667 def flush(self, rev):
659 if rev in self.header:
668 if rev in self.header:
660 h = self.header[rev]
669 h = self.header[rev]
661 if h != self.lastheader:
670 if h != self.lastheader:
662 self.lastheader = h
671 self.lastheader = h
663 self.ui.write(h)
672 self.ui.write(h)
664 del self.header[rev]
673 del self.header[rev]
665 if rev in self.hunk:
674 if rev in self.hunk:
666 self.ui.write(self.hunk[rev])
675 self.ui.write(self.hunk[rev])
667 del self.hunk[rev]
676 del self.hunk[rev]
668 return 1
677 return 1
669 return 0
678 return 0
670
679
671 def show(self, rev=0, changenode=None, copies=(), **props):
680 def show(self, rev=0, changenode=None, copies=(), **props):
672 if self.buffered:
681 if self.buffered:
673 self.ui.pushbuffer()
682 self.ui.pushbuffer()
674 self._show(rev, changenode, copies, props)
683 self._show(rev, changenode, copies, props)
675 self.hunk[rev] = self.ui.popbuffer()
684 self.hunk[rev] = self.ui.popbuffer()
676 else:
685 else:
677 self._show(rev, changenode, copies, props)
686 self._show(rev, changenode, copies, props)
678
687
679 def _show(self, rev, changenode, copies, props):
688 def _show(self, rev, changenode, copies, props):
680 '''show a single changeset or file revision'''
689 '''show a single changeset or file revision'''
681 log = self.repo.changelog
690 log = self.repo.changelog
682 if changenode is None:
691 if changenode is None:
683 changenode = log.node(rev)
692 changenode = log.node(rev)
684 elif not rev:
693 elif not rev:
685 rev = log.rev(changenode)
694 rev = log.rev(changenode)
686
695
687 if self.ui.quiet:
696 if self.ui.quiet:
688 self.ui.write("%d:%s\n" % (rev, short(changenode)))
697 self.ui.write("%d:%s\n" % (rev, short(changenode)))
689 return
698 return
690
699
691 changes = log.read(changenode)
700 changes = log.read(changenode)
692 date = util.datestr(changes[2])
701 date = util.datestr(changes[2])
693 extra = changes[5]
702 extra = changes[5]
694 branch = extra.get("branch")
703 branch = extra.get("branch")
695
704
696 hexfunc = self.ui.debugflag and hex or short
705 hexfunc = self.ui.debugflag and hex or short
697
706
698 parents = log.parentrevs(rev)
707 parents = log.parentrevs(rev)
699 if not self.ui.debugflag:
708 if not self.ui.debugflag:
700 if parents[1] == nullrev:
709 if parents[1] == nullrev:
701 if parents[0] >= rev - 1:
710 if parents[0] >= rev - 1:
702 parents = []
711 parents = []
703 else:
712 else:
704 parents = [parents[0]]
713 parents = [parents[0]]
705 parents = [(p, hexfunc(log.node(p))) for p in parents]
714 parents = [(p, hexfunc(log.node(p))) for p in parents]
706
715
707 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
716 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
708
717
709 # don't show the default branch name
718 # don't show the default branch name
710 if branch != 'default':
719 if branch != 'default':
711 branch = util.tolocal(branch)
720 branch = util.tolocal(branch)
712 self.ui.write(_("branch: %s\n") % branch)
721 self.ui.write(_("branch: %s\n") % branch)
713 for tag in self.repo.nodetags(changenode):
722 for tag in self.repo.nodetags(changenode):
714 self.ui.write(_("tag: %s\n") % tag)
723 self.ui.write(_("tag: %s\n") % tag)
715 for parent in parents:
724 for parent in parents:
716 self.ui.write(_("parent: %d:%s\n") % parent)
725 self.ui.write(_("parent: %d:%s\n") % parent)
717
726
718 if self.ui.debugflag:
727 if self.ui.debugflag:
719 self.ui.write(_("manifest: %d:%s\n") %
728 self.ui.write(_("manifest: %d:%s\n") %
720 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
729 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
721 self.ui.write(_("user: %s\n") % changes[1])
730 self.ui.write(_("user: %s\n") % changes[1])
722 self.ui.write(_("date: %s\n") % date)
731 self.ui.write(_("date: %s\n") % date)
723
732
724 if self.ui.debugflag:
733 if self.ui.debugflag:
725 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
734 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
726 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
735 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
727 files):
736 files):
728 if value:
737 if value:
729 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
738 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
730 elif changes[3] and self.ui.verbose:
739 elif changes[3] and self.ui.verbose:
731 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
740 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
732 if copies and self.ui.verbose:
741 if copies and self.ui.verbose:
733 copies = ['%s (%s)' % c for c in copies]
742 copies = ['%s (%s)' % c for c in copies]
734 self.ui.write(_("copies: %s\n") % ' '.join(copies))
743 self.ui.write(_("copies: %s\n") % ' '.join(copies))
735
744
736 if extra and self.ui.debugflag:
745 if extra and self.ui.debugflag:
737 extraitems = extra.items()
746 extraitems = extra.items()
738 extraitems.sort()
747 extraitems.sort()
739 for key, value in extraitems:
748 for key, value in extraitems:
740 self.ui.write(_("extra: %s=%s\n")
749 self.ui.write(_("extra: %s=%s\n")
741 % (key, value.encode('string_escape')))
750 % (key, value.encode('string_escape')))
742
751
743 description = changes[4].strip()
752 description = changes[4].strip()
744 if description:
753 if description:
745 if self.ui.verbose:
754 if self.ui.verbose:
746 self.ui.write(_("description:\n"))
755 self.ui.write(_("description:\n"))
747 self.ui.write(description)
756 self.ui.write(description)
748 self.ui.write("\n\n")
757 self.ui.write("\n\n")
749 else:
758 else:
750 self.ui.write(_("summary: %s\n") %
759 self.ui.write(_("summary: %s\n") %
751 description.splitlines()[0])
760 description.splitlines()[0])
752 self.ui.write("\n")
761 self.ui.write("\n")
753
762
754 self.showpatch(changenode)
763 self.showpatch(changenode)
755
764
756 def showpatch(self, node):
765 def showpatch(self, node):
757 if self.patch:
766 if self.patch:
758 prev = self.repo.changelog.parents(node)[0]
767 prev = self.repo.changelog.parents(node)[0]
759 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
768 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
760 self.ui.write("\n")
769 self.ui.write("\n")
761
770
762 class changeset_templater(changeset_printer):
771 class changeset_templater(changeset_printer):
763 '''format changeset information.'''
772 '''format changeset information.'''
764
773
765 def __init__(self, ui, repo, patch, mapfile, buffered):
774 def __init__(self, ui, repo, patch, mapfile, buffered):
766 changeset_printer.__init__(self, ui, repo, patch, buffered)
775 changeset_printer.__init__(self, ui, repo, patch, buffered)
767 filters = templater.common_filters.copy()
776 filters = templater.common_filters.copy()
768 filters['formatnode'] = (ui.debugflag and (lambda x: x)
777 filters['formatnode'] = (ui.debugflag and (lambda x: x)
769 or (lambda x: x[:12]))
778 or (lambda x: x[:12]))
770 self.t = templater.templater(mapfile, filters,
779 self.t = templater.templater(mapfile, filters,
771 cache={
780 cache={
772 'parent': '{rev}:{node|formatnode} ',
781 'parent': '{rev}:{node|formatnode} ',
773 'manifest': '{rev}:{node|formatnode}',
782 'manifest': '{rev}:{node|formatnode}',
774 'filecopy': '{name} ({source})'})
783 'filecopy': '{name} ({source})'})
775
784
776 def use_template(self, t):
785 def use_template(self, t):
777 '''set template string to use'''
786 '''set template string to use'''
778 self.t.cache['changeset'] = t
787 self.t.cache['changeset'] = t
779
788
780 def _show(self, rev, changenode, copies, props):
789 def _show(self, rev, changenode, copies, props):
781 '''show a single changeset or file revision'''
790 '''show a single changeset or file revision'''
782 log = self.repo.changelog
791 log = self.repo.changelog
783 if changenode is None:
792 if changenode is None:
784 changenode = log.node(rev)
793 changenode = log.node(rev)
785 elif not rev:
794 elif not rev:
786 rev = log.rev(changenode)
795 rev = log.rev(changenode)
787
796
788 changes = log.read(changenode)
797 changes = log.read(changenode)
789
798
790 def showlist(name, values, plural=None, **args):
799 def showlist(name, values, plural=None, **args):
791 '''expand set of values.
800 '''expand set of values.
792 name is name of key in template map.
801 name is name of key in template map.
793 values is list of strings or dicts.
802 values is list of strings or dicts.
794 plural is plural of name, if not simply name + 's'.
803 plural is plural of name, if not simply name + 's'.
795
804
796 expansion works like this, given name 'foo'.
805 expansion works like this, given name 'foo'.
797
806
798 if values is empty, expand 'no_foos'.
807 if values is empty, expand 'no_foos'.
799
808
800 if 'foo' not in template map, return values as a string,
809 if 'foo' not in template map, return values as a string,
801 joined by space.
810 joined by space.
802
811
803 expand 'start_foos'.
812 expand 'start_foos'.
804
813
805 for each value, expand 'foo'. if 'last_foo' in template
814 for each value, expand 'foo'. if 'last_foo' in template
806 map, expand it instead of 'foo' for last key.
815 map, expand it instead of 'foo' for last key.
807
816
808 expand 'end_foos'.
817 expand 'end_foos'.
809 '''
818 '''
810 if plural: names = plural
819 if plural: names = plural
811 else: names = name + 's'
820 else: names = name + 's'
812 if not values:
821 if not values:
813 noname = 'no_' + names
822 noname = 'no_' + names
814 if noname in self.t:
823 if noname in self.t:
815 yield self.t(noname, **args)
824 yield self.t(noname, **args)
816 return
825 return
817 if name not in self.t:
826 if name not in self.t:
818 if isinstance(values[0], str):
827 if isinstance(values[0], str):
819 yield ' '.join(values)
828 yield ' '.join(values)
820 else:
829 else:
821 for v in values:
830 for v in values:
822 yield dict(v, **args)
831 yield dict(v, **args)
823 return
832 return
824 startname = 'start_' + names
833 startname = 'start_' + names
825 if startname in self.t:
834 if startname in self.t:
826 yield self.t(startname, **args)
835 yield self.t(startname, **args)
827 vargs = args.copy()
836 vargs = args.copy()
828 def one(v, tag=name):
837 def one(v, tag=name):
829 try:
838 try:
830 vargs.update(v)
839 vargs.update(v)
831 except (AttributeError, ValueError):
840 except (AttributeError, ValueError):
832 try:
841 try:
833 for a, b in v:
842 for a, b in v:
834 vargs[a] = b
843 vargs[a] = b
835 except ValueError:
844 except ValueError:
836 vargs[name] = v
845 vargs[name] = v
837 return self.t(tag, **vargs)
846 return self.t(tag, **vargs)
838 lastname = 'last_' + name
847 lastname = 'last_' + name
839 if lastname in self.t:
848 if lastname in self.t:
840 last = values.pop()
849 last = values.pop()
841 else:
850 else:
842 last = None
851 last = None
843 for v in values:
852 for v in values:
844 yield one(v)
853 yield one(v)
845 if last is not None:
854 if last is not None:
846 yield one(last, tag=lastname)
855 yield one(last, tag=lastname)
847 endname = 'end_' + names
856 endname = 'end_' + names
848 if endname in self.t:
857 if endname in self.t:
849 yield self.t(endname, **args)
858 yield self.t(endname, **args)
850
859
851 def showbranches(**args):
860 def showbranches(**args):
852 branch = changes[5].get("branch")
861 branch = changes[5].get("branch")
853 if branch != 'default':
862 if branch != 'default':
854 branch = util.tolocal(branch)
863 branch = util.tolocal(branch)
855 return showlist('branch', [branch], plural='branches', **args)
864 return showlist('branch', [branch], plural='branches', **args)
856
865
857 def showparents(**args):
866 def showparents(**args):
858 parents = [[('rev', log.rev(p)), ('node', hex(p))]
867 parents = [[('rev', log.rev(p)), ('node', hex(p))]
859 for p in log.parents(changenode)
868 for p in log.parents(changenode)
860 if self.ui.debugflag or p != nullid]
869 if self.ui.debugflag or p != nullid]
861 if (not self.ui.debugflag and len(parents) == 1 and
870 if (not self.ui.debugflag and len(parents) == 1 and
862 parents[0][0][1] == rev - 1):
871 parents[0][0][1] == rev - 1):
863 return
872 return
864 return showlist('parent', parents, **args)
873 return showlist('parent', parents, **args)
865
874
866 def showtags(**args):
875 def showtags(**args):
867 return showlist('tag', self.repo.nodetags(changenode), **args)
876 return showlist('tag', self.repo.nodetags(changenode), **args)
868
877
869 def showextras(**args):
878 def showextras(**args):
870 extras = changes[5].items()
879 extras = changes[5].items()
871 extras.sort()
880 extras.sort()
872 for key, value in extras:
881 for key, value in extras:
873 args = args.copy()
882 args = args.copy()
874 args.update(dict(key=key, value=value))
883 args.update(dict(key=key, value=value))
875 yield self.t('extra', **args)
884 yield self.t('extra', **args)
876
885
877 def showcopies(**args):
886 def showcopies(**args):
878 c = [{'name': x[0], 'source': x[1]} for x in copies]
887 c = [{'name': x[0], 'source': x[1]} for x in copies]
879 return showlist('file_copy', c, plural='file_copies', **args)
888 return showlist('file_copy', c, plural='file_copies', **args)
880
889
881 if self.ui.debugflag:
890 if self.ui.debugflag:
882 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
891 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
883 def showfiles(**args):
892 def showfiles(**args):
884 return showlist('file', files[0], **args)
893 return showlist('file', files[0], **args)
885 def showadds(**args):
894 def showadds(**args):
886 return showlist('file_add', files[1], **args)
895 return showlist('file_add', files[1], **args)
887 def showdels(**args):
896 def showdels(**args):
888 return showlist('file_del', files[2], **args)
897 return showlist('file_del', files[2], **args)
889 def showmanifest(**args):
898 def showmanifest(**args):
890 args = args.copy()
899 args = args.copy()
891 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
900 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
892 node=hex(changes[0])))
901 node=hex(changes[0])))
893 return self.t('manifest', **args)
902 return self.t('manifest', **args)
894 else:
903 else:
895 def showfiles(**args):
904 def showfiles(**args):
896 return showlist('file', changes[3], **args)
905 return showlist('file', changes[3], **args)
897 showadds = ''
906 showadds = ''
898 showdels = ''
907 showdels = ''
899 showmanifest = ''
908 showmanifest = ''
900
909
901 defprops = {
910 defprops = {
902 'author': changes[1],
911 'author': changes[1],
903 'branches': showbranches,
912 'branches': showbranches,
904 'date': changes[2],
913 'date': changes[2],
905 'desc': changes[4],
914 'desc': changes[4],
906 'file_adds': showadds,
915 'file_adds': showadds,
907 'file_dels': showdels,
916 'file_dels': showdels,
908 'files': showfiles,
917 'files': showfiles,
909 'file_copies': showcopies,
918 'file_copies': showcopies,
910 'manifest': showmanifest,
919 'manifest': showmanifest,
911 'node': hex(changenode),
920 'node': hex(changenode),
912 'parents': showparents,
921 'parents': showparents,
913 'rev': rev,
922 'rev': rev,
914 'tags': showtags,
923 'tags': showtags,
915 'extras': showextras,
924 'extras': showextras,
916 }
925 }
917 props = props.copy()
926 props = props.copy()
918 props.update(defprops)
927 props.update(defprops)
919
928
920 try:
929 try:
921 if self.ui.debugflag and 'header_debug' in self.t:
930 if self.ui.debugflag and 'header_debug' in self.t:
922 key = 'header_debug'
931 key = 'header_debug'
923 elif self.ui.quiet and 'header_quiet' in self.t:
932 elif self.ui.quiet and 'header_quiet' in self.t:
924 key = 'header_quiet'
933 key = 'header_quiet'
925 elif self.ui.verbose and 'header_verbose' in self.t:
934 elif self.ui.verbose and 'header_verbose' in self.t:
926 key = 'header_verbose'
935 key = 'header_verbose'
927 elif 'header' in self.t:
936 elif 'header' in self.t:
928 key = 'header'
937 key = 'header'
929 else:
938 else:
930 key = ''
939 key = ''
931 if key:
940 if key:
932 h = templater.stringify(self.t(key, **props))
941 h = templater.stringify(self.t(key, **props))
933 if self.buffered:
942 if self.buffered:
934 self.header[rev] = h
943 self.header[rev] = h
935 else:
944 else:
936 self.ui.write(h)
945 self.ui.write(h)
937 if self.ui.debugflag and 'changeset_debug' in self.t:
946 if self.ui.debugflag and 'changeset_debug' in self.t:
938 key = 'changeset_debug'
947 key = 'changeset_debug'
939 elif self.ui.quiet and 'changeset_quiet' in self.t:
948 elif self.ui.quiet and 'changeset_quiet' in self.t:
940 key = 'changeset_quiet'
949 key = 'changeset_quiet'
941 elif self.ui.verbose and 'changeset_verbose' in self.t:
950 elif self.ui.verbose and 'changeset_verbose' in self.t:
942 key = 'changeset_verbose'
951 key = 'changeset_verbose'
943 else:
952 else:
944 key = 'changeset'
953 key = 'changeset'
945 self.ui.write(templater.stringify(self.t(key, **props)))
954 self.ui.write(templater.stringify(self.t(key, **props)))
946 self.showpatch(changenode)
955 self.showpatch(changenode)
947 except KeyError, inst:
956 except KeyError, inst:
948 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
957 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
949 inst.args[0]))
958 inst.args[0]))
950 except SyntaxError, inst:
959 except SyntaxError, inst:
951 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
960 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
952
961
953 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
962 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
954 """show one changeset using template or regular display.
963 """show one changeset using template or regular display.
955
964
956 Display format will be the first non-empty hit of:
965 Display format will be the first non-empty hit of:
957 1. option 'template'
966 1. option 'template'
958 2. option 'style'
967 2. option 'style'
959 3. [ui] setting 'logtemplate'
968 3. [ui] setting 'logtemplate'
960 4. [ui] setting 'style'
969 4. [ui] setting 'style'
961 If all of these values are either the unset or the empty string,
970 If all of these values are either the unset or the empty string,
962 regular display via changeset_printer() is done.
971 regular display via changeset_printer() is done.
963 """
972 """
964 # options
973 # options
965 patch = False
974 patch = False
966 if opts.get('patch'):
975 if opts.get('patch'):
967 patch = matchfn or util.always
976 patch = matchfn or util.always
968
977
969 tmpl = opts.get('template')
978 tmpl = opts.get('template')
970 mapfile = None
979 mapfile = None
971 if tmpl:
980 if tmpl:
972 tmpl = templater.parsestring(tmpl, quoted=False)
981 tmpl = templater.parsestring(tmpl, quoted=False)
973 else:
982 else:
974 mapfile = opts.get('style')
983 mapfile = opts.get('style')
975 # ui settings
984 # ui settings
976 if not mapfile:
985 if not mapfile:
977 tmpl = ui.config('ui', 'logtemplate')
986 tmpl = ui.config('ui', 'logtemplate')
978 if tmpl:
987 if tmpl:
979 tmpl = templater.parsestring(tmpl)
988 tmpl = templater.parsestring(tmpl)
980 else:
989 else:
981 mapfile = ui.config('ui', 'style')
990 mapfile = ui.config('ui', 'style')
982
991
983 if tmpl or mapfile:
992 if tmpl or mapfile:
984 if mapfile:
993 if mapfile:
985 if not os.path.split(mapfile)[0]:
994 if not os.path.split(mapfile)[0]:
986 mapname = (templater.templatepath('map-cmdline.' + mapfile)
995 mapname = (templater.templatepath('map-cmdline.' + mapfile)
987 or templater.templatepath(mapfile))
996 or templater.templatepath(mapfile))
988 if mapname: mapfile = mapname
997 if mapname: mapfile = mapname
989 try:
998 try:
990 t = changeset_templater(ui, repo, patch, mapfile, buffered)
999 t = changeset_templater(ui, repo, patch, mapfile, buffered)
991 except SyntaxError, inst:
1000 except SyntaxError, inst:
992 raise util.Abort(inst.args[0])
1001 raise util.Abort(inst.args[0])
993 if tmpl: t.use_template(tmpl)
1002 if tmpl: t.use_template(tmpl)
994 return t
1003 return t
995 return changeset_printer(ui, repo, patch, buffered)
1004 return changeset_printer(ui, repo, patch, buffered)
996
1005
997 def finddate(ui, repo, date):
1006 def finddate(ui, repo, date):
998 """Find the tipmost changeset that matches the given date spec"""
1007 """Find the tipmost changeset that matches the given date spec"""
999 df = util.matchdate(date + " to " + date)
1008 df = util.matchdate(date + " to " + date)
1000 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1009 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1001 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
1010 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
1002 results = {}
1011 results = {}
1003 for st, rev, fns in changeiter:
1012 for st, rev, fns in changeiter:
1004 if st == 'add':
1013 if st == 'add':
1005 d = get(rev)[2]
1014 d = get(rev)[2]
1006 if df(d[0]):
1015 if df(d[0]):
1007 results[rev] = d
1016 results[rev] = d
1008 elif st == 'iter':
1017 elif st == 'iter':
1009 if rev in results:
1018 if rev in results:
1010 ui.status("Found revision %s from %s\n" %
1019 ui.status("Found revision %s from %s\n" %
1011 (rev, util.datestr(results[rev])))
1020 (rev, util.datestr(results[rev])))
1012 return str(rev)
1021 return str(rev)
1013
1022
1014 raise util.Abort(_("revision matching date not found"))
1023 raise util.Abort(_("revision matching date not found"))
1015
1024
1016 def walkchangerevs(ui, repo, pats, change, opts):
1025 def walkchangerevs(ui, repo, pats, change, opts):
1017 '''Iterate over files and the revs they changed in.
1026 '''Iterate over files and the revs they changed in.
1018
1027
1019 Callers most commonly need to iterate backwards over the history
1028 Callers most commonly need to iterate backwards over the history
1020 it is interested in. Doing so has awful (quadratic-looking)
1029 it is interested in. Doing so has awful (quadratic-looking)
1021 performance, so we use iterators in a "windowed" way.
1030 performance, so we use iterators in a "windowed" way.
1022
1031
1023 We walk a window of revisions in the desired order. Within the
1032 We walk a window of revisions in the desired order. Within the
1024 window, we first walk forwards to gather data, then in the desired
1033 window, we first walk forwards to gather data, then in the desired
1025 order (usually backwards) to display it.
1034 order (usually backwards) to display it.
1026
1035
1027 This function returns an (iterator, matchfn) tuple. The iterator
1036 This function returns an (iterator, matchfn) tuple. The iterator
1028 yields 3-tuples. They will be of one of the following forms:
1037 yields 3-tuples. They will be of one of the following forms:
1029
1038
1030 "window", incrementing, lastrev: stepping through a window,
1039 "window", incrementing, lastrev: stepping through a window,
1031 positive if walking forwards through revs, last rev in the
1040 positive if walking forwards through revs, last rev in the
1032 sequence iterated over - use to reset state for the current window
1041 sequence iterated over - use to reset state for the current window
1033
1042
1034 "add", rev, fns: out-of-order traversal of the given file names
1043 "add", rev, fns: out-of-order traversal of the given file names
1035 fns, which changed during revision rev - use to gather data for
1044 fns, which changed during revision rev - use to gather data for
1036 possible display
1045 possible display
1037
1046
1038 "iter", rev, None: in-order traversal of the revs earlier iterated
1047 "iter", rev, None: in-order traversal of the revs earlier iterated
1039 over with "add" - use to display data'''
1048 over with "add" - use to display data'''
1040
1049
1041 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1050 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1042 if start < end:
1051 if start < end:
1043 while start < end:
1052 while start < end:
1044 yield start, min(windowsize, end-start)
1053 yield start, min(windowsize, end-start)
1045 start += windowsize
1054 start += windowsize
1046 if windowsize < sizelimit:
1055 if windowsize < sizelimit:
1047 windowsize *= 2
1056 windowsize *= 2
1048 else:
1057 else:
1049 while start > end:
1058 while start > end:
1050 yield start, min(windowsize, start-end-1)
1059 yield start, min(windowsize, start-end-1)
1051 start -= windowsize
1060 start -= windowsize
1052 if windowsize < sizelimit:
1061 if windowsize < sizelimit:
1053 windowsize *= 2
1062 windowsize *= 2
1054
1063
1055 files, matchfn, anypats = matchpats(repo, pats, opts)
1064 files, matchfn, anypats = matchpats(repo, pats, opts)
1056 follow = opts.get('follow') or opts.get('follow_first')
1065 follow = opts.get('follow') or opts.get('follow_first')
1057
1066
1058 if repo.changelog.count() == 0:
1067 if repo.changelog.count() == 0:
1059 return [], matchfn
1068 return [], matchfn
1060
1069
1061 if follow:
1070 if follow:
1062 defrange = '%s:0' % repo.changectx().rev()
1071 defrange = '%s:0' % repo.changectx().rev()
1063 else:
1072 else:
1064 defrange = 'tip:0'
1073 defrange = 'tip:0'
1065 revs = revrange(repo, opts['rev'] or [defrange])
1074 revs = revrange(repo, opts['rev'] or [defrange])
1066 wanted = {}
1075 wanted = {}
1067 slowpath = anypats or opts.get('removed')
1076 slowpath = anypats or opts.get('removed')
1068 fncache = {}
1077 fncache = {}
1069
1078
1070 if not slowpath and not files:
1079 if not slowpath and not files:
1071 # No files, no patterns. Display all revs.
1080 # No files, no patterns. Display all revs.
1072 wanted = dict.fromkeys(revs)
1081 wanted = dict.fromkeys(revs)
1073 copies = []
1082 copies = []
1074 if not slowpath:
1083 if not slowpath:
1075 # Only files, no patterns. Check the history of each file.
1084 # Only files, no patterns. Check the history of each file.
1076 def filerevgen(filelog, node):
1085 def filerevgen(filelog, node):
1077 cl_count = repo.changelog.count()
1086 cl_count = repo.changelog.count()
1078 if node is None:
1087 if node is None:
1079 last = filelog.count() - 1
1088 last = filelog.count() - 1
1080 else:
1089 else:
1081 last = filelog.rev(node)
1090 last = filelog.rev(node)
1082 for i, window in increasing_windows(last, nullrev):
1091 for i, window in increasing_windows(last, nullrev):
1083 revs = []
1092 revs = []
1084 for j in xrange(i - window, i + 1):
1093 for j in xrange(i - window, i + 1):
1085 n = filelog.node(j)
1094 n = filelog.node(j)
1086 revs.append((filelog.linkrev(n),
1095 revs.append((filelog.linkrev(n),
1087 follow and filelog.renamed(n)))
1096 follow and filelog.renamed(n)))
1088 revs.reverse()
1097 revs.reverse()
1089 for rev in revs:
1098 for rev in revs:
1090 # only yield rev for which we have the changelog, it can
1099 # only yield rev for which we have the changelog, it can
1091 # happen while doing "hg log" during a pull or commit
1100 # happen while doing "hg log" during a pull or commit
1092 if rev[0] < cl_count:
1101 if rev[0] < cl_count:
1093 yield rev
1102 yield rev
1094 def iterfiles():
1103 def iterfiles():
1095 for filename in files:
1104 for filename in files:
1096 yield filename, None
1105 yield filename, None
1097 for filename_node in copies:
1106 for filename_node in copies:
1098 yield filename_node
1107 yield filename_node
1099 minrev, maxrev = min(revs), max(revs)
1108 minrev, maxrev = min(revs), max(revs)
1100 for file_, node in iterfiles():
1109 for file_, node in iterfiles():
1101 filelog = repo.file(file_)
1110 filelog = repo.file(file_)
1102 # A zero count may be a directory or deleted file, so
1111 # A zero count may be a directory or deleted file, so
1103 # try to find matching entries on the slow path.
1112 # try to find matching entries on the slow path.
1104 if filelog.count() == 0:
1113 if filelog.count() == 0:
1105 slowpath = True
1114 slowpath = True
1106 break
1115 break
1107 for rev, copied in filerevgen(filelog, node):
1116 for rev, copied in filerevgen(filelog, node):
1108 if rev <= maxrev:
1117 if rev <= maxrev:
1109 if rev < minrev:
1118 if rev < minrev:
1110 break
1119 break
1111 fncache.setdefault(rev, [])
1120 fncache.setdefault(rev, [])
1112 fncache[rev].append(file_)
1121 fncache[rev].append(file_)
1113 wanted[rev] = 1
1122 wanted[rev] = 1
1114 if follow and copied:
1123 if follow and copied:
1115 copies.append(copied)
1124 copies.append(copied)
1116 if slowpath:
1125 if slowpath:
1117 if follow:
1126 if follow:
1118 raise util.Abort(_('can only follow copies/renames for explicit '
1127 raise util.Abort(_('can only follow copies/renames for explicit '
1119 'file names'))
1128 'file names'))
1120
1129
1121 # The slow path checks files modified in every changeset.
1130 # The slow path checks files modified in every changeset.
1122 def changerevgen():
1131 def changerevgen():
1123 for i, window in increasing_windows(repo.changelog.count()-1,
1132 for i, window in increasing_windows(repo.changelog.count()-1,
1124 nullrev):
1133 nullrev):
1125 for j in xrange(i - window, i + 1):
1134 for j in xrange(i - window, i + 1):
1126 yield j, change(j)[3]
1135 yield j, change(j)[3]
1127
1136
1128 for rev, changefiles in changerevgen():
1137 for rev, changefiles in changerevgen():
1129 matches = filter(matchfn, changefiles)
1138 matches = filter(matchfn, changefiles)
1130 if matches:
1139 if matches:
1131 fncache[rev] = matches
1140 fncache[rev] = matches
1132 wanted[rev] = 1
1141 wanted[rev] = 1
1133
1142
1134 class followfilter:
1143 class followfilter:
1135 def __init__(self, onlyfirst=False):
1144 def __init__(self, onlyfirst=False):
1136 self.startrev = nullrev
1145 self.startrev = nullrev
1137 self.roots = []
1146 self.roots = []
1138 self.onlyfirst = onlyfirst
1147 self.onlyfirst = onlyfirst
1139
1148
1140 def match(self, rev):
1149 def match(self, rev):
1141 def realparents(rev):
1150 def realparents(rev):
1142 if self.onlyfirst:
1151 if self.onlyfirst:
1143 return repo.changelog.parentrevs(rev)[0:1]
1152 return repo.changelog.parentrevs(rev)[0:1]
1144 else:
1153 else:
1145 return filter(lambda x: x != nullrev,
1154 return filter(lambda x: x != nullrev,
1146 repo.changelog.parentrevs(rev))
1155 repo.changelog.parentrevs(rev))
1147
1156
1148 if self.startrev == nullrev:
1157 if self.startrev == nullrev:
1149 self.startrev = rev
1158 self.startrev = rev
1150 return True
1159 return True
1151
1160
1152 if rev > self.startrev:
1161 if rev > self.startrev:
1153 # forward: all descendants
1162 # forward: all descendants
1154 if not self.roots:
1163 if not self.roots:
1155 self.roots.append(self.startrev)
1164 self.roots.append(self.startrev)
1156 for parent in realparents(rev):
1165 for parent in realparents(rev):
1157 if parent in self.roots:
1166 if parent in self.roots:
1158 self.roots.append(rev)
1167 self.roots.append(rev)
1159 return True
1168 return True
1160 else:
1169 else:
1161 # backwards: all parents
1170 # backwards: all parents
1162 if not self.roots:
1171 if not self.roots:
1163 self.roots.extend(realparents(self.startrev))
1172 self.roots.extend(realparents(self.startrev))
1164 if rev in self.roots:
1173 if rev in self.roots:
1165 self.roots.remove(rev)
1174 self.roots.remove(rev)
1166 self.roots.extend(realparents(rev))
1175 self.roots.extend(realparents(rev))
1167 return True
1176 return True
1168
1177
1169 return False
1178 return False
1170
1179
1171 # it might be worthwhile to do this in the iterator if the rev range
1180 # it might be worthwhile to do this in the iterator if the rev range
1172 # is descending and the prune args are all within that range
1181 # is descending and the prune args are all within that range
1173 for rev in opts.get('prune', ()):
1182 for rev in opts.get('prune', ()):
1174 rev = repo.changelog.rev(repo.lookup(rev))
1183 rev = repo.changelog.rev(repo.lookup(rev))
1175 ff = followfilter()
1184 ff = followfilter()
1176 stop = min(revs[0], revs[-1])
1185 stop = min(revs[0], revs[-1])
1177 for x in xrange(rev, stop-1, -1):
1186 for x in xrange(rev, stop-1, -1):
1178 if ff.match(x) and x in wanted:
1187 if ff.match(x) and x in wanted:
1179 del wanted[x]
1188 del wanted[x]
1180
1189
1181 def iterate():
1190 def iterate():
1182 if follow and not files:
1191 if follow and not files:
1183 ff = followfilter(onlyfirst=opts.get('follow_first'))
1192 ff = followfilter(onlyfirst=opts.get('follow_first'))
1184 def want(rev):
1193 def want(rev):
1185 if ff.match(rev) and rev in wanted:
1194 if ff.match(rev) and rev in wanted:
1186 return True
1195 return True
1187 return False
1196 return False
1188 else:
1197 else:
1189 def want(rev):
1198 def want(rev):
1190 return rev in wanted
1199 return rev in wanted
1191
1200
1192 for i, window in increasing_windows(0, len(revs)):
1201 for i, window in increasing_windows(0, len(revs)):
1193 yield 'window', revs[0] < revs[-1], revs[-1]
1202 yield 'window', revs[0] < revs[-1], revs[-1]
1194 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1203 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1195 srevs = list(nrevs)
1204 srevs = list(nrevs)
1196 srevs.sort()
1205 srevs.sort()
1197 for rev in srevs:
1206 for rev in srevs:
1198 fns = fncache.get(rev)
1207 fns = fncache.get(rev)
1199 if not fns:
1208 if not fns:
1200 def fns_generator():
1209 def fns_generator():
1201 for f in change(rev)[3]:
1210 for f in change(rev)[3]:
1202 if matchfn(f):
1211 if matchfn(f):
1203 yield f
1212 yield f
1204 fns = fns_generator()
1213 fns = fns_generator()
1205 yield 'add', rev, fns
1214 yield 'add', rev, fns
1206 for rev in nrevs:
1215 for rev in nrevs:
1207 yield 'iter', rev, None
1216 yield 'iter', rev, None
1208 return iterate(), matchfn
1217 return iterate(), matchfn
@@ -1,213 +1,220
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cp "$TESTDIR"/printenv.py .
3 cp "$TESTDIR"/printenv.py .
4
4
5 # commit hooks can see env vars
5 # commit hooks can see env vars
6 hg init a
6 hg init a
7 cd a
7 cd a
8 echo "[hooks]" > .hg/hgrc
8 echo "[hooks]" > .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
9 echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
10 echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
11 echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
12 echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
13 echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
14 echo 'pre-identify = false' >> .hg/hgrc
15 echo 'pre-cat = echo "meow $HG_ARGS"' >> .hg/hgrc
16 echo 'post-cat = echo "purr $HG_RESULT"' >> .hg/hgrc
14 echo a > a
17 echo a > a
15 hg add a
18 hg add a
16 hg commit -m a -d "1000000 0"
19 hg commit -m a -d "1000000 0"
17
20
18 hg clone . ../b
21 hg clone . ../b
19 cd ../b
22 cd ../b
20
23
21 # changegroup hooks can see env vars
24 # changegroup hooks can see env vars
22 echo '[hooks]' > .hg/hgrc
25 echo '[hooks]' > .hg/hgrc
23 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
26 echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
24 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
27 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
25 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
28 echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
26
29
27 # pretxncommit and commit hooks can see both parents of merge
30 # pretxncommit and commit hooks can see both parents of merge
28 cd ../a
31 cd ../a
29 echo b >> a
32 echo b >> a
30 hg commit -m a1 -d "1 0"
33 hg commit -m a1 -d "1 0"
31 hg update -C 0
34 hg update -C 0
32 echo b > b
35 echo b > b
33 hg add b
36 hg add b
34 hg commit -m b -d '1 0'
37 hg commit -m b -d '1 0'
35 hg merge 1
38 hg merge 1
36 hg commit -m merge -d '2 0'
39 hg commit -m merge -d '2 0'
37
40
41 # test generic hooks
42 hg id
43 hg cat b
44
38 cd ../b
45 cd ../b
39 hg pull ../a
46 hg pull ../a
40
47
41 # tag hooks can see env vars
48 # tag hooks can see env vars
42 cd ../a
49 cd ../a
43 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
50 echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
44 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
51 echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
45 hg tag -d '3 0' a
52 hg tag -d '3 0' a
46 hg tag -l la
53 hg tag -l la
47
54
48 # pretag hook can forbid tagging
55 # pretag hook can forbid tagging
49 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
56 echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
50 hg tag -d '4 0' fa
57 hg tag -d '4 0' fa
51 hg tag -l fla
58 hg tag -l fla
52
59
53 # pretxncommit hook can see changeset, can roll back txn, changeset
60 # pretxncommit hook can see changeset, can roll back txn, changeset
54 # no more there after
61 # no more there after
55 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
62 echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
56 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
63 echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
57 echo z > z
64 echo z > z
58 hg add z
65 hg add z
59 hg -q tip
66 hg -q tip
60 hg commit -m 'fail' -d '4 0'
67 hg commit -m 'fail' -d '4 0'
61 hg -q tip
68 hg -q tip
62
69
63 # precommit hook can prevent commit
70 # precommit hook can prevent commit
64 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
71 echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
65 hg commit -m 'fail' -d '4 0'
72 hg commit -m 'fail' -d '4 0'
66 hg -q tip
73 hg -q tip
67
74
68 # preupdate hook can prevent update
75 # preupdate hook can prevent update
69 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
76 echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
70 hg update 1
77 hg update 1
71
78
72 # update hook
79 # update hook
73 echo 'update = python ../printenv.py update' >> .hg/hgrc
80 echo 'update = python ../printenv.py update' >> .hg/hgrc
74 hg update
81 hg update
75
82
76 # prechangegroup hook can prevent incoming changes
83 # prechangegroup hook can prevent incoming changes
77 cd ../b
84 cd ../b
78 hg -q tip
85 hg -q tip
79 echo '[hooks]' > .hg/hgrc
86 echo '[hooks]' > .hg/hgrc
80 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
87 echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
81 hg pull ../a
88 hg pull ../a
82
89
83 # pretxnchangegroup hook can see incoming changes, can roll back txn,
90 # pretxnchangegroup hook can see incoming changes, can roll back txn,
84 # incoming changes no longer there after
91 # incoming changes no longer there after
85 echo '[hooks]' > .hg/hgrc
92 echo '[hooks]' > .hg/hgrc
86 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
93 echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
87 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
94 echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
88 hg pull ../a
95 hg pull ../a
89 hg -q tip
96 hg -q tip
90
97
91 # outgoing hooks can see env vars
98 # outgoing hooks can see env vars
92 rm .hg/hgrc
99 rm .hg/hgrc
93 echo '[hooks]' > ../a/.hg/hgrc
100 echo '[hooks]' > ../a/.hg/hgrc
94 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
101 echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
95 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
102 echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
96 hg pull ../a
103 hg pull ../a
97 hg rollback
104 hg rollback
98
105
99 # preoutgoing hook can prevent outgoing changes
106 # preoutgoing hook can prevent outgoing changes
100 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
107 echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
101 hg pull ../a
108 hg pull ../a
102
109
103 cat > hooktests.py <<EOF
110 cat > hooktests.py <<EOF
104 from mercurial import util
111 from mercurial import util
105
112
106 uncallable = 0
113 uncallable = 0
107
114
108 def printargs(args):
115 def printargs(args):
109 args.pop('ui', None)
116 args.pop('ui', None)
110 args.pop('repo', None)
117 args.pop('repo', None)
111 a = list(args.items())
118 a = list(args.items())
112 a.sort()
119 a.sort()
113 print 'hook args:'
120 print 'hook args:'
114 for k, v in a:
121 for k, v in a:
115 print ' ', k, v
122 print ' ', k, v
116
123
117 def passhook(**args):
124 def passhook(**args):
118 printargs(args)
125 printargs(args)
119
126
120 def failhook(**args):
127 def failhook(**args):
121 printargs(args)
128 printargs(args)
122 return True
129 return True
123
130
124 class LocalException(Exception):
131 class LocalException(Exception):
125 pass
132 pass
126
133
127 def raisehook(**args):
134 def raisehook(**args):
128 raise LocalException('exception from hook')
135 raise LocalException('exception from hook')
129
136
130 def aborthook(**args):
137 def aborthook(**args):
131 raise util.Abort('raise abort from hook')
138 raise util.Abort('raise abort from hook')
132
139
133 def brokenhook(**args):
140 def brokenhook(**args):
134 return 1 + {}
141 return 1 + {}
135
142
136 class container:
143 class container:
137 unreachable = 1
144 unreachable = 1
138 EOF
145 EOF
139
146
140 echo '# test python hooks'
147 echo '# test python hooks'
141 PYTHONPATH="`pwd`:$PYTHONPATH"
148 PYTHONPATH="`pwd`:$PYTHONPATH"
142 export PYTHONPATH
149 export PYTHONPATH
143
150
144 echo '[hooks]' > ../a/.hg/hgrc
151 echo '[hooks]' > ../a/.hg/hgrc
145 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
152 echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
146 hg pull ../a 2>&1 | grep 'raised an exception'
153 hg pull ../a 2>&1 | grep 'raised an exception'
147
154
148 echo '[hooks]' > ../a/.hg/hgrc
155 echo '[hooks]' > ../a/.hg/hgrc
149 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
156 echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
150 hg pull ../a 2>&1 | grep 'raised an exception'
157 hg pull ../a 2>&1 | grep 'raised an exception'
151
158
152 echo '[hooks]' > ../a/.hg/hgrc
159 echo '[hooks]' > ../a/.hg/hgrc
153 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
160 echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
154 hg pull ../a
161 hg pull ../a
155
162
156 echo '[hooks]' > ../a/.hg/hgrc
163 echo '[hooks]' > ../a/.hg/hgrc
157 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
164 echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
158 hg pull ../a
165 hg pull ../a
159
166
160 echo '[hooks]' > ../a/.hg/hgrc
167 echo '[hooks]' > ../a/.hg/hgrc
161 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
168 echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
162 hg pull ../a
169 hg pull ../a
163
170
164 echo '[hooks]' > ../a/.hg/hgrc
171 echo '[hooks]' > ../a/.hg/hgrc
165 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
172 echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
166 hg pull ../a
173 hg pull ../a
167
174
168 echo '[hooks]' > ../a/.hg/hgrc
175 echo '[hooks]' > ../a/.hg/hgrc
169 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
176 echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
170 hg pull ../a
177 hg pull ../a
171
178
172 echo '[hooks]' > ../a/.hg/hgrc
179 echo '[hooks]' > ../a/.hg/hgrc
173 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
180 echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
174 hg pull ../a
181 hg pull ../a
175
182
176 echo '[hooks]' > ../a/.hg/hgrc
183 echo '[hooks]' > ../a/.hg/hgrc
177 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
184 echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
178 hg pull ../a
185 hg pull ../a
179
186
180 echo '[hooks]' > ../a/.hg/hgrc
187 echo '[hooks]' > ../a/.hg/hgrc
181 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
188 echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
182 hg pull ../a
189 hg pull ../a
183
190
184 echo '# make sure --traceback works'
191 echo '# make sure --traceback works'
185 echo '[hooks]' > .hg/hgrc
192 echo '[hooks]' > .hg/hgrc
186 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
193 echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
187
194
188 echo a >> a
195 echo a >> a
189 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
196 hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
190
197
191 cd ..
198 cd ..
192 hg init c
199 hg init c
193 cd c
200 cd c
194
201
195 cat > hookext.py <<EOF
202 cat > hookext.py <<EOF
196 def autohook(**args):
203 def autohook(**args):
197 print "Automatically installed hook"
204 print "Automatically installed hook"
198
205
199 def reposetup(ui, repo):
206 def reposetup(ui, repo):
200 repo.ui.setconfig("hooks", "commit.auto", autohook)
207 repo.ui.setconfig("hooks", "commit.auto", autohook)
201 EOF
208 EOF
202 echo '[extensions]' >> .hg/hgrc
209 echo '[extensions]' >> .hg/hgrc
203 echo 'hookext = hookext.py' >> .hg/hgrc
210 echo 'hookext = hookext.py' >> .hg/hgrc
204
211
205 touch foo
212 touch foo
206 hg add foo
213 hg add foo
207 hg ci -m 'add foo'
214 hg ci -m 'add foo'
208 echo >> foo
215 echo >> foo
209 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
216 hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
210
217
211 hg showconfig hooks | sed -e 's/ at .*>/>/'
218 hg showconfig hooks | sed -e 's/ at .*>/>/'
212
219
213 exit 0
220 exit 0
@@ -1,146 +1,150
1 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
1 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
2 pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
2 pretxncommit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
3 0:29b62aeb769f
3 0:29b62aeb769f
4 commit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
4 commit hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
5 commit.b hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
5 commit.b hook: HG_NODE=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT1=0000000000000000000000000000000000000000 HG_PARENT2=
6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
7 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
8 pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
8 pretxncommit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
9 1:b702efe96888
9 1:b702efe96888
10 commit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
10 commit hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
11 commit.b hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
11 commit.b hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
13 precommit hook: HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
14 pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
14 pretxncommit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
15 2:1324a5531bac
15 2:1324a5531bac
16 commit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
16 commit hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
17 commit.b hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
17 commit.b hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT1=29b62aeb769fdf78d8d9c5f28b017f76d7ef824b HG_PARENT2=
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 (branch merge, don't forget to commit)
19 (branch merge, don't forget to commit)
20 precommit hook: HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
20 precommit hook: HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
21 pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
21 pretxncommit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
22 3:4c52fb2e4022
22 3:4c52fb2e4022
23 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
23 commit hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
24 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
24 commit.b hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT1=1324a5531bac09b329c3845d35ae6a7526874edb HG_PARENT2=b702efe9688826e3a91283852b328b84dbf37bc2
25 warning: pre-identify hook exited with status 1
26 meow cat b
27 purr 0
28 b
25 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
29 prechangegroup hook: HG_SOURCE=pull HG_URL=file:
26 changegroup hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
30 changegroup hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
27 incoming hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
31 incoming hook: HG_NODE=b702efe9688826e3a91283852b328b84dbf37bc2 HG_SOURCE=pull HG_URL=file:
28 incoming hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_SOURCE=pull HG_URL=file:
32 incoming hook: HG_NODE=1324a5531bac09b329c3845d35ae6a7526874edb HG_SOURCE=pull HG_URL=file:
29 incoming hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_SOURCE=pull HG_URL=file:
33 incoming hook: HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_SOURCE=pull HG_URL=file:
30 pulling from ../a
34 pulling from ../a
31 searching for changes
35 searching for changes
32 adding changesets
36 adding changesets
33 adding manifests
37 adding manifests
34 adding file changes
38 adding file changes
35 added 3 changesets with 2 changes to 2 files
39 added 3 changesets with 2 changes to 2 files
36 (run 'hg update' to get a working copy)
40 (run 'hg update' to get a working copy)
37 pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
41 pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
38 precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
42 precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
39 pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
43 pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
40 4:8ea2ef7ad3e8
44 4:8ea2ef7ad3e8
41 commit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
45 commit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
42 commit.b hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
46 commit.b hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 HG_PARENT2=
43 tag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
47 tag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a
44 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
48 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
45 tag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
49 tag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=la
46 pretag hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
50 pretag hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
47 pretag.forbid hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
51 pretag.forbid hook: HG_LOCAL=0 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fa
48 abort: pretag.forbid hook exited with status 1
52 abort: pretag.forbid hook exited with status 1
49 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
53 pretag hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
50 pretag.forbid hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
54 pretag.forbid hook: HG_LOCAL=1 HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_TAG=fla
51 abort: pretag.forbid hook exited with status 1
55 abort: pretag.forbid hook exited with status 1
52 4:8ea2ef7ad3e8
56 4:8ea2ef7ad3e8
53 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
57 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
54 pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
58 pretxncommit hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
55 5:fad284daf8c0
59 5:fad284daf8c0
56 pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
60 pretxncommit.forbid hook: HG_NODE=fad284daf8c032148abaffcd745dafeceefceb61 HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
57 abort: pretxncommit.forbid1 hook exited with status 1
61 abort: pretxncommit.forbid1 hook exited with status 1
58 transaction abort!
62 transaction abort!
59 rollback completed
63 rollback completed
60 4:8ea2ef7ad3e8
64 4:8ea2ef7ad3e8
61 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
65 precommit hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
62 precommit.forbid hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
66 precommit.forbid hook: HG_PARENT1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT2=
63 abort: precommit.forbid hook exited with status 1
67 abort: precommit.forbid hook exited with status 1
64 4:8ea2ef7ad3e8
68 4:8ea2ef7ad3e8
65 preupdate hook: HG_PARENT1=b702efe96888 HG_PARENT2=
69 preupdate hook: HG_PARENT1=b702efe96888 HG_PARENT2=
66 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
70 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
67 preupdate hook: HG_PARENT1=8ea2ef7ad3e8 HG_PARENT2=
71 preupdate hook: HG_PARENT1=8ea2ef7ad3e8 HG_PARENT2=
68 update hook: HG_ERROR=0 HG_PARENT1=8ea2ef7ad3e8 HG_PARENT2=
72 update hook: HG_ERROR=0 HG_PARENT1=8ea2ef7ad3e8 HG_PARENT2=
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 3:4c52fb2e4022
74 3:4c52fb2e4022
71 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
75 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
72 pulling from ../a
76 pulling from ../a
73 searching for changes
77 searching for changes
74 abort: prechangegroup.forbid hook exited with status 1
78 abort: prechangegroup.forbid hook exited with status 1
75 4:8ea2ef7ad3e8
79 4:8ea2ef7ad3e8
76 pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull HG_URL=file:
80 pretxnchangegroup.forbid hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull HG_URL=file:
77 pulling from ../a
81 pulling from ../a
78 searching for changes
82 searching for changes
79 adding changesets
83 adding changesets
80 adding manifests
84 adding manifests
81 adding file changes
85 adding file changes
82 added 1 changesets with 1 changes to 1 files
86 added 1 changesets with 1 changes to 1 files
83 abort: pretxnchangegroup.forbid1 hook exited with status 1
87 abort: pretxnchangegroup.forbid1 hook exited with status 1
84 transaction abort!
88 transaction abort!
85 rollback completed
89 rollback completed
86 3:4c52fb2e4022
90 3:4c52fb2e4022
87 preoutgoing hook: HG_SOURCE=pull
91 preoutgoing hook: HG_SOURCE=pull
88 outgoing hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull
92 outgoing hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_SOURCE=pull
89 pulling from ../a
93 pulling from ../a
90 searching for changes
94 searching for changes
91 adding changesets
95 adding changesets
92 adding manifests
96 adding manifests
93 adding file changes
97 adding file changes
94 added 1 changesets with 1 changes to 1 files
98 added 1 changesets with 1 changes to 1 files
95 (run 'hg update' to get a working copy)
99 (run 'hg update' to get a working copy)
96 rolling back last transaction
100 rolling back last transaction
97 preoutgoing hook: HG_SOURCE=pull
101 preoutgoing hook: HG_SOURCE=pull
98 preoutgoing.forbid hook: HG_SOURCE=pull
102 preoutgoing.forbid hook: HG_SOURCE=pull
99 pulling from ../a
103 pulling from ../a
100 searching for changes
104 searching for changes
101 abort: preoutgoing.forbid hook exited with status 1
105 abort: preoutgoing.forbid hook exited with status 1
102 # test python hooks
106 # test python hooks
103 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
107 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
104 error: preoutgoing.raise hook raised an exception: exception from hook
108 error: preoutgoing.raise hook raised an exception: exception from hook
105 pulling from ../a
109 pulling from ../a
106 searching for changes
110 searching for changes
107 error: preoutgoing.abort hook failed: raise abort from hook
111 error: preoutgoing.abort hook failed: raise abort from hook
108 abort: raise abort from hook
112 abort: raise abort from hook
109 pulling from ../a
113 pulling from ../a
110 searching for changes
114 searching for changes
111 hook args:
115 hook args:
112 hooktype preoutgoing
116 hooktype preoutgoing
113 source pull
117 source pull
114 abort: preoutgoing.fail hook failed
118 abort: preoutgoing.fail hook failed
115 pulling from ../a
119 pulling from ../a
116 searching for changes
120 searching for changes
117 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
121 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
118 pulling from ../a
122 pulling from ../a
119 searching for changes
123 searching for changes
120 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
124 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
121 pulling from ../a
125 pulling from ../a
122 searching for changes
126 searching for changes
123 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
127 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
124 pulling from ../a
128 pulling from ../a
125 searching for changes
129 searching for changes
126 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
130 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
127 pulling from ../a
131 pulling from ../a
128 searching for changes
132 searching for changes
129 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
133 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
130 pulling from ../a
134 pulling from ../a
131 searching for changes
135 searching for changes
132 hook args:
136 hook args:
133 hooktype preoutgoing
137 hooktype preoutgoing
134 source pull
138 source pull
135 adding changesets
139 adding changesets
136 adding manifests
140 adding manifests
137 adding file changes
141 adding file changes
138 added 1 changesets with 1 changes to 1 files
142 added 1 changesets with 1 changes to 1 files
139 (run 'hg update' to get a working copy)
143 (run 'hg update' to get a working copy)
140 # make sure --traceback works
144 # make sure --traceback works
141 Traceback (most recent call last):
145 Traceback (most recent call last):
142 Automatically installed hook
146 Automatically installed hook
143 foo
147 foo
144 calling hook commit.auto: <function autohook>
148 calling hook commit.auto: <function autohook>
145 Automatically installed hook
149 Automatically installed hook
146 hooks.commit.auto=<function autohook>
150 hooks.commit.auto=<function autohook>
General Comments 0
You need to be logged in to leave comments. Login now