mutable: implement most remaining dirnode methods. No tests yet.

This commit is contained in:
Brian Warner 2007-11-01 16:57:58 -07:00
parent 57373c9889
commit 36921fedb3
1 changed files with 85 additions and 4 deletions

View File

@ -7,7 +7,7 @@ from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError
from allmydata.util import hashutil
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.Crypto.Cipher import AES
@ -208,6 +208,8 @@ class NewDirectoryNode:
entries.append(netstring(entry))
return "".join(entries)
def is_readonly(self):
return self._node.is_readonly()
def is_mutable(self):
return self._node.is_mutable()
@ -222,7 +224,7 @@ class NewDirectoryNode:
def check(self):
"""Perform a file check. See IChecker.check for details."""
pass
pass # TODO
def list(self):
"""I return a Deferred that fires with a dictionary mapping child
@ -254,6 +256,19 @@ class NewDirectoryNode:
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={}):
"""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
@ -274,7 +289,7 @@ class NewDirectoryNode:
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
if self._node.is_readonly():
if self.is_readonly():
return defer.fail(NotMutableError())
d = self._read()
def _add(children):
@ -290,24 +305,90 @@ class NewDirectoryNode:
resulting FileNode to the directory at the given name. I return a
Deferred that fires (with the IFileNode of the uploaded file) when
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):
"""I remove the child at the specific name. I return a Deferred that
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):
"""I create and attach an empty directory at the given name. I return
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
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
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):
"""Return a frozenset of verifier-capability strings for all nodes
(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