]> arthur.barton.de Git - bup.git/blobdiff - lib/bup/vfs.py
Retrieve the dates for all branches with one bulk git call in the VFS.
[bup.git] / lib / bup / vfs.py
index 85b4c204c2f261fb1e984a7b450d38af4b22adc6..301d14572ef6ae5e3817f3ae4d0c791b35bf56ba 100644 (file)
@@ -6,6 +6,7 @@ and abstracts internal name mangling and storage from the exposition layer.
 import os, re, stat, time
 from bup import git, metadata
 from helpers import *
+from bup.git import BUP_NORMAL, BUP_CHUNKED
 from bup.hashsplit import GIT_MODE_TREE, GIT_MODE_FILE
 
 EMPTY_SHA='\0'*20
@@ -162,7 +163,7 @@ class _FileReader(object):
         pass
 
 
-class Node:
+class Node(object):
     """Base class for file representation."""
     def __init__(self, parent, name, mode, hash):
         self.parent = parent
@@ -299,16 +300,21 @@ class Node:
         """Open the current node. It is an error to open a non-file node."""
         raise NotFile('%s is not a regular file' % self.name)
 
-    def _populate_metadata(self):
+    def _populate_metadata(self, force=False):
         # Only Dirs contain .bupm files, so by default, do nothing.
         pass
 
     def metadata(self):
         """Return this Node's Metadata() object, if any."""
-        if self.parent:
-            self.parent._populate_metadata()
+        if not self._metadata and self.parent:
+            self.parent._populate_metadata(force=True)
         return self._metadata
 
+    def release(self):
+        """Release resources that can be automatically restored (at a cost)."""
+        self._metadata = None
+        self._subs = None
+
 
 class File(Node):
     """A normal file from bup's repository."""
@@ -400,16 +406,19 @@ class Dir(Node):
         Node.__init__(self, *args, **kwargs)
         self._bupm = None
 
-    def _populate_metadata(self):
+    def _populate_metadata(self, force=False):
+        if self._metadata and not force:
+            return
         if not self._subs:
             self._mksubs()
         if not self._bupm:
             return
         meta_stream = self._bupm.open()
-        self._metadata = metadata.Metadata.read(meta_stream)
+        dir_meta = metadata.Metadata.read(meta_stream)
         for sub in self:
             if not stat.S_ISDIR(sub.mode):
                 sub._metadata = metadata.Metadata.read(meta_stream)
+        self._metadata = dir_meta
 
     def _mksubs(self):
         self._subs = {}
@@ -422,7 +431,9 @@ class Dir(Node):
         assert(type == 'tree')
         for (mode,mangled_name,sha) in git.tree_decode(''.join(it)):
             if mangled_name == '.bupm':
-                self._bupm = File(self, mangled_name, mode, sha, git.BUP_NORMAL)
+                bupmode = stat.S_ISDIR(mode) and BUP_CHUNKED or BUP_NORMAL
+                self._bupm = File(self, mangled_name, GIT_MODE_FILE, sha,
+                                  bupmode)
                 continue
             name = mangled_name
             (name,bupmode) = git.demangle_name(mangled_name)
@@ -446,6 +457,11 @@ class Dir(Node):
             self._mksubs()
         return self._bupm
 
+    def release(self):
+        """Release restorable resources held by this node."""
+        self._bupm = None
+        super(Dir, self).release()
+
 
 class CommitDir(Node):
     """A directory that contains all commits that are reachable by a ref.
@@ -507,7 +523,7 @@ class TagDir(Node):
         for (name, sha) in git.list_refs():
             if name.startswith('refs/tags/'):
                 name = name[10:]
-                date = git.rev_get_date(sha.encode('hex'))
+                date = git.get_commit_dates([sha.encode('hex')])[0]
                 commithex = sha.encode('hex')
                 target = '../.commit/%s/%s' % (commithex[:2], commithex[2:])
                 tag1 = FakeSymlink(self, name, target)
@@ -574,10 +590,13 @@ class RefList(Node):
         tag_dir = TagDir(self, '.tag')
         self._subs['.tag'] = tag_dir
 
-        for (name,sha) in git.list_refs():
-            if name.startswith('refs/heads/'):
-                name = name[11:]
-                date = git.rev_get_date(sha.encode('hex'))
-                n1 = BranchList(self, name, sha)
-                n1.ctime = n1.mtime = date
-                self._subs[name] = n1
+        refs_info = [(name[11:], sha) for (name,sha) in git.list_refs() \
+                     if name.startswith('refs/heads/')]
+
+        dates = git.get_commit_dates([sha.encode('hex')
+                                      for (name, sha) in refs_info])
+
+        for (name, sha), date in zip(refs_info, dates):
+            n1 = BranchList(self, name, sha)
+            n1.ctime = n1.mtime = date
+            self._subs[name] = n1