##// END OF EJS Templates
clone: move code into hg module. make doc better....
Vadim Gelfer -
r2597:5ba8be56 default
parent child Browse files
Show More
@@ -1,3638 +1,3546 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 from i18n import gettext as _
11 11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
14 14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 15 demandload(globals(), "archival cStringIO changegroup email.Parser")
16 16 demandload(globals(), "hgweb.server sshserver")
17 17
18 18 class UnknownCommand(Exception):
19 19 """Exception raised if command is not in the command table."""
20 20 class AmbiguousCommand(Exception):
21 21 """Exception raised if command shortcut matches more than one command."""
22 22
23 23 def bail_if_changed(repo):
24 24 modified, added, removed, deleted, unknown = repo.changes()
25 25 if modified or added or removed or deleted:
26 26 raise util.Abort(_("outstanding uncommitted changes"))
27 27
28 28 def filterfiles(filters, files):
29 29 l = [x for x in files if x in filters]
30 30
31 31 for t in filters:
32 32 if t and t[-1] != "/":
33 33 t += "/"
34 34 l += [x for x in files if x.startswith(t)]
35 35 return l
36 36
37 37 def relpath(repo, args):
38 38 cwd = repo.getcwd()
39 39 if cwd:
40 40 return [util.normpath(os.path.join(cwd, x)) for x in args]
41 41 return args
42 42
43 43 def matchpats(repo, pats=[], opts={}, head=''):
44 44 cwd = repo.getcwd()
45 45 if not pats and cwd:
46 46 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
47 47 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
48 48 cwd = ''
49 49 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
50 50 opts.get('exclude'), head)
51 51
52 52 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
53 53 files, matchfn, anypats = matchpats(repo, pats, opts, head)
54 54 exact = dict(zip(files, files))
55 55 def walk():
56 56 for src, fn in repo.walk(node=node, files=files, match=matchfn,
57 57 badmatch=badmatch):
58 58 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
59 59 return files, matchfn, walk()
60 60
61 61 def walk(repo, pats, opts, node=None, head='', badmatch=None):
62 62 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
63 63 for r in results:
64 64 yield r
65 65
66 66 def walkchangerevs(ui, repo, pats, opts):
67 67 '''Iterate over files and the revs they changed in.
68 68
69 69 Callers most commonly need to iterate backwards over the history
70 70 it is interested in. Doing so has awful (quadratic-looking)
71 71 performance, so we use iterators in a "windowed" way.
72 72
73 73 We walk a window of revisions in the desired order. Within the
74 74 window, we first walk forwards to gather data, then in the desired
75 75 order (usually backwards) to display it.
76 76
77 77 This function returns an (iterator, getchange, matchfn) tuple. The
78 78 getchange function returns the changelog entry for a numeric
79 79 revision. The iterator yields 3-tuples. They will be of one of
80 80 the following forms:
81 81
82 82 "window", incrementing, lastrev: stepping through a window,
83 83 positive if walking forwards through revs, last rev in the
84 84 sequence iterated over - use to reset state for the current window
85 85
86 86 "add", rev, fns: out-of-order traversal of the given file names
87 87 fns, which changed during revision rev - use to gather data for
88 88 possible display
89 89
90 90 "iter", rev, None: in-order traversal of the revs earlier iterated
91 91 over with "add" - use to display data'''
92 92
93 93 def increasing_windows(start, end, windowsize=8, sizelimit=512):
94 94 if start < end:
95 95 while start < end:
96 96 yield start, min(windowsize, end-start)
97 97 start += windowsize
98 98 if windowsize < sizelimit:
99 99 windowsize *= 2
100 100 else:
101 101 while start > end:
102 102 yield start, min(windowsize, start-end-1)
103 103 start -= windowsize
104 104 if windowsize < sizelimit:
105 105 windowsize *= 2
106 106
107 107
108 108 files, matchfn, anypats = matchpats(repo, pats, opts)
109 109
110 110 if repo.changelog.count() == 0:
111 111 return [], False, matchfn
112 112
113 113 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
114 114 wanted = {}
115 115 slowpath = anypats
116 116 fncache = {}
117 117
118 118 chcache = {}
119 119 def getchange(rev):
120 120 ch = chcache.get(rev)
121 121 if ch is None:
122 122 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
123 123 return ch
124 124
125 125 if not slowpath and not files:
126 126 # No files, no patterns. Display all revs.
127 127 wanted = dict(zip(revs, revs))
128 128 if not slowpath:
129 129 # Only files, no patterns. Check the history of each file.
130 130 def filerevgen(filelog):
131 131 for i, window in increasing_windows(filelog.count()-1, -1):
132 132 revs = []
133 133 for j in xrange(i - window, i + 1):
134 134 revs.append(filelog.linkrev(filelog.node(j)))
135 135 revs.reverse()
136 136 for rev in revs:
137 137 yield rev
138 138
139 139 minrev, maxrev = min(revs), max(revs)
140 140 for file_ in files:
141 141 filelog = repo.file(file_)
142 142 # A zero count may be a directory or deleted file, so
143 143 # try to find matching entries on the slow path.
144 144 if filelog.count() == 0:
145 145 slowpath = True
146 146 break
147 147 for rev in filerevgen(filelog):
148 148 if rev <= maxrev:
149 149 if rev < minrev:
150 150 break
151 151 fncache.setdefault(rev, [])
152 152 fncache[rev].append(file_)
153 153 wanted[rev] = 1
154 154 if slowpath:
155 155 # The slow path checks files modified in every changeset.
156 156 def changerevgen():
157 157 for i, window in increasing_windows(repo.changelog.count()-1, -1):
158 158 for j in xrange(i - window, i + 1):
159 159 yield j, getchange(j)[3]
160 160
161 161 for rev, changefiles in changerevgen():
162 162 matches = filter(matchfn, changefiles)
163 163 if matches:
164 164 fncache[rev] = matches
165 165 wanted[rev] = 1
166 166
167 167 def iterate():
168 168 for i, window in increasing_windows(0, len(revs)):
169 169 yield 'window', revs[0] < revs[-1], revs[-1]
170 170 nrevs = [rev for rev in revs[i:i+window]
171 171 if rev in wanted]
172 172 srevs = list(nrevs)
173 173 srevs.sort()
174 174 for rev in srevs:
175 175 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
176 176 yield 'add', rev, fns
177 177 for rev in nrevs:
178 178 yield 'iter', rev, None
179 179 return iterate(), getchange, matchfn
180 180
181 181 revrangesep = ':'
182 182
183 183 def revfix(repo, val, defval):
184 184 '''turn user-level id of changeset into rev number.
185 185 user-level id can be tag, changeset, rev number, or negative rev
186 186 number relative to number of revs (-1 is tip, etc).'''
187 187 if not val:
188 188 return defval
189 189 try:
190 190 num = int(val)
191 191 if str(num) != val:
192 192 raise ValueError
193 193 if num < 0:
194 194 num += repo.changelog.count()
195 195 if num < 0:
196 196 num = 0
197 197 elif num >= repo.changelog.count():
198 198 raise ValueError
199 199 except ValueError:
200 200 try:
201 201 num = repo.changelog.rev(repo.lookup(val))
202 202 except KeyError:
203 203 raise util.Abort(_('invalid revision identifier %s'), val)
204 204 return num
205 205
206 206 def revpair(ui, repo, revs):
207 207 '''return pair of nodes, given list of revisions. second item can
208 208 be None, meaning use working dir.'''
209 209 if not revs:
210 210 return repo.dirstate.parents()[0], None
211 211 end = None
212 212 if len(revs) == 1:
213 213 start = revs[0]
214 214 if revrangesep in start:
215 215 start, end = start.split(revrangesep, 1)
216 216 start = revfix(repo, start, 0)
217 217 end = revfix(repo, end, repo.changelog.count() - 1)
218 218 else:
219 219 start = revfix(repo, start, None)
220 220 elif len(revs) == 2:
221 221 if revrangesep in revs[0] or revrangesep in revs[1]:
222 222 raise util.Abort(_('too many revisions specified'))
223 223 start = revfix(repo, revs[0], None)
224 224 end = revfix(repo, revs[1], None)
225 225 else:
226 226 raise util.Abort(_('too many revisions specified'))
227 227 if end is not None: end = repo.lookup(str(end))
228 228 return repo.lookup(str(start)), end
229 229
230 230 def revrange(ui, repo, revs):
231 231 """Yield revision as strings from a list of revision specifications."""
232 232 seen = {}
233 233 for spec in revs:
234 234 if revrangesep in spec:
235 235 start, end = spec.split(revrangesep, 1)
236 236 start = revfix(repo, start, 0)
237 237 end = revfix(repo, end, repo.changelog.count() - 1)
238 238 step = start > end and -1 or 1
239 239 for rev in xrange(start, end+step, step):
240 240 if rev in seen:
241 241 continue
242 242 seen[rev] = 1
243 243 yield str(rev)
244 244 else:
245 245 rev = revfix(repo, spec, None)
246 246 if rev in seen:
247 247 continue
248 248 seen[rev] = 1
249 249 yield str(rev)
250 250
251 251 def make_filename(repo, pat, node,
252 252 total=None, seqno=None, revwidth=None, pathname=None):
253 253 node_expander = {
254 254 'H': lambda: hex(node),
255 255 'R': lambda: str(repo.changelog.rev(node)),
256 256 'h': lambda: short(node),
257 257 }
258 258 expander = {
259 259 '%': lambda: '%',
260 260 'b': lambda: os.path.basename(repo.root),
261 261 }
262 262
263 263 try:
264 264 if node:
265 265 expander.update(node_expander)
266 266 if node and revwidth is not None:
267 267 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
268 268 if total is not None:
269 269 expander['N'] = lambda: str(total)
270 270 if seqno is not None:
271 271 expander['n'] = lambda: str(seqno)
272 272 if total is not None and seqno is not None:
273 273 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
274 274 if pathname is not None:
275 275 expander['s'] = lambda: os.path.basename(pathname)
276 276 expander['d'] = lambda: os.path.dirname(pathname) or '.'
277 277 expander['p'] = lambda: pathname
278 278
279 279 newname = []
280 280 patlen = len(pat)
281 281 i = 0
282 282 while i < patlen:
283 283 c = pat[i]
284 284 if c == '%':
285 285 i += 1
286 286 c = pat[i]
287 287 c = expander[c]()
288 288 newname.append(c)
289 289 i += 1
290 290 return ''.join(newname)
291 291 except KeyError, inst:
292 292 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
293 293 inst.args[0])
294 294
295 295 def make_file(repo, pat, node=None,
296 296 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
297 297 if not pat or pat == '-':
298 298 return 'w' in mode and sys.stdout or sys.stdin
299 299 if hasattr(pat, 'write') and 'w' in mode:
300 300 return pat
301 301 if hasattr(pat, 'read') and 'r' in mode:
302 302 return pat
303 303 return open(make_filename(repo, pat, node, total, seqno, revwidth,
304 304 pathname),
305 305 mode)
306 306
307 307 def write_bundle(cg, filename=None, compress=True):
308 308 """Write a bundle file and return its filename.
309 309
310 310 Existing files will not be overwritten.
311 311 If no filename is specified, a temporary file is created.
312 312 bz2 compression can be turned off.
313 313 The bundle file will be deleted in case of errors.
314 314 """
315 315 class nocompress(object):
316 316 def compress(self, x):
317 317 return x
318 318 def flush(self):
319 319 return ""
320 320
321 321 fh = None
322 322 cleanup = None
323 323 try:
324 324 if filename:
325 325 if os.path.exists(filename):
326 326 raise util.Abort(_("file '%s' already exists"), filename)
327 327 fh = open(filename, "wb")
328 328 else:
329 329 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
330 330 fh = os.fdopen(fd, "wb")
331 331 cleanup = filename
332 332
333 333 if compress:
334 334 fh.write("HG10")
335 335 z = bz2.BZ2Compressor(9)
336 336 else:
337 337 fh.write("HG10UN")
338 338 z = nocompress()
339 339 # parse the changegroup data, otherwise we will block
340 340 # in case of sshrepo because we don't know the end of the stream
341 341
342 342 # an empty chunkiter is the end of the changegroup
343 343 empty = False
344 344 while not empty:
345 345 empty = True
346 346 for chunk in changegroup.chunkiter(cg):
347 347 empty = False
348 348 fh.write(z.compress(changegroup.genchunk(chunk)))
349 349 fh.write(z.compress(changegroup.closechunk()))
350 350 fh.write(z.flush())
351 351 cleanup = None
352 352 return filename
353 353 finally:
354 354 if fh is not None:
355 355 fh.close()
356 356 if cleanup is not None:
357 357 os.unlink(cleanup)
358 358
359 359 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
360 360 changes=None, text=False, opts={}):
361 361 if not node1:
362 362 node1 = repo.dirstate.parents()[0]
363 363 # reading the data for node1 early allows it to play nicely
364 364 # with repo.changes and the revlog cache.
365 365 change = repo.changelog.read(node1)
366 366 mmap = repo.manifest.read(change[0])
367 367 date1 = util.datestr(change[2])
368 368
369 369 if not changes:
370 370 changes = repo.changes(node1, node2, files, match=match)
371 371 modified, added, removed, deleted, unknown = changes
372 372 if files:
373 373 modified, added, removed = map(lambda x: filterfiles(files, x),
374 374 (modified, added, removed))
375 375
376 376 if not modified and not added and not removed:
377 377 return
378 378
379 379 if node2:
380 380 change = repo.changelog.read(node2)
381 381 mmap2 = repo.manifest.read(change[0])
382 382 _date2 = util.datestr(change[2])
383 383 def date2(f):
384 384 return _date2
385 385 def read(f):
386 386 return repo.file(f).read(mmap2[f])
387 387 else:
388 388 tz = util.makedate()[1]
389 389 _date2 = util.datestr()
390 390 def date2(f):
391 391 try:
392 392 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
393 393 except OSError, err:
394 394 if err.errno != errno.ENOENT: raise
395 395 return _date2
396 396 def read(f):
397 397 return repo.wread(f)
398 398
399 399 if ui.quiet:
400 400 r = None
401 401 else:
402 402 hexfunc = ui.verbose and hex or short
403 403 r = [hexfunc(node) for node in [node1, node2] if node]
404 404
405 405 diffopts = ui.diffopts()
406 406 showfunc = opts.get('show_function') or diffopts['showfunc']
407 407 ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
408 408 ignorewsamount = opts.get('ignore_space_change') or \
409 409 diffopts['ignorewsamount']
410 410 ignoreblanklines = opts.get('ignore_blank_lines') or \
411 411 diffopts['ignoreblanklines']
412 412 for f in modified:
413 413 to = None
414 414 if f in mmap:
415 415 to = repo.file(f).read(mmap[f])
416 416 tn = read(f)
417 417 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
418 418 showfunc=showfunc, ignorews=ignorews,
419 419 ignorewsamount=ignorewsamount,
420 420 ignoreblanklines=ignoreblanklines))
421 421 for f in added:
422 422 to = None
423 423 tn = read(f)
424 424 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
425 425 showfunc=showfunc, ignorews=ignorews,
426 426 ignorewsamount=ignorewsamount,
427 427 ignoreblanklines=ignoreblanklines))
428 428 for f in removed:
429 429 to = repo.file(f).read(mmap[f])
430 430 tn = None
431 431 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
432 432 showfunc=showfunc, ignorews=ignorews,
433 433 ignorewsamount=ignorewsamount,
434 434 ignoreblanklines=ignoreblanklines))
435 435
436 436 def trimuser(ui, name, rev, revcache):
437 437 """trim the name of the user who committed a change"""
438 438 user = revcache.get(rev)
439 439 if user is None:
440 440 user = revcache[rev] = ui.shortuser(name)
441 441 return user
442 442
443 443 class changeset_printer(object):
444 444 '''show changeset information when templating not requested.'''
445 445
446 446 def __init__(self, ui, repo):
447 447 self.ui = ui
448 448 self.repo = repo
449 449
450 450 def show(self, rev=0, changenode=None, brinfo=None):
451 451 '''show a single changeset or file revision'''
452 452 log = self.repo.changelog
453 453 if changenode is None:
454 454 changenode = log.node(rev)
455 455 elif not rev:
456 456 rev = log.rev(changenode)
457 457
458 458 if self.ui.quiet:
459 459 self.ui.write("%d:%s\n" % (rev, short(changenode)))
460 460 return
461 461
462 462 changes = log.read(changenode)
463 463 date = util.datestr(changes[2])
464 464
465 465 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
466 466 for p in log.parents(changenode)
467 467 if self.ui.debugflag or p != nullid]
468 468 if (not self.ui.debugflag and len(parents) == 1 and
469 469 parents[0][0] == rev-1):
470 470 parents = []
471 471
472 472 if self.ui.verbose:
473 473 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
474 474 else:
475 475 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
476 476
477 477 for tag in self.repo.nodetags(changenode):
478 478 self.ui.status(_("tag: %s\n") % tag)
479 479 for parent in parents:
480 480 self.ui.write(_("parent: %d:%s\n") % parent)
481 481
482 482 if brinfo and changenode in brinfo:
483 483 br = brinfo[changenode]
484 484 self.ui.write(_("branch: %s\n") % " ".join(br))
485 485
486 486 self.ui.debug(_("manifest: %d:%s\n") %
487 487 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
488 488 self.ui.status(_("user: %s\n") % changes[1])
489 489 self.ui.status(_("date: %s\n") % date)
490 490
491 491 if self.ui.debugflag:
492 492 files = self.repo.changes(log.parents(changenode)[0], changenode)
493 493 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
494 494 files):
495 495 if value:
496 496 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
497 497 else:
498 498 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
499 499
500 500 description = changes[4].strip()
501 501 if description:
502 502 if self.ui.verbose:
503 503 self.ui.status(_("description:\n"))
504 504 self.ui.status(description)
505 505 self.ui.status("\n\n")
506 506 else:
507 507 self.ui.status(_("summary: %s\n") %
508 508 description.splitlines()[0])
509 509 self.ui.status("\n")
510 510
511 511 def show_changeset(ui, repo, opts):
512 512 '''show one changeset. uses template or regular display. caller
513 513 can pass in 'style' and 'template' options in opts.'''
514 514
515 515 tmpl = opts.get('template')
516 516 if tmpl:
517 517 tmpl = templater.parsestring(tmpl, quoted=False)
518 518 else:
519 519 tmpl = ui.config('ui', 'logtemplate')
520 520 if tmpl: tmpl = templater.parsestring(tmpl)
521 521 mapfile = opts.get('style') or ui.config('ui', 'style')
522 522 if tmpl or mapfile:
523 523 if mapfile:
524 524 if not os.path.isfile(mapfile):
525 525 mapname = templater.templatepath('map-cmdline.' + mapfile)
526 526 if not mapname: mapname = templater.templatepath(mapfile)
527 527 if mapname: mapfile = mapname
528 528 try:
529 529 t = templater.changeset_templater(ui, repo, mapfile)
530 530 except SyntaxError, inst:
531 531 raise util.Abort(inst.args[0])
532 532 if tmpl: t.use_template(tmpl)
533 533 return t
534 534 return changeset_printer(ui, repo)
535 535
536 536 def show_version(ui):
537 537 """output version and copyright information"""
538 538 ui.write(_("Mercurial Distributed SCM (version %s)\n")
539 539 % version.get_version())
540 540 ui.status(_(
541 541 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
542 542 "This is free software; see the source for copying conditions. "
543 543 "There is NO\nwarranty; "
544 544 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
545 545 ))
546 546
547 547 def help_(ui, name=None, with_version=False):
548 548 """show help for a command, extension, or list of commands
549 549
550 550 With no arguments, print a list of commands and short help.
551 551
552 552 Given a command name, print help for that command.
553 553
554 554 Given an extension name, print help for that extension, and the
555 555 commands it provides."""
556 556 option_lists = []
557 557
558 558 def helpcmd(name):
559 559 if with_version:
560 560 show_version(ui)
561 561 ui.write('\n')
562 562 aliases, i = findcmd(name)
563 563 # synopsis
564 564 ui.write("%s\n\n" % i[2])
565 565
566 566 # description
567 567 doc = i[0].__doc__
568 568 if not doc:
569 569 doc = _("(No help text available)")
570 570 if ui.quiet:
571 571 doc = doc.splitlines(0)[0]
572 572 ui.write("%s\n" % doc.rstrip())
573 573
574 574 if not ui.quiet:
575 575 # aliases
576 576 if len(aliases) > 1:
577 577 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
578 578
579 579 # options
580 580 if i[1]:
581 581 option_lists.append(("options", i[1]))
582 582
583 583 def helplist(select=None):
584 584 h = {}
585 585 cmds = {}
586 586 for c, e in table.items():
587 587 f = c.split("|", 1)[0]
588 588 if select and not select(f):
589 589 continue
590 590 if name == "shortlist" and not f.startswith("^"):
591 591 continue
592 592 f = f.lstrip("^")
593 593 if not ui.debugflag and f.startswith("debug"):
594 594 continue
595 595 doc = e[0].__doc__
596 596 if not doc:
597 597 doc = _("(No help text available)")
598 598 h[f] = doc.splitlines(0)[0].rstrip()
599 599 cmds[f] = c.lstrip("^")
600 600
601 601 fns = h.keys()
602 602 fns.sort()
603 603 m = max(map(len, fns))
604 604 for f in fns:
605 605 if ui.verbose:
606 606 commands = cmds[f].replace("|",", ")
607 607 ui.write(" %s:\n %s\n"%(commands, h[f]))
608 608 else:
609 609 ui.write(' %-*s %s\n' % (m, f, h[f]))
610 610
611 611 def helpext(name):
612 612 try:
613 613 mod = findext(name)
614 614 except KeyError:
615 615 raise UnknownCommand(name)
616 616
617 617 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
618 618 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
619 619 for d in doc[1:]:
620 620 ui.write(d, '\n')
621 621
622 622 ui.status('\n')
623 623 if ui.verbose:
624 624 ui.status(_('list of commands:\n\n'))
625 625 else:
626 626 ui.status(_('list of commands (use "hg help -v %s" '
627 627 'to show aliases and global options):\n\n') % name)
628 628
629 629 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
630 630 helplist(modcmds.has_key)
631 631
632 632 if name and name != 'shortlist':
633 633 try:
634 634 helpcmd(name)
635 635 except UnknownCommand:
636 636 helpext(name)
637 637
638 638 else:
639 639 # program name
640 640 if ui.verbose or with_version:
641 641 show_version(ui)
642 642 else:
643 643 ui.status(_("Mercurial Distributed SCM\n"))
644 644 ui.status('\n')
645 645
646 646 # list of commands
647 647 if name == "shortlist":
648 648 ui.status(_('basic commands (use "hg help" '
649 649 'for the full list or option "-v" for details):\n\n'))
650 650 elif ui.verbose:
651 651 ui.status(_('list of commands:\n\n'))
652 652 else:
653 653 ui.status(_('list of commands (use "hg help -v" '
654 654 'to show aliases and global options):\n\n'))
655 655
656 656 helplist()
657 657
658 658 # global options
659 659 if ui.verbose:
660 660 option_lists.append(("global options", globalopts))
661 661
662 662 # list all option lists
663 663 opt_output = []
664 664 for title, options in option_lists:
665 665 opt_output.append(("\n%s:\n" % title, None))
666 666 for shortopt, longopt, default, desc in options:
667 667 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
668 668 longopt and " --%s" % longopt),
669 669 "%s%s" % (desc,
670 670 default
671 671 and _(" (default: %s)") % default
672 672 or "")))
673 673
674 674 if opt_output:
675 675 opts_len = max([len(line[0]) for line in opt_output if line[1]])
676 676 for first, second in opt_output:
677 677 if second:
678 678 ui.write(" %-*s %s\n" % (opts_len, first, second))
679 679 else:
680 680 ui.write("%s\n" % first)
681 681
682 682 # Commands start here, listed alphabetically
683 683
684 684 def add(ui, repo, *pats, **opts):
685 685 """add the specified files on the next commit
686 686
687 687 Schedule files to be version controlled and added to the repository.
688 688
689 689 The files will be added to the repository at the next commit.
690 690
691 691 If no names are given, add all files in the repository.
692 692 """
693 693
694 694 names = []
695 695 for src, abs, rel, exact in walk(repo, pats, opts):
696 696 if exact:
697 697 if ui.verbose:
698 698 ui.status(_('adding %s\n') % rel)
699 699 names.append(abs)
700 700 elif repo.dirstate.state(abs) == '?':
701 701 ui.status(_('adding %s\n') % rel)
702 702 names.append(abs)
703 703 if not opts.get('dry_run'):
704 704 repo.add(names)
705 705
706 706 def addremove(ui, repo, *pats, **opts):
707 707 """add all new files, delete all missing files (DEPRECATED)
708 708
709 709 (DEPRECATED)
710 710 Add all new files and remove all missing files from the repository.
711 711
712 712 New files are ignored if they match any of the patterns in .hgignore. As
713 713 with add, these changes take effect at the next commit.
714 714
715 715 This command is now deprecated and will be removed in a future
716 716 release. Please use add and remove --after instead.
717 717 """
718 718 ui.warn(_('(the addremove command is deprecated; use add and remove '
719 719 '--after instead)\n'))
720 720 return addremove_lock(ui, repo, pats, opts)
721 721
722 722 def addremove_lock(ui, repo, pats, opts, wlock=None):
723 723 add, remove = [], []
724 724 for src, abs, rel, exact in walk(repo, pats, opts):
725 725 if src == 'f' and repo.dirstate.state(abs) == '?':
726 726 add.append(abs)
727 727 if ui.verbose or not exact:
728 728 ui.status(_('adding %s\n') % ((pats and rel) or abs))
729 729 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
730 730 remove.append(abs)
731 731 if ui.verbose or not exact:
732 732 ui.status(_('removing %s\n') % ((pats and rel) or abs))
733 733 if not opts.get('dry_run'):
734 734 repo.add(add, wlock=wlock)
735 735 repo.remove(remove, wlock=wlock)
736 736
737 737 def annotate(ui, repo, *pats, **opts):
738 738 """show changeset information per file line
739 739
740 740 List changes in files, showing the revision id responsible for each line
741 741
742 742 This command is useful to discover who did a change or when a change took
743 743 place.
744 744
745 745 Without the -a option, annotate will avoid processing files it
746 746 detects as binary. With -a, annotate will generate an annotation
747 747 anyway, probably with undesirable results.
748 748 """
749 749 def getnode(rev):
750 750 return short(repo.changelog.node(rev))
751 751
752 752 ucache = {}
753 753 def getname(rev):
754 754 try:
755 755 return ucache[rev]
756 756 except:
757 757 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
758 758 ucache[rev] = u
759 759 return u
760 760
761 761 dcache = {}
762 762 def getdate(rev):
763 763 datestr = dcache.get(rev)
764 764 if datestr is None:
765 765 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
766 766 return datestr
767 767
768 768 if not pats:
769 769 raise util.Abort(_('at least one file name or pattern required'))
770 770
771 771 opmap = [['user', getname], ['number', str], ['changeset', getnode],
772 772 ['date', getdate]]
773 773 if not opts['user'] and not opts['changeset'] and not opts['date']:
774 774 opts['number'] = 1
775 775
776 776 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
777 777
778 778 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
779 779 fctx = ctx.filectx(abs)
780 780 if not opts['text'] and util.binary(fctx.data()):
781 781 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
782 782 continue
783 783
784 784 lines = fctx.annotate()
785 785 pieces = []
786 786
787 787 for o, f in opmap:
788 788 if opts[o]:
789 789 l = [f(n) for n, dummy in lines]
790 790 if l:
791 791 m = max(map(len, l))
792 792 pieces.append(["%*s" % (m, x) for x in l])
793 793
794 794 if pieces:
795 795 for p, l in zip(zip(*pieces), lines):
796 796 ui.write("%s: %s" % (" ".join(p), l[1]))
797 797
798 798 def archive(ui, repo, dest, **opts):
799 799 '''create unversioned archive of a repository revision
800 800
801 801 By default, the revision used is the parent of the working
802 802 directory; use "-r" to specify a different revision.
803 803
804 804 To specify the type of archive to create, use "-t". Valid
805 805 types are:
806 806
807 807 "files" (default): a directory full of files
808 808 "tar": tar archive, uncompressed
809 809 "tbz2": tar archive, compressed using bzip2
810 810 "tgz": tar archive, compressed using gzip
811 811 "uzip": zip archive, uncompressed
812 812 "zip": zip archive, compressed using deflate
813 813
814 814 The exact name of the destination archive or directory is given
815 815 using a format string; see "hg help export" for details.
816 816
817 817 Each member added to an archive file has a directory prefix
818 818 prepended. Use "-p" to specify a format string for the prefix.
819 819 The default is the basename of the archive, with suffixes removed.
820 820 '''
821 821
822 822 if opts['rev']:
823 823 node = repo.lookup(opts['rev'])
824 824 else:
825 825 node, p2 = repo.dirstate.parents()
826 826 if p2 != nullid:
827 827 raise util.Abort(_('uncommitted merge - please provide a '
828 828 'specific revision'))
829 829
830 830 dest = make_filename(repo, dest, node)
831 831 if os.path.realpath(dest) == repo.root:
832 832 raise util.Abort(_('repository root cannot be destination'))
833 833 dummy, matchfn, dummy = matchpats(repo, [], opts)
834 834 kind = opts.get('type') or 'files'
835 835 prefix = opts['prefix']
836 836 if dest == '-':
837 837 if kind == 'files':
838 838 raise util.Abort(_('cannot archive plain files to stdout'))
839 839 dest = sys.stdout
840 840 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
841 841 prefix = make_filename(repo, prefix, node)
842 842 archival.archive(repo, dest, node, kind, not opts['no_decode'],
843 843 matchfn, prefix)
844 844
845 845 def backout(ui, repo, rev, **opts):
846 846 '''reverse effect of earlier changeset
847 847
848 848 Commit the backed out changes as a new changeset. The new
849 849 changeset is a child of the backed out changeset.
850 850
851 851 If you back out a changeset other than the tip, a new head is
852 852 created. This head is the parent of the working directory. If
853 853 you back out an old changeset, your working directory will appear
854 854 old after the backout. You should merge the backout changeset
855 855 with another head.
856 856
857 857 The --merge option remembers the parent of the working directory
858 858 before starting the backout, then merges the new head with that
859 859 changeset afterwards. This saves you from doing the merge by
860 860 hand. The result of this merge is not committed, as for a normal
861 861 merge.'''
862 862
863 863 bail_if_changed(repo)
864 864 op1, op2 = repo.dirstate.parents()
865 865 if op2 != nullid:
866 866 raise util.Abort(_('outstanding uncommitted merge'))
867 867 node = repo.lookup(rev)
868 868 parent, p2 = repo.changelog.parents(node)
869 869 if parent == nullid:
870 870 raise util.Abort(_('cannot back out a change with no parents'))
871 871 if p2 != nullid:
872 872 raise util.Abort(_('cannot back out a merge'))
873 873 repo.update(node, force=True, show_stats=False)
874 874 revert_opts = opts.copy()
875 875 revert_opts['rev'] = hex(parent)
876 876 revert(ui, repo, **revert_opts)
877 877 commit_opts = opts.copy()
878 878 commit_opts['addremove'] = False
879 879 if not commit_opts['message'] and not commit_opts['logfile']:
880 880 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
881 881 commit_opts['force_editor'] = True
882 882 commit(ui, repo, **commit_opts)
883 883 def nice(node):
884 884 return '%d:%s' % (repo.changelog.rev(node), short(node))
885 885 ui.status(_('changeset %s backs out changeset %s\n') %
886 886 (nice(repo.changelog.tip()), nice(node)))
887 887 if op1 != node:
888 888 if opts['merge']:
889 889 ui.status(_('merging with changeset %s\n') % nice(op1))
890 890 doupdate(ui, repo, hex(op1), **opts)
891 891 else:
892 892 ui.status(_('the backout changeset is a new head - '
893 893 'do not forget to merge\n'))
894 894 ui.status(_('(use "backout -m" if you want to auto-merge)\n'))
895 895
896 896 def bundle(ui, repo, fname, dest=None, **opts):
897 897 """create a changegroup file
898 898
899 899 Generate a compressed changegroup file collecting all changesets
900 900 not found in the other repository.
901 901
902 902 This file can then be transferred using conventional means and
903 903 applied to another repository with the unbundle command. This is
904 904 useful when native push and pull are not available or when
905 905 exporting an entire repository is undesirable. The standard file
906 906 extension is ".hg".
907 907
908 908 Unlike import/export, this exactly preserves all changeset
909 909 contents including permissions, rename data, and revision history.
910 910 """
911 911 dest = ui.expandpath(dest or 'default-push', dest or 'default')
912 912 other = hg.repository(ui, dest)
913 913 o = repo.findoutgoing(other, force=opts['force'])
914 914 cg = repo.changegroup(o, 'bundle')
915 915 write_bundle(cg, fname)
916 916
917 917 def cat(ui, repo, file1, *pats, **opts):
918 918 """output the latest or given revisions of files
919 919
920 920 Print the specified files as they were at the given revision.
921 921 If no revision is given then the tip is used.
922 922
923 923 Output may be to a file, in which case the name of the file is
924 924 given using a format string. The formatting rules are the same as
925 925 for the export command, with the following additions:
926 926
927 927 %s basename of file being printed
928 928 %d dirname of file being printed, or '.' if in repo root
929 929 %p root-relative path name of file being printed
930 930 """
931 931 ctx = repo.changectx(opts['rev'] or -1)
932 932 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
933 933 fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
934 934 fp.write(ctx.filectx(abs).data())
935 935
936 936 def clone(ui, source, dest=None, **opts):
937 937 """make a copy of an existing repository
938 938
939 939 Create a copy of an existing repository in a new directory.
940 940
941 941 If no destination directory name is specified, it defaults to the
942 942 basename of the source.
943 943
944 944 The location of the source is added to the new repository's
945 945 .hg/hgrc file, as the default to be used for future pulls.
946 946
947 947 For efficiency, hardlinks are used for cloning whenever the source
948 948 and destination are on the same filesystem. Some filesystems,
949 949 such as AFS, implement hardlinking incorrectly, but do not report
950 950 errors. In these cases, use the --pull option to avoid
951 951 hardlinking.
952 952
953 953 See pull for valid source format details.
954 954
955 955 It is possible to specify an ssh:// URL as the destination, but no
956 956 .hg/hgrc will be created on the remote side. Look at the help text
957 957 for the pull command for important details about ssh:// URLs.
958 958 """
959 if dest is None:
960 dest = os.path.basename(os.path.normpath(source))
961
962 if os.path.exists(dest):
963 raise util.Abort(_("destination '%s' already exists"), dest)
964
965 class Dircleanup(object):
966 def __init__(self, dir_):
967 self.rmtree = shutil.rmtree
968 self.dir_ = dir_
969 def close(self):
970 self.dir_ = None
971 def __del__(self):
972 if self.dir_:
973 self.rmtree(self.dir_, True)
974
975 959 if opts['ssh']:
976 960 ui.setconfig("ui", "ssh", opts['ssh'])
977 961 if opts['remotecmd']:
978 962 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
979 963
980 source = ui.expandpath(source)
981 src_repo = hg.repository(ui, source)
982
983 dest_repo = None
984 try:
985 dest_repo = hg.repository(ui, dest)
986 raise util.Abort(_("destination '%s' already exists." % dest))
987 except hg.RepoError:
988 dest_repo = hg.repository(ui, dest, create=1)
989
990 dest_path = None
991 d = None
992 if dest_repo.local():
993 dest_path = os.path.realpath(dest)
994 d = Dircleanup(dest_path)
995
996 abspath = source
997 copy = False
998 if src_repo.local() and dest_repo.local():
999 abspath = os.path.abspath(source)
1000 if not opts['pull'] and not opts['rev']:
1001 copy = True
1002
1003 if copy:
1004 try:
1005 # we use a lock here because if we race with commit, we
1006 # can end up with extra data in the cloned revlogs that's
1007 # not pointed to by changesets, thus causing verify to
1008 # fail
1009 l1 = src_repo.lock()
1010 except lock.LockException:
1011 copy = False
1012
1013 if copy:
1014 # we lock here to avoid premature writing to the target
1015 l2 = lock.lock(os.path.join(dest_path, ".hg", "lock"))
1016
1017 # we need to remove the (empty) data dir in dest so copyfiles can do it's work
1018 os.rmdir( os.path.join(dest_path, ".hg", "data") )
1019 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
1020 for f in files.split():
1021 src = os.path.join(source, ".hg", f)
1022 dst = os.path.join(dest_path, ".hg", f)
1023 try:
1024 util.copyfiles(src, dst)
1025 except OSError, inst:
1026 if inst.errno != errno.ENOENT:
1027 raise
1028
1029 # we need to re-init the repo after manually copying the data into it
1030 dest_repo = hg.repository(ui, dest)
1031
1032 else:
1033 revs = None
1034 if opts['rev']:
1035 if not src_repo.local():
1036 error = _("clone -r not supported yet for remote repositories.")
1037 raise util.Abort(error)
1038 else:
1039 revs = [src_repo.lookup(rev) for rev in opts['rev']]
1040
1041 if dest_repo.local():
1042 dest_repo.pull(src_repo, heads = revs)
1043 elif src_repo.local():
1044 src_repo.push(dest_repo, revs = revs)
1045 else:
1046 error = _("clone from remote to remote not supported.")
1047 raise util.Abort(error)
1048
1049 if dest_repo.local():
1050 f = dest_repo.opener("hgrc", "w", text=True)
1051 f.write("[paths]\n")
1052 f.write("default = %s\n" % abspath)
1053 f.close()
1054
1055 if not opts['noupdate']:
1056 doupdate(dest_repo.ui, dest_repo)
1057
1058 if d:
1059 d.close()
964 hg.clone(ui, ui.expandpath(source), dest,
965 pull=opts['pull'],
966 rev=opts['rev'],
967 update=not opts['noupdate'])
1060 968
1061 969 def commit(ui, repo, *pats, **opts):
1062 970 """commit the specified files or all outstanding changes
1063 971
1064 972 Commit changes to the given files into the repository.
1065 973
1066 974 If a list of files is omitted, all changes reported by "hg status"
1067 975 will be committed.
1068 976
1069 977 If no commit message is specified, the editor configured in your hgrc
1070 978 or in the EDITOR environment variable is started to enter a message.
1071 979 """
1072 980 message = opts['message']
1073 981 logfile = opts['logfile']
1074 982
1075 983 if message and logfile:
1076 984 raise util.Abort(_('options --message and --logfile are mutually '
1077 985 'exclusive'))
1078 986 if not message and logfile:
1079 987 try:
1080 988 if logfile == '-':
1081 989 message = sys.stdin.read()
1082 990 else:
1083 991 message = open(logfile).read()
1084 992 except IOError, inst:
1085 993 raise util.Abort(_("can't read commit message '%s': %s") %
1086 994 (logfile, inst.strerror))
1087 995
1088 996 if opts['addremove']:
1089 997 addremove_lock(ui, repo, pats, opts)
1090 998 fns, match, anypats = matchpats(repo, pats, opts)
1091 999 if pats:
1092 1000 modified, added, removed, deleted, unknown = (
1093 1001 repo.changes(files=fns, match=match))
1094 1002 files = modified + added + removed
1095 1003 else:
1096 1004 files = []
1097 1005 try:
1098 1006 repo.commit(files, message, opts['user'], opts['date'], match,
1099 1007 force_editor=opts.get('force_editor'))
1100 1008 except ValueError, inst:
1101 1009 raise util.Abort(str(inst))
1102 1010
1103 1011 def docopy(ui, repo, pats, opts, wlock):
1104 1012 # called with the repo lock held
1105 1013 cwd = repo.getcwd()
1106 1014 errors = 0
1107 1015 copied = []
1108 1016 targets = {}
1109 1017
1110 1018 def okaytocopy(abs, rel, exact):
1111 1019 reasons = {'?': _('is not managed'),
1112 1020 'a': _('has been marked for add'),
1113 1021 'r': _('has been marked for remove')}
1114 1022 state = repo.dirstate.state(abs)
1115 1023 reason = reasons.get(state)
1116 1024 if reason:
1117 1025 if state == 'a':
1118 1026 origsrc = repo.dirstate.copied(abs)
1119 1027 if origsrc is not None:
1120 1028 return origsrc
1121 1029 if exact:
1122 1030 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
1123 1031 else:
1124 1032 return abs
1125 1033
1126 1034 def copy(origsrc, abssrc, relsrc, target, exact):
1127 1035 abstarget = util.canonpath(repo.root, cwd, target)
1128 1036 reltarget = util.pathto(cwd, abstarget)
1129 1037 prevsrc = targets.get(abstarget)
1130 1038 if prevsrc is not None:
1131 1039 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1132 1040 (reltarget, abssrc, prevsrc))
1133 1041 return
1134 1042 if (not opts['after'] and os.path.exists(reltarget) or
1135 1043 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
1136 1044 if not opts['force']:
1137 1045 ui.warn(_('%s: not overwriting - file exists\n') %
1138 1046 reltarget)
1139 1047 return
1140 1048 if not opts['after'] and not opts.get('dry_run'):
1141 1049 os.unlink(reltarget)
1142 1050 if opts['after']:
1143 1051 if not os.path.exists(reltarget):
1144 1052 return
1145 1053 else:
1146 1054 targetdir = os.path.dirname(reltarget) or '.'
1147 1055 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1148 1056 os.makedirs(targetdir)
1149 1057 try:
1150 1058 restore = repo.dirstate.state(abstarget) == 'r'
1151 1059 if restore and not opts.get('dry_run'):
1152 1060 repo.undelete([abstarget], wlock)
1153 1061 try:
1154 1062 if not opts.get('dry_run'):
1155 1063 shutil.copyfile(relsrc, reltarget)
1156 1064 shutil.copymode(relsrc, reltarget)
1157 1065 restore = False
1158 1066 finally:
1159 1067 if restore:
1160 1068 repo.remove([abstarget], wlock)
1161 1069 except shutil.Error, inst:
1162 1070 raise util.Abort(str(inst))
1163 1071 except IOError, inst:
1164 1072 if inst.errno == errno.ENOENT:
1165 1073 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1166 1074 else:
1167 1075 ui.warn(_('%s: cannot copy - %s\n') %
1168 1076 (relsrc, inst.strerror))
1169 1077 errors += 1
1170 1078 return
1171 1079 if ui.verbose or not exact:
1172 1080 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1173 1081 targets[abstarget] = abssrc
1174 1082 if abstarget != origsrc and not opts.get('dry_run'):
1175 1083 repo.copy(origsrc, abstarget, wlock)
1176 1084 copied.append((abssrc, relsrc, exact))
1177 1085
1178 1086 def targetpathfn(pat, dest, srcs):
1179 1087 if os.path.isdir(pat):
1180 1088 abspfx = util.canonpath(repo.root, cwd, pat)
1181 1089 if destdirexists:
1182 1090 striplen = len(os.path.split(abspfx)[0])
1183 1091 else:
1184 1092 striplen = len(abspfx)
1185 1093 if striplen:
1186 1094 striplen += len(os.sep)
1187 1095 res = lambda p: os.path.join(dest, p[striplen:])
1188 1096 elif destdirexists:
1189 1097 res = lambda p: os.path.join(dest, os.path.basename(p))
1190 1098 else:
1191 1099 res = lambda p: dest
1192 1100 return res
1193 1101
1194 1102 def targetpathafterfn(pat, dest, srcs):
1195 1103 if util.patkind(pat, None)[0]:
1196 1104 # a mercurial pattern
1197 1105 res = lambda p: os.path.join(dest, os.path.basename(p))
1198 1106 else:
1199 1107 abspfx = util.canonpath(repo.root, cwd, pat)
1200 1108 if len(abspfx) < len(srcs[0][0]):
1201 1109 # A directory. Either the target path contains the last
1202 1110 # component of the source path or it does not.
1203 1111 def evalpath(striplen):
1204 1112 score = 0
1205 1113 for s in srcs:
1206 1114 t = os.path.join(dest, s[0][striplen:])
1207 1115 if os.path.exists(t):
1208 1116 score += 1
1209 1117 return score
1210 1118
1211 1119 striplen = len(abspfx)
1212 1120 if striplen:
1213 1121 striplen += len(os.sep)
1214 1122 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1215 1123 score = evalpath(striplen)
1216 1124 striplen1 = len(os.path.split(abspfx)[0])
1217 1125 if striplen1:
1218 1126 striplen1 += len(os.sep)
1219 1127 if evalpath(striplen1) > score:
1220 1128 striplen = striplen1
1221 1129 res = lambda p: os.path.join(dest, p[striplen:])
1222 1130 else:
1223 1131 # a file
1224 1132 if destdirexists:
1225 1133 res = lambda p: os.path.join(dest, os.path.basename(p))
1226 1134 else:
1227 1135 res = lambda p: dest
1228 1136 return res
1229 1137
1230 1138
1231 1139 pats = list(pats)
1232 1140 if not pats:
1233 1141 raise util.Abort(_('no source or destination specified'))
1234 1142 if len(pats) == 1:
1235 1143 raise util.Abort(_('no destination specified'))
1236 1144 dest = pats.pop()
1237 1145 destdirexists = os.path.isdir(dest)
1238 1146 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1239 1147 raise util.Abort(_('with multiple sources, destination must be an '
1240 1148 'existing directory'))
1241 1149 if opts['after']:
1242 1150 tfn = targetpathafterfn
1243 1151 else:
1244 1152 tfn = targetpathfn
1245 1153 copylist = []
1246 1154 for pat in pats:
1247 1155 srcs = []
1248 1156 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1249 1157 origsrc = okaytocopy(abssrc, relsrc, exact)
1250 1158 if origsrc:
1251 1159 srcs.append((origsrc, abssrc, relsrc, exact))
1252 1160 if not srcs:
1253 1161 continue
1254 1162 copylist.append((tfn(pat, dest, srcs), srcs))
1255 1163 if not copylist:
1256 1164 raise util.Abort(_('no files to copy'))
1257 1165
1258 1166 for targetpath, srcs in copylist:
1259 1167 for origsrc, abssrc, relsrc, exact in srcs:
1260 1168 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1261 1169
1262 1170 if errors:
1263 1171 ui.warn(_('(consider using --after)\n'))
1264 1172 return errors, copied
1265 1173
1266 1174 def copy(ui, repo, *pats, **opts):
1267 1175 """mark files as copied for the next commit
1268 1176
1269 1177 Mark dest as having copies of source files. If dest is a
1270 1178 directory, copies are put in that directory. If dest is a file,
1271 1179 there can only be one source.
1272 1180
1273 1181 By default, this command copies the contents of files as they
1274 1182 stand in the working directory. If invoked with --after, the
1275 1183 operation is recorded, but no copying is performed.
1276 1184
1277 1185 This command takes effect in the next commit.
1278 1186
1279 1187 NOTE: This command should be treated as experimental. While it
1280 1188 should properly record copied files, this information is not yet
1281 1189 fully used by merge, nor fully reported by log.
1282 1190 """
1283 1191 wlock = repo.wlock(0)
1284 1192 errs, copied = docopy(ui, repo, pats, opts, wlock)
1285 1193 return errs
1286 1194
1287 1195 def debugancestor(ui, index, rev1, rev2):
1288 1196 """find the ancestor revision of two revisions in a given index"""
1289 1197 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1290 1198 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1291 1199 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1292 1200
1293 1201 def debugcomplete(ui, cmd='', **opts):
1294 1202 """returns the completion list associated with the given command"""
1295 1203
1296 1204 if opts['options']:
1297 1205 options = []
1298 1206 otables = [globalopts]
1299 1207 if cmd:
1300 1208 aliases, entry = findcmd(cmd)
1301 1209 otables.append(entry[1])
1302 1210 for t in otables:
1303 1211 for o in t:
1304 1212 if o[0]:
1305 1213 options.append('-%s' % o[0])
1306 1214 options.append('--%s' % o[1])
1307 1215 ui.write("%s\n" % "\n".join(options))
1308 1216 return
1309 1217
1310 1218 clist = findpossible(cmd).keys()
1311 1219 clist.sort()
1312 1220 ui.write("%s\n" % "\n".join(clist))
1313 1221
1314 1222 def debugrebuildstate(ui, repo, rev=None):
1315 1223 """rebuild the dirstate as it would look like for the given revision"""
1316 1224 if not rev:
1317 1225 rev = repo.changelog.tip()
1318 1226 else:
1319 1227 rev = repo.lookup(rev)
1320 1228 change = repo.changelog.read(rev)
1321 1229 n = change[0]
1322 1230 files = repo.manifest.readflags(n)
1323 1231 wlock = repo.wlock()
1324 1232 repo.dirstate.rebuild(rev, files.iteritems())
1325 1233
1326 1234 def debugcheckstate(ui, repo):
1327 1235 """validate the correctness of the current dirstate"""
1328 1236 parent1, parent2 = repo.dirstate.parents()
1329 1237 repo.dirstate.read()
1330 1238 dc = repo.dirstate.map
1331 1239 keys = dc.keys()
1332 1240 keys.sort()
1333 1241 m1n = repo.changelog.read(parent1)[0]
1334 1242 m2n = repo.changelog.read(parent2)[0]
1335 1243 m1 = repo.manifest.read(m1n)
1336 1244 m2 = repo.manifest.read(m2n)
1337 1245 errors = 0
1338 1246 for f in dc:
1339 1247 state = repo.dirstate.state(f)
1340 1248 if state in "nr" and f not in m1:
1341 1249 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1342 1250 errors += 1
1343 1251 if state in "a" and f in m1:
1344 1252 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1345 1253 errors += 1
1346 1254 if state in "m" and f not in m1 and f not in m2:
1347 1255 ui.warn(_("%s in state %s, but not in either manifest\n") %
1348 1256 (f, state))
1349 1257 errors += 1
1350 1258 for f in m1:
1351 1259 state = repo.dirstate.state(f)
1352 1260 if state not in "nrm":
1353 1261 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1354 1262 errors += 1
1355 1263 if errors:
1356 1264 error = _(".hg/dirstate inconsistent with current parent's manifest")
1357 1265 raise util.Abort(error)
1358 1266
1359 1267 def debugconfig(ui, repo, *values):
1360 1268 """show combined config settings from all hgrc files
1361 1269
1362 1270 With no args, print names and values of all config items.
1363 1271
1364 1272 With one arg of the form section.name, print just the value of
1365 1273 that config item.
1366 1274
1367 1275 With multiple args, print names and values of all config items
1368 1276 with matching section names."""
1369 1277
1370 1278 if values:
1371 1279 if len([v for v in values if '.' in v]) > 1:
1372 1280 raise util.Abort(_('only one config item permitted'))
1373 1281 for section, name, value in ui.walkconfig():
1374 1282 sectname = section + '.' + name
1375 1283 if values:
1376 1284 for v in values:
1377 1285 if v == section:
1378 1286 ui.write('%s=%s\n' % (sectname, value))
1379 1287 elif v == sectname:
1380 1288 ui.write(value, '\n')
1381 1289 else:
1382 1290 ui.write('%s=%s\n' % (sectname, value))
1383 1291
1384 1292 def debugsetparents(ui, repo, rev1, rev2=None):
1385 1293 """manually set the parents of the current working directory
1386 1294
1387 1295 This is useful for writing repository conversion tools, but should
1388 1296 be used with care.
1389 1297 """
1390 1298
1391 1299 if not rev2:
1392 1300 rev2 = hex(nullid)
1393 1301
1394 1302 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1395 1303
1396 1304 def debugstate(ui, repo):
1397 1305 """show the contents of the current dirstate"""
1398 1306 repo.dirstate.read()
1399 1307 dc = repo.dirstate.map
1400 1308 keys = dc.keys()
1401 1309 keys.sort()
1402 1310 for file_ in keys:
1403 1311 ui.write("%c %3o %10d %s %s\n"
1404 1312 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1405 1313 time.strftime("%x %X",
1406 1314 time.localtime(dc[file_][3])), file_))
1407 1315 for f in repo.dirstate.copies:
1408 1316 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1409 1317
1410 1318 def debugdata(ui, file_, rev):
1411 1319 """dump the contents of an data file revision"""
1412 1320 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1413 1321 file_[:-2] + ".i", file_, 0)
1414 1322 try:
1415 1323 ui.write(r.revision(r.lookup(rev)))
1416 1324 except KeyError:
1417 1325 raise util.Abort(_('invalid revision identifier %s'), rev)
1418 1326
1419 1327 def debugindex(ui, file_):
1420 1328 """dump the contents of an index file"""
1421 1329 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1422 1330 ui.write(" rev offset length base linkrev" +
1423 1331 " nodeid p1 p2\n")
1424 1332 for i in range(r.count()):
1425 1333 node = r.node(i)
1426 1334 pp = r.parents(node)
1427 1335 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1428 1336 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1429 1337 short(node), short(pp[0]), short(pp[1])))
1430 1338
1431 1339 def debugindexdot(ui, file_):
1432 1340 """dump an index DAG as a .dot file"""
1433 1341 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1434 1342 ui.write("digraph G {\n")
1435 1343 for i in range(r.count()):
1436 1344 node = r.node(i)
1437 1345 pp = r.parents(node)
1438 1346 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1439 1347 if pp[1] != nullid:
1440 1348 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1441 1349 ui.write("}\n")
1442 1350
1443 1351 def debugrename(ui, repo, file, rev=None):
1444 1352 """dump rename information"""
1445 1353 r = repo.file(relpath(repo, [file])[0])
1446 1354 if rev:
1447 1355 try:
1448 1356 # assume all revision numbers are for changesets
1449 1357 n = repo.lookup(rev)
1450 1358 change = repo.changelog.read(n)
1451 1359 m = repo.manifest.read(change[0])
1452 1360 n = m[relpath(repo, [file])[0]]
1453 1361 except (hg.RepoError, KeyError):
1454 1362 n = r.lookup(rev)
1455 1363 else:
1456 1364 n = r.tip()
1457 1365 m = r.renamed(n)
1458 1366 if m:
1459 1367 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1460 1368 else:
1461 1369 ui.write(_("not renamed\n"))
1462 1370
1463 1371 def debugwalk(ui, repo, *pats, **opts):
1464 1372 """show how files match on given patterns"""
1465 1373 items = list(walk(repo, pats, opts))
1466 1374 if not items:
1467 1375 return
1468 1376 fmt = '%%s %%-%ds %%-%ds %%s' % (
1469 1377 max([len(abs) for (src, abs, rel, exact) in items]),
1470 1378 max([len(rel) for (src, abs, rel, exact) in items]))
1471 1379 for src, abs, rel, exact in items:
1472 1380 line = fmt % (src, abs, rel, exact and 'exact' or '')
1473 1381 ui.write("%s\n" % line.rstrip())
1474 1382
1475 1383 def diff(ui, repo, *pats, **opts):
1476 1384 """diff repository (or selected files)
1477 1385
1478 1386 Show differences between revisions for the specified files.
1479 1387
1480 1388 Differences between files are shown using the unified diff format.
1481 1389
1482 1390 When two revision arguments are given, then changes are shown
1483 1391 between those revisions. If only one revision is specified then
1484 1392 that revision is compared to the working directory, and, when no
1485 1393 revisions are specified, the working directory files are compared
1486 1394 to its parent.
1487 1395
1488 1396 Without the -a option, diff will avoid generating diffs of files
1489 1397 it detects as binary. With -a, diff will generate a diff anyway,
1490 1398 probably with undesirable results.
1491 1399 """
1492 1400 node1, node2 = revpair(ui, repo, opts['rev'])
1493 1401
1494 1402 fns, matchfn, anypats = matchpats(repo, pats, opts)
1495 1403
1496 1404 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1497 1405 text=opts['text'], opts=opts)
1498 1406
1499 1407 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1500 1408 node = repo.lookup(changeset)
1501 1409 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1502 1410 if opts['switch_parent']:
1503 1411 parents.reverse()
1504 1412 prev = (parents and parents[0]) or nullid
1505 1413 change = repo.changelog.read(node)
1506 1414
1507 1415 fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
1508 1416 revwidth=revwidth)
1509 1417 if fp != sys.stdout:
1510 1418 ui.note("%s\n" % fp.name)
1511 1419
1512 1420 fp.write("# HG changeset patch\n")
1513 1421 fp.write("# User %s\n" % change[1])
1514 1422 fp.write("# Date %d %d\n" % change[2])
1515 1423 fp.write("# Node ID %s\n" % hex(node))
1516 1424 fp.write("# Parent %s\n" % hex(prev))
1517 1425 if len(parents) > 1:
1518 1426 fp.write("# Parent %s\n" % hex(parents[1]))
1519 1427 fp.write(change[4].rstrip())
1520 1428 fp.write("\n\n")
1521 1429
1522 1430 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1523 1431 if fp != sys.stdout:
1524 1432 fp.close()
1525 1433
1526 1434 def export(ui, repo, *changesets, **opts):
1527 1435 """dump the header and diffs for one or more changesets
1528 1436
1529 1437 Print the changeset header and diffs for one or more revisions.
1530 1438
1531 1439 The information shown in the changeset header is: author,
1532 1440 changeset hash, parent and commit comment.
1533 1441
1534 1442 Output may be to a file, in which case the name of the file is
1535 1443 given using a format string. The formatting rules are as follows:
1536 1444
1537 1445 %% literal "%" character
1538 1446 %H changeset hash (40 bytes of hexadecimal)
1539 1447 %N number of patches being generated
1540 1448 %R changeset revision number
1541 1449 %b basename of the exporting repository
1542 1450 %h short-form changeset hash (12 bytes of hexadecimal)
1543 1451 %n zero-padded sequence number, starting at 1
1544 1452 %r zero-padded changeset revision number
1545 1453
1546 1454 Without the -a option, export will avoid generating diffs of files
1547 1455 it detects as binary. With -a, export will generate a diff anyway,
1548 1456 probably with undesirable results.
1549 1457
1550 1458 With the --switch-parent option, the diff will be against the second
1551 1459 parent. It can be useful to review a merge.
1552 1460 """
1553 1461 if not changesets:
1554 1462 raise util.Abort(_("export requires at least one changeset"))
1555 1463 seqno = 0
1556 1464 revs = list(revrange(ui, repo, changesets))
1557 1465 total = len(revs)
1558 1466 revwidth = max(map(len, revs))
1559 1467 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1560 1468 ui.note(msg)
1561 1469 for cset in revs:
1562 1470 seqno += 1
1563 1471 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1564 1472
1565 1473 def forget(ui, repo, *pats, **opts):
1566 1474 """don't add the specified files on the next commit (DEPRECATED)
1567 1475
1568 1476 (DEPRECATED)
1569 1477 Undo an 'hg add' scheduled for the next commit.
1570 1478
1571 1479 This command is now deprecated and will be removed in a future
1572 1480 release. Please use revert instead.
1573 1481 """
1574 1482 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1575 1483 forget = []
1576 1484 for src, abs, rel, exact in walk(repo, pats, opts):
1577 1485 if repo.dirstate.state(abs) == 'a':
1578 1486 forget.append(abs)
1579 1487 if ui.verbose or not exact:
1580 1488 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1581 1489 repo.forget(forget)
1582 1490
1583 1491 def grep(ui, repo, pattern, *pats, **opts):
1584 1492 """search for a pattern in specified files and revisions
1585 1493
1586 1494 Search revisions of files for a regular expression.
1587 1495
1588 1496 This command behaves differently than Unix grep. It only accepts
1589 1497 Python/Perl regexps. It searches repository history, not the
1590 1498 working directory. It always prints the revision number in which
1591 1499 a match appears.
1592 1500
1593 1501 By default, grep only prints output for the first revision of a
1594 1502 file in which it finds a match. To get it to print every revision
1595 1503 that contains a change in match status ("-" for a match that
1596 1504 becomes a non-match, or "+" for a non-match that becomes a match),
1597 1505 use the --all flag.
1598 1506 """
1599 1507 reflags = 0
1600 1508 if opts['ignore_case']:
1601 1509 reflags |= re.I
1602 1510 regexp = re.compile(pattern, reflags)
1603 1511 sep, eol = ':', '\n'
1604 1512 if opts['print0']:
1605 1513 sep = eol = '\0'
1606 1514
1607 1515 fcache = {}
1608 1516 def getfile(fn):
1609 1517 if fn not in fcache:
1610 1518 fcache[fn] = repo.file(fn)
1611 1519 return fcache[fn]
1612 1520
1613 1521 def matchlines(body):
1614 1522 begin = 0
1615 1523 linenum = 0
1616 1524 while True:
1617 1525 match = regexp.search(body, begin)
1618 1526 if not match:
1619 1527 break
1620 1528 mstart, mend = match.span()
1621 1529 linenum += body.count('\n', begin, mstart) + 1
1622 1530 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1623 1531 lend = body.find('\n', mend)
1624 1532 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1625 1533 begin = lend + 1
1626 1534
1627 1535 class linestate(object):
1628 1536 def __init__(self, line, linenum, colstart, colend):
1629 1537 self.line = line
1630 1538 self.linenum = linenum
1631 1539 self.colstart = colstart
1632 1540 self.colend = colend
1633 1541 def __eq__(self, other):
1634 1542 return self.line == other.line
1635 1543 def __hash__(self):
1636 1544 return hash(self.line)
1637 1545
1638 1546 matches = {}
1639 1547 def grepbody(fn, rev, body):
1640 1548 matches[rev].setdefault(fn, {})
1641 1549 m = matches[rev][fn]
1642 1550 for lnum, cstart, cend, line in matchlines(body):
1643 1551 s = linestate(line, lnum, cstart, cend)
1644 1552 m[s] = s
1645 1553
1646 1554 # FIXME: prev isn't used, why ?
1647 1555 prev = {}
1648 1556 ucache = {}
1649 1557 def display(fn, rev, states, prevstates):
1650 1558 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1651 1559 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1652 1560 counts = {'-': 0, '+': 0}
1653 1561 filerevmatches = {}
1654 1562 for l in diff:
1655 1563 if incrementing or not opts['all']:
1656 1564 change = ((l in prevstates) and '-') or '+'
1657 1565 r = rev
1658 1566 else:
1659 1567 change = ((l in states) and '-') or '+'
1660 1568 r = prev[fn]
1661 1569 cols = [fn, str(rev)]
1662 1570 if opts['line_number']:
1663 1571 cols.append(str(l.linenum))
1664 1572 if opts['all']:
1665 1573 cols.append(change)
1666 1574 if opts['user']:
1667 1575 cols.append(trimuser(ui, getchange(rev)[1], rev,
1668 1576 ucache))
1669 1577 if opts['files_with_matches']:
1670 1578 c = (fn, rev)
1671 1579 if c in filerevmatches:
1672 1580 continue
1673 1581 filerevmatches[c] = 1
1674 1582 else:
1675 1583 cols.append(l.line)
1676 1584 ui.write(sep.join(cols), eol)
1677 1585 counts[change] += 1
1678 1586 return counts['+'], counts['-']
1679 1587
1680 1588 fstate = {}
1681 1589 skip = {}
1682 1590 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1683 1591 count = 0
1684 1592 incrementing = False
1685 1593 for st, rev, fns in changeiter:
1686 1594 if st == 'window':
1687 1595 incrementing = rev
1688 1596 matches.clear()
1689 1597 elif st == 'add':
1690 1598 change = repo.changelog.read(repo.lookup(str(rev)))
1691 1599 mf = repo.manifest.read(change[0])
1692 1600 matches[rev] = {}
1693 1601 for fn in fns:
1694 1602 if fn in skip:
1695 1603 continue
1696 1604 fstate.setdefault(fn, {})
1697 1605 try:
1698 1606 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1699 1607 except KeyError:
1700 1608 pass
1701 1609 elif st == 'iter':
1702 1610 states = matches[rev].items()
1703 1611 states.sort()
1704 1612 for fn, m in states:
1705 1613 if fn in skip:
1706 1614 continue
1707 1615 if incrementing or not opts['all'] or fstate[fn]:
1708 1616 pos, neg = display(fn, rev, m, fstate[fn])
1709 1617 count += pos + neg
1710 1618 if pos and not opts['all']:
1711 1619 skip[fn] = True
1712 1620 fstate[fn] = m
1713 1621 prev[fn] = rev
1714 1622
1715 1623 if not incrementing:
1716 1624 fstate = fstate.items()
1717 1625 fstate.sort()
1718 1626 for fn, state in fstate:
1719 1627 if fn in skip:
1720 1628 continue
1721 1629 display(fn, rev, {}, state)
1722 1630 return (count == 0 and 1) or 0
1723 1631
1724 1632 def heads(ui, repo, **opts):
1725 1633 """show current repository heads
1726 1634
1727 1635 Show all repository head changesets.
1728 1636
1729 1637 Repository "heads" are changesets that don't have children
1730 1638 changesets. They are where development generally takes place and
1731 1639 are the usual targets for update and merge operations.
1732 1640 """
1733 1641 if opts['rev']:
1734 1642 heads = repo.heads(repo.lookup(opts['rev']))
1735 1643 else:
1736 1644 heads = repo.heads()
1737 1645 br = None
1738 1646 if opts['branches']:
1739 1647 br = repo.branchlookup(heads)
1740 1648 displayer = show_changeset(ui, repo, opts)
1741 1649 for n in heads:
1742 1650 displayer.show(changenode=n, brinfo=br)
1743 1651
1744 1652 def identify(ui, repo):
1745 1653 """print information about the working copy
1746 1654
1747 1655 Print a short summary of the current state of the repo.
1748 1656
1749 1657 This summary identifies the repository state using one or two parent
1750 1658 hash identifiers, followed by a "+" if there are uncommitted changes
1751 1659 in the working directory, followed by a list of tags for this revision.
1752 1660 """
1753 1661 parents = [p for p in repo.dirstate.parents() if p != nullid]
1754 1662 if not parents:
1755 1663 ui.write(_("unknown\n"))
1756 1664 return
1757 1665
1758 1666 hexfunc = ui.verbose and hex or short
1759 1667 modified, added, removed, deleted, unknown = repo.changes()
1760 1668 output = ["%s%s" %
1761 1669 ('+'.join([hexfunc(parent) for parent in parents]),
1762 1670 (modified or added or removed or deleted) and "+" or "")]
1763 1671
1764 1672 if not ui.quiet:
1765 1673 # multiple tags for a single parent separated by '/'
1766 1674 parenttags = ['/'.join(tags)
1767 1675 for tags in map(repo.nodetags, parents) if tags]
1768 1676 # tags for multiple parents separated by ' + '
1769 1677 if parenttags:
1770 1678 output.append(' + '.join(parenttags))
1771 1679
1772 1680 ui.write("%s\n" % ' '.join(output))
1773 1681
1774 1682 def import_(ui, repo, patch1, *patches, **opts):
1775 1683 """import an ordered set of patches
1776 1684
1777 1685 Import a list of patches and commit them individually.
1778 1686
1779 1687 If there are outstanding changes in the working directory, import
1780 1688 will abort unless given the -f flag.
1781 1689
1782 1690 You can import a patch straight from a mail message. Even patches
1783 1691 as attachments work (body part must be type text/plain or
1784 1692 text/x-patch to be used). From and Subject headers of email
1785 1693 message are used as default committer and commit message. All
1786 1694 text/plain body parts before first diff are added to commit
1787 1695 message.
1788 1696
1789 1697 If imported patch was generated by hg export, user and description
1790 1698 from patch override values from message headers and body. Values
1791 1699 given on command line with -m and -u override these.
1792 1700
1793 1701 To read a patch from standard input, use patch name "-".
1794 1702 """
1795 1703 patches = (patch1,) + patches
1796 1704
1797 1705 if not opts['force']:
1798 1706 bail_if_changed(repo)
1799 1707
1800 1708 d = opts["base"]
1801 1709 strip = opts["strip"]
1802 1710
1803 1711 mailre = re.compile(r'(?:From |[\w-]+:)')
1804 1712
1805 1713 # attempt to detect the start of a patch
1806 1714 # (this heuristic is borrowed from quilt)
1807 1715 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1808 1716 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1809 1717 '(---|\*\*\*)[ \t])', re.MULTILINE)
1810 1718
1811 1719 for patch in patches:
1812 1720 pf = os.path.join(d, patch)
1813 1721
1814 1722 message = None
1815 1723 user = None
1816 1724 date = None
1817 1725 hgpatch = False
1818 1726
1819 1727 p = email.Parser.Parser()
1820 1728 if pf == '-':
1821 1729 msg = p.parse(sys.stdin)
1822 1730 ui.status(_("applying patch from stdin\n"))
1823 1731 else:
1824 1732 msg = p.parse(file(pf))
1825 1733 ui.status(_("applying %s\n") % patch)
1826 1734
1827 1735 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
1828 1736 tmpfp = os.fdopen(fd, 'w')
1829 1737 try:
1830 1738 message = msg['Subject']
1831 1739 if message:
1832 1740 message = message.replace('\n\t', ' ')
1833 1741 ui.debug('Subject: %s\n' % message)
1834 1742 user = msg['From']
1835 1743 if user:
1836 1744 ui.debug('From: %s\n' % user)
1837 1745 diffs_seen = 0
1838 1746 ok_types = ('text/plain', 'text/x-patch')
1839 1747 for part in msg.walk():
1840 1748 content_type = part.get_content_type()
1841 1749 ui.debug('Content-Type: %s\n' % content_type)
1842 1750 if content_type not in ok_types:
1843 1751 continue
1844 1752 payload = part.get_payload(decode=True)
1845 1753 m = diffre.search(payload)
1846 1754 if m:
1847 1755 ui.debug(_('found patch at byte %d\n') % m.start(0))
1848 1756 diffs_seen += 1
1849 1757 hgpatch = False
1850 1758 fp = cStringIO.StringIO()
1851 1759 if message:
1852 1760 fp.write(message)
1853 1761 fp.write('\n')
1854 1762 for line in payload[:m.start(0)].splitlines():
1855 1763 if line.startswith('# HG changeset patch'):
1856 1764 ui.debug(_('patch generated by hg export\n'))
1857 1765 hgpatch = True
1858 1766 # drop earlier commit message content
1859 1767 fp.seek(0)
1860 1768 fp.truncate()
1861 1769 elif hgpatch:
1862 1770 if line.startswith('# User '):
1863 1771 user = line[7:]
1864 1772 ui.debug('From: %s\n' % user)
1865 1773 elif line.startswith("# Date "):
1866 1774 date = line[7:]
1867 1775 if not line.startswith('# '):
1868 1776 fp.write(line)
1869 1777 fp.write('\n')
1870 1778 message = fp.getvalue()
1871 1779 if tmpfp:
1872 1780 tmpfp.write(payload)
1873 1781 if not payload.endswith('\n'):
1874 1782 tmpfp.write('\n')
1875 1783 elif not diffs_seen and message and content_type == 'text/plain':
1876 1784 message += '\n' + payload
1877 1785
1878 1786 if opts['message']:
1879 1787 # pickup the cmdline msg
1880 1788 message = opts['message']
1881 1789 elif message:
1882 1790 # pickup the patch msg
1883 1791 message = message.strip()
1884 1792 else:
1885 1793 # launch the editor
1886 1794 message = None
1887 1795 ui.debug(_('message:\n%s\n') % message)
1888 1796
1889 1797 tmpfp.close()
1890 1798 if not diffs_seen:
1891 1799 raise util.Abort(_('no diffs found'))
1892 1800
1893 1801 files = util.patch(strip, tmpname, ui)
1894 1802 if len(files) > 0:
1895 1803 addremove_lock(ui, repo, files, {})
1896 1804 repo.commit(files, message, user, date)
1897 1805 finally:
1898 1806 os.unlink(tmpname)
1899 1807
1900 1808 def incoming(ui, repo, source="default", **opts):
1901 1809 """show new changesets found in source
1902 1810
1903 1811 Show new changesets found in the specified path/URL or the default
1904 1812 pull location. These are the changesets that would be pulled if a pull
1905 1813 was requested.
1906 1814
1907 1815 For remote repository, using --bundle avoids downloading the changesets
1908 1816 twice if the incoming is followed by a pull.
1909 1817
1910 1818 See pull for valid source format details.
1911 1819 """
1912 1820 source = ui.expandpath(source)
1913 1821 if opts['ssh']:
1914 1822 ui.setconfig("ui", "ssh", opts['ssh'])
1915 1823 if opts['remotecmd']:
1916 1824 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1917 1825
1918 1826 other = hg.repository(ui, source)
1919 1827 incoming = repo.findincoming(other, force=opts["force"])
1920 1828 if not incoming:
1921 1829 ui.status(_("no changes found\n"))
1922 1830 return
1923 1831
1924 1832 cleanup = None
1925 1833 try:
1926 1834 fname = opts["bundle"]
1927 1835 if fname or not other.local():
1928 1836 # create a bundle (uncompressed if other repo is not local)
1929 1837 cg = other.changegroup(incoming, "incoming")
1930 1838 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1931 1839 # keep written bundle?
1932 1840 if opts["bundle"]:
1933 1841 cleanup = None
1934 1842 if not other.local():
1935 1843 # use the created uncompressed bundlerepo
1936 1844 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1937 1845
1938 1846 revs = None
1939 1847 if opts['rev']:
1940 1848 revs = [other.lookup(rev) for rev in opts['rev']]
1941 1849 o = other.changelog.nodesbetween(incoming, revs)[0]
1942 1850 if opts['newest_first']:
1943 1851 o.reverse()
1944 1852 displayer = show_changeset(ui, other, opts)
1945 1853 for n in o:
1946 1854 parents = [p for p in other.changelog.parents(n) if p != nullid]
1947 1855 if opts['no_merges'] and len(parents) == 2:
1948 1856 continue
1949 1857 displayer.show(changenode=n)
1950 1858 if opts['patch']:
1951 1859 prev = (parents and parents[0]) or nullid
1952 1860 dodiff(ui, ui, other, prev, n)
1953 1861 ui.write("\n")
1954 1862 finally:
1955 1863 if hasattr(other, 'close'):
1956 1864 other.close()
1957 1865 if cleanup:
1958 1866 os.unlink(cleanup)
1959 1867
1960 1868 def init(ui, dest="."):
1961 1869 """create a new repository in the given directory
1962 1870
1963 1871 Initialize a new repository in the given directory. If the given
1964 1872 directory does not exist, it is created.
1965 1873
1966 1874 If no directory is given, the current directory is used.
1967 1875
1968 1876 It is possible to specify an ssh:// URL as the destination.
1969 1877 Look at the help text for the pull command for important details
1970 1878 about ssh:// URLs.
1971 1879 """
1972 1880 hg.repository(ui, dest, create=1)
1973 1881
1974 1882 def locate(ui, repo, *pats, **opts):
1975 1883 """locate files matching specific patterns
1976 1884
1977 1885 Print all files under Mercurial control whose names match the
1978 1886 given patterns.
1979 1887
1980 1888 This command searches the current directory and its
1981 1889 subdirectories. To search an entire repository, move to the root
1982 1890 of the repository.
1983 1891
1984 1892 If no patterns are given to match, this command prints all file
1985 1893 names.
1986 1894
1987 1895 If you want to feed the output of this command into the "xargs"
1988 1896 command, use the "-0" option to both this command and "xargs".
1989 1897 This will avoid the problem of "xargs" treating single filenames
1990 1898 that contain white space as multiple filenames.
1991 1899 """
1992 1900 end = opts['print0'] and '\0' or '\n'
1993 1901 rev = opts['rev']
1994 1902 if rev:
1995 1903 node = repo.lookup(rev)
1996 1904 else:
1997 1905 node = None
1998 1906
1999 1907 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2000 1908 head='(?:.*/|)'):
2001 1909 if not node and repo.dirstate.state(abs) == '?':
2002 1910 continue
2003 1911 if opts['fullpath']:
2004 1912 ui.write(os.path.join(repo.root, abs), end)
2005 1913 else:
2006 1914 ui.write(((pats and rel) or abs), end)
2007 1915
2008 1916 def log(ui, repo, *pats, **opts):
2009 1917 """show revision history of entire repository or files
2010 1918
2011 1919 Print the revision history of the specified files or the entire project.
2012 1920
2013 1921 By default this command outputs: changeset id and hash, tags,
2014 1922 non-trivial parents, user, date and time, and a summary for each
2015 1923 commit. When the -v/--verbose switch is used, the list of changed
2016 1924 files and full commit message is shown.
2017 1925 """
2018 1926 class dui(object):
2019 1927 # Implement and delegate some ui protocol. Save hunks of
2020 1928 # output for later display in the desired order.
2021 1929 def __init__(self, ui):
2022 1930 self.ui = ui
2023 1931 self.hunk = {}
2024 1932 self.header = {}
2025 1933 def bump(self, rev):
2026 1934 self.rev = rev
2027 1935 self.hunk[rev] = []
2028 1936 self.header[rev] = []
2029 1937 def note(self, *args):
2030 1938 if self.verbose:
2031 1939 self.write(*args)
2032 1940 def status(self, *args):
2033 1941 if not self.quiet:
2034 1942 self.write(*args)
2035 1943 def write(self, *args):
2036 1944 self.hunk[self.rev].append(args)
2037 1945 def write_header(self, *args):
2038 1946 self.header[self.rev].append(args)
2039 1947 def debug(self, *args):
2040 1948 if self.debugflag:
2041 1949 self.write(*args)
2042 1950 def __getattr__(self, key):
2043 1951 return getattr(self.ui, key)
2044 1952
2045 1953 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
2046 1954
2047 1955 if opts['limit']:
2048 1956 try:
2049 1957 limit = int(opts['limit'])
2050 1958 except ValueError:
2051 1959 raise util.Abort(_('limit must be a positive integer'))
2052 1960 if limit <= 0: raise util.Abort(_('limit must be positive'))
2053 1961 else:
2054 1962 limit = sys.maxint
2055 1963 count = 0
2056 1964
2057 1965 displayer = show_changeset(ui, repo, opts)
2058 1966 for st, rev, fns in changeiter:
2059 1967 if st == 'window':
2060 1968 du = dui(ui)
2061 1969 displayer.ui = du
2062 1970 elif st == 'add':
2063 1971 du.bump(rev)
2064 1972 changenode = repo.changelog.node(rev)
2065 1973 parents = [p for p in repo.changelog.parents(changenode)
2066 1974 if p != nullid]
2067 1975 if opts['no_merges'] and len(parents) == 2:
2068 1976 continue
2069 1977 if opts['only_merges'] and len(parents) != 2:
2070 1978 continue
2071 1979
2072 1980 if opts['keyword']:
2073 1981 changes = getchange(rev)
2074 1982 miss = 0
2075 1983 for k in [kw.lower() for kw in opts['keyword']]:
2076 1984 if not (k in changes[1].lower() or
2077 1985 k in changes[4].lower() or
2078 1986 k in " ".join(changes[3][:20]).lower()):
2079 1987 miss = 1
2080 1988 break
2081 1989 if miss:
2082 1990 continue
2083 1991
2084 1992 br = None
2085 1993 if opts['branches']:
2086 1994 br = repo.branchlookup([repo.changelog.node(rev)])
2087 1995
2088 1996 displayer.show(rev, brinfo=br)
2089 1997 if opts['patch']:
2090 1998 prev = (parents and parents[0]) or nullid
2091 1999 dodiff(du, du, repo, prev, changenode, match=matchfn)
2092 2000 du.write("\n\n")
2093 2001 elif st == 'iter':
2094 2002 if count == limit: break
2095 2003 if du.header[rev]:
2096 2004 for args in du.header[rev]:
2097 2005 ui.write_header(*args)
2098 2006 if du.hunk[rev]:
2099 2007 count += 1
2100 2008 for args in du.hunk[rev]:
2101 2009 ui.write(*args)
2102 2010
2103 2011 def manifest(ui, repo, rev=None):
2104 2012 """output the latest or given revision of the project manifest
2105 2013
2106 2014 Print a list of version controlled files for the given revision.
2107 2015
2108 2016 The manifest is the list of files being version controlled. If no revision
2109 2017 is given then the tip is used.
2110 2018 """
2111 2019 if rev:
2112 2020 try:
2113 2021 # assume all revision numbers are for changesets
2114 2022 n = repo.lookup(rev)
2115 2023 change = repo.changelog.read(n)
2116 2024 n = change[0]
2117 2025 except hg.RepoError:
2118 2026 n = repo.manifest.lookup(rev)
2119 2027 else:
2120 2028 n = repo.manifest.tip()
2121 2029 m = repo.manifest.read(n)
2122 2030 mf = repo.manifest.readflags(n)
2123 2031 files = m.keys()
2124 2032 files.sort()
2125 2033
2126 2034 for f in files:
2127 2035 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
2128 2036
2129 2037 def merge(ui, repo, node=None, **opts):
2130 2038 """Merge working directory with another revision
2131 2039
2132 2040 Merge the contents of the current working directory and the
2133 2041 requested revision. Files that changed between either parent are
2134 2042 marked as changed for the next commit and a commit must be
2135 2043 performed before any further updates are allowed.
2136 2044 """
2137 2045 return doupdate(ui, repo, node=node, merge=True, **opts)
2138 2046
2139 2047 def outgoing(ui, repo, dest=None, **opts):
2140 2048 """show changesets not found in destination
2141 2049
2142 2050 Show changesets not found in the specified destination repository or
2143 2051 the default push location. These are the changesets that would be pushed
2144 2052 if a push was requested.
2145 2053
2146 2054 See pull for valid destination format details.
2147 2055 """
2148 2056 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2149 2057 if opts['ssh']:
2150 2058 ui.setconfig("ui", "ssh", opts['ssh'])
2151 2059 if opts['remotecmd']:
2152 2060 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2153 2061 revs = None
2154 2062 if opts['rev']:
2155 2063 revs = [repo.lookup(rev) for rev in opts['rev']]
2156 2064
2157 2065 other = hg.repository(ui, dest)
2158 2066 o = repo.findoutgoing(other, force=opts['force'])
2159 2067 if not o:
2160 2068 ui.status(_("no changes found\n"))
2161 2069 return
2162 2070 o = repo.changelog.nodesbetween(o, revs)[0]
2163 2071 if opts['newest_first']:
2164 2072 o.reverse()
2165 2073 displayer = show_changeset(ui, repo, opts)
2166 2074 for n in o:
2167 2075 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2168 2076 if opts['no_merges'] and len(parents) == 2:
2169 2077 continue
2170 2078 displayer.show(changenode=n)
2171 2079 if opts['patch']:
2172 2080 prev = (parents and parents[0]) or nullid
2173 2081 dodiff(ui, ui, repo, prev, n)
2174 2082 ui.write("\n")
2175 2083
2176 2084 def parents(ui, repo, rev=None, branches=None, **opts):
2177 2085 """show the parents of the working dir or revision
2178 2086
2179 2087 Print the working directory's parent revisions.
2180 2088 """
2181 2089 if rev:
2182 2090 p = repo.changelog.parents(repo.lookup(rev))
2183 2091 else:
2184 2092 p = repo.dirstate.parents()
2185 2093
2186 2094 br = None
2187 2095 if branches is not None:
2188 2096 br = repo.branchlookup(p)
2189 2097 displayer = show_changeset(ui, repo, opts)
2190 2098 for n in p:
2191 2099 if n != nullid:
2192 2100 displayer.show(changenode=n, brinfo=br)
2193 2101
2194 2102 def paths(ui, repo, search=None):
2195 2103 """show definition of symbolic path names
2196 2104
2197 2105 Show definition of symbolic path name NAME. If no name is given, show
2198 2106 definition of available names.
2199 2107
2200 2108 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2201 2109 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2202 2110 """
2203 2111 if search:
2204 2112 for name, path in ui.configitems("paths"):
2205 2113 if name == search:
2206 2114 ui.write("%s\n" % path)
2207 2115 return
2208 2116 ui.warn(_("not found!\n"))
2209 2117 return 1
2210 2118 else:
2211 2119 for name, path in ui.configitems("paths"):
2212 2120 ui.write("%s = %s\n" % (name, path))
2213 2121
2214 2122 def postincoming(ui, repo, modheads, optupdate):
2215 2123 if modheads == 0:
2216 2124 return
2217 2125 if optupdate:
2218 2126 if modheads == 1:
2219 2127 return doupdate(ui, repo)
2220 2128 else:
2221 2129 ui.status(_("not updating, since new heads added\n"))
2222 2130 if modheads > 1:
2223 2131 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2224 2132 else:
2225 2133 ui.status(_("(run 'hg update' to get a working copy)\n"))
2226 2134
2227 2135 def pull(ui, repo, source="default", **opts):
2228 2136 """pull changes from the specified source
2229 2137
2230 2138 Pull changes from a remote repository to a local one.
2231 2139
2232 2140 This finds all changes from the repository at the specified path
2233 2141 or URL and adds them to the local repository. By default, this
2234 2142 does not update the copy of the project in the working directory.
2235 2143
2236 2144 Valid URLs are of the form:
2237 2145
2238 2146 local/filesystem/path
2239 2147 http://[user@]host[:port]/[path]
2240 2148 https://[user@]host[:port]/[path]
2241 2149 ssh://[user@]host[:port]/[path]
2242 2150
2243 2151 Some notes about using SSH with Mercurial:
2244 2152 - SSH requires an accessible shell account on the destination machine
2245 2153 and a copy of hg in the remote path or specified with as remotecmd.
2246 2154 - path is relative to the remote user's home directory by default.
2247 2155 Use an extra slash at the start of a path to specify an absolute path:
2248 2156 ssh://example.com//tmp/repository
2249 2157 - Mercurial doesn't use its own compression via SSH; the right thing
2250 2158 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2251 2159 Host *.mylocalnetwork.example.com
2252 2160 Compression off
2253 2161 Host *
2254 2162 Compression on
2255 2163 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2256 2164 with the --ssh command line option.
2257 2165 """
2258 2166 source = ui.expandpath(source)
2259 2167
2260 2168 if opts['ssh']:
2261 2169 ui.setconfig("ui", "ssh", opts['ssh'])
2262 2170 if opts['remotecmd']:
2263 2171 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2264 2172
2265 2173 other = hg.repository(ui, source)
2266 2174 ui.status(_('pulling from %s\n') % (source))
2267 2175 revs = None
2268 2176 if opts['rev'] and not other.local():
2269 2177 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2270 2178 elif opts['rev']:
2271 2179 revs = [other.lookup(rev) for rev in opts['rev']]
2272 2180 modheads = repo.pull(other, heads=revs, force=opts['force'])
2273 2181 return postincoming(ui, repo, modheads, opts['update'])
2274 2182
2275 2183 def push(ui, repo, dest=None, **opts):
2276 2184 """push changes to the specified destination
2277 2185
2278 2186 Push changes from the local repository to the given destination.
2279 2187
2280 2188 This is the symmetrical operation for pull. It helps to move
2281 2189 changes from the current repository to a different one. If the
2282 2190 destination is local this is identical to a pull in that directory
2283 2191 from the current one.
2284 2192
2285 2193 By default, push will refuse to run if it detects the result would
2286 2194 increase the number of remote heads. This generally indicates the
2287 2195 the client has forgotten to sync and merge before pushing.
2288 2196
2289 2197 Valid URLs are of the form:
2290 2198
2291 2199 local/filesystem/path
2292 2200 ssh://[user@]host[:port]/[path]
2293 2201
2294 2202 Look at the help text for the pull command for important details
2295 2203 about ssh:// URLs.
2296 2204
2297 2205 Pushing to http:// and https:// URLs is possible, too, if this
2298 2206 feature is enabled on the remote Mercurial server.
2299 2207 """
2300 2208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2301 2209
2302 2210 if opts['ssh']:
2303 2211 ui.setconfig("ui", "ssh", opts['ssh'])
2304 2212 if opts['remotecmd']:
2305 2213 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
2306 2214
2307 2215 other = hg.repository(ui, dest)
2308 2216 ui.status('pushing to %s\n' % (dest))
2309 2217 revs = None
2310 2218 if opts['rev']:
2311 2219 revs = [repo.lookup(rev) for rev in opts['rev']]
2312 2220 r = repo.push(other, opts['force'], revs=revs)
2313 2221 return r == 0
2314 2222
2315 2223 def rawcommit(ui, repo, *flist, **rc):
2316 2224 """raw commit interface (DEPRECATED)
2317 2225
2318 2226 (DEPRECATED)
2319 2227 Lowlevel commit, for use in helper scripts.
2320 2228
2321 2229 This command is not intended to be used by normal users, as it is
2322 2230 primarily useful for importing from other SCMs.
2323 2231
2324 2232 This command is now deprecated and will be removed in a future
2325 2233 release, please use debugsetparents and commit instead.
2326 2234 """
2327 2235
2328 2236 ui.warn(_("(the rawcommit command is deprecated)\n"))
2329 2237
2330 2238 message = rc['message']
2331 2239 if not message and rc['logfile']:
2332 2240 try:
2333 2241 message = open(rc['logfile']).read()
2334 2242 except IOError:
2335 2243 pass
2336 2244 if not message and not rc['logfile']:
2337 2245 raise util.Abort(_("missing commit message"))
2338 2246
2339 2247 files = relpath(repo, list(flist))
2340 2248 if rc['files']:
2341 2249 files += open(rc['files']).read().splitlines()
2342 2250
2343 2251 rc['parent'] = map(repo.lookup, rc['parent'])
2344 2252
2345 2253 try:
2346 2254 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2347 2255 except ValueError, inst:
2348 2256 raise util.Abort(str(inst))
2349 2257
2350 2258 def recover(ui, repo):
2351 2259 """roll back an interrupted transaction
2352 2260
2353 2261 Recover from an interrupted commit or pull.
2354 2262
2355 2263 This command tries to fix the repository status after an interrupted
2356 2264 operation. It should only be necessary when Mercurial suggests it.
2357 2265 """
2358 2266 if repo.recover():
2359 2267 return repo.verify()
2360 2268 return 1
2361 2269
2362 2270 def remove(ui, repo, *pats, **opts):
2363 2271 """remove the specified files on the next commit
2364 2272
2365 2273 Schedule the indicated files for removal from the repository.
2366 2274
2367 2275 This command schedules the files to be removed at the next commit.
2368 2276 This only removes files from the current branch, not from the
2369 2277 entire project history. If the files still exist in the working
2370 2278 directory, they will be deleted from it. If invoked with --after,
2371 2279 files that have been manually deleted are marked as removed.
2372 2280
2373 2281 Modified files and added files are not removed by default. To
2374 2282 remove them, use the -f/--force option.
2375 2283 """
2376 2284 names = []
2377 2285 if not opts['after'] and not pats:
2378 2286 raise util.Abort(_('no files specified'))
2379 2287 files, matchfn, anypats = matchpats(repo, pats, opts)
2380 2288 exact = dict.fromkeys(files)
2381 2289 mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
2382 2290 modified, added, removed, deleted, unknown = mardu
2383 2291 remove, forget = [], []
2384 2292 for src, abs, rel, exact in walk(repo, pats, opts):
2385 2293 reason = None
2386 2294 if abs not in deleted and opts['after']:
2387 2295 reason = _('is still present')
2388 2296 elif abs in modified and not opts['force']:
2389 2297 reason = _('is modified (use -f to force removal)')
2390 2298 elif abs in added:
2391 2299 if opts['force']:
2392 2300 forget.append(abs)
2393 2301 continue
2394 2302 reason = _('has been marked for add (use -f to force removal)')
2395 2303 elif abs in unknown:
2396 2304 reason = _('is not managed')
2397 2305 elif abs in removed:
2398 2306 continue
2399 2307 if reason:
2400 2308 if exact:
2401 2309 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2402 2310 else:
2403 2311 if ui.verbose or not exact:
2404 2312 ui.status(_('removing %s\n') % rel)
2405 2313 remove.append(abs)
2406 2314 repo.forget(forget)
2407 2315 repo.remove(remove, unlink=not opts['after'])
2408 2316
2409 2317 def rename(ui, repo, *pats, **opts):
2410 2318 """rename files; equivalent of copy + remove
2411 2319
2412 2320 Mark dest as copies of sources; mark sources for deletion. If
2413 2321 dest is a directory, copies are put in that directory. If dest is
2414 2322 a file, there can only be one source.
2415 2323
2416 2324 By default, this command copies the contents of files as they
2417 2325 stand in the working directory. If invoked with --after, the
2418 2326 operation is recorded, but no copying is performed.
2419 2327
2420 2328 This command takes effect in the next commit.
2421 2329
2422 2330 NOTE: This command should be treated as experimental. While it
2423 2331 should properly record rename files, this information is not yet
2424 2332 fully used by merge, nor fully reported by log.
2425 2333 """
2426 2334 wlock = repo.wlock(0)
2427 2335 errs, copied = docopy(ui, repo, pats, opts, wlock)
2428 2336 names = []
2429 2337 for abs, rel, exact in copied:
2430 2338 if ui.verbose or not exact:
2431 2339 ui.status(_('removing %s\n') % rel)
2432 2340 names.append(abs)
2433 2341 if not opts.get('dry_run'):
2434 2342 repo.remove(names, True, wlock)
2435 2343 return errs
2436 2344
2437 2345 def revert(ui, repo, *pats, **opts):
2438 2346 """revert files or dirs to their states as of some revision
2439 2347
2440 2348 With no revision specified, revert the named files or directories
2441 2349 to the contents they had in the parent of the working directory.
2442 2350 This restores the contents of the affected files to an unmodified
2443 2351 state. If the working directory has two parents, you must
2444 2352 explicitly specify the revision to revert to.
2445 2353
2446 2354 Modified files are saved with a .orig suffix before reverting.
2447 2355 To disable these backups, use --no-backup.
2448 2356
2449 2357 Using the -r option, revert the given files or directories to
2450 2358 their contents as of a specific revision. This can be helpful to"roll
2451 2359 back" some or all of a change that should not have been committed.
2452 2360
2453 2361 Revert modifies the working directory. It does not commit any
2454 2362 changes, or change the parent of the working directory. If you
2455 2363 revert to a revision other than the parent of the working
2456 2364 directory, the reverted files will thus appear modified
2457 2365 afterwards.
2458 2366
2459 2367 If a file has been deleted, it is recreated. If the executable
2460 2368 mode of a file was changed, it is reset.
2461 2369
2462 2370 If names are given, all files matching the names are reverted.
2463 2371
2464 2372 If no arguments are given, all files in the repository are reverted.
2465 2373 """
2466 2374 parent, p2 = repo.dirstate.parents()
2467 2375 if opts['rev']:
2468 2376 node = repo.lookup(opts['rev'])
2469 2377 elif p2 != nullid:
2470 2378 raise util.Abort(_('working dir has two parents; '
2471 2379 'you must specify the revision to revert to'))
2472 2380 else:
2473 2381 node = parent
2474 2382 mf = repo.manifest.read(repo.changelog.read(node)[0])
2475 2383 if node == parent:
2476 2384 pmf = mf
2477 2385 else:
2478 2386 pmf = None
2479 2387
2480 2388 wlock = repo.wlock()
2481 2389
2482 2390 # need all matching names in dirstate and manifest of target rev,
2483 2391 # so have to walk both. do not print errors if files exist in one
2484 2392 # but not other.
2485 2393
2486 2394 names = {}
2487 2395 target_only = {}
2488 2396
2489 2397 # walk dirstate.
2490 2398
2491 2399 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2492 2400 names[abs] = (rel, exact)
2493 2401 if src == 'b':
2494 2402 target_only[abs] = True
2495 2403
2496 2404 # walk target manifest.
2497 2405
2498 2406 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2499 2407 badmatch=names.has_key):
2500 2408 if abs in names: continue
2501 2409 names[abs] = (rel, exact)
2502 2410 target_only[abs] = True
2503 2411
2504 2412 changes = repo.changes(match=names.has_key, wlock=wlock)
2505 2413 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2506 2414
2507 2415 revert = ([], _('reverting %s\n'))
2508 2416 add = ([], _('adding %s\n'))
2509 2417 remove = ([], _('removing %s\n'))
2510 2418 forget = ([], _('forgetting %s\n'))
2511 2419 undelete = ([], _('undeleting %s\n'))
2512 2420 update = {}
2513 2421
2514 2422 disptable = (
2515 2423 # dispatch table:
2516 2424 # file state
2517 2425 # action if in target manifest
2518 2426 # action if not in target manifest
2519 2427 # make backup if in target manifest
2520 2428 # make backup if not in target manifest
2521 2429 (modified, revert, remove, True, True),
2522 2430 (added, revert, forget, True, False),
2523 2431 (removed, undelete, None, False, False),
2524 2432 (deleted, revert, remove, False, False),
2525 2433 (unknown, add, None, True, False),
2526 2434 (target_only, add, None, False, False),
2527 2435 )
2528 2436
2529 2437 entries = names.items()
2530 2438 entries.sort()
2531 2439
2532 2440 for abs, (rel, exact) in entries:
2533 2441 mfentry = mf.get(abs)
2534 2442 def handle(xlist, dobackup):
2535 2443 xlist[0].append(abs)
2536 2444 update[abs] = 1
2537 2445 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2538 2446 bakname = "%s.orig" % rel
2539 2447 ui.note(_('saving current version of %s as %s\n') %
2540 2448 (rel, bakname))
2541 2449 if not opts.get('dry_run'):
2542 2450 shutil.copyfile(rel, bakname)
2543 2451 shutil.copymode(rel, bakname)
2544 2452 if ui.verbose or not exact:
2545 2453 ui.status(xlist[1] % rel)
2546 2454 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2547 2455 if abs not in table: continue
2548 2456 # file has changed in dirstate
2549 2457 if mfentry:
2550 2458 handle(hitlist, backuphit)
2551 2459 elif misslist is not None:
2552 2460 handle(misslist, backupmiss)
2553 2461 else:
2554 2462 if exact: ui.warn(_('file not managed: %s\n' % rel))
2555 2463 break
2556 2464 else:
2557 2465 # file has not changed in dirstate
2558 2466 if node == parent:
2559 2467 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2560 2468 continue
2561 2469 if pmf is None:
2562 2470 # only need parent manifest in this unlikely case,
2563 2471 # so do not read by default
2564 2472 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2565 2473 if abs in pmf:
2566 2474 if mfentry:
2567 2475 # if version of file is same in parent and target
2568 2476 # manifests, do nothing
2569 2477 if pmf[abs] != mfentry:
2570 2478 handle(revert, False)
2571 2479 else:
2572 2480 handle(remove, False)
2573 2481
2574 2482 if not opts.get('dry_run'):
2575 2483 repo.dirstate.forget(forget[0])
2576 2484 r = repo.update(node, False, True, update.has_key, False, wlock=wlock,
2577 2485 show_stats=False)
2578 2486 repo.dirstate.update(add[0], 'a')
2579 2487 repo.dirstate.update(undelete[0], 'n')
2580 2488 repo.dirstate.update(remove[0], 'r')
2581 2489 return r
2582 2490
2583 2491 def rollback(ui, repo):
2584 2492 """roll back the last transaction in this repository
2585 2493
2586 2494 Roll back the last transaction in this repository, restoring the
2587 2495 project to its state prior to the transaction.
2588 2496
2589 2497 Transactions are used to encapsulate the effects of all commands
2590 2498 that create new changesets or propagate existing changesets into a
2591 2499 repository. For example, the following commands are transactional,
2592 2500 and their effects can be rolled back:
2593 2501
2594 2502 commit
2595 2503 import
2596 2504 pull
2597 2505 push (with this repository as destination)
2598 2506 unbundle
2599 2507
2600 2508 This command should be used with care. There is only one level of
2601 2509 rollback, and there is no way to undo a rollback.
2602 2510
2603 2511 This command is not intended for use on public repositories. Once
2604 2512 changes are visible for pull by other users, rolling a transaction
2605 2513 back locally is ineffective (someone else may already have pulled
2606 2514 the changes). Furthermore, a race is possible with readers of the
2607 2515 repository; for example an in-progress pull from the repository
2608 2516 may fail if a rollback is performed.
2609 2517 """
2610 2518 repo.rollback()
2611 2519
2612 2520 def root(ui, repo):
2613 2521 """print the root (top) of the current working dir
2614 2522
2615 2523 Print the root directory of the current repository.
2616 2524 """
2617 2525 ui.write(repo.root + "\n")
2618 2526
2619 2527 def serve(ui, repo, **opts):
2620 2528 """export the repository via HTTP
2621 2529
2622 2530 Start a local HTTP repository browser and pull server.
2623 2531
2624 2532 By default, the server logs accesses to stdout and errors to
2625 2533 stderr. Use the "-A" and "-E" options to log to files.
2626 2534 """
2627 2535
2628 2536 if opts["stdio"]:
2629 2537 if repo is None:
2630 2538 raise hg.RepoError(_('no repo found'))
2631 2539 s = sshserver.sshserver(ui, repo)
2632 2540 s.serve_forever()
2633 2541
2634 2542 optlist = ("name templates style address port ipv6"
2635 2543 " accesslog errorlog webdir_conf")
2636 2544 for o in optlist.split():
2637 2545 if opts[o]:
2638 2546 ui.setconfig("web", o, opts[o])
2639 2547
2640 2548 if repo is None and not ui.config("web", "webdir_conf"):
2641 2549 raise hg.RepoError(_('no repo found'))
2642 2550
2643 2551 if opts['daemon'] and not opts['daemon_pipefds']:
2644 2552 rfd, wfd = os.pipe()
2645 2553 args = sys.argv[:]
2646 2554 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2647 2555 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2648 2556 args[0], args)
2649 2557 os.close(wfd)
2650 2558 os.read(rfd, 1)
2651 2559 os._exit(0)
2652 2560
2653 2561 try:
2654 2562 httpd = hgweb.server.create_server(ui, repo)
2655 2563 except socket.error, inst:
2656 2564 raise util.Abort(_('cannot start server: ') + inst.args[1])
2657 2565
2658 2566 if ui.verbose:
2659 2567 addr, port = httpd.socket.getsockname()
2660 2568 if addr == '0.0.0.0':
2661 2569 addr = socket.gethostname()
2662 2570 else:
2663 2571 try:
2664 2572 addr = socket.gethostbyaddr(addr)[0]
2665 2573 except socket.error:
2666 2574 pass
2667 2575 if port != 80:
2668 2576 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2669 2577 else:
2670 2578 ui.status(_('listening at http://%s/\n') % addr)
2671 2579
2672 2580 if opts['pid_file']:
2673 2581 fp = open(opts['pid_file'], 'w')
2674 2582 fp.write(str(os.getpid()) + '\n')
2675 2583 fp.close()
2676 2584
2677 2585 if opts['daemon_pipefds']:
2678 2586 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2679 2587 os.close(rfd)
2680 2588 os.write(wfd, 'y')
2681 2589 os.close(wfd)
2682 2590 sys.stdout.flush()
2683 2591 sys.stderr.flush()
2684 2592 fd = os.open(util.nulldev, os.O_RDWR)
2685 2593 if fd != 0: os.dup2(fd, 0)
2686 2594 if fd != 1: os.dup2(fd, 1)
2687 2595 if fd != 2: os.dup2(fd, 2)
2688 2596 if fd not in (0, 1, 2): os.close(fd)
2689 2597
2690 2598 httpd.serve_forever()
2691 2599
2692 2600 def status(ui, repo, *pats, **opts):
2693 2601 """show changed files in the working directory
2694 2602
2695 2603 Show changed files in the repository. If names are
2696 2604 given, only files that match are shown.
2697 2605
2698 2606 The codes used to show the status of files are:
2699 2607 M = modified
2700 2608 A = added
2701 2609 R = removed
2702 2610 ! = deleted, but still tracked
2703 2611 ? = not tracked
2704 2612 I = ignored (not shown by default)
2705 2613 """
2706 2614
2707 2615 show_ignored = opts['ignored'] and True or False
2708 2616 files, matchfn, anypats = matchpats(repo, pats, opts)
2709 2617 cwd = (pats and repo.getcwd()) or ''
2710 2618 modified, added, removed, deleted, unknown, ignored = [
2711 2619 [util.pathto(cwd, x) for x in n]
2712 2620 for n in repo.changes(files=files, match=matchfn,
2713 2621 show_ignored=show_ignored)]
2714 2622
2715 2623 changetypes = [('modified', 'M', modified),
2716 2624 ('added', 'A', added),
2717 2625 ('removed', 'R', removed),
2718 2626 ('deleted', '!', deleted),
2719 2627 ('unknown', '?', unknown),
2720 2628 ('ignored', 'I', ignored)]
2721 2629
2722 2630 end = opts['print0'] and '\0' or '\n'
2723 2631
2724 2632 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2725 2633 or changetypes):
2726 2634 if opts['no_status']:
2727 2635 format = "%%s%s" % end
2728 2636 else:
2729 2637 format = "%s %%s%s" % (char, end)
2730 2638
2731 2639 for f in changes:
2732 2640 ui.write(format % f)
2733 2641
2734 2642 def tag(ui, repo, name, rev_=None, **opts):
2735 2643 """add a tag for the current tip or a given revision
2736 2644
2737 2645 Name a particular revision using <name>.
2738 2646
2739 2647 Tags are used to name particular revisions of the repository and are
2740 2648 very useful to compare different revision, to go back to significant
2741 2649 earlier versions or to mark branch points as releases, etc.
2742 2650
2743 2651 If no revision is given, the tip is used.
2744 2652
2745 2653 To facilitate version control, distribution, and merging of tags,
2746 2654 they are stored as a file named ".hgtags" which is managed
2747 2655 similarly to other project files and can be hand-edited if
2748 2656 necessary. The file '.hg/localtags' is used for local tags (not
2749 2657 shared among repositories).
2750 2658 """
2751 2659 if name == "tip":
2752 2660 raise util.Abort(_("the name 'tip' is reserved"))
2753 2661 if rev_ is not None:
2754 2662 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2755 2663 "please use 'hg tag [-r REV] NAME' instead\n"))
2756 2664 if opts['rev']:
2757 2665 raise util.Abort(_("use only one form to specify the revision"))
2758 2666 if opts['rev']:
2759 2667 rev_ = opts['rev']
2760 2668 if rev_:
2761 2669 r = hex(repo.lookup(rev_))
2762 2670 else:
2763 2671 r = hex(repo.changelog.tip())
2764 2672
2765 2673 disallowed = (revrangesep, '\r', '\n')
2766 2674 for c in disallowed:
2767 2675 if c in name:
2768 2676 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2769 2677
2770 2678 repo.hook('pretag', throw=True, node=r, tag=name,
2771 2679 local=int(not not opts['local']))
2772 2680
2773 2681 if opts['local']:
2774 2682 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2775 2683 repo.hook('tag', node=r, tag=name, local=1)
2776 2684 return
2777 2685
2778 2686 for x in repo.changes():
2779 2687 if ".hgtags" in x:
2780 2688 raise util.Abort(_("working copy of .hgtags is changed "
2781 2689 "(please commit .hgtags manually)"))
2782 2690
2783 2691 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2784 2692 if repo.dirstate.state(".hgtags") == '?':
2785 2693 repo.add([".hgtags"])
2786 2694
2787 2695 message = (opts['message'] or
2788 2696 _("Added tag %s for changeset %s") % (name, r))
2789 2697 try:
2790 2698 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2791 2699 repo.hook('tag', node=r, tag=name, local=0)
2792 2700 except ValueError, inst:
2793 2701 raise util.Abort(str(inst))
2794 2702
2795 2703 def tags(ui, repo):
2796 2704 """list repository tags
2797 2705
2798 2706 List the repository tags.
2799 2707
2800 2708 This lists both regular and local tags.
2801 2709 """
2802 2710
2803 2711 l = repo.tagslist()
2804 2712 l.reverse()
2805 2713 for t, n in l:
2806 2714 try:
2807 2715 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2808 2716 except KeyError:
2809 2717 r = " ?:?"
2810 2718 if ui.quiet:
2811 2719 ui.write("%s\n" % t)
2812 2720 else:
2813 2721 ui.write("%-30s %s\n" % (t, r))
2814 2722
2815 2723 def tip(ui, repo, **opts):
2816 2724 """show the tip revision
2817 2725
2818 2726 Show the tip revision.
2819 2727 """
2820 2728 n = repo.changelog.tip()
2821 2729 br = None
2822 2730 if opts['branches']:
2823 2731 br = repo.branchlookup([n])
2824 2732 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2825 2733 if opts['patch']:
2826 2734 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2827 2735
2828 2736 def unbundle(ui, repo, fname, **opts):
2829 2737 """apply a changegroup file
2830 2738
2831 2739 Apply a compressed changegroup file generated by the bundle
2832 2740 command.
2833 2741 """
2834 2742 f = urllib.urlopen(fname)
2835 2743
2836 2744 header = f.read(6)
2837 2745 if not header.startswith("HG"):
2838 2746 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2839 2747 elif not header.startswith("HG10"):
2840 2748 raise util.Abort(_("%s: unknown bundle version") % fname)
2841 2749 elif header == "HG10BZ":
2842 2750 def generator(f):
2843 2751 zd = bz2.BZ2Decompressor()
2844 2752 zd.decompress("BZ")
2845 2753 for chunk in f:
2846 2754 yield zd.decompress(chunk)
2847 2755 elif header == "HG10UN":
2848 2756 def generator(f):
2849 2757 for chunk in f:
2850 2758 yield chunk
2851 2759 else:
2852 2760 raise util.Abort(_("%s: unknown bundle compression type")
2853 2761 % fname)
2854 2762 gen = generator(util.filechunkiter(f, 4096))
2855 2763 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
2856 2764 return postincoming(ui, repo, modheads, opts['update'])
2857 2765
2858 2766 def undo(ui, repo):
2859 2767 """undo the last commit or pull (DEPRECATED)
2860 2768
2861 2769 (DEPRECATED)
2862 2770 This command is now deprecated and will be removed in a future
2863 2771 release. Please use the rollback command instead. For usage
2864 2772 instructions, see the rollback command.
2865 2773 """
2866 2774 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2867 2775 repo.rollback()
2868 2776
2869 2777 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2870 2778 branch=None, **opts):
2871 2779 """update or merge working directory
2872 2780
2873 2781 Update the working directory to the specified revision.
2874 2782
2875 2783 If there are no outstanding changes in the working directory and
2876 2784 there is a linear relationship between the current version and the
2877 2785 requested version, the result is the requested version.
2878 2786
2879 2787 To merge the working directory with another revision, use the
2880 2788 merge command.
2881 2789
2882 2790 By default, update will refuse to run if doing so would require
2883 2791 merging or discarding local changes.
2884 2792 """
2885 2793 if merge:
2886 2794 ui.warn(_('(the -m/--merge option is deprecated; '
2887 2795 'use the merge command instead)\n'))
2888 2796 return doupdate(ui, repo, node, merge, clean, force, branch, **opts)
2889 2797
2890 2798 def doupdate(ui, repo, node=None, merge=False, clean=False, force=None,
2891 2799 branch=None, **opts):
2892 2800 if branch:
2893 2801 br = repo.branchlookup(branch=branch)
2894 2802 found = []
2895 2803 for x in br:
2896 2804 if branch in br[x]:
2897 2805 found.append(x)
2898 2806 if len(found) > 1:
2899 2807 ui.warn(_("Found multiple heads for %s\n") % branch)
2900 2808 for x in found:
2901 2809 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br)
2902 2810 return 1
2903 2811 if len(found) == 1:
2904 2812 node = found[0]
2905 2813 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2906 2814 else:
2907 2815 ui.warn(_("branch %s not found\n") % (branch))
2908 2816 return 1
2909 2817 else:
2910 2818 node = node and repo.lookup(node) or repo.changelog.tip()
2911 2819 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2912 2820
2913 2821 def verify(ui, repo):
2914 2822 """verify the integrity of the repository
2915 2823
2916 2824 Verify the integrity of the current repository.
2917 2825
2918 2826 This will perform an extensive check of the repository's
2919 2827 integrity, validating the hashes and checksums of each entry in
2920 2828 the changelog, manifest, and tracked files, as well as the
2921 2829 integrity of their crosslinks and indices.
2922 2830 """
2923 2831 return repo.verify()
2924 2832
2925 2833 # Command options and aliases are listed here, alphabetically
2926 2834
2927 2835 table = {
2928 2836 "^add":
2929 2837 (add,
2930 2838 [('I', 'include', [], _('include names matching the given patterns')),
2931 2839 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2932 2840 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2933 2841 _('hg add [OPTION]... [FILE]...')),
2934 2842 "debugaddremove|addremove":
2935 2843 (addremove,
2936 2844 [('I', 'include', [], _('include names matching the given patterns')),
2937 2845 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2938 2846 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2939 2847 _('hg addremove [OPTION]... [FILE]...')),
2940 2848 "^annotate":
2941 2849 (annotate,
2942 2850 [('r', 'rev', '', _('annotate the specified revision')),
2943 2851 ('a', 'text', None, _('treat all files as text')),
2944 2852 ('u', 'user', None, _('list the author')),
2945 2853 ('d', 'date', None, _('list the date')),
2946 2854 ('n', 'number', None, _('list the revision number (default)')),
2947 2855 ('c', 'changeset', None, _('list the changeset')),
2948 2856 ('I', 'include', [], _('include names matching the given patterns')),
2949 2857 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2950 2858 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2951 2859 "archive":
2952 2860 (archive,
2953 2861 [('', 'no-decode', None, _('do not pass files through decoders')),
2954 2862 ('p', 'prefix', '', _('directory prefix for files in archive')),
2955 2863 ('r', 'rev', '', _('revision to distribute')),
2956 2864 ('t', 'type', '', _('type of distribution to create')),
2957 2865 ('I', 'include', [], _('include names matching the given patterns')),
2958 2866 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2959 2867 _('hg archive [OPTION]... DEST')),
2960 2868 "backout":
2961 2869 (backout,
2962 2870 [('', 'merge', None,
2963 2871 _('merge with old dirstate parent after backout')),
2964 2872 ('m', 'message', '', _('use <text> as commit message')),
2965 2873 ('l', 'logfile', '', _('read commit message from <file>')),
2966 2874 ('d', 'date', '', _('record datecode as commit date')),
2967 2875 ('u', 'user', '', _('record user as committer')),
2968 2876 ('I', 'include', [], _('include names matching the given patterns')),
2969 2877 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2970 2878 _('hg backout [OPTION]... REV')),
2971 2879 "bundle":
2972 2880 (bundle,
2973 2881 [('f', 'force', None,
2974 2882 _('run even when remote repository is unrelated'))],
2975 2883 _('hg bundle FILE DEST')),
2976 2884 "cat":
2977 2885 (cat,
2978 2886 [('o', 'output', '', _('print output to file with formatted name')),
2979 2887 ('r', 'rev', '', _('print the given revision')),
2980 2888 ('I', 'include', [], _('include names matching the given patterns')),
2981 2889 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2982 2890 _('hg cat [OPTION]... FILE...')),
2983 2891 "^clone":
2984 2892 (clone,
2985 2893 [('U', 'noupdate', None, _('do not update the new working directory')),
2986 2894 ('r', 'rev', [],
2987 2895 _('a changeset you would like to have after cloning')),
2988 2896 ('', 'pull', None, _('use pull protocol to copy metadata')),
2989 2897 ('e', 'ssh', '', _('specify ssh command to use')),
2990 2898 ('', 'remotecmd', '',
2991 2899 _('specify hg command to run on the remote side'))],
2992 2900 _('hg clone [OPTION]... SOURCE [DEST]')),
2993 2901 "^commit|ci":
2994 2902 (commit,
2995 2903 [('A', 'addremove', None,
2996 2904 _('mark new/missing files as added/removed before committing')),
2997 2905 ('m', 'message', '', _('use <text> as commit message')),
2998 2906 ('l', 'logfile', '', _('read the commit message from <file>')),
2999 2907 ('d', 'date', '', _('record datecode as commit date')),
3000 2908 ('u', 'user', '', _('record user as commiter')),
3001 2909 ('I', 'include', [], _('include names matching the given patterns')),
3002 2910 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3003 2911 _('hg commit [OPTION]... [FILE]...')),
3004 2912 "copy|cp":
3005 2913 (copy,
3006 2914 [('A', 'after', None, _('record a copy that has already occurred')),
3007 2915 ('f', 'force', None,
3008 2916 _('forcibly copy over an existing managed file')),
3009 2917 ('I', 'include', [], _('include names matching the given patterns')),
3010 2918 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3011 2919 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3012 2920 _('hg copy [OPTION]... [SOURCE]... DEST')),
3013 2921 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
3014 2922 "debugcomplete":
3015 2923 (debugcomplete,
3016 2924 [('o', 'options', None, _('show the command options'))],
3017 2925 _('debugcomplete [-o] CMD')),
3018 2926 "debugrebuildstate":
3019 2927 (debugrebuildstate,
3020 2928 [('r', 'rev', '', _('revision to rebuild to'))],
3021 2929 _('debugrebuildstate [-r REV] [REV]')),
3022 2930 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
3023 2931 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
3024 2932 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
3025 2933 "debugstate": (debugstate, [], _('debugstate')),
3026 2934 "debugdata": (debugdata, [], _('debugdata FILE REV')),
3027 2935 "debugindex": (debugindex, [], _('debugindex FILE')),
3028 2936 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
3029 2937 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
3030 2938 "debugwalk":
3031 2939 (debugwalk,
3032 2940 [('I', 'include', [], _('include names matching the given patterns')),
3033 2941 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3034 2942 _('debugwalk [OPTION]... [FILE]...')),
3035 2943 "^diff":
3036 2944 (diff,
3037 2945 [('r', 'rev', [], _('revision')),
3038 2946 ('a', 'text', None, _('treat all files as text')),
3039 2947 ('p', 'show-function', None,
3040 2948 _('show which function each change is in')),
3041 2949 ('w', 'ignore-all-space', None,
3042 2950 _('ignore white space when comparing lines')),
3043 2951 ('b', 'ignore-space-change', None,
3044 2952 _('ignore changes in the amount of white space')),
3045 2953 ('B', 'ignore-blank-lines', None,
3046 2954 _('ignore changes whose lines are all blank')),
3047 2955 ('I', 'include', [], _('include names matching the given patterns')),
3048 2956 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3049 2957 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
3050 2958 "^export":
3051 2959 (export,
3052 2960 [('o', 'output', '', _('print output to file with formatted name')),
3053 2961 ('a', 'text', None, _('treat all files as text')),
3054 2962 ('', 'switch-parent', None, _('diff against the second parent'))],
3055 2963 _('hg export [-a] [-o OUTFILESPEC] REV...')),
3056 2964 "debugforget|forget":
3057 2965 (forget,
3058 2966 [('I', 'include', [], _('include names matching the given patterns')),
3059 2967 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3060 2968 _('hg forget [OPTION]... FILE...')),
3061 2969 "grep":
3062 2970 (grep,
3063 2971 [('0', 'print0', None, _('end fields with NUL')),
3064 2972 ('', 'all', None, _('print all revisions that match')),
3065 2973 ('i', 'ignore-case', None, _('ignore case when matching')),
3066 2974 ('l', 'files-with-matches', None,
3067 2975 _('print only filenames and revs that match')),
3068 2976 ('n', 'line-number', None, _('print matching line numbers')),
3069 2977 ('r', 'rev', [], _('search in given revision range')),
3070 2978 ('u', 'user', None, _('print user who committed change')),
3071 2979 ('I', 'include', [], _('include names matching the given patterns')),
3072 2980 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3073 2981 _('hg grep [OPTION]... PATTERN [FILE]...')),
3074 2982 "heads":
3075 2983 (heads,
3076 2984 [('b', 'branches', None, _('show branches')),
3077 2985 ('', 'style', '', _('display using template map file')),
3078 2986 ('r', 'rev', '', _('show only heads which are descendants of rev')),
3079 2987 ('', 'template', '', _('display with template'))],
3080 2988 _('hg heads [-b] [-r <rev>]')),
3081 2989 "help": (help_, [], _('hg help [COMMAND]')),
3082 2990 "identify|id": (identify, [], _('hg identify')),
3083 2991 "import|patch":
3084 2992 (import_,
3085 2993 [('p', 'strip', 1,
3086 2994 _('directory strip option for patch. This has the same\n'
3087 2995 'meaning as the corresponding patch option')),
3088 2996 ('m', 'message', '', _('use <text> as commit message')),
3089 2997 ('b', 'base', '', _('base path')),
3090 2998 ('f', 'force', None,
3091 2999 _('skip check for outstanding uncommitted changes'))],
3092 3000 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
3093 3001 "incoming|in": (incoming,
3094 3002 [('M', 'no-merges', None, _('do not show merges')),
3095 3003 ('f', 'force', None,
3096 3004 _('run even when remote repository is unrelated')),
3097 3005 ('', 'style', '', _('display using template map file')),
3098 3006 ('n', 'newest-first', None, _('show newest record first')),
3099 3007 ('', 'bundle', '', _('file to store the bundles into')),
3100 3008 ('p', 'patch', None, _('show patch')),
3101 3009 ('r', 'rev', [], _('a specific revision you would like to pull')),
3102 3010 ('', 'template', '', _('display with template')),
3103 3011 ('e', 'ssh', '', _('specify ssh command to use')),
3104 3012 ('', 'remotecmd', '',
3105 3013 _('specify hg command to run on the remote side'))],
3106 3014 _('hg incoming [-p] [-n] [-M] [-r REV]...'
3107 3015 ' [--bundle FILENAME] [SOURCE]')),
3108 3016 "^init": (init, [], _('hg init [DEST]')),
3109 3017 "locate":
3110 3018 (locate,
3111 3019 [('r', 'rev', '', _('search the repository as it stood at rev')),
3112 3020 ('0', 'print0', None,
3113 3021 _('end filenames with NUL, for use with xargs')),
3114 3022 ('f', 'fullpath', None,
3115 3023 _('print complete paths from the filesystem root')),
3116 3024 ('I', 'include', [], _('include names matching the given patterns')),
3117 3025 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3118 3026 _('hg locate [OPTION]... [PATTERN]...')),
3119 3027 "^log|history":
3120 3028 (log,
3121 3029 [('b', 'branches', None, _('show branches')),
3122 3030 ('k', 'keyword', [], _('search for a keyword')),
3123 3031 ('l', 'limit', '', _('limit number of changes displayed')),
3124 3032 ('r', 'rev', [], _('show the specified revision or range')),
3125 3033 ('M', 'no-merges', None, _('do not show merges')),
3126 3034 ('', 'style', '', _('display using template map file')),
3127 3035 ('m', 'only-merges', None, _('show only merges')),
3128 3036 ('p', 'patch', None, _('show patch')),
3129 3037 ('', 'template', '', _('display with template')),
3130 3038 ('I', 'include', [], _('include names matching the given patterns')),
3131 3039 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3132 3040 _('hg log [OPTION]... [FILE]')),
3133 3041 "manifest": (manifest, [], _('hg manifest [REV]')),
3134 3042 "merge":
3135 3043 (merge,
3136 3044 [('b', 'branch', '', _('merge with head of a specific branch')),
3137 3045 ('f', 'force', None, _('force a merge with outstanding changes'))],
3138 3046 _('hg merge [-b TAG] [-f] [REV]')),
3139 3047 "outgoing|out": (outgoing,
3140 3048 [('M', 'no-merges', None, _('do not show merges')),
3141 3049 ('f', 'force', None,
3142 3050 _('run even when remote repository is unrelated')),
3143 3051 ('p', 'patch', None, _('show patch')),
3144 3052 ('', 'style', '', _('display using template map file')),
3145 3053 ('r', 'rev', [], _('a specific revision you would like to push')),
3146 3054 ('n', 'newest-first', None, _('show newest record first')),
3147 3055 ('', 'template', '', _('display with template')),
3148 3056 ('e', 'ssh', '', _('specify ssh command to use')),
3149 3057 ('', 'remotecmd', '',
3150 3058 _('specify hg command to run on the remote side'))],
3151 3059 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
3152 3060 "^parents":
3153 3061 (parents,
3154 3062 [('b', 'branches', None, _('show branches')),
3155 3063 ('', 'style', '', _('display using template map file')),
3156 3064 ('', 'template', '', _('display with template'))],
3157 3065 _('hg parents [-b] [REV]')),
3158 3066 "paths": (paths, [], _('hg paths [NAME]')),
3159 3067 "^pull":
3160 3068 (pull,
3161 3069 [('u', 'update', None,
3162 3070 _('update the working directory to tip after pull')),
3163 3071 ('e', 'ssh', '', _('specify ssh command to use')),
3164 3072 ('f', 'force', None,
3165 3073 _('run even when remote repository is unrelated')),
3166 3074 ('r', 'rev', [], _('a specific revision you would like to pull')),
3167 3075 ('', 'remotecmd', '',
3168 3076 _('specify hg command to run on the remote side'))],
3169 3077 _('hg pull [-u] [-e FILE] [-r REV]... [--remotecmd FILE] [SOURCE]')),
3170 3078 "^push":
3171 3079 (push,
3172 3080 [('f', 'force', None, _('force push')),
3173 3081 ('e', 'ssh', '', _('specify ssh command to use')),
3174 3082 ('r', 'rev', [], _('a specific revision you would like to push')),
3175 3083 ('', 'remotecmd', '',
3176 3084 _('specify hg command to run on the remote side'))],
3177 3085 _('hg push [-f] [-e FILE] [-r REV]... [--remotecmd FILE] [DEST]')),
3178 3086 "debugrawcommit|rawcommit":
3179 3087 (rawcommit,
3180 3088 [('p', 'parent', [], _('parent')),
3181 3089 ('d', 'date', '', _('date code')),
3182 3090 ('u', 'user', '', _('user')),
3183 3091 ('F', 'files', '', _('file list')),
3184 3092 ('m', 'message', '', _('commit message')),
3185 3093 ('l', 'logfile', '', _('commit message file'))],
3186 3094 _('hg debugrawcommit [OPTION]... [FILE]...')),
3187 3095 "recover": (recover, [], _('hg recover')),
3188 3096 "^remove|rm":
3189 3097 (remove,
3190 3098 [('A', 'after', None, _('record remove that has already occurred')),
3191 3099 ('f', 'force', None, _('remove file even if modified')),
3192 3100 ('I', 'include', [], _('include names matching the given patterns')),
3193 3101 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3194 3102 _('hg remove [OPTION]... FILE...')),
3195 3103 "rename|mv":
3196 3104 (rename,
3197 3105 [('A', 'after', None, _('record a rename that has already occurred')),
3198 3106 ('f', 'force', None,
3199 3107 _('forcibly copy over an existing managed file')),
3200 3108 ('I', 'include', [], _('include names matching the given patterns')),
3201 3109 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3202 3110 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3203 3111 _('hg rename [OPTION]... SOURCE... DEST')),
3204 3112 "^revert":
3205 3113 (revert,
3206 3114 [('r', 'rev', '', _('revision to revert to')),
3207 3115 ('', 'no-backup', None, _('do not save backup copies of files')),
3208 3116 ('I', 'include', [], _('include names matching given patterns')),
3209 3117 ('X', 'exclude', [], _('exclude names matching given patterns')),
3210 3118 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3211 3119 _('hg revert [-r REV] [NAME]...')),
3212 3120 "rollback": (rollback, [], _('hg rollback')),
3213 3121 "root": (root, [], _('hg root')),
3214 3122 "^serve":
3215 3123 (serve,
3216 3124 [('A', 'accesslog', '', _('name of access log file to write to')),
3217 3125 ('d', 'daemon', None, _('run server in background')),
3218 3126 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3219 3127 ('E', 'errorlog', '', _('name of error log file to write to')),
3220 3128 ('p', 'port', 0, _('port to use (default: 8000)')),
3221 3129 ('a', 'address', '', _('address to use')),
3222 3130 ('n', 'name', '',
3223 3131 _('name to show in web pages (default: working dir)')),
3224 3132 ('', 'webdir-conf', '', _('name of the webdir config file'
3225 3133 ' (serve more than one repo)')),
3226 3134 ('', 'pid-file', '', _('name of file to write process ID to')),
3227 3135 ('', 'stdio', None, _('for remote clients')),
3228 3136 ('t', 'templates', '', _('web templates to use')),
3229 3137 ('', 'style', '', _('template style to use')),
3230 3138 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3231 3139 _('hg serve [OPTION]...')),
3232 3140 "^status|st":
3233 3141 (status,
3234 3142 [('m', 'modified', None, _('show only modified files')),
3235 3143 ('a', 'added', None, _('show only added files')),
3236 3144 ('r', 'removed', None, _('show only removed files')),
3237 3145 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3238 3146 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3239 3147 ('i', 'ignored', None, _('show ignored files')),
3240 3148 ('n', 'no-status', None, _('hide status prefix')),
3241 3149 ('0', 'print0', None,
3242 3150 _('end filenames with NUL, for use with xargs')),
3243 3151 ('I', 'include', [], _('include names matching the given patterns')),
3244 3152 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3245 3153 _('hg status [OPTION]... [FILE]...')),
3246 3154 "tag":
3247 3155 (tag,
3248 3156 [('l', 'local', None, _('make the tag local')),
3249 3157 ('m', 'message', '', _('message for tag commit log entry')),
3250 3158 ('d', 'date', '', _('record datecode as commit date')),
3251 3159 ('u', 'user', '', _('record user as commiter')),
3252 3160 ('r', 'rev', '', _('revision to tag'))],
3253 3161 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3254 3162 "tags": (tags, [], _('hg tags')),
3255 3163 "tip":
3256 3164 (tip,
3257 3165 [('b', 'branches', None, _('show branches')),
3258 3166 ('', 'style', '', _('display using template map file')),
3259 3167 ('p', 'patch', None, _('show patch')),
3260 3168 ('', 'template', '', _('display with template'))],
3261 3169 _('hg tip [-b] [-p]')),
3262 3170 "unbundle":
3263 3171 (unbundle,
3264 3172 [('u', 'update', None,
3265 3173 _('update the working directory to tip after unbundle'))],
3266 3174 _('hg unbundle [-u] FILE')),
3267 3175 "debugundo|undo": (undo, [], _('hg undo')),
3268 3176 "^update|up|checkout|co":
3269 3177 (update,
3270 3178 [('b', 'branch', '', _('checkout the head of a specific branch')),
3271 3179 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3272 3180 ('C', 'clean', None, _('overwrite locally modified files')),
3273 3181 ('f', 'force', None, _('force a merge with outstanding changes'))],
3274 3182 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3275 3183 "verify": (verify, [], _('hg verify')),
3276 3184 "version": (show_version, [], _('hg version')),
3277 3185 }
3278 3186
3279 3187 globalopts = [
3280 3188 ('R', 'repository', '',
3281 3189 _('repository root directory or symbolic path name')),
3282 3190 ('', 'cwd', '', _('change working directory')),
3283 3191 ('y', 'noninteractive', None,
3284 3192 _('do not prompt, assume \'yes\' for any required answers')),
3285 3193 ('q', 'quiet', None, _('suppress output')),
3286 3194 ('v', 'verbose', None, _('enable additional output')),
3287 3195 ('', 'config', [], _('set/override config option')),
3288 3196 ('', 'debug', None, _('enable debugging output')),
3289 3197 ('', 'debugger', None, _('start debugger')),
3290 3198 ('', 'lsprof', None, _('print improved command execution profile')),
3291 3199 ('', 'traceback', None, _('print traceback on exception')),
3292 3200 ('', 'time', None, _('time how long the command takes')),
3293 3201 ('', 'profile', None, _('print command execution profile')),
3294 3202 ('', 'version', None, _('output version information and exit')),
3295 3203 ('h', 'help', None, _('display help and exit')),
3296 3204 ]
3297 3205
3298 3206 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3299 3207 " debugindex debugindexdot")
3300 3208 optionalrepo = ("paths serve debugconfig")
3301 3209
3302 3210 def findpossible(cmd):
3303 3211 """
3304 3212 Return cmd -> (aliases, command table entry)
3305 3213 for each matching command.
3306 3214 Return debug commands (or their aliases) only if no normal command matches.
3307 3215 """
3308 3216 choice = {}
3309 3217 debugchoice = {}
3310 3218 for e in table.keys():
3311 3219 aliases = e.lstrip("^").split("|")
3312 3220 found = None
3313 3221 if cmd in aliases:
3314 3222 found = cmd
3315 3223 else:
3316 3224 for a in aliases:
3317 3225 if a.startswith(cmd):
3318 3226 found = a
3319 3227 break
3320 3228 if found is not None:
3321 3229 if aliases[0].startswith("debug"):
3322 3230 debugchoice[found] = (aliases, table[e])
3323 3231 else:
3324 3232 choice[found] = (aliases, table[e])
3325 3233
3326 3234 if not choice and debugchoice:
3327 3235 choice = debugchoice
3328 3236
3329 3237 return choice
3330 3238
3331 3239 def findcmd(cmd):
3332 3240 """Return (aliases, command table entry) for command string."""
3333 3241 choice = findpossible(cmd)
3334 3242
3335 3243 if choice.has_key(cmd):
3336 3244 return choice[cmd]
3337 3245
3338 3246 if len(choice) > 1:
3339 3247 clist = choice.keys()
3340 3248 clist.sort()
3341 3249 raise AmbiguousCommand(cmd, clist)
3342 3250
3343 3251 if choice:
3344 3252 return choice.values()[0]
3345 3253
3346 3254 raise UnknownCommand(cmd)
3347 3255
3348 3256 def catchterm(*args):
3349 3257 raise util.SignalInterrupt
3350 3258
3351 3259 def run():
3352 3260 sys.exit(dispatch(sys.argv[1:]))
3353 3261
3354 3262 class ParseError(Exception):
3355 3263 """Exception raised on errors in parsing the command line."""
3356 3264
3357 3265 def parse(ui, args):
3358 3266 options = {}
3359 3267 cmdoptions = {}
3360 3268
3361 3269 try:
3362 3270 args = fancyopts.fancyopts(args, globalopts, options)
3363 3271 except fancyopts.getopt.GetoptError, inst:
3364 3272 raise ParseError(None, inst)
3365 3273
3366 3274 if args:
3367 3275 cmd, args = args[0], args[1:]
3368 3276 aliases, i = findcmd(cmd)
3369 3277 cmd = aliases[0]
3370 3278 defaults = ui.config("defaults", cmd)
3371 3279 if defaults:
3372 3280 args = defaults.split() + args
3373 3281 c = list(i[1])
3374 3282 else:
3375 3283 cmd = None
3376 3284 c = []
3377 3285
3378 3286 # combine global options into local
3379 3287 for o in globalopts:
3380 3288 c.append((o[0], o[1], options[o[1]], o[3]))
3381 3289
3382 3290 try:
3383 3291 args = fancyopts.fancyopts(args, c, cmdoptions)
3384 3292 except fancyopts.getopt.GetoptError, inst:
3385 3293 raise ParseError(cmd, inst)
3386 3294
3387 3295 # separate global options back out
3388 3296 for o in globalopts:
3389 3297 n = o[1]
3390 3298 options[n] = cmdoptions[n]
3391 3299 del cmdoptions[n]
3392 3300
3393 3301 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3394 3302
3395 3303 external = {}
3396 3304
3397 3305 def findext(name):
3398 3306 '''return module with given extension name'''
3399 3307 try:
3400 3308 return sys.modules[external[name]]
3401 3309 except KeyError:
3402 3310 dotname = '.' + name
3403 3311 for k, v in external.iteritems():
3404 3312 if k.endswith('.' + name) or v == name:
3405 3313 return sys.modules[v]
3406 3314 raise KeyError(name)
3407 3315
3408 3316 def dispatch(args):
3409 3317 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3410 3318 num = getattr(signal, name, None)
3411 3319 if num: signal.signal(num, catchterm)
3412 3320
3413 3321 try:
3414 3322 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3415 3323 except util.Abort, inst:
3416 3324 sys.stderr.write(_("abort: %s\n") % inst)
3417 3325 return -1
3418 3326
3419 3327 for ext_name, load_from_name in u.extensions():
3420 3328 try:
3421 3329 if load_from_name:
3422 3330 # the module will be loaded in sys.modules
3423 3331 # choose an unique name so that it doesn't
3424 3332 # conflicts with other modules
3425 3333 module_name = "hgext_%s" % ext_name.replace('.', '_')
3426 3334 mod = imp.load_source(module_name, load_from_name)
3427 3335 else:
3428 3336 def importh(name):
3429 3337 mod = __import__(name)
3430 3338 components = name.split('.')
3431 3339 for comp in components[1:]:
3432 3340 mod = getattr(mod, comp)
3433 3341 return mod
3434 3342 try:
3435 3343 mod = importh("hgext.%s" % ext_name)
3436 3344 except ImportError:
3437 3345 mod = importh(ext_name)
3438 3346 external[ext_name] = mod.__name__
3439 3347 except (util.SignalInterrupt, KeyboardInterrupt):
3440 3348 raise
3441 3349 except Exception, inst:
3442 3350 u.warn(_("*** failed to import extension %s: %s\n") % (x[0], inst))
3443 3351 if u.print_exc():
3444 3352 return 1
3445 3353
3446 3354 for name in external.itervalues():
3447 3355 mod = sys.modules[name]
3448 3356 uisetup = getattr(mod, 'uisetup', None)
3449 3357 if uisetup:
3450 3358 uisetup(u)
3451 3359 cmdtable = getattr(mod, 'cmdtable', {})
3452 3360 for t in cmdtable:
3453 3361 if t in table:
3454 3362 u.warn(_("module %s overrides %s\n") % (name, t))
3455 3363 table.update(cmdtable)
3456 3364
3457 3365 try:
3458 3366 cmd, func, args, options, cmdoptions = parse(u, args)
3459 3367 if options["time"]:
3460 3368 def get_times():
3461 3369 t = os.times()
3462 3370 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3463 3371 t = (t[0], t[1], t[2], t[3], time.clock())
3464 3372 return t
3465 3373 s = get_times()
3466 3374 def print_time():
3467 3375 t = get_times()
3468 3376 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3469 3377 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3470 3378 atexit.register(print_time)
3471 3379
3472 3380 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3473 3381 not options["noninteractive"], options["traceback"],
3474 3382 options["config"])
3475 3383
3476 3384 # enter the debugger before command execution
3477 3385 if options['debugger']:
3478 3386 pdb.set_trace()
3479 3387
3480 3388 try:
3481 3389 if options['cwd']:
3482 3390 try:
3483 3391 os.chdir(options['cwd'])
3484 3392 except OSError, inst:
3485 3393 raise util.Abort('%s: %s' %
3486 3394 (options['cwd'], inst.strerror))
3487 3395
3488 3396 path = u.expandpath(options["repository"]) or ""
3489 3397 repo = path and hg.repository(u, path=path) or None
3490 3398
3491 3399 if options['help']:
3492 3400 return help_(u, cmd, options['version'])
3493 3401 elif options['version']:
3494 3402 return show_version(u)
3495 3403 elif not cmd:
3496 3404 return help_(u, 'shortlist')
3497 3405
3498 3406 if cmd not in norepo.split():
3499 3407 try:
3500 3408 if not repo:
3501 3409 repo = hg.repository(u, path=path)
3502 3410 u = repo.ui
3503 3411 for name in external.itervalues():
3504 3412 mod = sys.modules[name]
3505 3413 if hasattr(mod, 'reposetup'):
3506 3414 mod.reposetup(u, repo)
3507 3415 except hg.RepoError:
3508 3416 if cmd not in optionalrepo.split():
3509 3417 raise
3510 3418 d = lambda: func(u, repo, *args, **cmdoptions)
3511 3419 else:
3512 3420 d = lambda: func(u, *args, **cmdoptions)
3513 3421
3514 3422 try:
3515 3423 if options['profile']:
3516 3424 import hotshot, hotshot.stats
3517 3425 prof = hotshot.Profile("hg.prof")
3518 3426 try:
3519 3427 try:
3520 3428 return prof.runcall(d)
3521 3429 except:
3522 3430 try:
3523 3431 u.warn(_('exception raised - generating '
3524 3432 'profile anyway\n'))
3525 3433 except:
3526 3434 pass
3527 3435 raise
3528 3436 finally:
3529 3437 prof.close()
3530 3438 stats = hotshot.stats.load("hg.prof")
3531 3439 stats.strip_dirs()
3532 3440 stats.sort_stats('time', 'calls')
3533 3441 stats.print_stats(40)
3534 3442 elif options['lsprof']:
3535 3443 try:
3536 3444 from mercurial import lsprof
3537 3445 except ImportError:
3538 3446 raise util.Abort(_(
3539 3447 'lsprof not available - install from '
3540 3448 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3541 3449 p = lsprof.Profiler()
3542 3450 p.enable(subcalls=True)
3543 3451 try:
3544 3452 return d()
3545 3453 finally:
3546 3454 p.disable()
3547 3455 stats = lsprof.Stats(p.getstats())
3548 3456 stats.sort()
3549 3457 stats.pprint(top=10, file=sys.stderr, climit=5)
3550 3458 else:
3551 3459 return d()
3552 3460 finally:
3553 3461 u.flush()
3554 3462 except:
3555 3463 # enter the debugger when we hit an exception
3556 3464 if options['debugger']:
3557 3465 pdb.post_mortem(sys.exc_info()[2])
3558 3466 u.print_exc()
3559 3467 raise
3560 3468 except ParseError, inst:
3561 3469 if inst.args[0]:
3562 3470 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3563 3471 help_(u, inst.args[0])
3564 3472 else:
3565 3473 u.warn(_("hg: %s\n") % inst.args[1])
3566 3474 help_(u, 'shortlist')
3567 3475 except AmbiguousCommand, inst:
3568 3476 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3569 3477 (inst.args[0], " ".join(inst.args[1])))
3570 3478 except UnknownCommand, inst:
3571 3479 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3572 3480 help_(u, 'shortlist')
3573 3481 except hg.RepoError, inst:
3574 3482 u.warn(_("abort: %s!\n") % inst)
3575 3483 except lock.LockHeld, inst:
3576 3484 if inst.errno == errno.ETIMEDOUT:
3577 3485 reason = _('timed out waiting for lock held by %s') % inst.locker
3578 3486 else:
3579 3487 reason = _('lock held by %s') % inst.locker
3580 3488 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3581 3489 except lock.LockUnavailable, inst:
3582 3490 u.warn(_("abort: could not lock %s: %s\n") %
3583 3491 (inst.desc or inst.filename, inst.strerror))
3584 3492 except revlog.RevlogError, inst:
3585 3493 u.warn(_("abort: "), inst, "!\n")
3586 3494 except util.SignalInterrupt:
3587 3495 u.warn(_("killed!\n"))
3588 3496 except KeyboardInterrupt:
3589 3497 try:
3590 3498 u.warn(_("interrupted!\n"))
3591 3499 except IOError, inst:
3592 3500 if inst.errno == errno.EPIPE:
3593 3501 if u.debugflag:
3594 3502 u.warn(_("\nbroken pipe\n"))
3595 3503 else:
3596 3504 raise
3597 3505 except IOError, inst:
3598 3506 if hasattr(inst, "code"):
3599 3507 u.warn(_("abort: %s\n") % inst)
3600 3508 elif hasattr(inst, "reason"):
3601 3509 u.warn(_("abort: error: %s\n") % inst.reason[1])
3602 3510 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3603 3511 if u.debugflag:
3604 3512 u.warn(_("broken pipe\n"))
3605 3513 elif getattr(inst, "strerror", None):
3606 3514 if getattr(inst, "filename", None):
3607 3515 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3608 3516 else:
3609 3517 u.warn(_("abort: %s\n") % inst.strerror)
3610 3518 else:
3611 3519 raise
3612 3520 except OSError, inst:
3613 3521 if hasattr(inst, "filename"):
3614 3522 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3615 3523 else:
3616 3524 u.warn(_("abort: %s\n") % inst.strerror)
3617 3525 except util.Abort, inst:
3618 3526 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3619 3527 except TypeError, inst:
3620 3528 # was this an argument error?
3621 3529 tb = traceback.extract_tb(sys.exc_info()[2])
3622 3530 if len(tb) > 2: # no
3623 3531 raise
3624 3532 u.debug(inst, "\n")
3625 3533 u.warn(_("%s: invalid arguments\n") % cmd)
3626 3534 help_(u, cmd)
3627 3535 except SystemExit, inst:
3628 3536 # Commands shouldn't sys.exit directly, but give a return code.
3629 3537 # Just in case catch this and and pass exit code to caller.
3630 3538 return inst.code
3631 3539 except:
3632 3540 u.warn(_("** unknown exception encountered, details follow\n"))
3633 3541 u.warn(_("** report bug details to mercurial@selenic.com\n"))
3634 3542 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3635 3543 % version.get_version())
3636 3544 raise
3637 3545
3638 3546 return -1
@@ -1,75 +1,205 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 from node import *
9 9 from repo import *
10 10 from demandload import *
11 11 from i18n import gettext as _
12 12 demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo")
13 demandload(globals(), "os util")
13 demandload(globals(), "errno lock os shutil util")
14 14
15 15 def bundle(ui, path):
16 16 if path.startswith('bundle://'):
17 17 path = path[9:]
18 18 else:
19 19 path = path[7:]
20 20 s = path.split("+", 1)
21 21 if len(s) == 1:
22 22 repopath, bundlename = "", s[0]
23 23 else:
24 24 repopath, bundlename = s
25 25 return bundlerepo.bundlerepository(ui, repopath, bundlename)
26 26
27 27 def hg(ui, path):
28 28 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
29 29 return httprepo.httprepository(ui, path.replace("hg://", "http://"))
30 30
31 31 def local_(ui, path, create=0):
32 32 if path.startswith('file:'):
33 33 path = path[5:]
34 34 return localrepo.localrepository(ui, path, create)
35 35
36 36 def ssh_(ui, path, create=0):
37 37 return sshrepo.sshrepository(ui, path, create)
38 38
39 39 def old_http(ui, path):
40 40 ui.warn(_("old-http:// syntax is deprecated, "
41 41 "please use static-http:// instead\n"))
42 42 return statichttprepo.statichttprepository(
43 43 ui, path.replace("old-http://", "http://"))
44 44
45 45 def static_http(ui, path):
46 46 return statichttprepo.statichttprepository(
47 47 ui, path.replace("static-http://", "http://"))
48 48
49 49 schemes = {
50 50 'bundle': bundle,
51 51 'file': local_,
52 52 'hg': hg,
53 53 'http': lambda ui, path: httprepo.httprepository(ui, path),
54 54 'https': lambda ui, path: httprepo.httpsrepository(ui, path),
55 55 'old-http': old_http,
56 56 'ssh': ssh_,
57 57 'static-http': static_http,
58 58 }
59 59
60 60 def repository(ui, path=None, create=0):
61 61 scheme = None
62 62 if path:
63 63 c = path.find(':')
64 64 if c > 0:
65 65 scheme = schemes.get(path[:c])
66 66 else:
67 67 path = ''
68 68 ctor = scheme or schemes['file']
69 69 if create:
70 70 try:
71 71 return ctor(ui, path, create)
72 72 except TypeError:
73 73 raise util.Abort(_('cannot create new repository over "%s" protocol') %
74 74 scheme)
75 75 return ctor(ui, path)
76
77 def clone(ui, source, dest=None, pull=False, rev=None, update=True):
78 """Make a copy of an existing repository.
79
80 Create a copy of an existing repository in a new directory. The
81 source and destination are URLs, as passed to the repository
82 function. Returns a pair of repository objects, the source and
83 newly created destination.
84
85 The location of the source is added to the new repository's
86 .hg/hgrc file, as the default to be used for future pulls and
87 pushes.
88
89 If an exception is raised, the partly cloned/updated destination
90 repository will be deleted.
91
92 Keyword arguments:
93
94 dest: URL of destination repository to create (defaults to base
95 name of source repository)
96
97 pull: always pull from source repository, even in local case
98
99 rev: revision to clone up to (implies pull=True)
100
101 update: update working directory after clone completes, if
102 destination is local repository
103 """
104 if dest is None:
105 dest = os.path.basename(os.path.normpath(source))
106
107 if os.path.exists(dest):
108 raise util.Abort(_("destination '%s' already exists"), dest)
109
110 class DirCleanup(object):
111 def __init__(self, dir_):
112 self.rmtree = shutil.rmtree
113 self.dir_ = dir_
114 def close(self):
115 self.dir_ = None
116 def __del__(self):
117 if self.dir_:
118 self.rmtree(self.dir_, True)
119
120 src_repo = repository(ui, source)
121
122 dest_repo = None
123 try:
124 dest_repo = repository(ui, dest)
125 raise util.Abort(_("destination '%s' already exists." % dest))
126 except RepoError:
127 dest_repo = repository(ui, dest, create=True)
128
129 dest_path = None
130 dir_cleanup = None
131 if dest_repo.local():
132 dest_path = os.path.realpath(dest)
133 dir_cleanup = DirCleanup(dest_path)
134
135 abspath = source
136 copy = False
137 if src_repo.local() and dest_repo.local():
138 abspath = os.path.abspath(source)
139 copy = not pull and not rev
140
141 src_lock, dest_lock = None, None
142 if copy:
143 try:
144 # we use a lock here because if we race with commit, we
145 # can end up with extra data in the cloned revlogs that's
146 # not pointed to by changesets, thus causing verify to
147 # fail
148 src_lock = src_repo.lock()
149 except lock.LockException:
150 copy = False
151
152 if copy:
153 # we lock here to avoid premature writing to the target
154 dest_lock = lock.lock(os.path.join(dest_path, ".hg", "lock"))
155
156 # we need to remove the (empty) data dir in dest so copyfiles
157 # can do its work
158 os.rmdir(os.path.join(dest_path, ".hg", "data"))
159 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
160 for f in files.split():
161 src = os.path.join(source, ".hg", f)
162 dst = os.path.join(dest_path, ".hg", f)
163 try:
164 util.copyfiles(src, dst)
165 except OSError, inst:
166 if inst.errno != errno.ENOENT:
167 raise
168
169 # we need to re-init the repo after manually copying the data
170 # into it
171 dest_repo = repository(ui, dest)
172
173 else:
174 revs = None
175 if rev:
176 if not src_repo.local():
177 raise util.Abort(_("clone by revision not supported yet "
178 "for remote repositories"))
179 revs = [src_repo.lookup(r) for r in rev]
180
181 if dest_repo.local():
182 dest_repo.pull(src_repo, heads=revs)
183 elif src_repo.local():
184 src_repo.push(dest_repo, revs=revs)
185 else:
186 raise util.Abort(_("clone from remote to remote not supported"))
187
188 if src_lock:
189 src_lock.release()
190
191 if dest_repo.local():
192 fp = dest_repo.opener("hgrc", "w", text=True)
193 fp.write("[paths]\n")
194 fp.write("default = %s\n" % abspath)
195 fp.close()
196
197 if dest_lock:
198 dest_lock.release()
199
200 if update:
201 dest_repo.update(dest_repo.changelog.tip())
202 if dir_cleanup:
203 dir_cleanup.close()
204
205 return src_repo, dest_repo
General Comments 0
You need to be logged in to leave comments. Login now