|
@@ -38,6 +38,7 @@ import uuid |
|
|
|
|
|
|
|
|
# The UUID for the namespace representing the path to a file |
|
|
# The UUID for the namespace representing the path to a file |
|
|
_NAMESPACE_MEDASHARE_PATH = uuid.UUID('f6f36b62-3770-4a68-bc3d-dc3e31e429e6') |
|
|
_NAMESPACE_MEDASHARE_PATH = uuid.UUID('f6f36b62-3770-4a68-bc3d-dc3e31e429e6') |
|
|
|
|
|
_NAMESPACE_MEDASHARE_CONTAINER = uuid.UUID('890a9d5c-0626-4de1-ab05-9e14947391eb') |
|
|
|
|
|
|
|
|
# useful for debugging when stderr is redirected/captured |
|
|
# useful for debugging when stderr is redirected/captured |
|
|
_real_stderr = sys.stderr |
|
|
_real_stderr = sys.stderr |
|
@@ -173,9 +174,13 @@ class MDBase(object): |
|
|
raise ValueError('Unable to find class for type %s' % |
|
|
raise ValueError('Unable to find class for type %s' % |
|
|
repr(ty)) |
|
|
repr(ty)) |
|
|
|
|
|
|
|
|
def new_version(self, *args): |
|
|
|
|
|
|
|
|
def new_version(self, *args, dels=(), replaces=()): |
|
|
'''For each k, v pair, add the property k as an additional one |
|
|
'''For each k, v pair, add the property k as an additional one |
|
|
(or new one if first), with the value v.''' |
|
|
|
|
|
|
|
|
(or new one if first), with the value v. |
|
|
|
|
|
|
|
|
|
|
|
Any key in dels is removed. |
|
|
|
|
|
|
|
|
|
|
|
Any k, v pair in replaces, replaces the entire key.''' |
|
|
|
|
|
|
|
|
obj = copy.deepcopy(self._obj) |
|
|
obj = copy.deepcopy(self._obj) |
|
|
|
|
|
|
|
@@ -186,6 +191,12 @@ class MDBase(object): |
|
|
else: |
|
|
else: |
|
|
obj.setdefault(k, []).append(v) |
|
|
obj.setdefault(k, []).append(v) |
|
|
|
|
|
|
|
|
|
|
|
for i in dels: |
|
|
|
|
|
del obj[i] |
|
|
|
|
|
|
|
|
|
|
|
for k, v in replaces: |
|
|
|
|
|
obj[k] = v |
|
|
|
|
|
|
|
|
del obj['modified'] |
|
|
del obj['modified'] |
|
|
|
|
|
|
|
|
return self.create_obj(obj) |
|
|
return self.create_obj(obj) |
|
@@ -538,6 +549,8 @@ class ObjectStore(object): |
|
|
del self._uuids[oldobj.uuid] |
|
|
del self._uuids[oldobj.uuid] |
|
|
|
|
|
|
|
|
self._uuids[_makeuuid(obj.id)] = obj |
|
|
self._uuids[_makeuuid(obj.id)] = obj |
|
|
|
|
|
elif obj.type == 'container': |
|
|
|
|
|
self._uuids[obj.make_id(obj.uri)] = obj |
|
|
|
|
|
|
|
|
for j in obj.hashes: |
|
|
for j in obj.hashes: |
|
|
h = self.makehash(j) |
|
|
h = self.makehash(j) |
|
@@ -721,6 +734,12 @@ class FileObject(MDBase): |
|
|
class Container(MDBase): |
|
|
class Container(MDBase): |
|
|
_type = 'container' |
|
|
_type = 'container' |
|
|
|
|
|
|
|
|
|
|
|
_common_optional = MDBase._common_optional | set([ 'uri' ]) |
|
|
|
|
|
|
|
|
|
|
|
@staticmethod |
|
|
|
|
|
def make_id(uri): |
|
|
|
|
|
return uuid.uuid5(_NAMESPACE_MEDASHARE_CONTAINER, uri) |
|
|
|
|
|
|
|
|
def enumeratedir(_dir, created_by_ref): |
|
|
def enumeratedir(_dir, created_by_ref): |
|
|
'''Enumerate all the files and directories (not recursive) in _dir. |
|
|
'''Enumerate all the files and directories (not recursive) in _dir. |
|
|
|
|
|
|
|
@@ -955,10 +974,28 @@ def cmd_container(options): |
|
|
torrent = bencode.bdecode(fp.read()) |
|
|
torrent = bencode.bdecode(fp.read()) |
|
|
bencodedinfo = bencode.bencode(torrent['info']) |
|
|
bencodedinfo = bencode.bencode(torrent['info']) |
|
|
infohash = hashlib.sha1(bencodedinfo).hexdigest() |
|
|
infohash = hashlib.sha1(bencodedinfo).hexdigest() |
|
|
|
|
|
|
|
|
# XXX - not entirely happy w/ URI |
|
|
# XXX - not entirely happy w/ URI |
|
|
cont = persona.Container(files=files, hashes=hashes, |
|
|
|
|
|
uri='magnet:?xt=urn:btih:%s&dn=%s' % (infohash, |
|
|
|
|
|
torrent['info']['name'].decode('utf-8'))) |
|
|
|
|
|
|
|
|
uri = 'magnet:?xt=urn:btih:%s&dn=%s' % (infohash, |
|
|
|
|
|
torrent['info']['name'].decode('utf-8')) |
|
|
|
|
|
|
|
|
|
|
|
kwargs = dict(files=files, hashes=hashes, |
|
|
|
|
|
uri=uri) |
|
|
|
|
|
|
|
|
|
|
|
if bad: |
|
|
|
|
|
kwargs['incomplete'] = True |
|
|
|
|
|
|
|
|
|
|
|
# XXX - doesn't combine files/hashes, that is if a |
|
|
|
|
|
# Container has one set of good files, and then the |
|
|
|
|
|
# next scan has a different set, only the second set |
|
|
|
|
|
# will be present, not any from the first set. |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
cont = objstr.by_id(Container.make_id(uri)) |
|
|
|
|
|
cont = cont.new_version(*kwargs.items(), dels=() if bad |
|
|
|
|
|
else ('incomplete',), replaces=kwargs.items()) |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
cont = persona.Container(**kwargs) |
|
|
|
|
|
|
|
|
objstr.loadobj(cont) |
|
|
objstr.loadobj(cont) |
|
|
|
|
|
|
|
@@ -1565,14 +1602,15 @@ class _TestCases(unittest.TestCase): |
|
|
shutil.copy(tor, self.tempdir) |
|
|
shutil.copy(tor, self.tempdir) |
|
|
|
|
|
|
|
|
# partly recreate files |
|
|
# partly recreate files |
|
|
missingfiles = bttestcase.origfiledata.copy() |
|
|
|
|
|
|
|
|
btfiles = bttestcase.origfiledata.copy() |
|
|
|
|
|
|
|
|
missingfiles.update(bttestcase.badfiles) |
|
|
|
|
|
|
|
|
if not cmd['complete']: |
|
|
|
|
|
btfiles.update(bttestcase.badfiles) |
|
|
|
|
|
|
|
|
sd = self.tempdir / bttestcase.dirname |
|
|
sd = self.tempdir / bttestcase.dirname |
|
|
sd.mkdir() |
|
|
|
|
|
|
|
|
sd.mkdir(exist_ok=True) |
|
|
|
|
|
|
|
|
bttestcase.make_files(sd, missingfiles) |
|
|
|
|
|
|
|
|
bttestcase.make_files(sd, btfiles) |
|
|
else: # pragma: no cover |
|
|
else: # pragma: no cover |
|
|
raise ValueError('unhandled special: %s' % repr(special)) |
|
|
raise ValueError('unhandled special: %s' % repr(special)) |
|
|
|
|
|
|
|
|