2 import sys, os, stat, errno, fuse, re, time, tempfile
19 return (ref, date, dir)
22 # FIXME: iterating through a file just to check its size is super slow!
30 def date_to_commit(ref, datestr):
31 dates = dates_for_ref(ref)
32 dates.sort(reverse=True)
34 dp = time.strptime(datestr, '%Y-%m-%d-%H%M%S')
36 dp = time.strptime(datestr, '%Y-%m-%d')
39 for (d,commit) in dates:
46 def dates_for_ref(ref):
47 dates = refdates.get(ref)
49 dates = refdates[ref] = list(git.rev_list(ref))
54 class Stat(fuse.Stat):
72 class BupFs(fuse.Fuse):
73 def getattr(self, path):
74 log('--getattr(%r)\n' % path)
75 sc = statcache.get(path)
78 (ref,date,filename) = namesplit(path)
81 st.st_mode = stat.S_IFDIR | 0755
82 st.st_nlink = 1 # FIXME
85 elif not date or not filename:
91 st.st_mode = stat.S_IFDIR | 0755
92 st.st_nlink = 1 # FIXME
97 commit = date_to_commit(ref, date)
98 (dir,name) = os.path.split(filename)
99 it = cp.get('%s:%s' % (commit.encode('hex'), dir))
102 for (mode,n,sha) in git._treeparse(''.join(it)):
104 st.st_mode = int(mode, 8)
105 st.st_nlink = 1 # FIXME
106 if stat.S_ISDIR(st.st_mode):
109 fileid = '%s:%s' % (commit.encode('hex'), filename)
110 st.st_size = sz(cp.join(fileid))
115 def readdir(self, path, offset):
116 log('--readdir(%r)\n' % path)
117 yield fuse.Direntry('.')
118 yield fuse.Direntry('..')
119 (ref,date,dir) = namesplit(path)
121 for (name,sha) in git.list_refs():
122 name = re.sub('^refs/heads/', '', name)
123 yield fuse.Direntry(name)
125 dates = dates_for_ref(ref)
126 for (date,commit) in dates:
127 l = time.localtime(date)
128 yield fuse.Direntry(time.strftime('%Y-%m-%d-%H%M%S', l))
130 commit = date_to_commit(ref, date)
131 it = cp.get('%s:%s' % (commit.encode('hex'), dir or ''))
134 for (mode,n,sha) in git._treeparse(''.join(it)):
135 yield fuse.Direntry(n)
137 def readlink(self, path):
138 log('--readlink(%r)\n' % path)
139 self.open(path, os.O_RDONLY) # FIXME: never released
140 return self.read(path, 10000, 0)
142 def open(self, path, flags):
143 log('--open(%r)\n' % path)
144 (ref,date,dir) = namesplit(path)
147 commit = date_to_commit(ref, date)
149 it = cp.get('%s:%s' % (commit.encode('hex'), dir or ''))
155 accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
156 if (flags & accmode) != os.O_RDONLY:
159 f = tempfile.TemporaryFile()
165 def release(self, path, flags):
166 log('--release(%r)\n' % path)
169 def read(self, path, size, offset):
170 log('--read(%r)\n' % path)
171 f = filecache.get(path)
178 if not hasattr(fuse, '__version__'):
179 raise RuntimeError, "your fuse module is too old for fuse.__version__"
180 fuse.fuse_python_api = (0, 2)
183 bup fuse [mountpoint]
185 d,debug increase debug level
186 f,foreground run in foreground
188 o = options.Options('bup fuse', optspec)
189 (opt, flags, extra) = o.parse(sys.argv[1:])
192 log("bup fuse: exactly one argument expected\n")
196 f.fuse_args.mountpoint = extra[0]
198 f.fuse_args.add('debug')
200 f.fuse_args.setmod('foreground')
201 f.fuse_args.add('allow_other')
203 git.check_repo_or_die()