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