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