2 RouteFS is a base class for developing read-only FUSE filesystems that
3 lets you focus on the directory tree instead of the system calls.
5 RouteFS uses the Routes library developed for Pylons. URLs were
6 inspired by filesystems, and now you can have filesystems inspired by
9 When developing a descendent of RouteFS, any methods defined in that
10 class are considered "controllers", and receive any other parameters
11 specified by the URL as keyword arguments.
19 fuse.fuse_python_api = (0, 2)
21 class RouteStat(fuse.Stat):
23 RouteStat is a descendent of fuse.Stat, defined to make sure that
24 all of the necessary attributes are always defined
38 class RouteMeta(type):
40 Metaclass to calculate controller methods
42 Routes needs to be pre-seeded with a list of "controllers". For
43 all descendents of RouteFS, the list of controllers is defined to
44 be any non-private methods of the class that were not in the
47 def __init__(cls, classname, bases, dict_):
48 super(RouteMeta, cls).__init__(classname, bases, dict_)
49 if bases != (fuse.Fuse,):
50 new_funcs = set(dict_.keys()).difference(dir(RouteFS))
51 cls.controllers([func for func in new_funcs \
52 if not func.startswith('_')])
54 class RouteFS(fuse.Fuse):
56 RouteFS: Web 2.0 for filesystems
58 __metaclass__ = RouteMeta
59 def __init__(self, *args, **kwargs):
60 super(RouteFS, self).__init__(*args, **kwargs)
62 self.map = self.make_map()
63 self.map.create_regs(self.controller_list)
67 This method should be overridden by descendents of RouteFS to
68 define the routing for the filesystem
72 m.connect(':controller')
77 def controllers(cls, lst):
78 cls.controller_list = lst
80 def _get_file(self, path):
82 Find the filesystem entry object for a given path
84 match = self.map.match(path)
87 controller = match.pop('controller')
88 result = getattr(self, controller)(**match)
91 if type(result) is str:
93 if type(result) is list:
94 result = Directory(result)
97 def readdir(self, path, offset):
99 If the path referred to is a directory, return the elements of
102 return self._get_file(path).readdir(offset)
104 def getattr(self, path):
106 Return the stat information for a path
108 The stat information for a directory, symlink, or file is
109 predetermined based on which it is.
111 return self._get_file(path).getattr()
113 def read(self, path, length, offset):
115 If the path specified is a file, return the requested portion
118 return self._get_file(path).read(length, offset)
120 def readlink(self, path):
122 If the path specified is a symlink, return the target
124 return self._get_file(path).readlink()
126 class TreeKey(object):
129 def readdir(self, offset):
131 def read(self, length, offset):
136 class NoEntry(TreeKey):
139 def readdir(self, offset):
141 def read(self, length, offset):
146 class TreeEntry(TreeKey):
149 def __new__(cls, contents, mode=None):
150 return super(TreeEntry, cls).__new__(cls, contents)
152 def __init__(self, contents, mode=None):
154 self.mode = self.default_mode
158 super(TreeEntry, self).__init__(contents)
160 class Directory(TreeEntry, list):
162 A dummy class representing a filesystem entry that should be a
169 st.st_mode = stat.S_IFDIR | self.mode
173 def readdir(self, offset):
174 for member in ['.', '..'] + self:
175 yield fuse.Direntry(str(member))
177 class Symlink(TreeEntry, str):
179 A dummy class representing something that should be a symlink
185 st.st_mode = stat.S_IFLNK | self.mode
187 st.st_size = len(self)
193 class File(TreeEntry, str):
195 A dummy class representing something that should be a file
201 st.st_mode = stat.S_IFREG | self.mode
203 st.st_size = len(self)
206 def read(self, length, offset):
207 return self[offset:offset + length]
211 A convenience function for initializing a RouteFS filesystem
213 server = cls(version="%prog " + fuse.__version__,
214 usage=fuse.Fuse.fusage,
215 dash_s_do='setsingle')
216 server.parse(values=server, errex=1)
219 from dictfs import DictFS
221 __all__ = ['RouteFS', 'DictFS', 'Symlink', 'Directory', 'File', 'main']