1 import os, re, stat, time
14 class NodeError(Exception):
16 class NoSuchFile(NodeError):
18 class NotDir(NodeError):
20 class NotFile(NodeError):
22 class TooManySymlinks(NodeError):
27 def __init__(self, node):
30 self.size = self.n.size()
43 def read(self, count = -1):
45 count = self.size - self.ofs
46 buf = self.n.readbytes(self.ofs, count)
52 def __init__(self, parent, name, mode, hash):
60 return cmp(a.name or None, b.name or None)
63 return iter(self.subs())
67 return os.path.join(self.parent.fullname(), self.name)
75 if self._subs == None:
77 return sorted(self._subs.values())
80 if self._subs == None:
82 ret = self._subs.get(name)
84 raise NoSuchFile("no file %r in %r" % (name, self.name))
89 return self.parent.top()
93 def _lresolve(self, parts):
94 #log('_lresolve %r in %r\n' % (parts, self.name))
97 (first, rest) = (parts[0], parts[1:])
99 return self._lresolve(rest)
102 raise NoSuchFile("no parent dir for %r" % self.name)
103 return self.parent._lresolve(rest)
105 return self.sub(first)._lresolve(rest)
107 return self.sub(first)
109 def lresolve(self, path):
111 if path.startswith('/'):
114 parts = re.split(r'/+', path or '.')
117 #log('parts: %r %r\n' % (path, parts))
118 return start._lresolve(parts)
120 def resolve(self, path):
121 return self.lresolve(path).lresolve('')
124 if self._subs == None:
132 raise NotFile('%s is not a regular file' % self.name)
134 def readbytes(self, ofs, count):
135 raise NotFile('%s is not a regular file' % self.name)
137 def read(self, num = -1):
140 return self.readbytes(0, num)
145 return cp().join(self.hash.encode('hex'))
148 return FileReader(self)
152 return sum(len(blob) for blob in self._content())
154 def readbytes(self, ofs, count):
156 buf = ''.join(self._content())
157 return buf[ofs:ofs+count]
162 def __init__(self, parent, name, hash):
163 File.__init__(self, parent, name, 0120000, hash)
166 return self.read(1024)
168 def dereference(self):
171 raise TooManySymlinks('too many levels of symlinks: %r'
175 return self.parent.lresolve(self.readlink())
179 def _lresolve(self, parts):
180 return self.dereference()._lresolve(parts)
183 class FakeSymlink(Symlink):
184 def __init__(self, parent, name, toname):
185 Symlink.__init__(self, parent, name, EMPTY_SHA)
195 it = cp().get(self.hash.encode('hex'))
199 it = cp().get(self.hash.encode('hex') + ':')
201 assert(type == 'tree')
202 for (mode,name,sha) in git._treeparse(''.join(it)):
204 if stat.S_ISDIR(mode):
205 self._subs[name] = Dir(self, name, mode, sha)
206 elif stat.S_ISLNK(mode):
207 self._subs[name] = Symlink(self, name, sha)
209 self._subs[name] = File(self, name, mode, sha)
212 class CommitList(Node):
213 def __init__(self, parent, name, hash):
214 Node.__init__(self, parent, name, 040000, hash)
218 revs = list(git.rev_list(self.hash.encode('hex')))
219 for (date, commit) in revs:
220 l = time.localtime(date)
221 ls = time.strftime('%Y-%m-%d-%H%M%S', l)
222 commithex = commit.encode('hex')
223 self._subs[commithex] = Dir(self, commithex, 040000, commit)
224 self._subs[ls] = FakeSymlink(self, ls, commit.encode('hex'))
227 (date, commit) = latest
228 self._subs['latest'] = FakeSymlink(self, 'latest',
229 commit.encode('hex'))
233 def __init__(self, parent):
234 Node.__init__(self, parent, '/', 040000, EMPTY_SHA)
238 for (name,sha) in git.list_refs():
239 if name.startswith('refs/heads/'):
241 self._subs[name] = CommitList(self, name, sha)