diff options
author | Christopher Allan Webber <cwebber@dustycloud.org> | 2011-08-08 22:27:51 -0500 |
---|---|---|
committer | Christopher Allan Webber <cwebber@dustycloud.org> | 2011-08-08 22:27:51 -0500 |
commit | df236d15c18687986786f09f33fedddfb63d5d13 (patch) | |
tree | 683c62cdc8371d786f7f718c1054b5726862f8fb | |
parent | 956ba354c9c79384250e85ad4d9f16900503921b (diff) | |
parent | 1bcf30faa9af876d1a2ccd442d7a96d39582d0f9 (diff) | |
download | mediagoblin-df236d15c18687986786f09f33fedddfb63d5d13.tar.lz mediagoblin-df236d15c18687986786f09f33fedddfb63d5d13.tar.xz mediagoblin-df236d15c18687986786f09f33fedddfb63d5d13.zip |
Merge branch 'master' of gitorious.org:mediagoblin/mediagoblin
-rw-r--r-- | mediagoblin/storage.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index e449eda3..88c748ce 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -286,6 +286,132 @@ class CloudFilesStorage(StorageInterface): return self.get_file(filepath).public_uri() +class MountStorage(StorageInterface): + """ + Experimental "Mount" virtual Storage Interface + + This isn't an interface to some real storage, instead + it's a redirecting interface, that redirects requests + to other "StorageInterface"s. + For example, requests for ["store1", "a"] to first + storage with the path ["a"], etc. + + To set this up, you currently need to call the mount() + method with the target path and a backend, that shall + be available under that target path. + You have to mount things in a sensible order, + especially you can't mount ["a", "b"] before ["a"]. + """ + def __init__(self, **kwargs): + self.mounttab = {} + + def mount(self, dirpath, backend): + """ + Mount a new backend under dirpath + """ + new_ent = clean_listy_filepath(dirpath) + + print "Mounting:", repr(new_ent) + already, rem_1, table, rem_2 = self._resolve_to_backend(new_ent, True) + print "===", repr(already), repr(rem_1), repr(rem_2), len(table) + + assert (len(rem_2) > 0) or (None not in table), \ + "That path is already mounted" + assert (len(rem_2) > 0) or (len(table)==0), \ + "A longer path is already mounted here" + + for part in rem_2: + table[part] = {} + table = table[part] + table[None] = backend + + def _resolve_to_backend(self, filepath, extra_info = False): + """ + extra_info = True is for internal use! + + Normally, returns the backend and the filepath inside that backend. + + With extra_info = True it returns the last directory node and the + remaining filepath from there in addition. + """ + table = self.mounttab + filepath = filepath[:] + res_fp = None + while True: + new_be = table.get(None) + if (new_be is not None) or res_fp is None: + res_be = new_be + res_fp = filepath[:] + res_extra = (table, filepath[:]) + # print "... New res: %r, %r, %r" % (res_be, res_fp, res_extra) + if len(filepath) == 0: + break + query = filepath.pop(0) + entry = table.get(query) + if entry is not None: + table = entry + res_extra = (table, filepath[:]) + else: + break + if extra_info: + return (res_be, res_fp) + res_extra + else: + return (res_be, res_fp) + + def resolve_to_backend(self, filepath): + backend, filepath = self._resolve_to_backend(filepath) + if backend is None: + raise Error("Path not mounted") + return backend, filepath + + def __repr__(self, table = None, indent = []): + res = [] + if table is None: + res.append("MountStorage<") + table = self.mounttab + v = table.get(None) + if v: + res.append(" " * len(indent) + repr(indent) + ": " + repr(v)) + for k, v in table.iteritems(): + if k == None: + continue + res.append(" " * len(indent) + repr(k) + ":") + res += self.__repr__(v, indent + [k]) + if table is self.mounttab: + res.append(">") + return "\n".join(res) + else: + return res + + def file_exists(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_exists(filepath) + + def get_file(self, filepath, mode='r'): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_file(filepath, mode) + + def delete_file(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.delete_file(filepath) + + def file_url(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_url(filepath) + + def get_local_path(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_local_path(filepath) + + def copy_locally(self, filepath, dest_path): + """ + Need to override copy_locally, because the local_storage + attribute is not correct. + """ + backend, filepath = self.resolve_to_backend(filepath) + backend.copy_locally(filepath, dest_path) + + ########### # Utilities ########### |