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 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