# HG changeset patch # User Thomas Arendsen Hein # Date 2006-10-27 21:09:46 # Node ID 23f7d96217831943b19eb5734a76c29f3afd3e1f # Parent 3bab1fc0ab7545bb18109db151560c5eca05a7c0 # Parent ece5c53577eb38693dc43ed27f5098dc4be80554 Merge with upstream diff --git a/hgext/mq.py b/hgext/mq.py --- 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 ' diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- 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: diff --git a/mercurial/commands.py b/mercurial/commands.py --- 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 = {} diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- 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, diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- 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]): diff --git a/mercurial/util.py b/mercurial/util.py --- 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): diff --git a/tests/test-grep.out b/tests/test-grep.out --- 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