Skip to content
Browse files

cmd-fuse: use the new vfs layer.

  • Loading branch information...
1 parent 3a01f09 commit 598a939946ae1f30c941252347fbfa085ea186d3 @apenwarr apenwarr committed Feb 14, 2010
Showing with 51 additions and 133 deletions.
  1. +51 −133 cmd-fuse.py
View
184 cmd-fuse.py
@@ -1,56 +1,9 @@
#!/usr/bin/env python
import sys, os, stat, errno, fuse, re, time, tempfile
-import options, git
+import options, git, vfs
from helpers import *
-def namesplit(path):
- l = path.split('/', 3)
- ref = None
- date = None
- dir = None
- assert(l[0] == '')
- if len(l) > 1:
- ref = l[1] or None
- if len(l) > 2:
- date = l[2]
- if len(l) > 3:
- dir = l[3]
- return (ref, date, dir)
-
-
-# FIXME: iterating through a file just to check its size is super slow!
-def sz(it):
- count = 0
- for d in it:
- count += len(d)
- return count
-
-
-def date_to_commit(ref, datestr):
- dates = dates_for_ref(ref)
- dates.sort(reverse=True)
- try:
- dp = time.strptime(datestr, '%Y-%m-%d-%H%M%S')
- except ValueError:
- dp = time.strptime(datestr, '%Y-%m-%d')
- dt = time.mktime(dp)
- commit = None
- for (d,commit) in dates:
- if d <= dt: break
- assert(commit)
- return commit
-
-
-refdates = {}
-def dates_for_ref(ref):
- dates = refdates.get(ref)
- if not dates:
- dates = refdates[ref] = list(git.rev_list(ref))
- dates.sort()
- return dates
-
-
class Stat(fuse.Stat):
def __init__(self):
self.st_mode = 0
@@ -65,120 +18,83 @@ def __init__(self):
self.st_ctime = 0
-statcache = {}
-filecache = {}
-
+cache = {}
+def cache_get(top, path):
+ parts = path.split('/')
+ cache[('',)] = top
+ c = None
+ max = len(parts)
+ #log('cache: %r\n' % cache.keys())
+ for i in range(max):
+ pre = parts[:max-i]
+ #log('cache trying: %r\n' % pre)
+ c = cache.get(tuple(pre))
+ if c:
+ rest = parts[max-i:]
+ for r in rest:
+ #log('resolving %r from %r\n' % (r, c.fullname()))
+ c = c.lresolve(r)
+ key = tuple(pre + [r])
+ #log('saving: %r\n' % (key,))
+ cache[key] = c
+ break
+ assert(c)
+ return c
+
+
class BupFs(fuse.Fuse):
+ def __init__(self, top):
+ fuse.Fuse.__init__(self)
+ self.top = top
+
def getattr(self, path):
log('--getattr(%r)\n' % path)
- sc = statcache.get(path)
- if sc:
- return sc
- (ref,date,filename) = namesplit(path)
- if not ref:
- st = Stat()
- st.st_mode = stat.S_IFDIR | 0755
- st.st_nlink = 1 # FIXME
- statcache[path] = st
- return st
- elif not date or not filename:
+ try:
+ node = cache_get(self.top, path)
st = Stat()
- try:
- git.read_ref(ref)
- except git.GitError:
- pass
- st.st_mode = stat.S_IFDIR | 0755
- st.st_nlink = 1 # FIXME
- statcache[path] = st
+ st.st_mode = node.mode
+ st.st_nlink = node.nlinks()
+ st.st_size = node.size()
return st
- else:
- st = Stat()
- commit = date_to_commit(ref, date)
- (dir,name) = os.path.split(filename)
- it = cp.get('%s:%s' % (commit.encode('hex'), dir))
- type = it.next()
- if type == 'tree':
- for (mode,n,sha) in git._treeparse(''.join(it)):
- if n == name:
- st.st_mode = int(mode, 8)
- st.st_nlink = 1 # FIXME
- if stat.S_ISDIR(st.st_mode):
- st.st_size = 1024
- else:
- fileid = '%s:%s' % (commit.encode('hex'), filename)
- st.st_size = sz(cp.join(fileid))
- statcache[path] = st
- return st
- return -errno.ENOENT
+ except vfs.NoSuchFile:
+ return -errno.ENOENT
def readdir(self, path, offset):
log('--readdir(%r)\n' % path)
+ node = cache_get(self.top, path)
yield fuse.Direntry('.')
yield fuse.Direntry('..')
- (ref,date,dir) = namesplit(path)
- if not ref:
- for (name,sha) in git.list_refs():
- name = re.sub('^refs/heads/', '', name)
- yield fuse.Direntry(name)
- elif not date:
- dates = dates_for_ref(ref)
- for (date,commit) in dates:
- l = time.localtime(date)
- yield fuse.Direntry(time.strftime('%Y-%m-%d-%H%M%S', l))
- else:
- commit = date_to_commit(ref, date)
- it = cp.get('%s:%s' % (commit.encode('hex'), dir or ''))
- type = it.next()
- if type == 'tree':
- for (mode,n,sha) in git._treeparse(''.join(it)):
- yield fuse.Direntry(n)
+ for sub in node.subs():
+ yield fuse.Direntry(sub.name)
def readlink(self, path):
log('--readlink(%r)\n' % path)
- self.open(path, os.O_RDONLY) # FIXME: never released
- return self.read(path, 10000, 0)
+ node = cache_get(self.top, path)
+ return node.readlink()
def open(self, path, flags):
log('--open(%r)\n' % path)
- (ref,date,dir) = namesplit(path)
- if not dir:
- return -errno.ENOENT
- commit = date_to_commit(ref, date)
- try:
- it = cp.get('%s:%s' % (commit.encode('hex'), dir or ''))
- except KeyError:
- return -errno.ENOENT
- type = it.next()
- if type != 'blob':
- return -errno.EINVAL
+ node = cache_get(self.top, path)
accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
if (flags & accmode) != os.O_RDONLY:
return -errno.EACCES
-
- f = tempfile.TemporaryFile()
- for blob in it:
- f.write(blob)
- f.flush()
- filecache[path] = f
+ node.open()
def release(self, path, flags):
log('--release(%r)\n' % path)
- del filecache[path]
def read(self, path, size, offset):
log('--read(%r)\n' % path)
- f = filecache.get(path)
- if not f:
- return -errno.ENOENT
- f.seek(offset)
- return f.read(size)
+ n = cache_get(self.top, path)
+ return n.readbytes(offset, size)
if not hasattr(fuse, '__version__'):
raise RuntimeError, "your fuse module is too old for fuse.__version__"
fuse.fuse_python_api = (0, 2)
+
optspec = """
bup fuse [-d] [-f] <mountpoint>
--
@@ -192,14 +108,16 @@ def read(self, path, size, offset):
log("bup fuse: exactly one argument expected\n")
o.usage()
-f = BupFs()
+git.check_repo_or_die()
+top = vfs.RefList(None)
+f = BupFs(top)
f.fuse_args.mountpoint = extra[0]
if opt.debug:
f.fuse_args.add('debug')
if opt.foreground:
f.fuse_args.setmod('foreground')
+print f.multithreaded
+f.multithreaded = False
f.fuse_args.add('allow_other')
-git.check_repo_or_die()
-cp = git.CatPipe()
f.main()

0 comments on commit 598a939

Please sign in to comment.
Something went wrong with that request. Please try again.