patch: use contexts for diff
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Mon, 25 Dec 2006 17:43:49 +0100
changeset 3967 dccb83241dd0
parent 3966 b4eaa68dea1b
child 3968 033082ba1d1a
patch: use contexts for diff
mercurial/patch.py
--- a/mercurial/patch.py	Mon Dec 25 18:57:55 2006 +0100
+++ b/mercurial/patch.py	Mon Dec 25 17:43:49 2006 +0100
@@ -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 @@
     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 @@
     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 @@
             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 @@
         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 @@
 
             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 @@
                         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 @@
                 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 @@
             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)