| | |
| | from __future__ import with_statement |
| | import logging |
| | from contextlib import contextmanager |
| |
|
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| |
|
| | def open_storage(path, mode='r', default_storage_factory=None): |
| | import os.path |
| | import zipfile |
| | import fs |
| | import _zipfile |
| | if os.path.exists(path): |
| | if os.path.isdir(path): |
| | return fs.FileSystemStorage(path) |
| | elif zipfile.is_zipfile(path): |
| | return _zipfile.ZipFileStorage(path, mode) |
| | raise IOError('%s: unsupported storage' % path) |
| | elif callable(default_storage_factory): |
| | return default_storage_factory(path, mode) |
| | else: |
| | raise IOError('%s: cannot open' % path) |
| |
|
| |
|
| | def resolve_path(folder, path): |
| | ''' resolve path in a folder |
| | |
| | :param folder: a folder (should have ``__getitem__``) |
| | :param path: path to resolve |
| | :returns: a node or None |
| | ''' |
| | if path in ('', '/'): |
| | return folder |
| |
|
| | import os |
| | path_segments = path.split(os.sep) |
| | assert len(path_segments) > 0 |
| |
|
| | for seg in path_segments: |
| | if not hasattr(folder, '__getitem__'): |
| | return None |
| | try: |
| | node = folder[seg] |
| | except KeyError: |
| | return None |
| | else: |
| | folder = node |
| |
|
| | return node |
| |
|
| |
|
| | def makedirs(folder, path): |
| | from path import split as path_split |
| | path_segments = path_split(path) |
| | for seg in path_segments: |
| | if seg in folder: |
| | folder = folder[seg] |
| | else: |
| | folder = folder.folder(seg) |
| | return folder |
| |
|
| |
|
| | def makedirs_to_file(folder, path): |
| | import os.path |
| | dirname, name = os.path.split(path) |
| | if name == '': |
| | msg = '%s: invalid path' % path |
| | raise ValueError(msg) |
| | folder = makedirs(folder, dirname) |
| | return folder.file(name) |
| |
|
| |
|
| | def put_file(node, path, **kwargs): |
| | if hasattr(node, 'put'): |
| | node.put(path, **kwargs) |
| | elif hasattr(node, 'open'): |
| | with file(path, 'rb') as f: |
| | with node.open('w') as g: |
| | stream_copy(f, g) |
| | else: |
| | raise IOError('node supports neither put nor open') |
| |
|
| |
|
| | def get_file(node, path): |
| | if hasattr(node, 'get'): |
| | node.get(path) |
| | elif hasattr(node, 'open'): |
| | with node.open() as f: |
| | with file(path, 'wb') as g: |
| | stream_copy(f, g) |
| | else: |
| | raise IOError('node supports neither get nor open') |
| |
|
| |
|
| | @contextmanager |
| | def openable_path_on_filesystem(node, writeback=False): |
| | if hasattr(node, 'path_on_filesystem'): |
| | with node.path_on_filesystem() as path: |
| | yield path |
| | else: |
| | import os |
| | from tempfile import mkstemp |
| | fd, path = mkstemp() |
| | try: |
| | with node.open() as f: |
| | with os.fdopen(fd, 'w+') as g: |
| | fd = None |
| | stream_copy(f, g) |
| | |
| | yield path |
| |
|
| | if writeback: |
| | put_file(node, path) |
| | finally: |
| | if fd is not None: |
| | os.close(fd) |
| | os.unlink(path) |
| |
|
| |
|
| | def copy_file(src_node, dst_node): |
| | if (hasattr(dst_node, 'path_on_filesystem') and |
| | hasattr(src_node, 'get')): |
| | with openable_path_on_filesystem(dst_node, writeback=True) as dst_path: |
| | get_file(src_node, dst_path) |
| | with openable_path_on_filesystem(src_node) as src_path: |
| | put_file(dst_node, src_path) |
| |
|
| |
|
| | def stream_copy(src, dst): |
| | while True: |
| | data = src.read(4096) |
| | if len(data) == 0: |
| | return |
| | dst.write(data) |
| |
|
| |
|
| | def iterate_nodes_recursively(folder, folder_path=''): |
| | import os.path |
| | for name in folder: |
| | node = folder[name] |
| | node_path = os.path.join(folder_path, name) |
| | yield node_path, node |
| | if hasattr(node, '__iter__') and hasattr(node, '__getitem__'): |
| | for x in iterate_nodes_recursively(node, node_path): |
| | yield x |
| |
|
| |
|
| | def iterate_files_recursively(folder, folder_path=''): |
| | for path, node in iterate_nodes_recursively(folder, folder_path): |
| | if hasattr(node, 'open'): |
| | yield path, node |
| |
|
| |
|
| | def ls_main(): |
| | doc = '''Usage: storage-ls [options] <storage> |
| | |
| | --help Show this screen. |
| | ''' |
| |
|
| | from docopt import docopt |
| | args = docopt(doc) |
| |
|
| | root_path = args['<storage>'] or '.' |
| | with open_storage(root_path, 'r') as stg: |
| | for path, node in iterate_files_recursively(stg): |
| | print path |
| |
|
| |
|
| | def put_main(): |
| | doc = '''Usage: storage-put [options] <storage> <path> <file> |
| | |
| | --help Show this screen. |
| | ''' |
| |
|
| | from docopt import docopt |
| | args = docopt(doc) |
| |
|
| | import os.path |
| | root_path = args['<storage>'] or '.' |
| | with open_storage(root_path, 'a') as stg: |
| | path = args['<path>'] |
| | file_path = args['<file>'] |
| |
|
| | if os.path.exists(file_path): |
| | node = makedirs_to_file(stg, path) |
| | put_file(node, file_path) |
| | else: |
| | logger.error('%s: not found', file_path) |
| | raise SystemExit(1) |
| |
|
| |
|
| | def get_main(): |
| | doc = '''Usage: storage-get [options] <storage> <path> <file> |
| | |
| | --help Show this screen. |
| | ''' |
| |
|
| | from docopt import docopt |
| | args = docopt(doc) |
| |
|
| | root_path = args['<storage>'] or '.' |
| | with open_storage(root_path, 'a') as stg: |
| | path = args['<path>'] |
| | file_path = args['<file>'] |
| |
|
| | node = resolve_path(stg, path) |
| | if node: |
| | get_file(node, file_path) |
| | else: |
| | logger.error('%s: not found', path) |
| | raise SystemExit(1) |
| |
|