mercurial/commands.py
changeset 697 cb1be2327220
parent 696 b266e92bcd0b
child 698 df78d8ccac4c
equal deleted inserted replaced
696:b266e92bcd0b 697:cb1be2327220
     3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
     3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
     4 #
     4 #
     5 # This software may be used and distributed according to the terms
     5 # This software may be used and distributed according to the terms
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 from demandload import *
     8 from demandload import demandload
     9 demandload(globals(), "os re sys signal")
     9 demandload(globals(), "os re sys signal")
    10 demandload(globals(), "fancyopts ui hg util")
    10 demandload(globals(), "fancyopts ui hg util")
    11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
    11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
    12 demandload(globals(), "errno socket version struct")
    12 demandload(globals(), "errno socket version struct")
    13 
    13 
    14 class UnknownCommand(Exception): pass
    14 class UnknownCommand(Exception):
       
    15     """Exception raised if command is not in the command table."""
    15 
    16 
    16 def filterfiles(filters, files):
    17 def filterfiles(filters, files):
    17     l = [ x for x in files if x in filters ]
    18     l = [x for x in files if x in filters]
    18 
    19 
    19     for t in filters:
    20     for t in filters:
    20         if t and t[-1] != "/": t += "/"
    21         if t and t[-1] != "/":
    21         l += [ x for x in files if x.startswith(t) ]
    22             t += "/"
       
    23         l += [x for x in files if x.startswith(t)]
    22     return l
    24     return l
    23 
    25 
    24 def relfilter(repo, files):
    26 def relfilter(repo, files):
    25     cwd = repo.getcwd()
    27     cwd = repo.getcwd()
    26     if cwd:
    28     if cwd:
    28     return files
    30     return files
    29 
    31 
    30 def relpath(repo, args):
    32 def relpath(repo, args):
    31     cwd = repo.getcwd()
    33     cwd = repo.getcwd()
    32     if cwd:
    34     if cwd:
    33         return [ util.pconvert(os.path.normpath(os.path.join(cwd, x))) for x in args ]
    35         return [util.pconvert(os.path.normpath(os.path.join(cwd, x)))
       
    36                 for x in args]
    34     return args
    37     return args
    35 
    38 
    36 revrangesep = ':'
    39 revrangesep = ':'
    37 
    40 
    38 def revrange(ui, repo, revs = [], revlog = None):
    41 def revrange(ui, repo, revs, revlog=None):
    39     if revlog is None:
    42     if revlog is None:
    40         revlog = repo.changelog
    43         revlog = repo.changelog
    41     revcount = revlog.count()
    44     revcount = revlog.count()
    42     def fix(val, defval):
    45     def fix(val, defval):
    43         if not val: return defval
    46         if not val:
       
    47             return defval
    44         try:
    48         try:
    45             num = int(val)
    49             num = int(val)
    46             if str(num) != val: raise ValueError
    50             if str(num) != val:
    47             if num < 0: num += revcount
    51                 raise ValueError
       
    52             if num < 0:
       
    53                 num += revcount
    48             if not (0 <= num < revcount):
    54             if not (0 <= num < revcount):
    49                 raise ValueError
    55                 raise ValueError
    50         except ValueError:
    56         except ValueError:
    51             try:
    57             try:
    52                 num = repo.changelog.rev(repo.lookup(val))
    58                 num = repo.changelog.rev(repo.lookup(val))
    83     expander = {
    89     expander = {
    84         '%': lambda: '%',
    90         '%': lambda: '%',
    85         'b': lambda: os.path.basename(repo.root),
    91         'b': lambda: os.path.basename(repo.root),
    86         }
    92         }
    87 
    93 
    88     if node: expander.update(node_expander)
    94     if node:
       
    95         expander.update(node_expander)
    89     if node and revwidth is not None:
    96     if node and revwidth is not None:
    90         expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
    97         expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
    91     if total is not None: expander['N'] = lambda: str(total)
    98     if total is not None:
    92     if seqno is not None: expander['n'] = lambda: str(seqno)
    99         expander['N'] = lambda: str(total)
       
   100     if seqno is not None:
       
   101         expander['n'] = lambda: str(seqno)
    93     if total is not None and seqno is not None:
   102     if total is not None and seqno is not None:
    94         expander['n'] = lambda:str(seqno).zfill(len(str(total)))
   103         expander['n'] = lambda:str(seqno).zfill(len(str(total)))
    95 
   104 
    96     newname = []
   105     newname = []
    97     patlen = len(pat)
   106     patlen = len(pat)
   118         return
   127         return
   119 
   128 
   120     if node2:
   129     if node2:
   121         change = repo.changelog.read(node2)
   130         change = repo.changelog.read(node2)
   122         mmap2 = repo.manifest.read(change[0])
   131         mmap2 = repo.manifest.read(change[0])
   123         def read(f): return repo.file(f).read(mmap2[f])
       
   124         date2 = date(change)
   132         date2 = date(change)
       
   133         def read(f):
       
   134             return repo.file(f).read(mmap2[f])
   125     else:
   135     else:
   126         date2 = time.asctime()
   136         date2 = time.asctime()
   127         if not node1:
   137         if not node1:
   128             node1 = repo.dirstate.parents()[0]
   138             node1 = repo.dirstate.parents()[0]
   129         def read(f): return repo.wfile(f).read()
   139         def read(f):
       
   140             return repo.wfile(f).read()
   130 
   141 
   131     if ui.quiet:
   142     if ui.quiet:
   132         r = None
   143         r = None
   133     else:
   144     else:
   134         hexfunc = ui.verbose and hg.hex or hg.short
   145         hexfunc = ui.verbose and hg.hex or hg.short
   220         "This is free software; see the source for copying conditions. "
   231         "This is free software; see the source for copying conditions. "
   221         "There is NO\nwarranty; "
   232         "There is NO\nwarranty; "
   222         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
   233         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
   223     )
   234     )
   224 
   235 
   225 def help(ui, cmd=None):
   236 def help_(ui, cmd=None):
   226     '''show help for a given command or all commands'''
   237     """show help for a given command or all commands"""
   227     if cmd:
   238     if cmd:
   228         try:
   239         try:
   229             i = find(cmd)
   240             i = find(cmd)
   230             ui.write("%s\n\n" % i[2])
   241             ui.write("%s\n\n" % i[2])
   231 
   242 
   232             if i[1]:
   243             if i[1]:
   233                 for s, l, d, c in i[1]:
   244                 for s, l, d, c in i[1]:
   234                     opt=' '
   245                     opt = ' '
   235                     if s: opt = opt + '-' + s + ' '
   246                     if s:
   236                     if l: opt = opt + '--' + l + ' '
   247                         opt = opt + '-' + s + ' '
   237                     if d: opt = opt + '(' + str(d) + ')'
   248                     if l:
       
   249                         opt = opt + '--' + l + ' '
       
   250                     if d:
       
   251                         opt = opt + '(' + str(d) + ')'
   238                     ui.write(opt, "\n")
   252                     ui.write(opt, "\n")
   239                     if c: ui.write('   %s\n' % c)
   253                     if c:
       
   254                         ui.write('   %s\n' % c)
   240                 ui.write("\n")
   255                 ui.write("\n")
   241 
   256 
   242             ui.write(i[0].__doc__, "\n")
   257             ui.write(i[0].__doc__, "\n")
   243         except UnknownCommand:
   258         except UnknownCommand:
   244             ui.warn("hg: unknown command %s\n" % cmd)
   259             ui.warn("hg: unknown command %s\n" % cmd)
   271         for f in fns:
   286         for f in fns:
   272             ui.write(' %-*s   %s\n' % (m, f, h[f]))
   287             ui.write(' %-*s   %s\n' % (m, f, h[f]))
   273 
   288 
   274 # Commands start here, listed alphabetically
   289 # Commands start here, listed alphabetically
   275 
   290 
   276 def add(ui, repo, file, *files):
   291 def add(ui, repo, file1, *files):
   277     '''add the specified files on the next commit'''
   292     '''add the specified files on the next commit'''
   278     repo.add(relpath(repo, (file,) + files))
   293     repo.add(relpath(repo, (file1,) + files))
   279 
   294 
   280 def addremove(ui, repo, *files):
   295 def addremove(ui, repo, *files):
   281     """add all new files, delete all missing files"""
   296     """add all new files, delete all missing files"""
   282     if files:
   297     if files:
   283         files = relpath(repo, files)
   298         files = relpath(repo, files)
   294     else:
   309     else:
   295         (c, a, d, u) = repo.changes(None, None)
   310         (c, a, d, u) = repo.changes(None, None)
   296     repo.add(u)
   311     repo.add(u)
   297     repo.remove(d)
   312     repo.remove(d)
   298 
   313 
   299 def annotate(u, repo, file, *files, **ops):
   314 def annotate(u, repo, file1, *files, **ops):
   300     """show changeset information per file line"""
   315     """show changeset information per file line"""
   301     def getnode(rev):
   316     def getnode(rev):
   302         return hg.short(repo.changelog.node(rev))
   317         return hg.short(repo.changelog.node(rev))
   303 
   318 
   304     def getname(rev):
   319     def getname(rev):
   324     node = repo.dirstate.parents()[0]
   339     node = repo.dirstate.parents()[0]
   325     if ops['revision']:
   340     if ops['revision']:
   326         node = repo.changelog.lookup(ops['revision'])
   341         node = repo.changelog.lookup(ops['revision'])
   327     change = repo.changelog.read(node)
   342     change = repo.changelog.read(node)
   328     mmap = repo.manifest.read(change[0])
   343     mmap = repo.manifest.read(change[0])
   329     for f in relpath(repo, (file,) + files):
   344     for f in relpath(repo, (file1,) + files):
   330         lines = repo.file(f).annotate(mmap[f])
   345         lines = repo.file(f).annotate(mmap[f])
   331         pieces = []
   346         pieces = []
   332 
   347 
   333         for o, f in opmap:
   348         for o, f in opmap:
   334             if ops[o]:
   349             if ops[o]:
   335                 l = [ f(n) for n,t in lines ]
   350                 l = [f(n) for n, dummy in lines]
   336                 m = max(map(len, l))
   351                 m = max(map(len, l))
   337                 pieces.append([ "%*s" % (m, x) for x in l])
   352                 pieces.append(["%*s" % (m, x) for x in l])
   338 
   353 
   339         for p,l in zip(zip(*pieces), lines):
   354         for p, l in zip(zip(*pieces), lines):
   340             u.write(" ".join(p) + ": " + l[1])
   355             u.write(" ".join(p) + ": " + l[1])
   341 
   356 
   342 def cat(ui, repo, file, rev = [], **opts):
   357 def cat(ui, repo, file1, rev=None, **opts):
   343     """output the latest or given revision of a file"""
   358     """output the latest or given revision of a file"""
   344     r = repo.file(relpath(repo, [file])[0])
   359     r = repo.file(relpath(repo, [file1])[0])
   345     n = r.tip()
   360     if rev:
   346     if rev: n = r.lookup(rev)
   361         n = r.lookup(rev)
       
   362     else:
       
   363         n = r.tip()
   347     if opts['output'] and opts['output'] != '-':
   364     if opts['output'] and opts['output'] != '-':
   348         try:
   365         try:
   349             outname = make_filename(repo, r, opts['output'], node=n)
   366             outname = make_filename(repo, r, opts['output'], node=n)
   350             fp = open(outname, 'wb')
   367             fp = open(outname, 'wb')
   351         except KeyError, inst:
   368         except KeyError, inst:
   363 
   380 
   364     if os.path.exists(dest):
   381     if os.path.exists(dest):
   365         ui.warn("abort: destination '%s' already exists\n" % dest)
   382         ui.warn("abort: destination '%s' already exists\n" % dest)
   366         return 1
   383         return 1
   367 
   384 
   368     class dircleanup:
   385     class Dircleanup:
   369         def __init__(self, dir):
   386         def __init__(self, dir_):
   370             import shutil
   387             import shutil
   371             self.rmtree = shutil.rmtree
   388             self.rmtree = shutil.rmtree
   372             self.dir = dir
   389             self.dir_ = dir_
   373             os.mkdir(dir)
   390             os.mkdir(dir_)
   374         def close(self):
   391         def close(self):
   375             self.dir = None
   392             self.dir_ = None
   376         def __del__(self):
   393         def __del__(self):
   377             if self.dir:
   394             if self.dir_:
   378                 self.rmtree(self.dir, True)
   395                 self.rmtree(self.dir_, True)
   379 
   396 
   380     d = dircleanup(dest)
   397     d = Dircleanup(dest)
   381     link = 0
       
   382     abspath = source
   398     abspath = source
   383     source = ui.expandpath(source)
   399     source = ui.expandpath(source)
   384     other = hg.repository(ui, source)
   400     other = hg.repository(ui, source)
   385 
   401 
   386     if other.dev() != -1:
   402     if other.dev() != -1:
   388 
   404 
   389     if other.dev() != -1 and os.stat(dest).st_dev == other.dev():
   405     if other.dev() != -1 and os.stat(dest).st_dev == other.dev():
   390         ui.note("cloning by hardlink\n")
   406         ui.note("cloning by hardlink\n")
   391         util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
   407         util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
   392         try:
   408         try:
   393             os.remove(os.path.join(dest, ".hg", "dirstate"))
   409             os.unlink(os.path.join(dest, ".hg", "dirstate"))
   394         except: pass
   410         except IOError:
       
   411             pass
   395 
   412 
   396         repo = hg.repository(ui, dest)
   413         repo = hg.repository(ui, dest)
   397 
   414 
   398     else:
   415     else:
   399         repo = hg.repository(ui, dest, create=1)
   416         repo = hg.repository(ui, dest, create=1)
   409     d.close()
   426     d.close()
   410 
   427 
   411 def commit(ui, repo, *files, **opts):
   428 def commit(ui, repo, *files, **opts):
   412     """commit the specified files or all outstanding changes"""
   429     """commit the specified files or all outstanding changes"""
   413     text = opts['text']
   430     text = opts['text']
   414     if not text and opts['logfile']:
   431     logfile = opts['logfile']
   415         try: text = open(opts['logfile']).read()
   432     if not text and logfile:
   416         except IOError: pass
   433         try:
       
   434             text = open(logfile).read()
       
   435         except IOError, why:
       
   436             ui.warn("Can't read commit text %s: %s\n" % (logfile, why))
   417 
   437 
   418     if opts['addremove']:
   438     if opts['addremove']:
   419         addremove(ui, repo, *files)
   439         addremove(ui, repo, *files)
   420     repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
   440     repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
   421 
   441 
   460     """show the contents of the current dirstate"""
   480     """show the contents of the current dirstate"""
   461     repo.dirstate.read()
   481     repo.dirstate.read()
   462     dc = repo.dirstate.map
   482     dc = repo.dirstate.map
   463     keys = dc.keys()
   483     keys = dc.keys()
   464     keys.sort()
   484     keys.sort()
   465     for file in keys:
   485     for file_ in keys:
   466         ui.write("%c %s\n" % (dc[file][0], file))
   486         ui.write("%c %s\n" % (dc[file_][0], file_))
   467 
   487 
   468 def debugindex(ui, file):
   488 def debugindex(ui, file_):
   469     """dump the contents of an index file"""
   489     """dump the contents of an index file"""
   470     r = hg.revlog(hg.opener(""), file, "")
   490     r = hg.revlog(hg.opener(""), file_, "")
   471     ui.write("   rev    offset  length   base linkrev" +
   491     ui.write("   rev    offset  length   base linkrev" +
   472              " p1           p2           nodeid\n")
   492              " p1           p2           nodeid\n")
   473     for i in range(r.count()):
   493     for i in range(r.count()):
   474         e = r.index[i]
   494         e = r.index[i]
   475         ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
   495         ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
   476                 i, e[0], e[1], e[2], e[3],
   496                 i, e[0], e[1], e[2], e[3],
   477             hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
   497             hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
   478 
   498 
   479 def debugindexdot(ui, file):
   499 def debugindexdot(ui, file_):
   480     """dump an index DAG as a .dot file"""
   500     """dump an index DAG as a .dot file"""
   481     r = hg.revlog(hg.opener(""), file, "")
   501     r = hg.revlog(hg.opener(""), file_, "")
   482     ui.write("digraph G {\n")
   502     ui.write("digraph G {\n")
   483     for i in range(r.count()):
   503     for i in range(r.count()):
   484         e = r.index[i]
   504         e = r.index[i]
   485         ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
   505         ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
   486         if e[5] != hg.nullid:
   506         if e[5] != hg.nullid:
   544     revwidth = max(len(revs[0]), len(revs[-1]))
   564     revwidth = max(len(revs[0]), len(revs[-1]))
   545     for cset in revs:
   565     for cset in revs:
   546         seqno += 1
   566         seqno += 1
   547         doexport(ui, repo, cset, seqno, total, revwidth, opts)
   567         doexport(ui, repo, cset, seqno, total, revwidth, opts)
   548 
   568 
   549 def forget(ui, repo, file, *files):
   569 def forget(ui, repo, file1, *files):
   550     """don't add the specified files on the next commit"""
   570     """don't add the specified files on the next commit"""
   551     repo.forget(relpath(repo, (file,) + files))
   571     repo.forget(relpath(repo, (file1,) + files))
   552 
   572 
   553 def heads(ui, repo):
   573 def heads(ui, repo):
   554     """show current repository heads"""
   574     """show current repository heads"""
   555     for n in repo.changelog.heads():
   575     for n in repo.changelog.heads():
   556         show_changeset(ui, repo, changenode=n)
   576         show_changeset(ui, repo, changenode=n)
   579 def import_(ui, repo, patch1, *patches, **opts):
   599 def import_(ui, repo, patch1, *patches, **opts):
   580     """import an ordered set of patches"""
   600     """import an ordered set of patches"""
   581     try:
   601     try:
   582         import psyco
   602         import psyco
   583         psyco.full()
   603         psyco.full()
   584     except:
   604     except ImportError:
   585         pass
   605         pass
   586 
   606 
   587     patches = (patch1,) + patches
   607     patches = (patch1,) + patches
   588 
   608 
   589     d = opts["base"]
   609     d = opts["base"]
   593         ui.status("applying %s\n" % patch)
   613         ui.status("applying %s\n" % patch)
   594         pf = os.path.join(d, patch)
   614         pf = os.path.join(d, patch)
   595 
   615 
   596         text = ""
   616         text = ""
   597         for l in file(pf):
   617         for l in file(pf):
   598             if l.startswith("--- ") or l.startswith("diff -r"): break
   618             if l.startswith("--- ") or l.startswith("diff -r"):
       
   619                 break
   599             text += l
   620             text += l
   600 
   621 
   601         # parse values that exist when importing the result of an hg export
   622         # parse values that exist when importing the result of an hg export
   602         hgpatch = user = snippet = None
   623         hgpatch = user = snippet = None
   603         ui.debug('text:\n')
   624         ui.debug('text:\n')
   604         for t in text.splitlines():
   625         for t in text.splitlines():
   605             ui.debug(t,'\n')
   626             ui.debug(t, '\n')
   606             if t == '# HG changeset patch' or hgpatch == True:
   627             if t == '# HG changeset patch' or hgpatch:
   607                 hgpatch = True
   628                 hgpatch = True
   608                 if t.startswith("# User "):
   629                 if t.startswith("# User "):
   609                     user = t[7:]
   630                     user = t[7:]
   610                     ui.debug('User: %s\n' % user)
   631                     ui.debug('User: %s\n' % user)
   611                 if not t.startswith("# ") and t.strip() and not snippet: snippet = t
   632                 if not t.startswith("# ") and t.strip() and not snippet:
   612         if snippet: text = snippet + '\n' + text
   633                     snippet = t
       
   634         if snippet:
       
   635             text = snippet + '\n' + text
   613         ui.debug('text:\n%s\n' % text)
   636         ui.debug('text:\n%s\n' % text)
   614 
   637 
   615         # make sure text isn't empty
   638         # make sure text isn't empty
   616         if not text: text = "imported patch %s\n" % patch
   639         if not text:
       
   640             text = "imported patch %s\n" % patch
   617 
   641 
   618         f = os.popen("patch -p%d < %s" % (strip, pf))
   642         f = os.popen("patch -p%d < %s" % (strip, pf))
   619         files = []
   643         files = []
   620         for l in f.read().splitlines():
   644         for l in f.read().splitlines():
   621             l.rstrip('\r\n');
   645             l.rstrip('\r\n');
   637     """create a new repository in the current directory"""
   661     """create a new repository in the current directory"""
   638 
   662 
   639     if source:
   663     if source:
   640         ui.warn("no longer supported: use \"hg clone\" instead\n")
   664         ui.warn("no longer supported: use \"hg clone\" instead\n")
   641         sys.exit(1)
   665         sys.exit(1)
   642     repo = hg.repository(ui, ".", create=1)
   666     hg.repository(ui, ".", create=1)
   643 
   667 
   644 def locate(ui, repo, *pats, **opts):
   668 def locate(ui, repo, *pats, **opts):
   645     """locate files matching specific patterns"""
   669     """locate files matching specific patterns"""
   646     if [p for p in pats if os.sep in p]:
   670     if [p for p in pats if os.sep in p]:
   647         ui.warn("error: patterns may not contain '%s'\n" % os.sep)
   671         ui.warn("error: patterns may not contain '%s'\n" % os.sep)
   648         ui.warn("use '-i <dir>' instead\n")
   672         ui.warn("use '-i <dir>' instead\n")
   649         sys.exit(1)
   673         sys.exit(1)
   650     def compile(pats, head = '^', tail = os.sep, on_empty = True):
   674     def compile(pats, head='^', tail=os.sep, on_empty=True):
   651         if not pats:
   675         if not pats:
   652             class c:
   676             class c:
   653                 def match(self, x): return on_empty
   677                 def match(self, x):
       
   678                     return on_empty
   654             return c()
   679             return c()
   655         regexp = r'%s(?:%s)%s' % (
   680         fnpats = [fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
   656             head,
   681                   for p in pats]
   657             '|'.join([fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
   682         regexp = r'%s(?:%s)%s' % (head, '|'.join(fnpats), tail)
   658                       for p in pats]),
       
   659             tail)
       
   660         return re.compile(regexp)
   683         return re.compile(regexp)
   661     exclude = compile(opts['exclude'], on_empty = False)
   684     exclude = compile(opts['exclude'], on_empty=False)
   662     include = compile(opts['include'])
   685     include = compile(opts['include'])
   663     pat = compile([os.path.normcase(p) for p in pats], head = '', tail = '$')
   686     pat = compile([os.path.normcase(p) for p in pats], head='', tail='$')
   664     end = '\n'
   687     end = opts['print0'] and '\0' or '\n'
   665     if opts['print0']: end = '\0'
   688     if opts['rev']:
   666     if opts['rev']: node = repo.manifest.lookup(opts['rev'])
   689         node = repo.manifest.lookup(opts['rev'])
   667     else: node = repo.manifest.tip()
   690     else:
       
   691         node = repo.manifest.tip()
   668     manifest = repo.manifest.read(node)
   692     manifest = repo.manifest.read(node)
   669     cwd = repo.getcwd()
   693     cwd = repo.getcwd()
   670     cwd_plus = cwd and (cwd + os.sep)
   694     cwd_plus = cwd and (cwd + os.sep)
   671     found = []
   695     found = []
   672     for f in manifest:
   696     for f in manifest:
   673         f = os.path.normcase(f)
   697         f = os.path.normcase(f)
   674         if exclude.match(f) or not(include.match(f) and
   698         if exclude.match(f) or not(include.match(f) and
   675                                    f.startswith(cwd_plus) and
   699                                    f.startswith(cwd_plus) and
   676                                    pat.match(os.path.basename(f))): continue
   700                                    pat.match(os.path.basename(f))):
   677         if opts['fullpath']: f = os.path.join(repo.root, f)
   701             continue
   678         elif cwd: f = f[len(cwd_plus):]
   702         if opts['fullpath']:
       
   703             f = os.path.join(repo.root, f)
       
   704         elif cwd:
       
   705             f = f[len(cwd_plus):]
   679         found.append(f)
   706         found.append(f)
   680     found.sort()
   707     found.sort()
   681     for f in found: ui.write(f, end)
   708     for f in found:
       
   709         ui.write(f, end)
   682 
   710 
   683 def log(ui, repo, f=None, **opts):
   711 def log(ui, repo, f=None, **opts):
   684     """show the revision history of the repository or a single file"""
   712     """show the revision history of the repository or a single file"""
   685     if f:
   713     if f:
   686         files = relpath(repo, [f])
   714         files = relpath(repo, [f])
   712             changenode = repo.changelog.node(i)
   740             changenode = repo.changelog.node(i)
   713             prev, other = repo.changelog.parents(changenode)
   741             prev, other = repo.changelog.parents(changenode)
   714             dodiff(sys.stdout, ui, repo, files, prev, changenode)
   742             dodiff(sys.stdout, ui, repo, files, prev, changenode)
   715             ui.write("\n\n")
   743             ui.write("\n\n")
   716 
   744 
   717 def manifest(ui, repo, rev = []):
   745 def manifest(ui, repo, rev=None):
   718     """output the latest or given revision of the project manifest"""
   746     """output the latest or given revision of the project manifest"""
   719     n = repo.manifest.tip()
       
   720     if rev:
   747     if rev:
   721         try:
   748         try:
   722             # assume all revision numbers are for changesets
   749             # assume all revision numbers are for changesets
   723             n = repo.lookup(rev)
   750             n = repo.lookup(rev)
   724             change = repo.changelog.read(n)
   751             change = repo.changelog.read(n)
   725             n = change[0]
   752             n = change[0]
   726         except:
   753         except hg.RepoError:
   727             n = repo.manifest.lookup(rev)
   754             n = repo.manifest.lookup(rev)
   728 
   755     else:
       
   756         n = repo.manifest.tip()
   729     m = repo.manifest.read(n)
   757     m = repo.manifest.read(n)
   730     mf = repo.manifest.readflags(n)
   758     mf = repo.manifest.readflags(n)
   731     files = m.keys()
   759     files = m.keys()
   732     files.sort()
   760     files.sort()
   733 
   761 
   772 def rawcommit(ui, repo, *flist, **rc):
   800 def rawcommit(ui, repo, *flist, **rc):
   773     "raw commit interface"
   801     "raw commit interface"
   774 
   802 
   775     text = rc['text']
   803     text = rc['text']
   776     if not text and rc['logfile']:
   804     if not text and rc['logfile']:
   777         try: text = open(rc['logfile']).read()
   805         try:
   778         except IOError: pass
   806             text = open(rc['logfile']).read()
       
   807         except IOError:
       
   808             pass
   779     if not text and not rc['logfile']:
   809     if not text and not rc['logfile']:
   780         ui.warn("abort: missing commit text\n")
   810         ui.warn("abort: missing commit text\n")
   781         return 1
   811         return 1
   782 
   812 
   783     files = relpath(repo, list(flist))
   813     files = relpath(repo, list(flist))
   790 
   820 
   791 def recover(ui, repo):
   821 def recover(ui, repo):
   792     """roll back an interrupted transaction"""
   822     """roll back an interrupted transaction"""
   793     repo.recover()
   823     repo.recover()
   794 
   824 
   795 def remove(ui, repo, file, *files):
   825 def remove(ui, repo, file1, *files):
   796     """remove the specified files on the next commit"""
   826     """remove the specified files on the next commit"""
   797     repo.remove(relpath(repo, (file,) + files))
   827     repo.remove(relpath(repo, (file1,) + files))
   798 
   828 
   799 def revert(ui, repo, *names, **opts):
   829 def revert(ui, repo, *names, **opts):
   800     """revert modified files or dirs back to their unmodified states"""
   830     """revert modified files or dirs back to their unmodified states"""
   801     node = opts['rev'] and repo.lookup(opts['rev']) or \
   831     node = opts['rev'] and repo.lookup(opts['rev']) or \
   802            repo.dirstate.parents()[0]
   832            repo.dirstate.parents()[0]
   816     chosen = {}
   846     chosen = {}
   817 
   847 
   818     def choose(name):
   848     def choose(name):
   819         def body(name):
   849         def body(name):
   820             for r in relnames:
   850             for r in relnames:
   821                 if not name.startswith(r): continue
   851                 if not name.startswith(r):
       
   852                     continue
   822                 rest = name[len(r):]
   853                 rest = name[len(r):]
   823                 if not rest: return r, True
   854                 if not rest:
       
   855                     return r, True
   824                 depth = rest.count(os.sep)
   856                 depth = rest.count(os.sep)
   825                 if not r:
   857                 if not r:
   826                     if depth == 0 or not opts['nonrecursive']: return r, True
   858                     if depth == 0 or not opts['nonrecursive']:
       
   859                         return r, True
   827                 elif rest[0] == os.sep:
   860                 elif rest[0] == os.sep:
   828                     if depth == 1 or not opts['nonrecursive']: return r, True
   861                     if depth == 1 or not opts['nonrecursive']:
       
   862                         return r, True
   829             return None, False
   863             return None, False
   830         relname, ret = body(name)
   864         relname, ret = body(name)
   831         if ret:
   865         if ret:
   832             chosen[relname] = 1
   866             chosen[relname] = 1
   833         return ret
   867         return ret
   872                 respond(" ".join(map(hg.hex, h)) + "\n")
   906                 respond(" ".join(map(hg.hex, h)) + "\n")
   873             if cmd == "lock":
   907             if cmd == "lock":
   874                 lock = repo.lock()
   908                 lock = repo.lock()
   875                 respond("")
   909                 respond("")
   876             if cmd == "unlock":
   910             if cmd == "unlock":
   877                 if lock: lock.release()
   911                 if lock:
       
   912                     lock.release()
   878                 lock = None
   913                 lock = None
   879                 respond("")
   914                 respond("")
   880             elif cmd == "branches":
   915             elif cmd == "branches":
   881                 arg, nodes = getarg()
   916                 arg, nodes = getarg()
   882                 nodes = map(hg.bin, nodes.split(" "))
   917                 nodes = map(hg.bin, nodes.split(" "))
   884                 for b in repo.branches(nodes):
   919                 for b in repo.branches(nodes):
   885                     r.append(" ".join(map(hg.hex, b)) + "\n")
   920                     r.append(" ".join(map(hg.hex, b)) + "\n")
   886                 respond("".join(r))
   921                 respond("".join(r))
   887             elif cmd == "between":
   922             elif cmd == "between":
   888                 arg, pairs = getarg()
   923                 arg, pairs = getarg()
   889                 pairs = [ map(hg.bin, p.split("-")) for p in pairs.split(" ") ]
   924                 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
   890                 r = []
   925                 r = []
   891                 for b in repo.between(pairs):
   926                 for b in repo.between(pairs):
   892                     r.append(" ".join(map(hg.hex, b)) + "\n")
   927                     r.append(" ".join(map(hg.hex, b)) + "\n")
   893                 respond("".join(r))
   928                 respond("".join(r))
   894             elif cmd == "changegroup":
   929             elif cmd == "changegroup":
   897                 nodes = map(hg.bin, roots.split(" "))
   932                 nodes = map(hg.bin, roots.split(" "))
   898 
   933 
   899                 cg = repo.changegroup(nodes)
   934                 cg = repo.changegroup(nodes)
   900                 while 1:
   935                 while 1:
   901                     d = cg.read(4096)
   936                     d = cg.read(4096)
   902                     if not d: break
   937                     if not d:
       
   938                         break
   903                     fout.write(d)
   939                     fout.write(d)
   904 
   940 
   905                 fout.flush()
   941                 fout.flush()
   906 
   942 
   907             elif cmd == "addchangegroup":
   943             elif cmd == "addchangegroup":
   912 
   948 
   913                 r = repo.addchangegroup(fin)
   949                 r = repo.addchangegroup(fin)
   914                 respond("")
   950                 respond("")
   915 
   951 
   916     def openlog(opt, default):
   952     def openlog(opt, default):
   917         if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
   953         if opts[opt] and opts[opt] != '-':
   918         else: return default
   954             return open(opts[opt], 'w')
       
   955         else:
       
   956             return default
   919 
   957 
   920     httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
   958     httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
   921                                 opts["address"], opts["port"],
   959                                 opts["address"], opts["port"],
   922                                 openlog('accesslog', sys.stdout),
   960                                 openlog('accesslog', sys.stdout),
   923                                 openlog('errorlog', sys.stderr))
   961                                 openlog('errorlog', sys.stderr))
   926         if addr == '0.0.0.0':
   964         if addr == '0.0.0.0':
   927             addr = socket.gethostname()
   965             addr = socket.gethostname()
   928         else:
   966         else:
   929             try:
   967             try:
   930                 addr = socket.gethostbyaddr(addr)[0]
   968                 addr = socket.gethostbyaddr(addr)[0]
   931             except: pass
   969             except socket.error:
       
   970                 pass
   932         if port != 80:
   971         if port != 80:
   933             ui.status('listening at http://%s:%d/\n' % (addr, port))
   972             ui.status('listening at http://%s:%d/\n' % (addr, port))
   934         else:
   973         else:
   935             ui.status('listening at http://%s/\n' % addr)
   974             ui.status('listening at http://%s/\n' % addr)
   936     httpd.serve_forever()
   975     httpd.serve_forever()
   944     ? = not tracked'''
   983     ? = not tracked'''
   945 
   984 
   946     (c, a, d, u) = repo.changes(None, None)
   985     (c, a, d, u) = repo.changes(None, None)
   947     (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
   986     (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
   948 
   987 
   949     for f in c: ui.write("C ", f, "\n")
   988     for f in c:
   950     for f in a: ui.write("A ", f, "\n")
   989         ui.write("C ", f, "\n")
   951     for f in d: ui.write("R ", f, "\n")
   990     for f in a:
   952     for f in u: ui.write("? ", f, "\n")
   991         ui.write("A ", f, "\n")
       
   992     for f in d:
       
   993         ui.write("R ", f, "\n")
       
   994     for f in u:
       
   995         ui.write("? ", f, "\n")
   953 
   996 
   954 def tag(ui, repo, name, rev = None, **opts):
   997 def tag(ui, repo, name, rev = None, **opts):
   955     """add a tag for the current tip or a given revision"""
   998     """add a tag for the current tip or a given revision"""
   956 
   999 
   957     if name == "tip":
  1000     if name == "tip":
   975         if ".hgtags" in x:
  1018         if ".hgtags" in x:
   976             ui.warn("abort: working copy of .hgtags is changed!\n")
  1019             ui.warn("abort: working copy of .hgtags is changed!\n")
   977             ui.status("(please commit .hgtags manually)\n")
  1020             ui.status("(please commit .hgtags manually)\n")
   978             return -1
  1021             return -1
   979 
  1022 
   980     add = 0
  1023     add = not os.path.exists(repo.wjoin(".hgtags"))
   981     if not os.path.exists(repo.wjoin(".hgtags")): add = 1
       
   982     repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
  1024     repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
   983     if add: repo.add([".hgtags"])
  1025     if add:
       
  1026         repo.add([".hgtags"])
   984 
  1027 
   985     if not opts['text']:
  1028     if not opts['text']:
   986         opts['text'] = "Added tag %s for changeset %s" % (name, r)
  1029         opts['text'] = "Added tag %s for changeset %s" % (name, r)
   987 
  1030 
   988     repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
  1031     repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
  1042 # Command options and aliases are listed here, alphabetically
  1085 # Command options and aliases are listed here, alphabetically
  1043 
  1086 
  1044 table = {
  1087 table = {
  1045     "^add": (add, [], "hg add [files]"),
  1088     "^add": (add, [], "hg add [files]"),
  1046     "addremove": (addremove, [], "hg addremove [files]"),
  1089     "addremove": (addremove, [], "hg addremove [files]"),
  1047     "^annotate": (annotate,
  1090     "^annotate":
  1048                      [('r', 'revision', '', 'revision'),
  1091         (annotate,
  1049                       ('u', 'user', None, 'show user'),
  1092          [('r', 'revision', '', 'revision'),
  1050                       ('n', 'number', None, 'show revision number'),
  1093           ('u', 'user', None, 'show user'),
  1051                       ('c', 'changeset', None, 'show changeset')],
  1094           ('n', 'number', None, 'show revision number'),
  1052                      'hg annotate [-u] [-c] [-n] [-r id] [files]'),
  1095           ('c', 'changeset', None, 'show changeset')],
  1053     "cat": (cat, [('o', 'output', "", 'output to file')], 'hg cat [-o outfile] <file> [rev]'),
  1096          'hg annotate [-u] [-c] [-n] [-r id] [files]'),
  1054     "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
  1097     "cat":
  1055               'hg clone [options] <source> [dest]'),
  1098         (cat,
  1056     "^commit|ci": (commit,
  1099          [('o', 'output', "", 'output to file')],
  1057                   [('t', 'text', "", 'commit text'),
  1100          'hg cat [-o outfile] <file> [rev]'),
  1058                    ('A', 'addremove', None, 'run add/remove during commit'),
  1101     "^clone":
  1059                    ('l', 'logfile', "", 'commit text file'),
  1102         (clone,
  1060                    ('d', 'date', "", 'date code'),
  1103          [('U', 'noupdate', None, 'skip update after cloning')],
  1061                    ('u', 'user', "", 'user')],
  1104          'hg clone [options] <source> [dest]'),
  1062                   'hg commit [files]'),
  1105     "^commit|ci":
       
  1106         (commit,
       
  1107          [('t', 'text', "", 'commit text'),
       
  1108           ('A', 'addremove', None, 'run add/remove during commit'),
       
  1109           ('l', 'logfile', "", 'commit text file'),
       
  1110           ('d', 'date', "", 'date code'),
       
  1111           ('u', 'user', "", 'user')],
       
  1112          'hg commit [files]'),
  1063     "copy": (copy, [], 'hg copy <source> <dest>'),
  1113     "copy": (copy, [], 'hg copy <source> <dest>'),
  1064     "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
  1114     "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
  1065     "debugstate": (debugstate, [], 'debugstate'),
  1115     "debugstate": (debugstate, [], 'debugstate'),
  1066     "debugindex": (debugindex, [], 'debugindex <file>'),
  1116     "debugindex": (debugindex, [], 'debugindex <file>'),
  1067     "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
  1117     "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
  1068     "^diff": (diff, [('r', 'rev', [], 'revision')],
  1118     "^diff":
  1069              'hg diff [-r A] [-r B] [files]'),
  1119         (diff,
  1070     "^export": (export, [('o', 'output', "", 'output to file')],
  1120          [('r', 'rev', [], 'revision')],
  1071                "hg export [-o file] <changeset> ..."),
  1121          'hg diff [-r A] [-r B] [files]'),
       
  1122     "^export":
       
  1123         (export,
       
  1124          [('o', 'output', "", 'output to file')],
       
  1125          "hg export [-o file] <changeset> ..."),
  1072     "forget": (forget, [], "hg forget [files]"),
  1126     "forget": (forget, [], "hg forget [files]"),
  1073     "heads": (heads, [], 'hg heads'),
  1127     "heads": (heads, [], 'hg heads'),
  1074     "help": (help, [], 'hg help [command]'),
  1128     "help": (help_, [], 'hg help [command]'),
  1075     "identify|id": (identify, [], 'hg identify'),
  1129     "identify|id": (identify, [], 'hg identify'),
  1076     "import|patch": (import_,
  1130     "import|patch":
  1077                      [('p', 'strip', 1, 'path strip'),
  1131         (import_,
  1078                       ('b', 'base', "", 'base path')],
  1132          [('p', 'strip', 1, 'path strip'),
  1079                      "hg import [options] <patches>"),
  1133           ('b', 'base', "", 'base path')],
       
  1134          "hg import [options] <patches>"),
  1080     "^init": (init, [], 'hg init'),
  1135     "^init": (init, [], 'hg init'),
  1081     "locate": (locate,
  1136     "locate":
  1082                [('0', 'print0', None, 'end records with NUL'),
  1137         (locate,
  1083                 ('f', 'fullpath', None, 'print complete paths'),
  1138          [('0', 'print0', None, 'end records with NUL'),
  1084                 ('i', 'include', [], 'include path in search'),
  1139           ('f', 'fullpath', None, 'print complete paths'),
  1085                 ('r', 'rev', '', 'revision'),
  1140           ('i', 'include', [], 'include path in search'),
  1086                 ('x', 'exclude', [], 'exclude path from search')],
  1141           ('r', 'rev', '', 'revision'),
  1087                'hg locate [options] [files]'),
  1142           ('x', 'exclude', [], 'exclude path from search')],
  1088     "^log|history": (log,
  1143          'hg locate [options] [files]'),
  1089                     [('r', 'rev', [], 'revision'),
  1144     "^log|history":
  1090                      ('p', 'patch', None, 'show patch')],
  1145         (log,
  1091                     'hg log [-r A] [-r B] [-p] [file]'),
  1146          [('r', 'rev', [], 'revision'),
       
  1147           ('p', 'patch', None, 'show patch')],
       
  1148          'hg log [-r A] [-r B] [-p] [file]'),
  1092     "manifest": (manifest, [], 'hg manifest [rev]'),
  1149     "manifest": (manifest, [], 'hg manifest [rev]'),
  1093     "parents": (parents, [], 'hg parents [node]'),
  1150     "parents": (parents, [], 'hg parents [node]'),
  1094     "^pull": (pull,
  1151     "^pull":
  1095                   [('u', 'update', None, 'update working directory')],
  1152         (pull,
  1096                   'hg pull [options] [source]'),
  1153          [('u', 'update', None, 'update working directory')],
       
  1154          'hg pull [options] [source]'),
  1097     "^push": (push, [], 'hg push <destination>'),
  1155     "^push": (push, [], 'hg push <destination>'),
  1098     "rawcommit": (rawcommit,
  1156     "rawcommit":
  1099                   [('p', 'parent', [], 'parent'),
  1157         (rawcommit,
  1100                    ('d', 'date', "", 'date code'),
  1158          [('p', 'parent', [], 'parent'),
  1101                    ('u', 'user', "", 'user'),
  1159           ('d', 'date', "", 'date code'),
  1102                    ('F', 'files', "", 'file list'),
  1160           ('u', 'user', "", 'user'),
  1103                    ('t', 'text', "", 'commit text'),
  1161           ('F', 'files', "", 'file list'),
  1104                    ('l', 'logfile', "", 'commit text file')],
  1162           ('t', 'text', "", 'commit text'),
  1105                   'hg rawcommit [options] [files]'),
  1163           ('l', 'logfile', "", 'commit text file')],
       
  1164          'hg rawcommit [options] [files]'),
  1106     "recover": (recover, [], "hg recover"),
  1165     "recover": (recover, [], "hg recover"),
  1107     "^remove|rm": (remove, [], "hg remove [files]"),
  1166     "^remove|rm": (remove, [], "hg remove [files]"),
  1108     "^revert": (revert,
  1167     "^revert":
  1109                [("n", "nonrecursive", None, "don't recurse into subdirs"),
  1168         (revert,
  1110                 ("r", "rev", "", "revision")],
  1169          [("n", "nonrecursive", None, "don't recurse into subdirs"),
  1111                "hg revert [files|dirs]"),
  1170           ("r", "rev", "", "revision")],
       
  1171          "hg revert [files|dirs]"),
  1112     "root": (root, [], "hg root"),
  1172     "root": (root, [], "hg root"),
  1113     "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
  1173     "^serve":
  1114                        ('E', 'errorlog', '', 'error log file'),
  1174         (serve,
  1115                        ('p', 'port', 8000, 'listen port'),
  1175          [('A', 'accesslog', '', 'access log file'),
  1116                        ('a', 'address', '', 'interface address'),
  1176           ('E', 'errorlog', '', 'error log file'),
  1117                        ('n', 'name', os.getcwd(), 'repository name'),
  1177           ('p', 'port', 8000, 'listen port'),
  1118                        ('', 'stdio', None, 'for remote clients'),
  1178           ('a', 'address', '', 'interface address'),
  1119                        ('t', 'templates', "", 'template map')],
  1179           ('n', 'name', os.getcwd(), 'repository name'),
  1120               "hg serve [options]"),
  1180           ('', 'stdio', None, 'for remote clients'),
       
  1181           ('t', 'templates', "", 'template map')],
       
  1182          "hg serve [options]"),
  1121     "^status": (status, [], 'hg status'),
  1183     "^status": (status, [], 'hg status'),
  1122     "tag": (tag,  [('l', 'local', None, 'make the tag local'),
  1184     "tag":
  1123                    ('t', 'text', "", 'commit text'),
  1185         (tag,
  1124                    ('d', 'date', "", 'date code'),
  1186          [('l', 'local', None, 'make the tag local'),
  1125                    ('u', 'user', "", 'user')],
  1187           ('t', 'text', "", 'commit text'),
  1126             'hg tag [options] <name> [rev]'),
  1188           ('d', 'date', "", 'date code'),
       
  1189           ('u', 'user', "", 'user')],
       
  1190          'hg tag [options] <name> [rev]'),
  1127     "tags": (tags, [], 'hg tags'),
  1191     "tags": (tags, [], 'hg tags'),
  1128     "tip": (tip, [], 'hg tip'),
  1192     "tip": (tip, [], 'hg tip'),
  1129     "undo": (undo, [], 'hg undo'),
  1193     "undo": (undo, [], 'hg undo'),
  1130     "^update|up|checkout|co":
  1194     "^update|up|checkout|co":
  1131             (update,
  1195         (update,
  1132              [('m', 'merge', None, 'allow merging of conflicts'),
  1196          [('m', 'merge', None, 'allow merging of conflicts'),
  1133               ('C', 'clean', None, 'overwrite locally modified files')],
  1197           ('C', 'clean', None, 'overwrite locally modified files')],
  1134              'hg update [options] [node]'),
  1198          'hg update [options] [node]'),
  1135     "verify": (verify, [], 'hg verify'),
  1199     "verify": (verify, [], 'hg verify'),
  1136     "version": (show_version, [], 'hg version'),
  1200     "version": (show_version, [], 'hg version'),
  1137     }
  1201     }
  1138 
  1202 
  1139 globalopts = [('v', 'verbose', None, 'verbose'),
  1203 globalopts = [('v', 'verbose', None, 'verbose'),
  1142               ('', 'profile', None, 'profile'),
  1206               ('', 'profile', None, 'profile'),
  1143               ('R', 'repository', "", 'repository root directory'),
  1207               ('R', 'repository', "", 'repository root directory'),
  1144               ('', 'traceback', None, 'print traceback on exception'),
  1208               ('', 'traceback', None, 'print traceback on exception'),
  1145               ('y', 'noninteractive', None, 'run non-interactively'),
  1209               ('y', 'noninteractive', None, 'run non-interactively'),
  1146               ('', 'version', None, 'output version information and exit'),
  1210               ('', 'version', None, 'output version information and exit'),
  1147               ]
  1211              ]
  1148 
  1212 
  1149 norepo = "clone init version help debugindex debugindexdot"
  1213 norepo = "clone init version help debugindex debugindexdot"
  1150 
  1214 
  1151 def find(cmd):
  1215 def find(cmd):
  1152     for e in table.keys():
  1216     for e in table.keys():
  1153         if re.match("(%s)$" % e, cmd):
  1217         if re.match("(%s)$" % e, cmd):
  1154             return table[e]
  1218             return table[e]
  1155 
  1219 
  1156     raise UnknownCommand(cmd)
  1220     raise UnknownCommand(cmd)
  1157 
  1221 
  1158 class SignalInterrupt(Exception): pass
  1222 class SignalInterrupt(Exception):
       
  1223     """Exception raised on SIGTERM and SIGHUP."""
  1159 
  1224 
  1160 def catchterm(*args):
  1225 def catchterm(*args):
  1161     raise SignalInterrupt
  1226     raise SignalInterrupt
  1162 
  1227 
  1163 def run():
  1228 def run():
  1164     sys.exit(dispatch(sys.argv[1:]))
  1229     sys.exit(dispatch(sys.argv[1:]))
  1165 
  1230 
  1166 class ParseError(Exception): pass
  1231 class ParseError(Exception):
       
  1232     """Exception raised on errors in parsing the command line."""
  1167 
  1233 
  1168 def parse(args):
  1234 def parse(args):
  1169     options = {}
  1235     options = {}
  1170     cmdoptions = {}
  1236     cmdoptions = {}
  1171 
  1237 
  1175         raise ParseError(None, inst)
  1241         raise ParseError(None, inst)
  1176 
  1242 
  1177     if options["version"]:
  1243     if options["version"]:
  1178         return ("version", show_version, [], options, cmdoptions)
  1244         return ("version", show_version, [], options, cmdoptions)
  1179     elif not args:
  1245     elif not args:
  1180         return ("help", help, [], options, cmdoptions)
  1246         return ("help", help_, [], options, cmdoptions)
  1181     else:
  1247     else:
  1182         cmd, args = args[0], args[1:]
  1248         cmd, args = args[0], args[1:]
  1183 
  1249 
  1184     i = find(cmd)
  1250     i = find(cmd)
  1185 
  1251 
  1186     # combine global options into local
  1252     # combine global options into local
  1187     c = list(i[1])
  1253     c = list(i[1])
  1188     l = len(c)
       
  1189     for o in globalopts:
  1254     for o in globalopts:
  1190         c.append((o[0], o[1], options[o[1]], o[3]))
  1255         c.append((o[0], o[1], options[o[1]], o[3]))
  1191 
  1256 
  1192     try:
  1257     try:
  1193         args = fancyopts.fancyopts(args, c, cmdoptions)
  1258         args = fancyopts.fancyopts(args, c, cmdoptions)
  1202 
  1267 
  1203     return (cmd, i[0], args, options, cmdoptions)
  1268     return (cmd, i[0], args, options, cmdoptions)
  1204 
  1269 
  1205 def dispatch(args):
  1270 def dispatch(args):
  1206     signal.signal(signal.SIGTERM, catchterm)
  1271     signal.signal(signal.SIGTERM, catchterm)
  1207     try: signal.signal(signal.SIGHUP, catchterm)
  1272     try:
  1208     except: pass
  1273         signal.signal(signal.SIGHUP, catchterm)
       
  1274     except AttributeError:
       
  1275         pass
  1209 
  1276 
  1210     try:
  1277     try:
  1211         cmd, func, args, options, cmdoptions = parse(args)
  1278         cmd, func, args, options, cmdoptions = parse(args)
  1212     except ParseError, inst:
  1279     except ParseError, inst:
  1213         u = ui.ui()
  1280         u = ui.ui()
  1214         if inst.args[0]:
  1281         if inst.args[0]:
  1215             u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
  1282             u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
  1216             help(u, inst.args[0])
  1283             help_(u, inst.args[0])
  1217         else:
  1284         else:
  1218             u.warn("hg: %s\n" % inst.args[1])
  1285             u.warn("hg: %s\n" % inst.args[1])
  1219             help(u)
  1286             help_(u)
  1220         sys.exit(-1)
  1287         sys.exit(-1)
  1221     except UnknownCommand, inst:
  1288     except UnknownCommand, inst:
  1222         u = ui.ui()
  1289         u = ui.ui()
  1223         u.warn("hg: unknown command '%s'\n" % inst.args[0])
  1290         u.warn("hg: unknown command '%s'\n" % inst.args[0])
  1224         help(u)
  1291         help_(u)
  1225         sys.exit(1)
  1292         sys.exit(1)
  1226 
  1293 
  1227     u = ui.ui(options["verbose"], options["debug"], options["quiet"],
  1294     u = ui.ui(options["verbose"], options["debug"], options["quiet"],
  1228                      not options["noninteractive"])
  1295               not options["noninteractive"])
  1229 
  1296 
  1230     try:
  1297     try:
  1231         try:
  1298         try:
  1232             if cmd not in norepo.split():
  1299             if cmd not in norepo.split():
  1233                 path = options["repository"] or ""
  1300                 path = options["repository"] or ""
  1279         tb = traceback.extract_tb(sys.exc_info()[2])
  1346         tb = traceback.extract_tb(sys.exc_info()[2])
  1280         if len(tb) > 2: # no
  1347         if len(tb) > 2: # no
  1281             raise
  1348             raise
  1282         u.debug(inst, "\n")
  1349         u.debug(inst, "\n")
  1283         u.warn("%s: invalid arguments\n" % cmd)
  1350         u.warn("%s: invalid arguments\n" % cmd)
  1284         help(u, cmd)
  1351         help_(u, cmd)
  1285 
  1352 
  1286     sys.exit(-1)
  1353     sys.exit(-1)