mutable: implement most remaining dirnode methods. No tests yet.
This commit is contained in:
parent
57373c9889
commit
36921fedb3
|
@ -7,7 +7,7 @@ from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
|
||||||
IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError
|
IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError
|
||||||
from allmydata.util import hashutil
|
from allmydata.util import hashutil
|
||||||
from allmydata.util.hashutil import netstring
|
from allmydata.util.hashutil import netstring
|
||||||
from allmydata.dirnode import IntegrityCheckError
|
from allmydata.dirnode import IntegrityCheckError, FileNode
|
||||||
from allmydata.uri import WriteableSSKFileURI, NewDirectoryURI
|
from allmydata.uri import WriteableSSKFileURI, NewDirectoryURI
|
||||||
from allmydata.Crypto.Cipher import AES
|
from allmydata.Crypto.Cipher import AES
|
||||||
|
|
||||||
|
@ -208,6 +208,8 @@ class NewDirectoryNode:
|
||||||
entries.append(netstring(entry))
|
entries.append(netstring(entry))
|
||||||
return "".join(entries)
|
return "".join(entries)
|
||||||
|
|
||||||
|
def is_readonly(self):
|
||||||
|
return self._node.is_readonly()
|
||||||
def is_mutable(self):
|
def is_mutable(self):
|
||||||
return self._node.is_mutable()
|
return self._node.is_mutable()
|
||||||
|
|
||||||
|
@ -222,7 +224,7 @@ class NewDirectoryNode:
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
"""Perform a file check. See IChecker.check for details."""
|
"""Perform a file check. See IChecker.check for details."""
|
||||||
pass
|
pass # TODO
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
"""I return a Deferred that fires with a dictionary mapping child
|
"""I return a Deferred that fires with a dictionary mapping child
|
||||||
|
@ -254,6 +256,19 @@ class NewDirectoryNode:
|
||||||
path-name elements.
|
path-name elements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not path:
|
||||||
|
return defer.succeed(self)
|
||||||
|
if isinstance(path, (str, unicode)):
|
||||||
|
path = path.split("/")
|
||||||
|
childname = path[0]
|
||||||
|
remaining_path = path[1:]
|
||||||
|
d = self.get(childname)
|
||||||
|
if remaining_path:
|
||||||
|
def _got(node):
|
||||||
|
return node.get_child_at_path(remaining_path)
|
||||||
|
d.addCallback(_got)
|
||||||
|
return d
|
||||||
|
|
||||||
def set_uri(self, name, child_uri, metadata={}):
|
def set_uri(self, name, child_uri, metadata={}):
|
||||||
"""I add a child (by URI) at the specific name. I return a Deferred
|
"""I add a child (by URI) at the specific name. I return a Deferred
|
||||||
that fires when the operation finishes. I will replace any existing
|
that fires when the operation finishes. I will replace any existing
|
||||||
|
@ -274,7 +289,7 @@ class NewDirectoryNode:
|
||||||
|
|
||||||
If this directory node is read-only, the Deferred will errback with a
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
NotMutableError."""
|
||||||
if self._node.is_readonly():
|
if self.is_readonly():
|
||||||
return defer.fail(NotMutableError())
|
return defer.fail(NotMutableError())
|
||||||
d = self._read()
|
d = self._read()
|
||||||
def _add(children):
|
def _add(children):
|
||||||
|
@ -290,24 +305,90 @@ class NewDirectoryNode:
|
||||||
resulting FileNode to the directory at the given name. I return a
|
resulting FileNode to the directory at the given name. I return a
|
||||||
Deferred that fires (with the IFileNode of the uploaded file) when
|
Deferred that fires (with the IFileNode of the uploaded file) when
|
||||||
the operation completes."""
|
the operation completes."""
|
||||||
|
if self.is_readonly():
|
||||||
|
return defer.fail(NotMutableError())
|
||||||
|
uploader = self._client.getServiceNamed("uploader")
|
||||||
|
d = uploader.upload(uploadable)
|
||||||
|
d.addCallback(lambda uri: self.set_node(name,
|
||||||
|
FileNode(uri, self._client)))
|
||||||
|
return d
|
||||||
|
|
||||||
def delete(self, name):
|
def delete(self, name):
|
||||||
"""I remove the child at the specific name. I return a Deferred that
|
"""I remove the child at the specific name. I return a Deferred that
|
||||||
fires when the operation finishes."""
|
fires when the operation finishes."""
|
||||||
|
if self.is_readonly():
|
||||||
|
return defer.fail(NotMutableError())
|
||||||
|
d = self._read()
|
||||||
|
def _delete(children):
|
||||||
|
del children[name]
|
||||||
|
new_contents = self._pack_contents(children)
|
||||||
|
return self._node.replace(new_contents)
|
||||||
|
d.addCallback(_delete)
|
||||||
|
d.addCallback(lambda res: None)
|
||||||
|
return d
|
||||||
|
|
||||||
def create_empty_directory(self, name):
|
def create_empty_directory(self, name):
|
||||||
"""I create and attach an empty directory at the given name. I return
|
"""I create and attach an empty directory at the given name. I return
|
||||||
a Deferred that fires when the operation finishes."""
|
a Deferred that fires when the operation finishes."""
|
||||||
|
if self.is_readonly():
|
||||||
|
return defer.fail(NotMutableError())
|
||||||
|
d = self._client.create_empty_dirnode()
|
||||||
|
d.addCallback(lambda child: self.set_node(name, child))
|
||||||
|
return d
|
||||||
|
|
||||||
def move_child_to(self, current_child_name, new_parent, new_child_name=None):
|
def move_child_to(self, current_child_name, new_parent,
|
||||||
|
new_child_name=None):
|
||||||
"""I take one of my children and move them to a new parent. The child
|
"""I take one of my children and move them to a new parent. The child
|
||||||
is referenced by name. On the new parent, the child will live under
|
is referenced by name. On the new parent, the child will live under
|
||||||
'new_child_name', which defaults to 'current_child_name'. I return a
|
'new_child_name', which defaults to 'current_child_name'. I return a
|
||||||
Deferred that fires when the operation finishes."""
|
Deferred that fires when the operation finishes."""
|
||||||
|
if self.is_readonly() or new_parent.is_readonly():
|
||||||
|
return defer.fail(NotMutableError())
|
||||||
|
if new_child_name is None:
|
||||||
|
new_child_name = current_child_name
|
||||||
|
d = self.get(current_child_name)
|
||||||
|
d.addCallback(lambda child: new_parent.set_node(new_child_name, child))
|
||||||
|
d.addCallback(lambda child: self.delete(current_child_name))
|
||||||
|
return d
|
||||||
|
|
||||||
def build_manifest(self):
|
def build_manifest(self):
|
||||||
"""Return a frozenset of verifier-capability strings for all nodes
|
"""Return a frozenset of verifier-capability strings for all nodes
|
||||||
(directories and files) reachable from this one."""
|
(directories and files) reachable from this one."""
|
||||||
|
|
||||||
|
# this is just a tree-walker, except that following each edge
|
||||||
|
# requires a Deferred.
|
||||||
|
|
||||||
|
manifest = set()
|
||||||
|
manifest.add(self.get_verifier())
|
||||||
|
|
||||||
|
d = self._build_manifest_from_node(self, manifest)
|
||||||
|
def _done(res):
|
||||||
|
# LIT nodes have no verifier-capability: their data is stored
|
||||||
|
# inside the URI itself, so there is no need to refresh anything.
|
||||||
|
# They indicate this by returning None from their get_verifier
|
||||||
|
# method. We need to remove any such Nones from our set. We also
|
||||||
|
# want to convert all these caps into strings.
|
||||||
|
return frozenset([cap.to_string()
|
||||||
|
for cap in manifest
|
||||||
|
if cap is not None])
|
||||||
|
d.addCallback(_done)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _build_manifest_from_node(self, node, manifest):
|
||||||
|
d = node.list()
|
||||||
|
def _got_list(res):
|
||||||
|
dl = []
|
||||||
|
for name, child in res.iteritems():
|
||||||
|
verifier = child.get_verifier()
|
||||||
|
if verifier not in manifest:
|
||||||
|
manifest.add(verifier)
|
||||||
|
if IDirectoryNode.providedBy(child):
|
||||||
|
dl.append(self._build_manifest_from_node(child,
|
||||||
|
manifest))
|
||||||
|
if dl:
|
||||||
|
return defer.DeferredList(dl)
|
||||||
|
d.addCallback(_got_list)
|
||||||
|
return d
|
||||||
|
|
||||||
# use client.create_dirnode() to make one of these
|
# use client.create_dirnode() to make one of these
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue