dirnode.set_uri/set_children: change signature to take writecap+readcap

instead of a single cap. The webapi t=set_children call benefits too.
This commit is contained in:
Brian Warner 2009-10-12 16:51:26 -07:00
parent 3ee740628a
commit e2ffc3dc03
7 changed files with 87 additions and 66 deletions

View File

@ -380,19 +380,11 @@ class DirectoryNode:
d = self.get_child_and_metadata(childname)
return d
def set_uri(self, name, child_uri, metadata=None, overwrite=True):
"""I add a child (by URI) at the specific name. I return a Deferred
that fires with the child node when the operation finishes. I will
replace any existing child of the same name.
The child_uri could be for a file, or for a directory (either
read-write or read-only, using a URI that came from get_uri() ).
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
def set_uri(self, name, writecap, readcap, metadata=None, overwrite=True):
precondition(isinstance(name, unicode), name)
precondition(isinstance(child_uri, str), child_uri)
child_node = self._create_node(child_uri, None)
precondition(isinstance(writecap, (str,type(None))), writecap)
precondition(isinstance(readcap, (str,type(None))), readcap)
child_node = self._create_node(writecap, readcap)
if isinstance(child_node, UnknownNode):
# don't be willing to pack unknown nodes: we might accidentally
# put some write-authority into the rocap slot because we don't
@ -409,15 +401,16 @@ class DirectoryNode:
a = Adder(self, overwrite=overwrite)
node_entries = []
for e in entries:
if len(e) == 2:
name, child_uri = e
if len(e) == 3:
name, writecap, readcap = e
metadata = None
else:
assert len(e) == 3
name, child_uri, metadata = e
assert len(e) == 4
name, writecap, readcap, metadata = e
assert isinstance(name, unicode)
assert isinstance(child_uri, str)
child_node = self._create_node(child_uri, None)
precondition(isinstance(writecap, (str,type(None))), writecap)
precondition(isinstance(readcap, (str,type(None))), readcap)
child_node = self._create_node(writecap, readcap)
if isinstance(child_node, UnknownNode):
msg = "cannot pack unknown node as child %s" % str(name)
raise CannotPackUnknownNodeError(msg)

View File

@ -873,15 +873,19 @@ class IDirectoryNode(IMutableFilesystemNode):
is empty, the metadata will be an empty dictionary.
"""
def set_uri(name, child_uri, metadata=None, overwrite=True):
"""I add a child (by URI) at the specific name. I return a Deferred
that fires when the operation finishes. If overwrite= is True, I will
replace any existing child of the same name, otherwise an existing
child will cause me to return ExistingChildError. The child name must
be a unicode string.
def set_uri(name, writecap, readcap=None, metadata=None, overwrite=True):
"""I add a child (by writecap+readcap) at the specific name. I return
a Deferred that fires when the operation finishes. If overwrite= is
True, I will replace any existing child of the same name, otherwise
an existing child will cause me to return ExistingChildError. The
child name must be a unicode string.
The child_uri could be for a file, or for a directory (either
read-write or read-only, using a URI that came from get_uri() ).
The child caps could be for a file, or for a directory. If the new
child is read/write, you will provide both writecap and readcap. If
the child is read-only, you will provide the readcap write (i.e. the
writecap= and readcap= arguments will both be the child's readcap).
The filecaps are typically obtained from an IFilesystemNode with
get_uri() and get_readonly_uri().
If metadata= is provided, I will use it as the metadata for the named
edge. This will replace any existing metadata. If metadata= is left
@ -894,11 +898,11 @@ class IDirectoryNode(IMutableFilesystemNode):
NotMutableError."""
def set_children(entries, overwrite=True):
"""Add multiple (name, child_uri) pairs (or (name, child_uri,
metadata) triples) to a directory node. Returns a Deferred that fires
(with None) when the operation finishes. This is equivalent to
calling set_uri() multiple times, but is much more efficient. All
child names must be unicode strings.
"""Add multiple (name, writecap, readcap) triples (or (name,
writecap, readcap, metadata) 4-tuples) to a directory node. Returns a
Deferred that fires (with None) when the operation finishes. This is
equivalent to calling set_uri() multiple times, but is much more
efficient. All child names must be unicode strings.
"""
def set_node(name, child, metadata=None, overwrite=True):

View File

@ -1186,8 +1186,8 @@ class Large(DeepCheckBase, unittest.TestCase):
self.subdir_node = subdir_node
kids = []
for i in range(1, COUNT):
litnode = LiteralFileURI("%03d-data" % i).to_string()
kids.append( (u"%03d-small" % i, litnode) )
litcap = LiteralFileURI("%03d-data" % i).to_string()
kids.append( (u"%03d-small" % i, litcap, litcap) )
return subdir_node.set_children(kids)
d.addCallback(_add_children)
up = upload.Data("large enough for CHK" * 100, "")

View File

@ -67,6 +67,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
d.addCallback(lambda res: c.create_dirnode())
d.addCallback(lambda dn:
self._rootnode.set_uri(u"rodir",
dn.get_uri(),
dn.get_readonly_uri()))
return d
d.addCallback(_created_subdir)
@ -159,7 +160,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
d = c.create_dirnode()
def _created(rw_dn):
d2 = rw_dn.set_uri(u"child", filecap)
d2 = rw_dn.set_uri(u"child", filecap, filecap)
d2.addCallback(lambda res: rw_dn)
return d2
d.addCallback(_created)
@ -171,7 +172,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
self.failUnless(ro_dn.is_mutable())
self.shouldFail(dirnode.NotMutableError, "set_uri ro", None,
ro_dn.set_uri, u"newchild", filecap)
ro_dn.set_uri, u"newchild", filecap, filecap)
self.shouldFail(dirnode.NotMutableError, "set_uri ro", None,
ro_dn.set_node, u"newchild", filenode)
self.shouldFail(dirnode.NotMutableError, "set_nodes ro", None,
@ -243,11 +244,13 @@ class Dirnode(GridTestMixin, unittest.TestCase,
self.expected_manifest.append( ((u"child",) , m.get_uri()) )
self.expected_verifycaps.add(ffu_v)
self.expected_storage_indexes.add(base32.b2a(m.get_storage_index()))
d.addCallback(lambda res: n.set_uri(u"child", fake_file_uri))
d.addCallback(lambda res: n.set_uri(u"child",
fake_file_uri, fake_file_uri))
d.addCallback(lambda res:
self.shouldFail(ExistingChildError, "set_uri-no",
"child 'child' already exists",
n.set_uri, u"child", other_file_uri,
n.set_uri, u"child",
other_file_uri, other_file_uri,
overwrite=False))
# /
# /child = mutable
@ -373,12 +376,16 @@ class Dirnode(GridTestMixin, unittest.TestCase,
# set_uri + metadata
# it should be possible to add a child without any metadata
d.addCallback(lambda res: n.set_uri(u"c2", fake_file_uri, {}))
d.addCallback(lambda res: n.set_uri(u"c2",
fake_file_uri, fake_file_uri,
{}))
d.addCallback(lambda res: n.get_metadata_for(u"c2"))
d.addCallback(lambda metadata: self.failUnlessEqual(metadata.keys(), ['tahoe']))
# You can't override the link timestamps.
d.addCallback(lambda res: n.set_uri(u"c2", fake_file_uri, { 'tahoe': {'linkcrtime': "bogus"}}))
d.addCallback(lambda res: n.set_uri(u"c2",
fake_file_uri, fake_file_uri,
{ 'tahoe': {'linkcrtime': "bogus"}}))
d.addCallback(lambda res: n.get_metadata_for(u"c2"))
def _has_good_linkcrtime(metadata):
self.failUnless(metadata.has_key('tahoe'))
@ -387,7 +394,8 @@ class Dirnode(GridTestMixin, unittest.TestCase,
d.addCallback(_has_good_linkcrtime)
# if we don't set any defaults, the child should get timestamps
d.addCallback(lambda res: n.set_uri(u"c3", fake_file_uri))
d.addCallback(lambda res: n.set_uri(u"c3",
fake_file_uri, fake_file_uri))
d.addCallback(lambda res: n.get_metadata_for(u"c3"))
d.addCallback(lambda metadata:
self.failUnlessEqual(set(metadata.keys()),
@ -395,7 +403,8 @@ class Dirnode(GridTestMixin, unittest.TestCase,
# or we can add specific metadata at set_uri() time, which
# overrides the timestamps
d.addCallback(lambda res: n.set_uri(u"c4", fake_file_uri,
d.addCallback(lambda res: n.set_uri(u"c4",
fake_file_uri, fake_file_uri,
{"key": "value"}))
d.addCallback(lambda res: n.get_metadata_for(u"c4"))
d.addCallback(lambda metadata:
@ -439,17 +448,19 @@ class Dirnode(GridTestMixin, unittest.TestCase,
d.addCallback(lambda res: n.delete(u"d4"))
# metadata through set_children()
d.addCallback(lambda res: n.set_children([ (u"e1", fake_file_uri),
(u"e2", fake_file_uri, {}),
(u"e3", fake_file_uri,
{"key": "value"}),
]))
d.addCallback(lambda res:
n.set_children([
(u"e1", fake_file_uri, fake_file_uri),
(u"e2", fake_file_uri, fake_file_uri, {}),
(u"e3", fake_file_uri, fake_file_uri,
{"key": "value"}),
]))
d.addCallback(lambda res:
self.shouldFail(ExistingChildError, "set_children-no",
"child 'e1' already exists",
n.set_children,
[ (u"e1", other_file_uri),
(u"new", other_file_uri), ],
[ (u"e1", other_file_uri, other_file_uri),
(u"new", other_file_uri, other_file_uri), ],
overwrite=False))
# and 'new' should not have been created
d.addCallback(lambda res: n.list())
@ -645,7 +656,8 @@ class Dirnode(GridTestMixin, unittest.TestCase,
# now make sure that we honor overwrite=False
d.addCallback(lambda res:
self.subdir2.set_uri(u"newchild", other_file_uri))
self.subdir2.set_uri(u"newchild",
other_file_uri, other_file_uri))
d.addCallback(lambda res:
self.shouldFail(ExistingChildError, "move_child_to-no",
@ -804,7 +816,8 @@ class Dirnode2(unittest.TestCase, testutil.ShouldFailMixin):
self.shouldFail(CannotPackUnknownNodeError,
"copy unknown",
"cannot pack unknown node as child add",
self._node.set_uri, u"add", future_writecap))
self._node.set_uri, u"add",
future_writecap, future_readcap))
d.addCallback(lambda ign: self._node.list())
def _check(children):
self.failUnlessEqual(len(children), 1)

View File

@ -862,8 +862,12 @@ class SystemTest(SystemTestMixin, unittest.TestCase):
d1.addCallback(self.log, "made P/personal/sekrit data")
d1.addCallback(lambda res: rootnode.get_child_at_path([u"subdir1", u"subdir2"]))
def _got_s2(s2node):
d2 = privnode.set_uri(u"s2-rw", s2node.get_uri())
d2.addCallback(lambda node: privnode.set_uri(u"s2-ro", s2node.get_readonly_uri()))
d2 = privnode.set_uri(u"s2-rw", s2node.get_uri(),
s2node.get_readonly_uri())
d2.addCallback(lambda node:
privnode.set_uri(u"s2-ro",
s2node.get_readonly_uri(),
s2node.get_readonly_uri()))
return d2
d1.addCallback(_got_s2)
d1.addCallback(lambda res: privnode)
@ -944,7 +948,7 @@ class SystemTest(SystemTestMixin, unittest.TestCase):
d1.addCallback(self.log, "doing delete(ro)")
d1.addCallback(lambda res: self.shouldFail2(NotMutableError, "delete(nope)", None, dirnode.delete, u"mydata992"))
d1.addCallback(lambda res: self.shouldFail2(NotMutableError, "set_uri(nope)", None, dirnode.set_uri, u"hopeless", self.uri))
d1.addCallback(lambda res: self.shouldFail2(NotMutableError, "set_uri(nope)", None, dirnode.set_uri, u"hopeless", self.uri, self.uri))
d1.addCallback(lambda res: self.shouldFail2(NoSuchChildError, "get(missing)", "missing", dirnode.get, u"missing"))

View File

@ -136,37 +136,40 @@ class WebMixin(object):
self._foo_verifycap = foo.get_verify_cap().to_string()
# NOTE: we ignore the deferred on all set_uri() calls, because we
# know the fake nodes do these synchronously
self.public_root.set_uri(u"foo", foo.get_uri())
self.public_root.set_uri(u"foo", foo.get_uri(),
foo.get_readonly_uri())
self.BAR_CONTENTS, n, self._bar_txt_uri = self.makefile(0)
foo.set_uri(u"bar.txt", self._bar_txt_uri)
foo.set_uri(u"bar.txt", self._bar_txt_uri, self._bar_txt_uri)
self._bar_txt_verifycap = n.get_verify_cap().to_string()
foo.set_uri(u"empty", res[3][1].get_uri())
foo.set_uri(u"empty", res[3][1].get_uri(),
res[3][1].get_readonly_uri())
sub_uri = res[4][1].get_uri()
self._sub_uri = sub_uri
foo.set_uri(u"sub", sub_uri)
foo.set_uri(u"sub", sub_uri, sub_uri)
sub = self.s.create_node_from_uri(sub_uri)
_ign, n, blocking_uri = self.makefile(1)
foo.set_uri(u"blockingfile", blocking_uri)
foo.set_uri(u"blockingfile", blocking_uri, blocking_uri)
unicode_filename = u"n\u00fc.txt" # n u-umlaut . t x t
# ok, unicode calls it LATIN SMALL LETTER U WITH DIAERESIS but I
# still think of it as an umlaut
foo.set_uri(unicode_filename, self._bar_txt_uri)
foo.set_uri(unicode_filename, self._bar_txt_uri, self._bar_txt_uri)
_ign, n, baz_file = self.makefile(2)
self._baz_file_uri = baz_file
sub.set_uri(u"baz.txt", baz_file)
sub.set_uri(u"baz.txt", baz_file, baz_file)
_ign, n, self._bad_file_uri = self.makefile(3)
# this uri should not be downloadable
del FakeCHKFileNode.all_contents[self._bad_file_uri]
rodir = res[5][1]
self.public_root.set_uri(u"reedownlee", rodir.get_readonly_uri())
rodir.set_uri(u"nor", baz_file)
self.public_root.set_uri(u"reedownlee", rodir.get_readonly_uri(),
rodir.get_readonly_uri())
rodir.set_uri(u"nor", baz_file, baz_file)
# public/
# public/foo/

View File

@ -204,7 +204,6 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
elif t == "stream-manifest":
d = self._POST_stream_manifest(ctx)
elif t == "set_children":
# TODO: docs
d = self._POST_set_children(req)
else:
raise WebError("POST to a directory with bad t=%s" % t)
@ -303,7 +302,7 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
charset = get_arg(req, "_charset", "utf-8")
name = name.decode(charset)
replace = boolean_of_arg(get_arg(req, "replace", "true"))
d = self.node.set_uri(name, childcap, overwrite=replace)
d = self.node.set_uri(name, childcap, childcap, overwrite=replace)
d.addCallback(lambda res: childcap)
return d
@ -471,8 +470,13 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
cs = []
for name, (file_or_dir, mddict) in children.iteritems():
name = unicode(name) # simplejson-2.0.1 returns str *or* unicode
cap = str(mddict.get('rw_uri') or mddict.get('ro_uri'))
cs.append((name, cap, mddict.get('metadata')))
writecap = mddict.get('rw_uri')
if writecap is not None:
writecap = str(writecap)
readcap = mddict.get('ro_uri')
if readcap is not None:
readcap = str(readcap)
cs.append((name, writecap, readcap, mddict.get('metadata')))
d = self.node.set_children(cs, replace)
d.addCallback(lambda res: "Okay so I did it.")
# TODO: results