diff options
author | willmcgugan <willmcgugan@67cdc799-7952-0410-af00-57a81ceafa0f> | 2010-12-14 22:21:58 +0000 |
---|---|---|
committer | willmcgugan <willmcgugan@67cdc799-7952-0410-af00-57a81ceafa0f> | 2010-12-14 22:21:58 +0000 |
commit | a143bd9a96c53c7bbdfc3728d33cbf5f75e3c933 (patch) | |
tree | e0be592446916b02b14fd7ba4116b34815d28340 /fs/opener.py | |
parent | a16c90b9e18acc1ad4cef7ad52d005c43cc22df1 (diff) | |
download | pyfilesystem-git-a143bd9a96c53c7bbdfc3728d33cbf5f75e3c933.tar.gz |
Added --listopeners switch to commands
Diffstat (limited to 'fs/opener.py')
-rw-r--r-- | fs/opener.py | 154 |
1 files changed, 104 insertions, 50 deletions
diff --git a/fs/opener.py b/fs/opener.py index 0ff0517..38b1689 100644 --- a/fs/opener.py +++ b/fs/opener.py @@ -9,11 +9,9 @@ from urlparse import urlparse class OpenerError(Exception): pass - class NoOpenerError(OpenerError): pass - class MissingParameterError(OpenerError): pass @@ -32,7 +30,24 @@ def _expand_syspath(path): return path + +def _parse_credentials(url): + username = None + password = None + if '@' in url: + credentials, url = url.split('@', 1) + if ':' in credentials: + username, password = credentials.split(':', 1) + else: + username = credentials + return username, password, url +def _parse_name(fs_name): + if '#' in fs_name: + fs_name, fs_name_params = fs_name.split('#', 1) + return fs_name, fs_name_params + else: + return fs_name, None class OpenerRegistry(object): @@ -79,7 +94,7 @@ class OpenerRegistry(object): for name in opener.names: self.registry[name] = index - def parse(self, fs_url, default_fs_name=None, open_dir=True, writeable=False, create=False): + def parse(self, fs_url, default_fs_name=None, open_dir=True, writeable=False, create_dir=False): orig_url = fs_url match = self.split_segments(fs_url) @@ -103,13 +118,13 @@ class OpenerRegistry(object): fs_url = _expand_syspath(fs_url) path = '' - fs_name, fs_name_params = self.parse_name(fs_name) + fs_name, fs_name_params = _parse_name(fs_name) opener = self.get_opener(fs_name) if fs_url is None: raise OpenerError("Unable to parse '%s'" % orig_url) - fs, fs_path = opener.get_fs(self, fs_name, fs_name_params, fs_url, writeable, create) + fs, fs_path = opener.get_fs(self, fs_name, fs_name_params, fs_url, writeable, create_dir) if fs_path and iswildcard(fs_path): pathname, resourcename = pathsplit(fs_path or '') @@ -125,31 +140,59 @@ class OpenerRegistry(object): fs_path = resourcename return fs, fs_path - - def parse_credentials(self, url): - - username = None - password = None - if '@' in url: - credentials, url = url.split('@', 1) - if ':' in credentials: - username, password = credentials.split(':', 1) - else: - username = credentials - return username, password, url - - def parse_name(self, fs_name): - if '#' in fs_name: - fs_name, fs_name_params = fs_name.split('#', 1) - return fs_name, fs_name_params - else: - return fs_name, None - def open(self, fs_url, mode='r'): + def open(self, fs_url, mode='rb'): + """Opens a file from a given FS url + + If you intend to do a lot of file manipulation, it would likely be more + efficient to do it directly through the an FS instance (from `parse` or + `opendir`). This method is fine for one-offs though. + + :param fs_url: a FS URL, e.g. ftp://ftp.mozilla.org/README + :param mode: mode to open file file + :rtype: a file + + """ + writeable = 'w' in mode or 'a' in mode or '+' in mode - fs, path = self.parse(fs_url, writeable=writeable) + fs, path = self.parse(fs_url, writeable=writeable) file_object = fs.open(path, mode) + + # If we just return the file, the fs goes out of scope and closes, + # which may make the file unusable. To get around this, we store a + # reference in the file object to the FS, and patch the file's + # close method to also close the FS. + close = file_object.close + def replace_close(): + fs.close() + return close() + file_object.close = replace_close + return file_object + + def getcontents(self, fs_url): + """Gets the contents from a given FS url (if it references a file) + + :param fs_url: a FS URL e.g. ftp://ftp.mozilla.org/README + + """ + + fs, path = self.parse(fs_url) + return fs.getcontents(path) + + def opendir(self, fs_url, writeable=True, create_dir=False): + """Opens an FS object from an FS URL + + :param fs_url: an FS URL e.g. ftp://ftp.mozilla.org + :param writeable: set to True (the default) if the FS must be writeable + :param create_dir: create the directory references by the FS URL, if + it doesn't already exist + + """ + fs, path = self.parse(fs_url, writable=writeable, create_dir=create_dir) + if path: + return fs.opendir(path) + return fs class Opener(object): @@ -166,14 +209,15 @@ class Opener(object): class OSFSOpener(Opener): - names = ['osfs', 'file'] + names = ['osfs', 'file'] + desc = "OS filesystem opener, works with any valid system path. This is the default opener and will be used if you don't indicate which opener to use." @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.osfs import OSFS path = _expand_syspath(fs_path) - if create and not os.path.exists(path): + if create_dir and not os.path.exists(path): from fs.osfs import _os_makedirs _os_makedirs(path) dirname, resourcename = pathsplit(fs_path) @@ -181,23 +225,27 @@ class OSFSOpener(Opener): return osfs, resourcename class ZipOpener(Opener): - names = ['zip', 'zip64'] + names = ['zip', 'zip64'] + desc = "Opens zip files. Use zip64 for > 2 megabyte zip files, if you have a 64 bit processor.\ne.g. zip://myzip" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): append_zip = fs_name_params == 'add' zip_fs, zip_path = registry.parse(fs_path) if zip_path is None: raise OpenerError('File required for zip opener') - if writeable: - open_mode = 'r+b' + if zip_fs.exists(zip_path): + if writeable: + open_mode = 'r+b' + else: + open_mode = 'rb' else: - open_mode = 'rb' + open_mode = 'w+' zip_file = zip_fs.open(zip_path, mode=open_mode) - username, password, fs_path = registry.parse_credentials(fs_path) + username, password, fs_path = _parse_credentials(fs_path) from fs.zipfs import ZipFS if zip_file is None: @@ -215,11 +263,12 @@ class ZipOpener(Opener): class RPCOpener(Opener): names = ['rpc'] + desc = "An opener for filesystems server over RPC (see the fsserve command). e.g. rpc://127.0.0.1" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.rpcfs import RPCFS - username, password, fs_path = registry.parse_credentials(fs_path) + username, password, fs_path = _parse_credentials(fs_path) if not fs_path.startswith('http://'): fs_path = 'http://' + fs_path @@ -227,7 +276,7 @@ class RPCOpener(Opener): rpcfs = RPCFS('%s://%s' % (scheme, netloc)) - if create and path: + if create_dir and path: rpcfs.makedir(path, recursive=True, allow_recreate=True) return rpcfs, path or None @@ -235,11 +284,12 @@ class RPCOpener(Opener): class FTPOpener(Opener): names = ['ftp'] + desc = "An opener for FTP (File Transfer Protocl) servers. e.g. ftp://ftp.mozilla.org" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.ftpfs import FTPFS - username, password, fs_path = registry.parse_credentials(fs_path) + username, password, fs_path = _parse_credentials(fs_path) scheme, netloc, path, params, query, fragment = urlparse(fs_path) if not scheme: @@ -252,7 +302,7 @@ class FTPOpener(Opener): ftpfs = FTPFS(url, user=username or '', passwd=password or '') ftpfs.cache_hint(True) - if create and path: + if create_dir and path: ftpfs.makedir(path, recursive=True, allow_recreate=True) if dirpath: @@ -266,10 +316,11 @@ class FTPOpener(Opener): class SFTPOpener(Opener): names = ['sftp'] + desc = "An opener for SFTP (Secure File Transfer Protocol) servers" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): - username, password, fs_path = registry.parse_credentials(fs_path) + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): + username, password, fs_path = _parse_credentials(fs_path) from fs.sftpfs import SFTPFS @@ -298,7 +349,7 @@ class SFTPOpener(Opener): else: host = (addr, port) - if create: + if create_dir: sftpfs = SFTPFS(host, root_path='/', **credentials) if not sftpfs._transport.is_authenticated(): sftpfs.close() @@ -316,24 +367,26 @@ class SFTPOpener(Opener): class MemOpener(Opener): names = ['mem', 'ram'] + desc = """Creates an in-memory filesystem (very fast but contents will disappear on exit).""" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.memoryfs import MemoryFS memfs = MemoryFS() - if create: + if create_dir: memfs = memfs.makeopendir(fs_path) return memfs, None class DebugOpener(Opener): names = ['debug'] + desc = "For developer -- adds debugging information to output. To use prepend an exisiting opener with debug: e.g debug:ftp://ftp.mozilla.org" @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.wrapfs.debugfs import DebugFS if fs_path: - fs, path = registry.parse(fs_path, writeable=writeable, create=create) + fs, path = registry.parse(fs_path, writeable=writeable, create=create_dir) return DebugFS(fs, verbose=False), None if fs_name_params == 'ram': from fs.memoryfs import MemoryFS @@ -345,12 +398,13 @@ class DebugOpener(Opener): class TempOpener(Opener): names = ['temp'] + desc = "Creates a temporary filesystem, that is erased on exit." @classmethod - def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create): + def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir): from fs.tempfs import TempFS fs = TempFS(identifier=fs_name_params) - if create and fs_path: + if create_dir and fs_path: fs = fs.makeopendir(fs_path) fs_path = pathsplit(fs_path) return fs, fs_path |