mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-20 17:52:50 +00:00
filetree: refactor INode serialization, start on tests
This commit is contained in:
parent
e843abe542
commit
c808d5a5ef
@ -12,7 +12,6 @@ class BaseDataNode(object):
|
||||
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)
|
||||
|
||||
|
@ -124,6 +124,7 @@ class _DirectorySubTree(object):
|
||||
|
||||
|
||||
def new(self):
|
||||
# create a new, empty directory
|
||||
self.root = SubTreeNode(self)
|
||||
self.mutable = True # sure, why not
|
||||
|
||||
@ -135,7 +136,7 @@ class _DirectorySubTree(object):
|
||||
# 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
|
||||
@ -176,6 +177,35 @@ class _DirectorySubTree(object):
|
||||
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"
|
||||
@ -199,7 +229,7 @@ class CHKDirectorySubTree(_DirectorySubTree):
|
||||
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):
|
||||
@ -228,10 +258,8 @@ class SSKDirectorySubTreeNode(object):
|
||||
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
|
||||
@ -252,7 +280,7 @@ class SSKDirectorySubTree(_DirectorySubTree):
|
||||
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):
|
||||
|
@ -4,16 +4,21 @@ from zope.interface import Interface
|
||||
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."""
|
||||
|
@ -14,6 +14,9 @@ all_openable_subtree_types = [
|
||||
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):
|
||||
|
@ -37,6 +37,10 @@ class _BaseRedirection(object):
|
||||
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
|
||||
|
@ -28,9 +28,29 @@ class VirtualDrive(object):
|
||||
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):
|
||||
@ -127,25 +147,6 @@ class VirtualDrive(object):
|
||||
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):
|
||||
|
@ -1,17 +1,17 @@
|
||||
|
||||
"""
|
||||
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={}):
|
||||
@ -311,3 +311,28 @@ del MultipleSubTrees
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user