changeset 3568:23f7d9621783

Merge with upstream
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 27 Oct 2006 23:09:46 +0200
parents 3bab1fc0ab75 (current diff) ece5c53577eb (diff)
children a27d90c9336e
files hgext/mq.py mercurial/commands.py mercurial/localrepo.py mercurial/util.py
diffstat 7 files changed, 107 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -502,7 +502,7 @@ class queue:
         if opts.get('rev'):
             if not self.applied:
                 raise util.Abort(_('no patches applied'))
-            revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])]
+            revs = cmdutil.revrange(ui, repo, opts['rev'])
             if len(revs) > 1 and revs[0] > revs[1]:
                 revs.reverse()
             for rev in revs:
@@ -1015,9 +1015,9 @@ class queue:
                     del mm[mm.index(x)]
                 dd.append(x)
 
-            m = list(util.unique(mm))
-            r = list(util.unique(dd))
-            a = list(util.unique(aa))
+            m = util.unique(mm)
+            r = util.unique(dd)
+            a = util.unique(aa)
             filelist = filter(matchfn, util.unique(m + r + a))
             if opts.get('git'):
                 self.diffopts().git = True
@@ -1276,7 +1276,7 @@ class queue:
             if files:
                 raise util.Abort(_('option "-r" not valid when importing '
                                    'files'))
