Add functions for determining the delta between the index and a revision tree.
authorJelmer Vernooij <jelmer@samba.org>
Wed, 7 Oct 2009 13:14:05 +0000 (15:14 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 7 Oct 2009 13:14:05 +0000 (15:14 +0200)
NEWS
dulwich/index.py
dulwich/object_store.py

diff --git a/NEWS b/NEWS
index 5890c217312658f6f378762c10f55099043bbd91..f2bfc7904eede4f452efa92005303128744d3306 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,11 @@
 0.4.1  UNRELEASED
 
+ FEATURES
+
+  * Add ObjectStore.iter_tree_contents()
+
+  * Add Index.changes_from_tree()
+
 0.4.0  2009-10-07
 
  DOCUMENTATION
index aa57e156034d64dd95ffd78752bdbd48af058f3b..b5f6014e5978c08e7f2b15632506f705ceaec7cb 100644 (file)
@@ -212,6 +212,10 @@ class Index(object):
         """Return the (git object) SHA1 for the object at a path."""
         return self[path][-2]
 
+    def get_mode(self, path):
+        """Return the POSIX file mode for the object at a path."""
+        return self[path][-6]
+
     def iterblobs(self):
         """Iterate over path, sha, mode tuples for use with commit_tree."""
         for path, entry in self:
@@ -234,6 +238,28 @@ class Index(object):
         for name, value in entries.iteritems():
             self[name] = value
 
+    def changes_from_tree(self, object_store, tree, want_unchanged=False):
+        """Find the differences between the contents of this index and a tree.
+
+        :param object_store: Object store to use for retrieving tree contents
+        :param tree: SHA1 of the root tree
+        :param want_unchanged: Whether unchanged files should be reported
+        :return: Iterator over tuples with (oldpath, newpath), (oldmode, newmode), (oldsha, newsha)
+        """
+        mine = set(self._byname.keys())
+        for (name, mode, sha) in object_store.iter_tree_contents(tree):
+            if name in mine:
+                if (want_unchanged or self.get_sha1(name) != sha or 
+                    self.get_mode(name) != mode):
+                    yield ((name, name), (mode, self.get_mode(name)), (sha, self.get_sha1(name)))
+                mine.remove(name)
+            else:
+                # Was removed
+                yield ((name, None), (mode, None), (sha, None))
+        # Mention added files
+        for name in mine:
+            yield ((None, name), (None, self.get_mode(name)), (None, self.get_sha1(name)))
+
 
 def commit_tree(object_store, blobs):
     """Commit a new tree.
index 3b0ca070169d1dbd7c03f02f577e1cc063b1f909..956962b1f654308b240b6b9d72349072fa526a92 100644 (file)
@@ -99,6 +99,25 @@ class BaseObjectStore(object):
         """
         raise NotImplementedError(self.add_objects)
 
+    def iter_tree_contents(self, tree):
+        """Yield (path, mode, hexsha) tuples for all non-Tree objects in a tree.
+
+        :param tree: SHA1 of the root of the tree
+        """
+        todo = set([(tree, "")])
+        while todo:
+            (tid, tpath) = todo.pop()
+            tree = self[tid]
+            for name, mode, hexsha in tree.iteritems(): 
+                if tpath == "":
+                    path = name
+                else:
+                    path = "%s/%s" % (tpath, name)
+                if stat.S_ISDIR(mode):
+                    todo.add((hexsha, path))
+                else:
+                    yield path, mode, hexsha
+
     def find_missing_objects(self, haves, wants, progress=None):
         """Find the missing objects required for a set of revisions.