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