I apparently used to have a crappy sense of style. Let's fix that.
[invirt/packages/python-routefs.git] / routefs / __init__.py
index bd7fa7b..294ec93 100644 (file)
@@ -5,19 +5,19 @@ lets you focus on the directory tree instead of the system calls.
 RouteFS uses the Routes library developed for Pylons. URLs were
 inspired by filesystems, and now you can have filesystems inspired by
 URLs.
 RouteFS uses the Routes library developed for Pylons. URLs were
 inspired by filesystems, and now you can have filesystems inspired by
 URLs.
-
-When developing a descendent of RouteFS, any methods defined in that
-class are considered "controllers", and receive any other parameters
-specified by the URL as keyword arguments.
 """
 
 """
 
-import fuse
-import routes
+
 import errno
 import stat
 
 import errno
 import stat
 
+import fuse
+import routes
+
+
 fuse.fuse_python_api = (0, 2)
 
 fuse.fuse_python_api = (0, 2)
 
+
 class RouteStat(fuse.Stat):
     """
     RouteStat is a descendent of fuse.Stat, defined to make sure that
 class RouteStat(fuse.Stat):
     """
     RouteStat is a descendent of fuse.Stat, defined to make sure that
@@ -35,48 +35,33 @@ class RouteStat(fuse.Stat):
         self.st_mtime = 0
         self.st_ctime = 0
 
         self.st_mtime = 0
         self.st_ctime = 0
 
-class RouteMeta(type):
-    """
-    Metaclass to calculate controller methods
-    
-    Routes needs to be pre-seeded with a list of "controllers". For
-    all descendents of RouteFS, the list of controllers is defined to
-    be any non-private methods of the class that were not in the
-    RouteFS class.
-    """
-    def __init__(cls, classname, bases, dict_):
-        super(RouteMeta, cls).__init__(classname, bases, dict_)
-        if bases != (fuse.Fuse,):
-            new_funcs = set(dict_.keys()).difference(dir(RouteFS))
-            cls.controllers([func for func in new_funcs \
-                                 if not func.startswith('_')])
 
 class RouteFS(fuse.Fuse):
     """
     RouteFS: Web 2.0 for filesystems
 
 class RouteFS(fuse.Fuse):
     """
     RouteFS: Web 2.0 for filesystems
+
+    Any method that will be used as the controller in a Routes mapping
+    (either by explicitly specifying the controller or by using the
+    ':controller' variable) must be added to RouteFS.controllers
     """
     """
-    __metaclass__ = RouteMeta
+    controllers = []
     def __init__(self, *args, **kwargs):
         super(RouteFS, self).__init__(*args, **kwargs)
     def __init__(self, *args, **kwargs):
         super(RouteFS, self).__init__(*args, **kwargs)
-        
+
         self.map = self.make_map()
         self.map = self.make_map()
-        self.map.create_regs(self.controller_list)
-        
+        self.map.create_regs(self.controllers)
+
     def make_map(self):
         """
         This method should be overridden by descendents of RouteFS to
         define the routing for the filesystem
         """
         m = routes.Mapper()
     def make_map(self):
         """
         This method should be overridden by descendents of RouteFS to
         define the routing for the filesystem
         """
         m = routes.Mapper()
-        
+
         m.connect(':controller')
         m.connect(':controller')
-        
+
         return m
         return m
-    
-    @classmethod
-    def controllers(cls, lst):
-        cls.controller_list = lst
-    
+
     def _get_file(self, path):
         """
         Find the filesystem entry object for a given path
     def _get_file(self, path):
         """
         Find the filesystem entry object for a given path
@@ -86,79 +71,92 @@ class RouteFS(fuse.Fuse):
             return NoEntry()
         controller = match.pop('controller')
         result = getattr(self, controller)(**match)
             return NoEntry()
         controller = match.pop('controller')
         result = getattr(self, controller)(**match)
+        if result is None:
+            return NoEntry()
         if type(result) is str:
             result = File(result)
         if type(result) is list:
             result = Directory(result)
         return result
         if type(result) is str:
             result = File(result)
         if type(result) is list:
             result = Directory(result)
         return result
-    
+
     def readdir(self, path, offset):
         """
         If the path referred to is a directory, return the elements of
         that diectory
         """
         return self._get_file(path).readdir(offset)
     def readdir(self, path, offset):
         """
         If the path referred to is a directory, return the elements of
         that diectory
         """
         return self._get_file(path).readdir(offset)
-    
+
     def getattr(self, path):
         """
         Return the stat information for a path
     def getattr(self, path):
         """
         Return the stat information for a path
-        
+
         The stat information for a directory, symlink, or file is
         predetermined based on which it is.
         """
         return self._get_file(path).getattr()
         The stat information for a directory, symlink, or file is
         predetermined based on which it is.
         """
         return self._get_file(path).getattr()
