mercurial/commands.py
changeset 2956 6dddcba7596a
parent 2955 9d1c3529ebbc
parent 2945 731f6b3d27c2
child 2958 ff3ea21a981a
equal deleted inserted replaced
2955:9d1c3529ebbc 2956:6dddcba7596a
     1 # commands.py - command processing for mercurial
     1 # commands.py - command processing for mercurial
     2 #
     2 #
     3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
     3 # Copyright 2005, 2006 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 demandload
     8 from demandload import demandload
     9 from node import *
     9 from node import *
    10 from i18n import gettext as _
    10 from i18n import gettext as _
    11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
    11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
    12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
    12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
    13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
    13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
    14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
    14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
    15 demandload(globals(), "archival cStringIO changegroup email.Parser")
    15 demandload(globals(), "archival cStringIO changegroup")
    16 demandload(globals(), "hgweb.server sshserver")
    16 demandload(globals(), "cmdutil hgweb.server sshserver")
    17 
    17 
    18 class UnknownCommand(Exception):
    18 class UnknownCommand(Exception):
    19     """Exception raised if command is not in the command table."""
    19     """Exception raised if command is not in the command table."""
    20 class AmbiguousCommand(Exception):
    20 class AmbiguousCommand(Exception):
    21     """Exception raised if command shortcut matches more than one command."""
    21     """Exception raised if command shortcut matches more than one command."""
    22 
    22 
    23 def bail_if_changed(repo):
    23 def bail_if_changed(repo):
    24     modified, added, removed, deleted, unknown = repo.changes()
    24     modified, added, removed, deleted = repo.status()[:4]
    25     if modified or added or removed or deleted:
    25     if modified or added or removed or deleted:
    26         raise util.Abort(_("outstanding uncommitted changes"))
    26         raise util.Abort(_("outstanding uncommitted changes"))
    27 
       
    28 def filterfiles(filters, files):
       
    29     l = [x for x in files if x in filters]
       
    30 
       
    31     for t in filters:
       
    32         if t and t[-1] != "/":
       
    33             t += "/"
       
    34         l += [x for x in files if x.startswith(t)]
       
    35     return l
       
    36 
    27 
    37 def relpath(repo, args):
    28 def relpath(repo, args):
    38     cwd = repo.getcwd()
    29     cwd = repo.getcwd()
    39     if cwd:
    30     if cwd:
    40         return [util.normpath(os.path.join(cwd, x)) for x in args]
    31         return [util.normpath(os.path.join(cwd, x)) for x in args]
    41     return args
    32     return args
    42 
    33 
    43 def matchpats(repo, pats=[], opts={}, head=''):
    34 def logmessage(opts):
    44     cwd = repo.getcwd()
    35     """ get the log message according to -m and -l option """
    45     if not pats and cwd:
    36     message = opts['message']
    46         opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
    37     logfile = opts['logfile']
    47         opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
    38 
    48         cwd = ''
    39     if message and logfile:
    49     return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
    40         raise util.Abort(_('options --message and --logfile are mutually '
    50                            opts.get('exclude'), head)
    41                            'exclusive'))
    51 
    42     if not message and logfile:
    52 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
    43         try:
    53     files, matchfn, anypats = matchpats(repo, pats, opts, head)
    44             if logfile == '-':
    54     exact = dict(zip(files, files))
    45                 message = sys.stdin.read()
    55     def walk():
    46             else:
    56         for src, fn in repo.walk(node=node, files=files, match=matchfn,
    47                 message = open(logfile).read()
    57                                  badmatch=badmatch):
    48         except IOError, inst:
    58             yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
    49             raise util.Abort(_("can't read commit message '%s': %s") %
    59     return files, matchfn, walk()
    50                              (logfile, inst.strerror))
    60 
    51     return message
    61 def walk(repo, pats, opts, node=None, head='', badmatch=None):
       
    62     files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
       
    63     for r in results:
       
    64         yield r
       
    65 
    52 
    66 def walkchangerevs(ui, repo, pats, opts):
    53 def walkchangerevs(ui, repo, pats, opts):
    67     '''Iterate over files and the revs they changed in.
    54     '''Iterate over files and the revs they changed in.
    68 
    55 
    69     Callers most commonly need to iterate backwards over the history
    56     Callers most commonly need to iterate backwards over the history
   103                 start -= windowsize
    90                 start -= windowsize
   104                 if windowsize < sizelimit:
    91                 if windowsize < sizelimit:
   105                     windowsize *= 2
    92                     windowsize *= 2
   106 
    93 
   107 
    94 
   108     files, matchfn, anypats = matchpats(repo, pats, opts)
    95     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
       
    96     follow = opts.get('follow') or opts.get('follow_first')
   109 
    97 
   110     if repo.changelog.count() == 0:
    98     if repo.changelog.count() == 0:
   111         return [], False, matchfn
    99         return [], False, matchfn
   112 
   100 
   113     revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
   101     if follow:
       
   102         p = repo.dirstate.parents()[0]
       
   103         if p == nullid:
       
   104             ui.warn(_('No working directory revision; defaulting to tip\n'))
       
   105             start = 'tip'
       
   106         else:
       
   107             start = repo.changelog.rev(p)
       
   108         defrange = '%s:0' % start
       
   109     else:
       
   110         defrange = 'tip:0'
       
   111     revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
   114     wanted = {}
   112     wanted = {}
   115     slowpath = anypats
   113     slowpath = anypats
   116     fncache = {}
   114     fncache = {}
   117 
   115 
   118     chcache = {}
   116     chcache = {}
   123         return ch
   121         return ch
   124 
   122 
   125     if not slowpath and not files:
   123     if not slowpath and not files:
   126         # No files, no patterns.  Display all revs.
   124         # No files, no patterns.  Display all revs.
   127         wanted = dict(zip(revs, revs))
   125         wanted = dict(zip(revs, revs))
       
   126     copies = []
   128     if not slowpath:
   127     if not slowpath:
   129         # Only files, no patterns.  Check the history of each file.
   128         # Only files, no patterns.  Check the history of each file.
   130         def filerevgen(filelog):
   129         def filerevgen(filelog, node):
   131             cl_count = repo.changelog.count()
   130             cl_count = repo.changelog.count()
   132             for i, window in increasing_windows(filelog.count()-1, -1):
   131             if node is None:
       
   132                 last = filelog.count() - 1
       
   133             else:
       
   134                 last = filelog.rev(node)
       
   135             for i, window in increasing_windows(last, -1):
   133                 revs = []
   136                 revs = []
   134                 for j in xrange(i - window, i + 1):
   137                 for j in xrange(i - window, i + 1):
   135                     revs.append(filelog.linkrev(filelog.node(j)))
   138                     n = filelog.node(j)
       
   139                     revs.append((filelog.linkrev(n),
       
   140                                  follow and filelog.renamed(n)))
   136                 revs.reverse()
   141                 revs.reverse()
   137                 for rev in revs:
   142                 for rev in revs:
   138                     # only yield rev for which we have the changelog, it can
   143                     # only yield rev for which we have the changelog, it can
   139                     # happen while doing "hg log" during a pull or commit
   144                     # happen while doing "hg log" during a pull or commit
   140                     if rev < cl_count:
   145                     if rev[0] < cl_count:
   141                         yield rev
   146                         yield rev
   142 
   147         def iterfiles():
       
   148             for filename in files:
       
   149                 yield filename, None
       
   150             for filename_node in copies:
       
   151                 yield filename_node
   143         minrev, maxrev = min(revs), max(revs)
   152         minrev, maxrev = min(revs), max(revs)
   144         for file_ in files:
   153         for file_, node in iterfiles():
   145             filelog = repo.file(file_)
   154             filelog = repo.file(file_)
   146             # A zero count may be a directory or deleted file, so
   155             # A zero count may be a directory or deleted file, so
   147             # try to find matching entries on the slow path.
   156             # try to find matching entries on the slow path.
   148             if filelog.count() == 0:
   157             if filelog.count() == 0:
   149                 slowpath = True
   158                 slowpath = True
   150                 break
   159                 break
   151             for rev in filerevgen(filelog):
   160             for rev, copied in filerevgen(filelog, node):
   152                 if rev <= maxrev:
   161                 if rev <= maxrev:
   153                     if rev < minrev:
   162                     if rev < minrev:
   154                         break
   163                         break
   155                     fncache.setdefault(rev, [])
   164                     fncache.setdefault(rev, [])
   156                     fncache[rev].append(file_)
   165                     fncache[rev].append(file_)
   157                     wanted[rev] = 1
   166                     wanted[rev] = 1
       
   167                     if follow and copied:
       
   168                         copies.append(copied)
   158     if slowpath:
   169     if slowpath:
       
   170         if follow:
       
   171             raise util.Abort(_('can only follow copies/renames for explicit '
       
   172                                'file names'))
       
   173 
   159         # The slow path checks files modified in every changeset.
   174         # The slow path checks files modified in every changeset.
   160         def changerevgen():
   175         def changerevgen():
   161             for i, window in increasing_windows(repo.changelog.count()-1, -1):
   176             for i, window in increasing_windows(repo.changelog.count()-1, -1):
   162                 for j in xrange(i - window, i + 1):
   177                 for j in xrange(i - window, i + 1):
   163                     yield j, getchange(j)[3]
   178                     yield j, getchange(j)[3]
   166             matches = filter(matchfn, changefiles)
   181             matches = filter(matchfn, changefiles)
   167             if matches:
   182             if matches:
   168                 fncache[rev] = matches
   183                 fncache[rev] = matches
   169                 wanted[rev] = 1
   184                 wanted[rev] = 1
   170 
   185 
       
   186     class followfilter:
       
   187         def __init__(self, onlyfirst=False):
       
   188             self.startrev = -1
       
   189             self.roots = []
       
   190             self.onlyfirst = onlyfirst
       
   191 
       
   192         def match(self, rev):
       
   193             def realparents(rev):
       
   194                 if self.onlyfirst:
       
   195                     return repo.changelog.parentrevs(rev)[0:1]
       
   196                 else:
       
   197                     return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
       
   198 
       
   199             if self.startrev == -1:
       
   200                 self.startrev = rev
       
   201                 return True
       
   202 
       
   203             if rev > self.startrev:
       
   204                 # forward: all descendants
       
   205                 if not self.roots:
       
   206                     self.roots.append(self.startrev)
       
   207                 for parent in realparents(rev):
       
   208                     if parent in self.roots:
       
   209                         self.roots.append(rev)
       
   210                         return True
       
   211             else:
       
   212                 # backwards: all parents
       
   213                 if not self.roots:
       
   214                     self.roots.extend(realparents(self.startrev))
       
   215                 if rev in self.roots:
       
   216                     self.roots.remove(rev)
       
   217                     self.roots.extend(realparents(rev))
       
   218                     return True
       
   219 
       
   220             return False
       
   221 
       
   222     # it might be worthwhile to do this in the iterator if the rev range
       
   223     # is descending and the prune args are all within that range
       
   224     for rev in opts.get('prune', ()):
       
   225         rev = repo.changelog.rev(repo.lookup(rev))
       
   226         ff = followfilter()
       
   227         stop = min(revs[0], revs[-1])
       
   228         for x in range(rev, stop-1, -1):
       
   229             if ff.match(x) and wanted.has_key(x):
       
   230                 del wanted[x]
       
   231 
   171     def iterate():
   232     def iterate():
       
   233         if follow and not files:
       
   234             ff = followfilter(onlyfirst=opts.get('follow_first'))
       
   235             def want(rev):
       
   236                 if ff.match(rev) and rev in wanted:
       
   237                     return True
       
   238                 return False
       
   239         else:
       
   240             def want(rev):
       
   241                 return rev in wanted
       
   242 
   172         for i, window in increasing_windows(0, len(revs)):
   243         for i, window in increasing_windows(0, len(revs)):
   173             yield 'window', revs[0] < revs[-1], revs[-1]
   244             yield 'window', revs[0] < revs[-1], revs[-1]
   174             nrevs = [rev for rev in revs[i:i+window]
   245             nrevs = [rev for rev in revs[i:i+window] if want(rev)]
   175                      if rev in wanted]
       
   176             srevs = list(nrevs)
   246             srevs = list(nrevs)
   177             srevs.sort()
   247             srevs.sort()
   178             for rev in srevs:
   248             for rev in srevs:
   179                 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
   249                 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
   180                 yield 'add', rev, fns
   250                 yield 'add', rev, fns
   250             if rev in seen:
   320             if rev in seen:
   251                 continue
   321                 continue
   252             seen[rev] = 1
   322             seen[rev] = 1
   253             yield str(rev)
   323             yield str(rev)
   254 
   324 
   255 def make_filename(repo, pat, node,
       
   256                   total=None, seqno=None, revwidth=None, pathname=None):
       
   257     node_expander = {
       
   258         'H': lambda: hex(node),
       
   259         'R': lambda: str(repo.changelog.rev(node)),
       
   260         'h': lambda: short(node),
       
   261         }
       
   262     expander = {
       
   263         '%': lambda: '%',
       
   264         'b': lambda: os.path.basename(repo.root),
       
   265         }
       
   266 
       
   267     try:
       
   268         if node:
       
   269             expander.update(node_expander)
       
   270         if node and revwidth is not None:
       
   271             expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
       
   272         if total is not None:
       
   273             expander['N'] = lambda: str(total)
       
   274         if seqno is not None:
       
   275             expander['n'] = lambda: str(seqno)
       
   276         if total is not None and seqno is not None:
       
   277             expander['n'] = lambda:str(seqno).zfill(len(str(total)))
       
   278         if pathname is not None:
       
   279             expander['s'] = lambda: os.path.basename(pathname)
       
   280             expander['d'] = lambda: os.path.dirname(pathname) or '.'
       
   281             expander['p'] = lambda: pathname
       
   282 
       
   283         newname = []
       
   284         patlen = len(pat)
       
   285         i = 0
       
   286         while i < patlen:
       
   287             c = pat[i]
       
   288             if c == '%':
       
   289                 i += 1
       
   290                 c = pat[i]
       
   291                 c = expander[c]()
       
   292             newname.append(c)
       
   293             i += 1
       
   294         return ''.join(newname)
       
   295     except KeyError, inst:
       
   296         raise util.Abort(_("invalid format spec '%%%s' in output file name"),
       
   297                     inst.args[0])
       
   298 
       
   299 def make_file(repo, pat, node=None,
       
   300               total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
       
   301     if not pat or pat == '-':
       
   302         return 'w' in mode and sys.stdout or sys.stdin
       
   303     if hasattr(pat, 'write') and 'w' in mode:
       
   304         return pat
       
   305     if hasattr(pat, 'read') and 'r' in mode:
       
   306         return pat
       
   307     return open(make_filename(repo, pat, node, total, seqno, revwidth,
       
   308                               pathname),
       
   309                 mode)
       
   310 
       
   311 def write_bundle(cg, filename=None, compress=True):
   325 def write_bundle(cg, filename=None, compress=True):
   312     """Write a bundle file and return its filename.
   326     """Write a bundle file and return its filename.
   313 
   327 
   314     Existing files will not be overwritten.
   328     Existing files will not be overwritten.
   315     If no filename is specified, a temporary file is created.
   329     If no filename is specified, a temporary file is created.
   358         if fh is not None:
   372         if fh is not None:
   359             fh.close()
   373             fh.close()
   360         if cleanup is not None:
   374         if cleanup is not None:
   361             os.unlink(cleanup)
   375             os.unlink(cleanup)
   362 
   376 
   363 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
       
   364            changes=None, text=False, opts={}):
       
   365     if not node1:
       
   366         node1 = repo.dirstate.parents()[0]
       
   367     # reading the data for node1 early allows it to play nicely
       
   368     # with repo.changes and the revlog cache.
       
   369     change = repo.changelog.read(node1)
       
   370     mmap = repo.manifest.read(change[0])
       
   371     date1 = util.datestr(change[2])
       
   372 
       
   373     if not changes:
       
   374         changes = repo.changes(node1, node2, files, match=match)
       
   375     modified, added, removed, deleted, unknown = changes
       
   376     if files:
       
   377         modified, added, removed = map(lambda x: filterfiles(files, x),
       
   378                                        (modified, added, removed))
       
   379 
       
   380     if not modified and not added and not removed:
       
   381         return
       
   382 
       
   383     if node2:
       
   384         change = repo.changelog.read(node2)
       
   385         mmap2 = repo.manifest.read(change[0])
       
   386         _date2 = util.datestr(change[2])
       
   387         def date2(f):
       
   388             return _date2
       
   389         def read(f):
       
   390             return repo.file(f).read(mmap2[f])
       
   391     else:
       
   392         tz = util.makedate()[1]
       
   393         _date2 = util.datestr()
       
   394         def date2(f):
       
   395             try:
       
   396                 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
       
   397             except OSError, err:
       
   398                 if err.errno != errno.ENOENT: raise
       
   399                 return _date2
       
   400         def read(f):
       
   401             return repo.wread(f)
       
   402 
       
   403     if ui.quiet:
       
   404         r = None
       
   405     else:
       
   406         hexfunc = ui.verbose and hex or short
       
   407         r = [hexfunc(node) for node in [node1, node2] if node]
       
   408 
       
   409     diffopts = ui.diffopts()
       
   410     showfunc = opts.get('show_function') or diffopts['showfunc']
       
   411     ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
       
   412     ignorewsamount = opts.get('ignore_space_change') or \
       
   413                      diffopts['ignorewsamount']
       
   414     ignoreblanklines = opts.get('ignore_blank_lines') or \
       
   415                      diffopts['ignoreblanklines']
       
   416     for f in modified:
       
   417         to = None
       
   418         if f in mmap:
       
   419             to = repo.file(f).read(mmap[f])
       
   420         tn = read(f)
       
   421         fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
       
   422                                showfunc=showfunc, ignorews=ignorews,
       
   423                                ignorewsamount=ignorewsamount,
       
   424                                ignoreblanklines=ignoreblanklines))
       
   425     for f in added:
       
   426         to = None
       
   427         tn = read(f)
       
   428         fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
       
   429                                showfunc=showfunc, ignorews=ignorews,
       
   430                                ignorewsamount=ignorewsamount,
       
   431                                ignoreblanklines=ignoreblanklines))
       
   432     for f in removed:
       
   433         to = repo.file(f).read(mmap[f])
       
   434         tn = None
       
   435         fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
       
   436                                showfunc=showfunc, ignorews=ignorews,
       
   437                                ignorewsamount=ignorewsamount,
       
   438                                ignoreblanklines=ignoreblanklines))
       
   439 
       
   440 def trimuser(ui, name, rev, revcache):
   377 def trimuser(ui, name, rev, revcache):
   441     """trim the name of the user who committed a change"""
   378     """trim the name of the user who committed a change"""
   442     user = revcache.get(rev)
   379     user = revcache.get(rev)
   443     if user is None:
   380     if user is None:
   444         user = revcache[rev] = ui.shortuser(name)
   381         user = revcache[rev] = ui.shortuser(name)
   491                       (self.repo.manifest.rev(changes[0]), hex(changes[0])))
   428                       (self.repo.manifest.rev(changes[0]), hex(changes[0])))
   492         self.ui.status(_("user:        %s\n") % changes[1])
   429         self.ui.status(_("user:        %s\n") % changes[1])
   493         self.ui.status(_("date:        %s\n") % date)
   430         self.ui.status(_("date:        %s\n") % date)
   494 
   431 
   495         if self.ui.debugflag:
   432         if self.ui.debugflag:
   496             files = self.repo.changes(log.parents(changenode)[0], changenode)
   433             files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
   497             for key, value in zip([_("files:"), _("files+:"), _("files-:")],
   434             for key, value in zip([_("files:"), _("files+:"), _("files-:")],
   498                                   files):
   435                                   files):
   499                 if value:
   436                 if value:
   500                     self.ui.note("%-12s %s\n" % (key, " ".join(value)))
   437                     self.ui.note("%-12s %s\n" % (key, " ".join(value)))
   501         else:
   438         else:
   535             raise util.Abort(inst.args[0])
   472             raise util.Abort(inst.args[0])
   536         if tmpl: t.use_template(tmpl)
   473         if tmpl: t.use_template(tmpl)
   537         return t
   474         return t
   538     return changeset_printer(ui, repo)
   475     return changeset_printer(ui, repo)
   539 
   476 
       
   477 def setremoteconfig(ui, opts):
       
   478     "copy remote options to ui tree"
       
   479     if opts.get('ssh'):
       
   480         ui.setconfig("ui", "ssh", opts['ssh'])
       
   481     if opts.get('remotecmd'):
       
   482         ui.setconfig("ui", "remotecmd", opts['remotecmd'])
       
   483 
   540 def show_version(ui):
   484 def show_version(ui):
   541     """output version and copyright information"""
   485     """output version and copyright information"""
   542     ui.write(_("Mercurial Distributed SCM (version %s)\n")
   486     ui.write(_("Mercurial Distributed SCM (version %s)\n")
   543              % version.get_version())
   487              % version.get_version())
   544     ui.status(_(
   488     ui.status(_(
   545         "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
   489         "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
   546         "This is free software; see the source for copying conditions. "
   490         "This is free software; see the source for copying conditions. "
   547         "There is NO\nwarranty; "
   491         "There is NO\nwarranty; "
   548         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
   492         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
   549     ))
   493     ))
   550 
   494 
   694 
   638 
   695     If no names are given, add all files in the repository.
   639     If no names are given, add all files in the repository.
   696     """
   640     """
   697 
   641 
   698     names = []
   642     names = []
   699     for src, abs, rel, exact in walk(repo, pats, opts):
   643     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
   700         if exact:
   644         if exact:
   701             if ui.verbose:
   645             if ui.verbose:
   702                 ui.status(_('adding %s\n') % rel)
   646                 ui.status(_('adding %s\n') % rel)
   703             names.append(abs)
   647             names.append(abs)
   704         elif repo.dirstate.state(abs) == '?':
   648         elif repo.dirstate.state(abs) == '?':
   713     Add all new files and remove all missing files from the repository.
   657     Add all new files and remove all missing files from the repository.
   714 
   658 
   715     New files are ignored if they match any of the patterns in .hgignore. As
   659     New files are ignored if they match any of the patterns in .hgignore. As
   716     with add, these changes take effect at the next commit.
   660     with add, these changes take effect at the next commit.
   717     """
   661     """
   718     return addremove_lock(ui, repo, pats, opts)
   662     return cmdutil.addremove(repo, pats, opts)
   719 
       
   720 def addremove_lock(ui, repo, pats, opts, wlock=None):
       
   721     add, remove = [], []
       
   722     for src, abs, rel, exact in walk(repo, pats, opts):
       
   723         if src == 'f' and repo.dirstate.state(abs) == '?':
       
   724             add.append(abs)
       
   725             if ui.verbose or not exact:
       
   726                 ui.status(_('adding %s\n') % ((pats and rel) or abs))
       
   727         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
       
   728             remove.append(abs)
       
   729             if ui.verbose or not exact:
       
   730                 ui.status(_('removing %s\n') % ((pats and rel) or abs))
       
   731     if not opts.get('dry_run'):
       
   732         repo.add(add, wlock=wlock)
       
   733         repo.remove(remove, wlock=wlock)
       
   734 
   663 
   735 def annotate(ui, repo, *pats, **opts):
   664 def annotate(ui, repo, *pats, **opts):
   736     """show changeset information per file line
   665     """show changeset information per file line
   737 
   666 
   738     List changes in files, showing the revision id responsible for each line
   667     List changes in files, showing the revision id responsible for each line
   771     if not opts['user'] and not opts['changeset'] and not opts['date']:
   700     if not opts['user'] and not opts['changeset'] and not opts['date']:
   772         opts['number'] = 1
   701         opts['number'] = 1
   773 
   702 
   774     ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
   703     ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
   775 
   704 
   776     for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
   705     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
       
   706                                              node=ctx.node()):
   777         fctx = ctx.filectx(abs)
   707         fctx = ctx.filectx(abs)
   778         if not opts['text'] and util.binary(fctx.data()):
   708         if not opts['text'] and util.binary(fctx.data()):
   779             ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
   709             ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
   780             continue
   710             continue
   781 
   711 
   823         node, p2 = repo.dirstate.parents()
   753         node, p2 = repo.dirstate.parents()
   824         if p2 != nullid:
   754         if p2 != nullid:
   825             raise util.Abort(_('uncommitted merge - please provide a '
   755             raise util.Abort(_('uncommitted merge - please provide a '
   826                                'specific revision'))
   756                                'specific revision'))
   827 
   757 
   828     dest = make_filename(repo, dest, node)
   758     dest = cmdutil.make_filename(repo, dest, node)
   829     if os.path.realpath(dest) == repo.root:
   759     if os.path.realpath(dest) == repo.root:
   830         raise util.Abort(_('repository root cannot be destination'))
   760         raise util.Abort(_('repository root cannot be destination'))
   831     dummy, matchfn, dummy = matchpats(repo, [], opts)
   761     dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
   832     kind = opts.get('type') or 'files'
   762     kind = opts.get('type') or 'files'
   833     prefix = opts['prefix']
   763     prefix = opts['prefix']
   834     if dest == '-':
   764     if dest == '-':
   835         if kind == 'files':
   765         if kind == 'files':
   836             raise util.Abort(_('cannot archive plain files to stdout'))
   766             raise util.Abort(_('cannot archive plain files to stdout'))
   837         dest = sys.stdout
   767         dest = sys.stdout
   838         if not prefix: prefix = os.path.basename(repo.root) + '-%h'
   768         if not prefix: prefix = os.path.basename(repo.root) + '-%h'
   839     prefix = make_filename(repo, prefix, node)
   769     prefix = cmdutil.make_filename(repo, prefix, node)
   840     archival.archive(repo, dest, node, kind, not opts['no_decode'],
   770     archival.archive(repo, dest, node, kind, not opts['no_decode'],
   841                      matchfn, prefix)
   771                      matchfn, prefix)
   842 
   772 
   843 def backout(ui, repo, rev, **opts):
   773 def backout(ui, repo, rev, **opts):
   844     '''reverse effect of earlier changeset
   774     '''reverse effect of earlier changeset
   877         parent = p
   807         parent = p
   878     else:
   808     else:
   879         if opts['parent']:
   809         if opts['parent']:
   880             raise util.Abort(_('cannot use --parent on non-merge changeset'))
   810             raise util.Abort(_('cannot use --parent on non-merge changeset'))
   881         parent = p1
   811         parent = p1
   882     repo.update(node, force=True, show_stats=False)
   812     hg.clean(repo, node, show_stats=False)
   883     revert_opts = opts.copy()
   813     revert_opts = opts.copy()
   884     revert_opts['rev'] = hex(parent)
   814     revert_opts['rev'] = hex(parent)
   885     revert(ui, repo, **revert_opts)
   815     revert(ui, repo, **revert_opts)
   886     commit_opts = opts.copy()
   816     commit_opts = opts.copy()
   887     commit_opts['addremove'] = False
   817     commit_opts['addremove'] = False
   894     ui.status(_('changeset %s backs out changeset %s\n') %
   824     ui.status(_('changeset %s backs out changeset %s\n') %
   895               (nice(repo.changelog.tip()), nice(node)))
   825               (nice(repo.changelog.tip()), nice(node)))
   896     if op1 != node:
   826     if op1 != node:
   897         if opts['merge']:
   827         if opts['merge']:
   898             ui.status(_('merging with changeset %s\n') % nice(op1))
   828             ui.status(_('merging with changeset %s\n') % nice(op1))
   899             doupdate(ui, repo, hex(op1), **opts)
   829             n = _lookup(repo, hex(op1))
       
   830             hg.merge(repo, n)
   900         else:
   831         else:
   901             ui.status(_('the backout changeset is a new head - '
   832             ui.status(_('the backout changeset is a new head - '
   902                         'do not forget to merge\n'))
   833                         'do not forget to merge\n'))
   903             ui.status(_('(use "backout -m" if you want to auto-merge)\n'))
   834             ui.status(_('(use "backout --merge" '
       
   835                         'if you want to auto-merge)\n'))
   904 
   836 
   905 def bundle(ui, repo, fname, dest=None, **opts):
   837 def bundle(ui, repo, fname, dest=None, **opts):
   906     """create a changegroup file
   838     """create a changegroup file
   907 
   839 
   908     Generate a compressed changegroup file collecting all changesets
   840     Generate a compressed changegroup file collecting all changesets
   935 
   867 
   936     %s   basename of file being printed
   868     %s   basename of file being printed
   937     %d   dirname of file being printed, or '.' if in repo root
   869     %d   dirname of file being printed, or '.' if in repo root
   938     %p   root-relative path name of file being printed
   870     %p   root-relative path name of file being printed
   939     """
   871     """
   940     ctx = repo.changectx(opts['rev'] or -1)
   872     ctx = repo.changectx(opts['rev'] or "-1")
   941     for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
   873     for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
   942         fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
   874                                              ctx.node()):
       
   875         fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
   943         fp.write(ctx.filectx(abs).data())
   876         fp.write(ctx.filectx(abs).data())
   944 
   877 
   945 def clone(ui, source, dest=None, **opts):
   878 def clone(ui, source, dest=None, **opts):
   946     """make a copy of an existing repository
   879     """make a copy of an existing repository
   947 
   880 
   952 
   885 
   953     The location of the source is added to the new repository's
   886     The location of the source is added to the new repository's
   954     .hg/hgrc file, as the default to be used for future pulls.
   887     .hg/hgrc file, as the default to be used for future pulls.
   955 
   888 
   956     For efficiency, hardlinks are used for cloning whenever the source
   889     For efficiency, hardlinks are used for cloning whenever the source
   957     and destination are on the same filesystem.  Some filesystems,
   890     and destination are on the same filesystem (note this applies only
   958     such as AFS, implement hardlinking incorrectly, but do not report
   891     to the repository data, not to the checked out files).  Some
   959     errors.  In these cases, use the --pull option to avoid
   892     filesystems, such as AFS, implement hardlinking incorrectly, but
   960     hardlinking.
   893     do not report errors.  In these cases, use the --pull option to
       
   894     avoid hardlinking.
       
   895 
       
   896     You can safely clone repositories and checked out files using full
       
   897     hardlinks with
       
   898 
       
   899       $ cp -al REPO REPOCLONE
       
   900 
       
   901     which is the fastest way to clone. However, the operation is not
       
   902     atomic (making sure REPO is not modified during the operation is
       
   903     up to you) and you have to make sure your editor breaks hardlinks
       
   904     (Emacs and most Linux Kernel tools do so).
       
   905 
       
   906     If you use the -r option to clone up to a specific revision, no
       
   907     subsequent revisions will be present in the cloned repository.
       
   908     This option implies --pull, even on local repositories.
   961 
   909 
   962     See pull for valid source format details.
   910     See pull for valid source format details.
   963 
   911 
   964     It is possible to specify an ssh:// URL as the destination, but no
   912     It is possible to specify an ssh:// URL as the destination, but no
   965     .hg/hgrc will be created on the remote side. Look at the help text
   913     .hg/hgrc will be created on the remote side. Look at the help text
   966     for the pull command for important details about ssh:// URLs.
   914     for the pull command for important details about ssh:// URLs.
   967     """
   915     """
   968     ui.setconfig_remoteopts(**opts)
   916     setremoteconfig(ui, opts)
   969     hg.clone(ui, ui.expandpath(source), dest,
   917     hg.clone(ui, ui.expandpath(source), dest,
   970              pull=opts['pull'],
   918              pull=opts['pull'],
   971              stream=opts['uncompressed'],
   919              stream=opts['uncompressed'],
   972              rev=opts['rev'],
   920              rev=opts['rev'],
   973              update=not opts['noupdate'])
   921              update=not opts['noupdate'])
   981     will be committed.
   929     will be committed.
   982 
   930 
   983     If no commit message is specified, the editor configured in your hgrc
   931     If no commit message is specified, the editor configured in your hgrc
   984     or in the EDITOR environment variable is started to enter a message.
   932     or in the EDITOR environment variable is started to enter a message.
   985     """
   933     """
   986     message = opts['message']
   934     message = logmessage(opts)
   987     logfile = opts['logfile']
       
   988 
       
   989     if message and logfile:
       
   990         raise util.Abort(_('options --message and --logfile are mutually '
       
   991                            'exclusive'))
       
   992     if not message and logfile:
       
   993         try:
       
   994             if logfile == '-':
       
   995                 message = sys.stdin.read()
       
   996             else:
       
   997                 message = open(logfile).read()
       
   998         except IOError, inst:
       
   999             raise util.Abort(_("can't read commit message '%s': %s") %
       
  1000                              (logfile, inst.strerror))
       
  1001 
   935 
  1002     if opts['addremove']:
   936     if opts['addremove']:
  1003         addremove_lock(ui, repo, pats, opts)
   937         cmdutil.addremove(repo, pats, opts)
  1004     fns, match, anypats = matchpats(repo, pats, opts)
   938     fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
  1005     if pats:
   939     if pats:
  1006         modified, added, removed, deleted, unknown = (
   940         modified, added, removed = repo.status(files=fns, match=match)[:3]
  1007             repo.changes(files=fns, match=match))
       
  1008         files = modified + added + removed
   941         files = modified + added + removed
  1009     else:
   942     else:
  1010         files = []
   943         files = []
  1011     try:
   944     try:
  1012         repo.commit(files, message, opts['user'], opts['date'], match,
   945         repo.commit(files, message, opts['user'], opts['date'], match,
  1157     else:
  1090     else:
  1158         tfn = targetpathfn
  1091         tfn = targetpathfn
  1159     copylist = []
  1092     copylist = []
  1160     for pat in pats:
  1093     for pat in pats:
  1161         srcs = []
  1094         srcs = []
  1162         for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
  1095         for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
  1163             origsrc = okaytocopy(abssrc, relsrc, exact)
  1096             origsrc = okaytocopy(abssrc, relsrc, exact)
  1164             if origsrc:
  1097             if origsrc:
  1165                 srcs.append((origsrc, abssrc, relsrc, exact))
  1098                 srcs.append((origsrc, abssrc, relsrc, exact))
  1166         if not srcs:
  1099         if not srcs:
  1167             continue
  1100             continue
  1231         rev = repo.changelog.tip()
  1164         rev = repo.changelog.tip()
  1232     else:
  1165     else:
  1233         rev = repo.lookup(rev)
  1166         rev = repo.lookup(rev)
  1234     change = repo.changelog.read(rev)
  1167     change = repo.changelog.read(rev)
  1235     n = change[0]
  1168     n = change[0]
  1236     files = repo.manifest.readflags(n)
  1169     files = repo.manifest.read(n)
  1237     wlock = repo.wlock()
  1170     wlock = repo.wlock()
  1238     repo.dirstate.rebuild(rev, files.iteritems())
  1171     repo.dirstate.rebuild(rev, files)
  1239 
  1172 
  1240 def debugcheckstate(ui, repo):
  1173 def debugcheckstate(ui, repo):
  1241     """validate the correctness of the current dirstate"""
  1174     """validate the correctness of the current dirstate"""
  1242     parent1, parent2 = repo.dirstate.parents()
  1175     parent1, parent2 = repo.dirstate.parents()
  1243     repo.dirstate.read()
  1176     repo.dirstate.read()
  1374     else:
  1307     else:
  1375         ui.write(_("not renamed\n"))
  1308         ui.write(_("not renamed\n"))
  1376 
  1309 
  1377 def debugwalk(ui, repo, *pats, **opts):
  1310 def debugwalk(ui, repo, *pats, **opts):
  1378     """show how files match on given patterns"""
  1311     """show how files match on given patterns"""
  1379     items = list(walk(repo, pats, opts))
  1312     items = list(cmdutil.walk(repo, pats, opts))
  1380     if not items:
  1313     if not items:
  1381         return
  1314         return
  1382     fmt = '%%s  %%-%ds  %%-%ds  %%s' % (
  1315     fmt = '%%s  %%-%ds  %%-%ds  %%s' % (
  1383         max([len(abs) for (src, abs, rel, exact) in items]),
  1316         max([len(abs) for (src, abs, rel, exact) in items]),
  1384         max([len(rel) for (src, abs, rel, exact) in items]))
  1317         max([len(rel) for (src, abs, rel, exact) in items]))
  1403     it detects as binary. With -a, diff will generate a diff anyway,
  1336     it detects as binary. With -a, diff will generate a diff anyway,
  1404     probably with undesirable results.
  1337     probably with undesirable results.
  1405     """
  1338     """
  1406     node1, node2 = revpair(ui, repo, opts['rev'])
  1339     node1, node2 = revpair(ui, repo, opts['rev'])
  1407 
  1340 
  1408     fns, matchfn, anypats = matchpats(repo, pats, opts)
  1341     fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
  1409 
  1342 
  1410     dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
  1343     patch.diff(repo, node1, node2, fns, match=matchfn,
  1411            text=opts['text'], opts=opts)
  1344                opts=patch.diffopts(ui, opts))
  1412 
       
  1413 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
       
  1414     node = repo.lookup(changeset)
       
  1415     parents = [p for p in repo.changelog.parents(node) if p != nullid]
       
  1416     if opts['switch_parent']:
       
  1417         parents.reverse()
       
  1418     prev = (parents and parents[0]) or nullid
       
  1419     change = repo.changelog.read(node)
       
  1420 
       
  1421     fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
       
  1422                    revwidth=revwidth)
       
  1423     if fp != sys.stdout:
       
  1424         ui.note("%s\n" % fp.name)
       
  1425 
       
  1426     fp.write("# HG changeset patch\n")
       
  1427     fp.write("# User %s\n" % change[1])
       
  1428     fp.write("# Date %d %d\n" % change[2])
       
  1429     fp.write("# Node ID %s\n" % hex(node))
       
  1430     fp.write("# Parent  %s\n" % hex(prev))
       
  1431     if len(parents) > 1:
       
  1432         fp.write("# Parent  %s\n" % hex(parents[1]))
       
  1433     fp.write(change[4].rstrip())
       
  1434     fp.write("\n\n")
       
  1435 
       
  1436     dodiff(fp, ui, repo, prev, node, text=opts['text'])
       
  1437     if fp != sys.stdout:
       
  1438         fp.close()
       
  1439 
  1345 
  1440 def export(ui, repo, *changesets, **opts):
  1346 def export(ui, repo, *changesets, **opts):
  1441     """dump the header and diffs for one or more changesets
  1347     """dump the header and diffs for one or more changesets
  1442 
  1348 
  1443     Print the changeset header and diffs for one or more revisions.
  1349     Print the changeset header and diffs for one or more revisions.
  1464     With the --switch-parent option, the diff will be against the second
  1370     With the --switch-parent option, the diff will be against the second
  1465     parent. It can be useful to review a merge.
  1371     parent. It can be useful to review a merge.
  1466     """
  1372     """
  1467     if not changesets:
  1373     if not changesets:
  1468         raise util.Abort(_("export requires at least one changeset"))
  1374         raise util.Abort(_("export requires at least one changeset"))
  1469     seqno = 0
       
  1470     revs = list(revrange(ui, repo, changesets))
  1375     revs = list(revrange(ui, repo, changesets))
  1471     total = len(revs)
  1376     if len(revs) > 1:
  1472     revwidth = max(map(len, revs))
  1377         ui.note(_('exporting patches:\n'))
  1473     msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
  1378     else:
  1474     ui.note(msg)
  1379         ui.note(_('exporting patch:\n'))
  1475     for cset in revs:
  1380     patch.export(repo, map(repo.lookup, revs), template=opts['output'],
  1476         seqno += 1
  1381                  switch_parent=opts['switch_parent'],
  1477         doexport(ui, repo, cset, seqno, total, revwidth, opts)
  1382                  opts=patch.diffopts(ui, opts))
  1478 
  1383 
  1479 def forget(ui, repo, *pats, **opts):
  1384 def forget(ui, repo, *pats, **opts):
  1480     """don't add the specified files on the next commit (DEPRECATED)
  1385     """don't add the specified files on the next commit (DEPRECATED)
  1481 
  1386 
  1482     (DEPRECATED)
  1387     (DEPRECATED)
  1485     This command is now deprecated and will be removed in a future
  1390     This command is now deprecated and will be removed in a future
  1486     release. Please use revert instead.
  1391     release. Please use revert instead.
  1487     """
  1392     """
  1488     ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
  1393     ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
  1489     forget = []
  1394     forget = []
  1490     for src, abs, rel, exact in walk(repo, pats, opts):
  1395     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
  1491         if repo.dirstate.state(abs) == 'a':
  1396         if repo.dirstate.state(abs) == 'a':
  1492             forget.append(abs)
  1397             forget.append(abs)
  1493             if ui.verbose or not exact:
  1398             if ui.verbose or not exact:
  1494                 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
  1399                 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
  1495     repo.forget(forget)
  1400     repo.forget(forget)
  1542         def __init__(self, line, linenum, colstart, colend):
  1447         def __init__(self, line, linenum, colstart, colend):
  1543             self.line = line
  1448             self.line = line
  1544             self.linenum = linenum
  1449             self.linenum = linenum
  1545             self.colstart = colstart
  1450             self.colstart = colstart
  1546             self.colend = colend
  1451             self.colend = colend
       
  1452 
  1547         def __eq__(self, other):
  1453         def __eq__(self, other):
  1548             return self.line == other.line
  1454             return self.line == other.line
  1549         def __hash__(self):
       
  1550             return hash(self.line)
       
  1551 
  1455 
  1552     matches = {}
  1456     matches = {}
       
  1457     copies = {}
  1553     def grepbody(fn, rev, body):
  1458     def grepbody(fn, rev, body):
  1554         matches[rev].setdefault(fn, {})
  1459         matches[rev].setdefault(fn, [])
  1555         m = matches[rev][fn]
  1460         m = matches[rev][fn]
  1556         for lnum, cstart, cend, line in matchlines(body):
  1461         for lnum, cstart, cend, line in matchlines(body):
  1557             s = linestate(line, lnum, cstart, cend)
  1462             s = linestate(line, lnum, cstart, cend)
  1558             m[s] = s
  1463             m.append(s)
  1559 
  1464 
  1560     # FIXME: prev isn't used, why ?
  1465     def difflinestates(a, b):
       
  1466         sm = difflib.SequenceMatcher(None, a, b)
       
  1467         for tag, alo, ahi, blo, bhi in sm.get_opcodes():
       
  1468             if tag == 'insert':
       
  1469                 for i in range(blo, bhi):
       
  1470                     yield ('+', b[i])
       
  1471             elif tag == 'delete':
       
  1472                 for i in range(alo, ahi):
       
  1473                     yield ('-', a[i])
       
  1474             elif tag == 'replace':
       
  1475                 for i in range(alo, ahi):
       
  1476                     yield ('-', a[i])
       
  1477                 for i in range(blo, bhi):
       
  1478                     yield ('+', b[i])
       
  1479 
  1561     prev = {}
  1480     prev = {}
  1562     ucache = {}
  1481     ucache = {}
  1563     def display(fn, rev, states, prevstates):
  1482     def display(fn, rev, states, prevstates):
  1564         diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
       
  1565         diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
       
  1566         counts = {'-': 0, '+': 0}
  1483         counts = {'-': 0, '+': 0}
  1567         filerevmatches = {}
  1484         filerevmatches = {}
  1568         for l in diff:
  1485         if incrementing or not opts['all']:
       
  1486             a, b = prevstates, states
       
  1487         else:
       
  1488             a, b = states, prevstates
       
  1489         for change, l in difflinestates(a, b):
  1569             if incrementing or not opts['all']:
  1490             if incrementing or not opts['all']:
  1570                 change = ((l in prevstates) and '-') or '+'
       
  1571                 r = rev
  1491                 r = rev
  1572             else:
  1492             else:
  1573                 change = ((l in states) and '-') or '+'
       
  1574                 r = prev[fn]
  1493                 r = prev[fn]
  1575             cols = [fn, str(rev)]
  1494             cols = [fn, str(r)]
  1576             if opts['line_number']:
  1495             if opts['line_number']:
  1577                 cols.append(str(l.linenum))
  1496                 cols.append(str(l.linenum))
  1578             if opts['all']:
  1497             if opts['all']:
  1579                 cols.append(change)
  1498                 cols.append(change)
  1580             if opts['user']:
  1499             if opts['user']:
  1581                 cols.append(trimuser(ui, getchange(rev)[1], rev,
  1500                 cols.append(trimuser(ui, getchange(r)[1], rev,
  1582                                                   ucache))
  1501                                      ucache))
  1583             if opts['files_with_matches']:
  1502             if opts['files_with_matches']:
  1584                 c = (fn, rev)
  1503                 c = (fn, rev)
  1585                 if c in filerevmatches:
  1504                 if c in filerevmatches:
  1586                     continue
  1505                     continue
  1587                 filerevmatches[c] = 1
  1506                 filerevmatches[c] = 1
  1594     fstate = {}
  1513     fstate = {}
  1595     skip = {}
  1514     skip = {}
  1596     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
  1515     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
  1597     count = 0
  1516     count = 0
  1598     incrementing = False
  1517     incrementing = False
       
  1518     follow = opts.get('follow')
  1599     for st, rev, fns in changeiter:
  1519     for st, rev, fns in changeiter:
  1600         if st == 'window':
  1520         if st == 'window':
  1601             incrementing = rev
  1521             incrementing = rev
  1602             matches.clear()
  1522             matches.clear()
  1603         elif st == 'add':
  1523         elif st == 'add':
  1608                 if fn in skip:
  1528                 if fn in skip:
  1609                     continue
  1529                     continue
  1610                 fstate.setdefault(fn, {})
  1530                 fstate.setdefault(fn, {})
  1611                 try:
  1531                 try:
  1612                     grepbody(fn, rev, getfile(fn).read(mf[fn]))
  1532                     grepbody(fn, rev, getfile(fn).read(mf[fn]))
       
  1533                     if follow:
       
  1534                         copied = getfile(fn).renamed(mf[fn])
       
  1535                         if copied:
       
  1536                             copies.setdefault(rev, {})[fn] = copied[0]
  1613                 except KeyError:
  1537                 except KeyError:
  1614                     pass
  1538                     pass
  1615         elif st == 'iter':
  1539         elif st == 'iter':
  1616             states = matches[rev].items()
  1540             states = matches[rev].items()
  1617             states.sort()
  1541             states.sort()
  1618             for fn, m in states:
  1542             for fn, m in states:
       
  1543                 copy = copies.get(rev, {}).get(fn)
  1619                 if fn in skip:
  1544                 if fn in skip:
       
  1545                     if copy:
       
  1546                         skip[copy] = True
  1620                     continue
  1547                     continue
  1621                 if incrementing or not opts['all'] or fstate[fn]:
  1548                 if incrementing or not opts['all'] or fstate[fn]:
  1622                     pos, neg = display(fn, rev, m, fstate[fn])
  1549                     pos, neg = display(fn, rev, m, fstate[fn])
  1623                     count += pos + neg
  1550                     count += pos + neg
  1624                     if pos and not opts['all']:
  1551                     if pos and not opts['all']:
  1625                         skip[fn] = True
  1552                         skip[fn] = True
       
  1553                         if copy:
       
  1554                             skip[copy] = True
  1626                 fstate[fn] = m
  1555                 fstate[fn] = m
       
  1556                 if copy:
       
  1557                     fstate[copy] = m
  1627                 prev[fn] = rev
  1558                 prev[fn] = rev
  1628 
  1559 
  1629     if not incrementing:
  1560     if not incrementing:
  1630         fstate = fstate.items()
  1561         fstate = fstate.items()
  1631         fstate.sort()
  1562         fstate.sort()
  1632         for fn, state in fstate:
  1563         for fn, state in fstate:
  1633             if fn in skip:
  1564             if fn in skip:
  1634                 continue
  1565                 continue
  1635             display(fn, rev, {}, state)
  1566             if fn not in copies.get(prev[fn], {}):
       
  1567                 display(fn, rev, {}, state)
  1636     return (count == 0 and 1) or 0
  1568     return (count == 0 and 1) or 0
  1637 
  1569 
  1638 def heads(ui, repo, **opts):
  1570 def heads(ui, repo, **opts):
  1639     """show current repository heads
  1571     """show current repository heads
  1640 
  1572 
  1668     if not parents:
  1600     if not parents:
  1669         ui.write(_("unknown\n"))
  1601         ui.write(_("unknown\n"))
  1670         return
  1602         return
  1671 
  1603 
  1672     hexfunc = ui.verbose and hex or short
  1604     hexfunc = ui.verbose and hex or short
  1673     modified, added, removed, deleted, unknown = repo.changes()
  1605     modified, added, removed, deleted = repo.status()[:4]
  1674     output = ["%s%s" %
  1606     output = ["%s%s" %
  1675               ('+'.join([hexfunc(parent) for parent in parents]),
  1607               ('+'.join([hexfunc(parent) for parent in parents]),
  1676               (modified or added or removed or deleted) and "+" or "")]
  1608               (modified or added or removed or deleted) and "+" or "")]
  1677 
  1609 
  1678     if not ui.quiet:
  1610     if not ui.quiet:
  1712         bail_if_changed(repo)
  1644         bail_if_changed(repo)
  1713 
  1645 
  1714     d = opts["base"]
  1646     d = opts["base"]
  1715     strip = opts["strip"]
  1647     strip = opts["strip"]
  1716 
  1648 
  1717     mailre = re.compile(r'(?:From |[\w-]+:)')
  1649     wlock = repo.wlock()
  1718 
  1650     lock = repo.lock()
  1719     # attempt to detect the start of a patch
  1651 
  1720     # (this heuristic is borrowed from quilt)
  1652     for p in patches:
  1721     diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
  1653         pf = os.path.join(d, p)
  1722                         'retrieving revision [0-9]+(\.[0-9]+)*$|' +
  1654 
  1723                         '(---|\*\*\*)[ \t])', re.MULTILINE)
       
  1724 
       
  1725     for patch in patches:
       
  1726         pf = os.path.join(d, patch)
       
  1727 
       
  1728         message = None
       
  1729         user = None
       
  1730         date = None
       
  1731         hgpatch = False
       
  1732 
       
  1733         p = email.Parser.Parser()
       
  1734         if pf == '-':
  1655         if pf == '-':
  1735             msg = p.parse(sys.stdin)
       
  1736             ui.status(_("applying patch from stdin\n"))
  1656             ui.status(_("applying patch from stdin\n"))
  1737         else:
  1657             tmpname, message, user, date = patch.extract(ui, sys.stdin)
  1738             msg = p.parse(file(pf))
  1658         else:
  1739             ui.status(_("applying %s\n") % patch)
  1659             ui.status(_("applying %s\n") % p)
  1740 
  1660             tmpname, message, user, date = patch.extract(ui, file(pf))
  1741         fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
  1661 
  1742         tmpfp = os.fdopen(fd, 'w')
  1662         if tmpname is None:
       
  1663             raise util.Abort(_('no diffs found'))
       
  1664 
  1743         try:
  1665         try:
  1744             message = msg['Subject']
       
  1745             if message:
       
  1746                 message = message.replace('\n\t', ' ')
       
  1747                 ui.debug('Subject: %s\n' % message)
       
  1748             user = msg['From']
       
  1749             if user:
       
  1750                 ui.debug('From: %s\n' % user)
       
  1751             diffs_seen = 0
       
  1752             ok_types = ('text/plain', 'text/x-patch')
       
  1753             for part in msg.walk():
       
  1754                 content_type = part.get_content_type()
       
  1755                 ui.debug('Content-Type: %s\n' % content_type)
       
  1756                 if content_type not in ok_types:
       
  1757                     continue
       
  1758                 payload = part.get_payload(decode=True)
       
  1759                 m = diffre.search(payload)
       
  1760                 if m:
       
  1761                     ui.debug(_('found patch at byte %d\n') % m.start(0))
       
  1762                     diffs_seen += 1
       
  1763                     hgpatch = False
       
  1764                     fp = cStringIO.StringIO()
       
  1765                     if message:
       
  1766                         fp.write(message)
       
  1767                         fp.write('\n')
       
  1768                     for line in payload[:m.start(0)].splitlines():
       
  1769                         if line.startswith('# HG changeset patch'):
       
  1770                             ui.debug(_('patch generated by hg export\n'))
       
  1771                             hgpatch = True
       
  1772                             # drop earlier commit message content
       
  1773                             fp.seek(0)
       
  1774                             fp.truncate()
       
  1775                         elif hgpatch:
       
  1776                             if line.startswith('# User '):
       
  1777                                 user = line[7:]
       
  1778                                 ui.debug('From: %s\n' % user)
       
  1779                             elif line.startswith("# Date "):
       
  1780                                 date = line[7:]
       
  1781                         if not line.startswith('# '):
       
  1782                             fp.write(line)
       
  1783                             fp.write('\n')
       
  1784                     message = fp.getvalue()
       
  1785                     if tmpfp:
       
  1786                         tmpfp.write(payload)
       
  1787                         if not payload.endswith('\n'):
       
  1788                             tmpfp.write('\n')
       
  1789                 elif not diffs_seen and message and content_type == 'text/plain':
       
  1790                     message += '\n' + payload
       
  1791 
       
  1792             if opts['message']:
  1666             if opts['message']:
  1793                 # pickup the cmdline msg
  1667                 # pickup the cmdline msg
  1794                 message = opts['message']
  1668                 message = opts['message']
  1795             elif message:
  1669             elif message:
  1796                 # pickup the patch msg
  1670                 # pickup the patch msg
  1798             else:
  1672             else:
  1799                 # launch the editor
  1673                 # launch the editor
  1800                 message = None
  1674                 message = None
  1801             ui.debug(_('message:\n%s\n') % message)
  1675             ui.debug(_('message:\n%s\n') % message)
  1802 
  1676 
  1803             tmpfp.close()
  1677             files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
  1804             if not diffs_seen:
  1678             files = patch.updatedir(ui, repo, files, wlock=wlock)
  1805                 raise util.Abort(_('no diffs found'))
  1679             repo.commit(files, message, user, date, wlock=wlock, lock=lock)
  1806 
       
  1807             files = util.patch(strip, tmpname, ui)
       
  1808             if len(files) > 0:
       
  1809                 addremove_lock(ui, repo, files, {})
       
  1810             repo.commit(files, message, user, date)
       
  1811         finally:
  1680         finally:
  1812             os.unlink(tmpname)
  1681             os.unlink(tmpname)
  1813 
  1682 
  1814 def incoming(ui, repo, source="default", **opts):
  1683 def incoming(ui, repo, source="default", **opts):
  1815     """show new changesets found in source
  1684     """show new changesets found in source
  1822     twice if the incoming is followed by a pull.
  1691     twice if the incoming is followed by a pull.
  1823 
  1692 
  1824     See pull for valid source format details.
  1693     See pull for valid source format details.
  1825     """
  1694     """
  1826     source = ui.expandpath(source)
  1695     source = ui.expandpath(source)
  1827     ui.setconfig_remoteopts(**opts)
  1696     setremoteconfig(ui, opts)
  1828 
  1697 
  1829     other = hg.repository(ui, source)
  1698     other = hg.repository(ui, source)
  1830     incoming = repo.findincoming(other, force=opts["force"])
  1699     incoming = repo.findincoming(other, force=opts["force"])
  1831     if not incoming:
  1700     if not incoming:
  1832         ui.status(_("no changes found\n"))
  1701         ui.status(_("no changes found\n"))
  1858             if opts['no_merges'] and len(parents) == 2:
  1727             if opts['no_merges'] and len(parents) == 2:
  1859                 continue
  1728                 continue
  1860             displayer.show(changenode=n)
  1729             displayer.show(changenode=n)
  1861             if opts['patch']:
  1730             if opts['patch']:
  1862                 prev = (parents and parents[0]) or nullid
  1731                 prev = (parents and parents[0]) or nullid
  1863                 dodiff(ui, ui, other, prev, n)
  1732                 patch.diff(repo, other, prev, n)
  1864                 ui.write("\n")
  1733                 ui.write("\n")
  1865     finally:
  1734     finally:
  1866         if hasattr(other, 'close'):
  1735         if hasattr(other, 'close'):
  1867             other.close()
  1736             other.close()
  1868         if cleanup:
  1737         if cleanup:
  1878 
  1747 
  1879     It is possible to specify an ssh:// URL as the destination.
  1748     It is possible to specify an ssh:// URL as the destination.
  1880     Look at the help text for the pull command for important details
  1749     Look at the help text for the pull command for important details
  1881     about ssh:// URLs.
  1750     about ssh:// URLs.
  1882     """
  1751     """
  1883     ui.setconfig_remoteopts(**opts)
  1752     setremoteconfig(ui, opts)
  1884     hg.repository(ui, dest, create=1)
  1753     hg.repository(ui, dest, create=1)
  1885 
  1754 
  1886 def locate(ui, repo, *pats, **opts):
  1755 def locate(ui, repo, *pats, **opts):
  1887     """locate files matching specific patterns
  1756     """locate files matching specific patterns
  1888 
  1757 
  1906     if rev:
  1775     if rev:
  1907         node = repo.lookup(rev)
  1776         node = repo.lookup(rev)
  1908     else:
  1777     else:
  1909         node = None
  1778         node = None
  1910 
  1779 
  1911     for src, abs, rel, exact in walk(repo, pats, opts, node=node,
  1780     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
  1912                                      head='(?:.*/|)'):
  1781                                              head='(?:.*/|)'):
  1913         if not node and repo.dirstate.state(abs) == '?':
  1782         if not node and repo.dirstate.state(abs) == '?':
  1914             continue
  1783             continue
  1915         if opts['fullpath']:
  1784         if opts['fullpath']:
  1916             ui.write(os.path.join(repo.root, abs), end)
  1785             ui.write(os.path.join(repo.root, abs), end)
  1917         else:
  1786         else:
  1918             ui.write(((pats and rel) or abs), end)
  1787             ui.write(((pats and rel) or abs), end)
  1919 
  1788 
  1920 def log(ui, repo, *pats, **opts):
  1789 def log(ui, repo, *pats, **opts):
  1921     """show revision history of entire repository or files
  1790     """show revision history of entire repository or files
  1922 
  1791 
  1923     Print the revision history of the specified files or the entire project.
  1792     Print the revision history of the specified files or the entire
       
  1793     project.
       
  1794 
       
  1795     File history is shown without following rename or copy history of
       
  1796     files.  Use -f/--follow with a file name to follow history across
       
  1797     renames and copies. --follow without a file name will only show
       
  1798     ancestors or descendants of the starting revision. --follow-first
       
  1799     only follows the first parent of merge revisions.
       
  1800 
       
  1801     If no revision range is specified, the default is tip:0 unless
       
  1802     --follow is set, in which case the working directory parent is
       
  1803     used as the starting revision.
  1924 
  1804 
  1925     By default this command outputs: changeset id and hash, tags,
  1805     By default this command outputs: changeset id and hash, tags,
  1926     non-trivial parents, user, date and time, and a summary for each
  1806     non-trivial parents, user, date and time, and a summary for each
  1927     commit. When the -v/--verbose switch is used, the list of changed
  1807     commit. When the -v/--verbose switch is used, the list of changed
  1928     files and full commit message is shown.
  1808     files and full commit message is shown.
  1998                 br = repo.branchlookup([repo.changelog.node(rev)])
  1878                 br = repo.branchlookup([repo.changelog.node(rev)])
  1999 
  1879 
  2000             displayer.show(rev, brinfo=br)
  1880             displayer.show(rev, brinfo=br)
  2001             if opts['patch']:
  1881             if opts['patch']:
  2002                 prev = (parents and parents[0]) or nullid
  1882                 prev = (parents and parents[0]) or nullid
  2003                 dodiff(du, du, repo, prev, changenode, match=matchfn)
  1883                 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
  2004                 du.write("\n\n")
  1884                 du.write("\n\n")
  2005         elif st == 'iter':
  1885         elif st == 'iter':
  2006             if count == limit: break
  1886             if count == limit: break
  2007             if du.header[rev]:
  1887             if du.header[rev]:
  2008                 for args in du.header[rev]:
  1888                 for args in du.header[rev]:
  2029         except hg.RepoError:
  1909         except hg.RepoError:
  2030             n = repo.manifest.lookup(rev)
  1910             n = repo.manifest.lookup(rev)
  2031     else:
  1911     else:
  2032         n = repo.manifest.tip()
  1912         n = repo.manifest.tip()
  2033     m = repo.manifest.read(n)
  1913     m = repo.manifest.read(n)
  2034     mf = repo.manifest.readflags(n)
       
  2035     files = m.keys()
  1914     files = m.keys()
  2036     files.sort()
  1915     files.sort()
  2037 
  1916 
  2038     for f in files:
  1917     for f in files:
  2039         ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
  1918         ui.write("%40s %3s %s\n" % (hex(m[f]),
  2040 
  1919                                     m.execf(f) and "755" or "644", f))
  2041 def merge(ui, repo, node=None, **opts):
  1920 
       
  1921 def merge(ui, repo, node=None, force=None, branch=None):
  2042     """Merge working directory with another revision
  1922     """Merge working directory with another revision
  2043 
  1923 
  2044     Merge the contents of the current working directory and the
  1924     Merge the contents of the current working directory and the
  2045     requested revision. Files that changed between either parent are
  1925     requested revision. Files that changed between either parent are
  2046     marked as changed for the next commit and a commit must be
  1926     marked as changed for the next commit and a commit must be
  2047     performed before any further updates are allowed.
  1927     performed before any further updates are allowed.
  2048     """
  1928 
  2049     return doupdate(ui, repo, node=node, merge=True, **opts)
  1929     If no revision is specified, the working directory's parent is a
       
  1930     head revision, and the repository contains exactly one other head,
       
  1931     the other head is merged with by default.  Otherwise, an explicit
       
  1932     revision to merge with must be provided.
       
  1933     """
       
  1934 
       
  1935     if node:
       
  1936         node = _lookup(repo, node, branch)
       
  1937     else:
       
  1938         heads = repo.heads()
       
  1939         if len(heads) > 2:
       
  1940             raise util.Abort(_('repo has %d heads - '
       
  1941                                'please merge with an explicit rev') %
       
  1942                              len(heads))
       
  1943         if len(heads) == 1:
       
  1944             raise util.Abort(_('there is nothing to merge - '
       
  1945                                'use "hg update" instead'))
       
  1946         parent = repo.dirstate.parents()[0]
       
  1947         if parent not in heads:
       
  1948             raise util.Abort(_('working dir not at a head rev - '
       
  1949                                'use "hg update" or merge with an explicit rev'))
       
  1950         node = parent == heads[0] and heads[-1] or heads[0]
       
  1951     return hg.merge(repo, node, force=force)
  2050 
  1952 
  2051 def outgoing(ui, repo, dest=None, **opts):
  1953 def outgoing(ui, repo, dest=None, **opts):
  2052     """show changesets not found in destination
  1954     """show changesets not found in destination
  2053 
  1955 
  2054     Show changesets not found in the specified destination repository or
  1956     Show changesets not found in the specified destination repository or
  2056     if a push was requested.
  1958     if a push was requested.
  2057 
  1959 
  2058     See pull for valid destination format details.
  1960     See pull for valid destination format details.
  2059     """
  1961     """
  2060     dest = ui.expandpath(dest or 'default-push', dest or 'default')
  1962     dest = ui.expandpath(dest or 'default-push', dest or 'default')
  2061     ui.setconfig_remoteopts(**opts)
  1963     setremoteconfig(ui, opts)
  2062     revs = None
  1964     revs = None
  2063     if opts['rev']:
  1965     if opts['rev']:
  2064         revs = [repo.lookup(rev) for rev in opts['rev']]
  1966         revs = [repo.lookup(rev) for rev in opts['rev']]
  2065 
  1967 
  2066     other = hg.repository(ui, dest)
  1968     other = hg.repository(ui, dest)
  2077         if opts['no_merges'] and len(parents) == 2:
  1979         if opts['no_merges'] and len(parents) == 2:
  2078             continue
  1980             continue
  2079         displayer.show(changenode=n)
  1981         displayer.show(changenode=n)
  2080         if opts['patch']:
  1982         if opts['patch']:
  2081             prev = (parents and parents[0]) or nullid
  1983             prev = (parents and parents[0]) or nullid
  2082             dodiff(ui, ui, repo, prev, n)
  1984             patch.diff(repo, prev, n)
  2083             ui.write("\n")
  1985             ui.write("\n")
  2084 
  1986 
  2085 def parents(ui, repo, rev=None, branches=None, **opts):
  1987 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
  2086     """show the parents of the working dir or revision
  1988     """show the parents of the working dir or revision
  2087 
  1989 
  2088     Print the working directory's parent revisions.
  1990     Print the working directory's parent revisions.
  2089     """
  1991     """
       
  1992     # legacy
       
  1993     if file_ and not rev:
       
  1994         try:
       
  1995             rev = repo.lookup(file_)
       
  1996             file_ = None
       
  1997         except hg.RepoError:
       
  1998             pass
       
  1999         else:
       
  2000             ui.warn(_("'hg parent REV' is deprecated, "
       
  2001                       "please use 'hg parents -r REV instead\n"))
       
  2002 
  2090     if rev:
  2003     if rev:
  2091         p = repo.changelog.parents(repo.lookup(rev))
  2004         if file_:
       
  2005             ctx = repo.filectx(file_, changeid=rev)
       
  2006         else:
       
  2007             ctx = repo.changectx(rev)
       
  2008         p = [cp.node() for cp in ctx.parents()]
  2092     else:
  2009     else:
  2093         p = repo.dirstate.parents()
  2010         p = repo.dirstate.parents()
  2094 
  2011 
  2095     br = None
  2012     br = None
  2096     if branches is not None:
  2013     if branches is not None:
  2123 def postincoming(ui, repo, modheads, optupdate):
  2040 def postincoming(ui, repo, modheads, optupdate):
  2124     if modheads == 0:
  2041     if modheads == 0:
  2125         return
  2042         return
  2126     if optupdate:
  2043     if optupdate:
  2127         if modheads == 1:
  2044         if modheads == 1:
  2128             return doupdate(ui, repo)
  2045             return hg.update(repo, repo.changelog.tip()) # update
  2129         else:
  2046         else:
  2130             ui.status(_("not updating, since new heads added\n"))
  2047             ui.status(_("not updating, since new heads added\n"))
  2131     if modheads > 1:
  2048     if modheads > 1:
  2132         ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
  2049         ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
  2133     else:
  2050     else:
  2163           Compression on
  2080           Compression on
  2164       Alternatively specify "ssh -C" as your ssh command in your hgrc or
  2081       Alternatively specify "ssh -C" as your ssh command in your hgrc or
  2165       with the --ssh command line option.
  2082       with the --ssh command line option.
  2166     """
  2083     """
  2167     source = ui.expandpath(source)
  2084     source = ui.expandpath(source)
  2168     ui.setconfig_remoteopts(**opts)
  2085     setremoteconfig(ui, opts)
  2169 
  2086 
  2170     other = hg.repository(ui, source)
  2087     other = hg.repository(ui, source)
  2171     ui.status(_('pulling from %s\n') % (source))
  2088     ui.status(_('pulling from %s\n') % (source))
  2172     revs = None
  2089     revs = None
  2173     if opts['rev'] and not other.local():
  2090     if opts['rev'] and not other.local():
  2201 
  2118 
  2202     Pushing to http:// and https:// URLs is possible, too, if this
  2119     Pushing to http:// and https:// URLs is possible, too, if this
  2203     feature is enabled on the remote Mercurial server.
  2120     feature is enabled on the remote Mercurial server.
  2204     """
  2121     """
  2205     dest = ui.expandpath(dest or 'default-push', dest or 'default')
  2122     dest = ui.expandpath(dest or 'default-push', dest or 'default')
  2206     ui.setconfig_remoteopts(**opts)
  2123     setremoteconfig(ui, opts)
  2207 
  2124 
  2208     other = hg.repository(ui, dest)
  2125     other = hg.repository(ui, dest)
  2209     ui.status('pushing to %s\n' % (dest))
  2126     ui.status('pushing to %s\n' % (dest))
  2210     revs = None
  2127     revs = None
  2211     if opts['rev']:
  2128     if opts['rev']:
  2255 
  2172 
  2256     This command tries to fix the repository status after an interrupted
  2173     This command tries to fix the repository status after an interrupted
  2257     operation. It should only be necessary when Mercurial suggests it.
  2174     operation. It should only be necessary when Mercurial suggests it.
  2258     """
  2175     """
  2259     if repo.recover():
  2176     if repo.recover():
  2260         return repo.verify()
  2177         return hg.verify(repo)
  2261     return 1
  2178     return 1
  2262 
  2179 
  2263 def remove(ui, repo, *pats, **opts):
  2180 def remove(ui, repo, *pats, **opts):
  2264     """remove the specified files on the next commit
  2181     """remove the specified files on the next commit
  2265 
  2182 
  2275     remove them, use the -f/--force option.
  2192     remove them, use the -f/--force option.
  2276     """
  2193     """
  2277     names = []
  2194     names = []
  2278     if not opts['after'] and not pats:
  2195     if not opts['after'] and not pats:
  2279         raise util.Abort(_('no files specified'))
  2196         raise util.Abort(_('no files specified'))
  2280     files, matchfn, anypats = matchpats(repo, pats, opts)
  2197     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
  2281     exact = dict.fromkeys(files)
  2198     exact = dict.fromkeys(files)
  2282     mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
  2199     mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
  2283     modified, added, removed, deleted, unknown = mardu
  2200     modified, added, removed, deleted, unknown = mardu
  2284     remove, forget = [], []
  2201     remove, forget = [], []
  2285     for src, abs, rel, exact in walk(repo, pats, opts):
  2202     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
  2286         reason = None
  2203         reason = None
  2287         if abs not in deleted and opts['after']:
  2204         if abs not in deleted and opts['after']:
  2288             reason = _('is still present')
  2205             reason = _('is still present')
  2289         elif abs in modified and not opts['force']:
  2206         elif abs in modified and not opts['force']:
  2290             reason = _('is modified (use -f to force removal)')
  2207             reason = _('is modified (use -f to force removal)')
  2387     names = {}
  2304     names = {}
  2388     target_only = {}
  2305     target_only = {}
  2389 
  2306 
  2390     # walk dirstate.
  2307     # walk dirstate.
  2391 
  2308 
  2392     for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
  2309     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
       
  2310                                              badmatch=mf.has_key):
  2393         names[abs] = (rel, exact)
  2311         names[abs] = (rel, exact)
  2394         if src == 'b':
  2312         if src == 'b':
  2395             target_only[abs] = True
  2313             target_only[abs] = True
  2396 
  2314 
  2397     # walk target manifest.
  2315     # walk target manifest.
  2398 
  2316 
  2399     for src, abs, rel, exact in walk(repo, pats, opts, node=node,
  2317     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
  2400                                      badmatch=names.has_key):
  2318                                              badmatch=names.has_key):
  2401         if abs in names: continue
  2319         if abs in names: continue
  2402         names[abs] = (rel, exact)
  2320         names[abs] = (rel, exact)
  2403         target_only[abs] = True
  2321         target_only[abs] = True
  2404 
  2322 
  2405     changes = repo.changes(match=names.has_key, wlock=wlock)
  2323     changes = repo.status(match=names.has_key, wlock=wlock)[:5]
  2406     modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
  2324     modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
  2407 
  2325 
  2408     revert = ([], _('reverting %s\n'))
  2326     revert = ([], _('reverting %s\n'))
  2409     add = ([], _('adding %s\n'))
  2327     add = ([], _('adding %s\n'))
  2410     remove = ([], _('removing %s\n'))
  2328     remove = ([], _('removing %s\n'))
  2472                 else:
  2390                 else:
  2473                     handle(remove, False)
  2391                     handle(remove, False)
  2474 
  2392 
  2475     if not opts.get('dry_run'):
  2393     if not opts.get('dry_run'):
  2476         repo.dirstate.forget(forget[0])
  2394         repo.dirstate.forget(forget[0])
  2477         r = repo.update(node, False, True, update.has_key, False, wlock=wlock,
  2395         r = hg.revert(repo, node, update.has_key, wlock)
  2478                         show_stats=False)
       
  2479         repo.dirstate.update(add[0], 'a')
  2396         repo.dirstate.update(add[0], 'a')
  2480         repo.dirstate.update(undelete[0], 'n')
  2397         repo.dirstate.update(undelete[0], 'n')
  2481         repo.dirstate.update(remove[0], 'r')
  2398         repo.dirstate.update(remove[0], 'r')
  2482         return r
  2399         return r
  2483 
  2400 
  2591     httpd.serve_forever()
  2508     httpd.serve_forever()
  2592 
  2509 
  2593 def status(ui, repo, *pats, **opts):
  2510 def status(ui, repo, *pats, **opts):
  2594     """show changed files in the working directory
  2511     """show changed files in the working directory
  2595 
  2512 
  2596     Show changed files in the repository.  If names are
  2513     Show status of files in the repository.  If names are given, only
  2597     given, only files that match are shown.
  2514     files that match are shown.  Files that are clean or ignored, are
       
  2515     not listed unless -c (clean), -i (ignored) or -A is given.
  2598 
  2516 
  2599     The codes used to show the status of files are:
  2517     The codes used to show the status of files are:
  2600     M = modified
  2518     M = modified
  2601     A = added
  2519     A = added
  2602     R = removed
  2520     R = removed
       
  2521     C = clean
  2603     ! = deleted, but still tracked
  2522     ! = deleted, but still tracked
  2604     ? = not tracked
  2523     ? = not tracked
  2605     I = ignored (not shown by default)
  2524     I = ignored (not shown by default)
  2606       = the previous added file was copied from here
  2525       = the previous added file was copied from here
  2607     """
  2526     """
  2608 
  2527 
  2609     show_ignored = opts['ignored'] and True or False
  2528     all = opts['all']
  2610     files, matchfn, anypats = matchpats(repo, pats, opts)
  2529     
       
  2530     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
  2611     cwd = (pats and repo.getcwd()) or ''
  2531     cwd = (pats and repo.getcwd()) or ''
  2612     modified, added, removed, deleted, unknown, ignored = [
  2532     modified, added, removed, deleted, unknown, ignored, clean = [
  2613         [util.pathto(cwd, x) for x in n]
  2533         [util.pathto(cwd, x) for x in n]
  2614         for n in repo.changes(files=files, match=matchfn,
  2534         for n in repo.status(files=files, match=matchfn,
  2615                               show_ignored=show_ignored)]
  2535                              list_ignored=all or opts['ignored'],
  2616 
  2536                              list_clean=all or opts['clean'])]
  2617     changetypes = [('modified', 'M', modified),
  2537 
       
  2538     changetypes = (('modified', 'M', modified),
  2618                    ('added', 'A', added),
  2539                    ('added', 'A', added),
  2619                    ('removed', 'R', removed),
  2540                    ('removed', 'R', removed),
  2620                    ('deleted', '!', deleted),
  2541                    ('deleted', '!', deleted),
  2621                    ('unknown', '?', unknown),
  2542                    ('unknown', '?', unknown),
  2622                    ('ignored', 'I', ignored)]
  2543                    ('ignored', 'I', ignored))
       
  2544 
       
  2545     explicit_changetypes = changetypes + (('clean', 'C', clean),)
  2623 
  2546 
  2624     end = opts['print0'] and '\0' or '\n'
  2547     end = opts['print0'] and '\0' or '\n'
  2625 
  2548 
  2626     for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
  2549     for opt, char, changes in ([ct for ct in explicit_changetypes
       
  2550                                 if all or opts[ct[0]]]
  2627                                or changetypes):
  2551                                or changetypes):
  2628         if opts['no_status']:
  2552         if opts['no_status']:
  2629             format = "%%s%s" % end
  2553             format = "%%s%s" % end
  2630         else:
  2554         else:
  2631             format = "%s %%s%s" % (char, end)
  2555             format = "%s %%s%s" % (char, end)
  2632 
  2556 
  2633         for f in changes:
  2557         for f in changes:
  2634             ui.write(format % f)
  2558             ui.write(format % f)
  2635             if (opts.get('copies') and not opts.get('no_status')
  2559             if ((all or opts.get('copies')) and not opts.get('no_status')
  2636                 and opt == 'added' and repo.dirstate.copies.has_key(f)):
  2560                 and opt == 'added' and repo.dirstate.copies.has_key(f)):
  2637                 ui.write('  %s%s' % (repo.dirstate.copies[f], end))
  2561                 ui.write('  %s%s' % (repo.dirstate.copies[f], end))
  2638 
  2562 
  2639 def tag(ui, repo, name, rev_=None, **opts):
  2563 def tag(ui, repo, name, rev_=None, **opts):
  2640     """add a tag for the current tip or a given revision
  2564     """add a tag for the current tip or a given revision
  2643 
  2567 
  2644     Tags are used to name particular revisions of the repository and are
  2568     Tags are used to name particular revisions of the repository and are
  2645     very useful to compare different revision, to go back to significant
  2569     very useful to compare different revision, to go back to significant
  2646     earlier versions or to mark branch points as releases, etc.
  2570     earlier versions or to mark branch points as releases, etc.
  2647 
  2571 
  2648     If no revision is given, the tip is used.
  2572     If no revision is given, the parent of the working directory is used.
  2649 
  2573 
  2650     To facilitate version control, distribution, and merging of tags,
  2574     To facilitate version control, distribution, and merging of tags,
  2651     they are stored as a file named ".hgtags" which is managed
  2575     they are stored as a file named ".hgtags" which is managed
  2652     similarly to other project files and can be hand-edited if
  2576     similarly to other project files and can be hand-edited if
  2653     necessary.  The file '.hg/localtags' is used for local tags (not
  2577     necessary.  The file '.hg/localtags' is used for local tags (not
  2654     shared among repositories).
  2578     shared among repositories).
  2655     """
  2579     """
  2656     if name == "tip":
  2580     if name in ['tip', '.']:
  2657         raise util.Abort(_("the name 'tip' is reserved"))
  2581         raise util.Abort(_("the name '%s' is reserved") % name)
  2658     if rev_ is not None:
  2582     if rev_ is not None:
  2659         ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
  2583         ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
  2660                   "please use 'hg tag [-r REV] NAME' instead\n"))
  2584                   "please use 'hg tag [-r REV] NAME' instead\n"))
  2661         if opts['rev']:
  2585         if opts['rev']:
  2662             raise util.Abort(_("use only one form to specify the revision"))
  2586             raise util.Abort(_("use only one form to specify the revision"))
  2663     if opts['rev']:
  2587     if opts['rev']:
  2664         rev_ = opts['rev']
  2588         rev_ = opts['rev']
  2665     if rev_:
  2589     if rev_:
  2666         r = hex(repo.lookup(rev_))
  2590         r = hex(repo.lookup(rev_))
  2667     else:
  2591     else:
  2668         r = hex(repo.changelog.tip())
  2592         p1, p2 = repo.dirstate.parents()
       
  2593         if p1 == nullid:
       
  2594             raise util.Abort(_('no revision to tag'))
       
  2595         if p2 != nullid:
       
  2596             raise util.Abort(_('outstanding uncommitted merges'))
       
  2597         r = hex(p1)
  2669 
  2598 
  2670     repo.tag(name, r, opts['local'], opts['message'], opts['user'],
  2599     repo.tag(name, r, opts['local'], opts['message'], opts['user'],
  2671              opts['date'])
  2600              opts['date'])
  2672 
  2601 
  2673 def tags(ui, repo):
  2602 def tags(ui, repo):
  2699     br = None
  2628     br = None
  2700     if opts['branches']:
  2629     if opts['branches']:
  2701         br = repo.branchlookup([n])
  2630         br = repo.branchlookup([n])
  2702     show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
  2631     show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
  2703     if opts['patch']:
  2632     if opts['patch']:
  2704         dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
  2633         patch.diff(repo, repo.changelog.parents(n)[0], n)
  2705 
  2634 
  2706 def unbundle(ui, repo, fname, **opts):
  2635 def unbundle(ui, repo, fname, **opts):
  2707     """apply a changegroup file
  2636     """apply a changegroup file
  2708 
  2637 
  2709     Apply a compressed changegroup file generated by the bundle
  2638     Apply a compressed changegroup file generated by the bundle
  2728                 yield chunk
  2657                 yield chunk
  2729     else:
  2658     else:
  2730         raise util.Abort(_("%s: unknown bundle compression type")
  2659         raise util.Abort(_("%s: unknown bundle compression type")
  2731                          % fname)
  2660                          % fname)
  2732     gen = generator(util.filechunkiter(f, 4096))
  2661     gen = generator(util.filechunkiter(f, 4096))
  2733     modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
  2662     modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
       
  2663                                    'bundle:' + fname)
  2734     return postincoming(ui, repo, modheads, opts['update'])
  2664     return postincoming(ui, repo, modheads, opts['update'])
  2735 
  2665 
  2736 def undo(ui, repo):
  2666 def undo(ui, repo):
  2737     """undo the last commit or pull (DEPRECATED)
  2667     """undo the last commit or pull (DEPRECATED)
  2738 
  2668 
  2743     """
  2673     """
  2744     ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
  2674     ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
  2745     repo.rollback()
  2675     repo.rollback()
  2746 
  2676 
  2747 def update(ui, repo, node=None, merge=False, clean=False, force=None,
  2677 def update(ui, repo, node=None, merge=False, clean=False, force=None,
  2748            branch=None, **opts):
  2678            branch=None):
  2749     """update or merge working directory
  2679     """update or merge working directory
  2750 
  2680 
  2751     Update the working directory to the specified revision.
  2681     Update the working directory to the specified revision.
  2752 
  2682 
  2753     If there are no outstanding changes in the working directory and
  2683     If there are no outstanding changes in the working directory and
  2758     merge command.
  2688     merge command.
  2759 
  2689 
  2760     By default, update will refuse to run if doing so would require
  2690     By default, update will refuse to run if doing so would require
  2761     merging or discarding local changes.
  2691     merging or discarding local changes.
  2762     """
  2692     """
       
  2693     node = _lookup(repo, node, branch)
  2763     if merge:
  2694     if merge:
  2764         ui.warn(_('(the -m/--merge option is deprecated; '
  2695         ui.warn(_('(the -m/--merge option is deprecated; '
  2765                   'use the merge command instead)\n'))
  2696                   'use the merge command instead)\n'))
  2766     return doupdate(ui, repo, node, merge, clean, force, branch, **opts)
  2697         return hg.merge(repo, node, force=force)
  2767 
  2698     elif clean:
  2768 def doupdate(ui, repo, node=None, merge=False, clean=False, force=None,
  2699         return hg.clean(repo, node)
  2769              branch=None, **opts):
  2700     else:
       
  2701         return hg.update(repo, node)
       
  2702 
       
  2703 def _lookup(repo, node, branch=None):
  2770     if branch:
  2704     if branch:
  2771         br = repo.branchlookup(branch=branch)
  2705         br = repo.branchlookup(branch=branch)
  2772         found = []
  2706         found = []
  2773         for x in br:
  2707         for x in br:
  2774             if branch in br[x]:
  2708             if branch in br[x]:
  2775                 found.append(x)
  2709                 found.append(x)
  2776         if len(found) > 1:
  2710         if len(found) > 1:
  2777             ui.warn(_("Found multiple heads for %s\n") % branch)
  2711             repo.ui.warn(_("Found multiple heads for %s\n") % branch)
  2778             for x in found:
  2712             for x in found:
  2779                 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br)
  2713                 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
  2780             return 1
  2714             raise util.Abort("")
  2781         if len(found) == 1:
  2715         if len(found) == 1:
  2782             node = found[0]
  2716             node = found[0]
  2783             ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
  2717             repo.ui.warn(_("Using head %s for branch %s\n")
  2784         else:
  2718                          % (short(node), branch))
  2785             ui.warn(_("branch %s not found\n") % (branch))
  2719         else:
  2786             return 1
  2720             raise util.Abort(_("branch %s not found\n") % (branch))
  2787     else:
  2721     else:
  2788         node = node and repo.lookup(node) or repo.changelog.tip()
  2722         node = node and repo.lookup(node) or repo.changelog.tip()
  2789     return repo.update(node, allow=merge, force=clean, forcemerge=force)
  2723     return node
  2790 
  2724 
  2791 def verify(ui, repo):
  2725 def verify(ui, repo):
  2792     """verify the integrity of the repository
  2726     """verify the integrity of the repository
  2793 
  2727 
  2794     Verify the integrity of the current repository.
  2728     Verify the integrity of the current repository.
  2796     This will perform an extensive check of the repository's
  2730     This will perform an extensive check of the repository's
  2797     integrity, validating the hashes and checksums of each entry in
  2731     integrity, validating the hashes and checksums of each entry in
  2798     the changelog, manifest, and tracked files, as well as the
  2732     the changelog, manifest, and tracked files, as well as the
  2799     integrity of their crosslinks and indices.
  2733     integrity of their crosslinks and indices.
  2800     """
  2734     """
  2801     return repo.verify()
  2735     return hg.verify(repo)
  2802 
  2736 
  2803 # Command options and aliases are listed here, alphabetically
  2737 # Command options and aliases are listed here, alphabetically
  2804 
  2738 
  2805 table = {
  2739 table = {
  2806     "^add":
  2740     "^add":
  2917         (diff,
  2851         (diff,
  2918          [('r', 'rev', [], _('revision')),
  2852          [('r', 'rev', [], _('revision')),
  2919           ('a', 'text', None, _('treat all files as text')),
  2853           ('a', 'text', None, _('treat all files as text')),
  2920           ('p', 'show-function', None,
  2854           ('p', 'show-function', None,
  2921            _('show which function each change is in')),
  2855            _('show which function each change is in')),
       
  2856           ('g', 'git', None, _('use git extended diff format')),
  2922           ('w', 'ignore-all-space', None,
  2857           ('w', 'ignore-all-space', None,
  2923            _('ignore white space when comparing lines')),
  2858            _('ignore white space when comparing lines')),
  2924           ('b', 'ignore-space-change', None,
  2859           ('b', 'ignore-space-change', None,
  2925            _('ignore changes in the amount of white space')),
  2860            _('ignore changes in the amount of white space')),
  2926           ('B', 'ignore-blank-lines', None,
  2861           ('B', 'ignore-blank-lines', None,
  2941          _('hg forget [OPTION]... FILE...')),
  2876          _('hg forget [OPTION]... FILE...')),
  2942     "grep":
  2877     "grep":
  2943         (grep,
  2878         (grep,
  2944          [('0', 'print0', None, _('end fields with NUL')),
  2879          [('0', 'print0', None, _('end fields with NUL')),
  2945           ('', 'all', None, _('print all revisions that match')),
  2880           ('', 'all', None, _('print all revisions that match')),
       
  2881           ('f', 'follow', None,
       
  2882            _('follow changeset history, or file history across copies and renames')),
  2946           ('i', 'ignore-case', None, _('ignore case when matching')),
  2883           ('i', 'ignore-case', None, _('ignore case when matching')),
  2947           ('l', 'files-with-matches', None,
  2884           ('l', 'files-with-matches', None,
  2948            _('print only filenames and revs that match')),
  2885            _('print only filenames and revs that match')),
  2949           ('n', 'line-number', None, _('print matching line numbers')),
  2886           ('n', 'line-number', None, _('print matching line numbers')),
  2950           ('r', 'rev', [], _('search in given revision range')),
  2887           ('r', 'rev', [], _('search in given revision range')),
  2977            _('run even when remote repository is unrelated')),
  2914            _('run even when remote repository is unrelated')),
  2978           ('', 'style', '', _('display using template map file')),
  2915           ('', 'style', '', _('display using template map file')),
  2979           ('n', 'newest-first', None, _('show newest record first')),
  2916           ('n', 'newest-first', None, _('show newest record first')),
  2980           ('', 'bundle', '', _('file to store the bundles into')),
  2917           ('', 'bundle', '', _('file to store the bundles into')),
  2981           ('p', 'patch', None, _('show patch')),
  2918           ('p', 'patch', None, _('show patch')),
  2982           ('r', 'rev', [], _('a specific revision you would like to pull')),
  2919           ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
  2983           ('', 'template', '', _('display with template')),
  2920           ('', 'template', '', _('display with template')),
  2984           ('e', 'ssh', '', _('specify ssh command to use')),
  2921           ('e', 'ssh', '', _('specify ssh command to use')),
  2985           ('', 'remotecmd', '',
  2922           ('', 'remotecmd', '',
  2986            _('specify hg command to run on the remote side'))],
  2923            _('specify hg command to run on the remote side'))],
  2987          _('hg incoming [-p] [-n] [-M] [-r REV]...'
  2924          _('hg incoming [-p] [-n] [-M] [-r REV]...'
  3003           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
  2940           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
  3004          _('hg locate [OPTION]... [PATTERN]...')),
  2941          _('hg locate [OPTION]... [PATTERN]...')),
  3005     "^log|history":
  2942     "^log|history":
  3006         (log,
  2943         (log,
  3007          [('b', 'branches', None, _('show branches')),
  2944          [('b', 'branches', None, _('show branches')),
       
  2945           ('f', 'follow', None,
       
  2946            _('follow changeset history, or file history across copies and renames')),
       
  2947           ('', 'follow-first', None,
       
  2948            _('only follow the first parent of merge changesets')),
  3008           ('k', 'keyword', [], _('search for a keyword')),
  2949           ('k', 'keyword', [], _('search for a keyword')),
  3009           ('l', 'limit', '', _('limit number of changes displayed')),
  2950           ('l', 'limit', '', _('limit number of changes displayed')),
  3010           ('r', 'rev', [], _('show the specified revision or range')),
  2951           ('r', 'rev', [], _('show the specified revision or range')),
  3011           ('M', 'no-merges', None, _('do not show merges')),
  2952           ('M', 'no-merges', None, _('do not show merges')),
  3012           ('', 'style', '', _('display using template map file')),
  2953           ('', 'style', '', _('display using template map file')),
  3013           ('m', 'only-merges', None, _('show only merges')),
  2954           ('m', 'only-merges', None, _('show only merges')),
  3014           ('p', 'patch', None, _('show patch')),
  2955           ('p', 'patch', None, _('show patch')),
       
  2956           ('P', 'prune', [], _('do not display revision or any of its ancestors')),
  3015           ('', 'template', '', _('display with template')),
  2957           ('', 'template', '', _('display with template')),
  3016           ('I', 'include', [], _('include names matching the given patterns')),
  2958           ('I', 'include', [], _('include names matching the given patterns')),
  3017           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
  2959           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
  3018          _('hg log [OPTION]... [FILE]')),
  2960          _('hg log [OPTION]... [FILE]')),
  3019     "manifest": (manifest, [], _('hg manifest [REV]')),
  2961     "manifest": (manifest, [], _('hg manifest [REV]')),
  3036            _('specify hg command to run on the remote side'))],
  2978            _('specify hg command to run on the remote side'))],
  3037          _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
  2979          _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
  3038     "^parents":
  2980     "^parents":
  3039         (parents,
  2981         (parents,
  3040          [('b', 'branches', None, _('show branches')),
  2982          [('b', 'branches', None, _('show branches')),
       
  2983           ('r', 'rev', '', _('show parents from the specified rev')),
  3041           ('', 'style', '', _('display using template map file')),
  2984           ('', 'style', '', _('display using template map file')),
  3042           ('', 'template', '', _('display with template'))],
  2985           ('', 'template', '', _('display with template'))],
  3043          _('hg parents [-b] [REV]')),
  2986          _('hg parents [-b] [-r REV] [FILE]')),
  3044     "paths": (paths, [], _('hg paths [NAME]')),
  2987     "paths": (paths, [], _('hg paths [NAME]')),
  3045     "^pull":
  2988     "^pull":
  3046         (pull,
  2989         (pull,
  3047          [('u', 'update', None,
  2990          [('u', 'update', None,
  3048            _('update the working directory to tip after pull')),
  2991            _('update the working directory to tip after pull')),
  3049           ('e', 'ssh', '', _('specify ssh command to use')),
  2992           ('e', 'ssh', '', _('specify ssh command to use')),
  3050           ('f', 'force', None,
  2993           ('f', 'force', None,
  3051            _('run even when remote repository is unrelated')),
  2994            _('run even when remote repository is unrelated')),
  3052           ('r', 'rev', [], _('a specific revision you would like to pull')),
  2995           ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
  3053           ('', 'remotecmd', '',
  2996           ('', 'remotecmd', '',
  3054            _('specify hg command to run on the remote side'))],
  2997            _('specify hg command to run on the remote side'))],
  3055          _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
  2998          _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
  3056     "^push":
  2999     "^push":
  3057         (push,
  3000         (push,
  3115           ('', 'style', '', _('template style to use')),
  3058           ('', 'style', '', _('template style to use')),
  3116           ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
  3059           ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
  3117          _('hg serve [OPTION]...')),
  3060          _('hg serve [OPTION]...')),
  3118     "^status|st":
  3061     "^status|st":
  3119         (status,
  3062         (status,
  3120          [('m', 'modified', None, _('show only modified files')),
  3063          [('A', 'all', None, _('show status of all files')),
       
  3064           ('m', 'modified', None, _('show only modified files')),
  3121           ('a', 'added', None, _('show only added files')),
  3065           ('a', 'added', None, _('show only added files')),
  3122           ('r', 'removed', None, _('show only removed files')),
  3066           ('r', 'removed', None, _('show only removed files')),
  3123           ('d', 'deleted', None, _('show only deleted (but tracked) files')),
  3067           ('d', 'deleted', None, _('show only deleted (but tracked) files')),
       
  3068           ('c', 'clean', None, _('show only files without changes')),
  3124           ('u', 'unknown', None, _('show only unknown (not tracked) files')),
  3069           ('u', 'unknown', None, _('show only unknown (not tracked) files')),
  3125           ('i', 'ignored', None, _('show ignored files')),
  3070           ('i', 'ignored', None, _('show ignored files')),
  3126           ('n', 'no-status', None, _('hide status prefix')),
  3071           ('n', 'no-status', None, _('hide status prefix')),
  3127           ('C', 'copies', None, _('show source of copied files')),
  3072           ('C', 'copies', None, _('show source of copied files')),
  3128           ('0', 'print0', None,
  3073           ('0', 'print0', None,
  3284 def findext(name):
  3229 def findext(name):
  3285     '''return module with given extension name'''
  3230     '''return module with given extension name'''
  3286     try:
  3231     try:
  3287         return sys.modules[external[name]]
  3232         return sys.modules[external[name]]
  3288     except KeyError:
  3233     except KeyError:
  3289         dotname = '.' + name
       
  3290         for k, v in external.iteritems():
  3234         for k, v in external.iteritems():
  3291             if k.endswith('.' + name) or v == name:
  3235             if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
  3292                 return sys.modules[v]
  3236                 return sys.modules[v]
  3293         raise KeyError(name)
  3237         raise KeyError(name)
  3294 
  3238 
  3295 def dispatch(args):
  3239 def load_extensions(ui):
  3296     for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
  3240     added = []
  3297         num = getattr(signal, name, None)
  3241     for ext_name, load_from_name in ui.extensions():
  3298         if num: signal.signal(num, catchterm)
  3242         if ext_name in external:
  3299 
  3243             continue
  3300     try:
       
  3301         u = ui.ui(traceback='--traceback' in sys.argv[1:])
       
  3302     except util.Abort, inst:
       
  3303         sys.stderr.write(_("abort: %s\n") % inst)
       
  3304         return -1
       
  3305 
       
  3306     for ext_name, load_from_name in u.extensions():
       
  3307         try:
  3244         try:
  3308             if load_from_name:
  3245             if load_from_name:
  3309                 # the module will be loaded in sys.modules
  3246                 # the module will be loaded in sys.modules
  3310                 # choose an unique name so that it doesn't
  3247                 # choose an unique name so that it doesn't
  3311                 # conflicts with other modules
  3248                 # conflicts with other modules
  3321                 try:
  3258                 try:
  3322                     mod = importh("hgext.%s" % ext_name)
  3259                     mod = importh("hgext.%s" % ext_name)
  3323                 except ImportError:
  3260                 except ImportError:
  3324                     mod = importh(ext_name)
  3261                     mod = importh(ext_name)
  3325             external[ext_name] = mod.__name__
  3262             external[ext_name] = mod.__name__
       
  3263             added.append((mod, ext_name))
  3326         except (util.SignalInterrupt, KeyboardInterrupt):
  3264         except (util.SignalInterrupt, KeyboardInterrupt):
  3327             raise
  3265             raise
  3328         except Exception, inst:
  3266         except Exception, inst:
  3329             u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
  3267             ui.warn(_("*** failed to import extension %s: %s\n") %
  3330             if u.print_exc():
  3268                     (ext_name, inst))
       
  3269             if ui.print_exc():
  3331                 return 1
  3270                 return 1
  3332 
  3271 
  3333     for name in external.itervalues():
  3272     for mod, name in added:
  3334         mod = sys.modules[name]
       
  3335         uisetup = getattr(mod, 'uisetup', None)
  3273         uisetup = getattr(mod, 'uisetup', None)
  3336         if uisetup:
  3274         if uisetup:
  3337             uisetup(u)
  3275             uisetup(ui)
  3338         cmdtable = getattr(mod, 'cmdtable', {})
  3276         cmdtable = getattr(mod, 'cmdtable', {})
  3339         for t in cmdtable:
  3277         for t in cmdtable:
  3340             if t in table:
  3278             if t in table:
  3341                 u.warn(_("module %s overrides %s\n") % (name, t))
  3279                 ui.warn(_("module %s overrides %s\n") % (name, t))
  3342         table.update(cmdtable)
  3280         table.update(cmdtable)
       
  3281     
       
  3282 def dispatch(args):
       
  3283     for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
       
  3284         num = getattr(signal, name, None)
       
  3285         if num: signal.signal(num, catchterm)
       
  3286 
       
  3287     try:
       
  3288         u = ui.ui(traceback='--traceback' in sys.argv[1:],
       
  3289                   readhooks=[load_extensions])
       
  3290     except util.Abort, inst:
       
  3291         sys.stderr.write(_("abort: %s\n") % inst)
       
  3292         return -1
  3343 
  3293 
  3344     try:
  3294     try:
  3345         cmd, func, args, options, cmdoptions = parse(u, args)
  3295         cmd, func, args, options, cmdoptions = parse(u, args)
  3346         if options["time"]:
  3296         if options["time"]:
  3347             def get_times():
  3297             def get_times():
  3389                     u = repo.ui
  3339                     u = repo.ui
  3390                     for name in external.itervalues():
  3340                     for name in external.itervalues():
  3391                         mod = sys.modules[name]
  3341                         mod = sys.modules[name]
  3392                         if hasattr(mod, 'reposetup'):
  3342                         if hasattr(mod, 'reposetup'):
  3393                             mod.reposetup(u, repo)
  3343                             mod.reposetup(u, repo)
       
  3344                             hg.repo_setup_hooks.append(mod.reposetup)
  3394                 except hg.RepoError:
  3345                 except hg.RepoError:
  3395                     if cmd not in optionalrepo.split():
  3346                     if cmd not in optionalrepo.split():
  3396                         raise
  3347                         raise
  3397                 d = lambda: func(u, repo, *args, **cmdoptions)
  3348                 d = lambda: func(u, repo, *args, **cmdoptions)
  3398             else:
  3349             else:
  3399                 d = lambda: func(u, *args, **cmdoptions)
  3350                 d = lambda: func(u, *args, **cmdoptions)
       
  3351 
       
  3352             # reupdate the options, repo/.hg/hgrc may have changed them
       
  3353             u.updateopts(options["verbose"], options["debug"], options["quiet"],
       
  3354                          not options["noninteractive"], options["traceback"],
       
  3355                          options["config"])
  3400 
  3356 
  3401             try:
  3357             try:
  3402                 if options['profile']:
  3358                 if options['profile']:
  3403                     import hotshot, hotshot.stats
  3359                     import hotshot, hotshot.stats
  3404                     prof = hotshot.Profile("hg.prof")
  3360                     prof = hotshot.Profile("hg.prof")