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