-    
+
     def read(self, path, length, offset):
         """
         If the path specified is a file, return the requested portion
         of the file
         """
     def read(self, path, length, offset):
         """
         If the path specified is a file, return the requested portion
         of the file
         """
-        obj = self._get_file(path)
-        if type(obj) is NoEntry:
-            return -errno.ENOENT
-        elif type(obj) in (Directory, Symlink):
-            return -errno.EINVAL
-        else:
-            return obj[offset:offset + length]
-    
+        return self._get_file(path).read(length, offset)
+
     def readlink(self, path):
         """
         If the path specified is a symlink, return the target
         """
     def readlink(self, path):
         """
         If the path specified is a symlink, return the target
         """
-        obj = self._get_file(path)
-        if obj is None:
-            return -errno.ENOENT
-        elif type(obj) is not Symlink:
-            return -errno.EINVAL
-        else:
-            return obj
+        return self._get_file(path).readlink()
+
+    def write(self, path, buf, offset):
+        """
+        If the path specified is a file, call the appropriate member 
+        on the file
+        """
+        return self._get_file(path).write(buf, offset)
+
 
 class TreeKey(object):
     def getattr(self):
         return -errno.EINVAL
     def readdir(self, offset):
         return -errno.EINVAL
 
 class TreeKey(object):
     def getattr(self):
         return -errno.EINVAL
     def readdir(self, offset):
         return -errno.EINVAL
+    def read(self, length, offset):
+        return -errno.EINVAL
+    def readlink(self):
+        return -errno.EINVAL
+    def write(self, length, offset):
+        return -errno.EINVAL
+
 
 class NoEntry(TreeKey):
     def getattr(self):
         return -errno.ENOENT
     def readdir(self, offset):
         return -errno.ENOENT
 
 class NoEntry(TreeKey):
     def getattr(self):
         return -errno.ENOENT
     def readdir(self, offset):
         return -errno.ENOENT
+    def read(self, length, offset):
+        return -errno.ENOENT
+    def readlink(self):
+        return -errno.ENOENT
+    def write(self, length, offset):
+        return -errno.ENOENT
+
 
 class TreeEntry(TreeKey):
     default_mode = 0444
 
 class TreeEntry(TreeKey):
     default_mode = 0444
-    
+
     def __new__(cls, contents, mode=None):
         return super(TreeEntry, cls).__new__(cls, contents)
     def __new__(cls, contents, mode=None):
         return super(TreeEntry, cls).__new__(cls, contents)
-    
+
     def __init__(self, contents, mode=None):
         if mode is None:
             self.mode = self.default_mode
         else:
             self.mode = mode
     def __init__(self, contents, mode=None):
         if mode is None:
             self.mode = self.default_mode
         else:
             self.mode = mode
-        
+
         super(TreeEntry, self).__init__(contents)
 
         super(TreeEntry, self).__init__(contents)
 
+
 class Directory(TreeEntry, list):
     """
     A dummy class representing a filesystem entry that should be a
 class Directory(TreeEntry, list):
     """
     A dummy class representing a filesystem entry that should be a
@@ -176,6 +174,7 @@ class Directory(TreeEntry, list):
         for member in ['.', '..'] + self:
             yield fuse.Direntry(str(member))
 
         for member in ['.', '..'] + self:
             yield fuse.Direntry(str(member))
 
+
 class Symlink(TreeEntry, str):
     """
     A dummy class representing something that should be a symlink
 class Symlink(TreeEntry, str):
     """
     A dummy class representing something that should be a symlink
@@ -189,6 +188,10 @@ class Symlink(TreeEntry, str):
         st.st_size = len(self)
         return st
 
         st.st_size = len(self)
         return st
 
+    def readlink(self):
+        return self
+
+
 class File(TreeEntry, str):
     """
     A dummy class representing something that should be a file
 class File(TreeEntry, str):
     """
     A dummy class representing something that should be a file
@@ -202,6 +205,10 @@ class File(TreeEntry, str):
         st.st_size = len(self)
         return st
 
         st.st_size = len(self)
         return st
 
+    def read(self, length, offset):
+        return self[offset:offset + length]
+
+
 def main(cls):
     """
     A convenience function for initializing a RouteFS filesystem
 def main(cls):
     """
     A convenience function for initializing a RouteFS filesystem
@@ -212,6 +219,7 @@ def main(cls):
     server.parse(values=server, errex=1)
     server.main()
 
     server.parse(values=server, errex=1)
     server.main()
 
+
 from dictfs import DictFS
 
 __all__ = ['RouteFS', 'DictFS', 'Symlink', 'Directory', 'File', 'main']
 from dictfs import DictFS
 
 __all__ = ['RouteFS', 'DictFS', 'Symlink', 'Directory', 'File', 'main']