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