diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -7,7 +7,7 @@ from i18n import _ from node import * -import base85, cmdutil, mdiff, util +import base85, cmdutil, mdiff, util, context, revlog import cStringIO, email.Parser, os, popen2, re, sha import sys, tempfile, zlib @@ -436,27 +436,25 @@ def diff(repo, node1=None, node2=None, f if not node1: node1 = repo.dirstate.parents()[0] - clcache = {} - def getchangelog(n): - if n not in clcache: - clcache[n] = repo.changelog.read(n) - return clcache[n] - mcache = {} - def getmanifest(n): - if n not in mcache: - mcache[n] = repo.manifest.read(n) - return mcache[n] - fcache = {} - def getfile(f): - if f not in fcache: - fcache[f] = repo.file(f) - return fcache[f] + ccache = {} + def getctx(r): + if r not in ccache: + ccache[r] = context.changectx(repo, r) + return ccache[r] + + flcache = {} + def getfilectx(f, ctx): + flctx = ctx.filectx(f, filelog=flcache.get(f)) + if f not in flcache: + flcache[f] = flctx._filelog + return flctx # reading the data for node1 early allows it to play nicely # with repo.status and the revlog cache. - change = getchangelog(node1) - mmap = getmanifest(change[0]) - date1 = util.datestr(change[2]) + ctx1 = context.changectx(repo, node1) + # force manifest reading + man1 = ctx1.manifest() + date1 = util.datestr(ctx1.date()) if not changes: changes = repo.status(node1, node2, files, match=match)[:5] @@ -476,67 +474,38 @@ def diff(repo, node1=None, node2=None, f if not modified and not added and not removed: return - # returns False if there was no rename between n1 and n2 - # returns None if the file was created between n1 and n2 - # returns the (file, node) present in n1 that was renamed to f in n2 - def renamedbetween(f, n1, n2): - r1, r2 = map(repo.changelog.rev, (n1, n2)) + if node2: + ctx2 = context.changectx(repo, node2) + else: + ctx2 = context.workingctx(repo) + man2 = ctx2.manifest() + + # returns False if there was no rename between ctx1 and ctx2 + # returns None if the file was created between ctx1 and ctx2 + # returns the (file, node) present in ctx1 that was renamed to f in ctx2 + def renamed(f): + startrev = ctx1.rev() + c = ctx2 + crev = c.rev() + if crev is None: + crev = repo.changelog.count() orig = f - src = None - while r2 > r1: - cl = getchangelog(n2) - if f in cl[3]: - m = getmanifest(cl[0]) + while crev > startrev: + if f in c.files(): try: - src = getfile(f).renamed(m[f]) - except KeyError: + src = getfilectx(f, c).renamed() + except revlog.LookupError: return None if src: f = src[0] - n2 = repo.changelog.parents(n2)[0] - r2 = repo.changelog.rev(n2) - cl = getchangelog(n1) - m = getmanifest(cl[0]) - if f not in m: + crev = c.parents()[0].rev() + # try to reuse + c = getctx(crev) + if f not in man1: return None if f == orig: return False - return f, m[f] - - if node2: - change = getchangelog(node2) - mmap2 = getmanifest(change[0]) - _date2 = util.datestr(change[2]) - def date2(f): - return _date2 - def read(f): - return getfile(f).read(mmap2[f]) - def renamed(f): - return renamedbetween(f, node1, node2) - else: - tz = util.makedate()[1] - _date2 = util.datestr() - def date2(f): - try: - return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) - except OSError, err: - if err.errno != errno.ENOENT: raise - return _date2 - def read(f): - return repo.wread(f) - def renamed(f): - src = repo.dirstate.copied(f) - parent = repo.dirstate.parents()[0] - if src: - f = src - of = renamedbetween(f, node1, parent) - if of or of is None: - return of - elif src: - cl = getchangelog(parent)[0] - return (src, getmanifest(cl)[src]) - else: - return None + return f if repo.ui.quiet: r = None @@ -550,7 +519,7 @@ def diff(repo, node1=None, node2=None, f src = renamed(f) if src: copied[f] = src - srcs = [x[1][0] for x in copied.items()] + srcs = [x[1] for x in copied.items()] all = modified + added + removed all.sort() @@ -560,10 +529,10 @@ def diff(repo, node1=None, node2=None, f tn = None dodiff = True header = [] - if f in mmap: - to = getfile(f).read(mmap[f]) + if f in man1: + to = getfilectx(f, ctx1).data() if f not in removed: - tn = read(f) + tn = getfilectx(f, ctx2).data() if opts.git: def gitmode(x): return x and '100755' or '100644' @@ -574,13 +543,10 @@ def diff(repo, node1=None, node2=None, f a, b = f, f if f in added: - if node2: - mode = gitmode(mmap2.execf(f)) - else: - mode = gitmode(util.is_exec(repo.wjoin(f), None)) + mode = gitmode(man2.execf(f)) if f in copied: - a, arev = copied[f] - omode = gitmode(mmap.execf(a)) + a = copied[f] + omode = gitmode(man1.execf(a)) addmodehdr(header, omode, mode) if a in removed and a not in gone: op = 'rename' @@ -589,7 +555,7 @@ def diff(repo, node1=None, node2=None, f op = 'copy' header.append('%s from %s\n' % (op, a)) header.append('%s to %s\n' % (op, f)) - to = getfile(a).read(arev) + to = getfilectx(a, ctx1).data() else: header.append('new file mode %s\n' % mode) if util.binary(tn): @@ -598,14 +564,11 @@ def diff(repo, node1=None, node2=None, f if f in srcs: dodiff = False else: - mode = gitmode(mmap.execf(f)) + mode = gitmode(man1.execf(f)) header.append('deleted file mode %s\n' % mode) else: - omode = gitmode(mmap.execf(f)) - if node2: - nmode = gitmode(mmap2.execf(f)) - else: - nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f))) + omode = gitmode(man1.execf(f)) + nmode = gitmode(man2.execf(f)) addmodehdr(header, omode, nmode) if util.binary(to) or util.binary(tn): dodiff = 'binary' @@ -615,7 +578,10 @@ def diff(repo, node1=None, node2=None, f fp.write(''.join(header)) b85diff(fp, to, tn) elif dodiff: - text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts) + text = mdiff.unidiff(to, date1, + # ctx2 date may be dynamic + tn, util.datestr(ctx2.date()), + f, r, opts=opts) if text or len(header) > 1: fp.write(''.join(header)) fp.write(text)