diff mercurial/filelog.py @ 1089:142b5d5ec9cc

Break apart hg.py - move the various parts of hg.py into their own files - create node.py to store node manipulation functions
author mpm@selenic.com
date Sat, 27 Aug 2005 14:21:25 -0700
parents mercurial/hg.py@05dc7aba22eb
children 0cdd73b0767c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/filelog.py	Sat Aug 27 14:21:25 2005 -0700
@@ -0,0 +1,98 @@
+# filelog.py - file history class for mercurial
+#
+# Copyright 2005 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import os
+from revlog import *
+from demandload import *
+demandload(globals(), "bdiff")
+
+class filelog(revlog):
+    def __init__(self, opener, path):
+        revlog.__init__(self, opener,
+                        os.path.join("data", self.encodedir(path + ".i")),
+                        os.path.join("data", self.encodedir(path + ".d")))
+
+    # This avoids a collision between a file named foo and a dir named
+    # foo.i or foo.d
+    def encodedir(self, path):
+        return (path
+                .replace(".hg/", ".hg.hg/")
+                .replace(".i/", ".i.hg/")
+                .replace(".d/", ".d.hg/"))
+
+    def decodedir(self, path):
+        return (path
+                .replace(".d.hg/", ".d/")
+                .replace(".i.hg/", ".i/")
+                .replace(".hg.hg/", ".hg/"))
+
+    def read(self, node):
+        t = self.revision(node)
+        if not t.startswith('\1\n'):
+            return t
+        s = t.find('\1\n', 2)
+        return t[s+2:]
+
+    def readmeta(self, node):
+        t = self.revision(node)
+        if not t.startswith('\1\n'):
+            return t
+        s = t.find('\1\n', 2)
+        mt = t[2:s]
+        for l in mt.splitlines():
+            k, v = l.split(": ", 1)
+            m[k] = v
+        return m
+
+    def add(self, text, meta, transaction, link, p1=None, p2=None):
+        if meta or text.startswith('\1\n'):
+            mt = ""
+            if meta:
+                mt = [ "%s: %s\n" % (k, v) for k,v in meta.items() ]
+            text = "\1\n" + "".join(mt) + "\1\n" + text
+        return self.addrevision(text, transaction, link, p1, p2)
+
+    def annotate(self, node):
+
+        def decorate(text, rev):
+            return ([rev] * len(text.splitlines()), text)
+
+        def pair(parent, child):
+            for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
+                child[0][b1:b2] = parent[0][a1:a2]
+            return child
+
+        # find all ancestors
+        needed = {node:1}
+        visit = [node]
+        while visit:
+            n = visit.pop(0)
+            for p in self.parents(n):
+                if p not in needed:
+                    needed[p] = 1
+                    visit.append(p)
+                else:
+                    # count how many times we'll use this
+                    needed[p] += 1
+
+        # sort by revision which is a topological order
+        visit = [ (self.rev(n), n) for n in needed.keys() ]
+        visit.sort()
+        hist = {}
+
+        for r,n in visit:
+            curr = decorate(self.read(n), self.linkrev(n))
+            for p in self.parents(n):
+                if p != nullid:
+                    curr = pair(hist[p], curr)
+                    # trim the history of unneeded revs
+                    needed[p] -= 1
+                    if not needed[p]:
+                        del hist[p]
+            hist[n] = curr
+
+        return zip(hist[n][0], hist[n][1].splitlines(1))