From e2ffc3dc03df8d73a4c43e3ac48ad9077bbbd82a Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 12 Oct 2009 16:51:26 -0700 Subject: [PATCH] dirnode.set_uri/set_children: change signature to take writecap+readcap instead of a single cap. The webapi t=set_children call benefits too. --- src/allmydata/dirnode.py | 29 +++++++---------- src/allmydata/interfaces.py | 32 ++++++++++--------- src/allmydata/test/test_deepcheck.py | 4 +-- src/allmydata/test/test_dirnode.py | 47 ++++++++++++++++++---------- src/allmydata/test/test_system.py | 10 ++++-- src/allmydata/test/test_web.py | 21 +++++++------ src/allmydata/web/directory.py | 12 ++++--- 7 files changed, 88 insertions(+), 67 deletions(-) diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py index cacb0ade..20faef2e 100644 --- a/src/allmydata/dirnode.py +++ b/src/allmydata/dirnode.py @@ -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) diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py index e582ee20..ce6bc5b2 100644 --- a/src/allmydata/interfaces.py +++ b/src/allmydata/interfaces.py @@ -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. - - 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() ). + 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 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): diff --git a/src/allmydata/test/test_deepcheck.py b/src/allmydata/test/test_deepcheck.py index e1cb3871..be3f35a6 100644 --- a/src/allmydata/test/test_deepcheck.py +++ b/src/allmydata/test/test_deepcheck.py @@ -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, "") diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py index fcd53702..aee125bf 100644 --- a/src/allmydata/test/test_dirnode.py +++ b/src/allmydata/test/test_dirnode.py @@ -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) diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py index 166a72f7..ed99d795 100644 --- a/src/allmydata/test/test_system.py +++ b/src/allmydata/test/test_system.py @@ -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")) diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index f829abaf..b3573dc4 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -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/ diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py index d1d9faad..89b08725 100644 --- a/src/allmydata/web/directory.py +++ b/src/allmydata/web/directory.py @@ -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 -- 2.45.2