Mercurial > hg
changeset 2871:ffa2be02c4e5
merge.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sat, 12 Aug 2006 15:43:38 -0700 |
parents | 8eaaf1321bfe (diff) 9a2a481ec3ea (current diff) |
children | 5dd6631c8238 |
files | mercurial/commands.py |
diffstat | 3 files changed, 76 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Sat Aug 12 15:41:26 2006 -0700 +++ b/mercurial/commands.py Sat Aug 12 15:43:38 2006 -0700 @@ -10,7 +10,7 @@ from i18n import gettext as _ demandload(globals(), "os re sys signal shutil imp urllib pdb") demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") -demandload(globals(), "fnmatch mdiff patch random signal tempfile time") +demandload(globals(), "fnmatch mdiff difflib patch random signal tempfile time") demandload(globals(), "traceback errno socket version struct atexit sets bz2") demandload(globals(), "archival cStringIO changegroup") demandload(globals(), "hgweb.server sshserver") @@ -1644,42 +1644,56 @@ self.linenum = linenum self.colstart = colstart self.colend = colend + def __eq__(self, other): return self.line == other.line - def __hash__(self): - return hash(self.line) matches = {} + copies = {} def grepbody(fn, rev, body): - matches[rev].setdefault(fn, {}) + matches[rev].setdefault(fn, []) m = matches[rev][fn] for lnum, cstart, cend, line in matchlines(body): s = linestate(line, lnum, cstart, cend) - m[s] = s - - # FIXME: prev isn't used, why ? + m.append(s) + + def difflinestates(a, b): + sm = difflib.SequenceMatcher(None, a, b) + for tag, alo, ahi, blo, bhi in sm.get_opcodes(): + if tag == 'insert': + for i in range(blo, bhi): + yield ('+', b[i]) + elif tag == 'delete': + for i in range(alo, ahi): + yield ('-', a[i]) + elif tag == 'replace': + for i in range(alo, ahi): + yield ('-', a[i]) + for i in range(blo, bhi): + yield ('+', b[i]) + prev = {} ucache = {} def display(fn, rev, states, prevstates): - diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates))) - diff.sort(lambda x, y: cmp(x.linenum, y.linenum)) counts = {'-': 0, '+': 0} filerevmatches = {} - for l in diff: + if incrementing or not opts['all']: + a, b = prevstates, states + else: + a, b = states, prevstates + for change, l in difflinestates(a, b): if incrementing or not opts['all']: - change = ((l in prevstates) and '-') or '+' r = rev else: - change = ((l in states) and '-') or '+' r = prev[fn] - cols = [fn, str(rev)] + 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(rev)[1], rev, - ucache)) + cols.append(trimuser(ui, getchange(r)[1], rev, + ucache)) if opts['files_with_matches']: c = (fn, rev) if c in filerevmatches: @@ -1696,10 +1710,12 @@ changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) count = 0 incrementing = False + follow = opts.get('follow') for st, rev, fns in changeiter: if st == 'window': incrementing = rev matches.clear() + copies.clear() elif st == 'add': change = repo.changelog.read(repo.lookup(str(rev))) mf = repo.manifest.read(change[0]) @@ -1708,22 +1724,34 @@ if fn in skip: continue fstate.setdefault(fn, {}) + copies.setdefault(rev, {}) try: grepbody(fn, rev, getfile(fn).read(mf[fn])) + if follow: + copied = getfile(fn).renamed(mf[fn]) + if copied: + copies[rev][fn] = copied[0] except KeyError: pass elif st == 'iter': states = matches[rev].items() states.sort() for fn, m in states: + copy = copies[rev].get(fn) if fn in skip: + if copy: + skip[copy] = True continue if incrementing or not opts['all'] or fstate[fn]: pos, neg = display(fn, rev, m, fstate[fn]) count += pos + neg if pos and not opts['all']: skip[fn] = True + if copy: + skip[copy] = True fstate[fn] = m + if copy: + fstate[copy] = m prev[fn] = rev if not incrementing: @@ -1732,7 +1760,8 @@ for fn, state in fstate: if fn in skip: continue - display(fn, rev, {}, state) + if fn not in copies[prev[fn]]: + display(fn, rev, {}, state) return (count == 0 and 1) or 0 def heads(ui, repo, **opts): @@ -3061,6 +3090,8 @@ (grep, [('0', 'print0', None, _('end fields with NUL')), ('', 'all', None, _('print all revisions that match')), + ('f', 'follow', None, + _('follow changeset history, or file history across copies and renames')), ('i', 'ignore-case', None, _('ignore case when matching')), ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
--- a/tests/test-grep Sat Aug 12 15:41:26 2006 -0700 +++ b/tests/test-grep Sat Aug 12 15:43:38 2006 -0700 @@ -18,6 +18,13 @@ mv port1 port hg commit -m 4 -u spam -d '4 0' hg grep port port -echo 'FIXME: history is wrong here' hg grep --all -nu port port hg grep import port + +hg cp port port2 +hg commit -m 4 -u spam -d '5 0' +echo '% follow' +hg grep -f 'import$' port2 +echo deport >> port2 +hg commit -m 5 -u eggs -d '6 0' +hg grep -f --all -nu port port2
--- a/tests/test-grep.out Sat Aug 12 15:41:26 2006 -0700 +++ b/tests/test-grep.out Sat Aug 12 15:43:38 2006 -0700 @@ -1,10 +1,25 @@ port:4:export port:4:vaportight port:4:import/export -FIXME: history is wrong here -port:1:1:-:eggs:import -port:1:2:+:eggs:vaportight -port:1:3:+:eggs:import/export -port:0:2:+:spam:export -port:0:1:+:spam:import +port:4:4:-:spam:import/export +port:3:4:+:eggs:import/export +port:2:1:-:spam:import +port:2:2:-:spam:export +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:4:import/export +% follow +port:0:import +port2:6:4:+:eggs:deport +port:4:4:-:spam:import/export +port:3:4:+:eggs:import/export +port:2:1:-:spam:import +port:2:2:-:spam:export +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