from twisted.internet import defer
import simplejson
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
- IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError
+ IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError, \
+ IVerifierURI
from allmydata.util import hashutil
from allmydata.util.hashutil import netstring
from allmydata.dirnode import IntegrityCheckError, FileNode
return cmp(self.uri, them.uri)
def get_verifier(self):
- return IMutableFileURI(self.uri).get_verifier()
+ return IMutableFileURI(self._uri).get_verifier()
def check(self):
verifier = self.get_verifier()
return self._client.create_file_from_uri(u)
if IMutableFileURI.providedBy(u):
return self._client.create_mutable_file_from_uri(u)
- raise TypeError("cannot handle URI")
+ raise TypeError("cannot handle '%s' URI" % (u.__class__,))
def _unpack_contents(self, data):
# the directory is serialized as a list of netstrings, one per child.
def get_uri(self):
return self._uri.to_string()
+ def get_readonly(self):
+ return self._uri.get_readonly().to_string()
+
def get_immutable_uri(self):
return self._uri.get_readonly().to_string()
"""I return a Deferred that fires with a specific named child node,
either an IFileNode or an IDirectoryNode."""
d = self._read()
- d.addCallback(lambda children: children[name])
+ d.addCallback(lambda children: children[name][0])
+ return d
+
+ def get_metadata_for(self, name):
+ d = self._read()
+ d.addCallback(lambda children: children[name][1])
return d
def get_child_at_path(self, path):
def delete(self, name):
"""I remove the child at the specific name. I return a Deferred that
- fires when the operation finishes."""
+ fires (with the node just removed) when the operation finishes."""
if self.is_readonly():
return defer.fail(NotMutableError())
d = self._read()
def _delete(children):
+ old_child, metadata = children[name]
del children[name]
new_contents = self._pack_contents(children)
- return self._node.replace(new_contents)
+ d = self._node.replace(new_contents)
+ def _done(res):
+ return old_child
+ d.addCallback(_done)
+ return d
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."""
+ a Deferred that fires (with the new directory node) 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))
+ def _created(child):
+ d = self.set_node(name, child)
+ d.addCallback(lambda res: child)
+ return d
+ d.addCallback(_created)
return d
def move_child_to(self, current_child_name, new_parent,
# 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()
+ return frozenset([IVerifierURI(cap).to_string()
for cap in manifest
if cap is not None])
d.addCallback(_done)
d = node.list()
def _got_list(res):
dl = []
- for name, child in res.iteritems():
+ for name, (child, metadata) in res.iteritems():
verifier = child.get_verifier()
if verifier not in manifest:
manifest.add(verifier)
+import itertools
from twisted.trial import unittest
from twisted.internet import defer
self.failUnlessEqual(bottom, ("hello", "world", "extra stuff"))
class FakeFilenode(mutable.MutableFileNode):
+ counter = itertools.count(1)
+ all_contents = {}
+
def init_from_uri(self, myuri):
self._uri = myuri
self.writekey = myuri.writekey
return self
def create(self, initial_contents):
- self.contents = initial_contents
- self.init_from_uri(uri.WriteableSSKFileURI("key", "fingerprint"))
+ count = self.counter.next()
+ self.init_from_uri(uri.WriteableSSKFileURI("key%d" % count,
+ "fingerprint%d" % count))
+ self.all_contents[self._uri] = initial_contents
return defer.succeed(None)
def download_to_data(self):
- return defer.succeed(self.contents)
+ return defer.succeed(self.all_contents[self._uri])
def replace(self, newdata):
- self.contents = newdata
+ self.all_contents[self._uri] = newdata
return defer.succeed(None)
def is_readonly(self):
return False
self.client = MyClient()
def test_create(self):
+ self.expected_manifest = []
+
d = self.client.create_empty_dirnode()
def _check(n):
self.failUnless(n.is_mutable())
self.failUnless(u_ro.startswith("URI:DIR2-RO:"), u_ro)
u_v = n.get_verifier()
self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v)
+ self.expected_manifest.append(u_v)
d = n.list()
d.addCallback(lambda res: self.failUnlessEqual(res, {}))
d.addCallback(lambda res: n.has_child("missing"))
d.addCallback(lambda res: self.failIf(res))
fake_file_uri = uri.WriteableSSKFileURI("a"*16,"b"*32)
+ ffu_v = fake_file_uri.get_verifier().to_string()
+ self.expected_manifest.append(ffu_v)
d.addCallback(lambda res: n.set_uri("child", fake_file_uri))
d.addCallback(lambda res: self.failUnlessEqual(res, None))
+
+ d.addCallback(lambda res: n.create_empty_directory("subdir"))
+ def _created(subdir):
+ self.failUnless(isinstance(subdir, FakeNewDirectoryNode))
+ self.subdir = subdir
+ new_v = subdir.get_verifier()
+ self.expected_manifest.append(new_v)
+ d.addCallback(_created)
+
+ d.addCallback(lambda res: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessEqual(sorted(children.keys()),
+ sorted(["child", "subdir"])))
+
+ d.addCallback(lambda res: n.build_manifest())
+ def _check_manifest(manifest):
+ self.failUnlessEqual(sorted(manifest),
+ sorted(self.expected_manifest))
+ d.addCallback(_check_manifest)
+
+ def _add_subsubdir(res):
+ return self.subdir.create_empty_directory("subsubdir")
+ d.addCallback(_add_subsubdir)
+ d.addCallback(lambda res: n.get_child_at_path("subdir/subsubdir"))
+ d.addCallback(lambda subsubdir:
+ self.failUnless(isinstance(subsubdir,
+ FakeNewDirectoryNode)))
+ d.addCallback(lambda res: n.get_child_at_path(""))
+ d.addCallback(lambda res: self.failUnlessEqual(res.get_uri(),
+ n.get_uri()))
+
+ d.addCallback(lambda res: n.get_metadata_for("child"))
+ d.addCallback(lambda metadata: self.failUnlessEqual(metadata, {}))
+
+ d.addCallback(lambda res: n.delete("subdir"))
+ d.addCallback(lambda old_child:
+ self.failUnlessEqual(old_child.get_uri(),
+ self.subdir.get_uri()))
+
d.addCallback(lambda res: n.list())
- def _check_list(children):
- self.failUnless("child" in children)
- d.addCallback(_check_list)
+ d.addCallback(lambda children:
+ self.failUnlessEqual(sorted(children.keys()),
+ sorted(["child"])))
return d
from twisted.python.components import registerAdapter
from allmydata.util import idlib, hashutil
from allmydata.interfaces import IURI, IDirnodeURI, IFileURI, IVerifierURI, \
- IMutableFileURI
+ IMutableFileURI, INewDirectoryURI
# the URI shall be an ascii representation of the file. It shall contain
# enough information to retrieve and validate the contents. It shall be
idlib.b2a(self.fingerprint))
class NewDirectoryURI(_BaseURI):
- implements(IURI, IDirnodeURI)
+ implements(IURI, IDirnodeURI, INewDirectoryURI)
def __init__(self, filenode_uri=None):
if filenode_uri:
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2:" + bits
+ def get_filenode_uri(self):
+ return self._filenode_uri
+
def is_readonly(self):
return False
def is_mutable(self):
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2-RO:" + bits
+ def get_filenode_uri(self):
+ return self._filenode_uri
+
def is_readonly(self):
return True
def is_mutable(self):
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2-Verifier:" + bits
+ def get_filenode_uri(self):
+ return self._filenode_uri
+
class DirnodeURI(_BaseURI):