##// END OF EJS Templates
grep: extend functionality, add man page entry, add unit test....
bos@serpentine.internal.keyresearch.com -
r1146:9061f79c default
parent child Browse files
Show More
@@ -0,0 +1,22
1 #!/bin/sh
2
3 mkdir t
4 cd t
5 hg init
6 echo import > port
7 hg add port
8 hg commit -m 0 -u spam -d '0 0'
9 echo export >> port
10 hg commit -m 1 -u eggs -d '1 0'
11 echo export > port
12 echo vaportight >> port
13 echo 'import/export' >> port
14 hg commit -m 2 -u spam -d '2 0'
15 echo 'import/export' >> port
16 hg commit -m 3 -u eggs -d '3 0'
17 head -3 port > port1
18 mv port1 port
19 hg commit -m 4 -u spam -d '4 0'
20 hg grep port port
21 hg grep -enu port port
22 hg grep import port
@@ -1,685 +1,710
1 HG(1)
1 HG(1)
2 =====
2 =====
3 Matt Mackall <mpm@selenic.com>
3 Matt Mackall <mpm@selenic.com>
4
4
5 NAME
5 NAME
6 ----
6 ----
7 hg - Mercurial source code management system
7 hg - Mercurial source code management system
8
8
9 SYNOPSIS
9 SYNOPSIS
10 --------
10 --------
11 'hg' [-v -d -q -y] <command> [command options] [files]
11 'hg' [-v -d -q -y] <command> [command options] [files]
12
12
13 DESCRIPTION
13 DESCRIPTION
14 -----------
14 -----------
15 The hg(1) command provides a command line interface to the Mercurial system.
15 The hg(1) command provides a command line interface to the Mercurial system.
16
16
17 OPTIONS
17 OPTIONS
18 -------
18 -------
19
19
20 -R, --repository::
20 -R, --repository::
21 repository root directory
21 repository root directory
22
22
23 --cwd::
23 --cwd::
24 change working directory
24 change working directory
25
25
26 -y, --noninteractive::
26 -y, --noninteractive::
27 do not prompt, assume 'yes' for any required answers
27 do not prompt, assume 'yes' for any required answers
28
28
29 -q, --quiet::
29 -q, --quiet::
30 suppress output
30 suppress output
31
31
32 -v, --verbose::
32 -v, --verbose::
33 enable additional output
33 enable additional output
34
34
35 --debug::
35 --debug::
36 enable debugging output
36 enable debugging output
37
37
38 --traceback::
38 --traceback::
39 print traceback on exception
39 print traceback on exception
40
40
41 --time::
41 --time::
42 time how long the command takes
42 time how long the command takes
43
43
44 --profile::
44 --profile::
45 print command execution profile
45 print command execution profile
46
46
47 --version::
47 --version::
48 output version information and exit
48 output version information and exit
49
49
50 -h, --help::
50 -h, --help::
51 display help and exit
51 display help and exit
52
52
53 COMMAND ELEMENTS
53 COMMAND ELEMENTS
54 ----------------
54 ----------------
55
55
56 files ...::
56 files ...::
57 indicates one or more filename or relative path filenames; see
57 indicates one or more filename or relative path filenames; see
58 "FILE NAME PATTERNS" for information on pattern matching
58 "FILE NAME PATTERNS" for information on pattern matching
59
59
60 path::
60 path::
61 indicates a path on the local machine
61 indicates a path on the local machine
62
62
63 revision::
63 revision::
64 indicates a changeset which can be specified as a changeset revision
64 indicates a changeset which can be specified as a changeset revision
65 number, a tag, or a unique substring of the changeset hash value
65 number, a tag, or a unique substring of the changeset hash value
66
66
67 repository path::
67 repository path::
68 either the pathname of a local repository or the URI of a remote
68 either the pathname of a local repository or the URI of a remote
69 repository. There are two available URI protocols, http:// which is
69 repository. There are two available URI protocols, http:// which is
70 fast and the old-http:// protocol which is much slower but does not
70 fast and the old-http:// protocol which is much slower but does not
71 require a special server on the web host.
71 require a special server on the web host.
72
72
73 COMMANDS
73 COMMANDS
74 --------
74 --------
75
75
76 add [options] [files ...]::
76 add [options] [files ...]::
77 Schedule files to be version controlled and added to the repository.
77 Schedule files to be version controlled and added to the repository.
78
78
79 The files will be added to the repository at the next commit.
79 The files will be added to the repository at the next commit.
80
80
81 If no names are given, add all files in the current directory and
81 If no names are given, add all files in the current directory and
82 its subdirectories.
82 its subdirectories.
83
83
84 addremove [options] [files ...]::
84 addremove [options] [files ...]::
85 Add all new files and remove all missing files from the repository.
85 Add all new files and remove all missing files from the repository.
86
86
87 New files are ignored if they match any of the patterns in .hgignore. As
87 New files are ignored if they match any of the patterns in .hgignore. As
88 with add, these changes take effect at the next commit.
88 with add, these changes take effect at the next commit.
89
89
90 annotate [-r <rev> -u -n -c] [files ...]::
90 annotate [-r <rev> -u -n -c] [files ...]::
91 List changes in files, showing the revision id responsible for each line
91 List changes in files, showing the revision id responsible for each line
92
92
93 This command is useful to discover who did a change or when a change took
93 This command is useful to discover who did a change or when a change took
94 place.
94 place.
95
95
96 Without the -a option, annotate will avoid processing files it
96 Without the -a option, annotate will avoid processing files it
97 detects as binary. With -a, annotate will generate an annotation
97 detects as binary. With -a, annotate will generate an annotation
98 anyway, probably with undesirable results.
98 anyway, probably with undesirable results.
99
99
100 options:
100 options:
101 -a, --text treat all files as text
101 -a, --text treat all files as text
102 -I, --include <pat> include names matching the given patterns
102 -I, --include <pat> include names matching the given patterns
103 -X, --exclude <pat> exclude names matching the given patterns
103 -X, --exclude <pat> exclude names matching the given patterns
104 -r, --revision <rev> annotate the specified revision
104 -r, --revision <rev> annotate the specified revision
105 -u, --user list the author
105 -u, --user list the author
106 -c, --changeset list the changeset
106 -c, --changeset list the changeset
107 -n, --number list the revision number (default)
107 -n, --number list the revision number (default)
108
108
109 cat <file> [revision]::
109 cat <file> [revision]::
110 Output to stdout the given revision for the specified file.
110 Output to stdout the given revision for the specified file.
111
111
112 If no revision is given then the tip is used.
112 If no revision is given then the tip is used.
113
113
114 clone [-U] <source> [dest]::
114 clone [-U] <source> [dest]::
115 Create a copy of an existing repository in a new directory.
115 Create a copy of an existing repository in a new directory.
116
116
117 If no destination directory name is specified, it defaults to the
117 If no destination directory name is specified, it defaults to the
118 basename of the source.
118 basename of the source.
119
119
120 The source is added to the new repository's .hg/hgrc file to be used in
120 The source is added to the new repository's .hg/hgrc file to be used in
121 future pulls.
121 future pulls.
122
122
123 For efficiency, hardlinks are used for cloning whenever the
123 For efficiency, hardlinks are used for cloning whenever the
124 source and destination are on the same filesystem.
124 source and destination are on the same filesystem.
125
125
126 options:
126 options:
127 -U, --noupdate do not update the new working directory
127 -U, --noupdate do not update the new working directory
128 -e, --ssh specify ssh command to use
128 -e, --ssh specify ssh command to use
129 --remotecmd specify hg command to run on the remote side
129 --remotecmd specify hg command to run on the remote side
130
130
131 commit [options] [files...]::
131 commit [options] [files...]::
132 Commit changes to the given files into the repository.
132 Commit changes to the given files into the repository.
133
133
134 If a list of files is omitted, all changes reported by "hg status"
134 If a list of files is omitted, all changes reported by "hg status"
135 from the root of the repository will be commited.
135 from the root of the repository will be commited.
136
136
137 The HGEDITOR or EDITOR environment variables are used to start an
137 The HGEDITOR or EDITOR environment variables are used to start an
138 editor to add a commit comment.
138 editor to add a commit comment.
139
139
140 Options:
140 Options:
141
141
142 -A, --addremove run addremove during commit
142 -A, --addremove run addremove during commit
143 -I, --include <pat> include names matching the given patterns
143 -I, --include <pat> include names matching the given patterns
144 -X, --exclude <pat> exclude names matching the given patterns
144 -X, --exclude <pat> exclude names matching the given patterns
145 -m, --message <text> use <text> as commit message
145 -m, --message <text> use <text> as commit message
146 -l, --logfile <file> read the commit message from <file>
146 -l, --logfile <file> read the commit message from <file>
147 -d, --date <datecode> record datecode as commit date
147 -d, --date <datecode> record datecode as commit date
148 -u, --user <user> record user as commiter
148 -u, --user <user> record user as commiter
149
149
150 aliases: ci
150 aliases: ci
151
151
152 copy <source> <dest>::
152 copy <source> <dest>::
153 Mark <dest> file as a copy or rename of a <source> one
153 Mark <dest> file as a copy or rename of a <source> one
154
154
155 This command takes effect for the next commit.
155 This command takes effect for the next commit.
156
156
157 diff [-a] [-r revision] [-r revision] [files ...]::
157 diff [-a] [-r revision] [-r revision] [files ...]::
158 Show differences between revisions for the specified files.
158 Show differences between revisions for the specified files.
159
159
160 Differences between files are shown using the unified diff format.
160 Differences between files are shown using the unified diff format.
161
161
162 When two revision arguments are given, then changes are shown
162 When two revision arguments are given, then changes are shown
163 between those revisions. If only one revision is specified then
163 between those revisions. If only one revision is specified then
164 that revision is compared to the working directory, and, when no
164 that revision is compared to the working directory, and, when no
165 revisions are specified, the working directory files are compared
165 revisions are specified, the working directory files are compared
166 to its parent.
166 to its parent.
167
167
168 Without the -a option, diff will avoid generating diffs of files
168 Without the -a option, diff will avoid generating diffs of files
169 it detects as binary. With -a, diff will generate a diff anyway,
169 it detects as binary. With -a, diff will generate a diff anyway,
170 probably with undesirable results.
170 probably with undesirable results.
171
171
172 options:
172 options:
173 -a, --text treat all files as text
173 -a, --text treat all files as text
174 -I, --include <pat> include names matching the given patterns
174 -I, --include <pat> include names matching the given patterns
175 -X, --exclude <pat> exclude names matching the given patterns
175 -X, --exclude <pat> exclude names matching the given patterns
176
176
177 export [-o filespec] [revision] ...::
177 export [-o filespec] [revision] ...::
178 Print the changeset header and diffs for one or more revisions.
178 Print the changeset header and diffs for one or more revisions.
179
179
180 The information shown in the changeset header is: author,
180 The information shown in the changeset header is: author,
181 changeset hash, parent and commit comment.
181 changeset hash, parent and commit comment.
182
182
183 Output may be to a file, in which case the name of the file is
183 Output may be to a file, in which case the name of the file is
184 given using a format string. The formatting rules are as follows:
184 given using a format string. The formatting rules are as follows:
185
185
186 %% literal "%" character
186 %% literal "%" character
187 %H changeset hash (40 bytes of hexadecimal)
187 %H changeset hash (40 bytes of hexadecimal)
188 %N number of patches being generated
188 %N number of patches being generated
189 %R changeset revision number
189 %R changeset revision number
190 %b basename of the exporting repository
190 %b basename of the exporting repository
191 %h short-form changeset hash (12 bytes of hexadecimal)
191 %h short-form changeset hash (12 bytes of hexadecimal)
192 %n zero-padded sequence number, starting at 1
192 %n zero-padded sequence number, starting at 1
193 %r zero-padded changeset revision number
193 %r zero-padded changeset revision number
194
194
195 Without the -a option, export will avoid generating diffs of files
195 Without the -a option, export will avoid generating diffs of files
196 it detects as binary. With -a, export will generate a diff anyway,
196 it detects as binary. With -a, export will generate a diff anyway,
197 probably with undesirable results.
197 probably with undesirable results.
198
198
199 options:
199 options:
200 -a, --text treat all files as text
200 -a, --text treat all files as text
201 -o, --output <filespec> print output to file with formatted named
201 -o, --output <filespec> print output to file with formatted named
202
202
203 forget [options] [files]::
203 forget [options] [files]::
204 Undo an 'hg add' scheduled for the next commit.
204 Undo an 'hg add' scheduled for the next commit.
205
205
206 options:
206 options:
207 -I, --include <pat> include names matching the given patterns
207 -I, --include <pat> include names matching the given patterns
208 -X, --exclude <pat> exclude names matching the given patterns
208 -X, --exclude <pat> exclude names matching the given patterns
209
209
210 grep [options] pattern [files]::
211 Search revisions of files for a regular expression.
212
213 This command behaves differently than Unix grep. It only accepts
214 Python/Perl regexps. It searches repository history, not the
215 working directory. It always prints the revision number in which
216 a match appears.
217
218 By default, grep only prints output for the first revision of a
219 file in which it finds a match. To get it to print every revision
220 that contains a change in match status ("-" for a match that
221 becomes a non-match, or "+" for a non-match that becomes a match),
222 use the --every-match flag.
223
224 options:
225 -0, --print0 end fields with NUL
226 -I, --include <pat> include names matching the given patterns
227 -X, --exclude <pat> exclude names matching the given patterns
228 -e, --every-match print every revision that matches
229 -i, --ignore-case ignore case when matching
230 -l, --files-with-matches print only file names and revs that match
231 -n, --line-number print matching line numbers
232 -r <rev>, --rev <rev> search in given revision range
233 -u, --user print user who committed change
234
210 heads::
235 heads::
211 Show all repository head changesets.
236 Show all repository head changesets.
212
237
213 Repository "heads" are changesets that don't have children
238 Repository "heads" are changesets that don't have children
214 changesets. They are where development generally takes place and
239 changesets. They are where development generally takes place and
215 are the usual targets for update and merge operations.
240 are the usual targets for update and merge operations.
216
241
217 identify::
242 identify::
218 Print a short summary of the current state of the repo.
243 Print a short summary of the current state of the repo.
219
244
220 This summary identifies the repository state using one or two parent
245 This summary identifies the repository state using one or two parent
221 hash identifiers, followed by a "+" if there are uncommitted changes
246 hash identifiers, followed by a "+" if there are uncommitted changes
222 in the working directory, followed by a list of tags for this revision.
247 in the working directory, followed by a list of tags for this revision.
223
248
224 aliases: id
249 aliases: id
225
250
226 import [-p <n> -b <base> -f] <patches>::
251 import [-p <n> -b <base> -f] <patches>::
227 Import a list of patches and commit them individually.
252 Import a list of patches and commit them individually.
228
253
229 options:
254 options:
230 -p, --strip <n> directory strip option for patch. This has the same
255 -p, --strip <n> directory strip option for patch. This has the same
231 meaning as the corresponding patch option
256 meaning as the corresponding patch option
232 -b <path> base directory to read patches from
257 -b <path> base directory to read patches from
233 -f, --force skip check for outstanding uncommitted changes
258 -f, --force skip check for outstanding uncommitted changes
234
259
235 aliases: patch
260 aliases: patch
236
261
237 incoming [source]::
262 incoming [source]::
238 Show new changesets found in the specified repo or the default
263 Show new changesets found in the specified repo or the default
239 pull repo. These are the changesets that would be pulled if a pull
264 pull repo. These are the changesets that would be pulled if a pull
240 was requested.
265 was requested.
241
266
242 Currently only local repositories are supported.
267 Currently only local repositories are supported.
243
268
244 aliases: in
269 aliases: in
245
270
246 init [dest]::
271 init [dest]::
247 Initialize a new repository in the given directory. If the given
272 Initialize a new repository in the given directory. If the given
248 directory does not exist, it is created.
273 directory does not exist, it is created.
249
274
250 If no directory is given, the current directory is used.
275 If no directory is given, the current directory is used.
251
276
252 locate [options] [files]::
277 locate [options] [files]::
253 Print all files under Mercurial control whose names match the
278 Print all files under Mercurial control whose names match the
254 given patterns.
279 given patterns.
255
280
256 This command searches the current directory and its
281 This command searches the current directory and its
257 subdirectories. To search an entire repository, move to the root
282 subdirectories. To search an entire repository, move to the root
258 of the repository.
283 of the repository.
259
284
260 If no patterns are given to match, this command prints all file
285 If no patterns are given to match, this command prints all file
261 names.
286 names.
262
287
263 If you want to feed the output of this command into the "xargs"
288 If you want to feed the output of this command into the "xargs"
264 command, use the "-0" option to both this command and "xargs".
289 command, use the "-0" option to both this command and "xargs".
265 This will avoid the problem of "xargs" treating single filenames
290 This will avoid the problem of "xargs" treating single filenames
266 that contain white space as multiple file names.
291 that contain white space as multiple file names.
267
292
268 options:
293 options:
269
294
270 -0, --print0 end filenames with NUL, for use with xargs
295 -0, --print0 end filenames with NUL, for use with xargs
271 -f, --fullpath print complete paths from the filesystem root
296 -f, --fullpath print complete paths from the filesystem root
272 -I, --include <pat> include names matching the given patterns
297 -I, --include <pat> include names matching the given patterns
273 -r, --rev <rev> search the repository as it stood at rev
298 -r, --rev <rev> search the repository as it stood at rev
274 -X, --exclude <pat> exclude names matching the given patterns
299 -X, --exclude <pat> exclude names matching the given patterns
275
300
276 log [-r revision ...] [-p] [files]::
301 log [-r revision ...] [-p] [files]::
277 Print the revision history of the specified files or the entire project.
302 Print the revision history of the specified files or the entire project.
278
303
279 By default this command outputs: changeset id and hash, tags,
304 By default this command outputs: changeset id and hash, tags,
280 parents, user, date and time, and a summary for each commit. The
305 parents, user, date and time, and a summary for each commit. The
281 -v switch adds some more detail, such as changed files, manifest
306 -v switch adds some more detail, such as changed files, manifest
282 hashes or message signatures.
307 hashes or message signatures.
283
308
284 options:
309 options:
285 -I, --include <pat> include names matching the given patterns
310 -I, --include <pat> include names matching the given patterns
286 -X, --exclude <pat> exclude names matching the given patterns
311 -X, --exclude <pat> exclude names matching the given patterns
287 -r, --rev <A> show the specified revision or range
312 -r, --rev <A> show the specified revision or range
288 -p, --patch show patch
313 -p, --patch show patch
289
314
290 aliases: history
315 aliases: history
291
316
292 manifest [revision]::
317 manifest [revision]::
293 Print a list of version controlled files for the given revision.
318 Print a list of version controlled files for the given revision.
294
319
295 The manifest is the list of files being version controlled. If no revision
320 The manifest is the list of files being version controlled. If no revision
296 is given then the tip is used.
321 is given then the tip is used.
297
322
298 outgoing [dest]::
323 outgoing [dest]::
299 Show changesets not found in the specified destination repo or the
324 Show changesets not found in the specified destination repo or the
300 default push repo. These are the changesets that would be pushed
325 default push repo. These are the changesets that would be pushed
301 if a push was requested.
326 if a push was requested.
302
327
303 aliases: out
328 aliases: out
304
329
305 parents::
330 parents::
306 Print the working directory's parent revisions.
331 Print the working directory's parent revisions.
307
332
308 paths [NAME]::
333 paths [NAME]::
309 Show definition of symbolic path name NAME. If no name is given, show
334 Show definition of symbolic path name NAME. If no name is given, show
310 definition of available names.
335 definition of available names.
311
336
312 Path names are defined in the [paths] section of /etc/mercurial/hgrc
337 Path names are defined in the [paths] section of /etc/mercurial/hgrc
313 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
338 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
314
339
315 pull <repository path>::
340 pull <repository path>::
316 Pull changes from a remote repository to a local one.
341 Pull changes from a remote repository to a local one.
317
342
318 This finds all changes from the repository at the specified path
343 This finds all changes from the repository at the specified path
319 or URL and adds them to the local repository. By default, this
344 or URL and adds them to the local repository. By default, this
320 does not update the copy of the project in the working directory.
345 does not update the copy of the project in the working directory.
321
346
322 Valid URLs are of the form:
347 Valid URLs are of the form:
323
348
324 local/filesystem/path
349 local/filesystem/path
325 http://[user@]host[:port][/path]
350 http://[user@]host[:port][/path]
326 https://[user@]host[:port][/path]
351 https://[user@]host[:port][/path]
327 ssh://[user@]host[:port][/path]
352 ssh://[user@]host[:port][/path]
328
353
329 SSH requires an accessible shell account on the destination
354 SSH requires an accessible shell account on the destination
330 machine and a copy of hg in the remote path.
355 machine and a copy of hg in the remote path.
331
356
332 options:
357 options:
333 -u, --update update the working directory to tip after pull
358 -u, --update update the working directory to tip after pull
334 -e, --ssh specify ssh command to use
359 -e, --ssh specify ssh command to use
335 --remotecmd specify hg command to run on the remote side
360 --remotecmd specify hg command to run on the remote side
336
361
337 push <destination>::
362 push <destination>::
338 Push changes from the local repository to the given destination.
363 Push changes from the local repository to the given destination.
339
364
340 This is the symmetrical operation for pull. It helps to move
365 This is the symmetrical operation for pull. It helps to move
341 changes from the current repository to a different one. If the
366 changes from the current repository to a different one. If the
342 destination is local this is identical to a pull in that directory
367 destination is local this is identical to a pull in that directory
343 from the current one.
368 from the current one.
344
369
345 By default, push will refuse to run if it detects the result would
370 By default, push will refuse to run if it detects the result would
346 increase the number of remote heads. This generally indicates the
371 increase the number of remote heads. This generally indicates the
347 the client has forgotten to sync and merge before pushing.
372 the client has forgotten to sync and merge before pushing.
348
373
349 Valid URLs are of the form:
374 Valid URLs are of the form:
350
375
351 local/filesystem/path
376 local/filesystem/path
352 ssh://[user@]host[:port][/path]
377 ssh://[user@]host[:port][/path]
353
378
354 SSH requires an accessible shell account on the destination
379 SSH requires an accessible shell account on the destination
355 machine and a copy of hg in the remote path.
380 machine and a copy of hg in the remote path.
356
381
357 options:
382 options:
358
383
359 -f, --force force update
384 -f, --force force update
360 -e, --ssh specify ssh command to use
385 -e, --ssh specify ssh command to use
361 --remotecmd specify hg command to run on the remote side
386 --remotecmd specify hg command to run on the remote side
362
387
363 rawcommit [-p -d -u -F -m -l]::
388 rawcommit [-p -d -u -F -m -l]::
364 Lowlevel commit, for use in helper scripts.
389 Lowlevel commit, for use in helper scripts.
365
390
366 This command is not intended to be used by normal users, as it is
391 This command is not intended to be used by normal users, as it is
367 primarily useful for importing from other SCMs.
392 primarily useful for importing from other SCMs.
368
393
369 recover::
394 recover::
370 Recover from an interrupted commit or pull.
395 Recover from an interrupted commit or pull.
371
396
372 This command tries to fix the repository status after an interrupted
397 This command tries to fix the repository status after an interrupted
373 operation. It should only be necessary when Mercurial suggests it.
398 operation. It should only be necessary when Mercurial suggests it.
374
399
375 remove [files ...]::
400 remove [files ...]::
376 Schedule the indicated files for removal from the repository.
401 Schedule the indicated files for removal from the repository.
377
402
378 This command schedules the files to be removed at the next commit.
403 This command schedules the files to be removed at the next commit.
379 This only removes files from the current branch, not from the
404 This only removes files from the current branch, not from the
380 entire project history.
405 entire project history.
381
406
382 aliases: rm
407 aliases: rm
383
408
384 revert [names ...]::
409 revert [names ...]::
385 Revert any uncommitted modifications made to the named files or
410 Revert any uncommitted modifications made to the named files or
386 directories. This restores the contents of the affected files to
411 directories. This restores the contents of the affected files to
387 an unmodified state.
412 an unmodified state.
388
413
389 If a file has been deleted, it is recreated. If the executable
414 If a file has been deleted, it is recreated. If the executable
390 mode of a file was changed, it is reset.
415 mode of a file was changed, it is reset.
391
416
392 If a directory is given, all files in that directory and its
417 If a directory is given, all files in that directory and its
393 subdirectories are reverted.
418 subdirectories are reverted.
394
419
395 If no arguments are given, all files in the current directory and
420 If no arguments are given, all files in the current directory and
396 its subdirectories are reverted.
421 its subdirectories are reverted.
397
422
398 options:
423 options:
399 -r, --rev <rev> revision to revert to
424 -r, --rev <rev> revision to revert to
400 -n, --nonrecursive do not recurse into subdirectories
425 -n, --nonrecursive do not recurse into subdirectories
401
426
402 root::
427 root::
403 Print the root directory of the current repository.
428 Print the root directory of the current repository.
404
429
405 serve [options]::
430 serve [options]::
406 Start a local HTTP repository browser and pull server.
431 Start a local HTTP repository browser and pull server.
407
432
408 By default, the server logs accesses to stdout and errors to
433 By default, the server logs accesses to stdout and errors to
409 stderr. Use the "-A" and "-E" options to log to files.
434 stderr. Use the "-A" and "-E" options to log to files.
410
435
411 options:
436 options:
412 -A, --accesslog <file> name of access log file to write to
437 -A, --accesslog <file> name of access log file to write to
413 -E, --errorlog <file> name of error log file to write to
438 -E, --errorlog <file> name of error log file to write to
414 -a, --address <addr> address to use
439 -a, --address <addr> address to use
415 -p, --port <n> port to use (default: 8000)
440 -p, --port <n> port to use (default: 8000)
416 -n, --name <name> name to show in web pages (default: working dir)
441 -n, --name <name> name to show in web pages (default: working dir)
417 -t, --templatedir <path> web templates to use
442 -t, --templatedir <path> web templates to use
418 -6, --ipv6 use IPv6 in addition to IPv4
443 -6, --ipv6 use IPv6 in addition to IPv4
419
444
420 status [options] [files]::
445 status [options] [files]::
421 Show changed files in the working directory. If no names are
446 Show changed files in the working directory. If no names are
422 given, all files are shown. Otherwise, only files matching the
447 given, all files are shown. Otherwise, only files matching the
423 given names are shown.
448 given names are shown.
424
449
425 The codes used to show the status of files are:
450 The codes used to show the status of files are:
426
451
427 M = changed
452 M = changed
428 A = added
453 A = added
429 R = removed
454 R = removed
430 ? = not tracked
455 ? = not tracked
431
456
432 options:
457 options:
433
458
434 -m, --modified show only modified files
459 -m, --modified show only modified files
435 -a, --added show only added files
460 -a, --added show only added files
436 -r, --removed show only removed files
461 -r, --removed show only removed files
437 -u, --unknown show only unknown (not tracked) files
462 -u, --unknown show only unknown (not tracked) files
438 -n, --no-status hide status prefix
463 -n, --no-status hide status prefix
439 -0, --print0 end filenames with NUL, for use with xargs
464 -0, --print0 end filenames with NUL, for use with xargs
440 -I, --include <pat> include names matching the given patterns
465 -I, --include <pat> include names matching the given patterns
441 -X, --exclude <pat> exclude names matching the given patterns
466 -X, --exclude <pat> exclude names matching the given patterns
442
467
443 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
468 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
444 Name a particular revision using <name>.
469 Name a particular revision using <name>.
445
470
446 Tags are used to name particular revisions of the repository and are
471 Tags are used to name particular revisions of the repository and are
447 very useful to compare different revision, to go back to significant
472 very useful to compare different revision, to go back to significant
448 earlier versions or to mark branch points as releases, etc.
473 earlier versions or to mark branch points as releases, etc.
449
474
450 If no revision is given, the tip is used.
475 If no revision is given, the tip is used.
451
476
452 To facilitate version control, distribution, and merging of tags,
477 To facilitate version control, distribution, and merging of tags,
453 they are stored as a file named ".hgtags" which is managed
478 they are stored as a file named ".hgtags" which is managed
454 similarly to other project files and can be hand-edited if
479 similarly to other project files and can be hand-edited if
455 necessary.
480 necessary.
456
481
457 options:
482 options:
458 -l, --local make the tag local
483 -l, --local make the tag local
459 -m, --message <text> message for tag commit log entry
484 -m, --message <text> message for tag commit log entry
460 -d, --date <datecode> datecode for commit
485 -d, --date <datecode> datecode for commit
461 -u, --user <user> user for commit
486 -u, --user <user> user for commit
462
487
463 Note: Local tags are not version-controlled or distributed and are
488 Note: Local tags are not version-controlled or distributed and are
464 stored in the .hg/localtags file. If there exists a local tag and
489 stored in the .hg/localtags file. If there exists a local tag and
465 a public tag with the same name, local tag is used.
490 a public tag with the same name, local tag is used.
466
491
467 tags::
492 tags::
468 List the repository tags.
493 List the repository tags.
469
494
470 This lists both regular and local tags.
495 This lists both regular and local tags.
471
496
472 tip::
497 tip::
473 Show the tip revision.
498 Show the tip revision.
474
499
475 undo::
500 undo::
476 Undo the last commit or pull transaction.
501 Undo the last commit or pull transaction.
477
502
478 Roll back the last pull or commit transaction on the
503 Roll back the last pull or commit transaction on the
479 repository, restoring the project to its earlier state.
504 repository, restoring the project to its earlier state.
480
505
481 This command should be used with care. There is only one level of
506 This command should be used with care. There is only one level of
482 undo and there is no redo.
507 undo and there is no redo.
483
508
484 This command is not intended for use on public repositories. Once
509 This command is not intended for use on public repositories. Once
485 a change is visible for pull by other users, undoing it locally is
510 a change is visible for pull by other users, undoing it locally is
486 ineffective.
511 ineffective.
487
512
488 update [-m -C] [revision]::
513 update [-m -C] [revision]::
489 Update the working directory to the specified revision.
514 Update the working directory to the specified revision.
490
515
491 By default, update will refuse to run if doing so would require
516 By default, update will refuse to run if doing so would require
492 merging or discarding local changes.
517 merging or discarding local changes.
493
518
494 With the -m option, a merge will be performed.
519 With the -m option, a merge will be performed.
495
520
496 With the -C option, local changes will be lost.
521 With the -C option, local changes will be lost.
497
522
498 options:
523 options:
499 -m, --merge allow merging of branches
524 -m, --merge allow merging of branches
500 -C, --clean overwrite locally modified files
525 -C, --clean overwrite locally modified files
501
526
502 aliases: up checkout co
527 aliases: up checkout co
503
528
504 verify::
529 verify::
505 Verify the integrity of the current repository.
530 Verify the integrity of the current repository.
506
531
507 This will perform an extensive check of the repository's
532 This will perform an extensive check of the repository's
508 integrity, validating the hashes and checksums of each entry in
533 integrity, validating the hashes and checksums of each entry in
509 the changelog, manifest, and tracked files, as well as the
534 the changelog, manifest, and tracked files, as well as the
510 integrity of their crosslinks and indices.
535 integrity of their crosslinks and indices.
511
536
512 FILE NAME PATTERNS
537 FILE NAME PATTERNS
513 ------------------
538 ------------------
514
539
515 Mercurial accepts several notations for identifying one or more
540 Mercurial accepts several notations for identifying one or more
516 file at a time.
541 file at a time.
517
542
518 By default, Mercurial treats file names as shell-style extended
543 By default, Mercurial treats file names as shell-style extended
519 glob patterns.
544 glob patterns.
520
545
521 Alternate pattern notations must be specified explicitly.
546 Alternate pattern notations must be specified explicitly.
522
547
523 To use a plain path name without any pattern matching, start a
548 To use a plain path name without any pattern matching, start a
524 name with "path:". These path names must match completely, from
549 name with "path:". These path names must match completely, from
525 the root of the current repository.
550 the root of the current repository.
526
551
527 To use an extended glob, start a name with "glob:". Globs are
552 To use an extended glob, start a name with "glob:". Globs are
528 rooted at the current directory; a glob such as "*.c" will match
553 rooted at the current directory; a glob such as "*.c" will match
529 files ending in ".c" in the current directory only.
554 files ending in ".c" in the current directory only.
530
555
531 The supported glob syntax extensions are "**" to match any string
556 The supported glob syntax extensions are "**" to match any string
532 across path separators, and "{a,b}" to mean "a or b".
557 across path separators, and "{a,b}" to mean "a or b".
533
558
534 To use a Perl/Python regular expression, start a name with "re:".
559 To use a Perl/Python regular expression, start a name with "re:".
535 Regexp pattern matching is anchored at the root of the repository.
560 Regexp pattern matching is anchored at the root of the repository.
536
561
537 Plain examples:
562 Plain examples:
538
563
539 path:foo/bar a name bar in a directory named foo in the root of
564 path:foo/bar a name bar in a directory named foo in the root of
540 the repository
565 the repository
541 path:path:name a file or directory named "path:name"
566 path:path:name a file or directory named "path:name"
542
567
543 Glob examples:
568 Glob examples:
544
569
545 glob:*.c any name ending in ".c" in the current directory
570 glob:*.c any name ending in ".c" in the current directory
546 *.c any name ending in ".c" in the current directory
571 *.c any name ending in ".c" in the current directory
547 **.c any name ending in ".c" in the current directory, or
572 **.c any name ending in ".c" in the current directory, or
548 any subdirectory
573 any subdirectory
549 foo/*.c any name ending in ".c" in the directory foo
574 foo/*.c any name ending in ".c" in the directory foo
550 foo/**.c any name ending in ".c" in the directory foo, or any
575 foo/**.c any name ending in ".c" in the directory foo, or any
551 subdirectory
576 subdirectory
552
577
553 Regexp examples:
578 Regexp examples:
554
579
555 re:.*\.c$ any name ending in ".c", anywhere in the repository
580 re:.*\.c$ any name ending in ".c", anywhere in the repository
556
581
557
582
558 SPECIFYING SINGLE REVISIONS
583 SPECIFYING SINGLE REVISIONS
559 ---------------------------
584 ---------------------------
560
585
561 Mercurial accepts several notations for identifying individual
586 Mercurial accepts several notations for identifying individual
562 revisions.
587 revisions.
563
588
564 A plain integer is treated as a revision number. Negative
589 A plain integer is treated as a revision number. Negative
565 integers are treated as offsets from the tip, with -1 denoting the
590 integers are treated as offsets from the tip, with -1 denoting the
566 tip.
591 tip.
567
592
568 A 40-digit hexadecimal string is treated as a unique revision
593 A 40-digit hexadecimal string is treated as a unique revision
569 identifier.
594 identifier.
570
595
571 A hexadecimal string less than 40 characters long is treated as a
596 A hexadecimal string less than 40 characters long is treated as a
572 unique revision identifier, and referred to as a short-form
597 unique revision identifier, and referred to as a short-form
573 identifier. A short-form identifier is only valid if it is the
598 identifier. A short-form identifier is only valid if it is the
574 prefix of one full-length identifier.
599 prefix of one full-length identifier.
575
600
576 Any other string is treated as a tag name, which is a symbolic
601 Any other string is treated as a tag name, which is a symbolic
577 name associated with a revision identifier. Tag names may not
602 name associated with a revision identifier. Tag names may not
578 contain the ":" character.
603 contain the ":" character.
579
604
580 The reserved name "tip" is a special tag that always identifies
605 The reserved name "tip" is a special tag that always identifies
581 the most recent revision.
606 the most recent revision.
582
607
583 SPECIFYING MULTIPLE REVISIONS
608 SPECIFYING MULTIPLE REVISIONS
584 -----------------------------
609 -----------------------------
585
610
586 When Mercurial accepts more than one revision, they may be
611 When Mercurial accepts more than one revision, they may be
587 specified individually, or provided as a continuous range,
612 specified individually, or provided as a continuous range,
588 separated by the ":" character.
613 separated by the ":" character.
589
614
590 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
615 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
591 are revision identifiers. Both BEGIN and END are optional. If
616 are revision identifiers. Both BEGIN and END are optional. If
592 BEGIN is not specified, it defaults to revision number 0. If END
617 BEGIN is not specified, it defaults to revision number 0. If END
593 is not specified, it defaults to the tip. The range ":" thus
618 is not specified, it defaults to the tip. The range ":" thus
594 means "all revisions".
619 means "all revisions".
595
620
596 If BEGIN is greater than END, revisions are treated in reverse
621 If BEGIN is greater than END, revisions are treated in reverse
597 order.
622 order.
598
623
599 A range acts as a closed interval. This means that a range of 3:5
624 A range acts as a closed interval. This means that a range of 3:5
600 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
625 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
601
626
602 ENVIRONMENT VARIABLES
627 ENVIRONMENT VARIABLES
603 ---------------------
628 ---------------------
604
629
605 HGEDITOR::
630 HGEDITOR::
606 This is the name of the editor to use when committing. Defaults to the
631 This is the name of the editor to use when committing. Defaults to the
607 value of EDITOR.
632 value of EDITOR.
608
633
609 (deprecated, use .hgrc)
634 (deprecated, use .hgrc)
610
635
611 HGMERGE::
636 HGMERGE::
612 An executable to use for resolving merge conflicts. The program
637 An executable to use for resolving merge conflicts. The program
613 will be executed with three arguments: local file, remote file,
638 will be executed with three arguments: local file, remote file,
614 ancestor file.
639 ancestor file.
615
640
616 The default program is "hgmerge", which is a shell script provided
641 The default program is "hgmerge", which is a shell script provided
617 by Mercurial with some sensible defaults.
642 by Mercurial with some sensible defaults.
618
643
619 (deprecated, use .hgrc)
644 (deprecated, use .hgrc)
620
645
621 HGUSER::
646 HGUSER::
622 This is the string used for the author of a commit.
647 This is the string used for the author of a commit.
623
648
624 (deprecated, use .hgrc)
649 (deprecated, use .hgrc)
625
650
626 EMAIL::
651 EMAIL::
627 If HGUSER is not set, this will be used as the author for a commit.
652 If HGUSER is not set, this will be used as the author for a commit.
628
653
629 LOGNAME::
654 LOGNAME::
630 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
655 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
631 '@hostname' appended) as the author value for a commit.
656 '@hostname' appended) as the author value for a commit.
632
657
633 EDITOR::
658 EDITOR::
634 This is the name of the editor used in the hgmerge script. It will be
659 This is the name of the editor used in the hgmerge script. It will be
635 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
660 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
636
661
637 PYTHONPATH::
662 PYTHONPATH::
638 This is used by Python to find imported modules and may need to be set
663 This is used by Python to find imported modules and may need to be set
639 appropriately if Mercurial is not installed system-wide.
664 appropriately if Mercurial is not installed system-wide.
640
665
641 FILES
666 FILES
642 -----
667 -----
643 .hgignore::
668 .hgignore::
644 This file contains regular expressions (one per line) that describe file
669 This file contains regular expressions (one per line) that describe file
645 names that should be ignored by hg.
670 names that should be ignored by hg.
646
671
647 .hgtags::
672 .hgtags::
648 This file contains changeset hash values and text tag names (one of each
673 This file contains changeset hash values and text tag names (one of each
649 separated by spaces) that correspond to tagged versions of the repository
674 separated by spaces) that correspond to tagged versions of the repository
650 contents.
675 contents.
651
676
652 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
677 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
653 This file contains defaults and configuration. Values in .hg/hgrc
678 This file contains defaults and configuration. Values in .hg/hgrc
654 override those in $HOME/.hgrc, and these override settings made in the
679 override those in $HOME/.hgrc, and these override settings made in the
655 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
680 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
656 the contents and format of these files.
681 the contents and format of these files.
657
682
658 BUGS
683 BUGS
659 ----
684 ----
660 Probably lots, please post them to the mailing list (See Resources below)
685 Probably lots, please post them to the mailing list (See Resources below)
661 when you find them.
686 when you find them.
662
687
663 SEE ALSO
688 SEE ALSO
664 --------
689 --------
665 hgrc(5)
690 hgrc(5)
666
691
667 AUTHOR
692 AUTHOR
668 ------
693 ------
669 Written by Matt Mackall <mpm@selenic.com>
694 Written by Matt Mackall <mpm@selenic.com>
670
695
671 RESOURCES
696 RESOURCES
672 ---------
697 ---------
673 http://selenic.com/mercurial[Main Web Site]
698 http://selenic.com/mercurial[Main Web Site]
674
699
675 http://www.serpentine.com/mercurial[Wiki site]
700 http://www.serpentine.com/mercurial[Wiki site]
676
701
677 http://selenic.com/hg[Source code repository]
702 http://selenic.com/hg[Source code repository]
678
703
679 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
704 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
680
705
681 COPYING
706 COPYING
682 -------
707 -------
683 Copyright (C) 2005 Matt Mackall.
708 Copyright (C) 2005 Matt Mackall.
684 Free use of this software is granted under the terms of the GNU General
709 Free use of this software is granted under the terms of the GNU General
685 Public License (GPL).
710 Public License (GPL).
@@ -1,1905 +1,1960
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 demandload(globals(), "os re sys signal shutil imp")
10 demandload(globals(), "os re sys signal shutil imp")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "errno socket version struct atexit sets")
13 demandload(globals(), "errno socket version struct atexit sets")
14
14
15 class UnknownCommand(Exception):
15 class UnknownCommand(Exception):
16 """Exception raised if command is not in the command table."""
16 """Exception raised if command is not in the command table."""
17
17
18 def filterfiles(filters, files):
18 def filterfiles(filters, files):
19 l = [x for x in files if x in filters]
19 l = [x for x in files if x in filters]
20
20
21 for t in filters:
21 for t in filters:
22 if t and t[-1] != "/":
22 if t and t[-1] != "/":
23 t += "/"
23 t += "/"
24 l += [x for x in files if x.startswith(t)]
24 l += [x for x in files if x.startswith(t)]
25 return l
25 return l
26
26
27 def relpath(repo, args):
27 def relpath(repo, args):
28 cwd = repo.getcwd()
28 cwd = repo.getcwd()
29 if cwd:
29 if cwd:
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return args
31 return args
32
32
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
35 opts.get('exclude'), head)
35 opts.get('exclude'), head)
36
36
37 def makewalk(repo, pats, opts, head=''):
37 def makewalk(repo, pats, opts, head=''):
38 cwd = repo.getcwd()
38 cwd = repo.getcwd()
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
40 exact = dict(zip(files, files))
40 exact = dict(zip(files, files))
41 def walk():
41 def walk():
42 for src, fn in repo.walk(files=files, match=matchfn):
42 for src, fn in repo.walk(files=files, match=matchfn):
43 yield src, fn, util.pathto(cwd, fn), fn in exact
43 yield src, fn, util.pathto(cwd, fn), fn in exact
44 return files, matchfn, walk()
44 return files, matchfn, walk()
45
45
46 def walk(repo, pats, opts, head=''):
46 def walk(repo, pats, opts, head=''):
47 files, matchfn, results = makewalk(repo, pats, opts, head)
47 files, matchfn, results = makewalk(repo, pats, opts, head)
48 for r in results:
48 for r in results:
49 yield r
49 yield r
50
50
51 def walkchangerevs(ui, repo, cwd, pats, opts):
51 def walkchangerevs(ui, repo, cwd, pats, opts):
52 # This code most commonly needs to iterate backwards over the
52 '''Iterate over files and the revs they changed in.
53 # history it is interested in. Doing so has awful
53
54 # (quadratic-looking) performance, so we use iterators in a
54 Callers most commonly need to iterate backwards over the history
55 # "windowed" way. Walk forwards through a window of revisions,
55 it is interested in. Doing so has awful (quadratic-looking)
56 # yielding them in the desired order, and walk the windows
56 performance, so we use iterators in a "windowed" way.
57 # themselves backwards.
57
58 We walk a window of revisions in the desired order. Within the
59 window, we first walk forwards to gather data, then in the desired
60 order (usually backwards) to display it.
61
62 This function returns an (iterator, getchange) pair. The
63 getchange function returns the changelog entry for a numeric
64 revision. The iterator yields 3-tuples. They will be of one of
65 the following forms:
66
67 "window", incrementing, lastrev: stepping through a window,
68 positive if walking forwards through revs, last rev in the
69 sequence iterated over - use to reset state for the current window
70
71 "add", rev, fns: out-of-order traversal of the given file names
72 fns, which changed during revision rev - use to gather data for
73 possible display
74
75 "iter", rev, None: in-order traversal of the revs earlier iterated
76 over with "add" - use to display data'''
58 cwd = repo.getcwd()
77 cwd = repo.getcwd()
59 if not pats and cwd:
78 if not pats and cwd:
60 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
79 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
61 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
80 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
62 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
81 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
63 pats, opts)
82 pats, opts)
64 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
83 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
65 wanted = {}
84 wanted = {}
66 slowpath = anypats
85 slowpath = anypats
67 window = 300
86 window = 300
68 fncache = {}
87 fncache = {}
88
89 chcache = {}
90 def getchange(rev):
91 ch = chcache.get(rev)
92 if ch is None:
93 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
94 return ch
95
69 if not slowpath and not files:
96 if not slowpath and not files:
70 # No files, no patterns. Display all revs.
97 # No files, no patterns. Display all revs.
71 wanted = dict(zip(revs, revs))
98 wanted = dict(zip(revs, revs))
72 if not slowpath:
99 if not slowpath:
73 # Only files, no patterns. Check the history of each file.
100 # Only files, no patterns. Check the history of each file.
74 def filerevgen(filelog):
101 def filerevgen(filelog):
75 for i in xrange(filelog.count() - 1, -1, -window):
102 for i in xrange(filelog.count() - 1, -1, -window):
76 revs = []
103 revs = []
77 for j in xrange(max(0, i - window), i + 1):
104 for j in xrange(max(0, i - window), i + 1):
78 revs.append(filelog.linkrev(filelog.node(j)))
105 revs.append(filelog.linkrev(filelog.node(j)))
79 revs.reverse()
106 revs.reverse()
80 for rev in revs:
107 for rev in revs:
81 yield rev
108 yield rev
82
109
83 minrev, maxrev = min(revs), max(revs)
110 minrev, maxrev = min(revs), max(revs)
84 for file in files:
111 for file in files:
85 filelog = repo.file(file)
112 filelog = repo.file(file)
86 # A zero count may be a directory or deleted file, so
113 # A zero count may be a directory or deleted file, so
87 # try to find matching entries on the slow path.
114 # try to find matching entries on the slow path.
88 if filelog.count() == 0:
115 if filelog.count() == 0:
89 slowpath = True
116 slowpath = True
90 break
117 break
91 for rev in filerevgen(filelog):
118 for rev in filerevgen(filelog):
92 if rev <= maxrev:
119 if rev <= maxrev:
93 if rev < minrev:
120 if rev < minrev:
94 break
121 break
95 fncache.setdefault(rev, [])
122 fncache.setdefault(rev, [])
96 fncache[rev].append(file)
123 fncache[rev].append(file)
97 wanted[rev] = 1
124 wanted[rev] = 1
98 if slowpath:
125 if slowpath:
99 # The slow path checks files modified in every changeset.
126 # The slow path checks files modified in every changeset.
100 def changerevgen():
127 def changerevgen():
101 for i in xrange(repo.changelog.count() - 1, -1, -window):
128 for i in xrange(repo.changelog.count() - 1, -1, -window):
102 for j in xrange(max(0, i - window), i + 1):
129 for j in xrange(max(0, i - window), i + 1):
103 yield j, repo.changelog.read(repo.lookup(str(j)))[3]
130 yield j, getchange(j)[3]
104
131
105 for rev, changefiles in changerevgen():
132 for rev, changefiles in changerevgen():
106 matches = filter(matchfn, changefiles)
133 matches = filter(matchfn, changefiles)
107 if matches:
134 if matches:
108 fncache[rev] = matches
135 fncache[rev] = matches
109 wanted[rev] = 1
136 wanted[rev] = 1
110
137
111 for i in xrange(0, len(revs), window):
138 def iterate():
112 yield 'window', revs[0] < revs[-1], revs[-1]
139 for i in xrange(0, len(revs), window):
113 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
140 yield 'window', revs[0] < revs[-1], revs[-1]
114 if rev in wanted]
141 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
115 srevs = list(nrevs)
142 if rev in wanted]
116 srevs.sort()
143 srevs = list(nrevs)
117 for rev in srevs:
144 srevs.sort()
118 fns = fncache.get(rev)
145 for rev in srevs:
119 if not fns:
146 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
120 fns = repo.changelog.read(repo.lookup(str(rev)))[3]
147 yield 'add', rev, fns
121 fns = filter(matchfn, fns)
148 for rev in nrevs:
122 yield 'add', rev, fns
149 yield 'iter', rev, None
123 for rev in nrevs:
150 return iterate(), getchange
124 yield 'iter', rev, None
125
151
126 revrangesep = ':'
152 revrangesep = ':'
127
153
128 def revrange(ui, repo, revs, revlog=None):
154 def revrange(ui, repo, revs, revlog=None):
129 """Yield revision as strings from a list of revision specifications."""
155 """Yield revision as strings from a list of revision specifications."""
130 if revlog is None:
156 if revlog is None:
131 revlog = repo.changelog
157 revlog = repo.changelog
132 revcount = revlog.count()
158 revcount = revlog.count()
133 def fix(val, defval):
159 def fix(val, defval):
134 if not val:
160 if not val:
135 return defval
161 return defval
136 try:
162 try:
137 num = int(val)
163 num = int(val)
138 if str(num) != val:
164 if str(num) != val:
139 raise ValueError
165 raise ValueError
140 if num < 0:
166 if num < 0:
141 num += revcount
167 num += revcount
142 if not (0 <= num < revcount):
168 if not (0 <= num < revcount):
143 raise ValueError
169 raise ValueError
144 except ValueError:
170 except ValueError:
145 try:
171 try:
146 num = repo.changelog.rev(repo.lookup(val))
172 num = repo.changelog.rev(repo.lookup(val))
147 except KeyError:
173 except KeyError:
148 try:
174 try:
149 num = revlog.rev(revlog.lookup(val))
175 num = revlog.rev(revlog.lookup(val))
150 except KeyError:
176 except KeyError:
151 raise util.Abort('invalid revision identifier %s', val)
177 raise util.Abort('invalid revision identifier %s', val)
152 return num
178 return num
179 seen = {}
153 for spec in revs:
180 for spec in revs:
154 if spec.find(revrangesep) >= 0:
181 if spec.find(revrangesep) >= 0:
155 start, end = spec.split(revrangesep, 1)
182 start, end = spec.split(revrangesep, 1)
156 start = fix(start, 0)
183 start = fix(start, 0)
157 end = fix(end, revcount - 1)
184 end = fix(end, revcount - 1)
158 step = start > end and -1 or 1
185 step = start > end and -1 or 1
159 for rev in xrange(start, end+step, step):
186 for rev in xrange(start, end+step, step):
187 if rev in seen: continue
188 seen[rev] = 1
160 yield str(rev)
189 yield str(rev)
161 else:
190 else:
162 yield str(fix(spec, None))
191 rev = fix(spec, None)
192 if rev in seen: continue
193 seen[rev] = 1
194 yield str(rev)
163
195
164 def make_filename(repo, r, pat, node=None,
196 def make_filename(repo, r, pat, node=None,
165 total=None, seqno=None, revwidth=None):
197 total=None, seqno=None, revwidth=None):
166 node_expander = {
198 node_expander = {
167 'H': lambda: hex(node),
199 'H': lambda: hex(node),
168 'R': lambda: str(r.rev(node)),
200 'R': lambda: str(r.rev(node)),
169 'h': lambda: short(node),
201 'h': lambda: short(node),
170 }
202 }
171 expander = {
203 expander = {
172 '%': lambda: '%',
204 '%': lambda: '%',
173 'b': lambda: os.path.basename(repo.root),
205 'b': lambda: os.path.basename(repo.root),
174 }
206 }
175
207
176 try:
208 try:
177 if node:
209 if node:
178 expander.update(node_expander)
210 expander.update(node_expander)
179 if node and revwidth is not None:
211 if node and revwidth is not None:
180 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
212 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
181 if total is not None:
213 if total is not None:
182 expander['N'] = lambda: str(total)
214 expander['N'] = lambda: str(total)
183 if seqno is not None:
215 if seqno is not None:
184 expander['n'] = lambda: str(seqno)
216 expander['n'] = lambda: str(seqno)
185 if total is not None and seqno is not None:
217 if total is not None and seqno is not None:
186 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
218 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
187
219
188 newname = []
220 newname = []
189 patlen = len(pat)
221 patlen = len(pat)
190 i = 0
222 i = 0
191 while i < patlen:
223 while i < patlen:
192 c = pat[i]
224 c = pat[i]
193 if c == '%':
225 if c == '%':
194 i += 1
226 i += 1
195 c = pat[i]
227 c = pat[i]
196 c = expander[c]()
228 c = expander[c]()
197 newname.append(c)
229 newname.append(c)
198 i += 1
230 i += 1
199 return ''.join(newname)
231 return ''.join(newname)
200 except KeyError, inst:
232 except KeyError, inst:
201 raise util.Abort("invalid format spec '%%%s' in output file name",
233 raise util.Abort("invalid format spec '%%%s' in output file name",
202 inst.args[0])
234 inst.args[0])
203
235
204 def make_file(repo, r, pat, node=None,
236 def make_file(repo, r, pat, node=None,
205 total=None, seqno=None, revwidth=None, mode='wb'):
237 total=None, seqno=None, revwidth=None, mode='wb'):
206 if not pat or pat == '-':
238 if not pat or pat == '-':
207 return 'w' in mode and sys.stdout or sys.stdin
239 return 'w' in mode and sys.stdout or sys.stdin
208 if hasattr(pat, 'write') and 'w' in mode:
240 if hasattr(pat, 'write') and 'w' in mode:
209 return pat
241 return pat
210 if hasattr(pat, 'read') and 'r' in mode:
242 if hasattr(pat, 'read') and 'r' in mode:
211 return pat
243 return pat
212 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
244 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
213 mode)
245 mode)
214
246
215 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
247 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
216 changes=None, text=False):
248 changes=None, text=False):
217 def date(c):
249 def date(c):
218 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
250 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
219
251
220 if not changes:
252 if not changes:
221 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
253 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
222 else:
254 else:
223 (c, a, d, u) = changes
255 (c, a, d, u) = changes
224 if files:
256 if files:
225 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
257 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
226
258
227 if not c and not a and not d:
259 if not c and not a and not d:
228 return
260 return
229
261
230 if node2:
262 if node2:
231 change = repo.changelog.read(node2)
263 change = repo.changelog.read(node2)
232 mmap2 = repo.manifest.read(change[0])
264 mmap2 = repo.manifest.read(change[0])
233 date2 = date(change)
265 date2 = date(change)
234 def read(f):
266 def read(f):
235 return repo.file(f).read(mmap2[f])
267 return repo.file(f).read(mmap2[f])
236 else:
268 else:
237 date2 = time.asctime()
269 date2 = time.asctime()
238 if not node1:
270 if not node1:
239 node1 = repo.dirstate.parents()[0]
271 node1 = repo.dirstate.parents()[0]
240 def read(f):
272 def read(f):
241 return repo.wfile(f).read()
273 return repo.wfile(f).read()
242
274
243 if ui.quiet:
275 if ui.quiet:
244 r = None
276 r = None
245 else:
277 else:
246 hexfunc = ui.verbose and hex or short
278 hexfunc = ui.verbose and hex or short
247 r = [hexfunc(node) for node in [node1, node2] if node]
279 r = [hexfunc(node) for node in [node1, node2] if node]
248
280
249 change = repo.changelog.read(node1)
281 change = repo.changelog.read(node1)
250 mmap = repo.manifest.read(change[0])
282 mmap = repo.manifest.read(change[0])
251 date1 = date(change)
283 date1 = date(change)
252
284
253 for f in c:
285 for f in c:
254 to = None
286 to = None
255 if f in mmap:
287 if f in mmap:
256 to = repo.file(f).read(mmap[f])
288 to = repo.file(f).read(mmap[f])
257 tn = read(f)
289 tn = read(f)
258 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
290 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
259 for f in a:
291 for f in a:
260 to = None
292 to = None
261 tn = read(f)
293 tn = read(f)
262 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
294 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
263 for f in d:
295 for f in d:
264 to = repo.file(f).read(mmap[f])
296 to = repo.file(f).read(mmap[f])
265 tn = None
297 tn = None
266 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
298 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
267
299
300 def trimuser(ui, rev, name, revcache):
301 """trim the name of the user who committed a change"""
302 try:
303 return revcache[rev]
304 except KeyError:
305 if not ui.verbose:
306 f = name.find('@')
307 if f >= 0:
308 name = name[:f]
309 f = name.find('<')
310 if f >= 0:
311 name = name[f+1:]
312 revcache[rev] = name
313 return name
314
268 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
315 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
269 """show a single changeset or file revision"""
316 """show a single changeset or file revision"""
270 log = repo.changelog
317 log = repo.changelog
271 if changenode is None:
318 if changenode is None:
272 changenode = log.node(rev)
319 changenode = log.node(rev)
273 elif not rev:
320 elif not rev:
274 rev = log.rev(changenode)
321 rev = log.rev(changenode)
275
322
276 if ui.quiet:
323 if ui.quiet:
277 ui.write("%d:%s\n" % (rev, short(changenode)))
324 ui.write("%d:%s\n" % (rev, short(changenode)))
278 return
325 return
279
326
280 changes = log.read(changenode)
327 changes = log.read(changenode)
281
328
282 t, tz = changes[2].split(' ')
329 t, tz = changes[2].split(' ')
283 # a conversion tool was sticking non-integer offsets into repos
330 # a conversion tool was sticking non-integer offsets into repos
284 try:
331 try:
285 tz = int(tz)
332 tz = int(tz)
286 except ValueError:
333 except ValueError:
287 tz = 0
334 tz = 0
288 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
335 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
289
336
290 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
337 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
291 for p in log.parents(changenode)
338 for p in log.parents(changenode)
292 if ui.debugflag or p != nullid]
339 if ui.debugflag or p != nullid]
293 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
340 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
294 parents = []
341 parents = []
295
342
296 if ui.verbose:
343 if ui.verbose:
297 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
344 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
298 else:
345 else:
299 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
346 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
300
347
301 for tag in repo.nodetags(changenode):
348 for tag in repo.nodetags(changenode):
302 ui.status("tag: %s\n" % tag)
349 ui.status("tag: %s\n" % tag)
303 for parent in parents:
350 for parent in parents:
304 ui.write("parent: %d:%s\n" % parent)
351 ui.write("parent: %d:%s\n" % parent)
305
352
306 if brinfo and changenode in brinfo:
353 if brinfo and changenode in brinfo:
307 br = brinfo[changenode]
354 br = brinfo[changenode]
308 ui.write("branch: %s\n" % " ".join(br))
355 ui.write("branch: %s\n" % " ".join(br))
309
356
310 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
357 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
311 hex(changes[0])))
358 hex(changes[0])))
312 ui.status("user: %s\n" % changes[1])
359 ui.status("user: %s\n" % changes[1])
313 ui.status("date: %s\n" % date)
360 ui.status("date: %s\n" % date)
314
361
315 if ui.debugflag:
362 if ui.debugflag:
316 files = repo.changes(log.parents(changenode)[0], changenode)
363 files = repo.changes(log.parents(changenode)[0], changenode)
317 for key, value in zip(["files:", "files+:", "files-:"], files):
364 for key, value in zip(["files:", "files+:", "files-:"], files):
318 if value:
365 if value:
319 ui.note("%-12s %s\n" % (key, " ".join(value)))
366 ui.note("%-12s %s\n" % (key, " ".join(value)))
320 else:
367 else:
321 ui.note("files: %s\n" % " ".join(changes[3]))
368 ui.note("files: %s\n" % " ".join(changes[3]))
322
369
323 description = changes[4].strip()
370 description = changes[4].strip()
324 if description:
371 if description:
325 if ui.verbose:
372 if ui.verbose:
326 ui.status("description:\n")
373 ui.status("description:\n")
327 ui.status(description)
374 ui.status(description)
328 ui.status("\n\n")
375 ui.status("\n\n")
329 else:
376 else:
330 ui.status("summary: %s\n" % description.splitlines()[0])
377 ui.status("summary: %s\n" % description.splitlines()[0])
331 ui.status("\n")
378 ui.status("\n")
332
379
333 def show_version(ui):
380 def show_version(ui):
334 """output version and copyright information"""
381 """output version and copyright information"""
335 ui.write("Mercurial Distributed SCM (version %s)\n"
382 ui.write("Mercurial Distributed SCM (version %s)\n"
336 % version.get_version())
383 % version.get_version())
337 ui.status(
384 ui.status(
338 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
385 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
339 "This is free software; see the source for copying conditions. "
386 "This is free software; see the source for copying conditions. "
340 "There is NO\nwarranty; "
387 "There is NO\nwarranty; "
341 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
388 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
342 )
389 )
343
390
344 def help_(ui, cmd=None, with_version=False):
391 def help_(ui, cmd=None, with_version=False):
345 """show help for a given command or all commands"""
392 """show help for a given command or all commands"""
346 option_lists = []
393 option_lists = []
347 if cmd and cmd != 'shortlist':
394 if cmd and cmd != 'shortlist':
348 if with_version:
395 if with_version:
349 show_version(ui)
396 show_version(ui)
350 ui.write('\n')
397 ui.write('\n')
351 key, i = find(cmd)
398 key, i = find(cmd)
352 # synopsis
399 # synopsis
353 ui.write("%s\n\n" % i[2])
400 ui.write("%s\n\n" % i[2])
354
401
355 # description
402 # description
356 doc = i[0].__doc__
403 doc = i[0].__doc__
357 if ui.quiet:
404 if ui.quiet:
358 doc = doc.splitlines(0)[0]
405 doc = doc.splitlines(0)[0]
359 ui.write("%s\n" % doc.rstrip())
406 ui.write("%s\n" % doc.rstrip())
360
407
361 if not ui.quiet:
408 if not ui.quiet:
362 # aliases
409 # aliases
363 aliases = ', '.join(key.split('|')[1:])
410 aliases = ', '.join(key.split('|')[1:])
364 if aliases:
411 if aliases:
365 ui.write("\naliases: %s\n" % aliases)
412 ui.write("\naliases: %s\n" % aliases)
366
413
367 # options
414 # options
368 if i[1]:
415 if i[1]:
369 option_lists.append(("options", i[1]))
416 option_lists.append(("options", i[1]))
370
417
371 else:
418 else:
372 # program name
419 # program name
373 if ui.verbose or with_version:
420 if ui.verbose or with_version:
374 show_version(ui)
421 show_version(ui)
375 else:
422 else:
376 ui.status("Mercurial Distributed SCM\n")
423 ui.status("Mercurial Distributed SCM\n")
377 ui.status('\n')
424 ui.status('\n')
378
425
379 # list of commands
426 # list of commands
380 if cmd == "shortlist":
427 if cmd == "shortlist":
381 ui.status('basic commands (use "hg help" '
428 ui.status('basic commands (use "hg help" '
382 'for the full list or option "-v" for details):\n\n')
429 'for the full list or option "-v" for details):\n\n')
383 elif ui.verbose:
430 elif ui.verbose:
384 ui.status('list of commands:\n\n')
431 ui.status('list of commands:\n\n')
385 else:
432 else:
386 ui.status('list of commands (use "hg help -v" '
433 ui.status('list of commands (use "hg help -v" '
387 'to show aliases and global options):\n\n')
434 'to show aliases and global options):\n\n')
388
435
389 h = {}
436 h = {}
390 cmds = {}
437 cmds = {}
391 for c, e in table.items():
438 for c, e in table.items():
392 f = c.split("|")[0]
439 f = c.split("|")[0]
393 if cmd == "shortlist" and not f.startswith("^"):
440 if cmd == "shortlist" and not f.startswith("^"):
394 continue
441 continue
395 f = f.lstrip("^")
442 f = f.lstrip("^")
396 if not ui.debugflag and f.startswith("debug"):
443 if not ui.debugflag and f.startswith("debug"):
397 continue
444 continue
398 d = ""
445 d = ""
399 if e[0].__doc__:
446 if e[0].__doc__:
400 d = e[0].__doc__.splitlines(0)[0].rstrip()
447 d = e[0].__doc__.splitlines(0)[0].rstrip()
401 h[f] = d
448 h[f] = d
402 cmds[f]=c.lstrip("^")
449 cmds[f]=c.lstrip("^")
403
450
404 fns = h.keys()
451 fns = h.keys()
405 fns.sort()
452 fns.sort()
406 m = max(map(len, fns))
453 m = max(map(len, fns))
407 for f in fns:
454 for f in fns:
408 if ui.verbose:
455 if ui.verbose:
409 commands = cmds[f].replace("|",", ")
456 commands = cmds[f].replace("|",", ")
410 ui.write(" %s:\n %s\n"%(commands,h[f]))
457 ui.write(" %s:\n %s\n"%(commands,h[f]))
411 else:
458 else:
412 ui.write(' %-*s %s\n' % (m, f, h[f]))
459 ui.write(' %-*s %s\n' % (m, f, h[f]))
413
460
414 # global options
461 # global options
415 if ui.verbose:
462 if ui.verbose:
416 option_lists.append(("global options", globalopts))
463 option_lists.append(("global options", globalopts))
417
464
418 # list all option lists
465 # list all option lists
419 opt_output = []
466 opt_output = []
420 for title, options in option_lists:
467 for title, options in option_lists:
421 opt_output.append(("\n%s:\n" % title, None))
468 opt_output.append(("\n%s:\n" % title, None))
422 for shortopt, longopt, default, desc in options:
469 for shortopt, longopt, default, desc in options:
423 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
470 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
424 longopt and " --%s" % longopt),
471 longopt and " --%s" % longopt),
425 "%s%s" % (desc,
472 "%s%s" % (desc,
426 default and " (default: %s)" % default
473 default and " (default: %s)" % default
427 or "")))
474 or "")))
428
475
429 if opt_output:
476 if opt_output:
430 opts_len = max([len(line[0]) for line in opt_output if line[1]])
477 opts_len = max([len(line[0]) for line in opt_output if line[1]])
431 for first, second in opt_output:
478 for first, second in opt_output:
432 if second:
479 if second:
433 ui.write(" %-*s %s\n" % (opts_len, first, second))
480 ui.write(" %-*s %s\n" % (opts_len, first, second))
434 else:
481 else:
435 ui.write("%s\n" % first)
482 ui.write("%s\n" % first)
436
483
437 # Commands start here, listed alphabetically
484 # Commands start here, listed alphabetically
438
485
439 def add(ui, repo, *pats, **opts):
486 def add(ui, repo, *pats, **opts):
440 '''add the specified files on the next commit'''
487 '''add the specified files on the next commit'''
441 names = []
488 names = []
442 for src, abs, rel, exact in walk(repo, pats, opts):
489 for src, abs, rel, exact in walk(repo, pats, opts):
443 if exact:
490 if exact:
444 names.append(abs)
491 names.append(abs)
445 elif repo.dirstate.state(abs) == '?':
492 elif repo.dirstate.state(abs) == '?':
446 ui.status('adding %s\n' % rel)
493 ui.status('adding %s\n' % rel)
447 names.append(abs)
494 names.append(abs)
448 repo.add(names)
495 repo.add(names)
449
496
450 def addremove(ui, repo, *pats, **opts):
497 def addremove(ui, repo, *pats, **opts):
451 """add all new files, delete all missing files"""
498 """add all new files, delete all missing files"""
452 add, remove = [], []
499 add, remove = [], []
453 for src, abs, rel, exact in walk(repo, pats, opts):
500 for src, abs, rel, exact in walk(repo, pats, opts):
454 if src == 'f' and repo.dirstate.state(abs) == '?':
501 if src == 'f' and repo.dirstate.state(abs) == '?':
455 add.append(abs)
502 add.append(abs)
456 if not exact:
503 if not exact:
457 ui.status('adding ', rel, '\n')
504 ui.status('adding ', rel, '\n')
458 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
505 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
459 remove.append(abs)
506 remove.append(abs)
460 if not exact:
507 if not exact:
461 ui.status('removing ', rel, '\n')
508 ui.status('removing ', rel, '\n')
462 repo.add(add)
509 repo.add(add)
463 repo.remove(remove)
510 repo.remove(remove)
464
511
465 def annotate(ui, repo, *pats, **opts):
512 def annotate(ui, repo, *pats, **opts):
466 """show changeset information per file line"""
513 """show changeset information per file line"""
467 def getnode(rev):
514 def getnode(rev):
468 return short(repo.changelog.node(rev))
515 return short(repo.changelog.node(rev))
469
516
517 ucache = {}
470 def getname(rev):
518 def getname(rev):
471 try:
519 cl = repo.changelog.read(repo.changelog.node(rev))
472 return bcache[rev]
520 return trimuser(ui, rev, cl[1], ucache)
473 except KeyError:
474 cl = repo.changelog.read(repo.changelog.node(rev))
475 name = cl[1]
476 f = name.find('@')
477 if f >= 0:
478 name = name[:f]
479 f = name.find('<')
480 if f >= 0:
481 name = name[f+1:]
482 bcache[rev] = name
483 return name
484
521
485 if not pats:
522 if not pats:
486 raise util.Abort('at least one file name or pattern required')
523 raise util.Abort('at least one file name or pattern required')
487
524
488 bcache = {}
489 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
525 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
490 if not opts['user'] and not opts['changeset']:
526 if not opts['user'] and not opts['changeset']:
491 opts['number'] = 1
527 opts['number'] = 1
492
528
493 if opts['rev']:
529 if opts['rev']:
494 node = repo.changelog.lookup(opts['rev'])
530 node = repo.changelog.lookup(opts['rev'])
495 else:
531 else:
496 node = repo.dirstate.parents()[0]
532 node = repo.dirstate.parents()[0]
497 change = repo.changelog.read(node)
533 change = repo.changelog.read(node)
498 mmap = repo.manifest.read(change[0])
534 mmap = repo.manifest.read(change[0])
499
535
500 for src, abs, rel, exact in walk(repo, pats, opts):
536 for src, abs, rel, exact in walk(repo, pats, opts):
501 if abs not in mmap:
537 if abs not in mmap:
502 ui.warn("warning: %s is not in the repository!\n" % rel)
538 ui.warn("warning: %s is not in the repository!\n" % rel)
503 continue
539 continue
504
540
505 f = repo.file(abs)
541 f = repo.file(abs)
506 if not opts['text'] and util.binary(f.read(mmap[abs])):
542 if not opts['text'] and util.binary(f.read(mmap[abs])):
507 ui.write("%s: binary file\n" % rel)
543 ui.write("%s: binary file\n" % rel)
508 continue
544 continue
509
545
510 lines = f.annotate(mmap[abs])
546 lines = f.annotate(mmap[abs])
511 pieces = []
547 pieces = []
512
548
513 for o, f in opmap:
549 for o, f in opmap:
514 if opts[o]:
550 if opts[o]:
515 l = [f(n) for n, dummy in lines]
551 l = [f(n) for n, dummy in lines]
516 if l:
552 if l:
517 m = max(map(len, l))
553 m = max(map(len, l))
518 pieces.append(["%*s" % (m, x) for x in l])
554 pieces.append(["%*s" % (m, x) for x in l])
519
555
520 if pieces:
556 if pieces:
521 for p, l in zip(zip(*pieces), lines):
557 for p, l in zip(zip(*pieces), lines):
522 ui.write("%s: %s" % (" ".join(p), l[1]))
558 ui.write("%s: %s" % (" ".join(p), l[1]))
523
559
524 def cat(ui, repo, file1, rev=None, **opts):
560 def cat(ui, repo, file1, rev=None, **opts):
525 """output the latest or given revision of a file"""
561 """output the latest or given revision of a file"""
526 r = repo.file(relpath(repo, [file1])[0])
562 r = repo.file(relpath(repo, [file1])[0])
527 if rev:
563 if rev:
528 try:
564 try:
529 # assume all revision numbers are for changesets
565 # assume all revision numbers are for changesets
530 n = repo.lookup(rev)
566 n = repo.lookup(rev)
531 change = repo.changelog.read(n)
567 change = repo.changelog.read(n)
532 m = repo.manifest.read(change[0])
568 m = repo.manifest.read(change[0])
533 n = m[relpath(repo, [file1])[0]]
569 n = m[relpath(repo, [file1])[0]]
534 except hg.RepoError, KeyError:
570 except hg.RepoError, KeyError:
535 n = r.lookup(rev)
571 n = r.lookup(rev)
536 else:
572 else:
537 n = r.tip()
573 n = r.tip()
538 fp = make_file(repo, r, opts['output'], node=n)
574 fp = make_file(repo, r, opts['output'], node=n)
539 fp.write(r.read(n))
575 fp.write(r.read(n))
540
576
541 def clone(ui, source, dest=None, **opts):
577 def clone(ui, source, dest=None, **opts):
542 """make a copy of an existing repository"""
578 """make a copy of an existing repository"""
543 if dest is None:
579 if dest is None:
544 dest = os.path.basename(os.path.normpath(source))
580 dest = os.path.basename(os.path.normpath(source))
545
581
546 if os.path.exists(dest):
582 if os.path.exists(dest):
547 ui.warn("abort: destination '%s' already exists\n" % dest)
583 ui.warn("abort: destination '%s' already exists\n" % dest)
548 return 1
584 return 1
549
585
550 dest = os.path.realpath(dest)
586 dest = os.path.realpath(dest)
551
587
552 class Dircleanup:
588 class Dircleanup:
553 def __init__(self, dir_):
589 def __init__(self, dir_):
554 self.rmtree = shutil.rmtree
590 self.rmtree = shutil.rmtree
555 self.dir_ = dir_
591 self.dir_ = dir_
556 os.mkdir(dir_)
592 os.mkdir(dir_)
557 def close(self):
593 def close(self):
558 self.dir_ = None
594 self.dir_ = None
559 def __del__(self):
595 def __del__(self):
560 if self.dir_:
596 if self.dir_:
561 self.rmtree(self.dir_, True)
597 self.rmtree(self.dir_, True)
562
598
563 if opts['ssh']:
599 if opts['ssh']:
564 ui.setconfig("ui", "ssh", opts['ssh'])
600 ui.setconfig("ui", "ssh", opts['ssh'])
565 if opts['remotecmd']:
601 if opts['remotecmd']:
566 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
602 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
567
603
568 d = Dircleanup(dest)
604 d = Dircleanup(dest)
569 source = ui.expandpath(source)
605 source = ui.expandpath(source)
570 abspath = source
606 abspath = source
571 other = hg.repository(ui, source)
607 other = hg.repository(ui, source)
572
608
573 if other.dev() != -1:
609 if other.dev() != -1:
574 abspath = os.path.abspath(source)
610 abspath = os.path.abspath(source)
575 copyfile = (os.stat(dest).st_dev == other.dev()
611 copyfile = (os.stat(dest).st_dev == other.dev()
576 and getattr(os, 'link', None) or shutil.copy2)
612 and getattr(os, 'link', None) or shutil.copy2)
577 if copyfile is not shutil.copy2:
613 if copyfile is not shutil.copy2:
578 ui.note("cloning by hardlink\n")
614 ui.note("cloning by hardlink\n")
579 # we use a lock here because because we're not nicely ordered
615 # we use a lock here because because we're not nicely ordered
580 l = lock.lock(os.path.join(source, ".hg", "lock"))
616 l = lock.lock(os.path.join(source, ".hg", "lock"))
581
617
582 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
618 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
583 copyfile)
619 copyfile)
584
620
585 for fn in "dirstate", "lock":
621 for fn in "dirstate", "lock":
586 try:
622 try:
587 os.unlink(os.path.join(dest, ".hg", fn))
623 os.unlink(os.path.join(dest, ".hg", fn))
588 except OSError:
624 except OSError:
589 pass
625 pass
590
626
591 repo = hg.repository(ui, dest)
627 repo = hg.repository(ui, dest)
592
628
593 else:
629 else:
594 repo = hg.repository(ui, dest, create=1)
630 repo = hg.repository(ui, dest, create=1)
595 repo.pull(other)
631 repo.pull(other)
596
632
597 f = repo.opener("hgrc", "w")
633 f = repo.opener("hgrc", "w")
598 f.write("[paths]\n")
634 f.write("[paths]\n")
599 f.write("default = %s\n" % abspath)
635 f.write("default = %s\n" % abspath)
600
636
601 if not opts['noupdate']:
637 if not opts['noupdate']:
602 update(ui, repo)
638 update(ui, repo)
603
639
604 d.close()
640 d.close()
605
641
606 def commit(ui, repo, *pats, **opts):
642 def commit(ui, repo, *pats, **opts):
607 """commit the specified files or all outstanding changes"""
643 """commit the specified files or all outstanding changes"""
608 if opts['text']:
644 if opts['text']:
609 ui.warn("Warning: -t and --text is deprecated,"
645 ui.warn("Warning: -t and --text is deprecated,"
610 " please use -m or --message instead.\n")
646 " please use -m or --message instead.\n")
611 message = opts['message'] or opts['text']
647 message = opts['message'] or opts['text']
612 logfile = opts['logfile']
648 logfile = opts['logfile']
613 if not message and logfile:
649 if not message and logfile:
614 try:
650 try:
615 if logfile == '-':
651 if logfile == '-':
616 message = sys.stdin.read()
652 message = sys.stdin.read()
617 else:
653 else:
618 message = open(logfile).read()
654 message = open(logfile).read()
619 except IOError, why:
655 except IOError, why:
620 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
656 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
621
657
622 if opts['addremove']:
658 if opts['addremove']:
623 addremove(ui, repo, *pats, **opts)
659 addremove(ui, repo, *pats, **opts)
624 cwd = repo.getcwd()
660 cwd = repo.getcwd()
625 if not pats and cwd:
661 if not pats and cwd:
626 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
662 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
627 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
663 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
628 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
664 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
629 pats, opts)
665 pats, opts)
630 if pats:
666 if pats:
631 c, a, d, u = repo.changes(files=fns, match=match)
667 c, a, d, u = repo.changes(files=fns, match=match)
632 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
668 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
633 else:
669 else:
634 files = []
670 files = []
635 repo.commit(files, message, opts['user'], opts['date'], match)
671 repo.commit(files, message, opts['user'], opts['date'], match)
636
672
637 def copy(ui, repo, source, dest):
673 def copy(ui, repo, source, dest):
638 """mark a file as copied or renamed for the next commit"""
674 """mark a file as copied or renamed for the next commit"""
639 return repo.copy(*relpath(repo, (source, dest)))
675 return repo.copy(*relpath(repo, (source, dest)))
640
676
641 def debugcheckstate(ui, repo):
677 def debugcheckstate(ui, repo):
642 """validate the correctness of the current dirstate"""
678 """validate the correctness of the current dirstate"""
643 parent1, parent2 = repo.dirstate.parents()
679 parent1, parent2 = repo.dirstate.parents()
644 repo.dirstate.read()
680 repo.dirstate.read()
645 dc = repo.dirstate.map
681 dc = repo.dirstate.map
646 keys = dc.keys()
682 keys = dc.keys()
647 keys.sort()
683 keys.sort()
648 m1n = repo.changelog.read(parent1)[0]
684 m1n = repo.changelog.read(parent1)[0]
649 m2n = repo.changelog.read(parent2)[0]
685 m2n = repo.changelog.read(parent2)[0]
650 m1 = repo.manifest.read(m1n)
686 m1 = repo.manifest.read(m1n)
651 m2 = repo.manifest.read(m2n)
687 m2 = repo.manifest.read(m2n)
652 errors = 0
688 errors = 0
653 for f in dc:
689 for f in dc:
654 state = repo.dirstate.state(f)
690 state = repo.dirstate.state(f)
655 if state in "nr" and f not in m1:
691 if state in "nr" and f not in m1:
656 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
692 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
657 errors += 1
693 errors += 1
658 if state in "a" and f in m1:
694 if state in "a" and f in m1:
659 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
695 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
660 errors += 1
696 errors += 1
661 if state in "m" and f not in m1 and f not in m2:
697 if state in "m" and f not in m1 and f not in m2:
662 ui.warn("%s in state %s, but not in either manifest\n" %
698 ui.warn("%s in state %s, but not in either manifest\n" %
663 (f, state))
699 (f, state))
664 errors += 1
700 errors += 1
665 for f in m1:
701 for f in m1:
666 state = repo.dirstate.state(f)
702 state = repo.dirstate.state(f)
667 if state not in "nrm":
703 if state not in "nrm":
668 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
704 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
669 errors += 1
705 errors += 1
670 if errors:
706 if errors:
671 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
707 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
672
708
673 def debugconfig(ui):
709 def debugconfig(ui):
674 """show combined config settings from all hgrc files"""
710 """show combined config settings from all hgrc files"""
675 try:
711 try:
676 repo = hg.repository(ui)
712 repo = hg.repository(ui)
677 except hg.RepoError:
713 except hg.RepoError:
678 pass
714 pass
679 for section, name, value in ui.walkconfig():
715 for section, name, value in ui.walkconfig():
680 ui.write('%s.%s=%s\n' % (section, name, value))
716 ui.write('%s.%s=%s\n' % (section, name, value))
681
717
682 def debugstate(ui, repo):
718 def debugstate(ui, repo):
683 """show the contents of the current dirstate"""
719 """show the contents of the current dirstate"""
684 repo.dirstate.read()
720 repo.dirstate.read()
685 dc = repo.dirstate.map
721 dc = repo.dirstate.map
686 keys = dc.keys()
722 keys = dc.keys()
687 keys.sort()
723 keys.sort()
688 for file_ in keys:
724 for file_ in keys:
689 ui.write("%c %3o %10d %s %s\n"
725 ui.write("%c %3o %10d %s %s\n"
690 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
726 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
691 time.strftime("%x %X",
727 time.strftime("%x %X",
692 time.localtime(dc[file_][3])), file_))
728 time.localtime(dc[file_][3])), file_))
693 ui.write("\n")
729 ui.write("\n")
694 for f in repo.dirstate.copies:
730 for f in repo.dirstate.copies:
695 ui.write("%s -> %s\n" % (repo.dirstate.copies[f], f))
731 ui.write("%s -> %s\n" % (repo.dirstate.copies[f], f))
696
732
697 def debugdata(ui, file_, rev):
733 def debugdata(ui, file_, rev):
698 """dump the contents of an data file revision"""
734 """dump the contents of an data file revision"""
699 r = revlog.revlog(file, file_[:-2] + ".i", file_)
735 r = revlog.revlog(file, file_[:-2] + ".i", file_)
700 ui.write(r.revision(r.lookup(rev)))
736 ui.write(r.revision(r.lookup(rev)))
701
737
702 def debugindex(ui, file_):
738 def debugindex(ui, file_):
703 """dump the contents of an index file"""
739 """dump the contents of an index file"""
704 r = revlog.revlog(file, file_, "")
740 r = revlog.revlog(file, file_, "")
705 ui.write(" rev offset length base linkrev" +
741 ui.write(" rev offset length base linkrev" +
706 " nodeid p1 p2\n")
742 " nodeid p1 p2\n")
707 for i in range(r.count()):
743 for i in range(r.count()):
708 e = r.index[i]
744 e = r.index[i]
709 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
745 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
710 i, e[0], e[1], e[2], e[3],
746 i, e[0], e[1], e[2], e[3],
711 short(e[6]), short(e[4]), short(e[5])))
747 short(e[6]), short(e[4]), short(e[5])))
712
748
713 def debugindexdot(ui, file_):
749 def debugindexdot(ui, file_):
714 """dump an index DAG as a .dot file"""
750 """dump an index DAG as a .dot file"""
715 r = revlog.revlog(file, file_, "")
751 r = revlog.revlog(file, file_, "")
716 ui.write("digraph G {\n")
752 ui.write("digraph G {\n")
717 for i in range(r.count()):
753 for i in range(r.count()):
718 e = r.index[i]
754 e = r.index[i]
719 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
755 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
720 if e[5] != nullid:
756 if e[5] != nullid:
721 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
757 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
722 ui.write("}\n")
758 ui.write("}\n")
723
759
724 def debugrename(ui, repo, file, rev=None):
760 def debugrename(ui, repo, file, rev=None):
725 r = repo.file(relpath(repo, [file])[0])
761 r = repo.file(relpath(repo, [file])[0])
726 if rev:
762 if rev:
727 try:
763 try:
728 # assume all revision numbers are for changesets
764 # assume all revision numbers are for changesets
729 n = repo.lookup(rev)
765 n = repo.lookup(rev)
730 change = repo.changelog.read(n)
766 change = repo.changelog.read(n)
731 m = repo.manifest.read(change[0])
767 m = repo.manifest.read(change[0])
732 n = m[relpath(repo, [file])[0]]
768 n = m[relpath(repo, [file])[0]]
733 except hg.RepoError, KeyError:
769 except hg.RepoError, KeyError:
734 n = r.lookup(rev)
770 n = r.lookup(rev)
735 else:
771 else:
736 n = r.tip()
772 n = r.tip()
737 m = r.renamed(n)
773 m = r.renamed(n)
738 if m:
774 if m:
739 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
775 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
740 else:
776 else:
741 ui.write("not renamed\n")
777 ui.write("not renamed\n")
742
778
743 def debugwalk(ui, repo, *pats, **opts):
779 def debugwalk(ui, repo, *pats, **opts):
744 """show how files match on given patterns"""
780 """show how files match on given patterns"""
745 items = list(walk(repo, pats, opts))
781 items = list(walk(repo, pats, opts))
746 if not items:
782 if not items:
747 return
783 return
748 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
784 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
749 max([len(abs) for (src, abs, rel, exact) in items]),
785 max([len(abs) for (src, abs, rel, exact) in items]),
750 max([len(rel) for (src, abs, rel, exact) in items]))
786 max([len(rel) for (src, abs, rel, exact) in items]))
751 for src, abs, rel, exact in items:
787 for src, abs, rel, exact in items:
752 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
788 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
753
789
754 def diff(ui, repo, *pats, **opts):
790 def diff(ui, repo, *pats, **opts):
755 """diff working directory (or selected files)"""
791 """diff working directory (or selected files)"""
756 node1, node2 = None, None
792 node1, node2 = None, None
757 revs = [repo.lookup(x) for x in opts['rev']]
793 revs = [repo.lookup(x) for x in opts['rev']]
758
794
759 if len(revs) > 0:
795 if len(revs) > 0:
760 node1 = revs[0]
796 node1 = revs[0]
761 if len(revs) > 1:
797 if len(revs) > 1:
762 node2 = revs[1]
798 node2 = revs[1]
763 if len(revs) > 2:
799 if len(revs) > 2:
764 raise util.Abort("too many revisions to diff")
800 raise util.Abort("too many revisions to diff")
765
801
766 files = []
802 files = []
767 match = util.always
803 match = util.always
768 if pats:
804 if pats:
769 roots, match, results = makewalk(repo, pats, opts)
805 roots, match, results = makewalk(repo, pats, opts)
770 for src, abs, rel, exact in results:
806 for src, abs, rel, exact in results:
771 files.append(abs)
807 files.append(abs)
772
808
773 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
809 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
774 text=opts['text'])
810 text=opts['text'])
775
811
776 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
812 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
777 node = repo.lookup(changeset)
813 node = repo.lookup(changeset)
778 prev, other = repo.changelog.parents(node)
814 prev, other = repo.changelog.parents(node)
779 change = repo.changelog.read(node)
815 change = repo.changelog.read(node)
780
816
781 fp = make_file(repo, repo.changelog, opts['output'],
817 fp = make_file(repo, repo.changelog, opts['output'],
782 node=node, total=total, seqno=seqno,
818 node=node, total=total, seqno=seqno,
783 revwidth=revwidth)
819 revwidth=revwidth)
784 if fp != sys.stdout:
820 if fp != sys.stdout:
785 ui.note("%s\n" % fp.name)
821 ui.note("%s\n" % fp.name)
786
822
787 fp.write("# HG changeset patch\n")
823 fp.write("# HG changeset patch\n")
788 fp.write("# User %s\n" % change[1])
824 fp.write("# User %s\n" % change[1])
789 fp.write("# Node ID %s\n" % hex(node))
825 fp.write("# Node ID %s\n" % hex(node))
790 fp.write("# Parent %s\n" % hex(prev))
826 fp.write("# Parent %s\n" % hex(prev))
791 if other != nullid:
827 if other != nullid:
792 fp.write("# Parent %s\n" % hex(other))
828 fp.write("# Parent %s\n" % hex(other))
793 fp.write(change[4].rstrip())
829 fp.write(change[4].rstrip())
794 fp.write("\n\n")
830 fp.write("\n\n")
795
831
796 dodiff(fp, ui, repo, prev, node, text=opts['text'])
832 dodiff(fp, ui, repo, prev, node, text=opts['text'])
797 if fp != sys.stdout:
833 if fp != sys.stdout:
798 fp.close()
834 fp.close()
799
835
800 def export(ui, repo, *changesets, **opts):
836 def export(ui, repo, *changesets, **opts):
801 """dump the header and diffs for one or more changesets"""
837 """dump the header and diffs for one or more changesets"""
802 if not changesets:
838 if not changesets:
803 raise util.Abort("export requires at least one changeset")
839 raise util.Abort("export requires at least one changeset")
804 seqno = 0
840 seqno = 0
805 revs = list(revrange(ui, repo, changesets))
841 revs = list(revrange(ui, repo, changesets))
806 total = len(revs)
842 total = len(revs)
807 revwidth = max(map(len, revs))
843 revwidth = max(map(len, revs))
808 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
844 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
809 for cset in revs:
845 for cset in revs:
810 seqno += 1
846 seqno += 1
811 doexport(ui, repo, cset, seqno, total, revwidth, opts)
847 doexport(ui, repo, cset, seqno, total, revwidth, opts)
812
848
813 def forget(ui, repo, *pats, **opts):
849 def forget(ui, repo, *pats, **opts):
814 """don't add the specified files on the next commit"""
850 """don't add the specified files on the next commit"""
815 forget = []
851 forget = []
816 for src, abs, rel, exact in walk(repo, pats, opts):
852 for src, abs, rel, exact in walk(repo, pats, opts):
817 if repo.dirstate.state(abs) == 'a':
853 if repo.dirstate.state(abs) == 'a':
818 forget.append(abs)
854 forget.append(abs)
819 if not exact:
855 if not exact:
820 ui.status('forgetting ', rel, '\n')
856 ui.status('forgetting ', rel, '\n')
821 repo.forget(forget)
857 repo.forget(forget)
822
858
823 def grep(ui, repo, pattern, *pats, **opts):
859 def grep(ui, repo, pattern, *pats, **opts):
824 """search for a pattern in specified files and revisions"""
860 """search for a pattern in specified files and revisions"""
825 reflags = 0
861 reflags = 0
826 if opts['ignore_case']:
862 if opts['ignore_case']:
827 reflags |= re.I
863 reflags |= re.I
828 regexp = re.compile(pattern, reflags)
864 regexp = re.compile(pattern, reflags)
829 sep, end = ':', '\n'
865 sep, eol = ':', '\n'
830 if opts['print0']:
866 if opts['print0']:
831 sep = end = '\0'
867 sep = eol = '\0'
832
868
833 fcache = {}
869 fcache = {}
834 def getfile(fn):
870 def getfile(fn):
835 if fn not in fcache:
871 if fn not in fcache:
836 fcache[fn] = repo.file(fn)
872 fcache[fn] = repo.file(fn)
837 return fcache[fn]
873 return fcache[fn]
838
874
839 def matchlines(body):
875 def matchlines(body):
840 begin = 0
876 begin = 0
841 linenum = 0
877 linenum = 0
842 while True:
878 while True:
843 match = regexp.search(body, begin)
879 match = regexp.search(body, begin)
844 if not match:
880 if not match:
845 break
881 break
846 mstart, mend = match.span()
882 mstart, mend = match.span()
847 linenum += body.count('\n', begin, mstart) + 1
883 linenum += body.count('\n', begin, mstart) + 1
848 lstart = body.rfind('\n', begin, mstart) + 1 or begin
884 lstart = body.rfind('\n', begin, mstart) + 1 or begin
849 lend = body.find('\n', mend)
885 lend = body.find('\n', mend)
850 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
886 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
851 begin = lend + 1
887 begin = lend + 1
852
888
853 class linestate:
889 class linestate:
854 def __init__(self, line, linenum, colstart, colend):
890 def __init__(self, line, linenum, colstart, colend):
855 self.line = line
891 self.line = line
856 self.linenum = linenum
892 self.linenum = linenum
857 self.colstart = colstart
893 self.colstart = colstart
858 self.colend = colend
894 self.colend = colend
859 def __eq__(self, other):
895 def __eq__(self, other):
860 return self.line == other.line
896 return self.line == other.line
861 def __hash__(self):
897 def __hash__(self):
862 return hash(self.line)
898 return hash(self.line)
863
899
864 matches = {}
900 matches = {}
865 def grepbody(fn, rev, body):
901 def grepbody(fn, rev, body):
866 matches[rev].setdefault(fn, {})
902 matches[rev].setdefault(fn, {})
867 m = matches[rev][fn]
903 m = matches[rev][fn]
868 for lnum, cstart, cend, line in matchlines(body):
904 for lnum, cstart, cend, line in matchlines(body):
869 s = linestate(line, lnum, cstart, cend)
905 s = linestate(line, lnum, cstart, cend)
870 m[s] = s
906 m[s] = s
871
907
872 prev = {}
908 prev = {}
909 ucache = {}
873 def display(fn, rev, states, prevstates):
910 def display(fn, rev, states, prevstates):
874 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
911 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
875 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
912 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
876 counts = {'-': 0, '+': 0}
913 counts = {'-': 0, '+': 0}
914 filerevmatches = {}
877 for l in diff:
915 for l in diff:
878 if incrementing or not opts['every_match']:
916 if incrementing or not opts['every_match']:
879 change = ((l in prevstates) and '-') or '+'
917 change = ((l in prevstates) and '-') or '+'
880 r = rev
918 r = rev
881 else:
919 else:
882 change = ((l in states) and '-') or '+'
920 change = ((l in states) and '-') or '+'
883 r = prev[fn]
921 r = prev[fn]
884 ui.write('%s:%s:%s:%s%s\n' % (fn, r, l.linenum, change, l.line))
922 cols = [fn, str(rev)]
923 if opts['line_number']: cols.append(str(l.linenum))
924 if opts['every_match']: cols.append(change)
925 if opts['user']: cols.append(trimuser(ui, rev, getchange(rev)[1],
926 ucache))
927 if opts['files_with_matches']:
928 c = (fn, rev)
929 if c in filerevmatches: continue
930 filerevmatches[c] = 1
931 else:
932 cols.append(l.line)
933 ui.write(sep.join(cols), eol)
885 counts[change] += 1
934 counts[change] += 1
886 return counts['+'], counts['-']
935 return counts['+'], counts['-']
887
936
888 fstate = {}
937 fstate = {}
889 skip = {}
938 skip = {}
890 for st, rev, fns in walkchangerevs(ui, repo, repo.getcwd(), pats, opts):
939 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
940 count = 0
941 for st, rev, fns in changeiter:
891 if st == 'window':
942 if st == 'window':
892 incrementing = rev
943 incrementing = rev
893 matches.clear()
944 matches.clear()
894 elif st == 'add':
945 elif st == 'add':
895 change = repo.changelog.read(repo.lookup(str(rev)))
946 change = repo.changelog.read(repo.lookup(str(rev)))
896 mf = repo.manifest.read(change[0])
947 mf = repo.manifest.read(change[0])
897 matches[rev] = {}
948 matches[rev] = {}
898 for fn in fns:
949 for fn in fns:
899 if fn in skip: continue
950 if fn in skip: continue
900 fstate.setdefault(fn, {})
951 fstate.setdefault(fn, {})
901 try:
952 try:
902 grepbody(fn, rev, getfile(fn).read(mf[fn]))
953 grepbody(fn, rev, getfile(fn).read(mf[fn]))
903 except KeyError:
954 except KeyError:
904 pass
955 pass
905 elif st == 'iter':
956 elif st == 'iter':
906 states = matches[rev].items()
957 states = matches[rev].items()
907 states.sort()
958 states.sort()
908 for fn, m in states:
959 for fn, m in states:
909 if fn in skip: continue
960 if fn in skip: continue
910 if incrementing or not opts['every_match'] or fstate[fn]:
961 if incrementing or not opts['every_match'] or fstate[fn]:
911 pos, neg = display(fn, rev, m, fstate[fn])
962 pos, neg = display(fn, rev, m, fstate[fn])
963 count += pos + neg
912 if pos and not opts['every_match']:
964 if pos and not opts['every_match']:
913 skip[fn] = True
965 skip[fn] = True
914 fstate[fn] = m
966 fstate[fn] = m
915 prev[fn] = rev
967 prev[fn] = rev
916
968
917 if not incrementing:
969 if not incrementing:
918 fstate = fstate.items()
970 fstate = fstate.items()
919 fstate.sort()
971 fstate.sort()
920 for fn, state in fstate:
972 for fn, state in fstate:
921 if fn in skip: continue
973 if fn in skip: continue
922 display(fn, rev, {}, state)
974 display(fn, rev, {}, state)
975 return (count == 0 and 1) or 0
923
976
924 def heads(ui, repo, **opts):
977 def heads(ui, repo, **opts):
925 """show current repository heads"""
978 """show current repository heads"""
926 heads = repo.changelog.heads()
979 heads = repo.changelog.heads()
927 br = None
980 br = None
928 if opts['branches']:
981 if opts['branches']:
929 br = repo.branchlookup(heads)
982 br = repo.branchlookup(heads)
930 for n in repo.changelog.heads():
983 for n in repo.changelog.heads():
931 show_changeset(ui, repo, changenode=n, brinfo=br)
984 show_changeset(ui, repo, changenode=n, brinfo=br)
932
985
933 def identify(ui, repo):
986 def identify(ui, repo):
934 """print information about the working copy"""
987 """print information about the working copy"""
935 parents = [p for p in repo.dirstate.parents() if p != nullid]
988 parents = [p for p in repo.dirstate.parents() if p != nullid]
936 if not parents:
989 if not parents:
937 ui.write("unknown\n")
990 ui.write("unknown\n")
938 return
991 return
939
992
940 hexfunc = ui.verbose and hex or short
993 hexfunc = ui.verbose and hex or short
941 (c, a, d, u) = repo.changes()
994 (c, a, d, u) = repo.changes()
942 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
995 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
943 (c or a or d) and "+" or "")]
996 (c or a or d) and "+" or "")]
944
997
945 if not ui.quiet:
998 if not ui.quiet:
946 # multiple tags for a single parent separated by '/'
999 # multiple tags for a single parent separated by '/'
947 parenttags = ['/'.join(tags)
1000 parenttags = ['/'.join(tags)
948 for tags in map(repo.nodetags, parents) if tags]
1001 for tags in map(repo.nodetags, parents) if tags]
949 # tags for multiple parents separated by ' + '
1002 # tags for multiple parents separated by ' + '
950 if parenttags:
1003 if parenttags:
951 output.append(' + '.join(parenttags))
1004 output.append(' + '.join(parenttags))
952
1005
953 ui.write("%s\n" % ' '.join(output))
1006 ui.write("%s\n" % ' '.join(output))
954
1007
955 def import_(ui, repo, patch1, *patches, **opts):
1008 def import_(ui, repo, patch1, *patches, **opts):
956 """import an ordered set of patches"""
1009 """import an ordered set of patches"""
957 patches = (patch1,) + patches
1010 patches = (patch1,) + patches
958
1011
959 if not opts['force']:
1012 if not opts['force']:
960 (c, a, d, u) = repo.changes()
1013 (c, a, d, u) = repo.changes()
961 if c or a or d:
1014 if c or a or d:
962 ui.warn("abort: outstanding uncommitted changes!\n")
1015 ui.warn("abort: outstanding uncommitted changes!\n")
963 return 1
1016 return 1
964
1017
965 d = opts["base"]
1018 d = opts["base"]
966 strip = opts["strip"]
1019 strip = opts["strip"]
967
1020
968 for patch in patches:
1021 for patch in patches:
969 ui.status("applying %s\n" % patch)
1022 ui.status("applying %s\n" % patch)
970 pf = os.path.join(d, patch)
1023 pf = os.path.join(d, patch)
971
1024
972 message = []
1025 message = []
973 user = None
1026 user = None
974 hgpatch = False
1027 hgpatch = False
975 for line in file(pf):
1028 for line in file(pf):
976 line = line.rstrip()
1029 line = line.rstrip()
977 if line.startswith("--- ") or line.startswith("diff -r"):
1030 if line.startswith("--- ") or line.startswith("diff -r"):
978 break
1031 break
979 elif hgpatch:
1032 elif hgpatch:
980 # parse values when importing the result of an hg export
1033 # parse values when importing the result of an hg export
981 if line.startswith("# User "):
1034 if line.startswith("# User "):
982 user = line[7:]
1035 user = line[7:]
983 ui.debug('User: %s\n' % user)
1036 ui.debug('User: %s\n' % user)
984 elif not line.startswith("# ") and line:
1037 elif not line.startswith("# ") and line:
985 message.append(line)
1038 message.append(line)
986 hgpatch = False
1039 hgpatch = False
987 elif line == '# HG changeset patch':
1040 elif line == '# HG changeset patch':
988 hgpatch = True
1041 hgpatch = True
989 message = [] # We may have collected garbage
1042 message = [] # We may have collected garbage
990 else:
1043 else:
991 message.append(line)
1044 message.append(line)
992
1045
993 # make sure message isn't empty
1046 # make sure message isn't empty
994 if not message:
1047 if not message:
995 message = "imported patch %s\n" % patch
1048 message = "imported patch %s\n" % patch
996 else:
1049 else:
997 message = "%s\n" % '\n'.join(message)
1050 message = "%s\n" % '\n'.join(message)
998 ui.debug('message:\n%s\n' % message)
1051 ui.debug('message:\n%s\n' % message)
999
1052
1000 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1053 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1001 files = []
1054 files = []
1002 for l in f.read().splitlines():
1055 for l in f.read().splitlines():
1003 l.rstrip('\r\n');
1056 l.rstrip('\r\n');
1004 ui.status("%s\n" % l)
1057 ui.status("%s\n" % l)
1005 if l.startswith('patching file '):
1058 if l.startswith('patching file '):
1006 pf = l[14:]
1059 pf = l[14:]
1007 if pf not in files:
1060 if pf not in files:
1008 files.append(pf)
1061 files.append(pf)
1009 patcherr = f.close()
1062 patcherr = f.close()
1010 if patcherr:
1063 if patcherr:
1011 raise util.Abort("patch failed")
1064 raise util.Abort("patch failed")
1012
1065
1013 if len(files) > 0:
1066 if len(files) > 0:
1014 addremove(ui, repo, *files)
1067 addremove(ui, repo, *files)
1015 repo.commit(files, message, user)
1068 repo.commit(files, message, user)
1016
1069
1017 def incoming(ui, repo, source="default"):
1070 def incoming(ui, repo, source="default"):
1018 """show new changesets found in source"""
1071 """show new changesets found in source"""
1019 source = ui.expandpath(source)
1072 source = ui.expandpath(source)
1020 other = hg.repository(ui, source)
1073 other = hg.repository(ui, source)
1021 if not other.local():
1074 if not other.local():
1022 ui.warn("abort: incoming doesn't work for remote"
1075 ui.warn("abort: incoming doesn't work for remote"
1023 + " repositories yet, sorry!\n")
1076 + " repositories yet, sorry!\n")
1024 return 1
1077 return 1
1025 o = repo.findincoming(other)
1078 o = repo.findincoming(other)
1026 if not o:
1079 if not o:
1027 return
1080 return
1028 o = other.newer(o)
1081 o = other.newer(o)
1029 o.reverse()
1082 o.reverse()
1030 for n in o:
1083 for n in o:
1031 show_changeset(ui, other, changenode=n)
1084 show_changeset(ui, other, changenode=n)
1032
1085
1033 def init(ui, dest="."):
1086 def init(ui, dest="."):
1034 """create a new repository in the given directory"""
1087 """create a new repository in the given directory"""
1035 if not os.path.exists(dest):
1088 if not os.path.exists(dest):
1036 os.mkdir(dest)
1089 os.mkdir(dest)
1037 hg.repository(ui, dest, create=1)
1090 hg.repository(ui, dest, create=1)
1038
1091
1039 def locate(ui, repo, *pats, **opts):
1092 def locate(ui, repo, *pats, **opts):
1040 """locate files matching specific patterns"""
1093 """locate files matching specific patterns"""
1041 end = opts['print0'] and '\0' or '\n'
1094 end = opts['print0'] and '\0' or '\n'
1042
1095
1043 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1096 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1044 if repo.dirstate.state(abs) == '?':
1097 if repo.dirstate.state(abs) == '?':
1045 continue
1098 continue
1046 if opts['fullpath']:
1099 if opts['fullpath']:
1047 ui.write(os.path.join(repo.root, abs), end)
1100 ui.write(os.path.join(repo.root, abs), end)
1048 else:
1101 else:
1049 ui.write(rel, end)
1102 ui.write(rel, end)
1050
1103
1051 def log(ui, repo, *pats, **opts):
1104 def log(ui, repo, *pats, **opts):
1052 """show revision history of entire repository or files"""
1105 """show revision history of entire repository or files"""
1053 class dui:
1106 class dui:
1054 # Implement and delegate some ui protocol. Save hunks of
1107 # Implement and delegate some ui protocol. Save hunks of
1055 # output for later display in the desired order.
1108 # output for later display in the desired order.
1056 def __init__(self, ui):
1109 def __init__(self, ui):
1057 self.ui = ui
1110 self.ui = ui
1058 self.hunk = {}
1111 self.hunk = {}
1059 def bump(self, rev):
1112 def bump(self, rev):
1060 self.rev = rev
1113 self.rev = rev
1061 self.hunk[rev] = []
1114 self.hunk[rev] = []
1062 def note(self, *args):
1115 def note(self, *args):
1063 if self.verbose:
1116 if self.verbose:
1064 self.write(*args)
1117 self.write(*args)
1065 def status(self, *args):
1118 def status(self, *args):
1066 if not self.quiet:
1119 if not self.quiet:
1067 self.write(*args)
1120 self.write(*args)
1068 def write(self, *args):
1121 def write(self, *args):
1069 self.hunk[self.rev].append(args)
1122 self.hunk[self.rev].append(args)
1070 def __getattr__(self, key):
1123 def __getattr__(self, key):
1071 return getattr(self.ui, key)
1124 return getattr(self.ui, key)
1072 cwd = repo.getcwd()
1125 cwd = repo.getcwd()
1073 if not pats and cwd:
1126 if not pats and cwd:
1074 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1127 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1075 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1128 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1076 for st, rev, fns in walkchangerevs(ui, repo, (pats and cwd) or '', pats,
1129 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1077 opts):
1130 pats, opts)
1131 for st, rev, fns in changeiter:
1078 if st == 'window':
1132 if st == 'window':
1079 du = dui(ui)
1133 du = dui(ui)
1080 elif st == 'add':
1134 elif st == 'add':
1081 du.bump(rev)
1135 du.bump(rev)
1082 show_changeset(du, repo, rev)
1136 show_changeset(du, repo, rev)
1083 if opts['patch']:
1137 if opts['patch']:
1084 changenode = repo.changelog.node(rev)
1138 changenode = repo.changelog.node(rev)
1085 prev, other = repo.changelog.parents(changenode)
1139 prev, other = repo.changelog.parents(changenode)
1086 dodiff(du, du, repo, prev, changenode, fns)
1140 dodiff(du, du, repo, prev, changenode, fns)
1087 du.write("\n\n")
1141 du.write("\n\n")
1088 elif st == 'iter':
1142 elif st == 'iter':
1089 for args in du.hunk[rev]:
1143 for args in du.hunk[rev]:
1090 ui.write(*args)
1144 ui.write(*args)
1091
1145
1092 def manifest(ui, repo, rev=None):
1146 def manifest(ui, repo, rev=None):
1093 """output the latest or given revision of the project manifest"""
1147 """output the latest or given revision of the project manifest"""
1094 if rev:
1148 if rev:
1095 try:
1149 try:
1096 # assume all revision numbers are for changesets
1150 # assume all revision numbers are for changesets
1097 n = repo.lookup(rev)
1151 n = repo.lookup(rev)
1098 change = repo.changelog.read(n)
1152 change = repo.changelog.read(n)
1099 n = change[0]
1153 n = change[0]
1100 except hg.RepoError:
1154 except hg.RepoError:
1101 n = repo.manifest.lookup(rev)
1155 n = repo.manifest.lookup(rev)
1102 else:
1156 else:
1103 n = repo.manifest.tip()
1157 n = repo.manifest.tip()
1104 m = repo.manifest.read(n)
1158 m = repo.manifest.read(n)
1105 mf = repo.manifest.readflags(n)
1159 mf = repo.manifest.readflags(n)
1106 files = m.keys()
1160 files = m.keys()
1107 files.sort()
1161 files.sort()
1108
1162
1109 for f in files:
1163 for f in files:
1110 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1164 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1111
1165
1112 def outgoing(ui, repo, dest="default-push"):
1166 def outgoing(ui, repo, dest="default-push"):
1113 """show changesets not found in destination"""
1167 """show changesets not found in destination"""
1114 dest = ui.expandpath(dest)
1168 dest = ui.expandpath(dest)
1115 other = hg.repository(ui, dest)
1169 other = hg.repository(ui, dest)
1116 o = repo.findoutgoing(other)
1170 o = repo.findoutgoing(other)
1117 o = repo.newer(o)
1171 o = repo.newer(o)
1118 o.reverse()
1172 o.reverse()
1119 for n in o:
1173 for n in o:
1120 show_changeset(ui, repo, changenode=n)
1174 show_changeset(ui, repo, changenode=n)
1121
1175
1122 def parents(ui, repo, rev=None):
1176 def parents(ui, repo, rev=None):
1123 """show the parents of the working dir or revision"""
1177 """show the parents of the working dir or revision"""
1124 if rev:
1178 if rev:
1125 p = repo.changelog.parents(repo.lookup(rev))
1179 p = repo.changelog.parents(repo.lookup(rev))
1126 else:
1180 else:
1127 p = repo.dirstate.parents()
1181 p = repo.dirstate.parents()
1128
1182
1129 for n in p:
1183 for n in p:
1130 if n != nullid:
1184 if n != nullid:
1131 show_changeset(ui, repo, changenode=n)
1185 show_changeset(ui, repo, changenode=n)
1132
1186
1133 def paths(ui, search=None):
1187 def paths(ui, search=None):
1134 """show definition of symbolic path names"""
1188 """show definition of symbolic path names"""
1135 try:
1189 try:
1136 repo = hg.repository(ui=ui)
1190 repo = hg.repository(ui=ui)
1137 except hg.RepoError:
1191 except hg.RepoError:
1138 pass
1192 pass
1139
1193
1140 if search:
1194 if search:
1141 for name, path in ui.configitems("paths"):
1195 for name, path in ui.configitems("paths"):
1142 if name == search:
1196 if name == search:
1143 ui.write("%s\n" % path)
1197 ui.write("%s\n" % path)
1144 return
1198 return
1145 ui.warn("not found!\n")
1199 ui.warn("not found!\n")
1146 return 1
1200 return 1
1147 else:
1201 else:
1148 for name, path in ui.configitems("paths"):
1202 for name, path in ui.configitems("paths"):
1149 ui.write("%s = %s\n" % (name, path))
1203 ui.write("%s = %s\n" % (name, path))
1150
1204
1151 def pull(ui, repo, source="default", **opts):
1205 def pull(ui, repo, source="default", **opts):
1152 """pull changes from the specified source"""
1206 """pull changes from the specified source"""
1153 source = ui.expandpath(source)
1207 source = ui.expandpath(source)
1154 ui.status('pulling from %s\n' % (source))
1208 ui.status('pulling from %s\n' % (source))
1155
1209
1156 if opts['ssh']:
1210 if opts['ssh']:
1157 ui.setconfig("ui", "ssh", opts['ssh'])
1211 ui.setconfig("ui", "ssh", opts['ssh'])
1158 if opts['remotecmd']:
1212 if opts['remotecmd']:
1159 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1213 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1160
1214
1161 other = hg.repository(ui, source)
1215 other = hg.repository(ui, source)
1162 r = repo.pull(other)
1216 r = repo.pull(other)
1163 if not r:
1217 if not r:
1164 if opts['update']:
1218 if opts['update']:
1165 return update(ui, repo)
1219 return update(ui, repo)
1166 else:
1220 else:
1167 ui.status("(run 'hg update' to get a working copy)\n")
1221 ui.status("(run 'hg update' to get a working copy)\n")
1168
1222
1169 return r
1223 return r
1170
1224
1171 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1225 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1172 """push changes to the specified destination"""
1226 """push changes to the specified destination"""
1173 dest = ui.expandpath(dest)
1227 dest = ui.expandpath(dest)
1174 ui.status('pushing to %s\n' % (dest))
1228 ui.status('pushing to %s\n' % (dest))
1175
1229
1176 if ssh:
1230 if ssh:
1177 ui.setconfig("ui", "ssh", ssh)
1231 ui.setconfig("ui", "ssh", ssh)
1178 if remotecmd:
1232 if remotecmd:
1179 ui.setconfig("ui", "remotecmd", remotecmd)
1233 ui.setconfig("ui", "remotecmd", remotecmd)
1180
1234
1181 other = hg.repository(ui, dest)
1235 other = hg.repository(ui, dest)
1182 r = repo.push(other, force)
1236 r = repo.push(other, force)
1183 return r
1237 return r
1184
1238
1185 def rawcommit(ui, repo, *flist, **rc):
1239 def rawcommit(ui, repo, *flist, **rc):
1186 "raw commit interface"
1240 "raw commit interface"
1187 if rc['text']:
1241 if rc['text']:
1188 ui.warn("Warning: -t and --text is deprecated,"
1242 ui.warn("Warning: -t and --text is deprecated,"
1189 " please use -m or --message instead.\n")
1243 " please use -m or --message instead.\n")
1190 message = rc['message'] or rc['text']
1244 message = rc['message'] or rc['text']
1191 if not message and rc['logfile']:
1245 if not message and rc['logfile']:
1192 try:
1246 try:
1193 message = open(rc['logfile']).read()
1247 message = open(rc['logfile']).read()
1194 except IOError:
1248 except IOError:
1195 pass
1249 pass
1196 if not message and not rc['logfile']:
1250 if not message and not rc['logfile']:
1197 ui.warn("abort: missing commit message\n")
1251 ui.warn("abort: missing commit message\n")
1198 return 1
1252 return 1
1199
1253
1200 files = relpath(repo, list(flist))
1254 files = relpath(repo, list(flist))
1201 if rc['files']:
1255 if rc['files']:
1202 files += open(rc['files']).read().splitlines()
1256 files += open(rc['files']).read().splitlines()
1203
1257
1204 rc['parent'] = map(repo.lookup, rc['parent'])
1258 rc['parent'] = map(repo.lookup, rc['parent'])
1205
1259
1206 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1260 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1207
1261
1208 def recover(ui, repo):
1262 def recover(ui, repo):
1209 """roll back an interrupted transaction"""
1263 """roll back an interrupted transaction"""
1210 repo.recover()
1264 repo.recover()
1211
1265
1212 def remove(ui, repo, file1, *files):
1266 def remove(ui, repo, file1, *files):
1213 """remove the specified files on the next commit"""
1267 """remove the specified files on the next commit"""
1214 repo.remove(relpath(repo, (file1,) + files))
1268 repo.remove(relpath(repo, (file1,) + files))
1215
1269
1216 def revert(ui, repo, *names, **opts):
1270 def revert(ui, repo, *names, **opts):
1217 """revert modified files or dirs back to their unmodified states"""
1271 """revert modified files or dirs back to their unmodified states"""
1218 node = opts['rev'] and repo.lookup(opts['rev']) or \
1272 node = opts['rev'] and repo.lookup(opts['rev']) or \
1219 repo.dirstate.parents()[0]
1273 repo.dirstate.parents()[0]
1220 root = os.path.realpath(repo.root)
1274 root = os.path.realpath(repo.root)
1221
1275
1222 def trimpath(p):
1276 def trimpath(p):
1223 p = os.path.realpath(p)
1277 p = os.path.realpath(p)
1224 if p.startswith(root):
1278 if p.startswith(root):
1225 rest = p[len(root):]
1279 rest = p[len(root):]
1226 if not rest:
1280 if not rest:
1227 return rest
1281 return rest
1228 if p.startswith(os.sep):
1282 if p.startswith(os.sep):
1229 return rest[1:]
1283 return rest[1:]
1230 return p
1284 return p
1231
1285
1232 relnames = map(trimpath, names or [os.getcwd()])
1286 relnames = map(trimpath, names or [os.getcwd()])
1233 chosen = {}
1287 chosen = {}
1234
1288
1235 def choose(name):
1289 def choose(name):
1236 def body(name):
1290 def body(name):
1237 for r in relnames:
1291 for r in relnames:
1238 if not name.startswith(r):
1292 if not name.startswith(r):
1239 continue
1293 continue
1240 rest = name[len(r):]
1294 rest = name[len(r):]
1241 if not rest:
1295 if not rest:
1242 return r, True
1296 return r, True
1243 depth = rest.count(os.sep)
1297 depth = rest.count(os.sep)
1244 if not r:
1298 if not r:
1245 if depth == 0 or not opts['nonrecursive']:
1299 if depth == 0 or not opts['nonrecursive']:
1246 return r, True
1300 return r, True
1247 elif rest[0] == os.sep:
1301 elif rest[0] == os.sep:
1248 if depth == 1 or not opts['nonrecursive']:
1302 if depth == 1 or not opts['nonrecursive']:
1249 return r, True
1303 return r, True
1250 return None, False
1304 return None, False
1251 relname, ret = body(name)
1305 relname, ret = body(name)
1252 if ret:
1306 if ret:
1253 chosen[relname] = 1
1307 chosen[relname] = 1
1254 return ret
1308 return ret
1255
1309
1256 r = repo.update(node, False, True, choose, False)
1310 r = repo.update(node, False, True, choose, False)
1257 for n in relnames:
1311 for n in relnames:
1258 if n not in chosen:
1312 if n not in chosen:
1259 ui.warn('error: no matches for %s\n' % n)
1313 ui.warn('error: no matches for %s\n' % n)
1260 r = 1
1314 r = 1
1261 sys.stdout.flush()
1315 sys.stdout.flush()
1262 return r
1316 return r
1263
1317
1264 def root(ui, repo):
1318 def root(ui, repo):
1265 """print the root (top) of the current working dir"""
1319 """print the root (top) of the current working dir"""
1266 ui.write(repo.root + "\n")
1320 ui.write(repo.root + "\n")
1267
1321
1268 def serve(ui, repo, **opts):
1322 def serve(ui, repo, **opts):
1269 """export the repository via HTTP"""
1323 """export the repository via HTTP"""
1270
1324
1271 if opts["stdio"]:
1325 if opts["stdio"]:
1272 fin, fout = sys.stdin, sys.stdout
1326 fin, fout = sys.stdin, sys.stdout
1273 sys.stdout = sys.stderr
1327 sys.stdout = sys.stderr
1274
1328
1275 def getarg():
1329 def getarg():
1276 argline = fin.readline()[:-1]
1330 argline = fin.readline()[:-1]
1277 arg, l = argline.split()
1331 arg, l = argline.split()
1278 val = fin.read(int(l))
1332 val = fin.read(int(l))
1279 return arg, val
1333 return arg, val
1280 def respond(v):
1334 def respond(v):
1281 fout.write("%d\n" % len(v))
1335 fout.write("%d\n" % len(v))
1282 fout.write(v)
1336 fout.write(v)
1283 fout.flush()
1337 fout.flush()
1284
1338
1285 lock = None
1339 lock = None
1286
1340
1287 while 1:
1341 while 1:
1288 cmd = fin.readline()[:-1]
1342 cmd = fin.readline()[:-1]
1289 if cmd == '':
1343 if cmd == '':
1290 return
1344 return
1291 if cmd == "heads":
1345 if cmd == "heads":
1292 h = repo.heads()
1346 h = repo.heads()
1293 respond(" ".join(map(hex, h)) + "\n")
1347 respond(" ".join(map(hex, h)) + "\n")
1294 if cmd == "lock":
1348 if cmd == "lock":
1295 lock = repo.lock()
1349 lock = repo.lock()
1296 respond("")
1350 respond("")
1297 if cmd == "unlock":
1351 if cmd == "unlock":
1298 if lock:
1352 if lock:
1299 lock.release()
1353 lock.release()
1300 lock = None
1354 lock = None
1301 respond("")
1355 respond("")
1302 elif cmd == "branches":
1356 elif cmd == "branches":
1303 arg, nodes = getarg()
1357 arg, nodes = getarg()
1304 nodes = map(bin, nodes.split(" "))
1358 nodes = map(bin, nodes.split(" "))
1305 r = []
1359 r = []
1306 for b in repo.branches(nodes):
1360 for b in repo.branches(nodes):
1307 r.append(" ".join(map(hex, b)) + "\n")
1361 r.append(" ".join(map(hex, b)) + "\n")
1308 respond("".join(r))
1362 respond("".join(r))
1309 elif cmd == "between":
1363 elif cmd == "between":
1310 arg, pairs = getarg()
1364 arg, pairs = getarg()
1311 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1365 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1312 r = []
1366 r = []
1313 for b in repo.between(pairs):
1367 for b in repo.between(pairs):
1314 r.append(" ".join(map(hex, b)) + "\n")
1368 r.append(" ".join(map(hex, b)) + "\n")
1315 respond("".join(r))
1369 respond("".join(r))
1316 elif cmd == "changegroup":
1370 elif cmd == "changegroup":
1317 nodes = []
1371 nodes = []
1318 arg, roots = getarg()
1372 arg, roots = getarg()
1319 nodes = map(bin, roots.split(" "))
1373 nodes = map(bin, roots.split(" "))
1320
1374
1321 cg = repo.changegroup(nodes)
1375 cg = repo.changegroup(nodes)
1322 while 1:
1376 while 1:
1323 d = cg.read(4096)
1377 d = cg.read(4096)
1324 if not d:
1378 if not d:
1325 break
1379 break
1326 fout.write(d)
1380 fout.write(d)
1327
1381
1328 fout.flush()
1382 fout.flush()
1329
1383
1330 elif cmd == "addchangegroup":
1384 elif cmd == "addchangegroup":
1331 if not lock:
1385 if not lock:
1332 respond("not locked")
1386 respond("not locked")
1333 continue
1387 continue
1334 respond("")
1388 respond("")
1335
1389
1336 r = repo.addchangegroup(fin)
1390 r = repo.addchangegroup(fin)
1337 respond("")
1391 respond("")
1338
1392
1339 optlist = "name templates style address port ipv6 accesslog errorlog"
1393 optlist = "name templates style address port ipv6 accesslog errorlog"
1340 for o in optlist.split():
1394 for o in optlist.split():
1341 if opts[o]:
1395 if opts[o]:
1342 ui.setconfig("web", o, opts[o])
1396 ui.setconfig("web", o, opts[o])
1343
1397
1344 httpd = hgweb.create_server(repo)
1398 httpd = hgweb.create_server(repo)
1345
1399
1346 if ui.verbose:
1400 if ui.verbose:
1347 addr, port = httpd.socket.getsockname()
1401 addr, port = httpd.socket.getsockname()
1348 if addr == '0.0.0.0':
1402 if addr == '0.0.0.0':
1349 addr = socket.gethostname()
1403 addr = socket.gethostname()
1350 else:
1404 else:
1351 try:
1405 try:
1352 addr = socket.gethostbyaddr(addr)[0]
1406 addr = socket.gethostbyaddr(addr)[0]
1353 except socket.error:
1407 except socket.error:
1354 pass
1408 pass
1355 if port != 80:
1409 if port != 80:
1356 ui.status('listening at http://%s:%d/\n' % (addr, port))
1410 ui.status('listening at http://%s:%d/\n' % (addr, port))
1357 else:
1411 else:
1358 ui.status('listening at http://%s/\n' % addr)
1412 ui.status('listening at http://%s/\n' % addr)
1359 httpd.serve_forever()
1413 httpd.serve_forever()
1360
1414
1361 def status(ui, repo, *pats, **opts):
1415 def status(ui, repo, *pats, **opts):
1362 '''show changed files in the working directory
1416 '''show changed files in the working directory
1363
1417
1364 M = modified
1418 M = modified
1365 A = added
1419 A = added
1366 R = removed
1420 R = removed
1367 ? = not tracked
1421 ? = not tracked
1368 '''
1422 '''
1369
1423
1370 cwd = repo.getcwd()
1424 cwd = repo.getcwd()
1371 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1425 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1372 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1426 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1373 for n in repo.changes(files=files, match=matchfn)]
1427 for n in repo.changes(files=files, match=matchfn)]
1374
1428
1375 changetypes = [('modified', 'M', c),
1429 changetypes = [('modified', 'M', c),
1376 ('added', 'A', a),
1430 ('added', 'A', a),
1377 ('removed', 'R', d),
1431 ('removed', 'R', d),
1378 ('unknown', '?', u)]
1432 ('unknown', '?', u)]
1379
1433
1380 end = opts['print0'] and '\0' or '\n'
1434 end = opts['print0'] and '\0' or '\n'
1381
1435
1382 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1436 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1383 or changetypes):
1437 or changetypes):
1384 if opts['no_status']:
1438 if opts['no_status']:
1385 format = "%%s%s" % end
1439 format = "%%s%s" % end
1386 else:
1440 else:
1387 format = "%s %%s%s" % (char, end);
1441 format = "%s %%s%s" % (char, end);
1388
1442
1389 for f in changes:
1443 for f in changes:
1390 ui.write(format % f)
1444 ui.write(format % f)
1391
1445
1392 def tag(ui, repo, name, rev=None, **opts):
1446 def tag(ui, repo, name, rev=None, **opts):
1393 """add a tag for the current tip or a given revision"""
1447 """add a tag for the current tip or a given revision"""
1394 if opts['text']:
1448 if opts['text']:
1395 ui.warn("Warning: -t and --text is deprecated,"
1449 ui.warn("Warning: -t and --text is deprecated,"
1396 " please use -m or --message instead.\n")
1450 " please use -m or --message instead.\n")
1397 if name == "tip":
1451 if name == "tip":
1398 ui.warn("abort: 'tip' is a reserved name!\n")
1452 ui.warn("abort: 'tip' is a reserved name!\n")
1399 return -1
1453 return -1
1400 if rev:
1454 if rev:
1401 r = hex(repo.lookup(rev))
1455 r = hex(repo.lookup(rev))
1402 else:
1456 else:
1403 r = hex(repo.changelog.tip())
1457 r = hex(repo.changelog.tip())
1404
1458
1405 if name.find(revrangesep) >= 0:
1459 if name.find(revrangesep) >= 0:
1406 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1460 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1407 return -1
1461 return -1
1408
1462
1409 if opts['local']:
1463 if opts['local']:
1410 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1464 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1411 return
1465 return
1412
1466
1413 (c, a, d, u) = repo.changes()
1467 (c, a, d, u) = repo.changes()
1414 for x in (c, a, d, u):
1468 for x in (c, a, d, u):
1415 if ".hgtags" in x:
1469 if ".hgtags" in x:
1416 ui.warn("abort: working copy of .hgtags is changed!\n")
1470 ui.warn("abort: working copy of .hgtags is changed!\n")
1417 ui.status("(please commit .hgtags manually)\n")
1471 ui.status("(please commit .hgtags manually)\n")
1418 return -1
1472 return -1
1419
1473
1420 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1474 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1421 if repo.dirstate.state(".hgtags") == '?':
1475 if repo.dirstate.state(".hgtags") == '?':
1422 repo.add([".hgtags"])
1476 repo.add([".hgtags"])
1423
1477
1424 message = (opts['message'] or opts['text'] or
1478 message = (opts['message'] or opts['text'] or
1425 "Added tag %s for changeset %s" % (name, r))
1479 "Added tag %s for changeset %s" % (name, r))
1426 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1480 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1427
1481
1428 def tags(ui, repo):
1482 def tags(ui, repo):
1429 """list repository tags"""
1483 """list repository tags"""
1430
1484
1431 l = repo.tagslist()
1485 l = repo.tagslist()
1432 l.reverse()
1486 l.reverse()
1433 for t, n in l:
1487 for t, n in l:
1434 try:
1488 try:
1435 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1489 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1436 except KeyError:
1490 except KeyError:
1437 r = " ?:?"
1491 r = " ?:?"
1438 ui.write("%-30s %s\n" % (t, r))
1492 ui.write("%-30s %s\n" % (t, r))
1439
1493
1440 def tip(ui, repo):
1494 def tip(ui, repo):
1441 """show the tip revision"""
1495 """show the tip revision"""
1442 n = repo.changelog.tip()
1496 n = repo.changelog.tip()
1443 show_changeset(ui, repo, changenode=n)
1497 show_changeset(ui, repo, changenode=n)
1444
1498
1445 def undo(ui, repo):
1499 def undo(ui, repo):
1446 """undo the last commit or pull
1500 """undo the last commit or pull
1447
1501
1448 Roll back the last pull or commit transaction on the
1502 Roll back the last pull or commit transaction on the
1449 repository, restoring the project to its earlier state.
1503 repository, restoring the project to its earlier state.
1450
1504
1451 This command should be used with care. There is only one level of
1505 This command should be used with care. There is only one level of
1452 undo and there is no redo.
1506 undo and there is no redo.
1453
1507
1454 This command is not intended for use on public repositories. Once
1508 This command is not intended for use on public repositories. Once
1455 a change is visible for pull by other users, undoing it locally is
1509 a change is visible for pull by other users, undoing it locally is
1456 ineffective.
1510 ineffective.
1457 """
1511 """
1458 repo.undo()
1512 repo.undo()
1459
1513
1460 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1514 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1461 '''update or merge working directory
1515 '''update or merge working directory
1462
1516
1463 If there are no outstanding changes in the working directory and
1517 If there are no outstanding changes in the working directory and
1464 there is a linear relationship between the current version and the
1518 there is a linear relationship between the current version and the
1465 requested version, the result is the requested version.
1519 requested version, the result is the requested version.
1466
1520
1467 Otherwise the result is a merge between the contents of the
1521 Otherwise the result is a merge between the contents of the
1468 current working directory and the requested version. Files that
1522 current working directory and the requested version. Files that
1469 changed between either parent are marked as changed for the next
1523 changed between either parent are marked as changed for the next
1470 commit and a commit must be performed before any further updates
1524 commit and a commit must be performed before any further updates
1471 are allowed.
1525 are allowed.
1472 '''
1526 '''
1473 if branch:
1527 if branch:
1474 br = repo.branchlookup(branch=branch)
1528 br = repo.branchlookup(branch=branch)
1475 found = []
1529 found = []
1476 for x in br:
1530 for x in br:
1477 if branch in br[x]:
1531 if branch in br[x]:
1478 found.append(x)
1532 found.append(x)
1479 if len(found) > 1:
1533 if len(found) > 1:
1480 ui.warn("Found multiple heads for %s\n" % branch)
1534 ui.warn("Found multiple heads for %s\n" % branch)
1481 for x in found:
1535 for x in found:
1482 show_changeset(ui, repo, changenode=x, brinfo=br)
1536 show_changeset(ui, repo, changenode=x, brinfo=br)
1483 return 1
1537 return 1
1484 if len(found) == 1:
1538 if len(found) == 1:
1485 node = found[0]
1539 node = found[0]
1486 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1540 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1487 else:
1541 else:
1488 ui.warn("branch %s not found\n" % (branch))
1542 ui.warn("branch %s not found\n" % (branch))
1489 return 1
1543 return 1
1490 else:
1544 else:
1491 node = node and repo.lookup(node) or repo.changelog.tip()
1545 node = node and repo.lookup(node) or repo.changelog.tip()
1492 return repo.update(node, allow=merge, force=clean)
1546 return repo.update(node, allow=merge, force=clean)
1493
1547
1494 def verify(ui, repo):
1548 def verify(ui, repo):
1495 """verify the integrity of the repository"""
1549 """verify the integrity of the repository"""
1496 return repo.verify()
1550 return repo.verify()
1497
1551
1498 # Command options and aliases are listed here, alphabetically
1552 # Command options and aliases are listed here, alphabetically
1499
1553
1500 table = {
1554 table = {
1501 "^add":
1555 "^add":
1502 (add,
1556 (add,
1503 [('I', 'include', [], 'include path in search'),
1557 [('I', 'include', [], 'include path in search'),
1504 ('X', 'exclude', [], 'exclude path from search')],
1558 ('X', 'exclude', [], 'exclude path from search')],
1505 "hg add [OPTION]... [FILE]..."),
1559 "hg add [OPTION]... [FILE]..."),
1506 "addremove":
1560 "addremove":
1507 (addremove,
1561 (addremove,
1508 [('I', 'include', [], 'include path in search'),
1562 [('I', 'include', [], 'include path in search'),
1509 ('X', 'exclude', [], 'exclude path from search')],
1563 ('X', 'exclude', [], 'exclude path from search')],
1510 "hg addremove [OPTION]... [FILE]..."),
1564 "hg addremove [OPTION]... [FILE]..."),
1511 "^annotate":
1565 "^annotate":
1512 (annotate,
1566 (annotate,
1513 [('r', 'rev', '', 'revision'),
1567 [('r', 'rev', '', 'revision'),
1514 ('a', 'text', None, 'treat all files as text'),
1568 ('a', 'text', None, 'treat all files as text'),
1515 ('u', 'user', None, 'show user'),
1569 ('u', 'user', None, 'show user'),
1516 ('n', 'number', None, 'show revision number'),
1570 ('n', 'number', None, 'show revision number'),
1517 ('c', 'changeset', None, 'show changeset'),
1571 ('c', 'changeset', None, 'show changeset'),
1518 ('I', 'include', [], 'include path in search'),
1572 ('I', 'include', [], 'include path in search'),
1519 ('X', 'exclude', [], 'exclude path from search')],
1573 ('X', 'exclude', [], 'exclude path from search')],
1520 'hg annotate [OPTION]... FILE...'),
1574 'hg annotate [OPTION]... FILE...'),
1521 "cat":
1575 "cat":
1522 (cat,
1576 (cat,
1523 [('o', 'output', "", 'output to file')],
1577 [('o', 'output', "", 'output to file')],
1524 'hg cat [-o OUTFILE] FILE [REV]'),
1578 'hg cat [-o OUTFILE] FILE [REV]'),
1525 "^clone":
1579 "^clone":
1526 (clone,
1580 (clone,
1527 [('U', 'noupdate', None, 'skip update after cloning'),
1581 [('U', 'noupdate', None, 'skip update after cloning'),
1528 ('e', 'ssh', "", 'ssh command'),
1582 ('e', 'ssh', "", 'ssh command'),
1529 ('', 'remotecmd', "", 'remote hg command')],
1583 ('', 'remotecmd', "", 'remote hg command')],
1530 'hg clone [OPTION]... SOURCE [DEST]'),
1584 'hg clone [OPTION]... SOURCE [DEST]'),
1531 "^commit|ci":
1585 "^commit|ci":
1532 (commit,
1586 (commit,
1533 [('A', 'addremove', None, 'run add/remove during commit'),
1587 [('A', 'addremove', None, 'run add/remove during commit'),
1534 ('I', 'include', [], 'include path in search'),
1588 ('I', 'include', [], 'include path in search'),
1535 ('X', 'exclude', [], 'exclude path from search'),
1589 ('X', 'exclude', [], 'exclude path from search'),
1536 ('m', 'message', "", 'commit message'),
1590 ('m', 'message', "", 'commit message'),
1537 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1591 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1538 ('l', 'logfile', "", 'commit message file'),
1592 ('l', 'logfile', "", 'commit message file'),
1539 ('d', 'date', "", 'date code'),
1593 ('d', 'date', "", 'date code'),
1540 ('u', 'user', "", 'user')],
1594 ('u', 'user', "", 'user')],
1541 'hg commit [OPTION]... [FILE]...'),
1595 'hg commit [OPTION]... [FILE]...'),
1542 "copy": (copy, [], 'hg copy SOURCE DEST'),
1596 "copy": (copy, [], 'hg copy SOURCE DEST'),
1543 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1597 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1544 "debugconfig": (debugconfig, [], 'debugconfig'),
1598 "debugconfig": (debugconfig, [], 'debugconfig'),
1545 "debugstate": (debugstate, [], 'debugstate'),
1599 "debugstate": (debugstate, [], 'debugstate'),
1546 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1600 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1547 "debugindex": (debugindex, [], 'debugindex FILE'),
1601 "debugindex": (debugindex, [], 'debugindex FILE'),
1548 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1602 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1549 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1603 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1550 "debugwalk":
1604 "debugwalk":
1551 (debugwalk,
1605 (debugwalk,
1552 [('I', 'include', [], 'include path in search'),
1606 [('I', 'include', [], 'include path in search'),
1553 ('X', 'exclude', [], 'exclude path from search')],
1607 ('X', 'exclude', [], 'exclude path from search')],
1554 'debugwalk [OPTION]... [FILE]...'),
1608 'debugwalk [OPTION]... [FILE]...'),
1555 "^diff":
1609 "^diff":
1556 (diff,
1610 (diff,
1557 [('r', 'rev', [], 'revision'),
1611 [('r', 'rev', [], 'revision'),
1558 ('a', 'text', None, 'treat all files as text'),
1612 ('a', 'text', None, 'treat all files as text'),
1559 ('I', 'include', [], 'include path in search'),
1613 ('I', 'include', [], 'include path in search'),
1560 ('X', 'exclude', [], 'exclude path from search')],
1614 ('X', 'exclude', [], 'exclude path from search')],
1561 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1615 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1562 "^export":
1616 "^export":
1563 (export,
1617 (export,
1564 [('o', 'output', "", 'output to file'),
1618 [('o', 'output', "", 'output to file'),
1565 ('a', 'text', None, 'treat all files as text')],
1619 ('a', 'text', None, 'treat all files as text')],
1566 "hg export [-a] [-o OUTFILE] REV..."),
1620 "hg export [-a] [-o OUTFILE] REV..."),
1567 "forget":
1621 "forget":
1568 (forget,
1622 (forget,
1569 [('I', 'include', [], 'include path in search'),
1623 [('I', 'include', [], 'include path in search'),
1570 ('X', 'exclude', [], 'exclude path from search')],
1624 ('X', 'exclude', [], 'exclude path from search')],
1571 "hg forget [OPTION]... FILE..."),
1625 "hg forget [OPTION]... FILE..."),
1572 "grep":
1626 "grep":
1573 (grep,
1627 (grep,
1574 [('0', 'print0', None, 'end filenames with NUL'),
1628 [('0', 'print0', None, 'end fields with NUL'),
1575 ('I', 'include', [], 'include path in search'),
1629 ('I', 'include', [], 'include path in search'),
1576 ('X', 'exclude', [], 'include path in search'),
1630 ('X', 'exclude', [], 'include path in search'),
1577 ('e', 'every-match', None, 'print every match in file history'),
1631 ('e', 'every-match', None, 'print every rev with matches'),
1578 ('i', 'ignore-case', None, 'ignore case when matching'),
1632 ('i', 'ignore-case', None, 'ignore case when matching'),
1579 ('l', 'files-with-matches', None, 'print names of files with matches'),
1633 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1580 ('n', 'line-number', '', 'print line numbers'),
1634 ('n', 'line-number', None, 'print line numbers'),
1581 ('r', 'rev', [], 'search in revision rev')],
1635 ('r', 'rev', [], 'search in revision rev'),
1636 ('u', 'user', None, 'print user who made change')],
1582 "hg grep [OPTION]... PATTERN [FILE]..."),
1637 "hg grep [OPTION]... PATTERN [FILE]..."),
1583 "heads":
1638 "heads":
1584 (heads,
1639 (heads,
1585 [('b', 'branches', None, 'find branch info')],
1640 [('b', 'branches', None, 'find branch info')],
1586 'hg heads [-b]'),
1641 'hg heads [-b]'),
1587 "help": (help_, [], 'hg help [COMMAND]'),
1642 "help": (help_, [], 'hg help [COMMAND]'),
1588 "identify|id": (identify, [], 'hg identify'),
1643 "identify|id": (identify, [], 'hg identify'),
1589 "import|patch":
1644 "import|patch":
1590 (import_,
1645 (import_,
1591 [('p', 'strip', 1, 'path strip'),
1646 [('p', 'strip', 1, 'path strip'),
1592 ('f', 'force', None, 'skip check for outstanding changes'),
1647 ('f', 'force', None, 'skip check for outstanding changes'),
1593 ('b', 'base', "", 'base path')],
1648 ('b', 'base', "", 'base path')],
1594 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1649 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1595 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1650 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1596 "^init": (init, [], 'hg init [DEST]'),
1651 "^init": (init, [], 'hg init [DEST]'),
1597 "locate":
1652 "locate":
1598 (locate,
1653 (locate,
1599 [('r', 'rev', '', 'revision'),
1654 [('r', 'rev', '', 'revision'),
1600 ('0', 'print0', None, 'end filenames with NUL'),
1655 ('0', 'print0', None, 'end filenames with NUL'),
1601 ('f', 'fullpath', None, 'print complete paths'),
1656 ('f', 'fullpath', None, 'print complete paths'),
1602 ('I', 'include', [], 'include path in search'),
1657 ('I', 'include', [], 'include path in search'),
1603 ('X', 'exclude', [], 'exclude path from search')],
1658 ('X', 'exclude', [], 'exclude path from search')],
1604 'hg locate [OPTION]... [PATTERN]...'),
1659 'hg locate [OPTION]... [PATTERN]...'),
1605 "^log|history":
1660 "^log|history":
1606 (log,
1661 (log,
1607 [('I', 'include', [], 'include path in search'),
1662 [('I', 'include', [], 'include path in search'),
1608 ('X', 'exclude', [], 'exclude path from search'),
1663 ('X', 'exclude', [], 'exclude path from search'),
1609 ('r', 'rev', [], 'revision'),
1664 ('r', 'rev', [], 'revision'),
1610 ('p', 'patch', None, 'show patch')],
1665 ('p', 'patch', None, 'show patch')],
1611 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1666 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1612 "manifest": (manifest, [], 'hg manifest [REV]'),
1667 "manifest": (manifest, [], 'hg manifest [REV]'),
1613 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1668 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1614 "parents": (parents, [], 'hg parents [REV]'),
1669 "parents": (parents, [], 'hg parents [REV]'),
1615 "paths": (paths, [], 'hg paths [NAME]'),
1670 "paths": (paths, [], 'hg paths [NAME]'),
1616 "^pull":
1671 "^pull":
1617 (pull,
1672 (pull,
1618 [('u', 'update', None, 'update working directory'),
1673 [('u', 'update', None, 'update working directory'),
1619 ('e', 'ssh', "", 'ssh command'),
1674 ('e', 'ssh', "", 'ssh command'),
1620 ('', 'remotecmd', "", 'remote hg command')],
1675 ('', 'remotecmd', "", 'remote hg command')],
1621 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1676 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1622 "^push":
1677 "^push":
1623 (push,
1678 (push,
1624 [('f', 'force', None, 'force push'),
1679 [('f', 'force', None, 'force push'),
1625 ('e', 'ssh', "", 'ssh command'),
1680 ('e', 'ssh', "", 'ssh command'),
1626 ('', 'remotecmd', "", 'remote hg command')],
1681 ('', 'remotecmd', "", 'remote hg command')],
1627 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1682 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1628 "rawcommit":
1683 "rawcommit":
1629 (rawcommit,
1684 (rawcommit,
1630 [('p', 'parent', [], 'parent'),
1685 [('p', 'parent', [], 'parent'),
1631 ('d', 'date', "", 'date code'),
1686 ('d', 'date', "", 'date code'),
1632 ('u', 'user', "", 'user'),
1687 ('u', 'user', "", 'user'),
1633 ('F', 'files', "", 'file list'),
1688 ('F', 'files', "", 'file list'),
1634 ('m', 'message', "", 'commit message'),
1689 ('m', 'message', "", 'commit message'),
1635 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1690 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1636 ('l', 'logfile', "", 'commit message file')],
1691 ('l', 'logfile', "", 'commit message file')],
1637 'hg rawcommit [OPTION]... [FILE]...'),
1692 'hg rawcommit [OPTION]... [FILE]...'),
1638 "recover": (recover, [], "hg recover"),
1693 "recover": (recover, [], "hg recover"),
1639 "^remove|rm": (remove, [], "hg remove FILE..."),
1694 "^remove|rm": (remove, [], "hg remove FILE..."),
1640 "^revert":
1695 "^revert":
1641 (revert,
1696 (revert,
1642 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1697 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1643 ("r", "rev", "", "revision")],
1698 ("r", "rev", "", "revision")],
1644 "hg revert [-n] [-r REV] [NAME]..."),
1699 "hg revert [-n] [-r REV] [NAME]..."),
1645 "root": (root, [], "hg root"),
1700 "root": (root, [], "hg root"),
1646 "^serve":
1701 "^serve":
1647 (serve,
1702 (serve,
1648 [('A', 'accesslog', '', 'access log file'),
1703 [('A', 'accesslog', '', 'access log file'),
1649 ('E', 'errorlog', '', 'error log file'),
1704 ('E', 'errorlog', '', 'error log file'),
1650 ('p', 'port', 0, 'listen port'),
1705 ('p', 'port', 0, 'listen port'),
1651 ('a', 'address', '', 'interface address'),
1706 ('a', 'address', '', 'interface address'),
1652 ('n', 'name', "", 'repository name'),
1707 ('n', 'name', "", 'repository name'),
1653 ('', 'stdio', None, 'for remote clients'),
1708 ('', 'stdio', None, 'for remote clients'),
1654 ('t', 'templates', "", 'template directory'),
1709 ('t', 'templates', "", 'template directory'),
1655 ('', 'style', "", 'template style'),
1710 ('', 'style', "", 'template style'),
1656 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1711 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1657 "hg serve [OPTION]..."),
1712 "hg serve [OPTION]..."),
1658 "^status":
1713 "^status":
1659 (status,
1714 (status,
1660 [('m', 'modified', None, 'show only modified files'),
1715 [('m', 'modified', None, 'show only modified files'),
1661 ('a', 'added', None, 'show only added files'),
1716 ('a', 'added', None, 'show only added files'),
1662 ('r', 'removed', None, 'show only removed files'),
1717 ('r', 'removed', None, 'show only removed files'),
1663 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1718 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1664 ('n', 'no-status', None, 'hide status prefix'),
1719 ('n', 'no-status', None, 'hide status prefix'),
1665 ('0', 'print0', None, 'end filenames with NUL'),
1720 ('0', 'print0', None, 'end filenames with NUL'),
1666 ('I', 'include', [], 'include path in search'),
1721 ('I', 'include', [], 'include path in search'),
1667 ('X', 'exclude', [], 'exclude path from search')],
1722 ('X', 'exclude', [], 'exclude path from search')],
1668 "hg status [OPTION]... [FILE]..."),
1723 "hg status [OPTION]... [FILE]..."),
1669 "tag":
1724 "tag":
1670 (tag,
1725 (tag,
1671 [('l', 'local', None, 'make the tag local'),
1726 [('l', 'local', None, 'make the tag local'),
1672 ('m', 'message', "", 'commit message'),
1727 ('m', 'message', "", 'commit message'),
1673 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1728 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1674 ('d', 'date', "", 'date code'),
1729 ('d', 'date', "", 'date code'),
1675 ('u', 'user', "", 'user')],
1730 ('u', 'user', "", 'user')],
1676 'hg tag [OPTION]... NAME [REV]'),
1731 'hg tag [OPTION]... NAME [REV]'),
1677 "tags": (tags, [], 'hg tags'),
1732 "tags": (tags, [], 'hg tags'),
1678 "tip": (tip, [], 'hg tip'),
1733 "tip": (tip, [], 'hg tip'),
1679 "undo": (undo, [], 'hg undo'),
1734 "undo": (undo, [], 'hg undo'),
1680 "^update|up|checkout|co":
1735 "^update|up|checkout|co":
1681 (update,
1736 (update,
1682 [('b', 'branch', "", 'checkout the head of a specific branch'),
1737 [('b', 'branch', "", 'checkout the head of a specific branch'),
1683 ('m', 'merge', None, 'allow merging of conflicts'),
1738 ('m', 'merge', None, 'allow merging of conflicts'),
1684 ('C', 'clean', None, 'overwrite locally modified files')],
1739 ('C', 'clean', None, 'overwrite locally modified files')],
1685 'hg update [-b TAG] [-m] [-C] [REV]'),
1740 'hg update [-b TAG] [-m] [-C] [REV]'),
1686 "verify": (verify, [], 'hg verify'),
1741 "verify": (verify, [], 'hg verify'),
1687 "version": (show_version, [], 'hg version'),
1742 "version": (show_version, [], 'hg version'),
1688 }
1743 }
1689
1744
1690 globalopts = [
1745 globalopts = [
1691 ('R', 'repository', "", 'repository root directory'),
1746 ('R', 'repository', "", 'repository root directory'),
1692 ('', 'cwd', '', 'change working directory'),
1747 ('', 'cwd', '', 'change working directory'),
1693 ('y', 'noninteractive', None, 'run non-interactively'),
1748 ('y', 'noninteractive', None, 'run non-interactively'),
1694 ('q', 'quiet', None, 'quiet mode'),
1749 ('q', 'quiet', None, 'quiet mode'),
1695 ('v', 'verbose', None, 'verbose mode'),
1750 ('v', 'verbose', None, 'verbose mode'),
1696 ('', 'debug', None, 'debug mode'),
1751 ('', 'debug', None, 'debug mode'),
1697 ('', 'traceback', None, 'print traceback on exception'),
1752 ('', 'traceback', None, 'print traceback on exception'),
1698 ('', 'time', None, 'time how long the command takes'),
1753 ('', 'time', None, 'time how long the command takes'),
1699 ('', 'profile', None, 'profile'),
1754 ('', 'profile', None, 'profile'),
1700 ('', 'version', None, 'output version information and exit'),
1755 ('', 'version', None, 'output version information and exit'),
1701 ('h', 'help', None, 'display help and exit'),
1756 ('h', 'help', None, 'display help and exit'),
1702 ]
1757 ]
1703
1758
1704 norepo = ("clone init version help debugconfig debugdata"
1759 norepo = ("clone init version help debugconfig debugdata"
1705 " debugindex debugindexdot paths")
1760 " debugindex debugindexdot paths")
1706
1761
1707 def find(cmd):
1762 def find(cmd):
1708 for e in table.keys():
1763 for e in table.keys():
1709 if re.match("(%s)$" % e, cmd):
1764 if re.match("(%s)$" % e, cmd):
1710 return e, table[e]
1765 return e, table[e]
1711
1766
1712 raise UnknownCommand(cmd)
1767 raise UnknownCommand(cmd)
1713
1768
1714 class SignalInterrupt(Exception):
1769 class SignalInterrupt(Exception):
1715 """Exception raised on SIGTERM and SIGHUP."""
1770 """Exception raised on SIGTERM and SIGHUP."""
1716
1771
1717 def catchterm(*args):
1772 def catchterm(*args):
1718 raise SignalInterrupt
1773 raise SignalInterrupt
1719
1774
1720 def run():
1775 def run():
1721 sys.exit(dispatch(sys.argv[1:]))
1776 sys.exit(dispatch(sys.argv[1:]))
1722
1777
1723 class ParseError(Exception):
1778 class ParseError(Exception):
1724 """Exception raised on errors in parsing the command line."""
1779 """Exception raised on errors in parsing the command line."""
1725
1780
1726 def parse(args):
1781 def parse(args):
1727 options = {}
1782 options = {}
1728 cmdoptions = {}
1783 cmdoptions = {}
1729
1784
1730 try:
1785 try:
1731 args = fancyopts.fancyopts(args, globalopts, options)
1786 args = fancyopts.fancyopts(args, globalopts, options)
1732 except fancyopts.getopt.GetoptError, inst:
1787 except fancyopts.getopt.GetoptError, inst:
1733 raise ParseError(None, inst)
1788 raise ParseError(None, inst)
1734
1789
1735 if args:
1790 if args:
1736 cmd, args = args[0], args[1:]
1791 cmd, args = args[0], args[1:]
1737 i = find(cmd)[1]
1792 i = find(cmd)[1]
1738 c = list(i[1])
1793 c = list(i[1])
1739 else:
1794 else:
1740 cmd = None
1795 cmd = None
1741 c = []
1796 c = []
1742
1797
1743 # combine global options into local
1798 # combine global options into local
1744 for o in globalopts:
1799 for o in globalopts:
1745 c.append((o[0], o[1], options[o[1]], o[3]))
1800 c.append((o[0], o[1], options[o[1]], o[3]))
1746
1801
1747 try:
1802 try:
1748 args = fancyopts.fancyopts(args, c, cmdoptions)
1803 args = fancyopts.fancyopts(args, c, cmdoptions)
1749 except fancyopts.getopt.GetoptError, inst:
1804 except fancyopts.getopt.GetoptError, inst:
1750 raise ParseError(cmd, inst)
1805 raise ParseError(cmd, inst)
1751
1806
1752 # separate global options back out
1807 # separate global options back out
1753 for o in globalopts:
1808 for o in globalopts:
1754 n = o[1]
1809 n = o[1]
1755 options[n] = cmdoptions[n]
1810 options[n] = cmdoptions[n]
1756 del cmdoptions[n]
1811 del cmdoptions[n]
1757
1812
1758 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1813 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1759
1814
1760 def dispatch(args):
1815 def dispatch(args):
1761 signal.signal(signal.SIGTERM, catchterm)
1816 signal.signal(signal.SIGTERM, catchterm)
1762 try:
1817 try:
1763 signal.signal(signal.SIGHUP, catchterm)
1818 signal.signal(signal.SIGHUP, catchterm)
1764 except AttributeError:
1819 except AttributeError:
1765 pass
1820 pass
1766
1821
1767 u = ui.ui()
1822 u = ui.ui()
1768 external = []
1823 external = []
1769 for x in u.extensions():
1824 for x in u.extensions():
1770 if x[1]:
1825 if x[1]:
1771 mod = imp.load_source(x[0], x[1])
1826 mod = imp.load_source(x[0], x[1])
1772 else:
1827 else:
1773 def importh(name):
1828 def importh(name):
1774 mod = __import__(name)
1829 mod = __import__(name)
1775 components = name.split('.')
1830 components = name.split('.')
1776 for comp in components[1:]:
1831 for comp in components[1:]:
1777 mod = getattr(mod, comp)
1832 mod = getattr(mod, comp)
1778 return mod
1833 return mod
1779 mod = importh(x[0])
1834 mod = importh(x[0])
1780 external.append(mod)
1835 external.append(mod)
1781 for x in external:
1836 for x in external:
1782 for t in x.cmdtable:
1837 for t in x.cmdtable:
1783 if t in table:
1838 if t in table:
1784 u.warn("module %s override %s\n" % (x.__name__, t))
1839 u.warn("module %s override %s\n" % (x.__name__, t))
1785 table.update(x.cmdtable)
1840 table.update(x.cmdtable)
1786
1841
1787 try:
1842 try:
1788 cmd, func, args, options, cmdoptions = parse(args)
1843 cmd, func, args, options, cmdoptions = parse(args)
1789 except ParseError, inst:
1844 except ParseError, inst:
1790 if inst.args[0]:
1845 if inst.args[0]:
1791 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1846 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1792 help_(u, inst.args[0])
1847 help_(u, inst.args[0])
1793 else:
1848 else:
1794 u.warn("hg: %s\n" % inst.args[1])
1849 u.warn("hg: %s\n" % inst.args[1])
1795 help_(u, 'shortlist')
1850 help_(u, 'shortlist')
1796 sys.exit(-1)
1851 sys.exit(-1)
1797 except UnknownCommand, inst:
1852 except UnknownCommand, inst:
1798 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1853 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1799 help_(u, 'shortlist')
1854 help_(u, 'shortlist')
1800 sys.exit(1)
1855 sys.exit(1)
1801
1856
1802 if options["time"]:
1857 if options["time"]:
1803 def get_times():
1858 def get_times():
1804 t = os.times()
1859 t = os.times()
1805 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1860 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1806 t = (t[0], t[1], t[2], t[3], time.clock())
1861 t = (t[0], t[1], t[2], t[3], time.clock())
1807 return t
1862 return t
1808 s = get_times()
1863 s = get_times()
1809 def print_time():
1864 def print_time():
1810 t = get_times()
1865 t = get_times()
1811 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1866 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1812 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1867 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1813 atexit.register(print_time)
1868 atexit.register(print_time)
1814
1869
1815 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1870 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1816 not options["noninteractive"])
1871 not options["noninteractive"])
1817
1872
1818 try:
1873 try:
1819 try:
1874 try:
1820 if options['help']:
1875 if options['help']:
1821 help_(u, cmd, options['version'])
1876 help_(u, cmd, options['version'])
1822 sys.exit(0)
1877 sys.exit(0)
1823 elif options['version']:
1878 elif options['version']:
1824 show_version(u)
1879 show_version(u)
1825 sys.exit(0)
1880 sys.exit(0)
1826 elif not cmd:
1881 elif not cmd:
1827 help_(u, 'shortlist')
1882 help_(u, 'shortlist')
1828 sys.exit(0)
1883 sys.exit(0)
1829
1884
1830 if options['cwd']:
1885 if options['cwd']:
1831 try:
1886 try:
1832 os.chdir(options['cwd'])
1887 os.chdir(options['cwd'])
1833 except OSError, inst:
1888 except OSError, inst:
1834 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1889 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1835 sys.exit(1)
1890 sys.exit(1)
1836
1891
1837 if cmd not in norepo.split():
1892 if cmd not in norepo.split():
1838 path = options["repository"] or ""
1893 path = options["repository"] or ""
1839 repo = hg.repository(ui=u, path=path)
1894 repo = hg.repository(ui=u, path=path)
1840 for x in external:
1895 for x in external:
1841 x.reposetup(u, repo)
1896 x.reposetup(u, repo)
1842 d = lambda: func(u, repo, *args, **cmdoptions)
1897 d = lambda: func(u, repo, *args, **cmdoptions)
1843 else:
1898 else:
1844 d = lambda: func(u, *args, **cmdoptions)
1899 d = lambda: func(u, *args, **cmdoptions)
1845
1900
1846 if options['profile']:
1901 if options['profile']:
1847 import hotshot, hotshot.stats
1902 import hotshot, hotshot.stats
1848 prof = hotshot.Profile("hg.prof")
1903 prof = hotshot.Profile("hg.prof")
1849 r = prof.runcall(d)
1904 r = prof.runcall(d)
1850 prof.close()
1905 prof.close()
1851 stats = hotshot.stats.load("hg.prof")
1906 stats = hotshot.stats.load("hg.prof")
1852 stats.strip_dirs()
1907 stats.strip_dirs()
1853 stats.sort_stats('time', 'calls')
1908 stats.sort_stats('time', 'calls')
1854 stats.print_stats(40)
1909 stats.print_stats(40)
1855 return r
1910 return r
1856 else:
1911 else:
1857 return d()
1912 return d()
1858 except:
1913 except:
1859 if options['traceback']:
1914 if options['traceback']:
1860 traceback.print_exc()
1915 traceback.print_exc()
1861 raise
1916 raise
1862 except hg.RepoError, inst:
1917 except hg.RepoError, inst:
1863 u.warn("abort: ", inst, "!\n")
1918 u.warn("abort: ", inst, "!\n")
1864 except SignalInterrupt:
1919 except SignalInterrupt:
1865 u.warn("killed!\n")
1920 u.warn("killed!\n")
1866 except KeyboardInterrupt:
1921 except KeyboardInterrupt:
1867 try:
1922 try:
1868 u.warn("interrupted!\n")
1923 u.warn("interrupted!\n")
1869 except IOError, inst:
1924 except IOError, inst:
1870 if inst.errno == errno.EPIPE:
1925 if inst.errno == errno.EPIPE:
1871 if u.debugflag:
1926 if u.debugflag:
1872 u.warn("\nbroken pipe\n")
1927 u.warn("\nbroken pipe\n")
1873 else:
1928 else:
1874 raise
1929 raise
1875 except IOError, inst:
1930 except IOError, inst:
1876 if hasattr(inst, "code"):
1931 if hasattr(inst, "code"):
1877 u.warn("abort: %s\n" % inst)
1932 u.warn("abort: %s\n" % inst)
1878 elif hasattr(inst, "reason"):
1933 elif hasattr(inst, "reason"):
1879 u.warn("abort: error: %s\n" % inst.reason[1])
1934 u.warn("abort: error: %s\n" % inst.reason[1])
1880 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1935 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1881 if u.debugflag:
1936 if u.debugflag:
1882 u.warn("broken pipe\n")
1937 u.warn("broken pipe\n")
1883 else:
1938 else:
1884 raise
1939 raise
1885 except OSError, inst:
1940 except OSError, inst:
1886 if hasattr(inst, "filename"):
1941 if hasattr(inst, "filename"):
1887 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1942 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1888 else:
1943 else:
1889 u.warn("abort: %s\n" % inst.strerror)
1944 u.warn("abort: %s\n" % inst.strerror)
1890 except util.Abort, inst:
1945 except util.Abort, inst:
1891 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1946 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1892 sys.exit(1)
1947 sys.exit(1)
1893 except TypeError, inst:
1948 except TypeError, inst:
1894 # was this an argument error?
1949 # was this an argument error?
1895 tb = traceback.extract_tb(sys.exc_info()[2])
1950 tb = traceback.extract_tb(sys.exc_info()[2])
1896 if len(tb) > 2: # no
1951 if len(tb) > 2: # no
1897 raise
1952 raise
1898 u.debug(inst, "\n")
1953 u.debug(inst, "\n")
1899 u.warn("%s: invalid arguments\n" % cmd)
1954 u.warn("%s: invalid arguments\n" % cmd)
1900 help_(u, cmd)
1955 help_(u, cmd)
1901 except UnknownCommand, inst:
1956 except UnknownCommand, inst:
1902 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1957 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1903 help_(u, 'shortlist')
1958 help_(u, 'shortlist')
1904
1959
1905 sys.exit(-1)
1960 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now