mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-26 16:11:08 +00:00
182 lines
5.0 KiB
Python
182 lines
5.0 KiB
Python
|
from kernel import *
|
||
|
import errno, posixpath, weakref
|
||
|
from time import time as now
|
||
|
from stat import S_IFDIR, S_IFREG, S_IFMT
|
||
|
from cStringIO import StringIO
|
||
|
from handler import Handler
|
||
|
from pathfs import PathFs
|
||
|
from pysvn.ra_filesystem import SvnRepositoryFilesystem
|
||
|
import pysvn.date
|
||
|
|
||
|
|
||
|
class SvnFS(PathFs):
|
||
|
|
||
|
def __init__(self, svnurl, root=''):
|
||
|
super(SvnFS, self).__init__(root)
|
||
|
self.svnurl = svnurl
|
||
|
self.openfiles = weakref.WeakValueDictionary()
|
||
|
self.creationtimes = {}
|
||
|
self.do_open()
|
||
|
|
||
|
def do_open(self, rev='HEAD'):
|
||
|
self.fs = SvnRepositoryFilesystem(svnurl, rev)
|
||
|
|
||
|
def do_commit(self, msg):
|
||
|
rev = self.fs.commit(msg)
|
||
|
if rev is None:
|
||
|
print '* no changes.'
|
||
|
else:
|
||
|
print '* checked in revision %d.' % (rev,)
|
||
|
self.do_open()
|
||
|
|
||
|
def do_status(self, path=''):
|
||
|
print '* status'
|
||
|
result = []
|
||
|
if path and not path.endswith('/'):
|
||
|
path += '/'
|
||
|
for delta in self.fs._compute_deltas():
|
||
|
if delta.path.startswith(path):
|
||
|
if delta.oldrev is None:
|
||
|
c = 'A'
|
||
|
elif delta.newrev is None:
|
||
|
c = 'D'
|
||
|
else:
|
||
|
c = 'M'
|
||
|
result.append(' %s %s\n' % (c, delta.path[len(path):]))
|
||
|
return ''.join(result)
|
||
|
|
||
|
def getattr(self, path):
|
||
|
stat = self.fs.stat(path)
|
||
|
if stat['svn:entry:kind'] == 'dir':
|
||
|
s = S_IFDIR
|
||
|
mode = 0777
|
||
|
else:
|
||
|
s = S_IFREG
|
||
|
mode = 0666
|
||
|
try:
|
||
|
time = pysvn.date.decode(stat['svn:entry:committed-date'])
|
||
|
except KeyError:
|
||
|
try:
|
||
|
time = self.creationtimes[path]
|
||
|
except KeyError:
|
||
|
time = self.creationtimes[path] = now()
|
||
|
return self.mkattr(path,
|
||
|
size = stat.get('svn:entry:size', 0),
|
||
|
st_kind = s,
|
||
|
mode = mode,
|
||
|
time = time)
|
||
|
|
||
|
def setattr(self, path, mode, uid, gid, size, atime, mtime):
|
||
|
if size is not None:
|
||
|
data = self.fs.read(path)
|
||
|
if size < len(data):
|
||
|
self.fs.write(path, data[:size])
|
||
|
elif size > len(data):
|
||
|
self.fs.write(path, data + '\x00' * (size - len(data)))
|
||
|
|
||
|
def listdir(self, path):
|
||
|
for name in self.fs.listdir(path):
|
||
|
kind = self.fs.check_path(posixpath.join(path, name))
|
||
|
if kind == 'dir':
|
||
|
yield name, TYPE_DIR
|
||
|
else:
|
||
|
yield name, TYPE_REG
|
||
|
|
||
|
def check_path(self, path):
|
||
|
kind = self.fs.check_path(path)
|
||
|
return kind is not None
|
||
|
|
||
|
def open(self, path, mode):
|
||
|
try:
|
||
|
of = self.openfiles[path]
|
||
|
except KeyError:
|
||
|
of = self.openfiles[path] = OpenFile(self.fs.read(path))
|
||
|
return of, FOPEN_KEEP_CACHE
|
||
|
|
||
|
def modified(self, path):
|
||
|
try:
|
||
|
of = self.openfiles[path]
|
||
|
except KeyError:
|
||
|
pass
|
||
|
else:
|
||
|
self.fs.write(path, of.f.getvalue())
|
||
|
|
||
|
def mknod_path(self, path, mode):
|
||
|
self.fs.add(path)
|
||
|
|
||
|
def mkdir_path(self, path, mode):
|
||
|
self.fs.mkdir(path)
|
||
|
|
||
|
def unlink_path(self, path):
|
||
|
self.fs.unlink(path)
|
||
|
|
||
|
def rmdir_path(self, path):
|
||
|
self.fs.rmdir(path)
|
||
|
|
||
|
def rename_path(self, oldpath, newpath):
|
||
|
kind = self.fs.check_path(oldpath)
|
||
|
if kind is None:
|
||
|
return False
|
||
|
self.fs.move(oldpath, newpath, kind)
|
||
|
return True
|
||
|
|
||
|
def getxattrs(self, path):
|
||
|
return XAttrs(self, path)
|
||
|
|
||
|
|
||
|
class OpenFile:
|
||
|
def __init__(self, data=''):
|
||
|
self.f = StringIO()
|
||
|
self.f.write(data)
|
||
|
self.f.seek(0)
|
||
|
|
||
|
def seek(self, pos):
|
||
|
self.f.seek(pos)
|
||
|
|
||
|
def read(self, sz):
|
||
|
return self.f.read(sz)
|
||
|
|
||
|
def write(self, buf):
|
||
|
self.f.write(buf)
|
||
|
|
||
|
|
||
|
class XAttrs:
|
||
|
def __init__(self, svnfs, path):
|
||
|
self.svnfs = svnfs
|
||
|
self.path = path
|
||
|
|
||
|
def keys(self):
|
||
|
return []
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
if key == 'status':
|
||
|
return self.svnfs.do_status(self.path)
|
||
|
raise KeyError(key)
|
||
|
|
||
|
def __setitem__(self, key, value):
|
||
|
if key == 'commit' and self.path == '':
|
||
|
self.svnfs.do_commit(value)
|
||
|
elif key == 'update' and self.path == '':
|
||
|
if self.svnfs.fs.modified():
|
||
|
raise IOError(errno.EPERM, "there are local changes")
|
||
|
if value == '':
|
||
|
rev = 'HEAD'
|
||
|
else:
|
||
|
try:
|
||
|
rev = int(value)
|
||
|
except ValueError:
|
||
|
raise IOError(errno.EPERM, "invalid revision number")
|
||
|
self.svnfs.do_open(rev)
|
||
|
else:
|
||
|
raise KeyError(key)
|
||
|
|
||
|
def __delitem__(self, key):
|
||
|
raise KeyError(key)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
import sys
|
||
|
svnurl, mountpoint = sys.argv[1:]
|
||
|
handler = Handler(mountpoint, SvnFS(svnurl))
|
||
|
handler.loop_forever()
|