raise NotImplementedError # must be provided by subclass
def serialize_node(self):
return "%s:%s" % (self.prefix, self.get_base_data())
- def populate_node(self, data, node_maker):
- assert data.startswith(self.prefix + ":")
- self.set_base_data(data[len(self.prefix)+1:])
+ def populate_node(self, body, node_maker):
+ self.set_base_data(body)
def new(self):
+ # create a new, empty directory
self.root = SubTreeNode(self)
self.mutable = True # sure, why not
# to populate_from_data()
raise NotImplementedError
- def populate_from_data(self, data, node_maker):
+ def _populate_from_data(self, data, node_maker):
self.root = SubTreeNode(self)
self.root.populate_node(bencode.bdecode(data), node_maker)
return self
break
return (found_path, node, remaining_path)
+class LocalFileSubTreeNode(BaseDataNode):
+ prefix = "LocalFileDirectory"
+
+ def new(self, filename):
+ self.filename = filename
+
+ def get_base_data(self):
+ return self.filename
+ def set_base_data(self, data):
+ self.filename = data
+
+class LocalFileSubTree(_DirectorySubTree):
+ def new(self, filename):
+ self.filename = filename
+ _DirectorySubTree.new(self)
+
+ def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
+ self.mutable = True # probably
+ self.filename = node.filename
+ f = open(self.filename, "rb")
+ data = f.read()
+ f.close()
+ return defer.succeed(self._populate_from_data(node_maker))
+
+ def update(self, prepath, work_queue):
+ f = open(self.filename, "wb")
+ self.serialize_to_file(f)
+ f.close()
+
class CHKDirectorySubTreeNode(BaseDataNode):
implements(ICHKDirectoryNode)
prefix = "CHKDirectory"
assert ICHKDirectoryNode(node)
self.mutable = parent_is_mutable
d = downloader.download(node.get_uri(), download.Data())
- d.addCallback(self.populate_from_data, node_maker)
+ d.addCallback(self._populate_from_data, node_maker)
return d
def update(self, prepath, work_queue):
def serialize_node(self):
data = (self.read_cap, self.write_cap)
return "%s:%s" % (self.prefix, bencode.bencode(data))
- def populate_node(self, data, node_maker):
- assert data.startswith(self.prefix + ":")
- capdata = data[len(self.prefix)+1:]
- self.read_cap, self.write_cap = bencode.bdecode(capdata)
+ def populate_node(self, body, node_maker):
+ self.read_cap, self.write_cap = bencode.bdecode(body)
def get_read_capability(self):
return self.read_cap
self.write_capability = node.get_write_capability()
self.mutable = bool(self.write_capability)
d = downloader.download_ssk(self.read_capability, download.Data())
- d.addCallback(self.populate_from_data, node_maker)
+ d.addCallback(self._populate_from_data, node_maker)
return d
def set_version(self, version):
class INode(Interface):
"""This is some sort of retrievable node. All objects which implement
other I*Node interfaces also implement this one."""
+
+ # the INode-implementing class must have an attribute named .prefix which
+ # contains a string.
+
def serialize_node():
"""Return a data structure which contains enough information to build
this node again in the future (by calling
vdrive.make_node_from_serialized(). For IDirectoryNodes, this will be
- a list. For all other nodes this will be a string."""
- def populate_node(data, node_maker):
- """vdrive.make_node_from_serialized() will first use the prefix
- inside 'data' to decide what kind of Node to create. It will then
- call this function to populate the new Node from the data returned by
- serialize_node."""
+ a list. For all other nodes this will be a string of the form
+ 'prefix:body', where 'prefix' must be the same as the class attribute
+ .prefix ."""
+ def populate_node(body, node_maker):
+ """vdrive.make_node_from_serialized() will first use the prefix from
+ the .prefix attribute to decide what kind of Node to create. It will
+ then call this function with the body to populate the new Node."""
class IFileNode(Interface):
"""This is a file which can be retrieved."""
redirect.QueenOrLocalFileRedirection,
]
+# the Opener can turn an INode (which describes a subtree, like a directory
+# or a redirection) into the fully-populated subtree.
+
class Opener(object):
implements(interfaces.IOpener)
def __init__(self, queen, downloader):
class LocalFileRedirection(_BaseRedirection):
stype = "LocalFileRedirection"
+ def new(self, handle, child_node):
+ self.filename = handle
+ _BaseRedirection.new(self, child_node)
+
def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
# return a Deferred that fires (with self) when this node is ready
# for use
self.workqueue = workqueue
workqueue.set_vdrive(self)
# TODO: queen?
+ self.queen = None
self.opener = opener.Opener(self.queen, downloader)
self.root_node = root_node
+ # these are called when loading and creating nodes
+ def make_node_from_serialized(self, serialized):
+ # this turns a string into an INode, which contains information about
+ # the file or directory (like a URI), but does not contain the actual
+ # contents. An IOpener can be used later to retrieve the contents
+ # (which means downloading the file if this is an IFileNode, or
+ # perhaps creating a new subtree from the contents)
+
+ # maybe include parent_is_mutable?
+ assert isinstance(serialized, str)
+ prefix, body = serialized.split(":", 2)
+
+ for node_class in all_node_types:
+ if prefix == node_class.prefix:
+ node = node_class()
+ node.populate_node(body, self.make_node_from_serialized)
+ return node
+ raise RuntimeError("unable to handle subtree type '%s'" % prefix)
+
# these methods are used to walk through our subtrees
def _get_root(self):
d.addCallback(_got_closest)
return d
- # these are called when loading and creating nodes
- def make_node_from_serialized(self, serialized):
- # this turns a string into an INode, which contains information about
- # the file or directory (like a URI), but does not contain the actual
- # contents. An IOpener can be used later to retrieve the contents
- # (which means downloading the file if this is an IFileNode, or
- # perhaps creating a new subtree from the contents)
-
- # maybe include parent_is_mutable?
- assert isinstance(serialized, str)
- colon = serialized.index(":")
- prefix = serialized[:colon]
- for node_class in all_node_types:
- if prefix == node_class.prefix:
- node = node_class()
- node.populate_node(serialized, self.make_node_from_serialized)
- return node
- raise RuntimeError("unable to handle subtree type '%s'" % prefix)
-
# these are called by the workqueue
def add(self, path, new_node):
-"""
from zope.interface import implements
from twisted.trial import unittest
from twisted.internet import defer
from allmydata.filetree.interfaces import IOpener, IDirectoryNode
-from allmydata.filetree.directory import (ImmutableDirectorySubTree,
+from allmydata.filetree.directory import (#ImmutableDirectorySubTree,
SubTreeNode,
CHKDirectorySubTree)
-from allmydata.filetree.specification import (CHKFileSpecification,
- CHKDirectorySpecification)
+#from allmydata.filetree.specification import (CHKFileSpecification,
+# CHKDirectorySpecification)
from allmydata import workqueue
from cStringIO import StringIO
+"""
class FakeOpener(object):
implements(IOpener)
def __init__(self, objects={}):
class Redirect(unittest.TestCase):
pass
"""
+
+from allmydata.filetree import directory, redirect, vdrive
+
+class Load(unittest.TestCase):
+
+ def testCreate(self):
+ # create some stuff, see if we can import everything
+ wq = workqueue.WorkQueue("test_filetree_new/Load/1.workqueue")
+ dl = None
+
+ # create an empty directory (stored locally) as our root
+ root = directory.LocalFileSubTree()
+ root.new("dirtree.save")
+
+ # and a node to point to it
+ root_node = directory.LocalFileSubTreeNode()
+ root_node.new("dirtree.save")
+
+ v = vdrive.VirtualDrive(wq, dl, root_node)
+
+ def start():
+ root_node = redirect.LocalFileRedirectionNode()
+ root_node.new("handle", dirtree)
+ root = redirect.LocalFileRedirection()
+ # wow, bootstrapping is hard