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
pass
-class Node:
+class Node(object):
"""Base class for file representation."""
def __init__(self, parent, name, mode, hash):
self.parent = parent
"""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."""
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 = {}
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)
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.
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)
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