| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| from __future__ import absolute_import |
| from __future__ import print_function |
| from __future__ import unicode_literals |
| import io |
| import os.path |
| import sys |
|
|
|
|
| PY3 = sys.version_info.major == 3 |
| if PY3: |
| basestring = str |
|
|
|
|
| def is_storage(item): |
| return hasattr(item, '__iter__') and hasattr(item, '__getitem__') |
|
|
|
|
| def is_stream(item): |
| return hasattr(item, 'open') and callable(item.open) |
|
|
|
|
| class ItemWrapper(object): |
| def __init__(self, wrapped): |
| self.wrapped = wrapped |
|
|
| def __getattr__(self, name): |
| return getattr(self.wrapped, name) |
|
|
|
|
| class StorageWrapper(ItemWrapper): |
| def __iter__(self): |
| return iter(self.wrapped) |
|
|
| def __getitem__(self, name): |
| return self.wrapped[name] |
|
|
|
|
| class ItemConversionStorage(StorageWrapper): |
|
|
| def __getitem__(self, name): |
| item = self.wrapped[name] |
| |
| conversion = self.resolve_conversion_for(name) |
| if conversion: |
| return conversion(item) |
| return item |
|
|
| def resolve_conversion_for(self, name): |
| ''' return a conversion function for the specified storage item ''' |
| pass |
|
|
|
|
| class ExtraItemStorage(StorageWrapper): |
|
|
| def __iter__(self): |
| for name in self.wrapped: |
| yield name |
|
|
| item = self.wrapped[name] |
| if hasattr(item, 'other_formats'): |
| other_formats = item.other_formats() |
| if other_formats: |
| for ext in other_formats: |
| yield name + ext |
|
|
| def __getitem__(self, name): |
| try: |
| item = self.wrapped[name] |
| if is_storage(item): |
| item = ExtraItemStorage(item) |
| return item |
| except KeyError: |
| |
| for root in self.wrapped: |
| item = self.wrapped[root] |
| if hasattr(item, 'other_formats'): |
| other_formats = item.other_formats() |
| if other_formats: |
| for ext, func in other_formats.items(): |
| if root + ext == name: |
| return Open2Stream(func) |
| raise |
|
|
|
|
| class Open2Stream(object): |
|
|
| def __init__(self, open): |
| self.open = open |
|
|
|
|
| def iter_storage_leafs(stg, basepath=''): |
| ''' iterate every leaf nodes in the storage |
| |
| stg: an instance of Storage |
| ''' |
| for name in stg: |
| path = basepath + name |
| item = stg[name] |
| if is_storage(item): |
| for x in iter_storage_leafs(item, path + '/'): |
| yield x |
| else: |
| yield path |
|
|
|
|
| def unpack(stg, outbase): |
| ''' unpack a storage into outbase directory |
| |
| stg: an instance of Storage |
| outbase: path to a directory in filesystem (should not end with '/') |
| ''' |
| for name in stg: |
| outpath = os.path.join(outbase, name) |
| item = stg[name] |
| if is_storage(item): |
| if not os.path.exists(outpath): |
| os.mkdir(outpath) |
| unpack(item, outpath) |
| else: |
| f = item.open() |
| try: |
| outpath = outpath.replace('\x05', '_05') |
| with io.open(outpath, 'wb') as outfile: |
| outfile.write(f.read()) |
| finally: |
| f.close() |
|
|
|
|
| def open_storage_item(stg, path): |
| if isinstance(path, basestring): |
| path_segments = path.split('/') |
| else: |
| path_segments = path |
|
|
| item = stg |
| for name in path_segments: |
| item = item[name] |
| return item |
|
|
|
|
| def printstorage(stg, basepath=''): |
| names = list(stg) |
| names.sort() |
| for name in names: |
| path = basepath + name |
| item = stg[name] |
| if is_storage(item): |
| printstorage(item, path + '/') |
| elif is_stream(item): |
| print(path.encode('unicode_escape').decode('utf-8')) |
|
|