''' Created on 25.9.2010 @author: marekp ''' import sys import platform import stat as statinfo import fs.errors as errors from fs.path import pathsplit try: # For non-CPython or older CPython versions. # Simplejson also comes with C speedup module which # is not in standard CPython >=2.6 library. import simplejson as json except ImportError: try: import json except ImportError: print "simplejson (http://pypi.python.org/pypi/simplejson/) required" raise from .connection import Connection python3 = int(platform.python_version_tuple()[0]) > 2 if python3: from urllib.error import HTTPError else: from urllib2 import HTTPError class TahoeUtil: def __init__(self, webapi): self.connection = Connection(webapi) def createdircap(self): return self.connection.post(u'/uri', params={u't': u'mkdir'}).read() def unlink(self, dircap, path=None): path = self.fixwinpath(path, False) self.connection.delete(u'/uri/%s%s' % (dircap, path)) def info(self, dircap, path): path = self.fixwinpath(path, False) meta = json.load(self.connection.get(u'/uri/%s%s' % (dircap, path), {u't': u'json'})) return self._info(path, meta) def fixwinpath(self, path, direction=True): ''' No, Tahoe really does not support file streams... This is ugly hack, because it is not Tahoe-specific. Should be move to middleware if will be any. ''' if platform.system() != 'Windows': return path if direction and ':' in path: path = path.replace(':', '__colon__') elif not direction and '__colon__' in path: path = path.replace('__colon__', ':') return path def _info(self, path, data): if isinstance(data, list): type = data[0] data = data[1] elif isinstance(data, dict): type = data['type'] else: raise errors.ResourceInvalidError('Metadata in unknown format!') if type == 'unknown': raise errors.ResourceNotFoundError(path) info = {'name': unicode(self.fixwinpath(path, True)), 'type': type, 'size': data.get('size', 0), 'ctime': None, 'uri': data.get('rw_uri', data.get('ro_uri'))} if 'metadata' in data: info['ctime'] = data['metadata'].get('ctime') if info['type'] == 'dirnode': info['st_mode'] = 0777 | statinfo.S_IFDIR else: info['st_mode'] = 0644 return info def list(self, dircap, path=None): path = self.fixwinpath(path, False) data = json.load(self.connection.get(u'/uri/%s%s' % (dircap, path), {u't': u'json'})) if len(data) < 2 or data[0] != 'dirnode': raise errors.ResourceInvalidError('Metadata in unknown format!') data = data[1]['children'] for i in data.keys(): x = self._info(i, data[i]) yield x def mkdir(self, dircap, path): path = self.fixwinpath(path, False) path = pathsplit(path) self.connection.post(u"/uri/%s%s" % (dircap, path[0]), data={u't': u'mkdir', u'name': path[1]}) def move(self, dircap, src, dst): if src == '/' or dst == '/': raise errors.UnsupportedError("Too dangerous operation, aborting") src = self.fixwinpath(src, False) dst = self.fixwinpath(dst, False) src_tuple = pathsplit(src) dst_tuple = pathsplit(dst) if src_tuple[0] == dst_tuple[0]: # Move inside one directory self.connection.post(u"/uri/%s%s" % (dircap, src_tuple[0]), data={u't': u'rename', u'from_name': src_tuple[1], u'to_name': dst_tuple[1]}) return # Move to different directory. Firstly create link on dst, then remove from src try: self.info(dircap, dst) except errors.ResourceNotFoundError: pass else: self.unlink(dircap, dst) uri = self.info(dircap, src)['uri'] self.connection.put(u"/uri/%s%s" % (dircap, dst), data=uri, params={u't': u'uri'}) if uri != self.info(dircap, dst)['uri']: raise errors.OperationFailedError('Move failed') self.unlink(dircap, src)