tahoe-lafs/contrib/fuse/impl_b/pyfuse/r_svnfs.py

143 lines
4.3 KiB
Python

"""
A read-only svn fs showing all the revisions in subdirectories.
"""
from objectfs import ObjectFs, SymLink
from handler import Handler
from pysvn.ra import connect
from pysvn.date import decode
import errno, posixpath, time
#USE_SYMLINKS = 0 # they are wrong if the original file had another path
# use getfattr -d filename to see the node's attributes, which include
# information like the revision at which the file was last modified
class Root:
def __init__(self, svnurl):
self.svnurl = svnurl
self.ra = connect(svnurl)
self.head = self.ra.get_latest_rev()
def listdir(self):
for rev in range(1, self.head+1):
yield str(rev)
yield 'HEAD'
def join(self, name):
try:
rev = int(name)
except ValueError:
if name == 'HEAD':
return SymLink(str(self.head))
else:
raise KeyError(name)
return TopLevelDir(self.ra, rev, rev, '')
class Node:
def __init__(self, ra, rev, last_changed_rev, path):
self.ra = ra
self.rev = rev
self.last_changed_rev = last_changed_rev
self.path = path
def __repr__(self):
return '<%s %d/%s>' % (self.__class__.__name__, self.rev, self.path)
class Dir(Node):
def listdir(self):
rev, props, entries = self.ra.get_dir(self.path, self.rev,
want_props = False)
for key, stats in entries.items():
yield key, getnode(self.ra, self.rev,
posixpath.join(self.path, key), stats)
class File(Node):
def __init__(self, ra, rev, last_changed_rev, path, size):
Node.__init__(self, ra, rev, last_changed_rev, path)
self.filesize = size
def size(self):
return self.filesize
def read(self):
checksum, rev, props, data = self.ra.get_file(self.path, self.rev,
want_props = False)
return data
class TopLevelDir(Dir):
def listdir(self):
for item in Dir.listdir(self):
yield item
yield 'svn:log', Log(self.ra, self.rev)
class Log:
def __init__(self, ra, rev):
self.ra = ra
self.rev = rev
def getlogentry(self):
try:
return self.logentry
except AttributeError:
logentries = self.ra.log('', startrev=self.rev, endrev=self.rev)
try:
[self.logentry] = logentries
except ValueError:
self.logentry = None
return self.logentry
def size(self):
return len(self.read())
def read(self):
logentry = self.getlogentry()
if logentry is None:
return 'r%d | (no change here)\n' % (self.rev,)
datetuple = time.gmtime(decode(logentry.date))
date = time.strftime("%c", datetuple)
return 'r%d | %s | %s\n\n%s' % (self.rev,
logentry.author,
date,
logentry.message)
if 0:
pass
##if USE_SYMLINKS:
## def getnode(ra, rev, path, stats):
## committed_rev = stats['svn:entry:committed-rev']
## if committed_rev == rev:
## kind = stats['svn:entry:kind']
## if kind == 'file':
## return File(ra, rev, path, stats['svn:entry:size'])
## elif kind == 'dir':
## return Dir(ra, rev, path)
## else:
## raise IOError(errno.EINVAL, "kind %r" % (kind,))
## else:
## depth = path.count('/')
## return SymLink('../' * depth + '../%d/%s' % (committed_rev, path))
else:
def getnode(ra, rev, path, stats):
last_changed_rev = stats['svn:entry:committed-rev']
kind = stats['svn:entry:kind']
if kind == 'file':
return File(ra, rev, last_changed_rev, path,
stats['svn:entry:size'])
elif kind == 'dir':
return Dir(ra, rev, last_changed_rev, path)
else:
raise IOError(errno.EINVAL, "kind %r" % (kind,))
if __name__ == '__main__':
import sys
svnurl, mountpoint = sys.argv[1:]
handler = Handler(mountpoint, ObjectFs(Root(svnurl)))
handler.loop_forever()