##// END OF EJS Templates
Add ui.patch option....
Patrick Mezard -
r4435:aac150af default
parent child Browse files
Show More
@@ -1,548 +1,551 b''
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
315
316 Note: In earlier releases, the names of hook environment variables
316 Note: In earlier releases, the names of hook environment variables
317 did not have a "HG_" prefix. The old unprefixed names are no longer
317 did not have a "HG_" prefix. The old unprefixed names are no longer
318 provided in the environment.
318 provided in the environment.
319
319
320 The syntax for Python hooks is as follows:
320 The syntax for Python hooks is as follows:
321
321
322 hookname = python:modulename.submodule.callable
322 hookname = python:modulename.submodule.callable
323
323
324 Python hooks are run within the Mercurial process. Each hook is
324 Python hooks are run within the Mercurial process. Each hook is
325 called with at least three keyword arguments: a ui object (keyword
325 called with at least three keyword arguments: a ui object (keyword
326 "ui"), a repository object (keyword "repo"), and a "hooktype"
326 "ui"), a repository object (keyword "repo"), and a "hooktype"
327 keyword that tells what kind of hook is used. Arguments listed as
327 keyword that tells what kind of hook is used. Arguments listed as
328 environment variables above are passed as keyword arguments, with no
328 environment variables above are passed as keyword arguments, with no
329 "HG_" prefix, and names in lower case.
329 "HG_" prefix, and names in lower case.
330
330
331 If a Python hook returns a "true" value or raises an exception, this
331 If a Python hook returns a "true" value or raises an exception, this
332 is treated as failure of the hook.
332 is treated as failure of the hook.
333
333
334 http_proxy::
334 http_proxy::
335 Used to access web-based Mercurial repositories through a HTTP
335 Used to access web-based Mercurial repositories through a HTTP
336 proxy.
336 proxy.
337 host;;
337 host;;
338 Host name and (optional) port of the proxy server, for example
338 Host name and (optional) port of the proxy server, for example
339 "myproxy:8000".
339 "myproxy:8000".
340 no;;
340 no;;
341 Optional. Comma-separated list of host names that should bypass
341 Optional. Comma-separated list of host names that should bypass
342 the proxy.
342 the proxy.
343 passwd;;
343 passwd;;
344 Optional. Password to authenticate with at the proxy server.
344 Optional. Password to authenticate with at the proxy server.
345 user;;
345 user;;
346 Optional. User name to authenticate with at the proxy server.
346 Optional. User name to authenticate with at the proxy server.
347
347
348 smtp::
348 smtp::
349 Configuration for extensions that need to send email messages.
349 Configuration for extensions that need to send email messages.
350 host;;
350 host;;
351 Host name of mail server, e.g. "mail.example.com".
351 Host name of mail server, e.g. "mail.example.com".
352 port;;
352 port;;
353 Optional. Port to connect to on mail server. Default: 25.
353 Optional. Port to connect to on mail server. Default: 25.
354 tls;;
354 tls;;
355 Optional. Whether to connect to mail server using TLS. True or
355 Optional. Whether to connect to mail server using TLS. True or
356 False. Default: False.
356 False. Default: False.
357 username;;
357 username;;
358 Optional. User name to authenticate to SMTP server with.
358 Optional. User name to authenticate to SMTP server with.
359 If username is specified, password must also be specified.
359 If username is specified, password must also be specified.
360 Default: none.
360 Default: none.
361 password;;
361 password;;
362 Optional. Password to authenticate to SMTP server with.
362 Optional. Password to authenticate to SMTP server with.
363 If username is specified, password must also be specified.
363 If username is specified, password must also be specified.
364 Default: none.
364 Default: none.
365 local_hostname;;
365 local_hostname;;
366 Optional. It's the hostname that the sender can use to identify itself
366 Optional. It's the hostname that the sender can use to identify itself
367 to the MTA.
367 to the MTA.
368
368
369 paths::
369 paths::
370 Assigns symbolic names to repositories. The left side is the
370 Assigns symbolic names to repositories. The left side is the
371 symbolic name, and the right gives the directory or URL that is the
371 symbolic name, and the right gives the directory or URL that is the
372 location of the repository. Default paths can be declared by
372 location of the repository. Default paths can be declared by
373 setting the following entries.
373 setting the following entries.
374 default;;
374 default;;
375 Directory or URL to use when pulling if no source is specified.
375 Directory or URL to use when pulling if no source is specified.
376 Default is set to repository from which the current repository
376 Default is set to repository from which the current repository
377 was cloned.
377 was cloned.
378 default-push;;
378 default-push;;
379 Optional. Directory or URL to use when pushing if no destination
379 Optional. Directory or URL to use when pushing if no destination
380 is specified.
380 is specified.
381
381
382 server::
382 server::
383 Controls generic server settings.
383 Controls generic server settings.
384 uncompressed;;
384 uncompressed;;
385 Whether to allow clients to clone a repo using the uncompressed
385 Whether to allow clients to clone a repo using the uncompressed
386 streaming protocol. This transfers about 40% more data than a
386 streaming protocol. This transfers about 40% more data than a
387 regular clone, but uses less memory and CPU on both server and
387 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
388 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
389 uncompressed streaming clone is a lot faster (~10x) than a regular
390 clone. Over most WAN connections (anything slower than about
390 clone. Over most WAN connections (anything slower than about
391 6Mbps), uncompressed streaming is slower, because of the extra
391 6Mbps), uncompressed streaming is slower, because of the extra
392 data transfer overhead. Default is False.
392 data transfer overhead. Default is False.
393
393
394 trusted::
394 trusted::
395 For security reasons, Mercurial will not use the settings in
395 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
396 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
397 trusted user or to a trusted group. The main exception is the
398 web interface, which automatically uses some safe settings, since
398 web interface, which automatically uses some safe settings, since
399 it's common to serve repositories from different users.
399 it's common to serve repositories from different users.
400
400
401 This section specifies what users and groups are trusted. The
401 This section specifies what users and groups are trusted. The
402 current user is always trusted. To trust everybody, list a user
402 current user is always trusted. To trust everybody, list a user
403 or a group with name "*".
403 or a group with name "*".
404
404
405 users;;
405 users;;
406 Comma-separated list of trusted users.
406 Comma-separated list of trusted users.
407 groups;;
407 groups;;
408 Comma-separated list of trusted groups.
408 Comma-separated list of trusted groups.
409
409
410 ui::
410 ui::
411 User interface controls.
411 User interface controls.
412 debug;;
412 debug;;
413 Print debugging information. True or False. Default is False.
413 Print debugging information. True or False. Default is False.
414 editor;;
414 editor;;
415 The editor to use during a commit. Default is $EDITOR or "vi".
415 The editor to use during a commit. Default is $EDITOR or "vi".
416 fallbackencoding;;
416 fallbackencoding;;
417 Encoding to try if it's not possible to decode the changelog using
417 Encoding to try if it's not possible to decode the changelog using
418 UTF-8. Default is ISO-8859-1.
418 UTF-8. Default is ISO-8859-1.
419 ignore;;
419 ignore;;
420 A file to read per-user ignore patterns from. This file should be in
420 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
421 the same format as a repository-wide .hgignore file. This option
422 supports hook syntax, so if you want to specify multiple ignore
422 supports hook syntax, so if you want to specify multiple ignore
423 files, you can do so by setting something like
423 files, you can do so by setting something like
424 "ignore.other = ~/.hgignore2". For details of the ignore file
424 "ignore.other = ~/.hgignore2". For details of the ignore file
425 format, see the hgignore(5) man page.
425 format, see the hgignore(5) man page.
426 interactive;;
426 interactive;;
427 Allow to prompt the user. True or False. Default is True.
427 Allow to prompt the user. True or False. Default is True.
428 logtemplate;;
428 logtemplate;;
429 Template string for commands that print changesets.
429 Template string for commands that print changesets.
430 style;;
430 style;;
431 Name of style to use for command output.
431 Name of style to use for command output.
432 merge;;
432 merge;;
433 The conflict resolution program to use during a manual merge.
433 The conflict resolution program to use during a manual merge.
434 Default is "hgmerge".
434 Default is "hgmerge".
435 patch;;
436 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
437 unset.
435 quiet;;
438 quiet;;
436 Reduce the amount of output printed. True or False. Default is False.
439 Reduce the amount of output printed. True or False. Default is False.
437 remotecmd;;
440 remotecmd;;
438 remote command to use for clone/push/pull operations. Default is 'hg'.
441 remote command to use for clone/push/pull operations. Default is 'hg'.
439 ssh;;
442 ssh;;
440 command to use for SSH connections. Default is 'ssh'.
443 command to use for SSH connections. Default is 'ssh'.
441 strict;;
444 strict;;
442 Require exact command names, instead of allowing unambiguous
445 Require exact command names, instead of allowing unambiguous
443 abbreviations. True or False. Default is False.
446 abbreviations. True or False. Default is False.
444 timeout;;
447 timeout;;
445 The timeout used when a lock is held (in seconds), a negative value
448 The timeout used when a lock is held (in seconds), a negative value
446 means no timeout. Default is 600.
449 means no timeout. Default is 600.
447 username;;
450 username;;
448 The committer of a changeset created when running "commit".
451 The committer of a changeset created when running "commit".
449 Typically a person's name and email address, e.g. "Fred Widget
452 Typically a person's name and email address, e.g. "Fred Widget
450 <fred@example.com>". Default is $EMAIL or username@hostname.
453 <fred@example.com>". Default is $EMAIL or username@hostname.
451 If the username in hgrc is empty, it has to be specified manually or
454 If the username in hgrc is empty, it has to be specified manually or
452 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
455 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
453 in the system hgrc).
456 in the system hgrc).
454 verbose;;
457 verbose;;
455 Increase the amount of output printed. True or False. Default is False.
458 Increase the amount of output printed. True or False. Default is False.
456
459
457
460
458 web::
461 web::
459 Web interface configuration.
462 Web interface configuration.
460 accesslog;;
463 accesslog;;
461 Where to output the access log. Default is stdout.
464 Where to output the access log. Default is stdout.
462 address;;
465 address;;
463 Interface address to bind to. Default is all.
466 Interface address to bind to. Default is all.
464 allow_archive;;
467 allow_archive;;
465 List of archive format (bz2, gz, zip) allowed for downloading.
468 List of archive format (bz2, gz, zip) allowed for downloading.
466 Default is empty.
469 Default is empty.
467 allowbz2;;
470 allowbz2;;
468 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
471 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
469 Default is false.
472 Default is false.
470 allowgz;;
473 allowgz;;
471 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
474 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
472 Default is false.
475 Default is false.
473 allowpull;;
476 allowpull;;
474 Whether to allow pulling from the repository. Default is true.
477 Whether to allow pulling from the repository. Default is true.
475 allow_push;;
478 allow_push;;
476 Whether to allow pushing to the repository. If empty or not set,
479 Whether to allow pushing to the repository. If empty or not set,
477 push is not allowed. If the special value "*", any remote user
480 push is not allowed. If the special value "*", any remote user
478 can push, including unauthenticated users. Otherwise, the remote
481 can push, including unauthenticated users. Otherwise, the remote
479 user must have been authenticated, and the authenticated user name
482 user must have been authenticated, and the authenticated user name
480 must be present in this list (separated by whitespace or ",").
483 must be present in this list (separated by whitespace or ",").
481 The contents of the allow_push list are examined after the
484 The contents of the allow_push list are examined after the
482 deny_push list.
485 deny_push list.
483 allowzip;;
486 allowzip;;
484 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
487 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
485 Default is false. This feature creates temporary files.
488 Default is false. This feature creates temporary files.
486 baseurl;;
489 baseurl;;
487 Base URL to use when publishing URLs in other locations, so
490 Base URL to use when publishing URLs in other locations, so
488 third-party tools like email notification hooks can construct URLs.
491 third-party tools like email notification hooks can construct URLs.
489 Example: "http://hgserver/repos/"
492 Example: "http://hgserver/repos/"
490 contact;;
493 contact;;
491 Name or email address of the person in charge of the repository.
494 Name or email address of the person in charge of the repository.
492 Default is "unknown".
495 Default is "unknown".
493 deny_push;;
496 deny_push;;
494 Whether to deny pushing to the repository. If empty or not set,
497 Whether to deny pushing to the repository. If empty or not set,
495 push is not denied. If the special value "*", all remote users
498 push is not denied. If the special value "*", all remote users
496 are denied push. Otherwise, unauthenticated users are all denied,
499 are denied push. Otherwise, unauthenticated users are all denied,
497 and any authenticated user name present in this list (separated by
500 and any authenticated user name present in this list (separated by
498 whitespace or ",") is also denied. The contents of the deny_push
501 whitespace or ",") is also denied. The contents of the deny_push
499 list are examined before the allow_push list.
502 list are examined before the allow_push list.
500 description;;
503 description;;
501 Textual description of the repository's purpose or contents.
504 Textual description of the repository's purpose or contents.
502 Default is "unknown".
505 Default is "unknown".
503 errorlog;;
506 errorlog;;
504 Where to output the error log. Default is stderr.
507 Where to output the error log. Default is stderr.
505 ipv6;;
508 ipv6;;
506 Whether to use IPv6. Default is false.
509 Whether to use IPv6. Default is false.
507 name;;
510 name;;
508 Repository name to use in the web interface. Default is current
511 Repository name to use in the web interface. Default is current
509 working directory.
512 working directory.
510 maxchanges;;
513 maxchanges;;
511 Maximum number of changes to list on the changelog. Default is 10.
514 Maximum number of changes to list on the changelog. Default is 10.
512 maxfiles;;
515 maxfiles;;
513 Maximum number of files to list per changeset. Default is 10.
516 Maximum number of files to list per changeset. Default is 10.
514 port;;
517 port;;
515 Port to listen on. Default is 8000.
518 Port to listen on. Default is 8000.
516 push_ssl;;
519 push_ssl;;
517 Whether to require that inbound pushes be transported over SSL to
520 Whether to require that inbound pushes be transported over SSL to
518 prevent password sniffing. Default is true.
521 prevent password sniffing. Default is true.
519 staticurl;;
522 staticurl;;
520 Base URL to use for static files. If unset, static files (e.g.
523 Base URL to use for static files. If unset, static files (e.g.
521 the hgicon.png favicon) will be served by the CGI script itself.
524 the hgicon.png favicon) will be served by the CGI script itself.
522 Use this setting to serve them directly with the HTTP server.
525 Use this setting to serve them directly with the HTTP server.
523 Example: "http://hgserver/static/"
526 Example: "http://hgserver/static/"
524 stripes;;
527 stripes;;
525 How many lines a "zebra stripe" should span in multiline output.
528 How many lines a "zebra stripe" should span in multiline output.
526 Default is 1; set to 0 to disable.
529 Default is 1; set to 0 to disable.
527 style;;
530 style;;
528 Which template map style to use.
531 Which template map style to use.
529 templates;;
532 templates;;
530 Where to find the HTML templates. Default is install path.
533 Where to find the HTML templates. Default is install path.
531
534
532
535
533 AUTHOR
536 AUTHOR
534 ------
537 ------
535 Bryan O'Sullivan <bos@serpentine.com>.
538 Bryan O'Sullivan <bos@serpentine.com>.
536
539
537 Mercurial was written by Matt Mackall <mpm@selenic.com>.
540 Mercurial was written by Matt Mackall <mpm@selenic.com>.
538
541
539 SEE ALSO
542 SEE ALSO
540 --------
543 --------
541 hg(1), hgignore(5)
544 hg(1), hgignore(5)
542
545
543 COPYING
546 COPYING
544 -------
547 -------
545 This manual page is copyright 2005 Bryan O'Sullivan.
548 This manual page is copyright 2005 Bryan O'Sullivan.
546 Mercurial is copyright 2005, 2006 Matt Mackall.
549 Mercurial is copyright 2005, 2006 Matt Mackall.
547 Free use of this software is granted under the terms of the GNU General
550 Free use of this software is granted under the terms of the GNU General
548 Public License (GPL).
551 Public License (GPL).
@@ -1,3375 +1,3377 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for 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 import demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
11 import bisect, os, re, sys, signal, imp, urllib, pdb, shlex, stat
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import traceback, errno, version, atexit, socket
14 import traceback, errno, version, atexit, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
20 """Exception raised if command shortcut matches more than one command."""
21
21
22 def bail_if_changed(repo):
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
25 raise util.Abort(_("outstanding uncommitted changes"))
26
26
27 def logmessage(opts):
27 def logmessage(opts):
28 """ get the log message according to -m and -l option """
28 """ get the log message according to -m and -l option """
29 message = opts['message']
29 message = opts['message']
30 logfile = opts['logfile']
30 logfile = opts['logfile']
31
31
32 if message and logfile:
32 if message and logfile:
33 raise util.Abort(_('options --message and --logfile are mutually '
33 raise util.Abort(_('options --message and --logfile are mutually '
34 'exclusive'))
34 'exclusive'))
35 if not message and logfile:
35 if not message and logfile:
36 try:
36 try:
37 if logfile == '-':
37 if logfile == '-':
38 message = sys.stdin.read()
38 message = sys.stdin.read()
39 else:
39 else:
40 message = open(logfile).read()
40 message = open(logfile).read()
41 except IOError, inst:
41 except IOError, inst:
42 raise util.Abort(_("can't read commit message '%s': %s") %
42 raise util.Abort(_("can't read commit message '%s': %s") %
43 (logfile, inst.strerror))
43 (logfile, inst.strerror))
44 return message
44 return message
45
45
46 def setremoteconfig(ui, opts):
46 def setremoteconfig(ui, opts):
47 "copy remote options to ui tree"
47 "copy remote options to ui tree"
48 if opts.get('ssh'):
48 if opts.get('ssh'):
49 ui.setconfig("ui", "ssh", opts['ssh'])
49 ui.setconfig("ui", "ssh", opts['ssh'])
50 if opts.get('remotecmd'):
50 if opts.get('remotecmd'):
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
52
52
53 # Commands start here, listed alphabetically
53 # Commands start here, listed alphabetically
54
54
55 def add(ui, repo, *pats, **opts):
55 def add(ui, repo, *pats, **opts):
56 """add the specified files on the next commit
56 """add the specified files on the next commit
57
57
58 Schedule files to be version controlled and added to the repository.
58 Schedule files to be version controlled and added to the repository.
59
59
60 The files will be added to the repository at the next commit. To
60 The files will be added to the repository at the next commit. To
61 undo an add before that, see hg revert.
61 undo an add before that, see hg revert.
62
62
63 If no names are given, add all files in the repository.
63 If no names are given, add all files in the repository.
64 """
64 """
65
65
66 names = []
66 names = []
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
68 if exact:
68 if exact:
69 if ui.verbose:
69 if ui.verbose:
70 ui.status(_('adding %s\n') % rel)
70 ui.status(_('adding %s\n') % rel)
71 names.append(abs)
71 names.append(abs)
72 elif repo.dirstate.state(abs) == '?':
72 elif repo.dirstate.state(abs) == '?':
73 ui.status(_('adding %s\n') % rel)
73 ui.status(_('adding %s\n') % rel)
74 names.append(abs)
74 names.append(abs)
75 if not opts.get('dry_run'):
75 if not opts.get('dry_run'):
76 repo.add(names)
76 repo.add(names)
77
77
78 def addremove(ui, repo, *pats, **opts):
78 def addremove(ui, repo, *pats, **opts):
79 """add all new files, delete all missing files
79 """add all new files, delete all missing files
80
80
81 Add all new files and remove all missing files from the repository.
81 Add all new files and remove all missing files from the repository.
82
82
83 New files are ignored if they match any of the patterns in .hgignore. As
83 New files are ignored if they match any of the patterns in .hgignore. As
84 with add, these changes take effect at the next commit.
84 with add, these changes take effect at the next commit.
85
85
86 Use the -s option to detect renamed files. With a parameter > 0,
86 Use the -s option to detect renamed files. With a parameter > 0,
87 this compares every removed file with every added file and records
87 this compares every removed file with every added file and records
88 those similar enough as renames. This option takes a percentage
88 those similar enough as renames. This option takes a percentage
89 between 0 (disabled) and 100 (files must be identical) as its
89 between 0 (disabled) and 100 (files must be identical) as its
90 parameter. Detecting renamed files this way can be expensive.
90 parameter. Detecting renamed files this way can be expensive.
91 """
91 """
92 sim = float(opts.get('similarity') or 0)
92 sim = float(opts.get('similarity') or 0)
93 if sim < 0 or sim > 100:
93 if sim < 0 or sim > 100:
94 raise util.Abort(_('similarity must be between 0 and 100'))
94 raise util.Abort(_('similarity must be between 0 and 100'))
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
96
96
97 def annotate(ui, repo, *pats, **opts):
97 def annotate(ui, repo, *pats, **opts):
98 """show changeset information per file line
98 """show changeset information per file line
99
99
100 List changes in files, showing the revision id responsible for each line
100 List changes in files, showing the revision id responsible for each line
101
101
102 This command is useful to discover who did a change or when a change took
102 This command is useful to discover who did a change or when a change took
103 place.
103 place.
104
104
105 Without the -a option, annotate will avoid processing files it
105 Without the -a option, annotate will avoid processing files it
106 detects as binary. With -a, annotate will generate an annotation
106 detects as binary. With -a, annotate will generate an annotation
107 anyway, probably with undesirable results.
107 anyway, probably with undesirable results.
108 """
108 """
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
110
110
111 if not pats:
111 if not pats:
112 raise util.Abort(_('at least one file name or pattern required'))
112 raise util.Abort(_('at least one file name or pattern required'))
113
113
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
115 ['number', lambda x: str(x.rev())],
115 ['number', lambda x: str(x.rev())],
116 ['changeset', lambda x: short(x.node())],
116 ['changeset', lambda x: short(x.node())],
117 ['date', getdate], ['follow', lambda x: x.path()]]
117 ['date', getdate], ['follow', lambda x: x.path()]]
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
119 and not opts['follow']):
119 and not opts['follow']):
120 opts['number'] = 1
120 opts['number'] = 1
121
121
122 ctx = repo.changectx(opts['rev'])
122 ctx = repo.changectx(opts['rev'])
123
123
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
125 node=ctx.node()):
125 node=ctx.node()):
126 fctx = ctx.filectx(abs)
126 fctx = ctx.filectx(abs)
127 if not opts['text'] and util.binary(fctx.data()):
127 if not opts['text'] and util.binary(fctx.data()):
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
129 continue
129 continue
130
130
131 lines = fctx.annotate(follow=opts.get('follow'))
131 lines = fctx.annotate(follow=opts.get('follow'))
132 pieces = []
132 pieces = []
133
133
134 for o, f in opmap:
134 for o, f in opmap:
135 if opts[o]:
135 if opts[o]:
136 l = [f(n) for n, dummy in lines]
136 l = [f(n) for n, dummy in lines]
137 if l:
137 if l:
138 m = max(map(len, l))
138 m = max(map(len, l))
139 pieces.append(["%*s" % (m, x) for x in l])
139 pieces.append(["%*s" % (m, x) for x in l])
140
140
141 if pieces:
141 if pieces:
142 for p, l in zip(zip(*pieces), lines):
142 for p, l in zip(zip(*pieces), lines):
143 ui.write("%s: %s" % (" ".join(p), l[1]))
143 ui.write("%s: %s" % (" ".join(p), l[1]))
144
144
145 def archive(ui, repo, dest, **opts):
145 def archive(ui, repo, dest, **opts):
146 '''create unversioned archive of a repository revision
146 '''create unversioned archive of a repository revision
147
147
148 By default, the revision used is the parent of the working
148 By default, the revision used is the parent of the working
149 directory; use "-r" to specify a different revision.
149 directory; use "-r" to specify a different revision.
150
150
151 To specify the type of archive to create, use "-t". Valid
151 To specify the type of archive to create, use "-t". Valid
152 types are:
152 types are:
153
153
154 "files" (default): a directory full of files
154 "files" (default): a directory full of files
155 "tar": tar archive, uncompressed
155 "tar": tar archive, uncompressed
156 "tbz2": tar archive, compressed using bzip2
156 "tbz2": tar archive, compressed using bzip2
157 "tgz": tar archive, compressed using gzip
157 "tgz": tar archive, compressed using gzip
158 "uzip": zip archive, uncompressed
158 "uzip": zip archive, uncompressed
159 "zip": zip archive, compressed using deflate
159 "zip": zip archive, compressed using deflate
160
160
161 The exact name of the destination archive or directory is given
161 The exact name of the destination archive or directory is given
162 using a format string; see "hg help export" for details.
162 using a format string; see "hg help export" for details.
163
163
164 Each member added to an archive file has a directory prefix
164 Each member added to an archive file has a directory prefix
165 prepended. Use "-p" to specify a format string for the prefix.
165 prepended. Use "-p" to specify a format string for the prefix.
166 The default is the basename of the archive, with suffixes removed.
166 The default is the basename of the archive, with suffixes removed.
167 '''
167 '''
168
168
169 node = repo.changectx(opts['rev']).node()
169 node = repo.changectx(opts['rev']).node()
170 dest = cmdutil.make_filename(repo, dest, node)
170 dest = cmdutil.make_filename(repo, dest, node)
171 if os.path.realpath(dest) == repo.root:
171 if os.path.realpath(dest) == repo.root:
172 raise util.Abort(_('repository root cannot be destination'))
172 raise util.Abort(_('repository root cannot be destination'))
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
174 kind = opts.get('type') or 'files'
174 kind = opts.get('type') or 'files'
175 prefix = opts['prefix']
175 prefix = opts['prefix']
176 if dest == '-':
176 if dest == '-':
177 if kind == 'files':
177 if kind == 'files':
178 raise util.Abort(_('cannot archive plain files to stdout'))
178 raise util.Abort(_('cannot archive plain files to stdout'))
179 dest = sys.stdout
179 dest = sys.stdout
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
181 prefix = cmdutil.make_filename(repo, prefix, node)
181 prefix = cmdutil.make_filename(repo, prefix, node)
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
183 matchfn, prefix)
183 matchfn, prefix)
184
184
185 def backout(ui, repo, rev, **opts):
185 def backout(ui, repo, rev, **opts):
186 '''reverse effect of earlier changeset
186 '''reverse effect of earlier changeset
187
187
188 Commit the backed out changes as a new changeset. The new
188 Commit the backed out changes as a new changeset. The new
189 changeset is a child of the backed out changeset.
189 changeset is a child of the backed out changeset.
190
190
191 If you back out a changeset other than the tip, a new head is
191 If you back out a changeset other than the tip, a new head is
192 created. This head is the parent of the working directory. If
192 created. This head is the parent of the working directory. If
193 you back out an old changeset, your working directory will appear
193 you back out an old changeset, your working directory will appear
194 old after the backout. You should merge the backout changeset
194 old after the backout. You should merge the backout changeset
195 with another head.
195 with another head.
196
196
197 The --merge option remembers the parent of the working directory
197 The --merge option remembers the parent of the working directory
198 before starting the backout, then merges the new head with that
198 before starting the backout, then merges the new head with that
199 changeset afterwards. This saves you from doing the merge by
199 changeset afterwards. This saves you from doing the merge by
200 hand. The result of this merge is not committed, as for a normal
200 hand. The result of this merge is not committed, as for a normal
201 merge.'''
201 merge.'''
202
202
203 bail_if_changed(repo)
203 bail_if_changed(repo)
204 op1, op2 = repo.dirstate.parents()
204 op1, op2 = repo.dirstate.parents()
205 if op2 != nullid:
205 if op2 != nullid:
206 raise util.Abort(_('outstanding uncommitted merge'))
206 raise util.Abort(_('outstanding uncommitted merge'))
207 node = repo.lookup(rev)
207 node = repo.lookup(rev)
208 p1, p2 = repo.changelog.parents(node)
208 p1, p2 = repo.changelog.parents(node)
209 if p1 == nullid:
209 if p1 == nullid:
210 raise util.Abort(_('cannot back out a change with no parents'))
210 raise util.Abort(_('cannot back out a change with no parents'))
211 if p2 != nullid:
211 if p2 != nullid:
212 if not opts['parent']:
212 if not opts['parent']:
213 raise util.Abort(_('cannot back out a merge changeset without '
213 raise util.Abort(_('cannot back out a merge changeset without '
214 '--parent'))
214 '--parent'))
215 p = repo.lookup(opts['parent'])
215 p = repo.lookup(opts['parent'])
216 if p not in (p1, p2):
216 if p not in (p1, p2):
217 raise util.Abort(_('%s is not a parent of %s') %
217 raise util.Abort(_('%s is not a parent of %s') %
218 (short(p), short(node)))
218 (short(p), short(node)))
219 parent = p
219 parent = p
220 else:
220 else:
221 if opts['parent']:
221 if opts['parent']:
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
223 parent = p1
223 parent = p1
224 hg.clean(repo, node, show_stats=False)
224 hg.clean(repo, node, show_stats=False)
225 revert_opts = opts.copy()
225 revert_opts = opts.copy()
226 revert_opts['date'] = None
226 revert_opts['date'] = None
227 revert_opts['all'] = True
227 revert_opts['all'] = True
228 revert_opts['rev'] = hex(parent)
228 revert_opts['rev'] = hex(parent)
229 revert(ui, repo, **revert_opts)
229 revert(ui, repo, **revert_opts)
230 commit_opts = opts.copy()
230 commit_opts = opts.copy()
231 commit_opts['addremove'] = False
231 commit_opts['addremove'] = False
232 if not commit_opts['message'] and not commit_opts['logfile']:
232 if not commit_opts['message'] and not commit_opts['logfile']:
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
234 commit_opts['force_editor'] = True
234 commit_opts['force_editor'] = True
235 commit(ui, repo, **commit_opts)
235 commit(ui, repo, **commit_opts)
236 def nice(node):
236 def nice(node):
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
238 ui.status(_('changeset %s backs out changeset %s\n') %
238 ui.status(_('changeset %s backs out changeset %s\n') %
239 (nice(repo.changelog.tip()), nice(node)))
239 (nice(repo.changelog.tip()), nice(node)))
240 if op1 != node:
240 if op1 != node:
241 if opts['merge']:
241 if opts['merge']:
242 ui.status(_('merging with changeset %s\n') % nice(op1))
242 ui.status(_('merging with changeset %s\n') % nice(op1))
243 hg.merge(repo, hex(op1))
243 hg.merge(repo, hex(op1))
244 else:
244 else:
245 ui.status(_('the backout changeset is a new head - '
245 ui.status(_('the backout changeset is a new head - '
246 'do not forget to merge\n'))
246 'do not forget to merge\n'))
247 ui.status(_('(use "backout --merge" '
247 ui.status(_('(use "backout --merge" '
248 'if you want to auto-merge)\n'))
248 'if you want to auto-merge)\n'))
249
249
250 def branch(ui, repo, label=None, **opts):
250 def branch(ui, repo, label=None, **opts):
251 """set or show the current branch name
251 """set or show the current branch name
252
252
253 With <name>, set the current branch name. Otherwise, show the
253 With <name>, set the current branch name. Otherwise, show the
254 current branch name.
254 current branch name.
255
255
256 Unless --force is specified, branch will not let you set a
256 Unless --force is specified, branch will not let you set a
257 branch name that shadows an existing branch.
257 branch name that shadows an existing branch.
258 """
258 """
259
259
260 if label:
260 if label:
261 if not opts.get('force') and label in repo.branchtags():
261 if not opts.get('force') and label in repo.branchtags():
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
262 if label not in [p.branch() for p in repo.workingctx().parents()]:
263 raise util.Abort(_('a branch of the same name already exists'
263 raise util.Abort(_('a branch of the same name already exists'
264 ' (use --force to override)'))
264 ' (use --force to override)'))
265 repo.dirstate.setbranch(util.fromlocal(label))
265 repo.dirstate.setbranch(util.fromlocal(label))
266 else:
266 else:
267 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
267 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
268
268
269 def branches(ui, repo):
269 def branches(ui, repo):
270 """list repository named branches
270 """list repository named branches
271
271
272 List the repository's named branches.
272 List the repository's named branches.
273 """
273 """
274 b = repo.branchtags()
274 b = repo.branchtags()
275 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
275 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
276 l.sort()
276 l.sort()
277 for r, n, t in l:
277 for r, n, t in l:
278 hexfunc = ui.debugflag and hex or short
278 hexfunc = ui.debugflag and hex or short
279 if ui.quiet:
279 if ui.quiet:
280 ui.write("%s\n" % t)
280 ui.write("%s\n" % t)
281 else:
281 else:
282 spaces = " " * (30 - util.locallen(t))
282 spaces = " " * (30 - util.locallen(t))
283 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
283 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
284
284
285 def bundle(ui, repo, fname, dest=None, **opts):
285 def bundle(ui, repo, fname, dest=None, **opts):
286 """create a changegroup file
286 """create a changegroup file
287
287
288 Generate a compressed changegroup file collecting changesets not
288 Generate a compressed changegroup file collecting changesets not
289 found in the other repository.
289 found in the other repository.
290
290
291 If no destination repository is specified the destination is assumed
291 If no destination repository is specified the destination is assumed
292 to have all the nodes specified by one or more --base parameters.
292 to have all the nodes specified by one or more --base parameters.
293
293
294 The bundle file can then be transferred using conventional means and
294 The bundle file can then be transferred using conventional means and
295 applied to another repository with the unbundle or pull command.
295 applied to another repository with the unbundle or pull command.
296 This is useful when direct push and pull are not available or when
296 This is useful when direct push and pull are not available or when
297 exporting an entire repository is undesirable.
297 exporting an entire repository is undesirable.
298
298
299 Applying bundles preserves all changeset contents including
299 Applying bundles preserves all changeset contents including
300 permissions, copy/rename information, and revision history.
300 permissions, copy/rename information, and revision history.
301 """
301 """
302 revs = opts.get('rev') or None
302 revs = opts.get('rev') or None
303 if revs:
303 if revs:
304 revs = [repo.lookup(rev) for rev in revs]
304 revs = [repo.lookup(rev) for rev in revs]
305 base = opts.get('base')
305 base = opts.get('base')
306 if base:
306 if base:
307 if dest:
307 if dest:
308 raise util.Abort(_("--base is incompatible with specifiying "
308 raise util.Abort(_("--base is incompatible with specifiying "
309 "a destination"))
309 "a destination"))
310 base = [repo.lookup(rev) for rev in base]
310 base = [repo.lookup(rev) for rev in base]
311 # create the right base
311 # create the right base
312 # XXX: nodesbetween / changegroup* should be "fixed" instead
312 # XXX: nodesbetween / changegroup* should be "fixed" instead
313 o = []
313 o = []
314 has = {nullid: None}
314 has = {nullid: None}
315 for n in base:
315 for n in base:
316 has.update(repo.changelog.reachable(n))
316 has.update(repo.changelog.reachable(n))
317 if revs:
317 if revs:
318 visit = list(revs)
318 visit = list(revs)
319 else:
319 else:
320 visit = repo.changelog.heads()
320 visit = repo.changelog.heads()
321 seen = {}
321 seen = {}
322 while visit:
322 while visit:
323 n = visit.pop(0)
323 n = visit.pop(0)
324 parents = [p for p in repo.changelog.parents(n) if p not in has]
324 parents = [p for p in repo.changelog.parents(n) if p not in has]
325 if len(parents) == 0:
325 if len(parents) == 0:
326 o.insert(0, n)
326 o.insert(0, n)
327 else:
327 else:
328 for p in parents:
328 for p in parents:
329 if p not in seen:
329 if p not in seen:
330 seen[p] = 1
330 seen[p] = 1
331 visit.append(p)
331 visit.append(p)
332 else:
332 else:
333 setremoteconfig(ui, opts)
333 setremoteconfig(ui, opts)
334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
335 other = hg.repository(ui, dest)
335 other = hg.repository(ui, dest)
336 o = repo.findoutgoing(other, force=opts['force'])
336 o = repo.findoutgoing(other, force=opts['force'])
337
337
338 if revs:
338 if revs:
339 cg = repo.changegroupsubset(o, revs, 'bundle')
339 cg = repo.changegroupsubset(o, revs, 'bundle')
340 else:
340 else:
341 cg = repo.changegroup(o, 'bundle')
341 cg = repo.changegroup(o, 'bundle')
342 changegroup.writebundle(cg, fname, "HG10BZ")
342 changegroup.writebundle(cg, fname, "HG10BZ")
343
343
344 def cat(ui, repo, file1, *pats, **opts):
344 def cat(ui, repo, file1, *pats, **opts):
345 """output the current or given revision of files
345 """output the current or given revision of files
346
346
347 Print the specified files as they were at the given revision.
347 Print the specified files as they were at the given revision.
348 If no revision is given, the parent of the working directory is used,
348 If no revision is given, the parent of the working directory is used,
349 or tip if no revision is checked out.
349 or tip if no revision is checked out.
350
350
351 Output may be to a file, in which case the name of the file is
351 Output may be to a file, in which case the name of the file is
352 given using a format string. The formatting rules are the same as
352 given using a format string. The formatting rules are the same as
353 for the export command, with the following additions:
353 for the export command, with the following additions:
354
354
355 %s basename of file being printed
355 %s basename of file being printed
356 %d dirname of file being printed, or '.' if in repo root
356 %d dirname of file being printed, or '.' if in repo root
357 %p root-relative path name of file being printed
357 %p root-relative path name of file being printed
358 """
358 """
359 ctx = repo.changectx(opts['rev'])
359 ctx = repo.changectx(opts['rev'])
360 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
360 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
361 ctx.node()):
361 ctx.node()):
362 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
362 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
363 fp.write(ctx.filectx(abs).data())
363 fp.write(ctx.filectx(abs).data())
364
364
365 def clone(ui, source, dest=None, **opts):
365 def clone(ui, source, dest=None, **opts):
366 """make a copy of an existing repository
366 """make a copy of an existing repository
367
367
368 Create a copy of an existing repository in a new directory.
368 Create a copy of an existing repository in a new directory.
369
369
370 If no destination directory name is specified, it defaults to the
370 If no destination directory name is specified, it defaults to the
371 basename of the source.
371 basename of the source.
372
372
373 The location of the source is added to the new repository's
373 The location of the source is added to the new repository's
374 .hg/hgrc file, as the default to be used for future pulls.
374 .hg/hgrc file, as the default to be used for future pulls.
375
375
376 For efficiency, hardlinks are used for cloning whenever the source
376 For efficiency, hardlinks are used for cloning whenever the source
377 and destination are on the same filesystem (note this applies only
377 and destination are on the same filesystem (note this applies only
378 to the repository data, not to the checked out files). Some
378 to the repository data, not to the checked out files). Some
379 filesystems, such as AFS, implement hardlinking incorrectly, but
379 filesystems, such as AFS, implement hardlinking incorrectly, but
380 do not report errors. In these cases, use the --pull option to
380 do not report errors. In these cases, use the --pull option to
381 avoid hardlinking.
381 avoid hardlinking.
382
382
383 You can safely clone repositories and checked out files using full
383 You can safely clone repositories and checked out files using full
384 hardlinks with
384 hardlinks with
385
385
386 $ cp -al REPO REPOCLONE
386 $ cp -al REPO REPOCLONE
387
387
388 which is the fastest way to clone. However, the operation is not
388 which is the fastest way to clone. However, the operation is not
389 atomic (making sure REPO is not modified during the operation is
389 atomic (making sure REPO is not modified during the operation is
390 up to you) and you have to make sure your editor breaks hardlinks
390 up to you) and you have to make sure your editor breaks hardlinks
391 (Emacs and most Linux Kernel tools do so).
391 (Emacs and most Linux Kernel tools do so).
392
392
393 If you use the -r option to clone up to a specific revision, no
393 If you use the -r option to clone up to a specific revision, no
394 subsequent revisions will be present in the cloned repository.
394 subsequent revisions will be present in the cloned repository.
395 This option implies --pull, even on local repositories.
395 This option implies --pull, even on local repositories.
396
396
397 See pull for valid source format details.
397 See pull for valid source format details.
398
398
399 It is possible to specify an ssh:// URL as the destination, but no
399 It is possible to specify an ssh:// URL as the destination, but no
400 .hg/hgrc and working directory will be created on the remote side.
400 .hg/hgrc and working directory will be created on the remote side.
401 Look at the help text for the pull command for important details
401 Look at the help text for the pull command for important details
402 about ssh:// URLs.
402 about ssh:// URLs.
403 """
403 """
404 setremoteconfig(ui, opts)
404 setremoteconfig(ui, opts)
405 hg.clone(ui, ui.expandpath(source), dest,
405 hg.clone(ui, ui.expandpath(source), dest,
406 pull=opts['pull'],
406 pull=opts['pull'],
407 stream=opts['uncompressed'],
407 stream=opts['uncompressed'],
408 rev=opts['rev'],
408 rev=opts['rev'],
409 update=not opts['noupdate'])
409 update=not opts['noupdate'])
410
410
411 def commit(ui, repo, *pats, **opts):
411 def commit(ui, repo, *pats, **opts):
412 """commit the specified files or all outstanding changes
412 """commit the specified files or all outstanding changes
413
413
414 Commit changes to the given files into the repository.
414 Commit changes to the given files into the repository.
415
415
416 If a list of files is omitted, all changes reported by "hg status"
416 If a list of files is omitted, all changes reported by "hg status"
417 will be committed.
417 will be committed.
418
418
419 If no commit message is specified, the editor configured in your hgrc
419 If no commit message is specified, the editor configured in your hgrc
420 or in the EDITOR environment variable is started to enter a message.
420 or in the EDITOR environment variable is started to enter a message.
421 """
421 """
422 message = logmessage(opts)
422 message = logmessage(opts)
423
423
424 if opts['addremove']:
424 if opts['addremove']:
425 cmdutil.addremove(repo, pats, opts)
425 cmdutil.addremove(repo, pats, opts)
426 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
426 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
427 if pats:
427 if pats:
428 status = repo.status(files=fns, match=match)
428 status = repo.status(files=fns, match=match)
429 modified, added, removed, deleted, unknown = status[:5]
429 modified, added, removed, deleted, unknown = status[:5]
430 files = modified + added + removed
430 files = modified + added + removed
431 slist = None
431 slist = None
432 for f in fns:
432 for f in fns:
433 if f == '.':
433 if f == '.':
434 continue
434 continue
435 if f not in files:
435 if f not in files:
436 rf = repo.wjoin(f)
436 rf = repo.wjoin(f)
437 if f in unknown:
437 if f in unknown:
438 raise util.Abort(_("file %s not tracked!") % rf)
438 raise util.Abort(_("file %s not tracked!") % rf)
439 try:
439 try:
440 mode = os.lstat(rf)[stat.ST_MODE]
440 mode = os.lstat(rf)[stat.ST_MODE]
441 except OSError:
441 except OSError:
442 raise util.Abort(_("file %s not found!") % rf)
442 raise util.Abort(_("file %s not found!") % rf)
443 if stat.S_ISDIR(mode):
443 if stat.S_ISDIR(mode):
444 name = f + '/'
444 name = f + '/'
445 if slist is None:
445 if slist is None:
446 slist = list(files)
446 slist = list(files)
447 slist.sort()
447 slist.sort()
448 i = bisect.bisect(slist, name)
448 i = bisect.bisect(slist, name)
449 if i >= len(slist) or not slist[i].startswith(name):
449 if i >= len(slist) or not slist[i].startswith(name):
450 raise util.Abort(_("no match under directory %s!")
450 raise util.Abort(_("no match under directory %s!")
451 % rf)
451 % rf)
452 elif not stat.S_ISREG(mode):
452 elif not stat.S_ISREG(mode):
453 raise util.Abort(_("can't commit %s: "
453 raise util.Abort(_("can't commit %s: "
454 "unsupported file type!") % rf)
454 "unsupported file type!") % rf)
455 else:
455 else:
456 files = []
456 files = []
457 try:
457 try:
458 repo.commit(files, message, opts['user'], opts['date'], match,
458 repo.commit(files, message, opts['user'], opts['date'], match,
459 force_editor=opts.get('force_editor'))
459 force_editor=opts.get('force_editor'))
460 except ValueError, inst:
460 except ValueError, inst:
461 raise util.Abort(str(inst))
461 raise util.Abort(str(inst))
462
462
463 def docopy(ui, repo, pats, opts, wlock):
463 def docopy(ui, repo, pats, opts, wlock):
464 # called with the repo lock held
464 # called with the repo lock held
465 #
465 #
466 # hgsep => pathname that uses "/" to separate directories
466 # hgsep => pathname that uses "/" to separate directories
467 # ossep => pathname that uses os.sep to separate directories
467 # ossep => pathname that uses os.sep to separate directories
468 cwd = repo.getcwd()
468 cwd = repo.getcwd()
469 errors = 0
469 errors = 0
470 copied = []
470 copied = []
471 targets = {}
471 targets = {}
472
472
473 # abs: hgsep
473 # abs: hgsep
474 # rel: ossep
474 # rel: ossep
475 # return: hgsep
475 # return: hgsep
476 def okaytocopy(abs, rel, exact):
476 def okaytocopy(abs, rel, exact):
477 reasons = {'?': _('is not managed'),
477 reasons = {'?': _('is not managed'),
478 'a': _('has been marked for add'),
478 'a': _('has been marked for add'),
479 'r': _('has been marked for remove')}
479 'r': _('has been marked for remove')}
480 state = repo.dirstate.state(abs)
480 state = repo.dirstate.state(abs)
481 reason = reasons.get(state)
481 reason = reasons.get(state)
482 if reason:
482 if reason:
483 if state == 'a':
483 if state == 'a':
484 origsrc = repo.dirstate.copied(abs)
484 origsrc = repo.dirstate.copied(abs)
485 if origsrc is not None:
485 if origsrc is not None:
486 return origsrc
486 return origsrc
487 if exact:
487 if exact:
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
488 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
489 else:
489 else:
490 return abs
490 return abs
491
491
492 # origsrc: hgsep
492 # origsrc: hgsep
493 # abssrc: hgsep
493 # abssrc: hgsep
494 # relsrc: ossep
494 # relsrc: ossep
495 # target: ossep
495 # target: ossep
496 def copy(origsrc, abssrc, relsrc, target, exact):
496 def copy(origsrc, abssrc, relsrc, target, exact):
497 abstarget = util.canonpath(repo.root, cwd, target)
497 abstarget = util.canonpath(repo.root, cwd, target)
498 reltarget = util.pathto(repo.root, cwd, abstarget)
498 reltarget = util.pathto(repo.root, cwd, abstarget)
499 prevsrc = targets.get(abstarget)
499 prevsrc = targets.get(abstarget)
500 if prevsrc is not None:
500 if prevsrc is not None:
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
501 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
502 (reltarget, util.localpath(abssrc),
502 (reltarget, util.localpath(abssrc),
503 util.localpath(prevsrc)))
503 util.localpath(prevsrc)))
504 return
504 return
505 if (not opts['after'] and os.path.exists(reltarget) or
505 if (not opts['after'] and os.path.exists(reltarget) or
506 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
506 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
507 if not opts['force']:
507 if not opts['force']:
508 ui.warn(_('%s: not overwriting - file exists\n') %
508 ui.warn(_('%s: not overwriting - file exists\n') %
509 reltarget)
509 reltarget)
510 return
510 return
511 if not opts['after'] and not opts.get('dry_run'):
511 if not opts['after'] and not opts.get('dry_run'):
512 os.unlink(reltarget)
512 os.unlink(reltarget)
513 if opts['after']:
513 if opts['after']:
514 if not os.path.exists(reltarget):
514 if not os.path.exists(reltarget):
515 return
515 return
516 else:
516 else:
517 targetdir = os.path.dirname(reltarget) or '.'
517 targetdir = os.path.dirname(reltarget) or '.'
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
518 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
519 os.makedirs(targetdir)
519 os.makedirs(targetdir)
520 try:
520 try:
521 restore = repo.dirstate.state(abstarget) == 'r'
521 restore = repo.dirstate.state(abstarget) == 'r'
522 if restore and not opts.get('dry_run'):
522 if restore and not opts.get('dry_run'):
523 repo.undelete([abstarget], wlock)
523 repo.undelete([abstarget], wlock)
524 try:
524 try:
525 if not opts.get('dry_run'):
525 if not opts.get('dry_run'):
526 util.copyfile(relsrc, reltarget)
526 util.copyfile(relsrc, reltarget)
527 restore = False
527 restore = False
528 finally:
528 finally:
529 if restore:
529 if restore:
530 repo.remove([abstarget], wlock=wlock)
530 repo.remove([abstarget], wlock=wlock)
531 except IOError, inst:
531 except IOError, inst:
532 if inst.errno == errno.ENOENT:
532 if inst.errno == errno.ENOENT:
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
533 ui.warn(_('%s: deleted in working copy\n') % relsrc)
534 else:
534 else:
535 ui.warn(_('%s: cannot copy - %s\n') %
535 ui.warn(_('%s: cannot copy - %s\n') %
536 (relsrc, inst.strerror))
536 (relsrc, inst.strerror))
537 errors += 1
537 errors += 1
538 return
538 return
539 if ui.verbose or not exact:
539 if ui.verbose or not exact:
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
540 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
541 targets[abstarget] = abssrc
541 targets[abstarget] = abssrc
542 if abstarget != origsrc and not opts.get('dry_run'):
542 if abstarget != origsrc and not opts.get('dry_run'):
543 repo.copy(origsrc, abstarget, wlock)
543 repo.copy(origsrc, abstarget, wlock)
544 copied.append((abssrc, relsrc, exact))
544 copied.append((abssrc, relsrc, exact))
545
545
546 # pat: ossep
546 # pat: ossep
547 # dest ossep
547 # dest ossep
548 # srcs: list of (hgsep, hgsep, ossep, bool)
548 # srcs: list of (hgsep, hgsep, ossep, bool)
549 # return: function that takes hgsep and returns ossep
549 # return: function that takes hgsep and returns ossep
550 def targetpathfn(pat, dest, srcs):
550 def targetpathfn(pat, dest, srcs):
551 if os.path.isdir(pat):
551 if os.path.isdir(pat):
552 abspfx = util.canonpath(repo.root, cwd, pat)
552 abspfx = util.canonpath(repo.root, cwd, pat)
553 abspfx = util.localpath(abspfx)
553 abspfx = util.localpath(abspfx)
554 if destdirexists:
554 if destdirexists:
555 striplen = len(os.path.split(abspfx)[0])
555 striplen = len(os.path.split(abspfx)[0])
556 else:
556 else:
557 striplen = len(abspfx)
557 striplen = len(abspfx)
558 if striplen:
558 if striplen:
559 striplen += len(os.sep)
559 striplen += len(os.sep)
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
560 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
561 elif destdirexists:
561 elif destdirexists:
562 res = lambda p: os.path.join(dest,
562 res = lambda p: os.path.join(dest,
563 os.path.basename(util.localpath(p)))
563 os.path.basename(util.localpath(p)))
564 else:
564 else:
565 res = lambda p: dest
565 res = lambda p: dest
566 return res
566 return res
567
567
568 # pat: ossep
568 # pat: ossep
569 # dest ossep
569 # dest ossep
570 # srcs: list of (hgsep, hgsep, ossep, bool)
570 # srcs: list of (hgsep, hgsep, ossep, bool)
571 # return: function that takes hgsep and returns ossep
571 # return: function that takes hgsep and returns ossep
572 def targetpathafterfn(pat, dest, srcs):
572 def targetpathafterfn(pat, dest, srcs):
573 if util.patkind(pat, None)[0]:
573 if util.patkind(pat, None)[0]:
574 # a mercurial pattern
574 # a mercurial pattern
575 res = lambda p: os.path.join(dest,
575 res = lambda p: os.path.join(dest,
576 os.path.basename(util.localpath(p)))
576 os.path.basename(util.localpath(p)))
577 else:
577 else:
578 abspfx = util.canonpath(repo.root, cwd, pat)
578 abspfx = util.canonpath(repo.root, cwd, pat)
579 if len(abspfx) < len(srcs[0][0]):
579 if len(abspfx) < len(srcs[0][0]):
580 # A directory. Either the target path contains the last
580 # A directory. Either the target path contains the last
581 # component of the source path or it does not.
581 # component of the source path or it does not.
582 def evalpath(striplen):
582 def evalpath(striplen):
583 score = 0
583 score = 0
584 for s in srcs:
584 for s in srcs:
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
585 t = os.path.join(dest, util.localpath(s[0])[striplen:])
586 if os.path.exists(t):
586 if os.path.exists(t):
587 score += 1
587 score += 1
588 return score
588 return score
589
589
590 abspfx = util.localpath(abspfx)
590 abspfx = util.localpath(abspfx)
591 striplen = len(abspfx)
591 striplen = len(abspfx)
592 if striplen:
592 if striplen:
593 striplen += len(os.sep)
593 striplen += len(os.sep)
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
594 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
595 score = evalpath(striplen)
595 score = evalpath(striplen)
596 striplen1 = len(os.path.split(abspfx)[0])
596 striplen1 = len(os.path.split(abspfx)[0])
597 if striplen1:
597 if striplen1:
598 striplen1 += len(os.sep)
598 striplen1 += len(os.sep)
599 if evalpath(striplen1) > score:
599 if evalpath(striplen1) > score:
600 striplen = striplen1
600 striplen = striplen1
601 res = lambda p: os.path.join(dest,
601 res = lambda p: os.path.join(dest,
602 util.localpath(p)[striplen:])
602 util.localpath(p)[striplen:])
603 else:
603 else:
604 # a file
604 # a file
605 if destdirexists:
605 if destdirexists:
606 res = lambda p: os.path.join(dest,
606 res = lambda p: os.path.join(dest,
607 os.path.basename(util.localpath(p)))
607 os.path.basename(util.localpath(p)))
608 else:
608 else:
609 res = lambda p: dest
609 res = lambda p: dest
610 return res
610 return res
611
611
612
612
613 pats = util.expand_glob(pats)
613 pats = util.expand_glob(pats)
614 if not pats:
614 if not pats:
615 raise util.Abort(_('no source or destination specified'))
615 raise util.Abort(_('no source or destination specified'))
616 if len(pats) == 1:
616 if len(pats) == 1:
617 raise util.Abort(_('no destination specified'))
617 raise util.Abort(_('no destination specified'))
618 dest = pats.pop()
618 dest = pats.pop()
619 destdirexists = os.path.isdir(dest)
619 destdirexists = os.path.isdir(dest)
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
620 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
621 raise util.Abort(_('with multiple sources, destination must be an '
621 raise util.Abort(_('with multiple sources, destination must be an '
622 'existing directory'))
622 'existing directory'))
623 if opts['after']:
623 if opts['after']:
624 tfn = targetpathafterfn
624 tfn = targetpathafterfn
625 else:
625 else:
626 tfn = targetpathfn
626 tfn = targetpathfn
627 copylist = []
627 copylist = []
628 for pat in pats:
628 for pat in pats:
629 srcs = []
629 srcs = []
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
630 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
631 globbed=True):
631 globbed=True):
632 origsrc = okaytocopy(abssrc, relsrc, exact)
632 origsrc = okaytocopy(abssrc, relsrc, exact)
633 if origsrc:
633 if origsrc:
634 srcs.append((origsrc, abssrc, relsrc, exact))
634 srcs.append((origsrc, abssrc, relsrc, exact))
635 if not srcs:
635 if not srcs:
636 continue
636 continue
637 copylist.append((tfn(pat, dest, srcs), srcs))
637 copylist.append((tfn(pat, dest, srcs), srcs))
638 if not copylist:
638 if not copylist:
639 raise util.Abort(_('no files to copy'))
639 raise util.Abort(_('no files to copy'))
640
640
641 for targetpath, srcs in copylist:
641 for targetpath, srcs in copylist:
642 for origsrc, abssrc, relsrc, exact in srcs:
642 for origsrc, abssrc, relsrc, exact in srcs:
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
643 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
644
644
645 if errors:
645 if errors:
646 ui.warn(_('(consider using --after)\n'))
646 ui.warn(_('(consider using --after)\n'))
647 return errors, copied
647 return errors, copied
648
648
649 def copy(ui, repo, *pats, **opts):
649 def copy(ui, repo, *pats, **opts):
650 """mark files as copied for the next commit
650 """mark files as copied for the next commit
651
651
652 Mark dest as having copies of source files. If dest is a
652 Mark dest as having copies of source files. If dest is a
653 directory, copies are put in that directory. If dest is a file,
653 directory, copies are put in that directory. If dest is a file,
654 there can only be one source.
654 there can only be one source.
655
655
656 By default, this command copies the contents of files as they
656 By default, this command copies the contents of files as they
657 stand in the working directory. If invoked with --after, the
657 stand in the working directory. If invoked with --after, the
658 operation is recorded, but no copying is performed.
658 operation is recorded, but no copying is performed.
659
659
660 This command takes effect in the next commit. To undo a copy
660 This command takes effect in the next commit. To undo a copy
661 before that, see hg revert.
661 before that, see hg revert.
662 """
662 """
663 wlock = repo.wlock(0)
663 wlock = repo.wlock(0)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
664 errs, copied = docopy(ui, repo, pats, opts, wlock)
665 return errs
665 return errs
666
666
667 def debugancestor(ui, index, rev1, rev2):
667 def debugancestor(ui, index, rev1, rev2):
668 """find the ancestor revision of two revisions in a given index"""
668 """find the ancestor revision of two revisions in a given index"""
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
669 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
670 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
671 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
672
672
673 def debugcomplete(ui, cmd='', **opts):
673 def debugcomplete(ui, cmd='', **opts):
674 """returns the completion list associated with the given command"""
674 """returns the completion list associated with the given command"""
675
675
676 if opts['options']:
676 if opts['options']:
677 options = []
677 options = []
678 otables = [globalopts]
678 otables = [globalopts]
679 if cmd:
679 if cmd:
680 aliases, entry = findcmd(ui, cmd)
680 aliases, entry = findcmd(ui, cmd)
681 otables.append(entry[1])
681 otables.append(entry[1])
682 for t in otables:
682 for t in otables:
683 for o in t:
683 for o in t:
684 if o[0]:
684 if o[0]:
685 options.append('-%s' % o[0])
685 options.append('-%s' % o[0])
686 options.append('--%s' % o[1])
686 options.append('--%s' % o[1])
687 ui.write("%s\n" % "\n".join(options))
687 ui.write("%s\n" % "\n".join(options))
688 return
688 return
689
689
690 clist = findpossible(ui, cmd).keys()
690 clist = findpossible(ui, cmd).keys()
691 clist.sort()
691 clist.sort()
692 ui.write("%s\n" % "\n".join(clist))
692 ui.write("%s\n" % "\n".join(clist))
693
693
694 def debugrebuildstate(ui, repo, rev=""):
694 def debugrebuildstate(ui, repo, rev=""):
695 """rebuild the dirstate as it would look like for the given revision"""
695 """rebuild the dirstate as it would look like for the given revision"""
696 if rev == "":
696 if rev == "":
697 rev = repo.changelog.tip()
697 rev = repo.changelog.tip()
698 ctx = repo.changectx(rev)
698 ctx = repo.changectx(rev)
699 files = ctx.manifest()
699 files = ctx.manifest()
700 wlock = repo.wlock()
700 wlock = repo.wlock()
701 repo.dirstate.rebuild(rev, files)
701 repo.dirstate.rebuild(rev, files)
702
702
703 def debugcheckstate(ui, repo):
703 def debugcheckstate(ui, repo):
704 """validate the correctness of the current dirstate"""
704 """validate the correctness of the current dirstate"""
705 parent1, parent2 = repo.dirstate.parents()
705 parent1, parent2 = repo.dirstate.parents()
706 repo.dirstate.read()
706 repo.dirstate.read()
707 dc = repo.dirstate.map
707 dc = repo.dirstate.map
708 keys = dc.keys()
708 keys = dc.keys()
709 keys.sort()
709 keys.sort()
710 m1 = repo.changectx(parent1).manifest()
710 m1 = repo.changectx(parent1).manifest()
711 m2 = repo.changectx(parent2).manifest()
711 m2 = repo.changectx(parent2).manifest()
712 errors = 0
712 errors = 0
713 for f in dc:
713 for f in dc:
714 state = repo.dirstate.state(f)
714 state = repo.dirstate.state(f)
715 if state in "nr" and f not in m1:
715 if state in "nr" and f not in m1:
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
716 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
717 errors += 1
717 errors += 1
718 if state in "a" and f in m1:
718 if state in "a" and f in m1:
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "m" and f not in m1 and f not in m2:
721 if state in "m" and f not in m1 and f not in m2:
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
722 ui.warn(_("%s in state %s, but not in either manifest\n") %
723 (f, state))
723 (f, state))
724 errors += 1
724 errors += 1
725 for f in m1:
725 for f in m1:
726 state = repo.dirstate.state(f)
726 state = repo.dirstate.state(f)
727 if state not in "nrm":
727 if state not in "nrm":
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
728 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
729 errors += 1
729 errors += 1
730 if errors:
730 if errors:
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
731 error = _(".hg/dirstate inconsistent with current parent's manifest")
732 raise util.Abort(error)
732 raise util.Abort(error)
733
733
734 def showconfig(ui, repo, *values, **opts):
734 def showconfig(ui, repo, *values, **opts):
735 """show combined config settings from all hgrc files
735 """show combined config settings from all hgrc files
736
736
737 With no args, print names and values of all config items.
737 With no args, print names and values of all config items.
738
738
739 With one arg of the form section.name, print just the value of
739 With one arg of the form section.name, print just the value of
740 that config item.
740 that config item.
741
741
742 With multiple args, print names and values of all config items
742 With multiple args, print names and values of all config items
743 with matching section names."""
743 with matching section names."""
744
744
745 untrusted = bool(opts.get('untrusted'))
745 untrusted = bool(opts.get('untrusted'))
746 if values:
746 if values:
747 if len([v for v in values if '.' in v]) > 1:
747 if len([v for v in values if '.' in v]) > 1:
748 raise util.Abort(_('only one config item permitted'))
748 raise util.Abort(_('only one config item permitted'))
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
749 for section, name, value in ui.walkconfig(untrusted=untrusted):
750 sectname = section + '.' + name
750 sectname = section + '.' + name
751 if values:
751 if values:
752 for v in values:
752 for v in values:
753 if v == section:
753 if v == section:
754 ui.write('%s=%s\n' % (sectname, value))
754 ui.write('%s=%s\n' % (sectname, value))
755 elif v == sectname:
755 elif v == sectname:
756 ui.write(value, '\n')
756 ui.write(value, '\n')
757 else:
757 else:
758 ui.write('%s=%s\n' % (sectname, value))
758 ui.write('%s=%s\n' % (sectname, value))
759
759
760 def debugsetparents(ui, repo, rev1, rev2=None):
760 def debugsetparents(ui, repo, rev1, rev2=None):
761 """manually set the parents of the current working directory
761 """manually set the parents of the current working directory
762
762
763 This is useful for writing repository conversion tools, but should
763 This is useful for writing repository conversion tools, but should
764 be used with care.
764 be used with care.
765 """
765 """
766
766
767 if not rev2:
767 if not rev2:
768 rev2 = hex(nullid)
768 rev2 = hex(nullid)
769
769
770 wlock = repo.wlock()
770 wlock = repo.wlock()
771 try:
771 try:
772 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
772 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
773 finally:
773 finally:
774 wlock.release()
774 wlock.release()
775
775
776 def debugstate(ui, repo):
776 def debugstate(ui, repo):
777 """show the contents of the current dirstate"""
777 """show the contents of the current dirstate"""
778 repo.dirstate.read()
778 repo.dirstate.read()
779 dc = repo.dirstate.map
779 dc = repo.dirstate.map
780 keys = dc.keys()
780 keys = dc.keys()
781 keys.sort()
781 keys.sort()
782 for file_ in keys:
782 for file_ in keys:
783 if dc[file_][3] == -1:
783 if dc[file_][3] == -1:
784 # Pad or slice to locale representation
784 # Pad or slice to locale representation
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
786 timestr = 'unset'
786 timestr = 'unset'
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
788 else:
788 else:
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
790 ui.write("%c %3o %10d %s %s\n"
790 ui.write("%c %3o %10d %s %s\n"
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
792 timestr, file_))
792 timestr, file_))
793 for f in repo.dirstate.copies():
793 for f in repo.dirstate.copies():
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
795
795
796 def debugdata(ui, file_, rev):
796 def debugdata(ui, file_, rev):
797 """dump the contents of a data file revision"""
797 """dump the contents of a data file revision"""
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
799 try:
799 try:
800 ui.write(r.revision(r.lookup(rev)))
800 ui.write(r.revision(r.lookup(rev)))
801 except KeyError:
801 except KeyError:
802 raise util.Abort(_('invalid revision identifier %s') % rev)
802 raise util.Abort(_('invalid revision identifier %s') % rev)
803
803
804 def debugdate(ui, date, range=None, **opts):
804 def debugdate(ui, date, range=None, **opts):
805 """parse and display a date"""
805 """parse and display a date"""
806 if opts["extended"]:
806 if opts["extended"]:
807 d = util.parsedate(date, util.extendeddateformats)
807 d = util.parsedate(date, util.extendeddateformats)
808 else:
808 else:
809 d = util.parsedate(date)
809 d = util.parsedate(date)
810 ui.write("internal: %s %s\n" % d)
810 ui.write("internal: %s %s\n" % d)
811 ui.write("standard: %s\n" % util.datestr(d))
811 ui.write("standard: %s\n" % util.datestr(d))
812 if range:
812 if range:
813 m = util.matchdate(range)
813 m = util.matchdate(range)
814 ui.write("match: %s\n" % m(d[0]))
814 ui.write("match: %s\n" % m(d[0]))
815
815
816 def debugindex(ui, file_):
816 def debugindex(ui, file_):
817 """dump the contents of an index file"""
817 """dump the contents of an index file"""
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
819 ui.write(" rev offset length base linkrev" +
819 ui.write(" rev offset length base linkrev" +
820 " nodeid p1 p2\n")
820 " nodeid p1 p2\n")
821 for i in xrange(r.count()):
821 for i in xrange(r.count()):
822 node = r.node(i)
822 node = r.node(i)
823 pp = r.parents(node)
823 pp = r.parents(node)
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
826 short(node), short(pp[0]), short(pp[1])))
826 short(node), short(pp[0]), short(pp[1])))
827
827
828 def debugindexdot(ui, file_):
828 def debugindexdot(ui, file_):
829 """dump an index DAG as a .dot file"""
829 """dump an index DAG as a .dot file"""
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
831 ui.write("digraph G {\n")
831 ui.write("digraph G {\n")
832 for i in xrange(r.count()):
832 for i in xrange(r.count()):
833 node = r.node(i)
833 node = r.node(i)
834 pp = r.parents(node)
834 pp = r.parents(node)
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
836 if pp[1] != nullid:
836 if pp[1] != nullid:
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
838 ui.write("}\n")
838 ui.write("}\n")
839
839
840 def debuginstall(ui):
840 def debuginstall(ui):
841 '''test Mercurial installation'''
841 '''test Mercurial installation'''
842
842
843 def writetemp(contents):
843 def writetemp(contents):
844 (fd, name) = tempfile.mkstemp()
844 (fd, name) = tempfile.mkstemp()
845 f = os.fdopen(fd, "wb")
845 f = os.fdopen(fd, "wb")
846 f.write(contents)
846 f.write(contents)
847 f.close()
847 f.close()
848 return name
848 return name
849
849
850 problems = 0
850 problems = 0
851
851
852 # encoding
852 # encoding
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
854 try:
854 try:
855 util.fromlocal("test")
855 util.fromlocal("test")
856 except util.Abort, inst:
856 except util.Abort, inst:
857 ui.write(" %s\n" % inst)
857 ui.write(" %s\n" % inst)
858 ui.write(_(" (check that your locale is properly set)\n"))
858 ui.write(_(" (check that your locale is properly set)\n"))
859 problems += 1
859 problems += 1
860
860
861 # compiled modules
861 # compiled modules
862 ui.status(_("Checking extensions...\n"))
862 ui.status(_("Checking extensions...\n"))
863 try:
863 try:
864 import bdiff, mpatch, base85
864 import bdiff, mpatch, base85
865 except Exception, inst:
865 except Exception, inst:
866 ui.write(" %s\n" % inst)
866 ui.write(" %s\n" % inst)
867 ui.write(_(" One or more extensions could not be found"))
867 ui.write(_(" One or more extensions could not be found"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
869 problems += 1
869 problems += 1
870
870
871 # templates
871 # templates
872 ui.status(_("Checking templates...\n"))
872 ui.status(_("Checking templates...\n"))
873 try:
873 try:
874 import templater
874 import templater
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
876 except Exception, inst:
876 except Exception, inst:
877 ui.write(" %s\n" % inst)
877 ui.write(" %s\n" % inst)
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
879 problems += 1
879 problems += 1
880
880
881 # patch
881 # patch
882 ui.status(_("Checking patch...\n"))
882 ui.status(_("Checking patch...\n"))
883 path = os.environ.get('PATH', '')
883 path = os.environ.get('PATH', '')
884 patcher = util.find_in_path('gpatch', path,
884 patcher = ui.config('ui', 'patch')
885 util.find_in_path('patch', path, None))
885 if not patcher:
886 patcher = util.find_in_path('gpatch', path,
887 util.find_in_path('patch', path, None))
886 if not patcher:
888 if not patcher:
887 ui.write(_(" Can't find patch or gpatch in PATH\n"))
889 ui.write(_(" Can't find patch or gpatch in PATH\n"))
888 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
890 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
889 problems += 1
891 problems += 1
890 else:
892 else:
891 # actually attempt a patch here
893 # actually attempt a patch here
892 a = "1\n2\n3\n4\n"
894 a = "1\n2\n3\n4\n"
893 b = "1\n2\n3\ninsert\n4\n"
895 b = "1\n2\n3\ninsert\n4\n"
894 fa = writetemp(a)
896 fa = writetemp(a)
895 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
897 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
896 fd = writetemp(d)
898 fd = writetemp(d)
897
899
898 files = {}
900 files = {}
899 try:
901 try:
900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
902 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
901 except util.Abort, e:
903 except util.Abort, e:
902 ui.write(_(" patch call failed:\n"))
904 ui.write(_(" patch call failed:\n"))
903 ui.write(" " + str(e) + "\n")
905 ui.write(" " + str(e) + "\n")
904 problems += 1
906 problems += 1
905 else:
907 else:
906 if list(files) != [os.path.basename(fa)]:
908 if list(files) != [os.path.basename(fa)]:
907 ui.write(_(" unexpected patch output!"))
909 ui.write(_(" unexpected patch output!"))
908 ui.write(_(" (you may have an incompatible version of patch)\n"))
910 ui.write(_(" (you may have an incompatible version of patch)\n"))
909 problems += 1
911 problems += 1
910 a = file(fa).read()
912 a = file(fa).read()
911 if a != b:
913 if a != b:
912 ui.write(_(" patch test failed!"))
914 ui.write(_(" patch test failed!"))
913 ui.write(_(" (you may have an incompatible version of patch)\n"))
915 ui.write(_(" (you may have an incompatible version of patch)\n"))
914 problems += 1
916 problems += 1
915
917
916 os.unlink(fa)
918 os.unlink(fa)
917 os.unlink(fd)
919 os.unlink(fd)
918
920
919 # merge helper
921 # merge helper
920 ui.status(_("Checking merge helper...\n"))
922 ui.status(_("Checking merge helper...\n"))
921 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
923 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
922 or "hgmerge")
924 or "hgmerge")
923 cmdpath = util.find_in_path(cmd, path)
925 cmdpath = util.find_in_path(cmd, path)
924 if not cmdpath:
926 if not cmdpath:
925 cmdpath = util.find_in_path(cmd.split()[0], path)
927 cmdpath = util.find_in_path(cmd.split()[0], path)
926 if not cmdpath:
928 if not cmdpath:
927 if cmd == 'hgmerge':
929 if cmd == 'hgmerge':
928 ui.write(_(" No merge helper set and can't find default"
930 ui.write(_(" No merge helper set and can't find default"
929 " hgmerge script in PATH\n"))
931 " hgmerge script in PATH\n"))
930 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
932 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
931 else:
933 else:
932 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
934 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
933 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
935 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
934 problems += 1
936 problems += 1
935 else:
937 else:
936 # actually attempt a patch here
938 # actually attempt a patch here
937 fa = writetemp("1\n2\n3\n4\n")
939 fa = writetemp("1\n2\n3\n4\n")
938 fl = writetemp("1\n2\n3\ninsert\n4\n")
940 fl = writetemp("1\n2\n3\ninsert\n4\n")
939 fr = writetemp("begin\n1\n2\n3\n4\n")
941 fr = writetemp("begin\n1\n2\n3\n4\n")
940 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
942 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
941 if r:
943 if r:
942 ui.write(_(" got unexpected merge error %d!") % r)
944 ui.write(_(" got unexpected merge error %d!") % r)
943 problems += 1
945 problems += 1
944 m = file(fl).read()
946 m = file(fl).read()
945 if m != "begin\n1\n2\n3\ninsert\n4\n":
947 if m != "begin\n1\n2\n3\ninsert\n4\n":
946 ui.write(_(" got unexpected merge results!") % r)
948 ui.write(_(" got unexpected merge results!") % r)
947 ui.write(_(" (your merge helper may have the"
949 ui.write(_(" (your merge helper may have the"
948 " wrong argument order)\n"))
950 " wrong argument order)\n"))
949 ui.write(m)
951 ui.write(m)
950 os.unlink(fa)
952 os.unlink(fa)
951 os.unlink(fl)
953 os.unlink(fl)
952 os.unlink(fr)
954 os.unlink(fr)
953
955
954 # editor
956 # editor
955 ui.status(_("Checking commit editor...\n"))
957 ui.status(_("Checking commit editor...\n"))
956 editor = (os.environ.get("HGEDITOR") or
958 editor = (os.environ.get("HGEDITOR") or
957 ui.config("ui", "editor") or
959 ui.config("ui", "editor") or
958 os.environ.get("EDITOR", "vi"))
960 os.environ.get("EDITOR", "vi"))
959 cmdpath = util.find_in_path(editor, path)
961 cmdpath = util.find_in_path(editor, path)
960 if not cmdpath:
962 if not cmdpath:
961 cmdpath = util.find_in_path(editor.split()[0], path)
963 cmdpath = util.find_in_path(editor.split()[0], path)
962 if not cmdpath:
964 if not cmdpath:
963 if editor == 'vi':
965 if editor == 'vi':
964 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
966 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
965 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
967 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
966 else:
968 else:
967 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
969 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
968 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
970 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
969 problems += 1
971 problems += 1
970
972
971 # check username
973 # check username
972 ui.status(_("Checking username...\n"))
974 ui.status(_("Checking username...\n"))
973 user = os.environ.get("HGUSER")
975 user = os.environ.get("HGUSER")
974 if user is None:
976 if user is None:
975 user = ui.config("ui", "username")
977 user = ui.config("ui", "username")
976 if user is None:
978 if user is None:
977 user = os.environ.get("EMAIL")
979 user = os.environ.get("EMAIL")
978 if not user:
980 if not user:
979 ui.warn(" ")
981 ui.warn(" ")
980 ui.username()
982 ui.username()
981 ui.write(_(" (specify a username in your .hgrc file)\n"))
983 ui.write(_(" (specify a username in your .hgrc file)\n"))
982
984
983 if not problems:
985 if not problems:
984 ui.status(_("No problems detected\n"))
986 ui.status(_("No problems detected\n"))
985 else:
987 else:
986 ui.write(_("%s problems detected,"
988 ui.write(_("%s problems detected,"
987 " please check your install!\n") % problems)
989 " please check your install!\n") % problems)
988
990
989 return problems
991 return problems
990
992
991 def debugrename(ui, repo, file1, *pats, **opts):
993 def debugrename(ui, repo, file1, *pats, **opts):
992 """dump rename information"""
994 """dump rename information"""
993
995
994 ctx = repo.changectx(opts.get('rev', 'tip'))
996 ctx = repo.changectx(opts.get('rev', 'tip'))
995 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
997 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
996 ctx.node()):
998 ctx.node()):
997 m = ctx.filectx(abs).renamed()
999 m = ctx.filectx(abs).renamed()
998 if m:
1000 if m:
999 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
1001 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
1000 else:
1002 else:
1001 ui.write(_("%s not renamed\n") % rel)
1003 ui.write(_("%s not renamed\n") % rel)
1002
1004
1003 def debugwalk(ui, repo, *pats, **opts):
1005 def debugwalk(ui, repo, *pats, **opts):
1004 """show how files match on given patterns"""
1006 """show how files match on given patterns"""
1005 items = list(cmdutil.walk(repo, pats, opts))
1007 items = list(cmdutil.walk(repo, pats, opts))
1006 if not items:
1008 if not items:
1007 return
1009 return
1008 fmt = '%%s %%-%ds %%-%ds %%s' % (
1010 fmt = '%%s %%-%ds %%-%ds %%s' % (
1009 max([len(abs) for (src, abs, rel, exact) in items]),
1011 max([len(abs) for (src, abs, rel, exact) in items]),
1010 max([len(rel) for (src, abs, rel, exact) in items]))
1012 max([len(rel) for (src, abs, rel, exact) in items]))
1011 for src, abs, rel, exact in items:
1013 for src, abs, rel, exact in items:
1012 line = fmt % (src, abs, rel, exact and 'exact' or '')
1014 line = fmt % (src, abs, rel, exact and 'exact' or '')
1013 ui.write("%s\n" % line.rstrip())
1015 ui.write("%s\n" % line.rstrip())
1014
1016
1015 def diff(ui, repo, *pats, **opts):
1017 def diff(ui, repo, *pats, **opts):
1016 """diff repository (or selected files)
1018 """diff repository (or selected files)
1017
1019
1018 Show differences between revisions for the specified files.
1020 Show differences between revisions for the specified files.
1019
1021
1020 Differences between files are shown using the unified diff format.
1022 Differences between files are shown using the unified diff format.
1021
1023
1022 NOTE: diff may generate unexpected results for merges, as it will
1024 NOTE: diff may generate unexpected results for merges, as it will
1023 default to comparing against the working directory's first parent
1025 default to comparing against the working directory's first parent
1024 changeset if no revisions are specified.
1026 changeset if no revisions are specified.
1025
1027
1026 When two revision arguments are given, then changes are shown
1028 When two revision arguments are given, then changes are shown
1027 between those revisions. If only one revision is specified then
1029 between those revisions. If only one revision is specified then
1028 that revision is compared to the working directory, and, when no
1030 that revision is compared to the working directory, and, when no
1029 revisions are specified, the working directory files are compared
1031 revisions are specified, the working directory files are compared
1030 to its parent.
1032 to its parent.
1031
1033
1032 Without the -a option, diff will avoid generating diffs of files
1034 Without the -a option, diff will avoid generating diffs of files
1033 it detects as binary. With -a, diff will generate a diff anyway,
1035 it detects as binary. With -a, diff will generate a diff anyway,
1034 probably with undesirable results.
1036 probably with undesirable results.
1035 """
1037 """
1036 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1038 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1037
1039
1038 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1040 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1039
1041
1040 patch.diff(repo, node1, node2, fns, match=matchfn,
1042 patch.diff(repo, node1, node2, fns, match=matchfn,
1041 opts=patch.diffopts(ui, opts))
1043 opts=patch.diffopts(ui, opts))
1042
1044
1043 def export(ui, repo, *changesets, **opts):
1045 def export(ui, repo, *changesets, **opts):
1044 """dump the header and diffs for one or more changesets
1046 """dump the header and diffs for one or more changesets
1045
1047
1046 Print the changeset header and diffs for one or more revisions.
1048 Print the changeset header and diffs for one or more revisions.
1047
1049
1048 The information shown in the changeset header is: author,
1050 The information shown in the changeset header is: author,
1049 changeset hash, parent(s) and commit comment.
1051 changeset hash, parent(s) and commit comment.
1050
1052
1051 NOTE: export may generate unexpected diff output for merge changesets,
1053 NOTE: export may generate unexpected diff output for merge changesets,
1052 as it will compare the merge changeset against its first parent only.
1054 as it will compare the merge changeset against its first parent only.
1053
1055
1054 Output may be to a file, in which case the name of the file is
1056 Output may be to a file, in which case the name of the file is
1055 given using a format string. The formatting rules are as follows:
1057 given using a format string. The formatting rules are as follows:
1056
1058
1057 %% literal "%" character
1059 %% literal "%" character
1058 %H changeset hash (40 bytes of hexadecimal)
1060 %H changeset hash (40 bytes of hexadecimal)
1059 %N number of patches being generated
1061 %N number of patches being generated
1060 %R changeset revision number
1062 %R changeset revision number
1061 %b basename of the exporting repository
1063 %b basename of the exporting repository
1062 %h short-form changeset hash (12 bytes of hexadecimal)
1064 %h short-form changeset hash (12 bytes of hexadecimal)
1063 %n zero-padded sequence number, starting at 1
1065 %n zero-padded sequence number, starting at 1
1064 %r zero-padded changeset revision number
1066 %r zero-padded changeset revision number
1065
1067
1066 Without the -a option, export will avoid generating diffs of files
1068 Without the -a option, export will avoid generating diffs of files
1067 it detects as binary. With -a, export will generate a diff anyway,
1069 it detects as binary. With -a, export will generate a diff anyway,
1068 probably with undesirable results.
1070 probably with undesirable results.
1069
1071
1070 With the --switch-parent option, the diff will be against the second
1072 With the --switch-parent option, the diff will be against the second
1071 parent. It can be useful to review a merge.
1073 parent. It can be useful to review a merge.
1072 """
1074 """
1073 if not changesets:
1075 if not changesets:
1074 raise util.Abort(_("export requires at least one changeset"))
1076 raise util.Abort(_("export requires at least one changeset"))
1075 revs = cmdutil.revrange(repo, changesets)
1077 revs = cmdutil.revrange(repo, changesets)
1076 if len(revs) > 1:
1078 if len(revs) > 1:
1077 ui.note(_('exporting patches:\n'))
1079 ui.note(_('exporting patches:\n'))
1078 else:
1080 else:
1079 ui.note(_('exporting patch:\n'))
1081 ui.note(_('exporting patch:\n'))
1080 patch.export(repo, revs, template=opts['output'],
1082 patch.export(repo, revs, template=opts['output'],
1081 switch_parent=opts['switch_parent'],
1083 switch_parent=opts['switch_parent'],
1082 opts=patch.diffopts(ui, opts))
1084 opts=patch.diffopts(ui, opts))
1083
1085
1084 def grep(ui, repo, pattern, *pats, **opts):
1086 def grep(ui, repo, pattern, *pats, **opts):
1085 """search for a pattern in specified files and revisions
1087 """search for a pattern in specified files and revisions
1086
1088
1087 Search revisions of files for a regular expression.
1089 Search revisions of files for a regular expression.
1088
1090
1089 This command behaves differently than Unix grep. It only accepts
1091 This command behaves differently than Unix grep. It only accepts
1090 Python/Perl regexps. It searches repository history, not the
1092 Python/Perl regexps. It searches repository history, not the
1091 working directory. It always prints the revision number in which
1093 working directory. It always prints the revision number in which
1092 a match appears.
1094 a match appears.
1093
1095
1094 By default, grep only prints output for the first revision of a
1096 By default, grep only prints output for the first revision of a
1095 file in which it finds a match. To get it to print every revision
1097 file in which it finds a match. To get it to print every revision
1096 that contains a change in match status ("-" for a match that
1098 that contains a change in match status ("-" for a match that
1097 becomes a non-match, or "+" for a non-match that becomes a match),
1099 becomes a non-match, or "+" for a non-match that becomes a match),
1098 use the --all flag.
1100 use the --all flag.
1099 """
1101 """
1100 reflags = 0
1102 reflags = 0
1101 if opts['ignore_case']:
1103 if opts['ignore_case']:
1102 reflags |= re.I
1104 reflags |= re.I
1103 regexp = re.compile(pattern, reflags)
1105 regexp = re.compile(pattern, reflags)
1104 sep, eol = ':', '\n'
1106 sep, eol = ':', '\n'
1105 if opts['print0']:
1107 if opts['print0']:
1106 sep = eol = '\0'
1108 sep = eol = '\0'
1107
1109
1108 fcache = {}
1110 fcache = {}
1109 def getfile(fn):
1111 def getfile(fn):
1110 if fn not in fcache:
1112 if fn not in fcache:
1111 fcache[fn] = repo.file(fn)
1113 fcache[fn] = repo.file(fn)
1112 return fcache[fn]
1114 return fcache[fn]
1113
1115
1114 def matchlines(body):
1116 def matchlines(body):
1115 begin = 0
1117 begin = 0
1116 linenum = 0
1118 linenum = 0
1117 while True:
1119 while True:
1118 match = regexp.search(body, begin)
1120 match = regexp.search(body, begin)
1119 if not match:
1121 if not match:
1120 break
1122 break
1121 mstart, mend = match.span()
1123 mstart, mend = match.span()
1122 linenum += body.count('\n', begin, mstart) + 1
1124 linenum += body.count('\n', begin, mstart) + 1
1123 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1125 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1124 lend = body.find('\n', mend)
1126 lend = body.find('\n', mend)
1125 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1127 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1126 begin = lend + 1
1128 begin = lend + 1
1127
1129
1128 class linestate(object):
1130 class linestate(object):
1129 def __init__(self, line, linenum, colstart, colend):
1131 def __init__(self, line, linenum, colstart, colend):
1130 self.line = line
1132 self.line = line
1131 self.linenum = linenum
1133 self.linenum = linenum
1132 self.colstart = colstart
1134 self.colstart = colstart
1133 self.colend = colend
1135 self.colend = colend
1134
1136
1135 def __eq__(self, other):
1137 def __eq__(self, other):
1136 return self.line == other.line
1138 return self.line == other.line
1137
1139
1138 matches = {}
1140 matches = {}
1139 copies = {}
1141 copies = {}
1140 def grepbody(fn, rev, body):
1142 def grepbody(fn, rev, body):
1141 matches[rev].setdefault(fn, [])
1143 matches[rev].setdefault(fn, [])
1142 m = matches[rev][fn]
1144 m = matches[rev][fn]
1143 for lnum, cstart, cend, line in matchlines(body):
1145 for lnum, cstart, cend, line in matchlines(body):
1144 s = linestate(line, lnum, cstart, cend)
1146 s = linestate(line, lnum, cstart, cend)
1145 m.append(s)
1147 m.append(s)
1146
1148
1147 def difflinestates(a, b):
1149 def difflinestates(a, b):
1148 sm = difflib.SequenceMatcher(None, a, b)
1150 sm = difflib.SequenceMatcher(None, a, b)
1149 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1151 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1150 if tag == 'insert':
1152 if tag == 'insert':
1151 for i in xrange(blo, bhi):
1153 for i in xrange(blo, bhi):
1152 yield ('+', b[i])
1154 yield ('+', b[i])
1153 elif tag == 'delete':
1155 elif tag == 'delete':
1154 for i in xrange(alo, ahi):
1156 for i in xrange(alo, ahi):
1155 yield ('-', a[i])
1157 yield ('-', a[i])
1156 elif tag == 'replace':
1158 elif tag == 'replace':
1157 for i in xrange(alo, ahi):
1159 for i in xrange(alo, ahi):
1158 yield ('-', a[i])
1160 yield ('-', a[i])
1159 for i in xrange(blo, bhi):
1161 for i in xrange(blo, bhi):
1160 yield ('+', b[i])
1162 yield ('+', b[i])
1161
1163
1162 prev = {}
1164 prev = {}
1163 def display(fn, rev, states, prevstates):
1165 def display(fn, rev, states, prevstates):
1164 found = False
1166 found = False
1165 filerevmatches = {}
1167 filerevmatches = {}
1166 r = prev.get(fn, -1)
1168 r = prev.get(fn, -1)
1167 if opts['all']:
1169 if opts['all']:
1168 iter = difflinestates(states, prevstates)
1170 iter = difflinestates(states, prevstates)
1169 else:
1171 else:
1170 iter = [('', l) for l in prevstates]
1172 iter = [('', l) for l in prevstates]
1171 for change, l in iter:
1173 for change, l in iter:
1172 cols = [fn, str(r)]
1174 cols = [fn, str(r)]
1173 if opts['line_number']:
1175 if opts['line_number']:
1174 cols.append(str(l.linenum))
1176 cols.append(str(l.linenum))
1175 if opts['all']:
1177 if opts['all']:
1176 cols.append(change)
1178 cols.append(change)
1177 if opts['user']:
1179 if opts['user']:
1178 cols.append(ui.shortuser(get(r)[1]))
1180 cols.append(ui.shortuser(get(r)[1]))
1179 if opts['files_with_matches']:
1181 if opts['files_with_matches']:
1180 c = (fn, r)
1182 c = (fn, r)
1181 if c in filerevmatches:
1183 if c in filerevmatches:
1182 continue
1184 continue
1183 filerevmatches[c] = 1
1185 filerevmatches[c] = 1
1184 else:
1186 else:
1185 cols.append(l.line)
1187 cols.append(l.line)
1186 ui.write(sep.join(cols), eol)
1188 ui.write(sep.join(cols), eol)
1187 found = True
1189 found = True
1188 return found
1190 return found
1189
1191
1190 fstate = {}
1192 fstate = {}
1191 skip = {}
1193 skip = {}
1192 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1194 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1193 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1195 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1194 found = False
1196 found = False
1195 follow = opts.get('follow')
1197 follow = opts.get('follow')
1196 for st, rev, fns in changeiter:
1198 for st, rev, fns in changeiter:
1197 if st == 'window':
1199 if st == 'window':
1198 matches.clear()
1200 matches.clear()
1199 elif st == 'add':
1201 elif st == 'add':
1200 mf = repo.changectx(rev).manifest()
1202 mf = repo.changectx(rev).manifest()
1201 matches[rev] = {}
1203 matches[rev] = {}
1202 for fn in fns:
1204 for fn in fns:
1203 if fn in skip:
1205 if fn in skip:
1204 continue
1206 continue
1205 fstate.setdefault(fn, {})
1207 fstate.setdefault(fn, {})
1206 try:
1208 try:
1207 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1209 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1208 if follow:
1210 if follow:
1209 copied = getfile(fn).renamed(mf[fn])
1211 copied = getfile(fn).renamed(mf[fn])
1210 if copied:
1212 if copied:
1211 copies.setdefault(rev, {})[fn] = copied[0]
1213 copies.setdefault(rev, {})[fn] = copied[0]
1212 except KeyError:
1214 except KeyError:
1213 pass
1215 pass
1214 elif st == 'iter':
1216 elif st == 'iter':
1215 states = matches[rev].items()
1217 states = matches[rev].items()
1216 states.sort()
1218 states.sort()
1217 for fn, m in states:
1219 for fn, m in states:
1218 copy = copies.get(rev, {}).get(fn)
1220 copy = copies.get(rev, {}).get(fn)
1219 if fn in skip:
1221 if fn in skip:
1220 if copy:
1222 if copy:
1221 skip[copy] = True
1223 skip[copy] = True
1222 continue
1224 continue
1223 if fn in prev or fstate[fn]:
1225 if fn in prev or fstate[fn]:
1224 r = display(fn, rev, m, fstate[fn])
1226 r = display(fn, rev, m, fstate[fn])
1225 found = found or r
1227 found = found or r
1226 if r and not opts['all']:
1228 if r and not opts['all']:
1227 skip[fn] = True
1229 skip[fn] = True
1228 if copy:
1230 if copy:
1229 skip[copy] = True
1231 skip[copy] = True
1230 fstate[fn] = m
1232 fstate[fn] = m
1231 if copy:
1233 if copy:
1232 fstate[copy] = m
1234 fstate[copy] = m
1233 prev[fn] = rev
1235 prev[fn] = rev
1234
1236
1235 fstate = fstate.items()
1237 fstate = fstate.items()
1236 fstate.sort()
1238 fstate.sort()
1237 for fn, state in fstate:
1239 for fn, state in fstate:
1238 if fn in skip:
1240 if fn in skip:
1239 continue
1241 continue
1240 if fn not in copies.get(prev[fn], {}):
1242 if fn not in copies.get(prev[fn], {}):
1241 found = display(fn, rev, {}, state) or found
1243 found = display(fn, rev, {}, state) or found
1242 return (not found and 1) or 0
1244 return (not found and 1) or 0
1243
1245
1244 def heads(ui, repo, **opts):
1246 def heads(ui, repo, **opts):
1245 """show current repository heads
1247 """show current repository heads
1246
1248
1247 Show all repository head changesets.
1249 Show all repository head changesets.
1248
1250
1249 Repository "heads" are changesets that don't have children
1251 Repository "heads" are changesets that don't have children
1250 changesets. They are where development generally takes place and
1252 changesets. They are where development generally takes place and
1251 are the usual targets for update and merge operations.
1253 are the usual targets for update and merge operations.
1252 """
1254 """
1253 if opts['rev']:
1255 if opts['rev']:
1254 heads = repo.heads(repo.lookup(opts['rev']))
1256 heads = repo.heads(repo.lookup(opts['rev']))
1255 else:
1257 else:
1256 heads = repo.heads()
1258 heads = repo.heads()
1257 displayer = cmdutil.show_changeset(ui, repo, opts)
1259 displayer = cmdutil.show_changeset(ui, repo, opts)
1258 for n in heads:
1260 for n in heads:
1259 displayer.show(changenode=n)
1261 displayer.show(changenode=n)
1260
1262
1261 def help_(ui, name=None, with_version=False):
1263 def help_(ui, name=None, with_version=False):
1262 """show help for a command, extension, or list of commands
1264 """show help for a command, extension, or list of commands
1263
1265
1264 With no arguments, print a list of commands and short help.
1266 With no arguments, print a list of commands and short help.
1265
1267
1266 Given a command name, print help for that command.
1268 Given a command name, print help for that command.
1267
1269
1268 Given an extension name, print help for that extension, and the
1270 Given an extension name, print help for that extension, and the
1269 commands it provides."""
1271 commands it provides."""
1270 option_lists = []
1272 option_lists = []
1271
1273
1272 def addglobalopts(aliases):
1274 def addglobalopts(aliases):
1273 if ui.verbose:
1275 if ui.verbose:
1274 option_lists.append((_("global options:"), globalopts))
1276 option_lists.append((_("global options:"), globalopts))
1275 if name == 'shortlist':
1277 if name == 'shortlist':
1276 option_lists.append((_('use "hg help" for the full list '
1278 option_lists.append((_('use "hg help" for the full list '
1277 'of commands'), ()))
1279 'of commands'), ()))
1278 else:
1280 else:
1279 if name == 'shortlist':
1281 if name == 'shortlist':
1280 msg = _('use "hg help" for the full list of commands '
1282 msg = _('use "hg help" for the full list of commands '
1281 'or "hg -v" for details')
1283 'or "hg -v" for details')
1282 elif aliases:
1284 elif aliases:
1283 msg = _('use "hg -v help%s" to show aliases and '
1285 msg = _('use "hg -v help%s" to show aliases and '
1284 'global options') % (name and " " + name or "")
1286 'global options') % (name and " " + name or "")
1285 else:
1287 else:
1286 msg = _('use "hg -v help %s" to show global options') % name
1288 msg = _('use "hg -v help %s" to show global options') % name
1287 option_lists.append((msg, ()))
1289 option_lists.append((msg, ()))
1288
1290
1289 def helpcmd(name):
1291 def helpcmd(name):
1290 if with_version:
1292 if with_version:
1291 version_(ui)
1293 version_(ui)
1292 ui.write('\n')
1294 ui.write('\n')
1293 aliases, i = findcmd(ui, name)
1295 aliases, i = findcmd(ui, name)
1294 # synopsis
1296 # synopsis
1295 ui.write("%s\n\n" % i[2])
1297 ui.write("%s\n\n" % i[2])
1296
1298
1297 # description
1299 # description
1298 doc = i[0].__doc__
1300 doc = i[0].__doc__
1299 if not doc:
1301 if not doc:
1300 doc = _("(No help text available)")
1302 doc = _("(No help text available)")
1301 if ui.quiet:
1303 if ui.quiet:
1302 doc = doc.splitlines(0)[0]
1304 doc = doc.splitlines(0)[0]
1303 ui.write("%s\n" % doc.rstrip())
1305 ui.write("%s\n" % doc.rstrip())
1304
1306
1305 if not ui.quiet:
1307 if not ui.quiet:
1306 # aliases
1308 # aliases
1307 if len(aliases) > 1:
1309 if len(aliases) > 1:
1308 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1310 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1309
1311
1310 # options
1312 # options
1311 if i[1]:
1313 if i[1]:
1312 option_lists.append((_("options:\n"), i[1]))
1314 option_lists.append((_("options:\n"), i[1]))
1313
1315
1314 addglobalopts(False)
1316 addglobalopts(False)
1315
1317
1316 def helplist(select=None):
1318 def helplist(select=None):
1317 h = {}
1319 h = {}
1318 cmds = {}
1320 cmds = {}
1319 for c, e in table.items():
1321 for c, e in table.items():
1320 f = c.split("|", 1)[0]
1322 f = c.split("|", 1)[0]
1321 if select and not select(f):
1323 if select and not select(f):
1322 continue
1324 continue
1323 if name == "shortlist" and not f.startswith("^"):
1325 if name == "shortlist" and not f.startswith("^"):
1324 continue
1326 continue
1325 f = f.lstrip("^")
1327 f = f.lstrip("^")
1326 if not ui.debugflag and f.startswith("debug"):
1328 if not ui.debugflag and f.startswith("debug"):
1327 continue
1329 continue
1328 doc = e[0].__doc__
1330 doc = e[0].__doc__
1329 if not doc:
1331 if not doc:
1330 doc = _("(No help text available)")
1332 doc = _("(No help text available)")
1331 h[f] = doc.splitlines(0)[0].rstrip()
1333 h[f] = doc.splitlines(0)[0].rstrip()
1332 cmds[f] = c.lstrip("^")
1334 cmds[f] = c.lstrip("^")
1333
1335
1334 fns = h.keys()
1336 fns = h.keys()
1335 fns.sort()
1337 fns.sort()
1336 m = max(map(len, fns))
1338 m = max(map(len, fns))
1337 for f in fns:
1339 for f in fns:
1338 if ui.verbose:
1340 if ui.verbose:
1339 commands = cmds[f].replace("|",", ")
1341 commands = cmds[f].replace("|",", ")
1340 ui.write(" %s:\n %s\n"%(commands, h[f]))
1342 ui.write(" %s:\n %s\n"%(commands, h[f]))
1341 else:
1343 else:
1342 ui.write(' %-*s %s\n' % (m, f, h[f]))
1344 ui.write(' %-*s %s\n' % (m, f, h[f]))
1343
1345
1344 if not ui.quiet:
1346 if not ui.quiet:
1345 addglobalopts(True)
1347 addglobalopts(True)
1346
1348
1347 def helptopic(name):
1349 def helptopic(name):
1348 v = None
1350 v = None
1349 for i in help.helptable:
1351 for i in help.helptable:
1350 l = i.split('|')
1352 l = i.split('|')
1351 if name in l:
1353 if name in l:
1352 v = i
1354 v = i
1353 header = l[-1]
1355 header = l[-1]
1354 if not v:
1356 if not v:
1355 raise UnknownCommand(name)
1357 raise UnknownCommand(name)
1356
1358
1357 # description
1359 # description
1358 doc = help.helptable[v]
1360 doc = help.helptable[v]
1359 if not doc:
1361 if not doc:
1360 doc = _("(No help text available)")
1362 doc = _("(No help text available)")
1361 if callable(doc):
1363 if callable(doc):
1362 doc = doc()
1364 doc = doc()
1363
1365
1364 ui.write("%s\n" % header)
1366 ui.write("%s\n" % header)
1365 ui.write("%s\n" % doc.rstrip())
1367 ui.write("%s\n" % doc.rstrip())
1366
1368
1367 def helpext(name):
1369 def helpext(name):
1368 try:
1370 try:
1369 mod = findext(name)
1371 mod = findext(name)
1370 except KeyError:
1372 except KeyError:
1371 raise UnknownCommand(name)
1373 raise UnknownCommand(name)
1372
1374
1373 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1375 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1374 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1376 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1375 for d in doc[1:]:
1377 for d in doc[1:]:
1376 ui.write(d, '\n')
1378 ui.write(d, '\n')
1377
1379
1378 ui.status('\n')
1380 ui.status('\n')
1379
1381
1380 try:
1382 try:
1381 ct = mod.cmdtable
1383 ct = mod.cmdtable
1382 except AttributeError:
1384 except AttributeError:
1383 ui.status(_('no commands defined\n'))
1385 ui.status(_('no commands defined\n'))
1384 return
1386 return
1385
1387
1386 ui.status(_('list of commands:\n\n'))
1388 ui.status(_('list of commands:\n\n'))
1387 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1389 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1388 helplist(modcmds.has_key)
1390 helplist(modcmds.has_key)
1389
1391
1390 if name and name != 'shortlist':
1392 if name and name != 'shortlist':
1391 i = None
1393 i = None
1392 for f in (helpcmd, helptopic, helpext):
1394 for f in (helpcmd, helptopic, helpext):
1393 try:
1395 try:
1394 f(name)
1396 f(name)
1395 i = None
1397 i = None
1396 break
1398 break
1397 except UnknownCommand, inst:
1399 except UnknownCommand, inst:
1398 i = inst
1400 i = inst
1399 if i:
1401 if i:
1400 raise i
1402 raise i
1401
1403
1402 else:
1404 else:
1403 # program name
1405 # program name
1404 if ui.verbose or with_version:
1406 if ui.verbose or with_version:
1405 version_(ui)
1407 version_(ui)
1406 else:
1408 else:
1407 ui.status(_("Mercurial Distributed SCM\n"))
1409 ui.status(_("Mercurial Distributed SCM\n"))
1408 ui.status('\n')
1410 ui.status('\n')
1409
1411
1410 # list of commands
1412 # list of commands
1411 if name == "shortlist":
1413 if name == "shortlist":
1412 ui.status(_('basic commands:\n\n'))
1414 ui.status(_('basic commands:\n\n'))
1413 else:
1415 else:
1414 ui.status(_('list of commands:\n\n'))
1416 ui.status(_('list of commands:\n\n'))
1415
1417
1416 helplist()
1418 helplist()
1417
1419
1418 # list all option lists
1420 # list all option lists
1419 opt_output = []
1421 opt_output = []
1420 for title, options in option_lists:
1422 for title, options in option_lists:
1421 opt_output.append(("\n%s" % title, None))
1423 opt_output.append(("\n%s" % title, None))
1422 for shortopt, longopt, default, desc in options:
1424 for shortopt, longopt, default, desc in options:
1423 if "DEPRECATED" in desc and not ui.verbose: continue
1425 if "DEPRECATED" in desc and not ui.verbose: continue
1424 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1426 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1425 longopt and " --%s" % longopt),
1427 longopt and " --%s" % longopt),
1426 "%s%s" % (desc,
1428 "%s%s" % (desc,
1427 default
1429 default
1428 and _(" (default: %s)") % default
1430 and _(" (default: %s)") % default
1429 or "")))
1431 or "")))
1430
1432
1431 if opt_output:
1433 if opt_output:
1432 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1434 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1433 for first, second in opt_output:
1435 for first, second in opt_output:
1434 if second:
1436 if second:
1435 ui.write(" %-*s %s\n" % (opts_len, first, second))
1437 ui.write(" %-*s %s\n" % (opts_len, first, second))
1436 else:
1438 else:
1437 ui.write("%s\n" % first)
1439 ui.write("%s\n" % first)
1438
1440
1439 def identify(ui, repo):
1441 def identify(ui, repo):
1440 """print information about the working copy
1442 """print information about the working copy
1441
1443
1442 Print a short summary of the current state of the repo.
1444 Print a short summary of the current state of the repo.
1443
1445
1444 This summary identifies the repository state using one or two parent
1446 This summary identifies the repository state using one or two parent
1445 hash identifiers, followed by a "+" if there are uncommitted changes
1447 hash identifiers, followed by a "+" if there are uncommitted changes
1446 in the working directory, followed by a list of tags for this revision.
1448 in the working directory, followed by a list of tags for this revision.
1447 """
1449 """
1448 parents = [p for p in repo.dirstate.parents() if p != nullid]
1450 parents = [p for p in repo.dirstate.parents() if p != nullid]
1449 if not parents:
1451 if not parents:
1450 ui.write(_("unknown\n"))
1452 ui.write(_("unknown\n"))
1451 return
1453 return
1452
1454
1453 hexfunc = ui.debugflag and hex or short
1455 hexfunc = ui.debugflag and hex or short
1454 modified, added, removed, deleted = repo.status()[:4]
1456 modified, added, removed, deleted = repo.status()[:4]
1455 output = ["%s%s" %
1457 output = ["%s%s" %
1456 ('+'.join([hexfunc(parent) for parent in parents]),
1458 ('+'.join([hexfunc(parent) for parent in parents]),
1457 (modified or added or removed or deleted) and "+" or "")]
1459 (modified or added or removed or deleted) and "+" or "")]
1458
1460
1459 if not ui.quiet:
1461 if not ui.quiet:
1460
1462
1461 branch = util.tolocal(repo.workingctx().branch())
1463 branch = util.tolocal(repo.workingctx().branch())
1462 if branch != 'default':
1464 if branch != 'default':
1463 output.append("(%s)" % branch)
1465 output.append("(%s)" % branch)
1464
1466
1465 # multiple tags for a single parent separated by '/'
1467 # multiple tags for a single parent separated by '/'
1466 parenttags = ['/'.join(tags)
1468 parenttags = ['/'.join(tags)
1467 for tags in map(repo.nodetags, parents) if tags]
1469 for tags in map(repo.nodetags, parents) if tags]
1468 # tags for multiple parents separated by ' + '
1470 # tags for multiple parents separated by ' + '
1469 if parenttags:
1471 if parenttags:
1470 output.append(' + '.join(parenttags))
1472 output.append(' + '.join(parenttags))
1471
1473
1472 ui.write("%s\n" % ' '.join(output))
1474 ui.write("%s\n" % ' '.join(output))
1473
1475
1474 def import_(ui, repo, patch1, *patches, **opts):
1476 def import_(ui, repo, patch1, *patches, **opts):
1475 """import an ordered set of patches
1477 """import an ordered set of patches
1476
1478
1477 Import a list of patches and commit them individually.
1479 Import a list of patches and commit them individually.
1478
1480
1479 If there are outstanding changes in the working directory, import
1481 If there are outstanding changes in the working directory, import
1480 will abort unless given the -f flag.
1482 will abort unless given the -f flag.
1481
1483
1482 You can import a patch straight from a mail message. Even patches
1484 You can import a patch straight from a mail message. Even patches
1483 as attachments work (body part must be type text/plain or
1485 as attachments work (body part must be type text/plain or
1484 text/x-patch to be used). From and Subject headers of email
1486 text/x-patch to be used). From and Subject headers of email
1485 message are used as default committer and commit message. All
1487 message are used as default committer and commit message. All
1486 text/plain body parts before first diff are added to commit
1488 text/plain body parts before first diff are added to commit
1487 message.
1489 message.
1488
1490
1489 If the imported patch was generated by hg export, user and description
1491 If the imported patch was generated by hg export, user and description
1490 from patch override values from message headers and body. Values
1492 from patch override values from message headers and body. Values
1491 given on command line with -m and -u override these.
1493 given on command line with -m and -u override these.
1492
1494
1493 If --exact is specified, import will set the working directory
1495 If --exact is specified, import will set the working directory
1494 to the parent of each patch before applying it, and will abort
1496 to the parent of each patch before applying it, and will abort
1495 if the resulting changeset has a different ID than the one
1497 if the resulting changeset has a different ID than the one
1496 recorded in the patch. This may happen due to character set
1498 recorded in the patch. This may happen due to character set
1497 problems or other deficiencies in the text patch format.
1499 problems or other deficiencies in the text patch format.
1498
1500
1499 To read a patch from standard input, use patch name "-".
1501 To read a patch from standard input, use patch name "-".
1500 """
1502 """
1501 patches = (patch1,) + patches
1503 patches = (patch1,) + patches
1502
1504
1503 if opts.get('exact') or not opts['force']:
1505 if opts.get('exact') or not opts['force']:
1504 bail_if_changed(repo)
1506 bail_if_changed(repo)
1505
1507
1506 d = opts["base"]
1508 d = opts["base"]
1507 strip = opts["strip"]
1509 strip = opts["strip"]
1508
1510
1509 wlock = repo.wlock()
1511 wlock = repo.wlock()
1510 lock = repo.lock()
1512 lock = repo.lock()
1511
1513
1512 for p in patches:
1514 for p in patches:
1513 pf = os.path.join(d, p)
1515 pf = os.path.join(d, p)
1514
1516
1515 if pf == '-':
1517 if pf == '-':
1516 ui.status(_("applying patch from stdin\n"))
1518 ui.status(_("applying patch from stdin\n"))
1517 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1519 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1518 else:
1520 else:
1519 ui.status(_("applying %s\n") % p)
1521 ui.status(_("applying %s\n") % p)
1520 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
1522 tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
1521
1523
1522 if tmpname is None:
1524 if tmpname is None:
1523 raise util.Abort(_('no diffs found'))
1525 raise util.Abort(_('no diffs found'))
1524
1526
1525 try:
1527 try:
1526 cmdline_message = logmessage(opts)
1528 cmdline_message = logmessage(opts)
1527 if cmdline_message:
1529 if cmdline_message:
1528 # pickup the cmdline msg
1530 # pickup the cmdline msg
1529 message = cmdline_message
1531 message = cmdline_message
1530 elif message:
1532 elif message:
1531 # pickup the patch msg
1533 # pickup the patch msg
1532 message = message.strip()
1534 message = message.strip()
1533 else:
1535 else:
1534 # launch the editor
1536 # launch the editor
1535 message = None
1537 message = None
1536 ui.debug(_('message:\n%s\n') % message)
1538 ui.debug(_('message:\n%s\n') % message)
1537
1539
1538 wp = repo.workingctx().parents()
1540 wp = repo.workingctx().parents()
1539 if opts.get('exact'):
1541 if opts.get('exact'):
1540 if not nodeid or not p1:
1542 if not nodeid or not p1:
1541 raise util.Abort(_('not a mercurial patch'))
1543 raise util.Abort(_('not a mercurial patch'))
1542 p1 = repo.lookup(p1)
1544 p1 = repo.lookup(p1)
1543 p2 = repo.lookup(p2 or hex(nullid))
1545 p2 = repo.lookup(p2 or hex(nullid))
1544
1546
1545 if p1 != wp[0].node():
1547 if p1 != wp[0].node():
1546 hg.clean(repo, p1, wlock=wlock)
1548 hg.clean(repo, p1, wlock=wlock)
1547 repo.dirstate.setparents(p1, p2)
1549 repo.dirstate.setparents(p1, p2)
1548 elif p2:
1550 elif p2:
1549 try:
1551 try:
1550 p1 = repo.lookup(p1)
1552 p1 = repo.lookup(p1)
1551 p2 = repo.lookup(p2)
1553 p2 = repo.lookup(p2)
1552 if p1 == wp[0].node():
1554 if p1 == wp[0].node():
1553 repo.dirstate.setparents(p1, p2)
1555 repo.dirstate.setparents(p1, p2)
1554 except hg.RepoError:
1556 except hg.RepoError:
1555 pass
1557 pass
1556
1558
1557 files = {}
1559 files = {}
1558 try:
1560 try:
1559 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1561 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1560 files=files)
1562 files=files)
1561 finally:
1563 finally:
1562 files = patch.updatedir(ui, repo, files, wlock=wlock)
1564 files = patch.updatedir(ui, repo, files, wlock=wlock)
1563 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1565 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1564 if opts.get('exact'):
1566 if opts.get('exact'):
1565 if hex(n) != nodeid:
1567 if hex(n) != nodeid:
1566 repo.rollback()
1568 repo.rollback()
1567 raise util.Abort(_('patch is damaged or loses information'))
1569 raise util.Abort(_('patch is damaged or loses information'))
1568 finally:
1570 finally:
1569 os.unlink(tmpname)
1571 os.unlink(tmpname)
1570
1572
1571 def incoming(ui, repo, source="default", **opts):
1573 def incoming(ui, repo, source="default", **opts):
1572 """show new changesets found in source
1574 """show new changesets found in source
1573
1575
1574 Show new changesets found in the specified path/URL or the default
1576 Show new changesets found in the specified path/URL or the default
1575 pull location. These are the changesets that would be pulled if a pull
1577 pull location. These are the changesets that would be pulled if a pull
1576 was requested.
1578 was requested.
1577
1579
1578 For remote repository, using --bundle avoids downloading the changesets
1580 For remote repository, using --bundle avoids downloading the changesets
1579 twice if the incoming is followed by a pull.
1581 twice if the incoming is followed by a pull.
1580
1582
1581 See pull for valid source format details.
1583 See pull for valid source format details.
1582 """
1584 """
1583 source = ui.expandpath(source)
1585 source = ui.expandpath(source)
1584 setremoteconfig(ui, opts)
1586 setremoteconfig(ui, opts)
1585
1587
1586 other = hg.repository(ui, source)
1588 other = hg.repository(ui, source)
1587 ui.status(_('comparing with %s\n') % source)
1589 ui.status(_('comparing with %s\n') % source)
1588 incoming = repo.findincoming(other, force=opts["force"])
1590 incoming = repo.findincoming(other, force=opts["force"])
1589 if not incoming:
1591 if not incoming:
1590 try:
1592 try:
1591 os.unlink(opts["bundle"])
1593 os.unlink(opts["bundle"])
1592 except:
1594 except:
1593 pass
1595 pass
1594 ui.status(_("no changes found\n"))
1596 ui.status(_("no changes found\n"))
1595 return 1
1597 return 1
1596
1598
1597 cleanup = None
1599 cleanup = None
1598 try:
1600 try:
1599 fname = opts["bundle"]
1601 fname = opts["bundle"]
1600 if fname or not other.local():
1602 if fname or not other.local():
1601 # create a bundle (uncompressed if other repo is not local)
1603 # create a bundle (uncompressed if other repo is not local)
1602 cg = other.changegroup(incoming, "incoming")
1604 cg = other.changegroup(incoming, "incoming")
1603 bundletype = other.local() and "HG10BZ" or "HG10UN"
1605 bundletype = other.local() and "HG10BZ" or "HG10UN"
1604 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1606 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1605 # keep written bundle?
1607 # keep written bundle?
1606 if opts["bundle"]:
1608 if opts["bundle"]:
1607 cleanup = None
1609 cleanup = None
1608 if not other.local():
1610 if not other.local():
1609 # use the created uncompressed bundlerepo
1611 # use the created uncompressed bundlerepo
1610 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1612 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1611
1613
1612 revs = None
1614 revs = None
1613 if opts['rev']:
1615 if opts['rev']:
1614 revs = [other.lookup(rev) for rev in opts['rev']]
1616 revs = [other.lookup(rev) for rev in opts['rev']]
1615 o = other.changelog.nodesbetween(incoming, revs)[0]
1617 o = other.changelog.nodesbetween(incoming, revs)[0]
1616 if opts['newest_first']:
1618 if opts['newest_first']:
1617 o.reverse()
1619 o.reverse()
1618 displayer = cmdutil.show_changeset(ui, other, opts)
1620 displayer = cmdutil.show_changeset(ui, other, opts)
1619 for n in o:
1621 for n in o:
1620 parents = [p for p in other.changelog.parents(n) if p != nullid]
1622 parents = [p for p in other.changelog.parents(n) if p != nullid]
1621 if opts['no_merges'] and len(parents) == 2:
1623 if opts['no_merges'] and len(parents) == 2:
1622 continue
1624 continue
1623 displayer.show(changenode=n)
1625 displayer.show(changenode=n)
1624 finally:
1626 finally:
1625 if hasattr(other, 'close'):
1627 if hasattr(other, 'close'):
1626 other.close()
1628 other.close()
1627 if cleanup:
1629 if cleanup:
1628 os.unlink(cleanup)
1630 os.unlink(cleanup)
1629
1631
1630 def init(ui, dest=".", **opts):
1632 def init(ui, dest=".", **opts):
1631 """create a new repository in the given directory
1633 """create a new repository in the given directory
1632
1634
1633 Initialize a new repository in the given directory. If the given
1635 Initialize a new repository in the given directory. If the given
1634 directory does not exist, it is created.
1636 directory does not exist, it is created.
1635
1637
1636 If no directory is given, the current directory is used.
1638 If no directory is given, the current directory is used.
1637
1639
1638 It is possible to specify an ssh:// URL as the destination.
1640 It is possible to specify an ssh:// URL as the destination.
1639 Look at the help text for the pull command for important details
1641 Look at the help text for the pull command for important details
1640 about ssh:// URLs.
1642 about ssh:// URLs.
1641 """
1643 """
1642 setremoteconfig(ui, opts)
1644 setremoteconfig(ui, opts)
1643 hg.repository(ui, dest, create=1)
1645 hg.repository(ui, dest, create=1)
1644
1646
1645 def locate(ui, repo, *pats, **opts):
1647 def locate(ui, repo, *pats, **opts):
1646 """locate files matching specific patterns
1648 """locate files matching specific patterns
1647
1649
1648 Print all files under Mercurial control whose names match the
1650 Print all files under Mercurial control whose names match the
1649 given patterns.
1651 given patterns.
1650
1652
1651 This command searches the entire repository by default. To search
1653 This command searches the entire repository by default. To search
1652 just the current directory and its subdirectories, use "--include .".
1654 just the current directory and its subdirectories, use "--include .".
1653
1655
1654 If no patterns are given to match, this command prints all file
1656 If no patterns are given to match, this command prints all file
1655 names.
1657 names.
1656
1658
1657 If you want to feed the output of this command into the "xargs"
1659 If you want to feed the output of this command into the "xargs"
1658 command, use the "-0" option to both this command and "xargs".
1660 command, use the "-0" option to both this command and "xargs".
1659 This will avoid the problem of "xargs" treating single filenames
1661 This will avoid the problem of "xargs" treating single filenames
1660 that contain white space as multiple filenames.
1662 that contain white space as multiple filenames.
1661 """
1663 """
1662 end = opts['print0'] and '\0' or '\n'
1664 end = opts['print0'] and '\0' or '\n'
1663 rev = opts['rev']
1665 rev = opts['rev']
1664 if rev:
1666 if rev:
1665 node = repo.lookup(rev)
1667 node = repo.lookup(rev)
1666 else:
1668 else:
1667 node = None
1669 node = None
1668
1670
1669 ret = 1
1671 ret = 1
1670 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1672 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1671 badmatch=util.always,
1673 badmatch=util.always,
1672 default='relglob'):
1674 default='relglob'):
1673 if src == 'b':
1675 if src == 'b':
1674 continue
1676 continue
1675 if not node and repo.dirstate.state(abs) == '?':
1677 if not node and repo.dirstate.state(abs) == '?':
1676 continue
1678 continue
1677 if opts['fullpath']:
1679 if opts['fullpath']:
1678 ui.write(os.path.join(repo.root, abs), end)
1680 ui.write(os.path.join(repo.root, abs), end)
1679 else:
1681 else:
1680 ui.write(((pats and rel) or abs), end)
1682 ui.write(((pats and rel) or abs), end)
1681 ret = 0
1683 ret = 0
1682
1684
1683 return ret
1685 return ret
1684
1686
1685 def log(ui, repo, *pats, **opts):
1687 def log(ui, repo, *pats, **opts):
1686 """show revision history of entire repository or files
1688 """show revision history of entire repository or files
1687
1689
1688 Print the revision history of the specified files or the entire
1690 Print the revision history of the specified files or the entire
1689 project.
1691 project.
1690
1692
1691 File history is shown without following rename or copy history of
1693 File history is shown without following rename or copy history of
1692 files. Use -f/--follow with a file name to follow history across
1694 files. Use -f/--follow with a file name to follow history across
1693 renames and copies. --follow without a file name will only show
1695 renames and copies. --follow without a file name will only show
1694 ancestors or descendants of the starting revision. --follow-first
1696 ancestors or descendants of the starting revision. --follow-first
1695 only follows the first parent of merge revisions.
1697 only follows the first parent of merge revisions.
1696
1698
1697 If no revision range is specified, the default is tip:0 unless
1699 If no revision range is specified, the default is tip:0 unless
1698 --follow is set, in which case the working directory parent is
1700 --follow is set, in which case the working directory parent is
1699 used as the starting revision.
1701 used as the starting revision.
1700
1702
1701 By default this command outputs: changeset id and hash, tags,
1703 By default this command outputs: changeset id and hash, tags,
1702 non-trivial parents, user, date and time, and a summary for each
1704 non-trivial parents, user, date and time, and a summary for each
1703 commit. When the -v/--verbose switch is used, the list of changed
1705 commit. When the -v/--verbose switch is used, the list of changed
1704 files and full commit message is shown.
1706 files and full commit message is shown.
1705
1707
1706 NOTE: log -p may generate unexpected diff output for merge
1708 NOTE: log -p may generate unexpected diff output for merge
1707 changesets, as it will compare the merge changeset against its
1709 changesets, as it will compare the merge changeset against its
1708 first parent only. Also, the files: list will only reflect files
1710 first parent only. Also, the files: list will only reflect files
1709 that are different from BOTH parents.
1711 that are different from BOTH parents.
1710
1712
1711 """
1713 """
1712
1714
1713 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1715 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1714 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1716 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1715
1717
1716 if opts['limit']:
1718 if opts['limit']:
1717 try:
1719 try:
1718 limit = int(opts['limit'])
1720 limit = int(opts['limit'])
1719 except ValueError:
1721 except ValueError:
1720 raise util.Abort(_('limit must be a positive integer'))
1722 raise util.Abort(_('limit must be a positive integer'))
1721 if limit <= 0: raise util.Abort(_('limit must be positive'))
1723 if limit <= 0: raise util.Abort(_('limit must be positive'))
1722 else:
1724 else:
1723 limit = sys.maxint
1725 limit = sys.maxint
1724 count = 0
1726 count = 0
1725
1727
1726 if opts['copies'] and opts['rev']:
1728 if opts['copies'] and opts['rev']:
1727 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1729 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1728 else:
1730 else:
1729 endrev = repo.changelog.count()
1731 endrev = repo.changelog.count()
1730 rcache = {}
1732 rcache = {}
1731 ncache = {}
1733 ncache = {}
1732 dcache = []
1734 dcache = []
1733 def getrenamed(fn, rev, man):
1735 def getrenamed(fn, rev, man):
1734 '''looks up all renames for a file (up to endrev) the first
1736 '''looks up all renames for a file (up to endrev) the first
1735 time the file is given. It indexes on the changerev and only
1737 time the file is given. It indexes on the changerev and only
1736 parses the manifest if linkrev != changerev.
1738 parses the manifest if linkrev != changerev.
1737 Returns rename info for fn at changerev rev.'''
1739 Returns rename info for fn at changerev rev.'''
1738 if fn not in rcache:
1740 if fn not in rcache:
1739 rcache[fn] = {}
1741 rcache[fn] = {}
1740 ncache[fn] = {}
1742 ncache[fn] = {}
1741 fl = repo.file(fn)
1743 fl = repo.file(fn)
1742 for i in xrange(fl.count()):
1744 for i in xrange(fl.count()):
1743 node = fl.node(i)
1745 node = fl.node(i)
1744 lr = fl.linkrev(node)
1746 lr = fl.linkrev(node)
1745 renamed = fl.renamed(node)
1747 renamed = fl.renamed(node)
1746 rcache[fn][lr] = renamed
1748 rcache[fn][lr] = renamed
1747 if renamed:
1749 if renamed:
1748 ncache[fn][node] = renamed
1750 ncache[fn][node] = renamed
1749 if lr >= endrev:
1751 if lr >= endrev:
1750 break
1752 break
1751 if rev in rcache[fn]:
1753 if rev in rcache[fn]:
1752 return rcache[fn][rev]
1754 return rcache[fn][rev]
1753 mr = repo.manifest.rev(man)
1755 mr = repo.manifest.rev(man)
1754 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1756 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1755 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1757 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1756 if not dcache or dcache[0] != man:
1758 if not dcache or dcache[0] != man:
1757 dcache[:] = [man, repo.manifest.readdelta(man)]
1759 dcache[:] = [man, repo.manifest.readdelta(man)]
1758 if fn in dcache[1]:
1760 if fn in dcache[1]:
1759 return ncache[fn].get(dcache[1][fn])
1761 return ncache[fn].get(dcache[1][fn])
1760 return None
1762 return None
1761
1763
1762 df = False
1764 df = False
1763 if opts["date"]:
1765 if opts["date"]:
1764 df = util.matchdate(opts["date"])
1766 df = util.matchdate(opts["date"])
1765
1767
1766 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1768 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1767 for st, rev, fns in changeiter:
1769 for st, rev, fns in changeiter:
1768 if st == 'add':
1770 if st == 'add':
1769 changenode = repo.changelog.node(rev)
1771 changenode = repo.changelog.node(rev)
1770 parents = [p for p in repo.changelog.parentrevs(rev)
1772 parents = [p for p in repo.changelog.parentrevs(rev)
1771 if p != nullrev]
1773 if p != nullrev]
1772 if opts['no_merges'] and len(parents) == 2:
1774 if opts['no_merges'] and len(parents) == 2:
1773 continue
1775 continue
1774 if opts['only_merges'] and len(parents) != 2:
1776 if opts['only_merges'] and len(parents) != 2:
1775 continue
1777 continue
1776
1778
1777 if df:
1779 if df:
1778 changes = get(rev)
1780 changes = get(rev)
1779 if not df(changes[2][0]):
1781 if not df(changes[2][0]):
1780 continue
1782 continue
1781
1783
1782 if opts['keyword']:
1784 if opts['keyword']:
1783 changes = get(rev)
1785 changes = get(rev)
1784 miss = 0
1786 miss = 0
1785 for k in [kw.lower() for kw in opts['keyword']]:
1787 for k in [kw.lower() for kw in opts['keyword']]:
1786 if not (k in changes[1].lower() or
1788 if not (k in changes[1].lower() or
1787 k in changes[4].lower() or
1789 k in changes[4].lower() or
1788 k in " ".join(changes[3]).lower()):
1790 k in " ".join(changes[3]).lower()):
1789 miss = 1
1791 miss = 1
1790 break
1792 break
1791 if miss:
1793 if miss:
1792 continue
1794 continue
1793
1795
1794 copies = []
1796 copies = []
1795 if opts.get('copies') and rev:
1797 if opts.get('copies') and rev:
1796 mf = get(rev)[0]
1798 mf = get(rev)[0]
1797 for fn in get(rev)[3]:
1799 for fn in get(rev)[3]:
1798 rename = getrenamed(fn, rev, mf)
1800 rename = getrenamed(fn, rev, mf)
1799 if rename:
1801 if rename:
1800 copies.append((fn, rename[0]))
1802 copies.append((fn, rename[0]))
1801 displayer.show(rev, changenode, copies=copies)
1803 displayer.show(rev, changenode, copies=copies)
1802 elif st == 'iter':
1804 elif st == 'iter':
1803 if count == limit: break
1805 if count == limit: break
1804 if displayer.flush(rev):
1806 if displayer.flush(rev):
1805 count += 1
1807 count += 1
1806
1808
1807 def manifest(ui, repo, rev=None):
1809 def manifest(ui, repo, rev=None):
1808 """output the current or given revision of the project manifest
1810 """output the current or given revision of the project manifest
1809
1811
1810 Print a list of version controlled files for the given revision.
1812 Print a list of version controlled files for the given revision.
1811 If no revision is given, the parent of the working directory is used,
1813 If no revision is given, the parent of the working directory is used,
1812 or tip if no revision is checked out.
1814 or tip if no revision is checked out.
1813
1815
1814 The manifest is the list of files being version controlled. If no revision
1816 The manifest is the list of files being version controlled. If no revision
1815 is given then the first parent of the working directory is used.
1817 is given then the first parent of the working directory is used.
1816
1818
1817 With -v flag, print file permissions. With --debug flag, print
1819 With -v flag, print file permissions. With --debug flag, print
1818 file revision hashes.
1820 file revision hashes.
1819 """
1821 """
1820
1822
1821 m = repo.changectx(rev).manifest()
1823 m = repo.changectx(rev).manifest()
1822 files = m.keys()
1824 files = m.keys()
1823 files.sort()
1825 files.sort()
1824
1826
1825 for f in files:
1827 for f in files:
1826 if ui.debugflag:
1828 if ui.debugflag:
1827 ui.write("%40s " % hex(m[f]))
1829 ui.write("%40s " % hex(m[f]))
1828 if ui.verbose:
1830 if ui.verbose:
1829 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1831 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1830 ui.write("%s\n" % f)
1832 ui.write("%s\n" % f)
1831
1833
1832 def merge(ui, repo, node=None, force=None):
1834 def merge(ui, repo, node=None, force=None):
1833 """merge working directory with another revision
1835 """merge working directory with another revision
1834
1836
1835 Merge the contents of the current working directory and the
1837 Merge the contents of the current working directory and the
1836 requested revision. Files that changed between either parent are
1838 requested revision. Files that changed between either parent are
1837 marked as changed for the next commit and a commit must be
1839 marked as changed for the next commit and a commit must be
1838 performed before any further updates are allowed.
1840 performed before any further updates are allowed.
1839
1841
1840 If no revision is specified, the working directory's parent is a
1842 If no revision is specified, the working directory's parent is a
1841 head revision, and the repository contains exactly one other head,
1843 head revision, and the repository contains exactly one other head,
1842 the other head is merged with by default. Otherwise, an explicit
1844 the other head is merged with by default. Otherwise, an explicit
1843 revision to merge with must be provided.
1845 revision to merge with must be provided.
1844 """
1846 """
1845
1847
1846 if not node:
1848 if not node:
1847 heads = repo.heads()
1849 heads = repo.heads()
1848 if len(heads) > 2:
1850 if len(heads) > 2:
1849 raise util.Abort(_('repo has %d heads - '
1851 raise util.Abort(_('repo has %d heads - '
1850 'please merge with an explicit rev') %
1852 'please merge with an explicit rev') %
1851 len(heads))
1853 len(heads))
1852 if len(heads) == 1:
1854 if len(heads) == 1:
1853 raise util.Abort(_('there is nothing to merge - '
1855 raise util.Abort(_('there is nothing to merge - '
1854 'use "hg update" instead'))
1856 'use "hg update" instead'))
1855 parent = repo.dirstate.parents()[0]
1857 parent = repo.dirstate.parents()[0]
1856 if parent not in heads:
1858 if parent not in heads:
1857 raise util.Abort(_('working dir not at a head rev - '
1859 raise util.Abort(_('working dir not at a head rev - '
1858 'use "hg update" or merge with an explicit rev'))
1860 'use "hg update" or merge with an explicit rev'))
1859 node = parent == heads[0] and heads[-1] or heads[0]
1861 node = parent == heads[0] and heads[-1] or heads[0]
1860 return hg.merge(repo, node, force=force)
1862 return hg.merge(repo, node, force=force)
1861
1863
1862 def outgoing(ui, repo, dest=None, **opts):
1864 def outgoing(ui, repo, dest=None, **opts):
1863 """show changesets not found in destination
1865 """show changesets not found in destination
1864
1866
1865 Show changesets not found in the specified destination repository or
1867 Show changesets not found in the specified destination repository or
1866 the default push location. These are the changesets that would be pushed
1868 the default push location. These are the changesets that would be pushed
1867 if a push was requested.
1869 if a push was requested.
1868
1870
1869 See pull for valid destination format details.
1871 See pull for valid destination format details.
1870 """
1872 """
1871 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1873 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1872 setremoteconfig(ui, opts)
1874 setremoteconfig(ui, opts)
1873 revs = None
1875 revs = None
1874 if opts['rev']:
1876 if opts['rev']:
1875 revs = [repo.lookup(rev) for rev in opts['rev']]
1877 revs = [repo.lookup(rev) for rev in opts['rev']]
1876
1878
1877 other = hg.repository(ui, dest)
1879 other = hg.repository(ui, dest)
1878 ui.status(_('comparing with %s\n') % dest)
1880 ui.status(_('comparing with %s\n') % dest)
1879 o = repo.findoutgoing(other, force=opts['force'])
1881 o = repo.findoutgoing(other, force=opts['force'])
1880 if not o:
1882 if not o:
1881 ui.status(_("no changes found\n"))
1883 ui.status(_("no changes found\n"))
1882 return 1
1884 return 1
1883 o = repo.changelog.nodesbetween(o, revs)[0]
1885 o = repo.changelog.nodesbetween(o, revs)[0]
1884 if opts['newest_first']:
1886 if opts['newest_first']:
1885 o.reverse()
1887 o.reverse()
1886 displayer = cmdutil.show_changeset(ui, repo, opts)
1888 displayer = cmdutil.show_changeset(ui, repo, opts)
1887 for n in o:
1889 for n in o:
1888 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1890 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1889 if opts['no_merges'] and len(parents) == 2:
1891 if opts['no_merges'] and len(parents) == 2:
1890 continue
1892 continue
1891 displayer.show(changenode=n)
1893 displayer.show(changenode=n)
1892
1894
1893 def parents(ui, repo, file_=None, **opts):
1895 def parents(ui, repo, file_=None, **opts):
1894 """show the parents of the working dir or revision
1896 """show the parents of the working dir or revision
1895
1897
1896 Print the working directory's parent revisions.
1898 Print the working directory's parent revisions.
1897 """
1899 """
1898 rev = opts.get('rev')
1900 rev = opts.get('rev')
1899 if rev:
1901 if rev:
1900 if file_:
1902 if file_:
1901 ctx = repo.filectx(file_, changeid=rev)
1903 ctx = repo.filectx(file_, changeid=rev)
1902 else:
1904 else:
1903 ctx = repo.changectx(rev)
1905 ctx = repo.changectx(rev)
1904 p = [cp.node() for cp in ctx.parents()]
1906 p = [cp.node() for cp in ctx.parents()]
1905 else:
1907 else:
1906 p = repo.dirstate.parents()
1908 p = repo.dirstate.parents()
1907
1909
1908 displayer = cmdutil.show_changeset(ui, repo, opts)
1910 displayer = cmdutil.show_changeset(ui, repo, opts)
1909 for n in p:
1911 for n in p:
1910 if n != nullid:
1912 if n != nullid:
1911 displayer.show(changenode=n)
1913 displayer.show(changenode=n)
1912
1914
1913 def paths(ui, repo, search=None):
1915 def paths(ui, repo, search=None):
1914 """show definition of symbolic path names
1916 """show definition of symbolic path names
1915
1917
1916 Show definition of symbolic path name NAME. If no name is given, show
1918 Show definition of symbolic path name NAME. If no name is given, show
1917 definition of available names.
1919 definition of available names.
1918
1920
1919 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1921 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1920 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1922 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1921 """
1923 """
1922 if search:
1924 if search:
1923 for name, path in ui.configitems("paths"):
1925 for name, path in ui.configitems("paths"):
1924 if name == search:
1926 if name == search:
1925 ui.write("%s\n" % path)
1927 ui.write("%s\n" % path)
1926 return
1928 return
1927 ui.warn(_("not found!\n"))
1929 ui.warn(_("not found!\n"))
1928 return 1
1930 return 1
1929 else:
1931 else:
1930 for name, path in ui.configitems("paths"):
1932 for name, path in ui.configitems("paths"):
1931 ui.write("%s = %s\n" % (name, path))
1933 ui.write("%s = %s\n" % (name, path))
1932
1934
1933 def postincoming(ui, repo, modheads, optupdate):
1935 def postincoming(ui, repo, modheads, optupdate):
1934 if modheads == 0:
1936 if modheads == 0:
1935 return
1937 return
1936 if optupdate:
1938 if optupdate:
1937 if modheads == 1:
1939 if modheads == 1:
1938 return hg.update(repo, repo.changelog.tip()) # update
1940 return hg.update(repo, repo.changelog.tip()) # update
1939 else:
1941 else:
1940 ui.status(_("not updating, since new heads added\n"))
1942 ui.status(_("not updating, since new heads added\n"))
1941 if modheads > 1:
1943 if modheads > 1:
1942 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1944 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1943 else:
1945 else:
1944 ui.status(_("(run 'hg update' to get a working copy)\n"))
1946 ui.status(_("(run 'hg update' to get a working copy)\n"))
1945
1947
1946 def pull(ui, repo, source="default", **opts):
1948 def pull(ui, repo, source="default", **opts):
1947 """pull changes from the specified source
1949 """pull changes from the specified source
1948
1950
1949 Pull changes from a remote repository to a local one.
1951 Pull changes from a remote repository to a local one.
1950
1952
1951 This finds all changes from the repository at the specified path
1953 This finds all changes from the repository at the specified path
1952 or URL and adds them to the local repository. By default, this
1954 or URL and adds them to the local repository. By default, this
1953 does not update the copy of the project in the working directory.
1955 does not update the copy of the project in the working directory.
1954
1956
1955 Valid URLs are of the form:
1957 Valid URLs are of the form:
1956
1958
1957 local/filesystem/path (or file://local/filesystem/path)
1959 local/filesystem/path (or file://local/filesystem/path)
1958 http://[user@]host[:port]/[path]
1960 http://[user@]host[:port]/[path]
1959 https://[user@]host[:port]/[path]
1961 https://[user@]host[:port]/[path]
1960 ssh://[user@]host[:port]/[path]
1962 ssh://[user@]host[:port]/[path]
1961 static-http://host[:port]/[path]
1963 static-http://host[:port]/[path]
1962
1964
1963 Paths in the local filesystem can either point to Mercurial
1965 Paths in the local filesystem can either point to Mercurial
1964 repositories or to bundle files (as created by 'hg bundle' or
1966 repositories or to bundle files (as created by 'hg bundle' or
1965 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1967 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1966 allows access to a Mercurial repository where you simply use a web
1968 allows access to a Mercurial repository where you simply use a web
1967 server to publish the .hg directory as static content.
1969 server to publish the .hg directory as static content.
1968
1970
1969 Some notes about using SSH with Mercurial:
1971 Some notes about using SSH with Mercurial:
1970 - SSH requires an accessible shell account on the destination machine
1972 - SSH requires an accessible shell account on the destination machine
1971 and a copy of hg in the remote path or specified with as remotecmd.
1973 and a copy of hg in the remote path or specified with as remotecmd.
1972 - path is relative to the remote user's home directory by default.
1974 - path is relative to the remote user's home directory by default.
1973 Use an extra slash at the start of a path to specify an absolute path:
1975 Use an extra slash at the start of a path to specify an absolute path:
1974 ssh://example.com//tmp/repository
1976 ssh://example.com//tmp/repository
1975 - Mercurial doesn't use its own compression via SSH; the right thing
1977 - Mercurial doesn't use its own compression via SSH; the right thing
1976 to do is to configure it in your ~/.ssh/config, e.g.:
1978 to do is to configure it in your ~/.ssh/config, e.g.:
1977 Host *.mylocalnetwork.example.com
1979 Host *.mylocalnetwork.example.com
1978 Compression no
1980 Compression no
1979 Host *
1981 Host *
1980 Compression yes
1982 Compression yes
1981 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1983 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1982 with the --ssh command line option.
1984 with the --ssh command line option.
1983 """
1985 """
1984 source = ui.expandpath(source)
1986 source = ui.expandpath(source)
1985 setremoteconfig(ui, opts)
1987 setremoteconfig(ui, opts)
1986
1988
1987 other = hg.repository(ui, source)
1989 other = hg.repository(ui, source)
1988 ui.status(_('pulling from %s\n') % (source))
1990 ui.status(_('pulling from %s\n') % (source))
1989 revs = None
1991 revs = None
1990 if opts['rev']:
1992 if opts['rev']:
1991 if 'lookup' in other.capabilities:
1993 if 'lookup' in other.capabilities:
1992 revs = [other.lookup(rev) for rev in opts['rev']]
1994 revs = [other.lookup(rev) for rev in opts['rev']]
1993 else:
1995 else:
1994 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1996 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1995 raise util.Abort(error)
1997 raise util.Abort(error)
1996 modheads = repo.pull(other, heads=revs, force=opts['force'])
1998 modheads = repo.pull(other, heads=revs, force=opts['force'])
1997 return postincoming(ui, repo, modheads, opts['update'])
1999 return postincoming(ui, repo, modheads, opts['update'])
1998
2000
1999 def push(ui, repo, dest=None, **opts):
2001 def push(ui, repo, dest=None, **opts):
2000 """push changes to the specified destination
2002 """push changes to the specified destination
2001
2003
2002 Push changes from the local repository to the given destination.
2004 Push changes from the local repository to the given destination.
2003
2005
2004 This is the symmetrical operation for pull. It helps to move
2006 This is the symmetrical operation for pull. It helps to move
2005 changes from the current repository to a different one. If the
2007 changes from the current repository to a different one. If the
2006 destination is local this is identical to a pull in that directory
2008 destination is local this is identical to a pull in that directory
2007 from the current one.
2009 from the current one.
2008
2010
2009 By default, push will refuse to run if it detects the result would
2011 By default, push will refuse to run if it detects the result would
2010 increase the number of remote heads. This generally indicates the
2012 increase the number of remote heads. This generally indicates the
2011 the client has forgotten to sync and merge before pushing.
2013 the client has forgotten to sync and merge before pushing.
2012
2014
2013 Valid URLs are of the form:
2015 Valid URLs are of the form:
2014
2016
2015 local/filesystem/path (or file://local/filesystem/path)
2017 local/filesystem/path (or file://local/filesystem/path)
2016 ssh://[user@]host[:port]/[path]
2018 ssh://[user@]host[:port]/[path]
2017 http://[user@]host[:port]/[path]
2019 http://[user@]host[:port]/[path]
2018 https://[user@]host[:port]/[path]
2020 https://[user@]host[:port]/[path]
2019
2021
2020 Look at the help text for the pull command for important details
2022 Look at the help text for the pull command for important details
2021 about ssh:// URLs.
2023 about ssh:// URLs.
2022
2024
2023 Pushing to http:// and https:// URLs is only possible, if this
2025 Pushing to http:// and https:// URLs is only possible, if this
2024 feature is explicitly enabled on the remote Mercurial server.
2026 feature is explicitly enabled on the remote Mercurial server.
2025 """
2027 """
2026 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2028 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2027 setremoteconfig(ui, opts)
2029 setremoteconfig(ui, opts)
2028
2030
2029 other = hg.repository(ui, dest)
2031 other = hg.repository(ui, dest)
2030 ui.status('pushing to %s\n' % (dest))
2032 ui.status('pushing to %s\n' % (dest))
2031 revs = None
2033 revs = None
2032 if opts['rev']:
2034 if opts['rev']:
2033 revs = [repo.lookup(rev) for rev in opts['rev']]
2035 revs = [repo.lookup(rev) for rev in opts['rev']]
2034 r = repo.push(other, opts['force'], revs=revs)
2036 r = repo.push(other, opts['force'], revs=revs)
2035 return r == 0
2037 return r == 0
2036
2038
2037 def rawcommit(ui, repo, *pats, **opts):
2039 def rawcommit(ui, repo, *pats, **opts):
2038 """raw commit interface (DEPRECATED)
2040 """raw commit interface (DEPRECATED)
2039
2041
2040 (DEPRECATED)
2042 (DEPRECATED)
2041 Lowlevel commit, for use in helper scripts.
2043 Lowlevel commit, for use in helper scripts.
2042
2044
2043 This command is not intended to be used by normal users, as it is
2045 This command is not intended to be used by normal users, as it is
2044 primarily useful for importing from other SCMs.
2046 primarily useful for importing from other SCMs.
2045
2047
2046 This command is now deprecated and will be removed in a future
2048 This command is now deprecated and will be removed in a future
2047 release, please use debugsetparents and commit instead.
2049 release, please use debugsetparents and commit instead.
2048 """
2050 """
2049
2051
2050 ui.warn(_("(the rawcommit command is deprecated)\n"))
2052 ui.warn(_("(the rawcommit command is deprecated)\n"))
2051
2053
2052 message = logmessage(opts)
2054 message = logmessage(opts)
2053
2055
2054 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2056 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2055 if opts['files']:
2057 if opts['files']:
2056 files += open(opts['files']).read().splitlines()
2058 files += open(opts['files']).read().splitlines()
2057
2059
2058 parents = [repo.lookup(p) for p in opts['parent']]
2060 parents = [repo.lookup(p) for p in opts['parent']]
2059
2061
2060 try:
2062 try:
2061 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2063 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2062 except ValueError, inst:
2064 except ValueError, inst:
2063 raise util.Abort(str(inst))
2065 raise util.Abort(str(inst))
2064
2066
2065 def recover(ui, repo):
2067 def recover(ui, repo):
2066 """roll back an interrupted transaction
2068 """roll back an interrupted transaction
2067
2069
2068 Recover from an interrupted commit or pull.
2070 Recover from an interrupted commit or pull.
2069
2071
2070 This command tries to fix the repository status after an interrupted
2072 This command tries to fix the repository status after an interrupted
2071 operation. It should only be necessary when Mercurial suggests it.
2073 operation. It should only be necessary when Mercurial suggests it.
2072 """
2074 """
2073 if repo.recover():
2075 if repo.recover():
2074 return hg.verify(repo)
2076 return hg.verify(repo)
2075 return 1
2077 return 1
2076
2078
2077 def remove(ui, repo, *pats, **opts):
2079 def remove(ui, repo, *pats, **opts):
2078 """remove the specified files on the next commit
2080 """remove the specified files on the next commit
2079
2081
2080 Schedule the indicated files for removal from the repository.
2082 Schedule the indicated files for removal from the repository.
2081
2083
2082 This only removes files from the current branch, not from the
2084 This only removes files from the current branch, not from the
2083 entire project history. If the files still exist in the working
2085 entire project history. If the files still exist in the working
2084 directory, they will be deleted from it. If invoked with --after,
2086 directory, they will be deleted from it. If invoked with --after,
2085 files are marked as removed, but not actually unlinked unless --force
2087 files are marked as removed, but not actually unlinked unless --force
2086 is also given. Without exact file names, --after will only mark
2088 is also given. Without exact file names, --after will only mark
2087 files as removed if they are no longer in the working directory.
2089 files as removed if they are no longer in the working directory.
2088
2090
2089 This command schedules the files to be removed at the next commit.
2091 This command schedules the files to be removed at the next commit.
2090 To undo a remove before that, see hg revert.
2092 To undo a remove before that, see hg revert.
2091
2093
2092 Modified files and added files are not removed by default. To
2094 Modified files and added files are not removed by default. To
2093 remove them, use the -f/--force option.
2095 remove them, use the -f/--force option.
2094 """
2096 """
2095 names = []
2097 names = []
2096 if not opts['after'] and not pats:
2098 if not opts['after'] and not pats:
2097 raise util.Abort(_('no files specified'))
2099 raise util.Abort(_('no files specified'))
2098 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2100 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2099 exact = dict.fromkeys(files)
2101 exact = dict.fromkeys(files)
2100 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2102 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2101 modified, added, removed, deleted, unknown = mardu
2103 modified, added, removed, deleted, unknown = mardu
2102 remove, forget = [], []
2104 remove, forget = [], []
2103 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2105 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2104 reason = None
2106 reason = None
2105 if abs in modified and not opts['force']:
2107 if abs in modified and not opts['force']:
2106 reason = _('is modified (use -f to force removal)')
2108 reason = _('is modified (use -f to force removal)')
2107 elif abs in added:
2109 elif abs in added:
2108 if opts['force']:
2110 if opts['force']:
2109 forget.append(abs)
2111 forget.append(abs)
2110 continue
2112 continue
2111 reason = _('has been marked for add (use -f to force removal)')
2113 reason = _('has been marked for add (use -f to force removal)')
2112 elif abs in unknown:
2114 elif abs in unknown:
2113 reason = _('is not managed')
2115 reason = _('is not managed')
2114 elif opts['after'] and not exact and abs not in deleted:
2116 elif opts['after'] and not exact and abs not in deleted:
2115 continue
2117 continue
2116 elif abs in removed:
2118 elif abs in removed:
2117 continue
2119 continue
2118 if reason:
2120 if reason:
2119 if exact:
2121 if exact:
2120 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2122 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2121 else:
2123 else:
2122 if ui.verbose or not exact:
2124 if ui.verbose or not exact:
2123 ui.status(_('removing %s\n') % rel)
2125 ui.status(_('removing %s\n') % rel)
2124 remove.append(abs)
2126 remove.append(abs)
2125 repo.forget(forget)
2127 repo.forget(forget)
2126 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2128 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2127
2129
2128 def rename(ui, repo, *pats, **opts):
2130 def rename(ui, repo, *pats, **opts):
2129 """rename files; equivalent of copy + remove
2131 """rename files; equivalent of copy + remove
2130
2132
2131 Mark dest as copies of sources; mark sources for deletion. If
2133 Mark dest as copies of sources; mark sources for deletion. If
2132 dest is a directory, copies are put in that directory. If dest is
2134 dest is a directory, copies are put in that directory. If dest is
2133 a file, there can only be one source.
2135 a file, there can only be one source.
2134
2136
2135 By default, this command copies the contents of files as they
2137 By default, this command copies the contents of files as they
2136 stand in the working directory. If invoked with --after, the
2138 stand in the working directory. If invoked with --after, the
2137 operation is recorded, but no copying is performed.
2139 operation is recorded, but no copying is performed.
2138
2140
2139 This command takes effect in the next commit. To undo a rename
2141 This command takes effect in the next commit. To undo a rename
2140 before that, see hg revert.
2142 before that, see hg revert.
2141 """
2143 """
2142 wlock = repo.wlock(0)
2144 wlock = repo.wlock(0)
2143 errs, copied = docopy(ui, repo, pats, opts, wlock)
2145 errs, copied = docopy(ui, repo, pats, opts, wlock)
2144 names = []
2146 names = []
2145 for abs, rel, exact in copied:
2147 for abs, rel, exact in copied:
2146 if ui.verbose or not exact:
2148 if ui.verbose or not exact:
2147 ui.status(_('removing %s\n') % rel)
2149 ui.status(_('removing %s\n') % rel)
2148 names.append(abs)
2150 names.append(abs)
2149 if not opts.get('dry_run'):
2151 if not opts.get('dry_run'):
2150 repo.remove(names, True, wlock=wlock)
2152 repo.remove(names, True, wlock=wlock)
2151 return errs
2153 return errs
2152
2154
2153 def revert(ui, repo, *pats, **opts):
2155 def revert(ui, repo, *pats, **opts):
2154 """revert files or dirs to their states as of some revision
2156 """revert files or dirs to their states as of some revision
2155
2157
2156 With no revision specified, revert the named files or directories
2158 With no revision specified, revert the named files or directories
2157 to the contents they had in the parent of the working directory.
2159 to the contents they had in the parent of the working directory.
2158 This restores the contents of the affected files to an unmodified
2160 This restores the contents of the affected files to an unmodified
2159 state and unschedules adds, removes, copies, and renames. If the
2161 state and unschedules adds, removes, copies, and renames. If the
2160 working directory has two parents, you must explicitly specify the
2162 working directory has two parents, you must explicitly specify the
2161 revision to revert to.
2163 revision to revert to.
2162
2164
2163 Modified files are saved with a .orig suffix before reverting.
2165 Modified files are saved with a .orig suffix before reverting.
2164 To disable these backups, use --no-backup.
2166 To disable these backups, use --no-backup.
2165
2167
2166 Using the -r option, revert the given files or directories to their
2168 Using the -r option, revert the given files or directories to their
2167 contents as of a specific revision. This can be helpful to "roll
2169 contents as of a specific revision. This can be helpful to "roll
2168 back" some or all of a change that should not have been committed.
2170 back" some or all of a change that should not have been committed.
2169
2171
2170 Revert modifies the working directory. It does not commit any
2172 Revert modifies the working directory. It does not commit any
2171 changes, or change the parent of the working directory. If you
2173 changes, or change the parent of the working directory. If you
2172 revert to a revision other than the parent of the working
2174 revert to a revision other than the parent of the working
2173 directory, the reverted files will thus appear modified
2175 directory, the reverted files will thus appear modified
2174 afterwards.
2176 afterwards.
2175
2177
2176 If a file has been deleted, it is recreated. If the executable
2178 If a file has been deleted, it is recreated. If the executable
2177 mode of a file was changed, it is reset.
2179 mode of a file was changed, it is reset.
2178
2180
2179 If names are given, all files matching the names are reverted.
2181 If names are given, all files matching the names are reverted.
2180
2182
2181 If no arguments are given, no files are reverted.
2183 If no arguments are given, no files are reverted.
2182 """
2184 """
2183
2185
2184 if opts["date"]:
2186 if opts["date"]:
2185 if opts["rev"]:
2187 if opts["rev"]:
2186 raise util.Abort(_("you can't specify a revision and a date"))
2188 raise util.Abort(_("you can't specify a revision and a date"))
2187 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2189 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2188
2190
2189 if not pats and not opts['all']:
2191 if not pats and not opts['all']:
2190 raise util.Abort(_('no files or directories specified; '
2192 raise util.Abort(_('no files or directories specified; '
2191 'use --all to revert the whole repo'))
2193 'use --all to revert the whole repo'))
2192
2194
2193 parent, p2 = repo.dirstate.parents()
2195 parent, p2 = repo.dirstate.parents()
2194 if not opts['rev'] and p2 != nullid:
2196 if not opts['rev'] and p2 != nullid:
2195 raise util.Abort(_('uncommitted merge - please provide a '
2197 raise util.Abort(_('uncommitted merge - please provide a '
2196 'specific revision'))
2198 'specific revision'))
2197 ctx = repo.changectx(opts['rev'])
2199 ctx = repo.changectx(opts['rev'])
2198 node = ctx.node()
2200 node = ctx.node()
2199 mf = ctx.manifest()
2201 mf = ctx.manifest()
2200 if node == parent:
2202 if node == parent:
2201 pmf = mf
2203 pmf = mf
2202 else:
2204 else:
2203 pmf = None
2205 pmf = None
2204
2206
2205 wlock = repo.wlock()
2207 wlock = repo.wlock()
2206
2208
2207 # need all matching names in dirstate and manifest of target rev,
2209 # need all matching names in dirstate and manifest of target rev,
2208 # so have to walk both. do not print errors if files exist in one
2210 # so have to walk both. do not print errors if files exist in one
2209 # but not other.
2211 # but not other.
2210
2212
2211 names = {}
2213 names = {}
2212 target_only = {}
2214 target_only = {}
2213
2215
2214 # walk dirstate.
2216 # walk dirstate.
2215
2217
2216 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2218 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2217 badmatch=mf.has_key):
2219 badmatch=mf.has_key):
2218 names[abs] = (rel, exact)
2220 names[abs] = (rel, exact)
2219 if src == 'b':
2221 if src == 'b':
2220 target_only[abs] = True
2222 target_only[abs] = True
2221
2223
2222 # walk target manifest.
2224 # walk target manifest.
2223
2225
2224 def badmatch(path):
2226 def badmatch(path):
2225 if path in names:
2227 if path in names:
2226 return True
2228 return True
2227 path_ = path + '/'
2229 path_ = path + '/'
2228 for f in names:
2230 for f in names:
2229 if f.startswith(path_):
2231 if f.startswith(path_):
2230 return True
2232 return True
2231 return False
2233 return False
2232
2234
2233 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2235 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2234 badmatch=badmatch):
2236 badmatch=badmatch):
2235 if abs in names or src == 'b':
2237 if abs in names or src == 'b':
2236 continue
2238 continue
2237 names[abs] = (rel, exact)
2239 names[abs] = (rel, exact)
2238 target_only[abs] = True
2240 target_only[abs] = True
2239
2241
2240 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2242 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2241 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2243 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2242
2244
2243 revert = ([], _('reverting %s\n'))
2245 revert = ([], _('reverting %s\n'))
2244 add = ([], _('adding %s\n'))
2246 add = ([], _('adding %s\n'))
2245 remove = ([], _('removing %s\n'))
2247 remove = ([], _('removing %s\n'))
2246 forget = ([], _('forgetting %s\n'))
2248 forget = ([], _('forgetting %s\n'))
2247 undelete = ([], _('undeleting %s\n'))
2249 undelete = ([], _('undeleting %s\n'))
2248 update = {}
2250 update = {}
2249
2251
2250 disptable = (
2252 disptable = (
2251 # dispatch table:
2253 # dispatch table:
2252 # file state
2254 # file state
2253 # action if in target manifest
2255 # action if in target manifest
2254 # action if not in target manifest
2256 # action if not in target manifest
2255 # make backup if in target manifest
2257 # make backup if in target manifest
2256 # make backup if not in target manifest
2258 # make backup if not in target manifest
2257 (modified, revert, remove, True, True),
2259 (modified, revert, remove, True, True),
2258 (added, revert, forget, True, False),
2260 (added, revert, forget, True, False),
2259 (removed, undelete, None, False, False),
2261 (removed, undelete, None, False, False),
2260 (deleted, revert, remove, False, False),
2262 (deleted, revert, remove, False, False),
2261 (unknown, add, None, True, False),
2263 (unknown, add, None, True, False),
2262 (target_only, add, None, False, False),
2264 (target_only, add, None, False, False),
2263 )
2265 )
2264
2266
2265 entries = names.items()
2267 entries = names.items()
2266 entries.sort()
2268 entries.sort()
2267
2269
2268 for abs, (rel, exact) in entries:
2270 for abs, (rel, exact) in entries:
2269 mfentry = mf.get(abs)
2271 mfentry = mf.get(abs)
2270 def handle(xlist, dobackup):
2272 def handle(xlist, dobackup):
2271 xlist[0].append(abs)
2273 xlist[0].append(abs)
2272 update[abs] = 1
2274 update[abs] = 1
2273 if (dobackup and not opts['no_backup'] and
2275 if (dobackup and not opts['no_backup'] and
2274 (os.path.islink(rel) or os.path.exists(rel))):
2276 (os.path.islink(rel) or os.path.exists(rel))):
2275 bakname = "%s.orig" % rel
2277 bakname = "%s.orig" % rel
2276 ui.note(_('saving current version of %s as %s\n') %
2278 ui.note(_('saving current version of %s as %s\n') %
2277 (rel, bakname))
2279 (rel, bakname))
2278 if not opts.get('dry_run'):
2280 if not opts.get('dry_run'):
2279 util.copyfile(rel, bakname)
2281 util.copyfile(rel, bakname)
2280 if ui.verbose or not exact:
2282 if ui.verbose or not exact:
2281 ui.status(xlist[1] % rel)
2283 ui.status(xlist[1] % rel)
2282 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2284 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2283 if abs not in table: continue
2285 if abs not in table: continue
2284 # file has changed in dirstate
2286 # file has changed in dirstate
2285 if mfentry:
2287 if mfentry:
2286 handle(hitlist, backuphit)
2288 handle(hitlist, backuphit)
2287 elif misslist is not None:
2289 elif misslist is not None:
2288 handle(misslist, backupmiss)
2290 handle(misslist, backupmiss)
2289 else:
2291 else:
2290 if exact: ui.warn(_('file not managed: %s\n') % rel)
2292 if exact: ui.warn(_('file not managed: %s\n') % rel)
2291 break
2293 break
2292 else:
2294 else:
2293 # file has not changed in dirstate
2295 # file has not changed in dirstate
2294 if node == parent:
2296 if node == parent:
2295 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2297 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2296 continue
2298 continue
2297 if pmf is None:
2299 if pmf is None:
2298 # only need parent manifest in this unlikely case,
2300 # only need parent manifest in this unlikely case,
2299 # so do not read by default
2301 # so do not read by default
2300 pmf = repo.changectx(parent).manifest()
2302 pmf = repo.changectx(parent).manifest()
2301 if abs in pmf:
2303 if abs in pmf:
2302 if mfentry:
2304 if mfentry:
2303 # if version of file is same in parent and target
2305 # if version of file is same in parent and target
2304 # manifests, do nothing
2306 # manifests, do nothing
2305 if pmf[abs] != mfentry:
2307 if pmf[abs] != mfentry:
2306 handle(revert, False)
2308 handle(revert, False)
2307 else:
2309 else:
2308 handle(remove, False)
2310 handle(remove, False)
2309
2311
2310 if not opts.get('dry_run'):
2312 if not opts.get('dry_run'):
2311 repo.dirstate.forget(forget[0])
2313 repo.dirstate.forget(forget[0])
2312 r = hg.revert(repo, node, update.has_key, wlock)
2314 r = hg.revert(repo, node, update.has_key, wlock)
2313 repo.dirstate.update(add[0], 'a')
2315 repo.dirstate.update(add[0], 'a')
2314 repo.dirstate.update(undelete[0], 'n')
2316 repo.dirstate.update(undelete[0], 'n')
2315 repo.dirstate.update(remove[0], 'r')
2317 repo.dirstate.update(remove[0], 'r')
2316 return r
2318 return r
2317
2319
2318 def rollback(ui, repo):
2320 def rollback(ui, repo):
2319 """roll back the last transaction in this repository
2321 """roll back the last transaction in this repository
2320
2322
2321 Roll back the last transaction in this repository, restoring the
2323 Roll back the last transaction in this repository, restoring the
2322 project to its state prior to the transaction.
2324 project to its state prior to the transaction.
2323
2325
2324 Transactions are used to encapsulate the effects of all commands
2326 Transactions are used to encapsulate the effects of all commands
2325 that create new changesets or propagate existing changesets into a
2327 that create new changesets or propagate existing changesets into a
2326 repository. For example, the following commands are transactional,
2328 repository. For example, the following commands are transactional,
2327 and their effects can be rolled back:
2329 and their effects can be rolled back:
2328
2330
2329 commit
2331 commit
2330 import
2332 import
2331 pull
2333 pull
2332 push (with this repository as destination)
2334 push (with this repository as destination)
2333 unbundle
2335 unbundle
2334
2336
2335 This command should be used with care. There is only one level of
2337 This command should be used with care. There is only one level of
2336 rollback, and there is no way to undo a rollback.
2338 rollback, and there is no way to undo a rollback.
2337
2339
2338 This command is not intended for use on public repositories. Once
2340 This command is not intended for use on public repositories. Once
2339 changes are visible for pull by other users, rolling a transaction
2341 changes are visible for pull by other users, rolling a transaction
2340 back locally is ineffective (someone else may already have pulled
2342 back locally is ineffective (someone else may already have pulled
2341 the changes). Furthermore, a race is possible with readers of the
2343 the changes). Furthermore, a race is possible with readers of the
2342 repository; for example an in-progress pull from the repository
2344 repository; for example an in-progress pull from the repository
2343 may fail if a rollback is performed.
2345 may fail if a rollback is performed.
2344 """
2346 """
2345 repo.rollback()
2347 repo.rollback()
2346
2348
2347 def root(ui, repo):
2349 def root(ui, repo):
2348 """print the root (top) of the current working dir
2350 """print the root (top) of the current working dir
2349
2351
2350 Print the root directory of the current repository.
2352 Print the root directory of the current repository.
2351 """
2353 """
2352 ui.write(repo.root + "\n")
2354 ui.write(repo.root + "\n")
2353
2355
2354 def serve(ui, repo, **opts):
2356 def serve(ui, repo, **opts):
2355 """export the repository via HTTP
2357 """export the repository via HTTP
2356
2358
2357 Start a local HTTP repository browser and pull server.
2359 Start a local HTTP repository browser and pull server.
2358
2360
2359 By default, the server logs accesses to stdout and errors to
2361 By default, the server logs accesses to stdout and errors to
2360 stderr. Use the "-A" and "-E" options to log to files.
2362 stderr. Use the "-A" and "-E" options to log to files.
2361 """
2363 """
2362
2364
2363 if opts["stdio"]:
2365 if opts["stdio"]:
2364 if repo is None:
2366 if repo is None:
2365 raise hg.RepoError(_("There is no Mercurial repository here"
2367 raise hg.RepoError(_("There is no Mercurial repository here"
2366 " (.hg not found)"))
2368 " (.hg not found)"))
2367 s = sshserver.sshserver(ui, repo)
2369 s = sshserver.sshserver(ui, repo)
2368 s.serve_forever()
2370 s.serve_forever()
2369
2371
2370 parentui = ui.parentui or ui
2372 parentui = ui.parentui or ui
2371 optlist = ("name templates style address port ipv6"
2373 optlist = ("name templates style address port ipv6"
2372 " accesslog errorlog webdir_conf")
2374 " accesslog errorlog webdir_conf")
2373 for o in optlist.split():
2375 for o in optlist.split():
2374 if opts[o]:
2376 if opts[o]:
2375 parentui.setconfig("web", o, str(opts[o]))
2377 parentui.setconfig("web", o, str(opts[o]))
2376
2378
2377 if repo is None and not ui.config("web", "webdir_conf"):
2379 if repo is None and not ui.config("web", "webdir_conf"):
2378 raise hg.RepoError(_("There is no Mercurial repository here"
2380 raise hg.RepoError(_("There is no Mercurial repository here"
2379 " (.hg not found)"))
2381 " (.hg not found)"))
2380
2382
2381 class service:
2383 class service:
2382 def init(self):
2384 def init(self):
2383 try:
2385 try:
2384 self.httpd = hgweb.server.create_server(parentui, repo)
2386 self.httpd = hgweb.server.create_server(parentui, repo)
2385 except socket.error, inst:
2387 except socket.error, inst:
2386 raise util.Abort(_('cannot start server: ') + inst.args[1])
2388 raise util.Abort(_('cannot start server: ') + inst.args[1])
2387
2389
2388 if not ui.verbose: return
2390 if not ui.verbose: return
2389
2391
2390 if httpd.port != 80:
2392 if httpd.port != 80:
2391 ui.status(_('listening at http://%s:%d/\n') %
2393 ui.status(_('listening at http://%s:%d/\n') %
2392 (httpd.addr, httpd.port))
2394 (httpd.addr, httpd.port))
2393 else:
2395 else:
2394 ui.status(_('listening at http://%s/\n') % httpd.addr)
2396 ui.status(_('listening at http://%s/\n') % httpd.addr)
2395
2397
2396 def run(self):
2398 def run(self):
2397 self.httpd.serve_forever()
2399 self.httpd.serve_forever()
2398
2400
2399 service = service()
2401 service = service()
2400
2402
2401 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2403 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2402
2404
2403 def status(ui, repo, *pats, **opts):
2405 def status(ui, repo, *pats, **opts):
2404 """show changed files in the working directory
2406 """show changed files in the working directory
2405
2407
2406 Show status of files in the repository. If names are given, only
2408 Show status of files in the repository. If names are given, only
2407 files that match are shown. Files that are clean or ignored, are
2409 files that match are shown. Files that are clean or ignored, are
2408 not listed unless -c (clean), -i (ignored) or -A is given.
2410 not listed unless -c (clean), -i (ignored) or -A is given.
2409
2411
2410 NOTE: status may appear to disagree with diff if permissions have
2412 NOTE: status may appear to disagree with diff if permissions have
2411 changed or a merge has occurred. The standard diff format does not
2413 changed or a merge has occurred. The standard diff format does not
2412 report permission changes and diff only reports changes relative
2414 report permission changes and diff only reports changes relative
2413 to one merge parent.
2415 to one merge parent.
2414
2416
2415 If one revision is given, it is used as the base revision.
2417 If one revision is given, it is used as the base revision.
2416 If two revisions are given, the difference between them is shown.
2418 If two revisions are given, the difference between them is shown.
2417
2419
2418 The codes used to show the status of files are:
2420 The codes used to show the status of files are:
2419 M = modified
2421 M = modified
2420 A = added
2422 A = added
2421 R = removed
2423 R = removed
2422 C = clean
2424 C = clean
2423 ! = deleted, but still tracked
2425 ! = deleted, but still tracked
2424 ? = not tracked
2426 ? = not tracked
2425 I = ignored (not shown by default)
2427 I = ignored (not shown by default)
2426 = the previous added file was copied from here
2428 = the previous added file was copied from here
2427 """
2429 """
2428
2430
2429 all = opts['all']
2431 all = opts['all']
2430 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2432 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2431
2433
2432 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2434 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2433 cwd = (pats and repo.getcwd()) or ''
2435 cwd = (pats and repo.getcwd()) or ''
2434 modified, added, removed, deleted, unknown, ignored, clean = [
2436 modified, added, removed, deleted, unknown, ignored, clean = [
2435 n for n in repo.status(node1=node1, node2=node2, files=files,
2437 n for n in repo.status(node1=node1, node2=node2, files=files,
2436 match=matchfn,
2438 match=matchfn,
2437 list_ignored=all or opts['ignored'],
2439 list_ignored=all or opts['ignored'],
2438 list_clean=all or opts['clean'])]
2440 list_clean=all or opts['clean'])]
2439
2441
2440 changetypes = (('modified', 'M', modified),
2442 changetypes = (('modified', 'M', modified),
2441 ('added', 'A', added),
2443 ('added', 'A', added),
2442 ('removed', 'R', removed),
2444 ('removed', 'R', removed),
2443 ('deleted', '!', deleted),
2445 ('deleted', '!', deleted),
2444 ('unknown', '?', unknown),
2446 ('unknown', '?', unknown),
2445 ('ignored', 'I', ignored))
2447 ('ignored', 'I', ignored))
2446
2448
2447 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2449 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2448
2450
2449 end = opts['print0'] and '\0' or '\n'
2451 end = opts['print0'] and '\0' or '\n'
2450
2452
2451 for opt, char, changes in ([ct for ct in explicit_changetypes
2453 for opt, char, changes in ([ct for ct in explicit_changetypes
2452 if all or opts[ct[0]]]
2454 if all or opts[ct[0]]]
2453 or changetypes):
2455 or changetypes):
2454 if opts['no_status']:
2456 if opts['no_status']:
2455 format = "%%s%s" % end
2457 format = "%%s%s" % end
2456 else:
2458 else:
2457 format = "%s %%s%s" % (char, end)
2459 format = "%s %%s%s" % (char, end)
2458
2460
2459 for f in changes:
2461 for f in changes:
2460 ui.write(format % util.pathto(repo.root, cwd, f))
2462 ui.write(format % util.pathto(repo.root, cwd, f))
2461 if ((all or opts.get('copies')) and not opts.get('no_status')):
2463 if ((all or opts.get('copies')) and not opts.get('no_status')):
2462 copied = repo.dirstate.copied(f)
2464 copied = repo.dirstate.copied(f)
2463 if copied:
2465 if copied:
2464 ui.write(' %s%s' % (util.pathto(repo.root, cwd, copied),
2466 ui.write(' %s%s' % (util.pathto(repo.root, cwd, copied),
2465 end))
2467 end))
2466
2468
2467 def tag(ui, repo, name, rev_=None, **opts):
2469 def tag(ui, repo, name, rev_=None, **opts):
2468 """add a tag for the current or given revision
2470 """add a tag for the current or given revision
2469
2471
2470 Name a particular revision using <name>.
2472 Name a particular revision using <name>.
2471
2473
2472 Tags are used to name particular revisions of the repository and are
2474 Tags are used to name particular revisions of the repository and are
2473 very useful to compare different revision, to go back to significant
2475 very useful to compare different revision, to go back to significant
2474 earlier versions or to mark branch points as releases, etc.
2476 earlier versions or to mark branch points as releases, etc.
2475
2477
2476 If no revision is given, the parent of the working directory is used,
2478 If no revision is given, the parent of the working directory is used,
2477 or tip if no revision is checked out.
2479 or tip if no revision is checked out.
2478
2480
2479 To facilitate version control, distribution, and merging of tags,
2481 To facilitate version control, distribution, and merging of tags,
2480 they are stored as a file named ".hgtags" which is managed
2482 they are stored as a file named ".hgtags" which is managed
2481 similarly to other project files and can be hand-edited if
2483 similarly to other project files and can be hand-edited if
2482 necessary. The file '.hg/localtags' is used for local tags (not
2484 necessary. The file '.hg/localtags' is used for local tags (not
2483 shared among repositories).
2485 shared among repositories).
2484 """
2486 """
2485 if name in ['tip', '.', 'null']:
2487 if name in ['tip', '.', 'null']:
2486 raise util.Abort(_("the name '%s' is reserved") % name)
2488 raise util.Abort(_("the name '%s' is reserved") % name)
2487 if rev_ is not None:
2489 if rev_ is not None:
2488 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2490 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2489 "please use 'hg tag [-r REV] NAME' instead\n"))
2491 "please use 'hg tag [-r REV] NAME' instead\n"))
2490 if opts['rev']:
2492 if opts['rev']:
2491 raise util.Abort(_("use only one form to specify the revision"))
2493 raise util.Abort(_("use only one form to specify the revision"))
2492 if opts['rev'] and opts['remove']:
2494 if opts['rev'] and opts['remove']:
2493 raise util.Abort(_("--rev and --remove are incompatible"))
2495 raise util.Abort(_("--rev and --remove are incompatible"))
2494 if opts['rev']:
2496 if opts['rev']:
2495 rev_ = opts['rev']
2497 rev_ = opts['rev']
2496 message = opts['message']
2498 message = opts['message']
2497 if opts['remove']:
2499 if opts['remove']:
2498 rev_ = nullid
2500 rev_ = nullid
2499 if not message:
2501 if not message:
2500 message = _('Removed tag %s') % name
2502 message = _('Removed tag %s') % name
2501 elif name in repo.tags() and not opts['force']:
2503 elif name in repo.tags() and not opts['force']:
2502 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2504 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2503 % name)
2505 % name)
2504 if not rev_ and repo.dirstate.parents()[1] != nullid:
2506 if not rev_ and repo.dirstate.parents()[1] != nullid:
2505 raise util.Abort(_('uncommitted merge - please provide a '
2507 raise util.Abort(_('uncommitted merge - please provide a '
2506 'specific revision'))
2508 'specific revision'))
2507 r = repo.changectx(rev_).node()
2509 r = repo.changectx(rev_).node()
2508
2510
2509 if not message:
2511 if not message:
2510 message = _('Added tag %s for changeset %s') % (name, short(r))
2512 message = _('Added tag %s for changeset %s') % (name, short(r))
2511
2513
2512 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2514 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2513
2515
2514 def tags(ui, repo):
2516 def tags(ui, repo):
2515 """list repository tags
2517 """list repository tags
2516
2518
2517 List the repository tags.
2519 List the repository tags.
2518
2520
2519 This lists both regular and local tags.
2521 This lists both regular and local tags.
2520 """
2522 """
2521
2523
2522 l = repo.tagslist()
2524 l = repo.tagslist()
2523 l.reverse()
2525 l.reverse()
2524 hexfunc = ui.debugflag and hex or short
2526 hexfunc = ui.debugflag and hex or short
2525 for t, n in l:
2527 for t, n in l:
2526 try:
2528 try:
2527 hn = hexfunc(n)
2529 hn = hexfunc(n)
2528 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2530 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2529 except revlog.LookupError:
2531 except revlog.LookupError:
2530 r = " ?:%s" % hn
2532 r = " ?:%s" % hn
2531 if ui.quiet:
2533 if ui.quiet:
2532 ui.write("%s\n" % t)
2534 ui.write("%s\n" % t)
2533 else:
2535 else:
2534 spaces = " " * (30 - util.locallen(t))
2536 spaces = " " * (30 - util.locallen(t))
2535 ui.write("%s%s %s\n" % (t, spaces, r))
2537 ui.write("%s%s %s\n" % (t, spaces, r))
2536
2538
2537 def tip(ui, repo, **opts):
2539 def tip(ui, repo, **opts):
2538 """show the tip revision
2540 """show the tip revision
2539
2541
2540 Show the tip revision.
2542 Show the tip revision.
2541 """
2543 """
2542 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2544 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2543
2545
2544 def unbundle(ui, repo, fname, **opts):
2546 def unbundle(ui, repo, fname, **opts):
2545 """apply a changegroup file
2547 """apply a changegroup file
2546
2548
2547 Apply a compressed changegroup file generated by the bundle
2549 Apply a compressed changegroup file generated by the bundle
2548 command.
2550 command.
2549 """
2551 """
2550 if os.path.exists(fname):
2552 if os.path.exists(fname):
2551 f = open(fname, "rb")
2553 f = open(fname, "rb")
2552 else:
2554 else:
2553 f = urllib.urlopen(fname)
2555 f = urllib.urlopen(fname)
2554 gen = changegroup.readbundle(f, fname)
2556 gen = changegroup.readbundle(f, fname)
2555 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2557 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2556 return postincoming(ui, repo, modheads, opts['update'])
2558 return postincoming(ui, repo, modheads, opts['update'])
2557
2559
2558 def update(ui, repo, node=None, clean=False, date=None):
2560 def update(ui, repo, node=None, clean=False, date=None):
2559 """update working directory
2561 """update working directory
2560
2562
2561 Update the working directory to the specified revision, or the
2563 Update the working directory to the specified revision, or the
2562 tip of the current branch if none is specified.
2564 tip of the current branch if none is specified.
2563
2565
2564 If there are no outstanding changes in the working directory and
2566 If there are no outstanding changes in the working directory and
2565 there is a linear relationship between the current version and the
2567 there is a linear relationship between the current version and the
2566 requested version, the result is the requested version.
2568 requested version, the result is the requested version.
2567
2569
2568 To merge the working directory with another revision, use the
2570 To merge the working directory with another revision, use the
2569 merge command.
2571 merge command.
2570
2572
2571 By default, update will refuse to run if doing so would require
2573 By default, update will refuse to run if doing so would require
2572 discarding local changes.
2574 discarding local changes.
2573 """
2575 """
2574 if date:
2576 if date:
2575 if node:
2577 if node:
2576 raise util.Abort(_("you can't specify a revision and a date"))
2578 raise util.Abort(_("you can't specify a revision and a date"))
2577 node = cmdutil.finddate(ui, repo, date)
2579 node = cmdutil.finddate(ui, repo, date)
2578
2580
2579 if clean:
2581 if clean:
2580 return hg.clean(repo, node)
2582 return hg.clean(repo, node)
2581 else:
2583 else:
2582 return hg.update(repo, node)
2584 return hg.update(repo, node)
2583
2585
2584 def verify(ui, repo):
2586 def verify(ui, repo):
2585 """verify the integrity of the repository
2587 """verify the integrity of the repository
2586
2588
2587 Verify the integrity of the current repository.
2589 Verify the integrity of the current repository.
2588
2590
2589 This will perform an extensive check of the repository's
2591 This will perform an extensive check of the repository's
2590 integrity, validating the hashes and checksums of each entry in
2592 integrity, validating the hashes and checksums of each entry in
2591 the changelog, manifest, and tracked files, as well as the
2593 the changelog, manifest, and tracked files, as well as the
2592 integrity of their crosslinks and indices.
2594 integrity of their crosslinks and indices.
2593 """
2595 """
2594 return hg.verify(repo)
2596 return hg.verify(repo)
2595
2597
2596 def version_(ui):
2598 def version_(ui):
2597 """output version and copyright information"""
2599 """output version and copyright information"""
2598 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2600 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2599 % version.get_version())
2601 % version.get_version())
2600 ui.status(_(
2602 ui.status(_(
2601 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2603 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2602 "This is free software; see the source for copying conditions. "
2604 "This is free software; see the source for copying conditions. "
2603 "There is NO\nwarranty; "
2605 "There is NO\nwarranty; "
2604 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2606 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2605 ))
2607 ))
2606
2608
2607 # Command options and aliases are listed here, alphabetically
2609 # Command options and aliases are listed here, alphabetically
2608
2610
2609 globalopts = [
2611 globalopts = [
2610 ('R', 'repository', '',
2612 ('R', 'repository', '',
2611 _('repository root directory or symbolic path name')),
2613 _('repository root directory or symbolic path name')),
2612 ('', 'cwd', '', _('change working directory')),
2614 ('', 'cwd', '', _('change working directory')),
2613 ('y', 'noninteractive', None,
2615 ('y', 'noninteractive', None,
2614 _('do not prompt, assume \'yes\' for any required answers')),
2616 _('do not prompt, assume \'yes\' for any required answers')),
2615 ('q', 'quiet', None, _('suppress output')),
2617 ('q', 'quiet', None, _('suppress output')),
2616 ('v', 'verbose', None, _('enable additional output')),
2618 ('v', 'verbose', None, _('enable additional output')),
2617 ('', 'config', [], _('set/override config option')),
2619 ('', 'config', [], _('set/override config option')),
2618 ('', 'debug', None, _('enable debugging output')),
2620 ('', 'debug', None, _('enable debugging output')),
2619 ('', 'debugger', None, _('start debugger')),
2621 ('', 'debugger', None, _('start debugger')),
2620 ('', 'encoding', util._encoding, _('set the charset encoding')),
2622 ('', 'encoding', util._encoding, _('set the charset encoding')),
2621 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2623 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2622 ('', 'lsprof', None, _('print improved command execution profile')),
2624 ('', 'lsprof', None, _('print improved command execution profile')),
2623 ('', 'traceback', None, _('print traceback on exception')),
2625 ('', 'traceback', None, _('print traceback on exception')),
2624 ('', 'time', None, _('time how long the command takes')),
2626 ('', 'time', None, _('time how long the command takes')),
2625 ('', 'profile', None, _('print command execution profile')),
2627 ('', 'profile', None, _('print command execution profile')),
2626 ('', 'version', None, _('output version information and exit')),
2628 ('', 'version', None, _('output version information and exit')),
2627 ('h', 'help', None, _('display help and exit')),
2629 ('h', 'help', None, _('display help and exit')),
2628 ]
2630 ]
2629
2631
2630 dryrunopts = [('n', 'dry-run', None,
2632 dryrunopts = [('n', 'dry-run', None,
2631 _('do not perform actions, just print output'))]
2633 _('do not perform actions, just print output'))]
2632
2634
2633 remoteopts = [
2635 remoteopts = [
2634 ('e', 'ssh', '', _('specify ssh command to use')),
2636 ('e', 'ssh', '', _('specify ssh command to use')),
2635 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2637 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2636 ]
2638 ]
2637
2639
2638 walkopts = [
2640 walkopts = [
2639 ('I', 'include', [], _('include names matching the given patterns')),
2641 ('I', 'include', [], _('include names matching the given patterns')),
2640 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2642 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2641 ]
2643 ]
2642
2644
2643 commitopts = [
2645 commitopts = [
2644 ('m', 'message', '', _('use <text> as commit message')),
2646 ('m', 'message', '', _('use <text> as commit message')),
2645 ('l', 'logfile', '', _('read commit message from <file>')),
2647 ('l', 'logfile', '', _('read commit message from <file>')),
2646 ]
2648 ]
2647
2649
2648 table = {
2650 table = {
2649 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2651 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2650 "addremove":
2652 "addremove":
2651 (addremove,
2653 (addremove,
2652 [('s', 'similarity', '',
2654 [('s', 'similarity', '',
2653 _('guess renamed files by similarity (0<=s<=100)')),
2655 _('guess renamed files by similarity (0<=s<=100)')),
2654 ] + walkopts + dryrunopts,
2656 ] + walkopts + dryrunopts,
2655 _('hg addremove [OPTION]... [FILE]...')),
2657 _('hg addremove [OPTION]... [FILE]...')),
2656 "^annotate":
2658 "^annotate":
2657 (annotate,
2659 (annotate,
2658 [('r', 'rev', '', _('annotate the specified revision')),
2660 [('r', 'rev', '', _('annotate the specified revision')),
2659 ('f', 'follow', None, _('follow file copies and renames')),
2661 ('f', 'follow', None, _('follow file copies and renames')),
2660 ('a', 'text', None, _('treat all files as text')),
2662 ('a', 'text', None, _('treat all files as text')),
2661 ('u', 'user', None, _('list the author')),
2663 ('u', 'user', None, _('list the author')),
2662 ('d', 'date', None, _('list the date')),
2664 ('d', 'date', None, _('list the date')),
2663 ('n', 'number', None, _('list the revision number (default)')),
2665 ('n', 'number', None, _('list the revision number (default)')),
2664 ('c', 'changeset', None, _('list the changeset')),
2666 ('c', 'changeset', None, _('list the changeset')),
2665 ] + walkopts,
2667 ] + walkopts,
2666 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2668 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2667 "archive":
2669 "archive":
2668 (archive,
2670 (archive,
2669 [('', 'no-decode', None, _('do not pass files through decoders')),
2671 [('', 'no-decode', None, _('do not pass files through decoders')),
2670 ('p', 'prefix', '', _('directory prefix for files in archive')),
2672 ('p', 'prefix', '', _('directory prefix for files in archive')),
2671 ('r', 'rev', '', _('revision to distribute')),
2673 ('r', 'rev', '', _('revision to distribute')),
2672 ('t', 'type', '', _('type of distribution to create')),
2674 ('t', 'type', '', _('type of distribution to create')),
2673 ] + walkopts,
2675 ] + walkopts,
2674 _('hg archive [OPTION]... DEST')),
2676 _('hg archive [OPTION]... DEST')),
2675 "backout":
2677 "backout":
2676 (backout,
2678 (backout,
2677 [('', 'merge', None,
2679 [('', 'merge', None,
2678 _('merge with old dirstate parent after backout')),
2680 _('merge with old dirstate parent after backout')),
2679 ('d', 'date', '', _('record datecode as commit date')),
2681 ('d', 'date', '', _('record datecode as commit date')),
2680 ('', 'parent', '', _('parent to choose when backing out merge')),
2682 ('', 'parent', '', _('parent to choose when backing out merge')),
2681 ('u', 'user', '', _('record user as committer')),
2683 ('u', 'user', '', _('record user as committer')),
2682 ] + walkopts + commitopts,
2684 ] + walkopts + commitopts,
2683 _('hg backout [OPTION]... REV')),
2685 _('hg backout [OPTION]... REV')),
2684 "branch": (branch,
2686 "branch": (branch,
2685 [('f', 'force', None,
2687 [('f', 'force', None,
2686 _('set branch name even if it shadows an existing branch'))],
2688 _('set branch name even if it shadows an existing branch'))],
2687 _('hg branch [NAME]')),
2689 _('hg branch [NAME]')),
2688 "branches": (branches, [], _('hg branches')),
2690 "branches": (branches, [], _('hg branches')),
2689 "bundle":
2691 "bundle":
2690 (bundle,
2692 (bundle,
2691 [('f', 'force', None,
2693 [('f', 'force', None,
2692 _('run even when remote repository is unrelated')),
2694 _('run even when remote repository is unrelated')),
2693 ('r', 'rev', [],
2695 ('r', 'rev', [],
2694 _('a changeset you would like to bundle')),
2696 _('a changeset you would like to bundle')),
2695 ('', 'base', [],
2697 ('', 'base', [],
2696 _('a base changeset to specify instead of a destination')),
2698 _('a base changeset to specify instead of a destination')),
2697 ] + remoteopts,
2699 ] + remoteopts,
2698 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2700 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2699 "cat":
2701 "cat":
2700 (cat,
2702 (cat,
2701 [('o', 'output', '', _('print output to file with formatted name')),
2703 [('o', 'output', '', _('print output to file with formatted name')),
2702 ('r', 'rev', '', _('print the given revision')),
2704 ('r', 'rev', '', _('print the given revision')),
2703 ] + walkopts,
2705 ] + walkopts,
2704 _('hg cat [OPTION]... FILE...')),
2706 _('hg cat [OPTION]... FILE...')),
2705 "^clone":
2707 "^clone":
2706 (clone,
2708 (clone,
2707 [('U', 'noupdate', None, _('do not update the new working directory')),
2709 [('U', 'noupdate', None, _('do not update the new working directory')),
2708 ('r', 'rev', [],
2710 ('r', 'rev', [],
2709 _('a changeset you would like to have after cloning')),
2711 _('a changeset you would like to have after cloning')),
2710 ('', 'pull', None, _('use pull protocol to copy metadata')),
2712 ('', 'pull', None, _('use pull protocol to copy metadata')),
2711 ('', 'uncompressed', None,
2713 ('', 'uncompressed', None,
2712 _('use uncompressed transfer (fast over LAN)')),
2714 _('use uncompressed transfer (fast over LAN)')),
2713 ] + remoteopts,
2715 ] + remoteopts,
2714 _('hg clone [OPTION]... SOURCE [DEST]')),
2716 _('hg clone [OPTION]... SOURCE [DEST]')),
2715 "^commit|ci":
2717 "^commit|ci":
2716 (commit,
2718 (commit,
2717 [('A', 'addremove', None,
2719 [('A', 'addremove', None,
2718 _('mark new/missing files as added/removed before committing')),
2720 _('mark new/missing files as added/removed before committing')),
2719 ('d', 'date', '', _('record datecode as commit date')),
2721 ('d', 'date', '', _('record datecode as commit date')),
2720 ('u', 'user', '', _('record user as commiter')),
2722 ('u', 'user', '', _('record user as commiter')),
2721 ] + walkopts + commitopts,
2723 ] + walkopts + commitopts,
2722 _('hg commit [OPTION]... [FILE]...')),
2724 _('hg commit [OPTION]... [FILE]...')),
2723 "copy|cp":
2725 "copy|cp":
2724 (copy,
2726 (copy,
2725 [('A', 'after', None, _('record a copy that has already occurred')),
2727 [('A', 'after', None, _('record a copy that has already occurred')),
2726 ('f', 'force', None,
2728 ('f', 'force', None,
2727 _('forcibly copy over an existing managed file')),
2729 _('forcibly copy over an existing managed file')),
2728 ] + walkopts + dryrunopts,
2730 ] + walkopts + dryrunopts,
2729 _('hg copy [OPTION]... [SOURCE]... DEST')),
2731 _('hg copy [OPTION]... [SOURCE]... DEST')),
2730 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2732 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2731 "debugcomplete":
2733 "debugcomplete":
2732 (debugcomplete,
2734 (debugcomplete,
2733 [('o', 'options', None, _('show the command options'))],
2735 [('o', 'options', None, _('show the command options'))],
2734 _('debugcomplete [-o] CMD')),
2736 _('debugcomplete [-o] CMD')),
2735 "debuginstall": (debuginstall, [], _('debuginstall')),
2737 "debuginstall": (debuginstall, [], _('debuginstall')),
2736 "debugrebuildstate":
2738 "debugrebuildstate":
2737 (debugrebuildstate,
2739 (debugrebuildstate,
2738 [('r', 'rev', '', _('revision to rebuild to'))],
2740 [('r', 'rev', '', _('revision to rebuild to'))],
2739 _('debugrebuildstate [-r REV] [REV]')),
2741 _('debugrebuildstate [-r REV] [REV]')),
2740 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2742 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2741 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2743 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2742 "debugstate": (debugstate, [], _('debugstate')),
2744 "debugstate": (debugstate, [], _('debugstate')),
2743 "debugdate":
2745 "debugdate":
2744 (debugdate,
2746 (debugdate,
2745 [('e', 'extended', None, _('try extended date formats'))],
2747 [('e', 'extended', None, _('try extended date formats'))],
2746 _('debugdate [-e] DATE [RANGE]')),
2748 _('debugdate [-e] DATE [RANGE]')),
2747 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2749 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2748 "debugindex": (debugindex, [], _('debugindex FILE')),
2750 "debugindex": (debugindex, [], _('debugindex FILE')),
2749 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2751 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2750 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2752 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2751 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2753 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2752 "^diff":
2754 "^diff":
2753 (diff,
2755 (diff,
2754 [('r', 'rev', [], _('revision')),
2756 [('r', 'rev', [], _('revision')),
2755 ('a', 'text', None, _('treat all files as text')),
2757 ('a', 'text', None, _('treat all files as text')),
2756 ('p', 'show-function', None,
2758 ('p', 'show-function', None,
2757 _('show which function each change is in')),
2759 _('show which function each change is in')),
2758 ('g', 'git', None, _('use git extended diff format')),
2760 ('g', 'git', None, _('use git extended diff format')),
2759 ('', 'nodates', None, _("don't include dates in diff headers")),
2761 ('', 'nodates', None, _("don't include dates in diff headers")),
2760 ('w', 'ignore-all-space', None,
2762 ('w', 'ignore-all-space', None,
2761 _('ignore white space when comparing lines')),
2763 _('ignore white space when comparing lines')),
2762 ('b', 'ignore-space-change', None,
2764 ('b', 'ignore-space-change', None,
2763 _('ignore changes in the amount of white space')),
2765 _('ignore changes in the amount of white space')),
2764 ('B', 'ignore-blank-lines', None,
2766 ('B', 'ignore-blank-lines', None,
2765 _('ignore changes whose lines are all blank')),
2767 _('ignore changes whose lines are all blank')),
2766 ] + walkopts,
2768 ] + walkopts,
2767 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2769 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2768 "^export":
2770 "^export":
2769 (export,
2771 (export,
2770 [('o', 'output', '', _('print output to file with formatted name')),
2772 [('o', 'output', '', _('print output to file with formatted name')),
2771 ('a', 'text', None, _('treat all files as text')),
2773 ('a', 'text', None, _('treat all files as text')),
2772 ('g', 'git', None, _('use git extended diff format')),
2774 ('g', 'git', None, _('use git extended diff format')),
2773 ('', 'nodates', None, _("don't include dates in diff headers")),
2775 ('', 'nodates', None, _("don't include dates in diff headers")),
2774 ('', 'switch-parent', None, _('diff against the second parent'))],
2776 ('', 'switch-parent', None, _('diff against the second parent'))],
2775 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2777 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2776 "grep":
2778 "grep":
2777 (grep,
2779 (grep,
2778 [('0', 'print0', None, _('end fields with NUL')),
2780 [('0', 'print0', None, _('end fields with NUL')),
2779 ('', 'all', None, _('print all revisions that match')),
2781 ('', 'all', None, _('print all revisions that match')),
2780 ('f', 'follow', None,
2782 ('f', 'follow', None,
2781 _('follow changeset history, or file history across copies and renames')),
2783 _('follow changeset history, or file history across copies and renames')),
2782 ('i', 'ignore-case', None, _('ignore case when matching')),
2784 ('i', 'ignore-case', None, _('ignore case when matching')),
2783 ('l', 'files-with-matches', None,
2785 ('l', 'files-with-matches', None,
2784 _('print only filenames and revs that match')),
2786 _('print only filenames and revs that match')),
2785 ('n', 'line-number', None, _('print matching line numbers')),
2787 ('n', 'line-number', None, _('print matching line numbers')),
2786 ('r', 'rev', [], _('search in given revision range')),
2788 ('r', 'rev', [], _('search in given revision range')),
2787 ('u', 'user', None, _('print user who committed change')),
2789 ('u', 'user', None, _('print user who committed change')),
2788 ] + walkopts,
2790 ] + walkopts,
2789 _('hg grep [OPTION]... PATTERN [FILE]...')),
2791 _('hg grep [OPTION]... PATTERN [FILE]...')),
2790 "heads":
2792 "heads":
2791 (heads,
2793 (heads,
2792 [('', 'style', '', _('display using template map file')),
2794 [('', 'style', '', _('display using template map file')),
2793 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2795 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2794 ('', 'template', '', _('display with template'))],
2796 ('', 'template', '', _('display with template'))],
2795 _('hg heads [-r REV]')),
2797 _('hg heads [-r REV]')),
2796 "help": (help_, [], _('hg help [COMMAND]')),
2798 "help": (help_, [], _('hg help [COMMAND]')),
2797 "identify|id": (identify, [], _('hg identify')),
2799 "identify|id": (identify, [], _('hg identify')),
2798 "import|patch":
2800 "import|patch":
2799 (import_,
2801 (import_,
2800 [('p', 'strip', 1,
2802 [('p', 'strip', 1,
2801 _('directory strip option for patch. This has the same\n'
2803 _('directory strip option for patch. This has the same\n'
2802 'meaning as the corresponding patch option')),
2804 'meaning as the corresponding patch option')),
2803 ('b', 'base', '', _('base path')),
2805 ('b', 'base', '', _('base path')),
2804 ('f', 'force', None,
2806 ('f', 'force', None,
2805 _('skip check for outstanding uncommitted changes')),
2807 _('skip check for outstanding uncommitted changes')),
2806 ('', 'exact', None,
2808 ('', 'exact', None,
2807 _('apply patch to the nodes from which it was generated'))] + commitopts,
2809 _('apply patch to the nodes from which it was generated'))] + commitopts,
2808 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2810 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2809 "incoming|in": (incoming,
2811 "incoming|in": (incoming,
2810 [('M', 'no-merges', None, _('do not show merges')),
2812 [('M', 'no-merges', None, _('do not show merges')),
2811 ('f', 'force', None,
2813 ('f', 'force', None,
2812 _('run even when remote repository is unrelated')),
2814 _('run even when remote repository is unrelated')),
2813 ('', 'style', '', _('display using template map file')),
2815 ('', 'style', '', _('display using template map file')),
2814 ('n', 'newest-first', None, _('show newest record first')),
2816 ('n', 'newest-first', None, _('show newest record first')),
2815 ('', 'bundle', '', _('file to store the bundles into')),
2817 ('', 'bundle', '', _('file to store the bundles into')),
2816 ('p', 'patch', None, _('show patch')),
2818 ('p', 'patch', None, _('show patch')),
2817 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2819 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2818 ('', 'template', '', _('display with template')),
2820 ('', 'template', '', _('display with template')),
2819 ] + remoteopts,
2821 ] + remoteopts,
2820 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2822 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2821 ' [--bundle FILENAME] [SOURCE]')),
2823 ' [--bundle FILENAME] [SOURCE]')),
2822 "^init":
2824 "^init":
2823 (init,
2825 (init,
2824 remoteopts,
2826 remoteopts,
2825 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2827 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2826 "locate":
2828 "locate":
2827 (locate,
2829 (locate,
2828 [('r', 'rev', '', _('search the repository as it stood at rev')),
2830 [('r', 'rev', '', _('search the repository as it stood at rev')),
2829 ('0', 'print0', None,
2831 ('0', 'print0', None,
2830 _('end filenames with NUL, for use with xargs')),
2832 _('end filenames with NUL, for use with xargs')),
2831 ('f', 'fullpath', None,
2833 ('f', 'fullpath', None,
2832 _('print complete paths from the filesystem root')),
2834 _('print complete paths from the filesystem root')),
2833 ] + walkopts,
2835 ] + walkopts,
2834 _('hg locate [OPTION]... [PATTERN]...')),
2836 _('hg locate [OPTION]... [PATTERN]...')),
2835 "^log|history":
2837 "^log|history":
2836 (log,
2838 (log,
2837 [('f', 'follow', None,
2839 [('f', 'follow', None,
2838 _('follow changeset history, or file history across copies and renames')),
2840 _('follow changeset history, or file history across copies and renames')),
2839 ('', 'follow-first', None,
2841 ('', 'follow-first', None,
2840 _('only follow the first parent of merge changesets')),
2842 _('only follow the first parent of merge changesets')),
2841 ('d', 'date', '', _('show revs matching date spec')),
2843 ('d', 'date', '', _('show revs matching date spec')),
2842 ('C', 'copies', None, _('show copied files')),
2844 ('C', 'copies', None, _('show copied files')),
2843 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2845 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2844 ('l', 'limit', '', _('limit number of changes displayed')),
2846 ('l', 'limit', '', _('limit number of changes displayed')),
2845 ('r', 'rev', [], _('show the specified revision or range')),
2847 ('r', 'rev', [], _('show the specified revision or range')),
2846 ('', 'removed', None, _('include revs where files were removed')),
2848 ('', 'removed', None, _('include revs where files were removed')),
2847 ('M', 'no-merges', None, _('do not show merges')),
2849 ('M', 'no-merges', None, _('do not show merges')),
2848 ('', 'style', '', _('display using template map file')),
2850 ('', 'style', '', _('display using template map file')),
2849 ('m', 'only-merges', None, _('show only merges')),
2851 ('m', 'only-merges', None, _('show only merges')),
2850 ('p', 'patch', None, _('show patch')),
2852 ('p', 'patch', None, _('show patch')),
2851 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2853 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2852 ('', 'template', '', _('display with template')),
2854 ('', 'template', '', _('display with template')),
2853 ] + walkopts,
2855 ] + walkopts,
2854 _('hg log [OPTION]... [FILE]')),
2856 _('hg log [OPTION]... [FILE]')),
2855 "manifest": (manifest, [], _('hg manifest [REV]')),
2857 "manifest": (manifest, [], _('hg manifest [REV]')),
2856 "^merge":
2858 "^merge":
2857 (merge,
2859 (merge,
2858 [('f', 'force', None, _('force a merge with outstanding changes'))],
2860 [('f', 'force', None, _('force a merge with outstanding changes'))],
2859 _('hg merge [-f] [REV]')),
2861 _('hg merge [-f] [REV]')),
2860 "outgoing|out": (outgoing,
2862 "outgoing|out": (outgoing,
2861 [('M', 'no-merges', None, _('do not show merges')),
2863 [('M', 'no-merges', None, _('do not show merges')),
2862 ('f', 'force', None,
2864 ('f', 'force', None,
2863 _('run even when remote repository is unrelated')),
2865 _('run even when remote repository is unrelated')),
2864 ('p', 'patch', None, _('show patch')),
2866 ('p', 'patch', None, _('show patch')),
2865 ('', 'style', '', _('display using template map file')),
2867 ('', 'style', '', _('display using template map file')),
2866 ('r', 'rev', [], _('a specific revision you would like to push')),
2868 ('r', 'rev', [], _('a specific revision you would like to push')),
2867 ('n', 'newest-first', None, _('show newest record first')),
2869 ('n', 'newest-first', None, _('show newest record first')),
2868 ('', 'template', '', _('display with template')),
2870 ('', 'template', '', _('display with template')),
2869 ] + remoteopts,
2871 ] + remoteopts,
2870 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2872 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2871 "^parents":
2873 "^parents":
2872 (parents,
2874 (parents,
2873 [('r', 'rev', '', _('show parents from the specified rev')),
2875 [('r', 'rev', '', _('show parents from the specified rev')),
2874 ('', 'style', '', _('display using template map file')),
2876 ('', 'style', '', _('display using template map file')),
2875 ('', 'template', '', _('display with template'))],
2877 ('', 'template', '', _('display with template'))],
2876 _('hg parents [-r REV] [FILE]')),
2878 _('hg parents [-r REV] [FILE]')),
2877 "paths": (paths, [], _('hg paths [NAME]')),
2879 "paths": (paths, [], _('hg paths [NAME]')),
2878 "^pull":
2880 "^pull":
2879 (pull,
2881 (pull,
2880 [('u', 'update', None,
2882 [('u', 'update', None,
2881 _('update to new tip if changesets were pulled')),
2883 _('update to new tip if changesets were pulled')),
2882 ('f', 'force', None,
2884 ('f', 'force', None,
2883 _('run even when remote repository is unrelated')),
2885 _('run even when remote repository is unrelated')),
2884 ('r', 'rev', [],
2886 ('r', 'rev', [],
2885 _('a specific revision up to which you would like to pull')),
2887 _('a specific revision up to which you would like to pull')),
2886 ] + remoteopts,
2888 ] + remoteopts,
2887 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2889 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2888 "^push":
2890 "^push":
2889 (push,
2891 (push,
2890 [('f', 'force', None, _('force push')),
2892 [('f', 'force', None, _('force push')),
2891 ('r', 'rev', [], _('a specific revision you would like to push')),
2893 ('r', 'rev', [], _('a specific revision you would like to push')),
2892 ] + remoteopts,
2894 ] + remoteopts,
2893 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2895 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2894 "debugrawcommit|rawcommit":
2896 "debugrawcommit|rawcommit":
2895 (rawcommit,
2897 (rawcommit,
2896 [('p', 'parent', [], _('parent')),
2898 [('p', 'parent', [], _('parent')),
2897 ('d', 'date', '', _('date code')),
2899 ('d', 'date', '', _('date code')),
2898 ('u', 'user', '', _('user')),
2900 ('u', 'user', '', _('user')),
2899 ('F', 'files', '', _('file list'))
2901 ('F', 'files', '', _('file list'))
2900 ] + commitopts,
2902 ] + commitopts,
2901 _('hg debugrawcommit [OPTION]... [FILE]...')),
2903 _('hg debugrawcommit [OPTION]... [FILE]...')),
2902 "recover": (recover, [], _('hg recover')),
2904 "recover": (recover, [], _('hg recover')),
2903 "^remove|rm":
2905 "^remove|rm":
2904 (remove,
2906 (remove,
2905 [('A', 'after', None, _('record remove that has already occurred')),
2907 [('A', 'after', None, _('record remove that has already occurred')),
2906 ('f', 'force', None, _('remove file even if modified')),
2908 ('f', 'force', None, _('remove file even if modified')),
2907 ] + walkopts,
2909 ] + walkopts,
2908 _('hg remove [OPTION]... FILE...')),
2910 _('hg remove [OPTION]... FILE...')),
2909 "rename|mv":
2911 "rename|mv":
2910 (rename,
2912 (rename,
2911 [('A', 'after', None, _('record a rename that has already occurred')),
2913 [('A', 'after', None, _('record a rename that has already occurred')),
2912 ('f', 'force', None,
2914 ('f', 'force', None,
2913 _('forcibly copy over an existing managed file')),
2915 _('forcibly copy over an existing managed file')),
2914 ] + walkopts + dryrunopts,
2916 ] + walkopts + dryrunopts,
2915 _('hg rename [OPTION]... SOURCE... DEST')),
2917 _('hg rename [OPTION]... SOURCE... DEST')),
2916 "^revert":
2918 "^revert":
2917 (revert,
2919 (revert,
2918 [('a', 'all', None, _('revert all changes when no arguments given')),
2920 [('a', 'all', None, _('revert all changes when no arguments given')),
2919 ('d', 'date', '', _('tipmost revision matching date')),
2921 ('d', 'date', '', _('tipmost revision matching date')),
2920 ('r', 'rev', '', _('revision to revert to')),
2922 ('r', 'rev', '', _('revision to revert to')),
2921 ('', 'no-backup', None, _('do not save backup copies of files')),
2923 ('', 'no-backup', None, _('do not save backup copies of files')),
2922 ] + walkopts + dryrunopts,
2924 ] + walkopts + dryrunopts,
2923 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2925 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2924 "rollback": (rollback, [], _('hg rollback')),
2926 "rollback": (rollback, [], _('hg rollback')),
2925 "root": (root, [], _('hg root')),
2927 "root": (root, [], _('hg root')),
2926 "showconfig|debugconfig":
2928 "showconfig|debugconfig":
2927 (showconfig,
2929 (showconfig,
2928 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2930 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2929 _('showconfig [-u] [NAME]...')),
2931 _('showconfig [-u] [NAME]...')),
2930 "^serve":
2932 "^serve":
2931 (serve,
2933 (serve,
2932 [('A', 'accesslog', '', _('name of access log file to write to')),
2934 [('A', 'accesslog', '', _('name of access log file to write to')),
2933 ('d', 'daemon', None, _('run server in background')),
2935 ('d', 'daemon', None, _('run server in background')),
2934 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2936 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2935 ('E', 'errorlog', '', _('name of error log file to write to')),
2937 ('E', 'errorlog', '', _('name of error log file to write to')),
2936 ('p', 'port', 0, _('port to use (default: 8000)')),
2938 ('p', 'port', 0, _('port to use (default: 8000)')),
2937 ('a', 'address', '', _('address to use')),
2939 ('a', 'address', '', _('address to use')),
2938 ('n', 'name', '',
2940 ('n', 'name', '',
2939 _('name to show in web pages (default: working dir)')),
2941 _('name to show in web pages (default: working dir)')),
2940 ('', 'webdir-conf', '', _('name of the webdir config file'
2942 ('', 'webdir-conf', '', _('name of the webdir config file'
2941 ' (serve more than one repo)')),
2943 ' (serve more than one repo)')),
2942 ('', 'pid-file', '', _('name of file to write process ID to')),
2944 ('', 'pid-file', '', _('name of file to write process ID to')),
2943 ('', 'stdio', None, _('for remote clients')),
2945 ('', 'stdio', None, _('for remote clients')),
2944 ('t', 'templates', '', _('web templates to use')),
2946 ('t', 'templates', '', _('web templates to use')),
2945 ('', 'style', '', _('template style to use')),
2947 ('', 'style', '', _('template style to use')),
2946 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2948 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2947 _('hg serve [OPTION]...')),
2949 _('hg serve [OPTION]...')),
2948 "^status|st":
2950 "^status|st":
2949 (status,
2951 (status,
2950 [('A', 'all', None, _('show status of all files')),
2952 [('A', 'all', None, _('show status of all files')),
2951 ('m', 'modified', None, _('show only modified files')),
2953 ('m', 'modified', None, _('show only modified files')),
2952 ('a', 'added', None, _('show only added files')),
2954 ('a', 'added', None, _('show only added files')),
2953 ('r', 'removed', None, _('show only removed files')),
2955 ('r', 'removed', None, _('show only removed files')),
2954 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2956 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2955 ('c', 'clean', None, _('show only files without changes')),
2957 ('c', 'clean', None, _('show only files without changes')),
2956 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2958 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2957 ('i', 'ignored', None, _('show only ignored files')),
2959 ('i', 'ignored', None, _('show only ignored files')),
2958 ('n', 'no-status', None, _('hide status prefix')),
2960 ('n', 'no-status', None, _('hide status prefix')),
2959 ('C', 'copies', None, _('show source of copied files')),
2961 ('C', 'copies', None, _('show source of copied files')),
2960 ('0', 'print0', None,
2962 ('0', 'print0', None,
2961 _('end filenames with NUL, for use with xargs')),
2963 _('end filenames with NUL, for use with xargs')),
2962 ('', 'rev', [], _('show difference from revision')),
2964 ('', 'rev', [], _('show difference from revision')),
2963 ] + walkopts,
2965 ] + walkopts,
2964 _('hg status [OPTION]... [FILE]...')),
2966 _('hg status [OPTION]... [FILE]...')),
2965 "tag":
2967 "tag":
2966 (tag,
2968 (tag,
2967 [('f', 'force', None, _('replace existing tag')),
2969 [('f', 'force', None, _('replace existing tag')),
2968 ('l', 'local', None, _('make the tag local')),
2970 ('l', 'local', None, _('make the tag local')),
2969 ('m', 'message', '', _('message for tag commit log entry')),
2971 ('m', 'message', '', _('message for tag commit log entry')),
2970 ('d', 'date', '', _('record datecode as commit date')),
2972 ('d', 'date', '', _('record datecode as commit date')),
2971 ('u', 'user', '', _('record user as commiter')),
2973 ('u', 'user', '', _('record user as commiter')),
2972 ('r', 'rev', '', _('revision to tag')),
2974 ('r', 'rev', '', _('revision to tag')),
2973 ('', 'remove', None, _('remove a tag'))],
2975 ('', 'remove', None, _('remove a tag'))],
2974 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2976 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2975 "tags": (tags, [], _('hg tags')),
2977 "tags": (tags, [], _('hg tags')),
2976 "tip":
2978 "tip":
2977 (tip,
2979 (tip,
2978 [('', 'style', '', _('display using template map file')),
2980 [('', 'style', '', _('display using template map file')),
2979 ('p', 'patch', None, _('show patch')),
2981 ('p', 'patch', None, _('show patch')),
2980 ('', 'template', '', _('display with template'))],
2982 ('', 'template', '', _('display with template'))],
2981 _('hg tip [-p]')),
2983 _('hg tip [-p]')),
2982 "unbundle":
2984 "unbundle":
2983 (unbundle,
2985 (unbundle,
2984 [('u', 'update', None,
2986 [('u', 'update', None,
2985 _('update to new tip if changesets were unbundled'))],
2987 _('update to new tip if changesets were unbundled'))],
2986 _('hg unbundle [-u] FILE')),
2988 _('hg unbundle [-u] FILE')),
2987 "^update|up|checkout|co":
2989 "^update|up|checkout|co":
2988 (update,
2990 (update,
2989 [('C', 'clean', None, _('overwrite locally modified files')),
2991 [('C', 'clean', None, _('overwrite locally modified files')),
2990 ('d', 'date', '', _('tipmost revision matching date'))],
2992 ('d', 'date', '', _('tipmost revision matching date'))],
2991 _('hg update [-C] [-d DATE] [REV]')),
2993 _('hg update [-C] [-d DATE] [REV]')),
2992 "verify": (verify, [], _('hg verify')),
2994 "verify": (verify, [], _('hg verify')),
2993 "version": (version_, [], _('hg version')),
2995 "version": (version_, [], _('hg version')),
2994 }
2996 }
2995
2997
2996 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2998 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2997 " debugindex debugindexdot debugdate debuginstall")
2999 " debugindex debugindexdot debugdate debuginstall")
2998 optionalrepo = ("paths serve showconfig")
3000 optionalrepo = ("paths serve showconfig")
2999
3001
3000 def findpossible(ui, cmd):
3002 def findpossible(ui, cmd):
3001 """
3003 """
3002 Return cmd -> (aliases, command table entry)
3004 Return cmd -> (aliases, command table entry)
3003 for each matching command.
3005 for each matching command.
3004 Return debug commands (or their aliases) only if no normal command matches.
3006 Return debug commands (or their aliases) only if no normal command matches.
3005 """
3007 """
3006 choice = {}
3008 choice = {}
3007 debugchoice = {}
3009 debugchoice = {}
3008 for e in table.keys():
3010 for e in table.keys():
3009 aliases = e.lstrip("^").split("|")
3011 aliases = e.lstrip("^").split("|")
3010 found = None
3012 found = None
3011 if cmd in aliases:
3013 if cmd in aliases:
3012 found = cmd
3014 found = cmd
3013 elif not ui.config("ui", "strict"):
3015 elif not ui.config("ui", "strict"):
3014 for a in aliases:
3016 for a in aliases:
3015 if a.startswith(cmd):
3017 if a.startswith(cmd):
3016 found = a
3018 found = a
3017 break
3019 break
3018 if found is not None:
3020 if found is not None:
3019 if aliases[0].startswith("debug") or found.startswith("debug"):
3021 if aliases[0].startswith("debug") or found.startswith("debug"):
3020 debugchoice[found] = (aliases, table[e])
3022 debugchoice[found] = (aliases, table[e])
3021 else:
3023 else:
3022 choice[found] = (aliases, table[e])
3024 choice[found] = (aliases, table[e])
3023
3025
3024 if not choice and debugchoice:
3026 if not choice and debugchoice:
3025 choice = debugchoice
3027 choice = debugchoice
3026
3028
3027 return choice
3029 return choice
3028
3030
3029 def findcmd(ui, cmd):
3031 def findcmd(ui, cmd):
3030 """Return (aliases, command table entry) for command string."""
3032 """Return (aliases, command table entry) for command string."""
3031 choice = findpossible(ui, cmd)
3033 choice = findpossible(ui, cmd)
3032
3034
3033 if choice.has_key(cmd):
3035 if choice.has_key(cmd):
3034 return choice[cmd]
3036 return choice[cmd]
3035
3037
3036 if len(choice) > 1:
3038 if len(choice) > 1:
3037 clist = choice.keys()
3039 clist = choice.keys()
3038 clist.sort()
3040 clist.sort()
3039 raise AmbiguousCommand(cmd, clist)
3041 raise AmbiguousCommand(cmd, clist)
3040
3042
3041 if choice:
3043 if choice:
3042 return choice.values()[0]
3044 return choice.values()[0]
3043
3045
3044 raise UnknownCommand(cmd)
3046 raise UnknownCommand(cmd)
3045
3047
3046 def catchterm(*args):
3048 def catchterm(*args):
3047 raise util.SignalInterrupt
3049 raise util.SignalInterrupt
3048
3050
3049 def run():
3051 def run():
3050 sys.exit(dispatch(sys.argv[1:]))
3052 sys.exit(dispatch(sys.argv[1:]))
3051
3053
3052 class ParseError(Exception):
3054 class ParseError(Exception):
3053 """Exception raised on errors in parsing the command line."""
3055 """Exception raised on errors in parsing the command line."""
3054
3056
3055 def parse(ui, args):
3057 def parse(ui, args):
3056 options = {}
3058 options = {}
3057 cmdoptions = {}
3059 cmdoptions = {}
3058
3060
3059 try:
3061 try:
3060 args = fancyopts.fancyopts(args, globalopts, options)
3062 args = fancyopts.fancyopts(args, globalopts, options)
3061 except fancyopts.getopt.GetoptError, inst:
3063 except fancyopts.getopt.GetoptError, inst:
3062 raise ParseError(None, inst)
3064 raise ParseError(None, inst)
3063
3065
3064 if args:
3066 if args:
3065 cmd, args = args[0], args[1:]
3067 cmd, args = args[0], args[1:]
3066 aliases, i = findcmd(ui, cmd)
3068 aliases, i = findcmd(ui, cmd)
3067 cmd = aliases[0]
3069 cmd = aliases[0]
3068 defaults = ui.config("defaults", cmd)
3070 defaults = ui.config("defaults", cmd)
3069 if defaults:
3071 if defaults:
3070 args = shlex.split(defaults) + args
3072 args = shlex.split(defaults) + args
3071 c = list(i[1])
3073 c = list(i[1])
3072 else:
3074 else:
3073 cmd = None
3075 cmd = None
3074 c = []
3076 c = []
3075
3077
3076 # combine global options into local
3078 # combine global options into local
3077 for o in globalopts:
3079 for o in globalopts:
3078 c.append((o[0], o[1], options[o[1]], o[3]))
3080 c.append((o[0], o[1], options[o[1]], o[3]))
3079
3081
3080 try:
3082 try:
3081 args = fancyopts.fancyopts(args, c, cmdoptions)
3083 args = fancyopts.fancyopts(args, c, cmdoptions)
3082 except fancyopts.getopt.GetoptError, inst:
3084 except fancyopts.getopt.GetoptError, inst:
3083 raise ParseError(cmd, inst)
3085 raise ParseError(cmd, inst)
3084
3086
3085 # separate global options back out
3087 # separate global options back out
3086 for o in globalopts:
3088 for o in globalopts:
3087 n = o[1]
3089 n = o[1]
3088 options[n] = cmdoptions[n]
3090 options[n] = cmdoptions[n]
3089 del cmdoptions[n]
3091 del cmdoptions[n]
3090
3092
3091 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3093 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3092
3094
3093 external = {}
3095 external = {}
3094
3096
3095 def findext(name):
3097 def findext(name):
3096 '''return module with given extension name'''
3098 '''return module with given extension name'''
3097 try:
3099 try:
3098 return sys.modules[external[name]]
3100 return sys.modules[external[name]]
3099 except KeyError:
3101 except KeyError:
3100 for k, v in external.iteritems():
3102 for k, v in external.iteritems():
3101 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3103 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3102 return sys.modules[v]
3104 return sys.modules[v]
3103 raise KeyError(name)
3105 raise KeyError(name)
3104
3106
3105 def load_extensions(ui):
3107 def load_extensions(ui):
3106 added = []
3108 added = []
3107 for ext_name, load_from_name in ui.extensions():
3109 for ext_name, load_from_name in ui.extensions():
3108 if ext_name in external:
3110 if ext_name in external:
3109 continue
3111 continue
3110 try:
3112 try:
3111 if load_from_name:
3113 if load_from_name:
3112 # the module will be loaded in sys.modules
3114 # the module will be loaded in sys.modules
3113 # choose an unique name so that it doesn't
3115 # choose an unique name so that it doesn't
3114 # conflicts with other modules
3116 # conflicts with other modules
3115 module_name = "hgext_%s" % ext_name.replace('.', '_')
3117 module_name = "hgext_%s" % ext_name.replace('.', '_')
3116 mod = imp.load_source(module_name, load_from_name)
3118 mod = imp.load_source(module_name, load_from_name)
3117 else:
3119 else:
3118 def importh(name):
3120 def importh(name):
3119 mod = __import__(name)
3121 mod = __import__(name)
3120 components = name.split('.')
3122 components = name.split('.')
3121 for comp in components[1:]:
3123 for comp in components[1:]:
3122 mod = getattr(mod, comp)
3124 mod = getattr(mod, comp)
3123 return mod
3125 return mod
3124 try:
3126 try:
3125 mod = importh("hgext.%s" % ext_name)
3127 mod = importh("hgext.%s" % ext_name)
3126 except ImportError:
3128 except ImportError:
3127 mod = importh(ext_name)
3129 mod = importh(ext_name)
3128 external[ext_name] = mod.__name__
3130 external[ext_name] = mod.__name__
3129 added.append((mod, ext_name))
3131 added.append((mod, ext_name))
3130 except (util.SignalInterrupt, KeyboardInterrupt):
3132 except (util.SignalInterrupt, KeyboardInterrupt):
3131 raise
3133 raise
3132 except Exception, inst:
3134 except Exception, inst:
3133 ui.warn(_("*** failed to import extension %s: %s\n") %
3135 ui.warn(_("*** failed to import extension %s: %s\n") %
3134 (ext_name, inst))
3136 (ext_name, inst))
3135 if ui.print_exc():
3137 if ui.print_exc():
3136 return 1
3138 return 1
3137
3139
3138 for mod, name in added:
3140 for mod, name in added:
3139 uisetup = getattr(mod, 'uisetup', None)
3141 uisetup = getattr(mod, 'uisetup', None)
3140 if uisetup:
3142 if uisetup:
3141 uisetup(ui)
3143 uisetup(ui)
3142 reposetup = getattr(mod, 'reposetup', None)
3144 reposetup = getattr(mod, 'reposetup', None)
3143 if reposetup:
3145 if reposetup:
3144 hg.repo_setup_hooks.append(reposetup)
3146 hg.repo_setup_hooks.append(reposetup)
3145 cmdtable = getattr(mod, 'cmdtable', {})
3147 cmdtable = getattr(mod, 'cmdtable', {})
3146 overrides = [cmd for cmd in cmdtable if cmd in table]
3148 overrides = [cmd for cmd in cmdtable if cmd in table]
3147 if overrides:
3149 if overrides:
3148 ui.warn(_("extension '%s' overrides commands: %s\n")
3150 ui.warn(_("extension '%s' overrides commands: %s\n")
3149 % (name, " ".join(overrides)))
3151 % (name, " ".join(overrides)))
3150 table.update(cmdtable)
3152 table.update(cmdtable)
3151
3153
3152 def parseconfig(config):
3154 def parseconfig(config):
3153 """parse the --config options from the command line"""
3155 """parse the --config options from the command line"""
3154 parsed = []
3156 parsed = []
3155 for cfg in config:
3157 for cfg in config:
3156 try:
3158 try:
3157 name, value = cfg.split('=', 1)
3159 name, value = cfg.split('=', 1)
3158 section, name = name.split('.', 1)
3160 section, name = name.split('.', 1)
3159 if not section or not name:
3161 if not section or not name:
3160 raise IndexError
3162 raise IndexError
3161 parsed.append((section, name, value))
3163 parsed.append((section, name, value))
3162 except (IndexError, ValueError):
3164 except (IndexError, ValueError):
3163 raise util.Abort(_('malformed --config option: %s') % cfg)
3165 raise util.Abort(_('malformed --config option: %s') % cfg)
3164 return parsed
3166 return parsed
3165
3167
3166 def dispatch(args):
3168 def dispatch(args):
3167 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3169 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3168 num = getattr(signal, name, None)
3170 num = getattr(signal, name, None)
3169 if num: signal.signal(num, catchterm)
3171 if num: signal.signal(num, catchterm)
3170
3172
3171 try:
3173 try:
3172 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3174 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3173 except util.Abort, inst:
3175 except util.Abort, inst:
3174 sys.stderr.write(_("abort: %s\n") % inst)
3176 sys.stderr.write(_("abort: %s\n") % inst)
3175 return -1
3177 return -1
3176
3178
3177 load_extensions(u)
3179 load_extensions(u)
3178 u.addreadhook(load_extensions)
3180 u.addreadhook(load_extensions)
3179
3181
3180 try:
3182 try:
3181 cmd, func, args, options, cmdoptions = parse(u, args)
3183 cmd, func, args, options, cmdoptions = parse(u, args)
3182 if options["encoding"]:
3184 if options["encoding"]:
3183 util._encoding = options["encoding"]
3185 util._encoding = options["encoding"]
3184 if options["encodingmode"]:
3186 if options["encodingmode"]:
3185 util._encodingmode = options["encodingmode"]
3187 util._encodingmode = options["encodingmode"]
3186 if options["time"]:
3188 if options["time"]:
3187 def get_times():
3189 def get_times():
3188 t = os.times()
3190 t = os.times()
3189 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3191 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3190 t = (t[0], t[1], t[2], t[3], time.clock())
3192 t = (t[0], t[1], t[2], t[3], time.clock())
3191 return t
3193 return t
3192 s = get_times()
3194 s = get_times()
3193 def print_time():
3195 def print_time():
3194 t = get_times()
3196 t = get_times()
3195 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3197 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3196 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3198 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3197 atexit.register(print_time)
3199 atexit.register(print_time)
3198
3200
3199 # enter the debugger before command execution
3201 # enter the debugger before command execution
3200 if options['debugger']:
3202 if options['debugger']:
3201 pdb.set_trace()
3203 pdb.set_trace()
3202
3204
3203 try:
3205 try:
3204 if options['cwd']:
3206 if options['cwd']:
3205 os.chdir(options['cwd'])
3207 os.chdir(options['cwd'])
3206
3208
3207 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3209 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3208 not options["noninteractive"], options["traceback"],
3210 not options["noninteractive"], options["traceback"],
3209 parseconfig(options["config"]))
3211 parseconfig(options["config"]))
3210
3212
3211 path = u.expandpath(options["repository"]) or ""
3213 path = u.expandpath(options["repository"]) or ""
3212 repo = path and hg.repository(u, path=path) or None
3214 repo = path and hg.repository(u, path=path) or None
3213 if repo and not repo.local():
3215 if repo and not repo.local():
3214 raise util.Abort(_("repository '%s' is not local") % path)
3216 raise util.Abort(_("repository '%s' is not local") % path)
3215
3217
3216 if options['help']:
3218 if options['help']:
3217 return help_(u, cmd, options['version'])
3219 return help_(u, cmd, options['version'])
3218 elif options['version']:
3220 elif options['version']:
3219 return version_(u)
3221 return version_(u)
3220 elif not cmd:
3222 elif not cmd:
3221 return help_(u, 'shortlist')
3223 return help_(u, 'shortlist')
3222
3224
3223 if cmd not in norepo.split():
3225 if cmd not in norepo.split():
3224 try:
3226 try:
3225 if not repo:
3227 if not repo:
3226 repo = hg.repository(u, path=path)
3228 repo = hg.repository(u, path=path)
3227 u = repo.ui
3229 u = repo.ui
3228 except hg.RepoError:
3230 except hg.RepoError:
3229 if cmd not in optionalrepo.split():
3231 if cmd not in optionalrepo.split():
3230 raise
3232 raise
3231 d = lambda: func(u, repo, *args, **cmdoptions)
3233 d = lambda: func(u, repo, *args, **cmdoptions)
3232 else:
3234 else:
3233 d = lambda: func(u, *args, **cmdoptions)
3235 d = lambda: func(u, *args, **cmdoptions)
3234
3236
3235 try:
3237 try:
3236 if options['profile']:
3238 if options['profile']:
3237 import hotshot, hotshot.stats
3239 import hotshot, hotshot.stats
3238 prof = hotshot.Profile("hg.prof")
3240 prof = hotshot.Profile("hg.prof")
3239 try:
3241 try:
3240 try:
3242 try:
3241 return prof.runcall(d)
3243 return prof.runcall(d)
3242 except:
3244 except:
3243 try:
3245 try:
3244 u.warn(_('exception raised - generating '
3246 u.warn(_('exception raised - generating '
3245 'profile anyway\n'))
3247 'profile anyway\n'))
3246 except:
3248 except:
3247 pass
3249 pass
3248 raise
3250 raise
3249 finally:
3251 finally:
3250 prof.close()
3252 prof.close()
3251 stats = hotshot.stats.load("hg.prof")
3253 stats = hotshot.stats.load("hg.prof")
3252 stats.strip_dirs()
3254 stats.strip_dirs()
3253 stats.sort_stats('time', 'calls')
3255 stats.sort_stats('time', 'calls')
3254 stats.print_stats(40)
3256 stats.print_stats(40)
3255 elif options['lsprof']:
3257 elif options['lsprof']:
3256 try:
3258 try:
3257 from mercurial import lsprof
3259 from mercurial import lsprof
3258 except ImportError:
3260 except ImportError:
3259 raise util.Abort(_(
3261 raise util.Abort(_(
3260 'lsprof not available - install from '
3262 'lsprof not available - install from '
3261 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3263 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3262 p = lsprof.Profiler()
3264 p = lsprof.Profiler()
3263 p.enable(subcalls=True)
3265 p.enable(subcalls=True)
3264 try:
3266 try:
3265 return d()
3267 return d()
3266 finally:
3268 finally:
3267 p.disable()
3269 p.disable()
3268 stats = lsprof.Stats(p.getstats())
3270 stats = lsprof.Stats(p.getstats())
3269 stats.sort()
3271 stats.sort()
3270 stats.pprint(top=10, file=sys.stderr, climit=5)
3272 stats.pprint(top=10, file=sys.stderr, climit=5)
3271 else:
3273 else:
3272 return d()
3274 return d()
3273 finally:
3275 finally:
3274 u.flush()
3276 u.flush()
3275 except:
3277 except:
3276 # enter the debugger when we hit an exception
3278 # enter the debugger when we hit an exception
3277 if options['debugger']:
3279 if options['debugger']:
3278 pdb.post_mortem(sys.exc_info()[2])
3280 pdb.post_mortem(sys.exc_info()[2])
3279 u.print_exc()
3281 u.print_exc()
3280 raise
3282 raise
3281 except ParseError, inst:
3283 except ParseError, inst:
3282 if inst.args[0]:
3284 if inst.args[0]:
3283 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3285 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3284 help_(u, inst.args[0])
3286 help_(u, inst.args[0])
3285 else:
3287 else:
3286 u.warn(_("hg: %s\n") % inst.args[1])
3288 u.warn(_("hg: %s\n") % inst.args[1])
3287 help_(u, 'shortlist')
3289 help_(u, 'shortlist')
3288 except AmbiguousCommand, inst:
3290 except AmbiguousCommand, inst:
3289 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3291 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3290 (inst.args[0], " ".join(inst.args[1])))
3292 (inst.args[0], " ".join(inst.args[1])))
3291 except UnknownCommand, inst:
3293 except UnknownCommand, inst:
3292 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3294 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3293 help_(u, 'shortlist')
3295 help_(u, 'shortlist')
3294 except hg.RepoError, inst:
3296 except hg.RepoError, inst:
3295 u.warn(_("abort: %s!\n") % inst)
3297 u.warn(_("abort: %s!\n") % inst)
3296 except lock.LockHeld, inst:
3298 except lock.LockHeld, inst:
3297 if inst.errno == errno.ETIMEDOUT:
3299 if inst.errno == errno.ETIMEDOUT:
3298 reason = _('timed out waiting for lock held by %s') % inst.locker
3300 reason = _('timed out waiting for lock held by %s') % inst.locker
3299 else:
3301 else:
3300 reason = _('lock held by %s') % inst.locker
3302 reason = _('lock held by %s') % inst.locker
3301 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3303 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3302 except lock.LockUnavailable, inst:
3304 except lock.LockUnavailable, inst:
3303 u.warn(_("abort: could not lock %s: %s\n") %
3305 u.warn(_("abort: could not lock %s: %s\n") %
3304 (inst.desc or inst.filename, inst.strerror))
3306 (inst.desc or inst.filename, inst.strerror))
3305 except revlog.RevlogError, inst:
3307 except revlog.RevlogError, inst:
3306 u.warn(_("abort: %s!\n") % inst)
3308 u.warn(_("abort: %s!\n") % inst)
3307 except util.SignalInterrupt:
3309 except util.SignalInterrupt:
3308 u.warn(_("killed!\n"))
3310 u.warn(_("killed!\n"))
3309 except KeyboardInterrupt:
3311 except KeyboardInterrupt:
3310 try:
3312 try:
3311 u.warn(_("interrupted!\n"))
3313 u.warn(_("interrupted!\n"))
3312 except IOError, inst:
3314 except IOError, inst:
3313 if inst.errno == errno.EPIPE:
3315 if inst.errno == errno.EPIPE:
3314 if u.debugflag:
3316 if u.debugflag:
3315 u.warn(_("\nbroken pipe\n"))
3317 u.warn(_("\nbroken pipe\n"))
3316 else:
3318 else:
3317 raise
3319 raise
3318 except socket.error, inst:
3320 except socket.error, inst:
3319 u.warn(_("abort: %s\n") % inst[1])
3321 u.warn(_("abort: %s\n") % inst[1])
3320 except IOError, inst:
3322 except IOError, inst:
3321 if hasattr(inst, "code"):
3323 if hasattr(inst, "code"):
3322 u.warn(_("abort: %s\n") % inst)
3324 u.warn(_("abort: %s\n") % inst)
3323 elif hasattr(inst, "reason"):
3325 elif hasattr(inst, "reason"):
3324 try: # usually it is in the form (errno, strerror)
3326 try: # usually it is in the form (errno, strerror)
3325 reason = inst.reason.args[1]
3327 reason = inst.reason.args[1]
3326 except: # it might be anything, for example a string
3328 except: # it might be anything, for example a string
3327 reason = inst.reason
3329 reason = inst.reason
3328 u.warn(_("abort: error: %s\n") % reason)
3330 u.warn(_("abort: error: %s\n") % reason)
3329 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3331 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3330 if u.debugflag:
3332 if u.debugflag:
3331 u.warn(_("broken pipe\n"))
3333 u.warn(_("broken pipe\n"))
3332 elif getattr(inst, "strerror", None):
3334 elif getattr(inst, "strerror", None):
3333 if getattr(inst, "filename", None):
3335 if getattr(inst, "filename", None):
3334 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3336 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3335 else:
3337 else:
3336 u.warn(_("abort: %s\n") % inst.strerror)
3338 u.warn(_("abort: %s\n") % inst.strerror)
3337 else:
3339 else:
3338 raise
3340 raise
3339 except OSError, inst:
3341 except OSError, inst:
3340 if getattr(inst, "filename", None):
3342 if getattr(inst, "filename", None):
3341 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3343 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3342 else:
3344 else:
3343 u.warn(_("abort: %s\n") % inst.strerror)
3345 u.warn(_("abort: %s\n") % inst.strerror)
3344 except util.UnexpectedOutput, inst:
3346 except util.UnexpectedOutput, inst:
3345 u.warn(_("abort: %s") % inst[0])
3347 u.warn(_("abort: %s") % inst[0])
3346 if not isinstance(inst[1], basestring):
3348 if not isinstance(inst[1], basestring):
3347 u.warn(" %r\n" % (inst[1],))
3349 u.warn(" %r\n" % (inst[1],))
3348 elif not inst[1]:
3350 elif not inst[1]:
3349 u.warn(_(" empty string\n"))
3351 u.warn(_(" empty string\n"))
3350 else:
3352 else:
3351 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3353 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3352 except util.Abort, inst:
3354 except util.Abort, inst:
3353 u.warn(_("abort: %s\n") % inst)
3355 u.warn(_("abort: %s\n") % inst)
3354 except TypeError, inst:
3356 except TypeError, inst:
3355 # was this an argument error?
3357 # was this an argument error?
3356 tb = traceback.extract_tb(sys.exc_info()[2])
3358 tb = traceback.extract_tb(sys.exc_info()[2])
3357 if len(tb) > 2: # no
3359 if len(tb) > 2: # no
3358 raise
3360 raise
3359 u.debug(inst, "\n")
3361 u.debug(inst, "\n")
3360 u.warn(_("%s: invalid arguments\n") % cmd)
3362 u.warn(_("%s: invalid arguments\n") % cmd)
3361 help_(u, cmd)
3363 help_(u, cmd)
3362 except SystemExit, inst:
3364 except SystemExit, inst:
3363 # Commands shouldn't sys.exit directly, but give a return code.
3365 # Commands shouldn't sys.exit directly, but give a return code.
3364 # Just in case catch this and and pass exit code to caller.
3366 # Just in case catch this and and pass exit code to caller.
3365 return inst.code
3367 return inst.code
3366 except:
3368 except:
3367 u.warn(_("** unknown exception encountered, details follow\n"))
3369 u.warn(_("** unknown exception encountered, details follow\n"))
3368 u.warn(_("** report bug details to "
3370 u.warn(_("** report bug details to "
3369 "http://www.selenic.com/mercurial/bts\n"))
3371 "http://www.selenic.com/mercurial/bts\n"))
3370 u.warn(_("** or mercurial@selenic.com\n"))
3372 u.warn(_("** or mercurial@selenic.com\n"))
3371 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3373 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3372 % version.get_version())
3374 % version.get_version())
3373 raise
3375 raise
3374
3376
3375 return -1
3377 return -1
@@ -1,661 +1,663 b''
1 # patch.py - patch file parsing routines
1 # patch.py - patch file parsing routines
2 #
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006 Brendan Cully <brendan@kublai.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 i18n import _
8 from i18n import _
9 from node import *
9 from node import *
10 import base85, cmdutil, mdiff, util, context, revlog
10 import base85, cmdutil, mdiff, util, context, revlog
11 import cStringIO, email.Parser, os, popen2, re, sha
11 import cStringIO, email.Parser, os, popen2, re, sha
12 import sys, tempfile, zlib
12 import sys, tempfile, zlib
13
13
14 # helper functions
14 # helper functions
15
15
16 def copyfile(src, dst, basedir=None):
16 def copyfile(src, dst, basedir=None):
17 if not basedir:
17 if not basedir:
18 basedir = os.getcwd()
18 basedir = os.getcwd()
19
19
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
20 abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
21 if os.path.exists(absdst):
21 if os.path.exists(absdst):
22 raise util.Abort(_("cannot create %s: destination already exists") %
22 raise util.Abort(_("cannot create %s: destination already exists") %
23 dst)
23 dst)
24
24
25 targetdir = os.path.dirname(absdst)
25 targetdir = os.path.dirname(absdst)
26 if not os.path.isdir(targetdir):
26 if not os.path.isdir(targetdir):
27 os.makedirs(targetdir)
27 os.makedirs(targetdir)
28
28
29 util.copyfile(abssrc, absdst)
29 util.copyfile(abssrc, absdst)
30
30
31 # public functions
31 # public functions
32
32
33 def extract(ui, fileobj):
33 def extract(ui, fileobj):
34 '''extract patch from data read from fileobj.
34 '''extract patch from data read from fileobj.
35
35
36 patch can be a normal patch or contained in an email message.
36 patch can be a normal patch or contained in an email message.
37
37
38 return tuple (filename, message, user, date, node, p1, p2).
38 return tuple (filename, message, user, date, node, p1, p2).
39 Any item in the returned tuple can be None. If filename is None,
39 Any item in the returned tuple can be None. If filename is None,
40 fileobj did not contain a patch. Caller must unlink filename when done.'''
40 fileobj did not contain a patch. Caller must unlink filename when done.'''
41
41
42 # attempt to detect the start of a patch
42 # attempt to detect the start of a patch
43 # (this heuristic is borrowed from quilt)
43 # (this heuristic is borrowed from quilt)
44 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
44 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
45 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
45 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
46 '(---|\*\*\*)[ \t])', re.MULTILINE)
46 '(---|\*\*\*)[ \t])', re.MULTILINE)
47
47
48 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
48 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
49 tmpfp = os.fdopen(fd, 'w')
49 tmpfp = os.fdopen(fd, 'w')
50 try:
50 try:
51 msg = email.Parser.Parser().parse(fileobj)
51 msg = email.Parser.Parser().parse(fileobj)
52
52
53 message = msg['Subject']
53 message = msg['Subject']
54 user = msg['From']
54 user = msg['From']
55 # should try to parse msg['Date']
55 # should try to parse msg['Date']
56 date = None
56 date = None
57 nodeid = None
57 nodeid = None
58 parents = []
58 parents = []
59
59
60 if message:
60 if message:
61 if message.startswith('[PATCH'):
61 if message.startswith('[PATCH'):
62 pend = message.find(']')
62 pend = message.find(']')
63 if pend >= 0:
63 if pend >= 0:
64 message = message[pend+1:].lstrip()
64 message = message[pend+1:].lstrip()
65 message = message.replace('\n\t', ' ')
65 message = message.replace('\n\t', ' ')
66 ui.debug('Subject: %s\n' % message)
66 ui.debug('Subject: %s\n' % message)
67 if user:
67 if user:
68 ui.debug('From: %s\n' % user)
68 ui.debug('From: %s\n' % user)
69 diffs_seen = 0
69 diffs_seen = 0
70 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
70 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
71
71
72 for part in msg.walk():
72 for part in msg.walk():
73 content_type = part.get_content_type()
73 content_type = part.get_content_type()
74 ui.debug('Content-Type: %s\n' % content_type)
74 ui.debug('Content-Type: %s\n' % content_type)
75 if content_type not in ok_types:
75 if content_type not in ok_types:
76 continue
76 continue
77 payload = part.get_payload(decode=True)
77 payload = part.get_payload(decode=True)
78 m = diffre.search(payload)
78 m = diffre.search(payload)
79 if m:
79 if m:
80 hgpatch = False
80 hgpatch = False
81 ignoretext = False
81 ignoretext = False
82
82
83 ui.debug(_('found patch at byte %d\n') % m.start(0))
83 ui.debug(_('found patch at byte %d\n') % m.start(0))
84 diffs_seen += 1
84 diffs_seen += 1
85 cfp = cStringIO.StringIO()
85 cfp = cStringIO.StringIO()
86 if message:
86 if message:
87 cfp.write(message)
87 cfp.write(message)
88 cfp.write('\n')
88 cfp.write('\n')
89 for line in payload[:m.start(0)].splitlines():
89 for line in payload[:m.start(0)].splitlines():
90 if line.startswith('# HG changeset patch'):
90 if line.startswith('# HG changeset patch'):
91 ui.debug(_('patch generated by hg export\n'))
91 ui.debug(_('patch generated by hg export\n'))
92 hgpatch = True
92 hgpatch = True
93 # drop earlier commit message content
93 # drop earlier commit message content
94 cfp.seek(0)
94 cfp.seek(0)
95 cfp.truncate()
95 cfp.truncate()
96 elif hgpatch:
96 elif hgpatch:
97 if line.startswith('# User '):
97 if line.startswith('# User '):
98 user = line[7:]
98 user = line[7:]
99 ui.debug('From: %s\n' % user)
99 ui.debug('From: %s\n' % user)
100 elif line.startswith("# Date "):
100 elif line.startswith("# Date "):
101 date = line[7:]
101 date = line[7:]
102 elif line.startswith("# Node ID "):
102 elif line.startswith("# Node ID "):
103 nodeid = line[10:]
103 nodeid = line[10:]
104 elif line.startswith("# Parent "):
104 elif line.startswith("# Parent "):
105 parents.append(line[10:])
105 parents.append(line[10:])
106 elif line == '---' and 'git-send-email' in msg['X-Mailer']:
106 elif line == '---' and 'git-send-email' in msg['X-Mailer']:
107 ignoretext = True
107 ignoretext = True
108 if not line.startswith('# ') and not ignoretext:
108 if not line.startswith('# ') and not ignoretext:
109 cfp.write(line)
109 cfp.write(line)
110 cfp.write('\n')
110 cfp.write('\n')
111 message = cfp.getvalue()
111 message = cfp.getvalue()
112 if tmpfp:
112 if tmpfp:
113 tmpfp.write(payload)
113 tmpfp.write(payload)
114 if not payload.endswith('\n'):
114 if not payload.endswith('\n'):
115 tmpfp.write('\n')
115 tmpfp.write('\n')
116 elif not diffs_seen and message and content_type == 'text/plain':
116 elif not diffs_seen and message and content_type == 'text/plain':
117 message += '\n' + payload
117 message += '\n' + payload
118 except:
118 except:
119 tmpfp.close()
119 tmpfp.close()
120 os.unlink(tmpname)
120 os.unlink(tmpname)
121 raise
121 raise
122
122
123 tmpfp.close()
123 tmpfp.close()
124 if not diffs_seen:
124 if not diffs_seen:
125 os.unlink(tmpname)
125 os.unlink(tmpname)
126 return None, message, user, date, None, None, None
126 return None, message, user, date, None, None, None
127 p1 = parents and parents.pop(0) or None
127 p1 = parents and parents.pop(0) or None
128 p2 = parents and parents.pop(0) or None
128 p2 = parents and parents.pop(0) or None
129 return tmpname, message, user, date, nodeid, p1, p2
129 return tmpname, message, user, date, nodeid, p1, p2
130
130
131 GP_PATCH = 1 << 0 # we have to run patch
131 GP_PATCH = 1 << 0 # we have to run patch
132 GP_FILTER = 1 << 1 # there's some copy/rename operation
132 GP_FILTER = 1 << 1 # there's some copy/rename operation
133 GP_BINARY = 1 << 2 # there's a binary patch
133 GP_BINARY = 1 << 2 # there's a binary patch
134
134
135 def readgitpatch(patchname):
135 def readgitpatch(patchname):
136 """extract git-style metadata about patches from <patchname>"""
136 """extract git-style metadata about patches from <patchname>"""
137 class gitpatch:
137 class gitpatch:
138 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
138 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
139 def __init__(self, path):
139 def __init__(self, path):
140 self.path = path
140 self.path = path
141 self.oldpath = None
141 self.oldpath = None
142 self.mode = None
142 self.mode = None
143 self.op = 'MODIFY'
143 self.op = 'MODIFY'
144 self.copymod = False
144 self.copymod = False
145 self.lineno = 0
145 self.lineno = 0
146 self.binary = False
146 self.binary = False
147
147
148 # Filter patch for git information
148 # Filter patch for git information
149 gitre = re.compile('diff --git a/(.*) b/(.*)')
149 gitre = re.compile('diff --git a/(.*) b/(.*)')
150 pf = file(patchname)
150 pf = file(patchname)
151 gp = None
151 gp = None
152 gitpatches = []
152 gitpatches = []
153 # Can have a git patch with only metadata, causing patch to complain
153 # Can have a git patch with only metadata, causing patch to complain
154 dopatch = 0
154 dopatch = 0
155
155
156 lineno = 0
156 lineno = 0
157 for line in pf:
157 for line in pf:
158 lineno += 1
158 lineno += 1
159 if line.startswith('diff --git'):
159 if line.startswith('diff --git'):
160 m = gitre.match(line)
160 m = gitre.match(line)
161 if m:
161 if m:
162 if gp:
162 if gp:
163 gitpatches.append(gp)
163 gitpatches.append(gp)
164 src, dst = m.group(1, 2)
164 src, dst = m.group(1, 2)
165 gp = gitpatch(dst)
165 gp = gitpatch(dst)
166 gp.lineno = lineno
166 gp.lineno = lineno
167 elif gp:
167 elif gp:
168 if line.startswith('--- '):
168 if line.startswith('--- '):
169 if gp.op in ('COPY', 'RENAME'):
169 if gp.op in ('COPY', 'RENAME'):
170 gp.copymod = True
170 gp.copymod = True
171 dopatch |= GP_FILTER
171 dopatch |= GP_FILTER
172 gitpatches.append(gp)
172 gitpatches.append(gp)
173 gp = None
173 gp = None
174 dopatch |= GP_PATCH
174 dopatch |= GP_PATCH
175 continue
175 continue
176 if line.startswith('rename from '):
176 if line.startswith('rename from '):
177 gp.op = 'RENAME'
177 gp.op = 'RENAME'
178 gp.oldpath = line[12:].rstrip()
178 gp.oldpath = line[12:].rstrip()
179 elif line.startswith('rename to '):
179 elif line.startswith('rename to '):
180 gp.path = line[10:].rstrip()
180 gp.path = line[10:].rstrip()
181 elif line.startswith('copy from '):
181 elif line.startswith('copy from '):
182 gp.op = 'COPY'
182 gp.op = 'COPY'
183 gp.oldpath = line[10:].rstrip()
183 gp.oldpath = line[10:].rstrip()
184 elif line.startswith('copy to '):
184 elif line.startswith('copy to '):
185 gp.path = line[8:].rstrip()
185 gp.path = line[8:].rstrip()
186 elif line.startswith('deleted file'):
186 elif line.startswith('deleted file'):
187 gp.op = 'DELETE'
187 gp.op = 'DELETE'
188 elif line.startswith('new file mode '):
188 elif line.startswith('new file mode '):
189 gp.op = 'ADD'
189 gp.op = 'ADD'
190 gp.mode = int(line.rstrip()[-3:], 8)
190 gp.mode = int(line.rstrip()[-3:], 8)
191 elif line.startswith('new mode '):
191 elif line.startswith('new mode '):
192 gp.mode = int(line.rstrip()[-3:], 8)
192 gp.mode = int(line.rstrip()[-3:], 8)
193 elif line.startswith('GIT binary patch'):
193 elif line.startswith('GIT binary patch'):
194 dopatch |= GP_BINARY
194 dopatch |= GP_BINARY
195 gp.binary = True
195 gp.binary = True
196 if gp:
196 if gp:
197 gitpatches.append(gp)
197 gitpatches.append(gp)
198
198
199 if not gitpatches:
199 if not gitpatches:
200 dopatch = GP_PATCH
200 dopatch = GP_PATCH
201
201
202 return (dopatch, gitpatches)
202 return (dopatch, gitpatches)
203
203
204 def dogitpatch(patchname, gitpatches, cwd=None):
204 def dogitpatch(patchname, gitpatches, cwd=None):
205 """Preprocess git patch so that vanilla patch can handle it"""
205 """Preprocess git patch so that vanilla patch can handle it"""
206 def extractbin(fp):
206 def extractbin(fp):
207 i = [0] # yuck
207 i = [0] # yuck
208 def readline():
208 def readline():
209 i[0] += 1
209 i[0] += 1
210 return fp.readline().rstrip()
210 return fp.readline().rstrip()
211 line = readline()
211 line = readline()
212 while line and not line.startswith('literal '):
212 while line and not line.startswith('literal '):
213 line = readline()
213 line = readline()
214 if not line:
214 if not line:
215 return None, i[0]
215 return None, i[0]
216 size = int(line[8:])
216 size = int(line[8:])
217 dec = []
217 dec = []
218 line = readline()
218 line = readline()
219 while line:
219 while line:
220 l = line[0]
220 l = line[0]
221 if l <= 'Z' and l >= 'A':
221 if l <= 'Z' and l >= 'A':
222 l = ord(l) - ord('A') + 1
222 l = ord(l) - ord('A') + 1
223 else:
223 else:
224 l = ord(l) - ord('a') + 27
224 l = ord(l) - ord('a') + 27
225 dec.append(base85.b85decode(line[1:])[:l])
225 dec.append(base85.b85decode(line[1:])[:l])
226 line = readline()
226 line = readline()
227 text = zlib.decompress(''.join(dec))
227 text = zlib.decompress(''.join(dec))
228 if len(text) != size:
228 if len(text) != size:
229 raise util.Abort(_('binary patch is %d bytes, not %d') %
229 raise util.Abort(_('binary patch is %d bytes, not %d') %
230 (len(text), size))
230 (len(text), size))
231 return text, i[0]
231 return text, i[0]
232
232
233 pf = file(patchname)
233 pf = file(patchname)
234 pfline = 1
234 pfline = 1
235
235
236 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
236 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
237 tmpfp = os.fdopen(fd, 'w')
237 tmpfp = os.fdopen(fd, 'w')
238
238
239 try:
239 try:
240 for i in xrange(len(gitpatches)):
240 for i in xrange(len(gitpatches)):
241 p = gitpatches[i]
241 p = gitpatches[i]
242 if not p.copymod and not p.binary:
242 if not p.copymod and not p.binary:
243 continue
243 continue
244
244
245 # rewrite patch hunk
245 # rewrite patch hunk
246 while pfline < p.lineno:
246 while pfline < p.lineno:
247 tmpfp.write(pf.readline())
247 tmpfp.write(pf.readline())
248 pfline += 1
248 pfline += 1
249
249
250 if p.binary:
250 if p.binary:
251 text, delta = extractbin(pf)
251 text, delta = extractbin(pf)
252 if not text:
252 if not text:
253 raise util.Abort(_('binary patch extraction failed'))
253 raise util.Abort(_('binary patch extraction failed'))
254 pfline += delta
254 pfline += delta
255 if not cwd:
255 if not cwd:
256 cwd = os.getcwd()
256 cwd = os.getcwd()
257 absdst = os.path.join(cwd, p.path)
257 absdst = os.path.join(cwd, p.path)
258 basedir = os.path.dirname(absdst)
258 basedir = os.path.dirname(absdst)
259 if not os.path.isdir(basedir):
259 if not os.path.isdir(basedir):
260 os.makedirs(basedir)
260 os.makedirs(basedir)
261 out = file(absdst, 'wb')
261 out = file(absdst, 'wb')
262 out.write(text)
262 out.write(text)
263 out.close()
263 out.close()
264 elif p.copymod:
264 elif p.copymod:
265 copyfile(p.oldpath, p.path, basedir=cwd)
265 copyfile(p.oldpath, p.path, basedir=cwd)
266 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
266 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
267 line = pf.readline()
267 line = pf.readline()
268 pfline += 1
268 pfline += 1
269 while not line.startswith('--- a/'):
269 while not line.startswith('--- a/'):
270 tmpfp.write(line)
270 tmpfp.write(line)
271 line = pf.readline()
271 line = pf.readline()
272 pfline += 1
272 pfline += 1
273 tmpfp.write('--- a/%s\n' % p.path)
273 tmpfp.write('--- a/%s\n' % p.path)
274
274
275 line = pf.readline()
275 line = pf.readline()
276 while line:
276 while line:
277 tmpfp.write(line)
277 tmpfp.write(line)
278 line = pf.readline()
278 line = pf.readline()
279 except:
279 except:
280 tmpfp.close()
280 tmpfp.close()
281 os.unlink(patchname)
281 os.unlink(patchname)
282 raise
282 raise
283
283
284 tmpfp.close()
284 tmpfp.close()
285 return patchname
285 return patchname
286
286
287 def patch(patchname, ui, strip=1, cwd=None, files={}):
287 def patch(patchname, ui, strip=1, cwd=None, files={}):
288 """apply the patch <patchname> to the working directory.
288 """apply the patch <patchname> to the working directory.
289 a list of patched files is returned"""
289 a list of patched files is returned"""
290
290
291 # helper function
291 # helper function
292 def __patch(patchname):
292 def __patch(patchname):
293 """patch and updates the files and fuzz variables"""
293 """patch and updates the files and fuzz variables"""
294 fuzz = False
294 fuzz = False
295
295
296 patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''),
297 'patch')
298 args = []
296 args = []
299 if util.needbinarypatch():
297 patcher = ui.config('ui', 'patch')
300 args.append('--binary')
298 if not patcher:
299 patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''),
300 'patch')
301 if util.needbinarypatch():
302 args.append('--binary')
301
303
302 if cwd:
304 if cwd:
303 args.append('-d %s' % util.shellquote(cwd))
305 args.append('-d %s' % util.shellquote(cwd))
304 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
306 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
305 util.shellquote(patchname)))
307 util.shellquote(patchname)))
306
308
307 for line in fp:
309 for line in fp:
308 line = line.rstrip()
310 line = line.rstrip()
309 ui.note(line + '\n')
311 ui.note(line + '\n')
310 if line.startswith('patching file '):
312 if line.startswith('patching file '):
311 pf = util.parse_patch_output(line)
313 pf = util.parse_patch_output(line)
312 printed_file = False
314 printed_file = False
313 files.setdefault(pf, (None, None))
315 files.setdefault(pf, (None, None))
314 elif line.find('with fuzz') >= 0:
316 elif line.find('with fuzz') >= 0:
315 fuzz = True
317 fuzz = True
316 if not printed_file:
318 if not printed_file:
317 ui.warn(pf + '\n')
319 ui.warn(pf + '\n')
318 printed_file = True
320 printed_file = True
319 ui.warn(line + '\n')
321 ui.warn(line + '\n')
320 elif line.find('saving rejects to file') >= 0:
322 elif line.find('saving rejects to file') >= 0:
321 ui.warn(line + '\n')
323 ui.warn(line + '\n')
322 elif line.find('FAILED') >= 0:
324 elif line.find('FAILED') >= 0:
323 if not printed_file:
325 if not printed_file:
324 ui.warn(pf + '\n')
326 ui.warn(pf + '\n')
325 printed_file = True
327 printed_file = True
326 ui.warn(line + '\n')
328 ui.warn(line + '\n')
327 code = fp.close()
329 code = fp.close()
328 if code:
330 if code:
329 raise util.Abort(_("patch command failed: %s") %
331 raise util.Abort(_("patch command failed: %s") %
330 util.explain_exit(code)[0])
332 util.explain_exit(code)[0])
331 return fuzz
333 return fuzz
332
334
333 (dopatch, gitpatches) = readgitpatch(patchname)
335 (dopatch, gitpatches) = readgitpatch(patchname)
334 for gp in gitpatches:
336 for gp in gitpatches:
335 files[gp.path] = (gp.op, gp)
337 files[gp.path] = (gp.op, gp)
336
338
337 fuzz = False
339 fuzz = False
338 if dopatch:
340 if dopatch:
339 filterpatch = dopatch & (GP_FILTER | GP_BINARY)
341 filterpatch = dopatch & (GP_FILTER | GP_BINARY)
340 if filterpatch:
342 if filterpatch:
341 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
343 patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
342 try:
344 try:
343 if dopatch & GP_PATCH:
345 if dopatch & GP_PATCH:
344 fuzz = __patch(patchname)
346 fuzz = __patch(patchname)
345 finally:
347 finally:
346 if filterpatch:
348 if filterpatch:
347 os.unlink(patchname)
349 os.unlink(patchname)
348
350
349 return fuzz
351 return fuzz
350
352
351 def diffopts(ui, opts={}, untrusted=False):
353 def diffopts(ui, opts={}, untrusted=False):
352 def get(key, name=None):
354 def get(key, name=None):
353 return (opts.get(key) or
355 return (opts.get(key) or
354 ui.configbool('diff', name or key, None, untrusted=untrusted))
356 ui.configbool('diff', name or key, None, untrusted=untrusted))
355 return mdiff.diffopts(
357 return mdiff.diffopts(
356 text=opts.get('text'),
358 text=opts.get('text'),
357 git=get('git'),
359 git=get('git'),
358 nodates=get('nodates'),
360 nodates=get('nodates'),
359 showfunc=get('show_function', 'showfunc'),
361 showfunc=get('show_function', 'showfunc'),
360 ignorews=get('ignore_all_space', 'ignorews'),
362 ignorews=get('ignore_all_space', 'ignorews'),
361 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
363 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
362 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
364 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
363
365
364 def updatedir(ui, repo, patches, wlock=None):
366 def updatedir(ui, repo, patches, wlock=None):
365 '''Update dirstate after patch application according to metadata'''
367 '''Update dirstate after patch application according to metadata'''
366 if not patches:
368 if not patches:
367 return
369 return
368 copies = []
370 copies = []
369 removes = {}
371 removes = {}
370 cfiles = patches.keys()
372 cfiles = patches.keys()
371 cwd = repo.getcwd()
373 cwd = repo.getcwd()
372 if cwd:
374 if cwd:
373 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
375 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
374 for f in patches:
376 for f in patches:
375 ctype, gp = patches[f]
377 ctype, gp = patches[f]
376 if ctype == 'RENAME':
378 if ctype == 'RENAME':
377 copies.append((gp.oldpath, gp.path, gp.copymod))
379 copies.append((gp.oldpath, gp.path, gp.copymod))
378 removes[gp.oldpath] = 1
380 removes[gp.oldpath] = 1
379 elif ctype == 'COPY':
381 elif ctype == 'COPY':
380 copies.append((gp.oldpath, gp.path, gp.copymod))
382 copies.append((gp.oldpath, gp.path, gp.copymod))
381 elif ctype == 'DELETE':
383 elif ctype == 'DELETE':
382 removes[gp.path] = 1
384 removes[gp.path] = 1
383 for src, dst, after in copies:
385 for src, dst, after in copies:
384 if not after:
386 if not after:
385 copyfile(src, dst, repo.root)
387 copyfile(src, dst, repo.root)
386 repo.copy(src, dst, wlock=wlock)
388 repo.copy(src, dst, wlock=wlock)
387 removes = removes.keys()
389 removes = removes.keys()
388 if removes:
390 if removes:
389 removes.sort()
391 removes.sort()
390 repo.remove(removes, True, wlock=wlock)
392 repo.remove(removes, True, wlock=wlock)
391 for f in patches:
393 for f in patches:
392 ctype, gp = patches[f]
394 ctype, gp = patches[f]
393 if gp and gp.mode:
395 if gp and gp.mode:
394 x = gp.mode & 0100 != 0
396 x = gp.mode & 0100 != 0
395 dst = os.path.join(repo.root, gp.path)
397 dst = os.path.join(repo.root, gp.path)
396 # patch won't create empty files
398 # patch won't create empty files
397 if ctype == 'ADD' and not os.path.exists(dst):
399 if ctype == 'ADD' and not os.path.exists(dst):
398 repo.wwrite(gp.path, '', x and 'x' or '')
400 repo.wwrite(gp.path, '', x and 'x' or '')
399 else:
401 else:
400 util.set_exec(dst, x)
402 util.set_exec(dst, x)
401 cmdutil.addremove(repo, cfiles, wlock=wlock)
403 cmdutil.addremove(repo, cfiles, wlock=wlock)
402 files = patches.keys()
404 files = patches.keys()
403 files.extend([r for r in removes if r not in files])
405 files.extend([r for r in removes if r not in files])
404 files.sort()
406 files.sort()
405
407
406 return files
408 return files
407
409
408 def b85diff(fp, to, tn):
410 def b85diff(fp, to, tn):
409 '''print base85-encoded binary diff'''
411 '''print base85-encoded binary diff'''
410 def gitindex(text):
412 def gitindex(text):
411 if not text:
413 if not text:
412 return '0' * 40
414 return '0' * 40
413 l = len(text)
415 l = len(text)
414 s = sha.new('blob %d\0' % l)
416 s = sha.new('blob %d\0' % l)
415 s.update(text)
417 s.update(text)
416 return s.hexdigest()
418 return s.hexdigest()
417
419
418 def fmtline(line):
420 def fmtline(line):
419 l = len(line)
421 l = len(line)
420 if l <= 26:
422 if l <= 26:
421 l = chr(ord('A') + l - 1)
423 l = chr(ord('A') + l - 1)
422 else:
424 else:
423 l = chr(l - 26 + ord('a') - 1)
425 l = chr(l - 26 + ord('a') - 1)
424 return '%c%s\n' % (l, base85.b85encode(line, True))
426 return '%c%s\n' % (l, base85.b85encode(line, True))
425
427
426 def chunk(text, csize=52):
428 def chunk(text, csize=52):
427 l = len(text)
429 l = len(text)
428 i = 0
430 i = 0
429 while i < l:
431 while i < l:
430 yield text[i:i+csize]
432 yield text[i:i+csize]
431 i += csize
433 i += csize
432
434
433 tohash = gitindex(to)
435 tohash = gitindex(to)
434 tnhash = gitindex(tn)
436 tnhash = gitindex(tn)
435 if tohash == tnhash:
437 if tohash == tnhash:
436 return ""
438 return ""
437
439
438 # TODO: deltas
440 # TODO: deltas
439 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
441 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
440 (tohash, tnhash, len(tn))]
442 (tohash, tnhash, len(tn))]
441 for l in chunk(zlib.compress(tn)):
443 for l in chunk(zlib.compress(tn)):
442 ret.append(fmtline(l))
444 ret.append(fmtline(l))
443 ret.append('\n')
445 ret.append('\n')
444 return ''.join(ret)
446 return ''.join(ret)
445
447
446 def diff(repo, node1=None, node2=None, files=None, match=util.always,
448 def diff(repo, node1=None, node2=None, files=None, match=util.always,
447 fp=None, changes=None, opts=None):
449 fp=None, changes=None, opts=None):
448 '''print diff of changes to files between two nodes, or node and
450 '''print diff of changes to files between two nodes, or node and
449 working directory.
451 working directory.
450
452
451 if node1 is None, use first dirstate parent instead.
453 if node1 is None, use first dirstate parent instead.
452 if node2 is None, compare node1 with working directory.'''
454 if node2 is None, compare node1 with working directory.'''
453
455
454 if opts is None:
456 if opts is None:
455 opts = mdiff.defaultopts
457 opts = mdiff.defaultopts
456 if fp is None:
458 if fp is None:
457 fp = repo.ui
459 fp = repo.ui
458
460
459 if not node1:
461 if not node1:
460 node1 = repo.dirstate.parents()[0]
462 node1 = repo.dirstate.parents()[0]
461
463
462 ccache = {}
464 ccache = {}
463 def getctx(r):
465 def getctx(r):
464 if r not in ccache:
466 if r not in ccache:
465 ccache[r] = context.changectx(repo, r)
467 ccache[r] = context.changectx(repo, r)
466 return ccache[r]
468 return ccache[r]
467
469
468 flcache = {}
470 flcache = {}
469 def getfilectx(f, ctx):
471 def getfilectx(f, ctx):
470 flctx = ctx.filectx(f, filelog=flcache.get(f))
472 flctx = ctx.filectx(f, filelog=flcache.get(f))
471 if f not in flcache:
473 if f not in flcache:
472 flcache[f] = flctx._filelog
474 flcache[f] = flctx._filelog
473 return flctx
475 return flctx
474
476
475 # reading the data for node1 early allows it to play nicely
477 # reading the data for node1 early allows it to play nicely
476 # with repo.status and the revlog cache.
478 # with repo.status and the revlog cache.
477 ctx1 = context.changectx(repo, node1)
479 ctx1 = context.changectx(repo, node1)
478 # force manifest reading
480 # force manifest reading
479 man1 = ctx1.manifest()
481 man1 = ctx1.manifest()
480 date1 = util.datestr(ctx1.date())
482 date1 = util.datestr(ctx1.date())
481
483
482 if not changes:
484 if not changes:
483 changes = repo.status(node1, node2, files, match=match)[:5]
485 changes = repo.status(node1, node2, files, match=match)[:5]
484 modified, added, removed, deleted, unknown = changes
486 modified, added, removed, deleted, unknown = changes
485
487
486 if not modified and not added and not removed:
488 if not modified and not added and not removed:
487 return
489 return
488
490
489 if node2:
491 if node2:
490 ctx2 = context.changectx(repo, node2)
492 ctx2 = context.changectx(repo, node2)
491 else:
493 else:
492 ctx2 = context.workingctx(repo)
494 ctx2 = context.workingctx(repo)
493 man2 = ctx2.manifest()
495 man2 = ctx2.manifest()
494
496
495 # returns False if there was no rename between ctx1 and ctx2
497 # returns False if there was no rename between ctx1 and ctx2
496 # returns None if the file was created between ctx1 and ctx2
498 # returns None if the file was created between ctx1 and ctx2
497 # returns the (file, node) present in ctx1 that was renamed to f in ctx2
499 # returns the (file, node) present in ctx1 that was renamed to f in ctx2
498 def renamed(f):
500 def renamed(f):
499 startrev = ctx1.rev()
501 startrev = ctx1.rev()
500 c = ctx2
502 c = ctx2
501 crev = c.rev()
503 crev = c.rev()
502 if crev is None:
504 if crev is None:
503 crev = repo.changelog.count()
505 crev = repo.changelog.count()
504 orig = f
506 orig = f
505 while crev > startrev:
507 while crev > startrev:
506 if f in c.files():
508 if f in c.files():
507 try:
509 try:
508 src = getfilectx(f, c).renamed()
510 src = getfilectx(f, c).renamed()
509 except revlog.LookupError:
511 except revlog.LookupError:
510 return None
512 return None
511 if src:
513 if src:
512 f = src[0]
514 f = src[0]
513 crev = c.parents()[0].rev()
515 crev = c.parents()[0].rev()
514 # try to reuse
516 # try to reuse
515 c = getctx(crev)
517 c = getctx(crev)
516 if f not in man1:
518 if f not in man1:
517 return None
519 return None
518 if f == orig:
520 if f == orig:
519 return False
521 return False
520 return f
522 return f
521
523
522 if repo.ui.quiet:
524 if repo.ui.quiet:
523 r = None
525 r = None
524 else:
526 else:
525 hexfunc = repo.ui.debugflag and hex or short
527 hexfunc = repo.ui.debugflag and hex or short
526 r = [hexfunc(node) for node in [node1, node2] if node]
528 r = [hexfunc(node) for node in [node1, node2] if node]
527
529
528 if opts.git:
530 if opts.git:
529 copied = {}
531 copied = {}
530 for f in added:
532 for f in added:
531 src = renamed(f)
533 src = renamed(f)
532 if src:
534 if src:
533 copied[f] = src
535 copied[f] = src
534 srcs = [x[1] for x in copied.items()]
536 srcs = [x[1] for x in copied.items()]
535
537
536 all = modified + added + removed
538 all = modified + added + removed
537 all.sort()
539 all.sort()
538 gone = {}
540 gone = {}
539
541
540 for f in all:
542 for f in all:
541 to = None
543 to = None
542 tn = None
544 tn = None
543 dodiff = True
545 dodiff = True
544 header = []
546 header = []
545 if f in man1:
547 if f in man1:
546 to = getfilectx(f, ctx1).data()
548 to = getfilectx(f, ctx1).data()
547 if f not in removed:
549 if f not in removed:
548 tn = getfilectx(f, ctx2).data()
550 tn = getfilectx(f, ctx2).data()
549 if opts.git:
551 if opts.git:
550 def gitmode(x):
552 def gitmode(x):
551 return x and '100755' or '100644'
553 return x and '100755' or '100644'
552 def addmodehdr(header, omode, nmode):
554 def addmodehdr(header, omode, nmode):
553 if omode != nmode:
555 if omode != nmode:
554 header.append('old mode %s\n' % omode)
556 header.append('old mode %s\n' % omode)
555 header.append('new mode %s\n' % nmode)
557 header.append('new mode %s\n' % nmode)
556
558
557 a, b = f, f
559 a, b = f, f
558 if f in added:
560 if f in added:
559 mode = gitmode(man2.execf(f))
561 mode = gitmode(man2.execf(f))
560 if f in copied:
562 if f in copied:
561 a = copied[f]
563 a = copied[f]
562 omode = gitmode(man1.execf(a))
564 omode = gitmode(man1.execf(a))
563 addmodehdr(header, omode, mode)
565 addmodehdr(header, omode, mode)
564 if a in removed and a not in gone:
566 if a in removed and a not in gone:
565 op = 'rename'
567 op = 'rename'
566 gone[a] = 1
568 gone[a] = 1
567 else:
569 else:
568 op = 'copy'
570 op = 'copy'
569 header.append('%s from %s\n' % (op, a))
571 header.append('%s from %s\n' % (op, a))
570 header.append('%s to %s\n' % (op, f))
572 header.append('%s to %s\n' % (op, f))
571 to = getfilectx(a, ctx1).data()
573 to = getfilectx(a, ctx1).data()
572 else:
574 else:
573 header.append('new file mode %s\n' % mode)
575 header.append('new file mode %s\n' % mode)
574 if util.binary(tn):
576 if util.binary(tn):
575 dodiff = 'binary'
577 dodiff = 'binary'
576 elif f in removed:
578 elif f in removed:
577 if f in srcs:
579 if f in srcs:
578 dodiff = False
580 dodiff = False
579 else:
581 else:
580 mode = gitmode(man1.execf(f))
582 mode = gitmode(man1.execf(f))
581 header.append('deleted file mode %s\n' % mode)
583 header.append('deleted file mode %s\n' % mode)
582 else:
584 else:
583 omode = gitmode(man1.execf(f))
585 omode = gitmode(man1.execf(f))
584 nmode = gitmode(man2.execf(f))
586 nmode = gitmode(man2.execf(f))
585 addmodehdr(header, omode, nmode)
587 addmodehdr(header, omode, nmode)
586 if util.binary(to) or util.binary(tn):
588 if util.binary(to) or util.binary(tn):
587 dodiff = 'binary'
589 dodiff = 'binary'
588 r = None
590 r = None
589 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
591 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
590 if dodiff:
592 if dodiff:
591 if dodiff == 'binary':
593 if dodiff == 'binary':
592 text = b85diff(fp, to, tn)
594 text = b85diff(fp, to, tn)
593 else:
595 else:
594 text = mdiff.unidiff(to, date1,
596 text = mdiff.unidiff(to, date1,
595 # ctx2 date may be dynamic
597 # ctx2 date may be dynamic
596 tn, util.datestr(ctx2.date()),
598 tn, util.datestr(ctx2.date()),
597 f, r, opts=opts)
599 f, r, opts=opts)
598 if text or len(header) > 1:
600 if text or len(header) > 1:
599 fp.write(''.join(header))
601 fp.write(''.join(header))
600 fp.write(text)
602 fp.write(text)
601
603
602 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
604 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
603 opts=None):
605 opts=None):
604 '''export changesets as hg patches.'''
606 '''export changesets as hg patches.'''
605
607
606 total = len(revs)
608 total = len(revs)
607 revwidth = max([len(str(rev)) for rev in revs])
609 revwidth = max([len(str(rev)) for rev in revs])
608
610
609 def single(rev, seqno, fp):
611 def single(rev, seqno, fp):
610 ctx = repo.changectx(rev)
612 ctx = repo.changectx(rev)
611 node = ctx.node()
613 node = ctx.node()
612 parents = [p.node() for p in ctx.parents() if p]
614 parents = [p.node() for p in ctx.parents() if p]
613 if switch_parent:
615 if switch_parent:
614 parents.reverse()
616 parents.reverse()
615 prev = (parents and parents[0]) or nullid
617 prev = (parents and parents[0]) or nullid
616
618
617 if not fp:
619 if not fp:
618 fp = cmdutil.make_file(repo, template, node, total=total,
620 fp = cmdutil.make_file(repo, template, node, total=total,
619 seqno=seqno, revwidth=revwidth)
621 seqno=seqno, revwidth=revwidth)
620 if fp != sys.stdout and hasattr(fp, 'name'):
622 if fp != sys.stdout and hasattr(fp, 'name'):
621 repo.ui.note("%s\n" % fp.name)
623 repo.ui.note("%s\n" % fp.name)
622
624
623 fp.write("# HG changeset patch\n")
625 fp.write("# HG changeset patch\n")
624 fp.write("# User %s\n" % ctx.user())
626 fp.write("# User %s\n" % ctx.user())
625 fp.write("# Date %d %d\n" % ctx.date())
627 fp.write("# Date %d %d\n" % ctx.date())
626 fp.write("# Node ID %s\n" % hex(node))
628 fp.write("# Node ID %s\n" % hex(node))
627 fp.write("# Parent %s\n" % hex(prev))
629 fp.write("# Parent %s\n" % hex(prev))
628 if len(parents) > 1:
630 if len(parents) > 1:
629 fp.write("# Parent %s\n" % hex(parents[1]))
631 fp.write("# Parent %s\n" % hex(parents[1]))
630 fp.write(ctx.description().rstrip())
632 fp.write(ctx.description().rstrip())
631 fp.write("\n\n")
633 fp.write("\n\n")
632
634
633 diff(repo, prev, node, fp=fp, opts=opts)
635 diff(repo, prev, node, fp=fp, opts=opts)
634 if fp not in (sys.stdout, repo.ui):
636 if fp not in (sys.stdout, repo.ui):
635 fp.close()
637 fp.close()
636
638
637 for seqno, rev in enumerate(revs):
639 for seqno, rev in enumerate(revs):
638 single(rev, seqno+1, fp)
640 single(rev, seqno+1, fp)
639
641
640 def diffstat(patchlines):
642 def diffstat(patchlines):
641 if not util.find_in_path('diffstat', os.environ.get('PATH', '')):
643 if not util.find_in_path('diffstat', os.environ.get('PATH', '')):
642 return
644 return
643 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
645 fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
644 try:
646 try:
645 p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
647 p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
646 try:
648 try:
647 for line in patchlines: print >> p.tochild, line
649 for line in patchlines: print >> p.tochild, line
648 p.tochild.close()
650 p.tochild.close()
649 if p.wait(): return
651 if p.wait(): return
650 fp = os.fdopen(fd, 'r')
652 fp = os.fdopen(fd, 'r')
651 stat = []
653 stat = []
652 for line in fp: stat.append(line.lstrip())
654 for line in fp: stat.append(line.lstrip())
653 last = stat.pop()
655 last = stat.pop()
654 stat.insert(0, last)
656 stat.insert(0, last)
655 stat = ''.join(stat)
657 stat = ''.join(stat)
656 if stat.startswith('0 files'): raise ValueError
658 if stat.startswith('0 files'): raise ValueError
657 return stat
659 return stat
658 except: raise
660 except: raise
659 finally:
661 finally:
660 try: os.unlink(name)
662 try: os.unlink(name)
661 except: pass
663 except: pass
General Comments 0
You need to be logged in to leave comments. Login now