-            rev = [int(r) for r in cmdutil.revrange(self.ui, repo, rev)]
+            rev = cmdutil.revrange(self.ui, repo, rev)
             rev.sort(lambda x, y: cmp(y, x))
         if (len(files) > 1 or len(rev) > 1) and patchname:
             raise util.Abort(_('option "-n" not valid when importing multiple '
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -13,43 +13,25 @@ demandload(globals(), 'os sys')
 
 revrangesep = ':'
 
-def revfix(repo, val, defval):
-    '''turn user-level id of changeset into rev number.
-    user-level id can be tag, changeset, rev number, or negative rev
-    number relative to number of revs (-1 is tip, etc).'''
-    if not val:
-        return defval
-    try:
-        num = int(val)
-        if str(num) != val:
-            raise ValueError
-        if num < 0:
-            num += repo.changelog.count()
-        if num < 0:
-            num = 0
-        elif num >= repo.changelog.count():
-            raise ValueError
-    except ValueError:
-        try:
-            num = repo.changelog.rev(repo.lookup(val))
-        except KeyError:
-            raise util.Abort(_('invalid revision identifier %s') % val)
-    return num
-
 def revpair(ui, repo, revs):
     '''return pair of nodes, given list of revisions. second item can
     be None, meaning use working dir.'''
+
+    def revfix(repo, val, defval):
+        if not val and val != 0:
+            val = defval
+        return repo.lookup(val)
+
     if not revs:
         return repo.dirstate.parents()[0], None
     end = None
     if len(revs) == 1:
-        start = revs[0]
-        if revrangesep in start:
-            start, end = start.split(revrangesep, 1)
+        if revrangesep in revs[0]:
+            start, end = revs[0].split(revrangesep, 1)
             start = revfix(repo, start, 0)
             end = revfix(repo, end, repo.changelog.count() - 1)
         else:
-            start = revfix(repo, start, None)
+            start = revfix(repo, revs[0], None)
     elif len(revs) == 2:
         if revrangesep in revs[0] or revrangesep in revs[1]:
             raise util.Abort(_('too many revisions specified'))
@@ -57,12 +39,17 @@ def revpair(ui, repo, revs):
         end = revfix(repo, revs[1], None)
     else:
         raise util.Abort(_('too many revisions specified'))
-    if end is not None: end = repo.lookup(str(end))
-    return repo.lookup(str(start)), end
+    return start, end
 
 def revrange(ui, repo, revs):
     """Yield revision as strings from a list of revision specifications."""
-    seen = {}
+
+    def revfix(repo, val, defval):
+        if not val and val != 0:
+            return defval
+        return repo.changelog.rev(repo.lookup(val))
+
+    seen, l = {}, []
     for spec in revs:
         if revrangesep in spec:
             start, end = spec.split(revrangesep, 1)
@@ -73,13 +60,15 @@ def revrange(ui, repo, revs):
                 if rev in seen:
                     continue
                 seen[rev] = 1
-                yield str(rev)
+                l.append(rev)
         else:
             rev = revfix(repo, spec, None)
             if rev in seen:
                 continue
             seen[rev] = 1
-            yield str(rev)
+            l.append(rev)
+
+    return l
 
 def make_filename(repo, pat, node,
                   total=None, seqno=None, revwidth=None, pathname=None):
@@ -149,19 +138,12 @@ def matchpats(repo, pats=[], opts={}, he
     return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
                            opts.get('exclude'), head)
 
-def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
+def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
     files, matchfn, anypats = matchpats(repo, pats, opts, head)
-    exact = dict(zip(files, files))
-    def walk():
-        for src, fn in repo.walk(node=node, files=files, match=matchfn,
-                                 badmatch=badmatch):
-            yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
-    return files, matchfn, walk()
-
-def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
-    files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
-    for r in results:
-        yield r
+    exact = dict.fromkeys(files)
+    for src, fn in repo.walk(node=node, files=files, match=matchfn,
+                             badmatch=badmatch):
+        yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
 
 def findrenames(repo, added=None, removed=None, threshold=0.5):
     if added is None or removed is None:
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -50,7 +50,7 @@ def logmessage(opts):
                              (logfile, inst.strerror))
     return message
 
-def walkchangerevs(ui, repo, pats, opts):
+def walkchangerevs(ui, repo, pats, change, opts):
     '''Iterate over files and the revs they changed in.
 
     Callers most commonly need to iterate backwards over the history
@@ -61,10 +61,8 @@ def walkchangerevs(ui, repo, pats, opts)
     window, we first walk forwards to gather data, then in the desired
     order (usually backwards) to display it.
 
-    This function returns an (iterator, getchange, matchfn) tuple.  The
-    getchange function returns the changelog entry for a numeric
-    revision.  The iterator yields 3-tuples.  They will be of one of
-    the following forms:
+    This function returns an (iterator, matchfn) tuple. The iterator
+    yields 3-tuples. They will be of one of the following forms:
 
     "window", incrementing, lastrev: stepping through a window,
     positive if walking forwards through revs, last rev in the
@@ -91,32 +89,24 @@ def walkchangerevs(ui, repo, pats, opts)
                 if windowsize < sizelimit:
                     windowsize *= 2
 
-
     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
     follow = opts.get('follow') or opts.get('follow_first')
 
     if repo.changelog.count() == 0:
-        return [], False, matchfn
+        return [], matchfn
 
     if follow:
         defrange = '%s:0' % repo.changectx().rev()
     else:
         defrange = 'tip:0'
-    revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange]))
+    revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
     wanted = {}
     slowpath = anypats
     fncache = {}
 
-    chcache = {}
-    def getchange(rev):
-        ch = chcache.get(rev)
-        if ch is None:
-            chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
-        return ch
-
     if not slowpath and not files:
         # No files, no patterns.  Display all revs.
-        wanted = dict(zip(revs, revs))
+        wanted = dict.fromkeys(revs)
     copies = []
     if not slowpath:
         # Only files, no patterns.  Check the history of each file.
@@ -169,7 +159,7 @@ def walkchangerevs(ui, repo, pats, opts)
         def changerevgen():
             for i, window in increasing_windows(repo.changelog.count()-1, -1):
                 for j in xrange(i - window, i + 1):
-                    yield j, getchange(j)[3]
+                    yield j, change(j)[3]
 
         for rev, changefiles in changerevgen():
             matches = filter(matchfn, changefiles)
@@ -220,7 +210,7 @@ def walkchangerevs(ui, repo, pats, opts)
         ff = followfilter()
         stop = min(revs[0], revs[-1])
         for x in xrange(rev, stop-1, -1):
-            if ff.match(x) and wanted.has_key(x):
+            if ff.match(x) and x in wanted:
                 del wanted[x]
 
     def iterate():
@@ -240,11 +230,11 @@ def walkchangerevs(ui, repo, pats, opts)
             srevs = list(nrevs)
             srevs.sort()
             for rev in srevs:
-                fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
+                fns = fncache.get(rev) or filter(matchfn, change(rev)[3])
                 yield 'add', rev, fns
             for rev in nrevs:
                 yield 'iter', rev, None
-    return iterate(), getchange, matchfn
+    return iterate(), matchfn
 
 def write_bundle(cg, filename=None, compress=True):
     """Write a bundle file and return its filename.
@@ -298,13 +288,6 @@ def write_bundle(cg, filename=None, comp
         if cleanup is not None:
             os.unlink(cleanup)
 
-def trimuser(ui, name, rev, revcache):
-    """trim the name of the user who committed a change"""
-    user = revcache.get(rev)
-    if user is None:
-        user = revcache[rev] = ui.shortuser(name)
-    return user
-
 class changeset_printer(object):
     '''show changeset information when templating not requested.'''
 
@@ -1383,7 +1366,7 @@ def export(ui, repo, *changesets, **opts
     """
     if not changesets:
         raise util.Abort(_("export requires at least one changeset"))
-    revs = list(cmdutil.revrange(ui, repo, changesets))
+    revs = cmdutil.revrange(ui, repo, changesets)
     if len(revs) > 1:
         ui.note(_('exporting patches:\n'))
     else:
@@ -1471,29 +1454,23 @@ def grep(ui, repo, pattern, *pats, **opt
                     yield ('+', b[i])
 
     prev = {}
-    ucache = {}
     def display(fn, rev, states, prevstates):
         counts = {'-': 0, '+': 0}
         filerevmatches = {}
         if incrementing or not opts['all']:
-            a, b = prevstates, states
+            a, b, r = prevstates, states, rev
         else:
-            a, b = states, prevstates
+            a, b, r = states, prevstates, prev.get(fn, -1)
         for change, l in difflinestates(a, b):
-            if incrementing or not opts['all']:
-                r = rev
-            else:
-                r = prev[fn]
             cols = [fn, str(r)]
             if opts['line_number']:
                 cols.append(str(l.linenum))
             if opts['all']:
                 cols.append(change)
             if opts['user']:
-                cols.append(trimuser(ui, getchange(r)[1], rev,
-                                     ucache))
+                cols.append(ui.shortuser(getchange(r)[1]))
             if opts['files_with_matches']:
-                c = (fn, rev)
+                c = (fn, r)
                 if c in filerevmatches:
                     continue
                 filerevmatches[c] = 1
@@ -1505,7 +1482,8 @@ def grep(ui, repo, pattern, *pats, **opt
 
     fstate = {}
     skip = {}
-    changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
+    getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
+    changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
     count = 0
     incrementing = False
     follow = opts.get('follow')
@@ -1514,8 +1492,7 @@ def grep(ui, repo, pattern, *pats, **opt
             incrementing = rev
             matches.clear()
         elif st == 'add':
-            change = repo.changelog.read(repo.lookup(str(rev)))
-            mf = repo.manifest.read(change[0])
+            mf = repo.changectx(rev).manifest()
             matches[rev] = {}
             for fn in fns:
                 if fn in skip:
@@ -1838,7 +1815,8 @@ def log(ui, repo, *pats, **opts):
         def __getattr__(self, key):
             return getattr(self.ui, key)
 
-    changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
+    getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
+    changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
 
     if opts['branches']:
         ui.warn(_("the --branches option is deprecated, "
@@ -1855,8 +1833,7 @@ def log(ui, repo, *pats, **opts):
     count = 0
 
     if opts['copies'] and opts['rev']:
-        endrev = max([int(i)
-                      for i in cmdutil.revrange(ui, repo, opts['rev'])]) + 1
+        endrev = max(cmdutil.revrange(ui, repo, opts['rev'])) + 1
     else:
         endrev = repo.changelog.count()
     rcache = {}
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -25,7 +25,6 @@ class dirstate(object):
         self.dirs = None
         self.copymap = {}
         self.ignorefunc = None
-        self.blockignore = False
 
     def wjoin(self, f):
         return os.path.join(self.root, f)
@@ -98,8 +97,6 @@ class dirstate(object):
         '''default match function used by dirstate and
         localrepository.  this honours the repository .hgignore file
         and any other files specified in the [ui] section of .hgrc.'''
-        if self.blockignore:
-            return False
         if not self.ignorefunc:
             ignore = self.hgignore()
             allpats = []
@@ -350,45 +347,42 @@ class dirstate(object):
                 kind))
         return False
 
-    def statwalk(self, files=None, match=util.always, dc=None, ignored=False,
+    def walk(self, files=None, match=util.always, badmatch=None):
+        # filter out the stat
+        for src, f, st in self.statwalk(files, match, badmatch=badmatch):
+            yield src, f
+
+    def statwalk(self, files=None, match=util.always, ignored=False,
                  badmatch=None):
+        '''
+        walk recursively through the directory tree, finding all files
+        matched by the match function
+
+        results are yielded in a tuple (src, filename, st), where src
+        is one of:
+        'f' the file was found in the directory tree
+        'm' the file was only in the dirstate and not in the tree
+        'b' file was not found and matched badmatch
+
+        and st is the stat result if the file was found in the directory.
+        '''
         self.lazyread()
 
         # walk all files by default
         if not files:
             files = [self.root]
-            if not dc:
-                dc = self.map.copy()
-        elif not dc:
+            dc = self.map.copy()
+        else:
+            files = util.unique(files)
             dc = self.filterfiles(files)
 
-        def statmatch(file_, stat):
-            file_ = util.pconvert(file_)
-            if not ignored and file_ not in dc and self.ignore(file_):
+        def imatch(file_):
+            if file_ not in dc and self.ignore(file_):
                 return False
             return match(file_)
 
-        return self.walkhelper(files=files, statmatch=statmatch, dc=dc,
-                               badmatch=badmatch)
-
-    def walk(self, files=None, match=util.always, dc=None, badmatch=None):
-        # filter out the stat
-        for src, f, st in self.statwalk(files, match, dc, badmatch=badmatch):
-            yield src, f
+        if ignored: imatch = match
 
-    # walk recursively through the directory tree, finding all files
-    # matched by the statmatch function
-    #
-    # results are yielded in a tuple (src, filename, st), where src
-    # is one of:
-    # 'f' the file was found in the directory tree
-    # 'm' the file was only in the dirstate and not in the tree
-    # and st is the stat result if the file was found in the directory.
-    #
-    # dc is an optional arg for the current dirstate.  dc is not modified
-    # directly by this function, but might be modified by your statmatch call.
-    #
-    def walkhelper(self, files, statmatch, dc, badmatch=None):
         # self.root may end with a path separator when self.root == '/'
         common_prefix_len = len(self.root)
         if not self.root.endswith('/'):
@@ -420,12 +414,12 @@ class dirstate(object):
                     # don't trip over symlinks
                     st = os.lstat(p)
                     if stat.S_ISDIR(st.st_mode):
-                        ds = os.path.join(nd, f +'/')
-                        if statmatch(ds, st):
+                        ds = util.pconvert(os.path.join(nd, f +'/'))
+                        if imatch(ds):
                             work.append(p)
-                        if statmatch(np, st) and np in dc:
+                        if imatch(np) and np in dc:
                             yield 'm', np, st
-                    elif statmatch(np, st):
+                    elif imatch(np):
                         if self.supported_type(np, st):
                             yield 'f', np, st
                         elif np in dc:
@@ -438,12 +432,12 @@ class dirstate(object):
 
         # step one, find all files that match our criteria
         files.sort()
-        for ff in util.unique(files):
+        for ff in files:
+            nf = util.normpath(ff)
             f = self.wjoin(ff)
             try:
                 st = os.lstat(f)
             except OSError, inst:
-                nf = util.normpath(ff)
                 found = False
                 for fn in dc:
                     if nf == fn or (fn.startswith(nf) and fn[len(nf)] == '/'):
@@ -454,7 +448,7 @@ class dirstate(object):
                         self.ui.warn('%s: %s\n' % (
                             util.pathto(self.getcwd(), ff),
                             inst.strerror))
-                    elif badmatch and badmatch(ff) and statmatch(ff, None):
+                    elif badmatch and badmatch(ff) and imatch(nf):
                         yield 'b', ff, None
                 continue
             if stat.S_ISDIR(st.st_mode):
@@ -464,23 +458,18 @@ class dirstate(object):
                 for e in sorted_:
                     yield e
             else:
-                ff = util.normpath(ff)
-                if seen(ff):
-                    continue
-                self.blockignore = True
-                if statmatch(ff, st):
+                if not seen(nf) and match(nf):
                     if self.supported_type(ff, st, verbose=True):
-                        yield 'f', ff, st
+                        yield 'f', nf, st
                     elif ff in dc:
-                        yield 'm', ff, st
-                self.blockignore = False
+                        yield 'm', nf, st
 
         # step two run through anything left in the dc hash and yield
         # if we haven't already seen it
         ks = dc.keys()
         ks.sort()
         for k in ks:
-            if not seen(k) and (statmatch(k, None)):
+            if not seen(k) and imatch(k):
                 yield 'm', k, None
 
     def status(self, files=None, match=util.always, list_ignored=False,
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -714,6 +714,18 @@ class localrepository(repo.repository):
         return n
 
     def walk(self, node=None, files=[], match=util.always, badmatch=None):
+        '''
+        walk recursively through the directory tree or a given
+        changeset, finding all files matched by the match
+        function
+
+        results are yielded in a tuple (src, filename), where src
+        is one of:
+        'f' the file was found in the directory tree
+        'm' the file was only in the dirstate and not in the tree
+        'b' file was not found and matched badmatch
+        '''
+
         if node:
             fdict = dict.fromkeys(files)
             for fn in self.manifest.read(self.changelog.read(node)[0]):
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -128,10 +128,12 @@ def binary(s):
 def unique(g):
     """return the uniq elements of iterable g"""
     seen = {}
+    l = []
     for f in g:
         if f not in seen:
             seen[f] = 1
-            yield f
+            l.append(f)
+    return l
 
 class Abort(Exception):
     """Raised if a command needs to print an error and exit."""
@@ -985,6 +987,9 @@ def shortuser(user):
     f = user.find(' ')
     if f >= 0:
         user = user[:f]
+    f = user.find('.')
+    if f >= 0:
+        user = user[:f]
     return user
 
 def walkrepos(path):
--- a/tests/test-grep.out
+++ b/tests/test-grep.out
@@ -9,7 +9,7 @@ port:2:1:+:spam:export
 port:2:2:+:spam:vaportight
 port:2:3:+:spam:import/export
 port:1:2:+:eggs:export
-port:0:1:+:eggs:import
+port:0:1:+:spam:import
 port:4:import/export
 % follow
 port:0:import
@@ -22,4 +22,4 @@ port:2:1:+:spam:export
 port:2:2:+:spam:vaportight
 port:2:3:+:spam:import/export
 port:1:2:+:eggs:export
-port:0:1:+:eggs:import
+port:0:1:+:spam:import