##// END OF EJS Templates
Modify init command to take an optional directory to set up....
Bryan O'Sullivan -
r907:652507dc default
parent child Browse files
Show More
@@ -1,597 +1,600 b''
1 1 HG(1)
2 2 =====
3 3 Matt Mackall <mpm@selenic.com>
4 4
5 5 NAME
6 6 ----
7 7 hg - Mercurial source code management system
8 8
9 9 SYNOPSIS
10 10 --------
11 11 'hg' [-v -d -q -y] <command> [command options] [files]
12 12
13 13 DESCRIPTION
14 14 -----------
15 15 The hg(1) command provides a command line interface to the Mercurial system.
16 16
17 17 OPTIONS
18 18 -------
19 19
20 20 --debug, -d::
21 21 enable debugging output
22 22
23 23 --quiet, -q::
24 24 suppress output
25 25
26 26 --verbose, -v::
27 27 enable additional output
28 28
29 29 --noninteractive, -y::
30 30 do not prompt, assume 'yes' for any required answers
31 31
32 32 COMMAND ELEMENTS
33 33 ----------------
34 34
35 35 files ...::
36 36 indicates one or more filename or relative path filenames; see
37 37 "FILE NAME PATTERNS" for information on pattern matching
38 38
39 39 path::
40 40 indicates a path on the local machine
41 41
42 42 revision::
43 43 indicates a changeset which can be specified as a changeset revision
44 44 number, a tag, or a unique substring of the changeset hash value
45 45
46 46 repository path::
47 47 either the pathname of a local repository or the URI of a remote
48 48 repository. There are two available URI protocols, http:// which is
49 49 fast and the old-http:// protocol which is much slower but does not
50 50 require a special server on the web host.
51 51
52 52 COMMANDS
53 53 --------
54 54
55 55 add [options] [files ...]::
56 56 Schedule files to be version controlled and added to the repository.
57 57
58 58 The files will be added to the repository at the next commit.
59 59
60 60 If no names are given, add all files in the current directory and
61 61 its subdirectories.
62 62
63 63 addremove [options] [files ...]::
64 64 Add all new files and remove all missing files from the repository.
65 65
66 66 New files are ignored if they match any of the patterns in .hgignore. As
67 67 with add, these changes take effect at the next commit.
68 68
69 69 annotate [-r <rev> -u -n -c] [files ...]::
70 70 List changes in files, showing the revision id responsible for each line
71 71
72 72 This command is useful to discover who did a change or when a change took
73 73 place.
74 74
75 75 options:
76 76 -I, --include <pat> include names matching the given patterns
77 77 -X, --exclude <pat> exclude names matching the given patterns
78 78 -r, --revision <rev> annotate the specified revision
79 79 -u, --user list the author
80 80 -c, --changeset list the changeset
81 81 -n, --number list the revision number (default)
82 82
83 83 cat <file> [revision]::
84 84 Output to stdout the given revision for the specified file.
85 85
86 86 If no revision is given then the tip is used.
87 87
88 88 clone [-U] <source> [dest]::
89 89 Create a copy of an existing repository in a new directory.
90 90
91 91 If no destination directory name is specified, it defaults to the
92 92 basename of the source.
93 93
94 94 The source is added to the new repository's .hg/hgrc file to be used in
95 95 future pulls.
96 96
97 97 For efficiency, hardlinks are used for cloning whenever the
98 98 source and destination are on the same filesystem.
99 99
100 100 options:
101 101 -U, --noupdate do not update the new working directory
102 102
103 103 commit [options] [files...]::
104 104 Commit changes to the given files into the repository.
105 105
106 106 If a list of files is omitted, all changes reported by "hg status"
107 107 from the root of the repository will be commited.
108 108
109 109 The HGEDITOR or EDITOR environment variables are used to start an
110 110 editor to add a commit comment.
111 111
112 112 Options:
113 113
114 114 -A, --addremove run addremove during commit
115 115 -I, --include <pat> include names matching the given patterns
116 116 -X, --exclude <pat> exclude names matching the given patterns
117 117 -m, --message <text> use <text> as commit message
118 118 -l, --logfile <file> show the commit message for the given file
119 119 -d, --date <datecode> record datecode as commit date
120 120 -u, --user <user> record user as commiter
121 121
122 122 aliases: ci
123 123
124 124 copy <source> <dest>::
125 125 Mark <dest> file as a copy or rename of a <source> one
126 126
127 127 This command takes effect for the next commit.
128 128
129 129 diff [-r revision] [-r revision] [files ...]::
130 130 Show differences between revisions for the specified files.
131 131
132 132 Differences between files are shown using the unified diff format.
133 133
134 134 When two revision arguments are given, then changes are shown
135 135 between those revisions. If only one revision is specified then
136 136 that revision is compared to the working directory, and, when no
137 137 revisions are specified, the working directory files are compared
138 138 to its parent.
139 139
140 140 options:
141 141 -I, --include <pat> include names matching the given patterns
142 142 -X, --exclude <pat> exclude names matching the given patterns
143 143
144 144 export [-o filespec] [revision] ...::
145 145 Print the changeset header and diffs for one or more revisions.
146 146
147 147 The information shown in the changeset header is: author,
148 148 changeset hash, parent and commit comment.
149 149
150 150 Output may be to a file, in which case the name of the file is
151 151 given using a format string. The formatting rules are as follows:
152 152
153 153 %% literal "%" character
154 154 %H changeset hash (40 bytes of hexadecimal)
155 155 %N number of patches being generated
156 156 %R changeset revision number
157 157 %b basename of the exporting repository
158 158 %h short-form changeset hash (12 bytes of hexadecimal)
159 159 %n zero-padded sequence number, starting at 1
160 160 %r zero-padded changeset revision number
161 161
162 162 Options:
163 163
164 164 -o, --output <filespec> print output to file with formatted named
165 165
166 166 forget [options] [files]::
167 167 Undo an 'hg add' scheduled for the next commit.
168 168
169 169 options:
170 170 -I, --include <pat> include names matching the given patterns
171 171 -X, --exclude <pat> exclude names matching the given patterns
172 172
173 173 heads::
174 174 Show all repository head changesets.
175 175
176 176 Repository "heads" are changesets that don't have children
177 177 changesets. They are where development generally takes place and
178 178 are the usual targets for update and merge operations.
179 179
180 180 identify::
181 181 Print a short summary of the current state of the repo.
182 182
183 183 This summary identifies the repository state using one or two parent
184 184 hash identifiers, followed by a "+" if there are uncommitted changes
185 185 in the working directory, followed by a list of tags for this revision.
186 186
187 187 aliases: id
188 188
189 189 import [-p <n> -b <base> -q] <patches>::
190 190 Import a list of patches and commit them individually.
191 191
192 192 options:
193 193 -p, --strip <n> directory strip option for patch. This has the same
194 194 meaning as the correnponding patch option
195 195 -b <path> base directory to read patches from
196 196
197 197 aliases: patch
198 198
199 init::
200 Initialize a new repository in the current directory.
199 init [dest]::
200 Initialize a new repository in the given directory. If the given
201 directory does not exist, it is created.
202
203 If no directory is given, the current directory is used.
201 204
202 205 locate [options] [files]::
203 206 Print all files under Mercurial control whose names match the
204 207 given patterns.
205 208
206 209 This command searches the current directory and its
207 210 subdirectories. To search an entire repository, move to the root
208 211 of the repository.
209 212
210 213 If no patterns are given to match, this command prints all file
211 214 names.
212 215
213 216 If you want to feed the output of this command into the "xargs"
214 217 command, use the "-0" option to both this command and "xargs".
215 218 This will avoid the problem of "xargs" treating single filenames
216 219 that contain white space as multiple file names.
217 220
218 221 options:
219 222
220 223 -0, --print0 end filenames with NUL, for use with xargs
221 224 -f, --fullpath print complete paths from the filesystem root
222 225 -I, --include <pat> include names matching the given patterns
223 226 -r, --rev <rev> search the repository as it stood at rev
224 227 -X, --exclude <pat> exclude names matching the given patterns
225 228
226 229 log [-r revision ...] [-p] [file]::
227 230 Print the revision history of the specified file or the entire project.
228 231
229 232 By default this command outputs: changeset id and hash, tags,
230 233 parents, user, date and time, and a summary for each commit. The
231 234 -v switch adds some more detail, such as changed files, manifest
232 235 hashes or message signatures.
233 236
234 237 options:
235 238 -r, --rev <A>, ... When a revision argument is given, only this file or
236 239 changelog revision is displayed. With two revision
237 240 arguments all revisions in this range are listed.
238 241 Additional revision arguments may be given repeating
239 242 the above cycle.
240 243 -p, --patch show patch
241 244
242 245 aliases: history
243 246
244 247 manifest [revision]::
245 248 Print a list of version controlled files for the given revision.
246 249
247 250 The manifest is the list of files being version controlled. If no revision
248 251 is given then the tip is used.
249 252
250 253 parents::
251 254 Print the working directory's parent revisions.
252 255
253 256 pull <repository path>::
254 257 Pull changes from a remote repository to a local one.
255 258
256 259 This finds all changes from the repository at the specified path
257 260 or URL and adds them to the local repository. By default, this
258 261 does not update the copy of the project in the working directory.
259 262
260 263 options:
261 264 -u, --update update the working directory to tip after pull
262 265
263 266 push <destination>::
264 267 Push changes from the local repository to the given destination.
265 268
266 269 This is the symmetrical operation for pull. It helps to move
267 270 changes from the current repository to a different one. If the
268 271 destination is local this is identical to a pull in that directory
269 272 from the current one.
270 273
271 274 The other currently available push method is SSH. This requires an
272 275 accessible shell account on the destination machine and a copy of
273 276 hg in the remote path. Destinations are specified in the following
274 277 form:
275 278
276 279 ssh://[user@]host[:port]/path
277 280
278 281 rawcommit [-p -d -u -F -m -l]::
279 282 Lowlevel commit, for use in helper scripts.
280 283
281 284 This command is not intended to be used by normal users, as it is
282 285 primarily useful for importing from other SCMs.
283 286
284 287 recover::
285 288 Recover from an interrupted commit or pull.
286 289
287 290 This command tries to fix the repository status after an interrupted
288 291 operation. It should only be necessary when Mercurial suggests it.
289 292
290 293 remove [files ...]::
291 294 Schedule the indicated files for removal from the repository.
292 295
293 296 This command shedules the files to be removed at the next commit.
294 297 This only removes files from the current branch, not from the
295 298 entire project history.
296 299
297 300 aliases: rm
298 301
299 302 revert [names ...]::
300 303 Revert any uncommitted modifications made to the named files or
301 304 directories. This restores the contents of the affected files to
302 305 an unmodified state.
303 306
304 307 If a file has been deleted, it is recreated. If the executable
305 308 mode of a file was changed, it is reset.
306 309
307 310 If a directory is given, all files in that directory and its
308 311 subdirectories are reverted.
309 312
310 313 If no arguments are given, all files in the current directory and
311 314 its subdirectories are reverted.
312 315
313 316 options:
314 317 -r, --rev <rev> revision to revert to
315 318 -n, --nonrecursive do not recurse into subdirectories
316 319
317 320 root::
318 321 Print the root directory of the current repository.
319 322
320 323 serve [options]::
321 324 Start a local HTTP repository browser and pull server.
322 325
323 326 By default, the server logs accesses to stdout and errors to
324 327 stderr. Use the "-A" and "-E" options to log to files.
325 328
326 329 options:
327 330 -A, --accesslog <file> name of access log file to write to
328 331 -E, --errorlog <file> name of error log file to write to
329 332 -a, --address <addr> address to use
330 333 -p, --port <n> port to use (default: 8000)
331 334 -n, --name <name> name to show in web pages (default: working dir)
332 335 -t, --templatedir <path> web templates to use
333 336 -6, --ipv6 use IPv6 in addition to IPv4
334 337
335 338 status [options] [files]::
336 339 Show changed files in the working directory. If no names are
337 340 given, all files are shown. Otherwise, only files matching the
338 341 given names are shown.
339 342
340 343 The codes used to show the status of files are:
341 344
342 345 M = changed
343 346 A = added
344 347 R = removed
345 348 ? = not tracked
346 349
347 350 options:
348 351
349 352 -m, --modified show only modified files
350 353 -a, --added show only added files
351 354 -r, --removed show only removed files
352 355 -u, --unknown show only unknown (not tracked) files
353 356 -I, --include <pat> include names matching the given patterns
354 357 -X, --exclude <pat> exclude names matching the given patterns
355 358
356 359 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
357 360 Name a particular revision using <name>.
358 361
359 362 Tags are used to name particular revisions of the repository and are
360 363 very useful to compare different revision, to go back to significant
361 364 earlier versions or to mark branch points as releases, etc.
362 365
363 366 If no revision is given, the tip is used.
364 367
365 368 To facilitate version control, distribution, and merging of tags,
366 369 they are stored as a file named ".hgtags" which is managed
367 370 similarly to other project files and can be hand-edited if
368 371 necessary.
369 372
370 373 options:
371 374 -l, --local make the tag local
372 375 -m, --message <text> message for tag commit log entry
373 376 -d, --date <datecode> datecode for commit
374 377 -u, --user <user> user for commit
375 378
376 379 Note: Local tags are not version-controlled or distributed and are
377 380 stored in the .hg/localtags file. If there exists a local tag and
378 381 a public tag with the same name, local tag is used.
379 382
380 383 tags::
381 384 List the repository tags.
382 385
383 386 This lists both regular and local tags.
384 387
385 388 tip::
386 389 Show the tip revision.
387 390
388 391 undo::
389 392 Undo the last commit or pull transaction.
390 393
391 394 Roll back the last pull or commit transaction on the
392 395 repository, restoring the project to its earlier state.
393 396
394 397 This command should be used with care. There is only one level of
395 398 undo and there is no redo.
396 399
397 400 This command is not intended for use on public repositories. Once
398 401 a change is visible for pull by other users, undoing it locally is
399 402 ineffective.
400 403
401 404 update [-m -C] [revision]::
402 405 Update the working directory to the specified revision.
403 406
404 407 By default, update will refuse to run if doing so would require
405 408 merging or discarding local changes.
406 409
407 410 With the -m option, a merge will be performed.
408 411
409 412 With the -C option, local changes will be lost.
410 413
411 414 options:
412 415 -m, --merge allow merging of branches
413 416 -C, --clean overwrite locally modified files
414 417
415 418 aliases: up checkout co
416 419
417 420 verify::
418 421 Verify the integrity of the current repository.
419 422
420 423 This will perform an extensive check of the repository's
421 424 integrity, validating the hashes and checksums of each entry in
422 425 the changelog, manifest, and tracked files, as well as the
423 426 integrity of their crosslinks and indices.
424 427
425 428 FILE NAME PATTERNS
426 429 ------------------
427 430
428 431 Mercurial accepts several notations for identifying one or more
429 432 file at a time.
430 433
431 434 By default, Mercurial treats file names as shell-style extended
432 435 glob patterns.
433 436
434 437 Alternate pattern notations must be specified explicitly.
435 438
436 439 To use a plain path name without any pattern matching, start a
437 440 name with "path:". These path names must match completely, from
438 441 the root of the current repository.
439 442
440 443 To use an extended glob, start a name with "glob:". Globs are
441 444 rooted at the current directory; a glob such as "*.c" will match
442 445 files ending in ".c" in the current directory only.
443 446
444 447 The supported glob syntax extensions are "**" to match any string
445 448 across path separators, and "{a,b}" to mean "a or b".
446 449
447 450 To use a Perl/Python regular expression, start a name with "re:".
448 451 Regexp pattern matching is anchored at the root of the repository.
449 452
450 453 Plain examples:
451 454
452 455 path:foo/bar a name bar in a directory named foo in the root of
453 456 the repository
454 457 path:path:name a file or directory named "path:name"
455 458
456 459 Glob examples:
457 460
458 461 glob:*.c any name ending in ".c" in the current directory
459 462 *.c any name ending in ".c" in the current directory
460 463 **.c any name ending in ".c" in the current directory, or
461 464 any subdirectory
462 465 foo/*.c any name ending in ".c" in the directory foo
463 466 foo/**.c any name ending in ".c" in the directory foo, or any
464 467 subdirectory
465 468
466 469 Regexp examples:
467 470
468 471 re:.*\.c$ any name ending in ".c", anywhere in the repsitory
469 472
470 473
471 474 SPECIFYING SINGLE REVISIONS
472 475 ---------------------------
473 476
474 477 Mercurial accepts several notations for identifying individual
475 478 revisions.
476 479
477 480 A plain integer is treated as a revision number. Negative
478 481 integers are treated as offsets from the tip, with -1 denoting the
479 482 tip.
480 483
481 484 A 40-digit hexadecimal string is treated as a unique revision
482 485 identifier.
483 486
484 487 A hexadecimal string less than 40 characters long is treated as a
485 488 unique revision identifier, and referred to as a short-form
486 489 identifier. A short-form identifier is only valid if it is the
487 490 prefix of one full-length identifier.
488 491
489 492 Any other string is treated as a tag name, which is a symbolic
490 493 name associated with a revision identifier. Tag names may not
491 494 contain the ":" character.
492 495
493 496 The reserved name "tip" is a special tag that always identifies
494 497 the most recent revision.
495 498
496 499 SPECIFYING MULTIPLE REVISIONS
497 500 -----------------------------
498 501
499 502 When Mercurial accepts more than one revision, they may be
500 503 specified individually, or provided as a continuous range,
501 504 separated by the ":" character.
502 505
503 506 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
504 507 are revision identifiers. Both BEGIN and END are optional. If
505 508 BEGIN is not specified, it defaults to revision number 0. If END
506 509 is not specified, it defaults to the tip. The range ":" thus
507 510 means "all revisions".
508 511
509 512 If BEGIN is greater than END, revisions are treated in reverse
510 513 order.
511 514
512 515 A range acts as a closed interval. This means that a range of 3:5
513 516 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
514 517
515 518 ENVIRONMENT VARIABLES
516 519 ---------------------
517 520
518 521 HGEDITOR::
519 522 This is the name of the editor to use when committing. Defaults to the
520 523 value of EDITOR.
521 524
522 525 (deprecated, use .hgrc)
523 526
524 527 HGMERGE::
525 528 An executable to use for resolving merge conflicts. The program
526 529 will be executed with three arguments: local file, remote file,
527 530 ancestor file.
528 531
529 532 The default program is "hgmerge", which is a shell script provided
530 533 by Mercurial with some sensible defaults.
531 534
532 535 (deprecated, use .hgrc)
533 536
534 537 HGUSER::
535 538 This is the string used for the author of a commit.
536 539
537 540 (deprecated, use .hgrc)
538 541
539 542 EMAIL::
540 543 If HGUSER is not set, this will be used as the author for a commit.
541 544
542 545 LOGNAME::
543 546 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
544 547 '@hostname' appended) as the author value for a commit.
545 548
546 549 EDITOR::
547 550 This is the name of the editor used in the hgmerge script. It will be
548 551 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
549 552
550 553 PYTHONPATH::
551 554 This is used by Python to find imported modules and may need to be set
552 555 appropriately if Mercurial is not installed system-wide.
553 556
554 557 FILES
555 558 -----
556 559 .hgignore::
557 560 This file contains regular expressions (one per line) that describe file
558 561 names that should be ignored by hg.
559 562
560 563 .hgtags::
561 564 This file contains changeset hash values and text tag names (one of each
562 565 seperated by spaces) that correspond to tagged versions of the repository
563 566 contents.
564 567
565 568 $HOME/.hgrc, .hg/hgrc::
566 569 This file contains defaults and configuration. Values in .hg/hgrc
567 570 override those in .hgrc. See hgrc(5) for details of the contents
568 571 and format of these files.
569 572
570 573 BUGS
571 574 ----
572 575 Probably lots, please post them to the mailing list (See Resources below)
573 576 when you find them.
574 577
575 578 SEE ALSO
576 579 --------
577 580 hgrc(5)
578 581
579 582 AUTHOR
580 583 ------
581 584 Written by Matt Mackall <mpm@selenic.com>
582 585
583 586 RESOURCES
584 587 ---------
585 588 http://selenic.com/mercurial[Main Web Site]
586 589
587 590 http://www.serpentine.com/mercurial[Wiki site]
588 591
589 592 http://selenic.com/hg[Source code repository]
590 593
591 594 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
592 595
593 596 COPYING
594 597 -------
595 598 Copyright (C) 2005 Matt Mackall.
596 599 Free use of this software is granted under the terms of the GNU General
597 600 Public License (GPL).
@@ -1,1542 +1,1541 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import demandload
9 9 demandload(globals(), "os re sys signal shutil")
10 10 demandload(globals(), "fancyopts ui hg util")
11 11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 12 demandload(globals(), "errno socket version struct atexit")
13 13
14 14 class UnknownCommand(Exception):
15 15 """Exception raised if command is not in the command table."""
16 16
17 17 def filterfiles(filters, files):
18 18 l = [x for x in files if x in filters]
19 19
20 20 for t in filters:
21 21 if t and t[-1] != "/":
22 22 t += "/"
23 23 l += [x for x in files if x.startswith(t)]
24 24 return l
25 25
26 26 def relfilter(repo, files):
27 27 cwd = repo.getcwd()
28 28 if cwd:
29 29 return filterfiles([util.pconvert(cwd)], files)
30 30 return files
31 31
32 32 def relpath(repo, args):
33 33 cwd = repo.getcwd()
34 34 if cwd:
35 35 return [util.normpath(os.path.join(cwd, x)) for x in args]
36 36 return args
37 37
38 38 def matchpats(repo, cwd, pats = [], opts = {}, head = ''):
39 39 return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
40 40 opts.get('exclude'), head)
41 41
42 42 def makewalk(repo, pats, opts, head = ''):
43 43 cwd = repo.getcwd()
44 44 files, matchfn = matchpats(repo, cwd, pats, opts, head)
45 45 def walk():
46 46 for src, fn in repo.walk(files = files, match = matchfn):
47 47 yield src, fn, util.pathto(cwd, fn)
48 48 return files, matchfn, walk()
49 49
50 50 def walk(repo, pats, opts, head = ''):
51 51 files, matchfn, results = makewalk(repo, pats, opts, head)
52 52 for r in results: yield r
53 53
54 54 revrangesep = ':'
55 55
56 56 def revrange(ui, repo, revs, revlog=None):
57 57 if revlog is None:
58 58 revlog = repo.changelog
59 59 revcount = revlog.count()
60 60 def fix(val, defval):
61 61 if not val:
62 62 return defval
63 63 try:
64 64 num = int(val)
65 65 if str(num) != val:
66 66 raise ValueError
67 67 if num < 0:
68 68 num += revcount
69 69 if not (0 <= num < revcount):
70 70 raise ValueError
71 71 except ValueError:
72 72 try:
73 73 num = repo.changelog.rev(repo.lookup(val))
74 74 except KeyError:
75 75 try:
76 76 num = revlog.rev(revlog.lookup(val))
77 77 except KeyError:
78 78 raise util.Abort('invalid revision identifier %s', val)
79 79 return num
80 80 for spec in revs:
81 81 if spec.find(revrangesep) >= 0:
82 82 start, end = spec.split(revrangesep, 1)
83 83 start = fix(start, 0)
84 84 end = fix(end, revcount - 1)
85 85 if end > start:
86 86 end += 1
87 87 step = 1
88 88 else:
89 89 end -= 1
90 90 step = -1
91 91 for rev in xrange(start, end, step):
92 92 yield str(rev)
93 93 else:
94 94 yield spec
95 95
96 96 def make_filename(repo, r, pat, node=None,
97 97 total=None, seqno=None, revwidth=None):
98 98 node_expander = {
99 99 'H': lambda: hg.hex(node),
100 100 'R': lambda: str(r.rev(node)),
101 101 'h': lambda: hg.short(node),
102 102 }
103 103 expander = {
104 104 '%': lambda: '%',
105 105 'b': lambda: os.path.basename(repo.root),
106 106 }
107 107
108 108 try:
109 109 if node:
110 110 expander.update(node_expander)
111 111 if node and revwidth is not None:
112 112 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
113 113 if total is not None:
114 114 expander['N'] = lambda: str(total)
115 115 if seqno is not None:
116 116 expander['n'] = lambda: str(seqno)
117 117 if total is not None and seqno is not None:
118 118 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
119 119
120 120 newname = []
121 121 patlen = len(pat)
122 122 i = 0
123 123 while i < patlen:
124 124 c = pat[i]
125 125 if c == '%':
126 126 i += 1
127 127 c = pat[i]
128 128 c = expander[c]()
129 129 newname.append(c)
130 130 i += 1
131 131 return ''.join(newname)
132 132 except KeyError, inst:
133 133 raise util.Abort("invalid format spec '%%%s' in output file name",
134 134 inst.args[0])
135 135
136 136 def make_file(repo, r, pat, node=None,
137 137 total=None, seqno=None, revwidth=None, mode='wb'):
138 138 if not pat or pat == '-':
139 139 if 'w' in mode: return sys.stdout
140 140 else: return sys.stdin
141 141 if hasattr(pat, 'write') and 'w' in mode:
142 142 return pat
143 143 if hasattr(pat, 'read') and 'r' in mode:
144 144 return pat
145 145 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
146 146 mode)
147 147
148 148 def dodiff(fp, ui, repo, files=None, node1=None, node2=None, match=util.always, changes=None):
149 149 def date(c):
150 150 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
151 151
152 152 if not changes:
153 153 (c, a, d, u) = repo.changes(node1, node2, files, match = match)
154 154 else:
155 155 (c, a, d, u) = changes
156 156 if files:
157 157 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
158 158
159 159 if not c and not a and not d:
160 160 return
161 161
162 162 if node2:
163 163 change = repo.changelog.read(node2)
164 164 mmap2 = repo.manifest.read(change[0])
165 165 date2 = date(change)
166 166 def read(f):
167 167 return repo.file(f).read(mmap2[f])
168 168 else:
169 169 date2 = time.asctime()
170 170 if not node1:
171 171 node1 = repo.dirstate.parents()[0]
172 172 def read(f):
173 173 return repo.wfile(f).read()
174 174
175 175 if ui.quiet:
176 176 r = None
177 177 else:
178 178 hexfunc = ui.verbose and hg.hex or hg.short
179 179 r = [hexfunc(node) for node in [node1, node2] if node]
180 180
181 181 change = repo.changelog.read(node1)
182 182 mmap = repo.manifest.read(change[0])
183 183 date1 = date(change)
184 184
185 185 for f in c:
186 186 to = None
187 187 if f in mmap:
188 188 to = repo.file(f).read(mmap[f])
189 189 tn = read(f)
190 190 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
191 191 for f in a:
192 192 to = None
193 193 tn = read(f)
194 194 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
195 195 for f in d:
196 196 to = repo.file(f).read(mmap[f])
197 197 tn = None
198 198 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
199 199
200 200 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
201 201 """show a single changeset or file revision"""
202 202 changelog = repo.changelog
203 203 if filelog:
204 204 log = filelog
205 205 filerev = rev
206 206 node = filenode = filelog.node(filerev)
207 207 changerev = filelog.linkrev(filenode)
208 208 changenode = changenode or changelog.node(changerev)
209 209 else:
210 210 log = changelog
211 211 changerev = rev
212 212 if changenode is None:
213 213 changenode = changelog.node(changerev)
214 214 elif not changerev:
215 215 rev = changerev = changelog.rev(changenode)
216 216 node = changenode
217 217
218 218 if ui.quiet:
219 219 ui.write("%d:%s\n" % (rev, hg.hex(node)))
220 220 return
221 221
222 222 changes = changelog.read(changenode)
223 223
224 224 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
225 225 for p in log.parents(node)
226 226 if ui.debugflag or p != hg.nullid]
227 227 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
228 228 parents = []
229 229
230 230 if ui.verbose:
231 231 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
232 232 else:
233 233 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
234 234
235 235 for tag in repo.nodetags(changenode):
236 236 ui.status("tag: %s\n" % tag)
237 237 for parent in parents:
238 238 ui.write("parent: %d:%s\n" % parent)
239 239 if filelog:
240 240 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
241 241
242 242 if brinfo and changenode in brinfo:
243 243 br = brinfo[changenode]
244 244 ui.write("branch: %s\n" % " ".join(br))
245 245
246 246 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
247 247 hg.hex(changes[0])))
248 248 ui.status("user: %s\n" % changes[1])
249 249 ui.status("date: %s\n" % time.asctime(
250 250 time.localtime(float(changes[2].split(' ')[0]))))
251 251
252 252 if ui.debugflag:
253 253 files = repo.changes(changelog.parents(changenode)[0], changenode)
254 254 for key, value in zip(["files:", "files+:", "files-:"], files):
255 255 if value:
256 256 ui.note("%-12s %s\n" % (key, " ".join(value)))
257 257 else:
258 258 ui.note("files: %s\n" % " ".join(changes[3]))
259 259
260 260 description = changes[4].strip()
261 261 if description:
262 262 if ui.verbose:
263 263 ui.status("description:\n")
264 264 ui.status(description)
265 265 ui.status("\n\n")
266 266 else:
267 267 ui.status("summary: %s\n" % description.splitlines()[0])
268 268 ui.status("\n")
269 269
270 270 def show_version(ui):
271 271 """output version and copyright information"""
272 272 ui.write("Mercurial Distributed SCM (version %s)\n"
273 273 % version.get_version())
274 274 ui.status(
275 275 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
276 276 "This is free software; see the source for copying conditions. "
277 277 "There is NO\nwarranty; "
278 278 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
279 279 )
280 280
281 281 def help_(ui, cmd=None):
282 282 """show help for a given command or all commands"""
283 283 if cmd and cmd != 'shortlist':
284 284 key, i = find(cmd)
285 285 # synopsis
286 286 ui.write("%s\n\n" % i[2])
287 287
288 288 # description
289 289 doc = i[0].__doc__
290 290 if ui.quiet:
291 291 doc = doc.splitlines(0)[0]
292 292 ui.write("%s\n" % doc.rstrip())
293 293
294 294 # aliases
295 295 if not ui.quiet:
296 296 aliases = ', '.join(key.split('|')[1:])
297 297 if aliases:
298 298 ui.write("\naliases: %s\n" % aliases)
299 299
300 300 # options
301 301 if not ui.quiet and i[1]:
302 302 ui.write("\noptions:\n\n")
303 303 for s, l, d, c in i[1]:
304 304 opt = ' '
305 305 if s:
306 306 opt = opt + '-' + s + ' '
307 307 if l:
308 308 opt = opt + '--' + l + ' '
309 309 if d:
310 310 opt = opt + '(' + str(d) + ')'
311 311 ui.write(opt, "\n")
312 312 if c:
313 313 ui.write(' %s\n' % c)
314 314
315 315 else:
316 316 # program name
317 317 if ui.verbose:
318 318 show_version(ui)
319 319 else:
320 320 ui.status("Mercurial Distributed SCM\n")
321 321 ui.status('\n')
322 322
323 323 # list of commands
324 324 if cmd == "shortlist":
325 325 ui.status('basic commands (use "hg help" '
326 326 'for the full list or option "-v" for details):\n\n')
327 327 elif ui.verbose:
328 328 ui.status('list of commands:\n\n')
329 329 else:
330 330 ui.status('list of commands (use "hg help -v" '
331 331 'to show aliases and global options):\n\n')
332 332
333 333 h = {}
334 334 cmds = {}
335 335 for c, e in table.items():
336 336 f = c.split("|")[0]
337 337 if cmd == "shortlist" and not f.startswith("^"):
338 338 continue
339 339 f = f.lstrip("^")
340 340 if not ui.debugflag and f.startswith("debug"):
341 341 continue
342 342 d = ""
343 343 if e[0].__doc__:
344 344 d = e[0].__doc__.splitlines(0)[0].rstrip()
345 345 h[f] = d
346 346 cmds[f]=c.lstrip("^")
347 347
348 348 fns = h.keys()
349 349 fns.sort()
350 350 m = max(map(len, fns))
351 351 for f in fns:
352 352 if ui.verbose:
353 353 commands = cmds[f].replace("|",", ")
354 354 ui.write(" %s:\n %s\n"%(commands,h[f]))
355 355 else:
356 356 ui.write(' %-*s %s\n' % (m, f, h[f]))
357 357
358 358 # global options
359 359 if ui.verbose:
360 360 ui.write("\nglobal options:\n\n")
361 361 for s, l, d, c in globalopts:
362 362 opt = ' '
363 363 if s:
364 364 opt = opt + '-' + s + ' '
365 365 if l:
366 366 opt = opt + '--' + l + ' '
367 367 if d:
368 368 opt = opt + '(' + str(d) + ')'
369 369 ui.write(opt, "\n")
370 370 if c:
371 371 ui.write(' %s\n' % c)
372 372
373 373 # Commands start here, listed alphabetically
374 374
375 375 def add(ui, repo, *pats, **opts):
376 376 '''add the specified files on the next commit'''
377 377 names = []
378 378 q = dict(zip(pats, pats))
379 379 for src, abs, rel in walk(repo, pats, opts):
380 380 if rel in q or abs in q:
381 381 names.append(abs)
382 382 elif repo.dirstate.state(abs) == '?':
383 383 ui.status('adding %s\n' % rel)
384 384 names.append(abs)
385 385 repo.add(names)
386 386
387 387 def addremove(ui, repo, *pats, **opts):
388 388 """add all new files, delete all missing files"""
389 389 q = dict(zip(pats, pats))
390 390 add, remove = [], []
391 391 for src, abs, rel in walk(repo, pats, opts):
392 392 if src == 'f' and repo.dirstate.state(abs) == '?':
393 393 add.append(abs)
394 394 if rel not in q: ui.status('adding ', rel, '\n')
395 395 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
396 396 remove.append(abs)
397 397 if rel not in q: ui.status('removing ', rel, '\n')
398 398 repo.add(add)
399 399 repo.remove(remove)
400 400
401 401 def annotate(ui, repo, *pats, **opts):
402 402 """show changeset information per file line"""
403 403 def getnode(rev):
404 404 return hg.short(repo.changelog.node(rev))
405 405
406 406 def getname(rev):
407 407 try:
408 408 return bcache[rev]
409 409 except KeyError:
410 410 cl = repo.changelog.read(repo.changelog.node(rev))
411 411 name = cl[1]
412 412 f = name.find('@')
413 413 if f >= 0:
414 414 name = name[:f]
415 415 f = name.find('<')
416 416 if f >= 0:
417 417 name = name[f+1:]
418 418 bcache[rev] = name
419 419 return name
420 420
421 421 if not pats:
422 422 raise util.Abort('at least one file name or pattern required')
423 423
424 424 bcache = {}
425 425 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
426 426 if not opts['user'] and not opts['changeset']:
427 427 opts['number'] = 1
428 428
429 429 if opts['rev']:
430 430 node = repo.changelog.lookup(opts['rev'])
431 431 else:
432 432 node = repo.dirstate.parents()[0]
433 433 change = repo.changelog.read(node)
434 434 mmap = repo.manifest.read(change[0])
435 435 for src, abs, rel in walk(repo, pats, opts):
436 436 if abs not in mmap:
437 437 ui.warn("warning: %s is not in the repository!\n" % rel)
438 438 continue
439 439
440 440 lines = repo.file(abs).annotate(mmap[abs])
441 441 pieces = []
442 442
443 443 for o, f in opmap:
444 444 if opts[o]:
445 445 l = [f(n) for n, dummy in lines]
446 446 if l:
447 447 m = max(map(len, l))
448 448 pieces.append(["%*s" % (m, x) for x in l])
449 449
450 450 if pieces:
451 451 for p, l in zip(zip(*pieces), lines):
452 452 ui.write("%s: %s" % (" ".join(p), l[1]))
453 453
454 454 def cat(ui, repo, file1, rev=None, **opts):
455 455 """output the latest or given revision of a file"""
456 456 r = repo.file(relpath(repo, [file1])[0])
457 457 if rev:
458 458 n = r.lookup(rev)
459 459 else:
460 460 n = r.tip()
461 461 fp = make_file(repo, r, opts['output'], node=n)
462 462 fp.write(r.read(n))
463 463
464 464 def clone(ui, source, dest=None, **opts):
465 465 """make a copy of an existing repository"""
466 466 if dest is None:
467 467 dest = os.path.basename(os.path.normpath(source))
468 468
469 469 if os.path.exists(dest):
470 470 ui.warn("abort: destination '%s' already exists\n" % dest)
471 471 return 1
472 472
473 473 dest = os.path.realpath(dest)
474 474
475 475 class Dircleanup:
476 476 def __init__(self, dir_):
477 477 self.rmtree = shutil.rmtree
478 478 self.dir_ = dir_
479 479 os.mkdir(dir_)
480 480 def close(self):
481 481 self.dir_ = None
482 482 def __del__(self):
483 483 if self.dir_:
484 484 self.rmtree(self.dir_, True)
485 485
486 486 d = Dircleanup(dest)
487 487 abspath = source
488 488 source = ui.expandpath(source)
489 489 other = hg.repository(ui, source)
490 490
491 491 if other.dev() != -1:
492 492 abspath = os.path.abspath(source)
493 493 copyfile = (os.stat(dest).st_dev == other.dev()
494 494 and getattr(os, 'link', None) or shutil.copy2)
495 495 if copyfile is not shutil.copy2:
496 496 ui.note("cloning by hardlink\n")
497 497 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
498 498 copyfile)
499 499 try:
500 500 os.unlink(os.path.join(dest, ".hg", "dirstate"))
501 501 except OSError:
502 502 pass
503 503
504 504 repo = hg.repository(ui, dest)
505 505
506 506 else:
507 507 repo = hg.repository(ui, dest, create=1)
508 508 repo.pull(other)
509 509
510 510 f = repo.opener("hgrc", "w")
511 511 f.write("[paths]\n")
512 512 f.write("default = %s\n" % abspath)
513 513
514 514 if not opts['noupdate']:
515 515 update(ui, repo)
516 516
517 517 d.close()
518 518
519 519 def commit(ui, repo, *pats, **opts):
520 520 """commit the specified files or all outstanding changes"""
521 521 if opts['text']:
522 522 ui.warn("Warning: -t and --text is deprecated,"
523 523 " please use -m or --message instead.\n")
524 524 message = opts['message'] or opts['text']
525 525 logfile = opts['logfile']
526 526 if not message and logfile:
527 527 try:
528 528 if logfile == '-':
529 529 message = sys.stdin.read()
530 530 else:
531 531 message = open(logfile).read()
532 532 except IOError, why:
533 533 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
534 534
535 535 if opts['addremove']:
536 536 addremove(ui, repo, *pats, **opts)
537 537 cwd = repo.getcwd()
538 538 if not pats and cwd:
539 539 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
540 540 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
541 541 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
542 542 if pats:
543 543 c, a, d, u = repo.changes(files = fns, match = match)
544 544 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
545 545 else:
546 546 files = []
547 547 repo.commit(files, message, opts['user'], opts['date'], match)
548 548
549 549 def copy(ui, repo, source, dest):
550 550 """mark a file as copied or renamed for the next commit"""
551 551 return repo.copy(*relpath(repo, (source, dest)))
552 552
553 553 def debugcheckstate(ui, repo):
554 554 """validate the correctness of the current dirstate"""
555 555 parent1, parent2 = repo.dirstate.parents()
556 556 repo.dirstate.read()
557 557 dc = repo.dirstate.map
558 558 keys = dc.keys()
559 559 keys.sort()
560 560 m1n = repo.changelog.read(parent1)[0]
561 561 m2n = repo.changelog.read(parent2)[0]
562 562 m1 = repo.manifest.read(m1n)
563 563 m2 = repo.manifest.read(m2n)
564 564 errors = 0
565 565 for f in dc:
566 566 state = repo.dirstate.state(f)
567 567 if state in "nr" and f not in m1:
568 568 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
569 569 errors += 1
570 570 if state in "a" and f in m1:
571 571 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
572 572 errors += 1
573 573 if state in "m" and f not in m1 and f not in m2:
574 574 ui.warn("%s in state %s, but not in either manifest\n" %
575 575 (f, state))
576 576 errors += 1
577 577 for f in m1:
578 578 state = repo.dirstate.state(f)
579 579 if state not in "nrm":
580 580 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
581 581 errors += 1
582 582 if errors:
583 583 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
584 584
585 585 def debugstate(ui, repo):
586 586 """show the contents of the current dirstate"""
587 587 repo.dirstate.read()
588 588 dc = repo.dirstate.map
589 589 keys = dc.keys()
590 590 keys.sort()
591 591 for file_ in keys:
592 592 ui.write("%c %3o %10d %s %s\n"
593 593 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
594 594 time.strftime("%x %X",
595 595 time.localtime(dc[file_][3])), file_))
596 596
597 597 def debugindex(ui, file_):
598 598 """dump the contents of an index file"""
599 599 r = hg.revlog(hg.opener(""), file_, "")
600 600 ui.write(" rev offset length base linkrev" +
601 601 " p1 p2 nodeid\n")
602 602 for i in range(r.count()):
603 603 e = r.index[i]
604 604 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
605 605 i, e[0], e[1], e[2], e[3],
606 606 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
607 607
608 608 def debugindexdot(ui, file_):
609 609 """dump an index DAG as a .dot file"""
610 610 r = hg.revlog(hg.opener(""), file_, "")
611 611 ui.write("digraph G {\n")
612 612 for i in range(r.count()):
613 613 e = r.index[i]
614 614 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
615 615 if e[5] != hg.nullid:
616 616 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
617 617 ui.write("}\n")
618 618
619 619 def debugwalk(ui, repo, *pats, **opts):
620 620 items = list(walk(repo, pats, opts))
621 621 if not items: return
622 622 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
623 623 for i in items: print fmt % i
624 624
625 625 def diff(ui, repo, *pats, **opts):
626 626 """diff working directory (or selected files)"""
627 627 revs = []
628 628 if opts['rev']:
629 629 revs = map(lambda x: repo.lookup(x), opts['rev'])
630 630
631 631 if len(revs) > 2:
632 632 raise util.Abort("too many revisions to diff")
633 633
634 634 files = []
635 635 match = util.always
636 636 if pats:
637 637 roots, match, results = makewalk(repo, pats, opts)
638 638 for src, abs, rel in results:
639 639 files.append(abs)
640 640 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
641 641
642 642 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
643 643 node = repo.lookup(changeset)
644 644 prev, other = repo.changelog.parents(node)
645 645 change = repo.changelog.read(node)
646 646
647 647 fp = make_file(repo, repo.changelog, opts['output'],
648 648 node=node, total=total, seqno=seqno,
649 649 revwidth=revwidth)
650 650 if fp != sys.stdout:
651 651 ui.note("%s\n" % fp.name)
652 652
653 653 fp.write("# HG changeset patch\n")
654 654 fp.write("# User %s\n" % change[1])
655 655 fp.write("# Node ID %s\n" % hg.hex(node))
656 656 fp.write("# Parent %s\n" % hg.hex(prev))
657 657 if other != hg.nullid:
658 658 fp.write("# Parent %s\n" % hg.hex(other))
659 659 fp.write(change[4].rstrip())
660 660 fp.write("\n\n")
661 661
662 662 dodiff(fp, ui, repo, None, prev, node)
663 663 if fp != sys.stdout: fp.close()
664 664
665 665 def export(ui, repo, *changesets, **opts):
666 666 """dump the header and diffs for one or more changesets"""
667 667 if not changesets:
668 668 raise util.Abort("export requires at least one changeset")
669 669 seqno = 0
670 670 revs = list(revrange(ui, repo, changesets))
671 671 total = len(revs)
672 672 revwidth = max(len(revs[0]), len(revs[-1]))
673 673 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
674 674 for cset in revs:
675 675 seqno += 1
676 676 doexport(ui, repo, cset, seqno, total, revwidth, opts)
677 677
678 678 def forget(ui, repo, *pats, **opts):
679 679 """don't add the specified files on the next commit"""
680 680 q = dict(zip(pats, pats))
681 681 forget = []
682 682 for src, abs, rel in walk(repo, pats, opts):
683 683 if repo.dirstate.state(abs) == 'a':
684 684 forget.append(abs)
685 685 if rel not in q: ui.status('forgetting ', rel, '\n')
686 686 repo.forget(forget)
687 687
688 688 def heads(ui, repo, **opts):
689 689 """show current repository heads"""
690 690 heads = repo.changelog.heads()
691 691 br = None
692 692 if opts['branches']:
693 693 br = repo.branchlookup(heads)
694 694 for n in repo.changelog.heads():
695 695 show_changeset(ui, repo, changenode=n, brinfo=br)
696 696
697 697 def identify(ui, repo):
698 698 """print information about the working copy"""
699 699 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
700 700 if not parents:
701 701 ui.write("unknown\n")
702 702 return
703 703
704 704 hexfunc = ui.verbose and hg.hex or hg.short
705 705 (c, a, d, u) = repo.changes()
706 706 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
707 707 (c or a or d) and "+" or "")]
708 708
709 709 if not ui.quiet:
710 710 # multiple tags for a single parent separated by '/'
711 711 parenttags = ['/'.join(tags)
712 712 for tags in map(repo.nodetags, parents) if tags]
713 713 # tags for multiple parents separated by ' + '
714 714 if parenttags:
715 715 output.append(' + '.join(parenttags))
716 716
717 717 ui.write("%s\n" % ' '.join(output))
718 718
719 719 def import_(ui, repo, patch1, *patches, **opts):
720 720 """import an ordered set of patches"""
721 721 patches = (patch1,) + patches
722 722
723 723 d = opts["base"]
724 724 strip = opts["strip"]
725 725
726 726 for patch in patches:
727 727 ui.status("applying %s\n" % patch)
728 728 pf = os.path.join(d, patch)
729 729
730 730 message = []
731 731 user = None
732 732 hgpatch = False
733 733 for line in file(pf):
734 734 line = line.rstrip()
735 735 if line.startswith("--- ") or line.startswith("diff -r"):
736 736 break
737 737 elif hgpatch:
738 738 # parse values when importing the result of an hg export
739 739 if line.startswith("# User "):
740 740 user = line[7:]
741 741 ui.debug('User: %s\n' % user)
742 742 elif not line.startswith("# ") and line:
743 743 message.append(line)
744 744 hgpatch = False
745 745 elif line == '# HG changeset patch':
746 746 hgpatch = True
747 747 message = [] # We may have collected garbage
748 748 else:
749 749 message.append(line)
750 750
751 751 # make sure message isn't empty
752 752 if not message:
753 753 message = "imported patch %s\n" % patch
754 754 else:
755 755 message = "%s\n" % '\n'.join(message)
756 756 ui.debug('message:\n%s\n' % message)
757 757
758 758 f = os.popen("patch -p%d < '%s'" % (strip, pf))
759 759 files = []
760 760 for l in f.read().splitlines():
761 761 l.rstrip('\r\n');
762 762 ui.status("%s\n" % l)
763 763 if l.startswith('patching file '):
764 764 pf = l[14:]
765 765 if pf not in files:
766 766 files.append(pf)
767 767 patcherr = f.close()
768 768 if patcherr:
769 769 raise util.Abort("patch failed")
770 770
771 771 if len(files) > 0:
772 772 addremove(ui, repo, *files)
773 773 repo.commit(files, message, user)
774 774
775 def init(ui, source=None):
776 """create a new repository in the current directory"""
777
778 if source:
779 raise util.Abort("no longer supported: use \"hg clone\" instead")
780 hg.repository(ui, ".", create=1)
775 def init(ui, dest="."):
776 """create a new repository in the given directory"""
777 if not os.path.exists(dest):
778 os.mkdir(dest)
779 hg.repository(ui, dest, create=1)
781 780
782 781 def locate(ui, repo, *pats, **opts):
783 782 """locate files matching specific patterns"""
784 783 end = '\n'
785 784 if opts['print0']: end = '\0'
786 785
787 786 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
788 787 if repo.dirstate.state(abs) == '?': continue
789 788 if opts['fullpath']:
790 789 ui.write(os.path.join(repo.root, abs), end)
791 790 else:
792 791 ui.write(rel, end)
793 792
794 793 def log(ui, repo, f=None, **opts):
795 794 """show the revision history of the repository or a single file"""
796 795 if f:
797 796 files = relpath(repo, [f])
798 797 filelog = repo.file(files[0])
799 798 log = filelog
800 799 lookup = filelog.lookup
801 800 else:
802 801 files = None
803 802 filelog = None
804 803 log = repo.changelog
805 804 lookup = repo.lookup
806 805 revlist = []
807 806 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
808 807 while revs:
809 808 if len(revs) == 1:
810 809 revlist.append(revs.pop(0))
811 810 else:
812 811 a = revs.pop(0)
813 812 b = revs.pop(0)
814 813 off = a > b and -1 or 1
815 814 revlist.extend(range(a, b + off, off))
816 815
817 816 for i in revlist or range(log.count() - 1, -1, -1):
818 817 show_changeset(ui, repo, filelog=filelog, rev=i)
819 818 if opts['patch']:
820 819 if filelog:
821 820 filenode = filelog.node(i)
822 821 i = filelog.linkrev(filenode)
823 822 changenode = repo.changelog.node(i)
824 823 prev, other = repo.changelog.parents(changenode)
825 824 dodiff(sys.stdout, ui, repo, files, prev, changenode)
826 825 ui.write("\n\n")
827 826
828 827 def manifest(ui, repo, rev=None):
829 828 """output the latest or given revision of the project manifest"""
830 829 if rev:
831 830 try:
832 831 # assume all revision numbers are for changesets
833 832 n = repo.lookup(rev)
834 833 change = repo.changelog.read(n)
835 834 n = change[0]
836 835 except hg.RepoError:
837 836 n = repo.manifest.lookup(rev)
838 837 else:
839 838 n = repo.manifest.tip()
840 839 m = repo.manifest.read(n)
841 840 mf = repo.manifest.readflags(n)
842 841 files = m.keys()
843 842 files.sort()
844 843
845 844 for f in files:
846 845 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
847 846
848 847 def parents(ui, repo, rev=None):
849 848 """show the parents of the working dir or revision"""
850 849 if rev:
851 850 p = repo.changelog.parents(repo.lookup(rev))
852 851 else:
853 852 p = repo.dirstate.parents()
854 853
855 854 for n in p:
856 855 if n != hg.nullid:
857 856 show_changeset(ui, repo, changenode=n)
858 857
859 858 def paths(ui, repo, search = None):
860 859 """show path or list of available paths"""
861 860 if search:
862 861 for name, path in ui.configitems("paths"):
863 862 if name == search:
864 863 ui.write("%s\n" % path)
865 864 return
866 865 ui.warn("not found!\n")
867 866 return 1
868 867 else:
869 868 for name, path in ui.configitems("paths"):
870 869 ui.write("%s = %s\n" % (name, path))
871 870
872 871 def pull(ui, repo, source="default", **opts):
873 872 """pull changes from the specified source"""
874 873 source = ui.expandpath(source)
875 874 ui.status('pulling from %s\n' % (source))
876 875
877 876 other = hg.repository(ui, source)
878 877 r = repo.pull(other)
879 878 if not r:
880 879 if opts['update']:
881 880 return update(ui, repo)
882 881 else:
883 882 ui.status("(run 'hg update' to get a working copy)\n")
884 883
885 884 return r
886 885
887 886 def push(ui, repo, dest="default-push", force=False):
888 887 """push changes to the specified destination"""
889 888 dest = ui.expandpath(dest)
890 889 ui.status('pushing to %s\n' % (dest))
891 890
892 891 other = hg.repository(ui, dest)
893 892 r = repo.push(other, force)
894 893 return r
895 894
896 895 def rawcommit(ui, repo, *flist, **rc):
897 896 "raw commit interface"
898 897 if rc['text']:
899 898 ui.warn("Warning: -t and --text is deprecated,"
900 899 " please use -m or --message instead.\n")
901 900 message = rc['message'] or rc['text']
902 901 if not message and rc['logfile']:
903 902 try:
904 903 message = open(rc['logfile']).read()
905 904 except IOError:
906 905 pass
907 906 if not message and not rc['logfile']:
908 907 ui.warn("abort: missing commit message\n")
909 908 return 1
910 909
911 910 files = relpath(repo, list(flist))
912 911 if rc['files']:
913 912 files += open(rc['files']).read().splitlines()
914 913
915 914 rc['parent'] = map(repo.lookup, rc['parent'])
916 915
917 916 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
918 917
919 918 def recover(ui, repo):
920 919 """roll back an interrupted transaction"""
921 920 repo.recover()
922 921
923 922 def remove(ui, repo, file1, *files):
924 923 """remove the specified files on the next commit"""
925 924 repo.remove(relpath(repo, (file1,) + files))
926 925
927 926 def revert(ui, repo, *names, **opts):
928 927 """revert modified files or dirs back to their unmodified states"""
929 928 node = opts['rev'] and repo.lookup(opts['rev']) or \
930 929 repo.dirstate.parents()[0]
931 930 root = os.path.realpath(repo.root)
932 931
933 932 def trimpath(p):
934 933 p = os.path.realpath(p)
935 934 if p.startswith(root):
936 935 rest = p[len(root):]
937 936 if not rest:
938 937 return rest
939 938 if p.startswith(os.sep):
940 939 return rest[1:]
941 940 return p
942 941
943 942 relnames = map(trimpath, names or [os.getcwd()])
944 943 chosen = {}
945 944
946 945 def choose(name):
947 946 def body(name):
948 947 for r in relnames:
949 948 if not name.startswith(r):
950 949 continue
951 950 rest = name[len(r):]
952 951 if not rest:
953 952 return r, True
954 953 depth = rest.count(os.sep)
955 954 if not r:
956 955 if depth == 0 or not opts['nonrecursive']:
957 956 return r, True
958 957 elif rest[0] == os.sep:
959 958 if depth == 1 or not opts['nonrecursive']:
960 959 return r, True
961 960 return None, False
962 961 relname, ret = body(name)
963 962 if ret:
964 963 chosen[relname] = 1
965 964 return ret
966 965
967 966 r = repo.update(node, False, True, choose, False)
968 967 for n in relnames:
969 968 if n not in chosen:
970 969 ui.warn('error: no matches for %s\n' % n)
971 970 r = 1
972 971 sys.stdout.flush()
973 972 return r
974 973
975 974 def root(ui, repo):
976 975 """print the root (top) of the current working dir"""
977 976 ui.write(repo.root + "\n")
978 977
979 978 def serve(ui, repo, **opts):
980 979 """export the repository via HTTP"""
981 980
982 981 if opts["stdio"]:
983 982 fin, fout = sys.stdin, sys.stdout
984 983 sys.stdout = sys.stderr
985 984
986 985 def getarg():
987 986 argline = fin.readline()[:-1]
988 987 arg, l = argline.split()
989 988 val = fin.read(int(l))
990 989 return arg, val
991 990 def respond(v):
992 991 fout.write("%d\n" % len(v))
993 992 fout.write(v)
994 993 fout.flush()
995 994
996 995 lock = None
997 996
998 997 while 1:
999 998 cmd = fin.readline()[:-1]
1000 999 if cmd == '':
1001 1000 return
1002 1001 if cmd == "heads":
1003 1002 h = repo.heads()
1004 1003 respond(" ".join(map(hg.hex, h)) + "\n")
1005 1004 if cmd == "lock":
1006 1005 lock = repo.lock()
1007 1006 respond("")
1008 1007 if cmd == "unlock":
1009 1008 if lock:
1010 1009 lock.release()
1011 1010 lock = None
1012 1011 respond("")
1013 1012 elif cmd == "branches":
1014 1013 arg, nodes = getarg()
1015 1014 nodes = map(hg.bin, nodes.split(" "))
1016 1015 r = []
1017 1016 for b in repo.branches(nodes):
1018 1017 r.append(" ".join(map(hg.hex, b)) + "\n")
1019 1018 respond("".join(r))
1020 1019 elif cmd == "between":
1021 1020 arg, pairs = getarg()
1022 1021 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1023 1022 r = []
1024 1023 for b in repo.between(pairs):
1025 1024 r.append(" ".join(map(hg.hex, b)) + "\n")
1026 1025 respond("".join(r))
1027 1026 elif cmd == "changegroup":
1028 1027 nodes = []
1029 1028 arg, roots = getarg()
1030 1029 nodes = map(hg.bin, roots.split(" "))
1031 1030
1032 1031 cg = repo.changegroup(nodes)
1033 1032 while 1:
1034 1033 d = cg.read(4096)
1035 1034 if not d:
1036 1035 break
1037 1036 fout.write(d)
1038 1037
1039 1038 fout.flush()
1040 1039
1041 1040 elif cmd == "addchangegroup":
1042 1041 if not lock:
1043 1042 respond("not locked")
1044 1043 continue
1045 1044 respond("")
1046 1045
1047 1046 r = repo.addchangegroup(fin)
1048 1047 respond("")
1049 1048
1050 1049 def openlog(opt, default):
1051 1050 if opts[opt] and opts[opt] != '-':
1052 1051 return open(opts[opt], 'w')
1053 1052 else:
1054 1053 return default
1055 1054
1056 1055 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1057 1056 opts["address"], opts["port"], opts["ipv6"],
1058 1057 openlog('accesslog', sys.stdout),
1059 1058 openlog('errorlog', sys.stderr))
1060 1059 if ui.verbose:
1061 1060 addr, port = httpd.socket.getsockname()
1062 1061 if addr == '0.0.0.0':
1063 1062 addr = socket.gethostname()
1064 1063 else:
1065 1064 try:
1066 1065 addr = socket.gethostbyaddr(addr)[0]
1067 1066 except socket.error:
1068 1067 pass
1069 1068 if port != 80:
1070 1069 ui.status('listening at http://%s:%d/\n' % (addr, port))
1071 1070 else:
1072 1071 ui.status('listening at http://%s/\n' % addr)
1073 1072 httpd.serve_forever()
1074 1073
1075 1074 def status(ui, repo, *pats, **opts):
1076 1075 '''show changed files in the working directory
1077 1076
1078 1077 M = modified
1079 1078 A = added
1080 1079 R = removed
1081 1080 ? = not tracked
1082 1081 '''
1083 1082
1084 1083 cwd = repo.getcwd()
1085 1084 files, matchfn = matchpats(repo, cwd, pats, opts)
1086 1085 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1087 1086 for n in repo.changes(files=files, match=matchfn)]
1088 1087
1089 1088 changetypes = [('modified', 'M', c),
1090 1089 ('added', 'A', a),
1091 1090 ('removed', 'R', d),
1092 1091 ('unknown', '?', u)]
1093 1092
1094 1093 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1095 1094 or changetypes):
1096 1095 for f in changes:
1097 1096 ui.write("%s %s\n" % (char, f))
1098 1097
1099 1098 def tag(ui, repo, name, rev=None, **opts):
1100 1099 """add a tag for the current tip or a given revision"""
1101 1100 if opts['text']:
1102 1101 ui.warn("Warning: -t and --text is deprecated,"
1103 1102 " please use -m or --message instead.\n")
1104 1103 if name == "tip":
1105 1104 ui.warn("abort: 'tip' is a reserved name!\n")
1106 1105 return -1
1107 1106 if rev:
1108 1107 r = hg.hex(repo.lookup(rev))
1109 1108 else:
1110 1109 r = hg.hex(repo.changelog.tip())
1111 1110
1112 1111 if name.find(revrangesep) >= 0:
1113 1112 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1114 1113 return -1
1115 1114
1116 1115 if opts['local']:
1117 1116 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1118 1117 return
1119 1118
1120 1119 (c, a, d, u) = repo.changes()
1121 1120 for x in (c, a, d, u):
1122 1121 if ".hgtags" in x:
1123 1122 ui.warn("abort: working copy of .hgtags is changed!\n")
1124 1123 ui.status("(please commit .hgtags manually)\n")
1125 1124 return -1
1126 1125
1127 1126 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1128 1127 if repo.dirstate.state(".hgtags") == '?':
1129 1128 repo.add([".hgtags"])
1130 1129
1131 1130 message = (opts['message'] or opts['text'] or
1132 1131 "Added tag %s for changeset %s" % (name, r))
1133 1132 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1134 1133
1135 1134 def tags(ui, repo):
1136 1135 """list repository tags"""
1137 1136
1138 1137 l = repo.tagslist()
1139 1138 l.reverse()
1140 1139 for t, n in l:
1141 1140 try:
1142 1141 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1143 1142 except KeyError:
1144 1143 r = " ?:?"
1145 1144 ui.write("%-30s %s\n" % (t, r))
1146 1145
1147 1146 def tip(ui, repo):
1148 1147 """show the tip revision"""
1149 1148 n = repo.changelog.tip()
1150 1149 show_changeset(ui, repo, changenode=n)
1151 1150
1152 1151 def undo(ui, repo):
1153 1152 """undo the last commit or pull
1154 1153
1155 1154 Roll back the last pull or commit transaction on the
1156 1155 repository, restoring the project to its earlier state.
1157 1156
1158 1157 This command should be used with care. There is only one level of
1159 1158 undo and there is no redo.
1160 1159
1161 1160 This command is not intended for use on public repositories. Once
1162 1161 a change is visible for pull by other users, undoing it locally is
1163 1162 ineffective.
1164 1163 """
1165 1164 repo.undo()
1166 1165
1167 1166 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1168 1167 '''update or merge working directory
1169 1168
1170 1169 If there are no outstanding changes in the working directory and
1171 1170 there is a linear relationship between the current version and the
1172 1171 requested version, the result is the requested version.
1173 1172
1174 1173 Otherwise the result is a merge between the contents of the
1175 1174 current working directory and the requested version. Files that
1176 1175 changed between either parent are marked as changed for the next
1177 1176 commit and a commit must be performed before any further updates
1178 1177 are allowed.
1179 1178 '''
1180 1179 if branch:
1181 1180 br = repo.branchlookup(branch=branch)
1182 1181 found = []
1183 1182 for x in br:
1184 1183 if branch in br[x]:
1185 1184 found.append(x)
1186 1185 if len(found) > 1:
1187 1186 ui.warn("Found multiple heads for %s\n" % branch)
1188 1187 for x in found:
1189 1188 show_changeset(ui, repo, changenode=x, brinfo=br)
1190 1189 return 1
1191 1190 if len(found) == 1:
1192 1191 node = found[0]
1193 1192 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1194 1193 else:
1195 1194 ui.warn("branch %s not found\n" % (branch))
1196 1195 return 1
1197 1196 else:
1198 1197 node = node and repo.lookup(node) or repo.changelog.tip()
1199 1198 return repo.update(node, allow=merge, force=clean)
1200 1199
1201 1200 def verify(ui, repo):
1202 1201 """verify the integrity of the repository"""
1203 1202 return repo.verify()
1204 1203
1205 1204 # Command options and aliases are listed here, alphabetically
1206 1205
1207 1206 table = {
1208 1207 "^add":
1209 1208 (add,
1210 1209 [('I', 'include', [], 'include path in search'),
1211 1210 ('X', 'exclude', [], 'exclude path from search')],
1212 1211 "hg add [FILE]..."),
1213 1212 "addremove":
1214 1213 (addremove,
1215 1214 [('I', 'include', [], 'include path in search'),
1216 1215 ('X', 'exclude', [], 'exclude path from search')],
1217 1216 "hg addremove [OPTION]... [FILE]..."),
1218 1217 "^annotate":
1219 1218 (annotate,
1220 1219 [('r', 'rev', '', 'revision'),
1221 1220 ('u', 'user', None, 'show user'),
1222 1221 ('n', 'number', None, 'show revision number'),
1223 1222 ('c', 'changeset', None, 'show changeset'),
1224 1223 ('I', 'include', [], 'include path in search'),
1225 1224 ('X', 'exclude', [], 'exclude path from search')],
1226 1225 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1227 1226 "cat":
1228 1227 (cat,
1229 1228 [('o', 'output', "", 'output to file')],
1230 1229 'hg cat [-o OUTFILE] FILE [REV]'),
1231 1230 "^clone":
1232 1231 (clone,
1233 1232 [('U', 'noupdate', None, 'skip update after cloning')],
1234 1233 'hg clone [-U] SOURCE [DEST]'),
1235 1234 "^commit|ci":
1236 1235 (commit,
1237 1236 [('A', 'addremove', None, 'run add/remove during commit'),
1238 1237 ('I', 'include', [], 'include path in search'),
1239 1238 ('X', 'exclude', [], 'exclude path from search'),
1240 1239 ('m', 'message', "", 'commit message'),
1241 1240 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1242 1241 ('l', 'logfile', "", 'commit message file'),
1243 1242 ('d', 'date', "", 'date code'),
1244 1243 ('u', 'user', "", 'user')],
1245 1244 'hg commit [OPTION]... [FILE]...'),
1246 1245 "copy": (copy, [], 'hg copy SOURCE DEST'),
1247 1246 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1248 1247 "debugstate": (debugstate, [], 'debugstate'),
1249 1248 "debugindex": (debugindex, [], 'debugindex FILE'),
1250 1249 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1251 1250 "debugwalk":
1252 1251 (debugwalk,
1253 1252 [('I', 'include', [], 'include path in search'),
1254 1253 ('X', 'exclude', [], 'exclude path from search')],
1255 1254 'debugwalk [OPTIONS]... [FILE]...'),
1256 1255 "^diff":
1257 1256 (diff,
1258 1257 [('r', 'rev', [], 'revision'),
1259 1258 ('I', 'include', [], 'include path in search'),
1260 1259 ('X', 'exclude', [], 'exclude path from search')],
1261 1260 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1262 1261 "^export":
1263 1262 (export,
1264 1263 [('o', 'output', "", 'output to file')],
1265 1264 "hg export [-o OUTFILE] REV..."),
1266 1265 "forget":
1267 1266 (forget,
1268 1267 [('I', 'include', [], 'include path in search'),
1269 1268 ('X', 'exclude', [], 'exclude path from search')],
1270 1269 "hg forget FILE..."),
1271 1270 "heads":
1272 1271 (heads,
1273 1272 [('b', 'branches', None, 'find branch info')],
1274 1273 'hg [-b] heads'),
1275 1274 "help": (help_, [], 'hg help [COMMAND]'),
1276 1275 "identify|id": (identify, [], 'hg identify'),
1277 1276 "import|patch":
1278 1277 (import_,
1279 1278 [('p', 'strip', 1, 'path strip'),
1280 1279 ('b', 'base', "", 'base path')],
1281 1280 "hg import [-p NUM] [-b BASE] PATCH..."),
1282 "^init": (init, [], 'hg init'),
1281 "^init": (init, [], 'hg init [DEST]'),
1283 1282 "locate":
1284 1283 (locate,
1285 1284 [('r', 'rev', '', 'revision'),
1286 1285 ('0', 'print0', None, 'end records with NUL'),
1287 1286 ('f', 'fullpath', None, 'print complete paths'),
1288 1287 ('I', 'include', [], 'include path in search'),
1289 1288 ('X', 'exclude', [], 'exclude path from search')],
1290 1289 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1291 1290 "^log|history":
1292 1291 (log,
1293 1292 [('r', 'rev', [], 'revision'),
1294 1293 ('p', 'patch', None, 'show patch')],
1295 1294 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1296 1295 "manifest": (manifest, [], 'hg manifest [REV]'),
1297 1296 "parents": (parents, [], 'hg parents [REV]'),
1298 1297 "paths": (paths, [], 'hg paths [name]'),
1299 1298 "^pull":
1300 1299 (pull,
1301 1300 [('u', 'update', None, 'update working directory')],
1302 1301 'hg pull [-u] [SOURCE]'),
1303 1302 "^push":
1304 1303 (push,
1305 1304 [('f', 'force', None, 'force push')],
1306 1305 'hg push [DEST]'),
1307 1306 "rawcommit":
1308 1307 (rawcommit,
1309 1308 [('p', 'parent', [], 'parent'),
1310 1309 ('d', 'date', "", 'date code'),
1311 1310 ('u', 'user', "", 'user'),
1312 1311 ('F', 'files', "", 'file list'),
1313 1312 ('m', 'message', "", 'commit message'),
1314 1313 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1315 1314 ('l', 'logfile', "", 'commit message file')],
1316 1315 'hg rawcommit [OPTION]... [FILE]...'),
1317 1316 "recover": (recover, [], "hg recover"),
1318 1317 "^remove|rm": (remove, [], "hg remove FILE..."),
1319 1318 "^revert":
1320 1319 (revert,
1321 1320 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1322 1321 ("r", "rev", "", "revision")],
1323 1322 "hg revert [-n] [-r REV] [NAME]..."),
1324 1323 "root": (root, [], "hg root"),
1325 1324 "^serve":
1326 1325 (serve,
1327 1326 [('A', 'accesslog', '', 'access log file'),
1328 1327 ('E', 'errorlog', '', 'error log file'),
1329 1328 ('p', 'port', 8000, 'listen port'),
1330 1329 ('a', 'address', '', 'interface address'),
1331 1330 ('n', 'name', os.getcwd(), 'repository name'),
1332 1331 ('', 'stdio', None, 'for remote clients'),
1333 1332 ('t', 'templates', "", 'template map'),
1334 1333 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1335 1334 "hg serve [OPTION]..."),
1336 1335 "^status":
1337 1336 (status,
1338 1337 [('m', 'modified', None, 'show only modified files'),
1339 1338 ('a', 'added', None, 'show only added files'),
1340 1339 ('r', 'removed', None, 'show only removed files'),
1341 1340 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1342 1341 ('I', 'include', [], 'include path in search'),
1343 1342 ('X', 'exclude', [], 'exclude path from search')],
1344 1343 "hg status [FILE]..."),
1345 1344 "tag":
1346 1345 (tag,
1347 1346 [('l', 'local', None, 'make the tag local'),
1348 1347 ('m', 'message', "", 'commit message'),
1349 1348 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1350 1349 ('d', 'date', "", 'date code'),
1351 1350 ('u', 'user', "", 'user')],
1352 1351 'hg tag [OPTION]... NAME [REV]'),
1353 1352 "tags": (tags, [], 'hg tags'),
1354 1353 "tip": (tip, [], 'hg tip'),
1355 1354 "undo": (undo, [], 'hg undo'),
1356 1355 "^update|up|checkout|co":
1357 1356 (update,
1358 1357 [('b', 'branch', "", 'checkout the head of a specific branch'),
1359 1358 ('m', 'merge', None, 'allow merging of conflicts'),
1360 1359 ('C', 'clean', None, 'overwrite locally modified files')],
1361 1360 'hg update [-b TAG] [-m] [-C] [REV]'),
1362 1361 "verify": (verify, [], 'hg verify'),
1363 1362 "version": (show_version, [], 'hg version'),
1364 1363 }
1365 1364
1366 1365 globalopts = [('v', 'verbose', None, 'verbose mode'),
1367 1366 ('', 'debug', None, 'debug mode'),
1368 1367 ('q', 'quiet', None, 'quiet mode'),
1369 1368 ('', 'profile', None, 'profile'),
1370 1369 ('R', 'repository', "", 'repository root directory'),
1371 1370 ('', 'traceback', None, 'print traceback on exception'),
1372 1371 ('y', 'noninteractive', None, 'run non-interactively'),
1373 1372 ('', 'version', None, 'output version information and exit'),
1374 1373 ('', 'time', None, 'time how long the command takes'),
1375 1374 ]
1376 1375
1377 1376 norepo = "clone init version help debugindex debugindexdot"
1378 1377
1379 1378 def find(cmd):
1380 1379 for e in table.keys():
1381 1380 if re.match("(%s)$" % e, cmd):
1382 1381 return e, table[e]
1383 1382
1384 1383 raise UnknownCommand(cmd)
1385 1384
1386 1385 class SignalInterrupt(Exception):
1387 1386 """Exception raised on SIGTERM and SIGHUP."""
1388 1387
1389 1388 def catchterm(*args):
1390 1389 raise SignalInterrupt
1391 1390
1392 1391 def run():
1393 1392 sys.exit(dispatch(sys.argv[1:]))
1394 1393
1395 1394 class ParseError(Exception):
1396 1395 """Exception raised on errors in parsing the command line."""
1397 1396
1398 1397 def parse(args):
1399 1398 options = {}
1400 1399 cmdoptions = {}
1401 1400
1402 1401 try:
1403 1402 args = fancyopts.fancyopts(args, globalopts, options)
1404 1403 except fancyopts.getopt.GetoptError, inst:
1405 1404 raise ParseError(None, inst)
1406 1405
1407 1406 if options["version"]:
1408 1407 return ("version", show_version, [], options, cmdoptions)
1409 1408 elif not args:
1410 1409 return ("help", help_, ["shortlist"], options, cmdoptions)
1411 1410 else:
1412 1411 cmd, args = args[0], args[1:]
1413 1412
1414 1413 i = find(cmd)[1]
1415 1414
1416 1415 # combine global options into local
1417 1416 c = list(i[1])
1418 1417 for o in globalopts:
1419 1418 c.append((o[0], o[1], options[o[1]], o[3]))
1420 1419
1421 1420 try:
1422 1421 args = fancyopts.fancyopts(args, c, cmdoptions)
1423 1422 except fancyopts.getopt.GetoptError, inst:
1424 1423 raise ParseError(cmd, inst)
1425 1424
1426 1425 # separate global options back out
1427 1426 for o in globalopts:
1428 1427 n = o[1]
1429 1428 options[n] = cmdoptions[n]
1430 1429 del cmdoptions[n]
1431 1430
1432 1431 return (cmd, i[0], args, options, cmdoptions)
1433 1432
1434 1433 def dispatch(args):
1435 1434 signal.signal(signal.SIGTERM, catchterm)
1436 1435 try:
1437 1436 signal.signal(signal.SIGHUP, catchterm)
1438 1437 except AttributeError:
1439 1438 pass
1440 1439
1441 1440 try:
1442 1441 cmd, func, args, options, cmdoptions = parse(args)
1443 1442 except ParseError, inst:
1444 1443 u = ui.ui()
1445 1444 if inst.args[0]:
1446 1445 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1447 1446 help_(u, inst.args[0])
1448 1447 else:
1449 1448 u.warn("hg: %s\n" % inst.args[1])
1450 1449 help_(u, 'shortlist')
1451 1450 sys.exit(-1)
1452 1451 except UnknownCommand, inst:
1453 1452 u = ui.ui()
1454 1453 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1455 1454 help_(u, 'shortlist')
1456 1455 sys.exit(1)
1457 1456
1458 1457 if options["time"]:
1459 1458 def get_times():
1460 1459 t = os.times()
1461 1460 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1462 1461 t = (t[0], t[1], t[2], t[3], time.clock())
1463 1462 return t
1464 1463 s = get_times()
1465 1464 def print_time():
1466 1465 t = get_times()
1467 1466 u = ui.ui()
1468 1467 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1469 1468 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1470 1469 atexit.register(print_time)
1471 1470
1472 1471 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1473 1472 not options["noninteractive"])
1474 1473
1475 1474 try:
1476 1475 try:
1477 1476 if cmd not in norepo.split():
1478 1477 path = options["repository"] or ""
1479 1478 repo = hg.repository(ui=u, path=path)
1480 1479 d = lambda: func(u, repo, *args, **cmdoptions)
1481 1480 else:
1482 1481 d = lambda: func(u, *args, **cmdoptions)
1483 1482
1484 1483 if options['profile']:
1485 1484 import hotshot, hotshot.stats
1486 1485 prof = hotshot.Profile("hg.prof")
1487 1486 r = prof.runcall(d)
1488 1487 prof.close()
1489 1488 stats = hotshot.stats.load("hg.prof")
1490 1489 stats.strip_dirs()
1491 1490 stats.sort_stats('time', 'calls')
1492 1491 stats.print_stats(40)
1493 1492 return r
1494 1493 else:
1495 1494 return d()
1496 1495 except:
1497 1496 if options['traceback']:
1498 1497 traceback.print_exc()
1499 1498 raise
1500 1499 except hg.RepoError, inst:
1501 1500 u.warn("abort: ", inst, "!\n")
1502 1501 except SignalInterrupt:
1503 1502 u.warn("killed!\n")
1504 1503 except KeyboardInterrupt:
1505 1504 try:
1506 1505 u.warn("interrupted!\n")
1507 1506 except IOError, inst:
1508 1507 if inst.errno == errno.EPIPE:
1509 1508 if u.debugflag:
1510 1509 u.warn("\nbroken pipe\n")
1511 1510 else:
1512 1511 raise
1513 1512 except IOError, inst:
1514 1513 if hasattr(inst, "code"):
1515 1514 u.warn("abort: %s\n" % inst)
1516 1515 elif hasattr(inst, "reason"):
1517 1516 u.warn("abort: error: %s\n" % inst.reason[1])
1518 1517 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1519 1518 if u.debugflag: u.warn("broken pipe\n")
1520 1519 else:
1521 1520 raise
1522 1521 except OSError, inst:
1523 1522 if hasattr(inst, "filename"):
1524 1523 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1525 1524 else:
1526 1525 u.warn("abort: %s\n" % inst.strerror)
1527 1526 except util.Abort, inst:
1528 1527 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1529 1528 sys.exit(1)
1530 1529 except TypeError, inst:
1531 1530 # was this an argument error?
1532 1531 tb = traceback.extract_tb(sys.exc_info()[2])
1533 1532 if len(tb) > 2: # no
1534 1533 raise
1535 1534 u.debug(inst, "\n")
1536 1535 u.warn("%s: invalid arguments\n" % cmd)
1537 1536 help_(u, cmd)
1538 1537 except UnknownCommand, inst:
1539 1538 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1540 1539 help_(u, 'shortlist')
1541 1540
1542 1541 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now