]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
remove old filetree code
authorBrian Warner <warner@lothar.com>
Tue, 26 Jun 2007 03:34:19 +0000 (20:34 -0700)
committerBrian Warner <warner@lothar.com>
Tue, 26 Jun 2007 03:34:19 +0000 (20:34 -0700)
13 files changed:
setup.py
src/allmydata/filetree/__init__.py [deleted file]
src/allmydata/filetree/basenode.py [deleted file]
src/allmydata/filetree/directory.py [deleted file]
src/allmydata/filetree/file.py [deleted file]
src/allmydata/filetree/interfaces.py [deleted file]
src/allmydata/filetree/nodemaker.py [deleted file]
src/allmydata/filetree/redirect.py [deleted file]
src/allmydata/filetree/vdrive.py [deleted file]
src/allmydata/test/test_filetree_new.py [deleted file]
src/allmydata/test/test_vdrive.py
src/allmydata/test/test_workqueue.py [deleted file]
src/allmydata/vdrive.py

index 5036b8e49d85a728f3374ece53327f21db4ae533..726dd47b080c64c2b61753c0b6eb3292cb3a43e4 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -79,7 +79,7 @@ majority of the nodes are no longer available.""",
       url='http://allmydata.org/',
       license='GNU GPL',
       packages=["allmydata", "allmydata.test", "allmydata.util",
-                "allmydata.filetree", "allmydata.scripts",],
+                "allmydata.scripts",],
       package_dir={ "allmydata": "src/allmydata",},
       scripts = ["bin/allmydata-tahoe"],
       package_data={ 'allmydata': ['web/*.xhtml', 'web/*.css'] },
diff --git a/src/allmydata/filetree/__init__.py b/src/allmydata/filetree/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/allmydata/filetree/basenode.py b/src/allmydata/filetree/basenode.py
deleted file mode 100644 (file)
index 44ce1d7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-from zope.interface import implements
-from allmydata.filetree.interfaces import INode
-
-class BaseDataNode(object):
-    implements(INode)
-    prefix = None # must be set by subclass
-
-    def new(self, data):
-        self.set_base_data(data)
-        return self
-
-    def get_base_data(self):
-        raise NotImplementedError # must be provided by subclass
-    def set_base_data(self, data):
-        raise NotImplementedError # must be provided by subclass
-    def serialize_node(self):
-        return "%s:%s" % (self.prefix, self.get_base_data())
-    def populate_node(self, body, node_maker):
-        self.set_base_data(body)
-
diff --git a/src/allmydata/filetree/directory.py b/src/allmydata/filetree/directory.py
deleted file mode 100644 (file)
index 32908f9..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-
-from zope.interface import implements
-from twisted.internet import defer
-from cStringIO import StringIO
-from allmydata.filetree.interfaces import (
-    INode, INodeMaker, IDirectoryNode, ISubTree,
-    ICHKDirectoryNode, ISSKDirectoryNode,
-    NoSuchChildError,
-    )
-from allmydata.filetree.basenode import BaseDataNode
-from allmydata import download
-from allmydata.util import bencode
-
-# interesting feature ideas:
-#  pubsub for MutableDirectoryNode: get rapid notification of changes
-#  caused by someone else
-#
-#  bind a local physical directory to the MutableDirectoryNode contents:
-#  each time the vdrive changes, update the local drive to match, and
-#  vice versa.
-
-from itertools import islice, izip
-def in_pairs(iterable):
-    "s -> (s0,s1), (s2,s3), (s4,s5), ..."
-    a = islice(iterable, 0, None, 2)
-    b = islice(iterable, 1, None, 2)
-    return izip(a, b)
-
-
-class SubTreeNode:
-    implements(INode, IDirectoryNode)
-
-    def __init__(self, tree):
-        self.enclosing_tree = tree
-        self.children = {}
-#        # subdirectory_node_children maps child name to another SubTreeNode
-#        # instance. This is only for internal directory nodes. All other
-#        # nodes are listed in child_specifications instead.
-#        self.subdirectory_node_children = {}
-#        # child_specifications maps child name to a specification tuple which
-#        # describes how to obtain the actual child. For example, if "foo.jpg"
-#        # in this node represents a CHK-encoded FILE with a uri of "fooURI",
-#        # then self.child_specifications["foo.jpg"] = ("CHKFILE","fooURI")
-#        self.child_specifications = {}
-
-    def list(self):
-        return self.children
-
-    def get(self, childname):
-        if childname in self.children:
-            return self.children[childname]
-        else:
-            raise NoSuchChildError("no child named '%s'" % (childname,))
-
-    def get_subtree(self):
-        return self.enclosing_tree
-
-    def delete(self, childname):
-        assert self.enclosing_tree.is_mutable()
-        if childname in self.children:
-            del self.children[childname]
-        else:
-            raise NoSuchChildError("no child named '%s'" % (childname,))
-
-    def add_subdir(self, childname):
-        assert childname not in self.children
-        newnode = SubTreeNode(self.enclosing_tree)
-        self.children[childname] = newnode
-        return newnode
-
-    def add(self, childname, node):
-        assert childname not in self.children
-        assert INode(node)
-        self.children[childname] = node
-        return self
-
-    def serialize_node(self):
-        # note: this is a one-pass recursive serialization that will result
-        # in the whole file table being held in memory. This is only
-        # appropriate for directories with fewer than, say, 10k nodes. If we
-        # support larger directories, we should turn this into some kind of
-        # generator instead, and write the serialized data directly to a
-        # tempfile.
-        #
-        # [name1, child1, name2, child2..]
-        #
-        #  child1 is either a list for subdirs, or a string for non-subdirs
-
-        data = []
-        for name in sorted(self.children.keys()):
-            data.append(name)
-            data.append(self.children[name].serialize_node())
-        return data
-
-    def populate_dirnode(self, data, node_maker):
-        assert INodeMaker(node_maker)
-        assert len(data) % 2 == 0
-        for (name, child_data) in in_pairs(data):
-            if isinstance(child_data, (list, tuple)):
-                child = SubTreeNode(self.enclosing_tree)
-                child.populate_dirnode(child_data, node_maker)
-            else:
-                assert isinstance(child_data, str)
-                child = node_maker.make_node_from_serialized(child_data)
-            self.children[name] = child
-
-    def is_leaf_subtree(self):
-        return False
-
-
-class _DirectorySubTree(object):
-    """I represent a set of connected directories that all share the same
-    access control: any given person can read or write anything in this tree
-    as a group, and it is not possible to give access to some pieces of this
-    tree and not to others. Read-only access to individual files can be
-    granted independently, of course, but through an unnamed URI, not as a
-    subdirectory.
-
-    Each internal directory is represented by a separate Node.
-
-    This is an abstract base class. Individual subclasses will implement
-    various forms of serialization, persistence, and mutability.
-
-    """
-    implements(ISubTree)
-
-
-    def new(self):
-        # create a new, empty directory
-        self.root = SubTreeNode(self)
-        self.mutable = True # sure, why not
-        return self
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        # self.populate_from_node must be defined by the subclass (CHK or
-        # SSK), since it controls how the spec is interpreted. It will
-        # probably use the contents of the node to figure out what to
-        # download from the grid, then pass this downloaded serialized data
-        # to populate_from_data()
-        raise NotImplementedError
-
-    def _populate_from_data(self, data, node_maker):
-        self.root = SubTreeNode(self)
-        self.root.populate_dirnode(bencode.bdecode(data), node_maker)
-        return self
-
-    def serialize_subtree_to_file(self, f):
-        sexprs = self.root.serialize_node()
-        bencode.bwrite(sexprs, f)
-
-    def is_mutable(self):
-        return self.mutable
-
-    def get_node_for_path(self, path):
-        # this is restricted to traversing our own subtree. Returns
-        # (found_path, node, remaining_path)
-        found_path = []
-        remaining_path = path[:]
-        node = self.root
-        while remaining_path:
-            name = remaining_path[0]
-            try:
-                childnode = node.get(name)
-            except NoSuchChildError:
-                # The node *would* be in this subtree if it existed, but it
-                # doesn't. Leave found_path and remaining_path alone, and
-                # node points at the last parent node that was on the path.
-                break
-            if IDirectoryNode.providedBy(childnode):
-                # recurse
-                node = childnode
-                found_path.append(name)
-                remaining_path.pop(0)
-                continue
-            else:
-                # the path takes us out of this subtree and into another
-                node = childnode # next subtree node
-                found_path.append(name)
-                remaining_path.pop(0)
-                break
-        return (found_path, node, remaining_path)
-
-    def put_node_at_path(self, path, new_node):
-        assert len(path) > 0
-        child_name = path[-1]
-
-        # first step: get (or create) the parent directory
-        node = self.root
-        for subdir_name in path[:-1]:
-            # TODO: peeking at private attributes is naughty, but using
-            # node.get() and catching NoSuchChildError would be slightly
-            # ugly. Reconsider the IDirectoryNode.get() API.
-            childnode = node.children.get(subdir_name)
-            if childnode:
-                assert IDirectoryNode.providedBy(childnode)
-            else:
-                # we have to create new directories until the parent exists
-                childnode = node.add_subdir(subdir_name)
-            node = childnode
-
-        # 'node' is now pointing at the parent directory
-        if child_name in node.children:
-            # oops, there's already something there. We can replace it.
-            # TODO: How do we free the subtree that was just orphaned?
-            node.delete(child_name)
-
-        # now we can finally add the new node
-        node.add(child_name, new_node)
-
-    def delete_node_at_path(self, path):
-        assert len(path) > 0
-        child_name = path[-1]
-
-        # first step: get the parent directory
-        node = self.root
-        for subdir_name in path[:-1]:
-            subdir_node = node.get(subdir_name) # may raise NoSuchChildError
-            node = subdir_node
-
-        # 'node' is now pointing at the parent directory. Let's make sure the
-        # path they want to delete actually exists. We don't really care what
-        # the child *is*, just that it exists.
-        node.get(child_name) # may raise NoSuchChildError
-
-        # now delete it
-        # TODO: How do we free the subtree that was just orphaned?
-        node.delete(child_name)
-
-
-class LocalFileSubTreeNode(BaseDataNode):
-    prefix = "LocalFileDirectory"
-
-    def new(self, filename):
-        self.filename = filename
-        return self
-
-    def get_base_data(self):
-        return self.filename
-    def set_base_data(self, data):
-        self.filename = data
-
-    def is_leaf_subtree(self):
-        return False
-
-class LocalFileSubTree(_DirectorySubTree):
-    node_class = LocalFileSubTreeNode
-
-    def new(self, filename):
-        self.filename = filename
-        return _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()
-        d = defer.succeed(data)
-        d.addCallback(self._populate_from_data, node_maker)
-        return d
-
-    def mutation_modifies_parent(self):
-        return False
-
-    def create_node_now(self):
-        return LocalFileSubTreeNode().new(self.filename)
-
-    def _update(self):
-        f = open(self.filename, "wb")
-        self.serialize_subtree_to_file(f)
-        f.close()
-
-    def update_now(self, uploader):
-        self._update()
-        return self.create_node_now()
-
-    def update(self, work_queue):
-        # TODO: this may suffer from the same execute-too-early problem as
-        # redirect.LocalFileRedirection
-        self._update()
-        return None
-
-
-class CHKDirectorySubTreeNode(BaseDataNode):
-    implements(ICHKDirectoryNode)
-    prefix = "CHKDirectory"
-
-    def get_base_data(self):
-        return self.uri
-    def set_base_data(self, data):
-        self.uri = data
-
-    def get_uri(self):
-        return self.uri
-
-    def is_leaf_subtree(self):
-        return False
-
-
-class CHKDirectorySubTree(_DirectorySubTree):
-    # maybe mutable, maybe not
-    node_class = CHKDirectorySubTreeNode
-
-    def new(self):
-        self.uri = None
-        return _DirectorySubTree.new(self)
-
-    def set_uri(self, uri):
-        self.uri = uri
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        assert ICHKDirectoryNode(node)
-        self.mutable = parent_is_mutable
-        d = downloader.download(node.get_uri(), download.Data())
-        d.addCallback(self._populate_from_data, node_maker)
-        def _populated(res):
-            self.uri = node.get_uri()
-            return self
-        d.addCallback(_populated)
-        return d
-
-    def mutation_modifies_parent(self):
-        return True
-
-    def create_node_now(self):
-        return CHKDirectorySubTreeNode().new(self.uri)
-
-    def update_now(self, uploader):
-        f = StringIO()
-        self.serialize_subtree_to_file(f)
-        data = f.getvalue()
-        d = uploader.upload_data(data)
-        def _uploaded(uri):
-            self.uri = uri
-            return self.create_node_now()
-        d.addCallback(_uploaded)
-        return d
-
-    def update(self, workqueue):
-        # this is the CHK form
-        old_uri = self.uri
-        f, filename = workqueue.create_tempfile(".chkdir")
-        self.serialize_subtree_to_file(f)
-        f.close()
-        boxname = workqueue.create_boxname()
-        workqueue.add_upload_chk(filename, boxname)
-        workqueue.add_delete_tempfile(filename)
-        workqueue.add_retain_uri_from_box(boxname)
-        workqueue.add_delete_box(boxname)
-        if old_uri:
-            workqueue.add_unlink_uri(old_uri)
-        # TODO: think about how self.old_uri will get updated. I *think* that
-        # this whole instance will get replaced, so it ought to be ok. But
-        # this needs investigation.
-
-        # mutation affects our parent, so we return a boxname for them
-        return boxname
-
-
-class SSKDirectorySubTreeNode(object):
-    implements(INode, ISSKDirectoryNode)
-    prefix = "SSKDirectory"
-
-    def serialize_node(self):
-        data = (self.read_cap, self.write_cap)
-        return "%s:%s" % (self.prefix, bencode.bencode(data))
-    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
-    def get_write_capability(self):
-        return self.write_cap
-    def set_read_capability(self, read_cap):
-        self.read_cap = read_cap
-    def set_write_capability(self, write_cap):
-        self.write_cap = write_cap
-
-    def is_leaf_subtree(self):
-        return False
-
-
-class SSKDirectorySubTree(_DirectorySubTree):
-    node_class = SSKDirectorySubTreeNode
-
-    def new(self):
-        _DirectorySubTree.new(self)
-        self.version = 0
-        # TODO: populate
-        return self
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        node = ISSKDirectoryNode(node)
-        self.read_capability = node.get_read_capability()
-        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)
-        return d
-
-    def set_version(self, version):
-        self.version = version
-
-    def mutation_modifies_parent(self):
-        return False
-
-    def create_node_now(self):
-        node = SSKDirectorySubTreeNode()
-        node.set_read_capability(self.read_capability)
-        node.set_write_capability(self.write_capability)
-        return node
-
-    def update_now(self, uploader):
-        if not self.write_capability:
-            raise RuntimeError("This SSKDirectorySubTree is not mutable")
-
-        f = StringIO()
-        self.serialize_subtree_to_file(f)
-        data = f.getvalue()
-
-        self.version += 1
-        d = uploader.upload_ssk_data(self.write_capability, self.version, data)
-        d.addCallback(lambda ignored: self.create_node_now())
-        return d
-
-    def update(self, workqueue):
-        # this is the SSK form
-        f, filename = workqueue.create_tempfile(".sskdir")
-        self.serialize_subtree_to_file(f)
-        f.close()
-
-        oldversion = self.version
-        self.version = self.version + 1
-
-        workqueue.add_upload_ssk(self.write_capability, oldversion, filename)
-        workqueue.add_delete_tempfile(filename)
-        workqueue.add_retain_ssk(self.read_capability)
-        # mutation does not affect our parent
-        return None
diff --git a/src/allmydata/filetree/file.py b/src/allmydata/filetree/file.py
deleted file mode 100644 (file)
index 25c9e05..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-
-from zope.interface import implements
-from allmydata.filetree.interfaces import INode, IFileNode
-from allmydata.filetree.basenode import BaseDataNode
-from allmydata.util import bencode
-
-class CHKFileNode(BaseDataNode):
-    implements(IFileNode)
-    prefix = "CHKFile"
-
-    def new(self, uri):
-        self.uri = uri
-        return self
-
-    def put_node_at_path(self, path, node):
-        raise RuntimeError
-
-    def get_base_data(self):
-        return self.uri
-    def set_base_data(self, data):
-        self.uri = data
-
-    def get_uri(self):
-        return self.uri
-
-    def is_leaf_subtree(self):
-        return True
-
-class SSKFileNode(object):
-    implements(INode, IFileNode)
-    prefix = "SSKFile"
-
-    def put_node_at_path(self, path, node):
-        raise RuntimeError
-
-    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 get_read_capability(self):
-        return self.read_cap
-    def get_write_capability(self):
-        return self.write_cap
-
-    def is_leaf_subtree(self):
-        return True
-
diff --git a/src/allmydata/filetree/interfaces.py b/src/allmydata/filetree/interfaces.py
deleted file mode 100644 (file)
index 04d18e8..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-
-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
-        INodeMaker.make_node_from_serialized(). For IDirectoryNodes, this
-        will be 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):
-        """INodeMaker.make_node_from_serialized() will first use the prefix
-        from the .prefix attribute to decide what kind of Node to create.
-        They will then call this populate_node() method with the body to
-        populate the new Node. 'node_maker' provides INodeMaker, which
-        provides that same make_node_from_serialized function to create any
-        internal child nodes that might be necessary."""
-
-    def is_leaf_subtree():
-        """Return True if this node does not refer to a traversable
-        subtree. When searching for the node that describes a path, the
-        search will stop at the first leaf node found. IFileNodes should
-        return True here.
-        """
-# TODO: there is a slightly confusing mixture of IDirectoryNodes and all
-# other kinds of nodes. It is convenient to mix them because that way list()
-# can point at nodes of all sorts, but IDirectoryNodes are very different
-# than the rest (because they to not represent distinct subtrees). There
-# might be a better way to factor this.
-
-# TODO: 'node' is a problematic term here. It refers to nodes in the graph of
-# connected subtrees. It also refers to nodes in the graph of directories and
-# links within a single subtree. And the interface named INode is
-# unfortunately a homonym with "inode", the data structure we previously used
-# to represent information about an uploaded file which was too large to keep
-# locally (the list of blockids), which meant the inode itself was uploaded.
-# We no longer use inodes, but using a word that sounds just like it may
-# cause confusion.
-
-class IFileNode(Interface):
-    """This is a file which can be retrieved."""
-    # TODO: not sure which of these to provide.. should URIs contain "CHK" or
-    # "SSK" in them? Or should that be a detail of IDownloader?
-    def get_uri():
-        """Return the URI of the target file. This URI can be passed
-        to an IDownloader to retrieve the data."""
-    def download(downloader, target):
-        """Download the file to the given target (using the provided
-        downloader). Return a deferred that fires (with 'target') when the
-        download is complete."""
-
-class IDirectoryNode(Interface):
-    """This is a directory which can be listed."""
-    # these calls do not modify the subtree
-    def list():
-        """Return a dictionary mapping each childname to a node. These nodes
-        implement various I*Node interfaces depending upon what they can do."""
-    def get(childname):
-        """Return a child node. Raises NoSuchChildError if there is no
-        child of that name."""
-    def get_subtree():
-        """Return the ISubTree which contains this node."""
-
-    # the following calls modify the subtree. After calling them, you must
-    # tell the enclosing subtree to serialize and upload itself. They can
-    # only be called if this directory node is associated with a mutable
-    # subtree.
-    def delete(childname):
-        """Delete any child referenced by this name."""
-    def add_subdir(childname):
-        """Create a new directory node, and return it."""
-    def add(childname, node):
-        """Add a new node to this path. Returns self."""
-
-class ISubTree(Interface):
-    """A subtree is a collection of Nodes: files, directories, other trees.
-
-    A subtree represents a set of connected directories and files that all
-    share the same access control: any given person can read or write
-    anything in this tree as a group, and it is not possible to give access
-    to some pieces of this tree and not to others. Read-only access to
-    individual files can be granted independently, of course, but through an
-    unnamed URI, not as a subdirectory.
-
-    Each internal directory is represented by a separate Node. This might be
-    a DirectoryNode, or it might be a FileNode.
-    """
-
-    # All ISubTree-providing instances must have a class-level attribute
-    # named .node_class which references the matching INode-providing class.
-    # This is used by the ISubTreeMaker to turn nodes into subtrees.
-
-    def populate_from_node(node, parent_is_mutable, node_maker, downloader):
-        """Subtrees are created by ISubTreeMaker.open() being called with an
-        INode which describes both the kind of subtree to be created and a
-        way to obtain its contents. open() uses the node to create a new
-        instance of the appropriate subtree type, then calls this
-        populate_from_node() method.
-
-        Each subtree's populate_from_node() method is expected to use the
-        downloader to obtain a file with the subtree's serialized contents
-        (probably by pulling data from some source, like the grid, the vdrive 
-        server, an HTTP server, or somewhere on the local filesystem), then
-        unserialize them and populate the subtree's state.
-
-        Return a Deferred that will fire (with self) when this subtree is
-        ready for use (specifically when it is ready for get() and add()
-        calls).
-        """
-
-    def is_mutable():
-        """This returns True if we have the ability to modify this subtree.
-        If this returns True, this reference may be adapted to
-        IMutableSubTree to actually exercise these mutation rights.
-        """
-
-    def mutation_modifies_parent():
-        """This returns True if any modification to this subtree will result
-        in it getting a new identity, and thus requiring its parent be
-        notified. This is True for CHKDirectorySubTree, but False for
-        SSKDirectorySubTree and all redirections.
-        """
-
-    def get_node_for_path(path):
-        """Ask this subtree to follow the path through its internal nodes.
-
-        Returns a tuple of (found_path, node, remaining_path). This method
-        operations synchronously, and does not return a Deferred.
-
-        (found_path=path, found_node, [])
-        If the path terminates within this subtree, found_path=path and
-        remaining_path=[], and the node will be an internal IDirectoryNode.
-
-        (found_path, last_node, remaining_path)
-        If the path does not terminate within this subtree but neither does
-        it exit this subtree, the last internal IDirectoryNode that *was* on
-        the path will be returned in 'node'. The path components that led to
-        this node will be in found_path, and the remaining components will be
-        in remaining_path. If you want to create the target node, loop over
-        remaining_path as follows::
-
-         while remaining_path:
-           node = node.add_subdir(remaining_path.pop(0))
-
-        (found_path, exit_node, remaining_path)
-        If the path leaves this subtree, 'node' will be a different kind of
-        INode (probably one that points at a child directory of some sort),
-        found_path will be the components that led to this point, and
-        remaining_path will be the remaining components. If you still wish to
-        locate the target, use 'node' to open a new subtree, then provide
-        'remaining_path' to the new subtree's get_node_for_path() method.
-
-        """
-
-    def put_node_at_path(path, node):
-        """Add the given node to this subtree, at 'path'.
-
-        This may create internal directory subnodes as necessary. This must
-        run synchronously, and returns None.
-        """
-
-    def delete_node_at_path(path):
-        """Delete the node at the the given path.
-
-        This must run synchronously, and returns None.
-        """
-
-    def serialize_subtree_to_file(f):
-        """Create a string which describes my structure and write it to the
-        given filehandle (using only .write()). This string should be
-        suitable for uploading to the grid or storing in a local file."""
-
-    def update_now(uploader):
-        """Perform whatever work is necessary to record this subtree to
-        persistent storage.
-
-        This returns an INode, or a Deferred that fires (with an INode) when
-        the subtree has been persisted.
-
-        For directory subtrees, this will cause the subtree to serialize
-        itself to a file, then upload this file to the grid, then create an
-        INode-providing instance which describes where the file wound up. For
-        redirections, this will cause the subtree to modify the redirection's
-        persistent storage, then return the (unmodified) INode that describes
-        the redirection.
-
-        This form does not use the workqueue. If the node is shut down before
-        the Deferred fires, a redirection or SSK subtree might be left in its
-        previous state, or it might have been updated.
-        """
-
-    def update(workqueue):
-        """Perform and schedule whatever work is necessary to record this
-        subtree to persistent storage.
-
-        Returns a boxname or None, synchronously. This function does not
-        return a Deferred.
-
-        If the parent subtree needs to be modified with the new identity of
-        this subtree (i.e. for CHKDirectorySubTree instances), this will
-        return a boxname in which the serialized INode will be placed once
-        the added workqueue steps have completed. The caller should add
-        'addpath' steps to the workqueue using this boxname (which will
-        eventually cause recursion on other subtrees, until some subtree is
-        updated which does not require notifying the parent). update() will
-        add steps to delete the box at the end of the workqueue.
-
-        If the parent subtree does not need to be modified (i.e. for
-        SSKDirectorySubTree instances, or redirections), this will return
-        None.
-
-        This is like update_now(), but uses the workqueue to insure
-        consistency in the face of node shutdowns. Once our intentions have
-        been recorded in the workqueue, if the node is shut down before the
-        upload steps have completed, the update will eventually complete the
-        next time the node is started.
-        """
-
-    def create_node_now():
-        # TODO: this is no longer just for testing.. vdrive.addpath needs it
-        """FOR TESTING ONLY. Immediately create and return an INode which
-        describes the current state of this subtree. This does not perform
-        any upload or persistence work, and thus depends upon any internal
-        state having been previously set correctly. In general this will
-        return the correct value for subtrees which have just been created
-        (and not yet mutated). It will also return the correct value for
-        subtrees which do not change their identity when they are mutated
-        (SSKDirectorySubTrees and redirections).
-        """
-
-class INodeMaker(Interface):
-    def make_node_from_serialized(serialized):
-        """Turn a string into an INode, which contains information about the
-        file or directory (like a URI), but does not contain the actual
-        contents. An ISubTreeMaker 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)."""
-
-class ISubTreeMaker(Interface):
-    def make_subtree_from_node(node, parent_is_mutable):
-        """Turn an INode into an ISubTree.
-
-        I accept an INode-providing specification of a subtree, and return a
-        Deferred that fires with an ISubTree-providing instance. I will
-        perform network IO and download the serialized data that the INode
-        references, if necessary, or ask the vdrive server (or other provider) 
-        for a pointer, or read it from local disk.
-        """
-
-
-class IVirtualDrive(Interface):
-
-    def __init__(workqueue, downloader, root_node):
-        pass
-
-    # commands to manipulate files
-
-    def list(path):
-        """List the contents of the directory at the given path.
-
-        'path' is a list of strings (empty to refer to the root directory)
-        and must refer to a DIRECTORY node. This method returns a Deferred
-        that fires with a dictionary that maps strings to filetypes. The
-        strings are useful as path name components. The filetypes are
-        Interfaces: either IDirectoryNode if path+[childname] can be used in
-        a 'list' method, or IFileNode if path+[childname] can be used in a
-        'download' method.
-
-        The Deferred will errback (with NoSuchDirectoryError) if the path
-        does not point to an actual directory.
-        """
-
-    def download(path, target):
-        """Download the file at the given path to 'target'.
-
-        'path' must refer to a FILE. 'target' must implement IDownloadTarget.
-        This returns a Deferred that fires (with 'target') when the download
-        is complete.
-        """
-
-    def upload_data(path, data):
-        """Upload a string to the given path. The path must not already exist.
-
-        path[:-1] must refer to a writable DIRECTORY node.
-
-        This uses the workqueue, and returns None.
-        """
-
-    def upload(path, filename):
-        """Upload a file from disk to the given path.
-
-        This uses the workqueue, and returns None.
-        """
-
-    def delete(path):
-        """Delete the file or directory at the given path.
-
-        Returns a Deferred that fires (with self) when the delete is
-        complete.
-        """
-
-    def add_node(path, node):
-        """Add a node to the given path. Use the workqueue.
-        """
-
-    # commands to manipulate subtrees
-
-    # ... detach subtree, merge subtree, etc
-
-
-# TODO
-
-class ICHKDirectoryNode(Interface):
-    def get_uri():
-        pass
-class ISSKDirectoryNode(Interface):
-    def get_read_capability():
-        pass
-    def get_write_capability():
-        pass
-
-
-
-class NoSuchChildError(Exception):
-    pass
-class NoSuchDirectoryError(Exception):
-    pass
-class PathAlreadyExistsError(Exception):
-    pass
-class PathDoesNotExistError(Exception):
-    pass
diff --git a/src/allmydata/filetree/nodemaker.py b/src/allmydata/filetree/nodemaker.py
deleted file mode 100644 (file)
index 05a1364..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-from zope.interface import implements
-from allmydata.filetree import directory, file, redirect
-from allmydata.filetree.interfaces import INodeMaker
-
-# this list is used by NodeMaker to convert node specification strings (found
-# inside the serialized form of subtrees) into Nodes (which live in the
-# in-RAM form of subtrees).
-all_node_types = [
-    directory.LocalFileSubTreeNode,
-    directory.CHKDirectorySubTreeNode,
-    directory.SSKDirectorySubTreeNode,
-    file.CHKFileNode,
-    file.SSKFileNode,
-    redirect.LocalFileRedirectionNode,
-    redirect.VdriveRedirectionNode,
-    redirect.HTTPRedirectionNode,
-    redirect.VdriveOrLocalFileRedirectionNode,
-]
-
-class NodeMaker(object):
-    implements(INodeMaker)
-
-    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 ISubTreeMaker 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)
-                return node
-        raise RuntimeError("unable to handle node type '%s'" % prefix)
-
diff --git a/src/allmydata/filetree/redirect.py b/src/allmydata/filetree/redirect.py
deleted file mode 100644 (file)
index 90bbcc2..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-
-from cStringIO import StringIO
-from zope.interface import implements
-from twisted.internet import defer
-
-from allmydata.filetree.interfaces import ISubTree, INodeMaker
-from allmydata.filetree.basenode import BaseDataNode
-from allmydata.util import bencode
-
-class LocalFileRedirectionNode(BaseDataNode):
-    prefix = "LocalFileRedirection"
-
-    def new(self, handle):
-        self.handle = handle
-        return self
-
-    def get_base_data(self):
-        return self.handle
-    def set_base_data(self, data):
-        self.handle = data
-
-    def is_leaf_subtree(self):
-        return False
-
-class _BaseRedirection(object):
-    implements(ISubTree)
-
-    def new(self, child_node):
-        self.child_node = child_node
-        return self
-
-    def mutation_modifies_parent(self):
-        return False
-
-    def get_node_for_path(self, path):
-        return ([], self.child_node, path)
-
-    def put_node_at_path(self, path, node):
-        assert path == []
-        self.child_node = node
-
-    def serialize_subtree_to_file(self, f):
-        f.write(self.child_node.serialize_node())
-
-    def _populate_from_data(self, data, node_maker):
-        assert INodeMaker(node_maker)
-        self.child_node = node_maker.make_node_from_serialized(data)
-        return self
-
-
-class LocalFileRedirection(_BaseRedirection):
-    node_class = LocalFileRedirectionNode
-
-    def new(self, handle, child_node):
-        self.filename = handle
-        return _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
-
-        assert isinstance(node, LocalFileRedirectionNode)
-        self.filename = node.handle
-        # there is a local file which contains a bencoded serialized subtree
-        # specification.
-
-        # TODO: will this enable outsiders to cause us to read from arbitrary
-        # files? Think about this. It is probably a good idea to restrict the
-        # filename to be a single component, and to always put them in a
-        # well-known directory that contains nothing else, and maybe make
-        # them unguessable.
-        f = open(self.filename, "rb")
-        data = f.read()
-        f.close()
-        # note: we don't cache the contents of the file. TODO: consider
-        # doing this based upon mtime. It is important that we be able to
-        # notice if the file has been changed.
-        d = defer.succeed(data)
-        d.addCallback(self._populate_from_data, node_maker)
-        return d
-
-    def is_mutable(self):
-        return True
-
-    def create_node_now(self):
-        return LocalFileRedirectionNode().new(self.filename)
-
-    def _update(self):
-        f = open(self.filename, "wb")
-        self.serialize_subtree_to_file(f)
-        f.close()
-
-    def update_now(self, uploader):
-        self._update()
-        return self.create_node_now()
-
-    def update(self, workqueue):
-        # TODO: this happens too early, before earlier items in the workqueue
-        # have been executed. This might not be a problem, if our update()
-        # method isn't actually called until everything earlier has been
-        # executed anyways. Need to ponder this.
-        self._update()
-        return None
-
-class VdriveRedirectionNode(LocalFileRedirectionNode):
-    prefix = "VdriveRedirection"
-
-class VdriveRedirection(_BaseRedirection):
-    node_class = VdriveRedirectionNode
-
-    def new(self, handle):
-        self.handle = handle
-        return self
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        # this specifies a handle for which the Vdrive maintains a serialized
-        # subtree specification.
-        assert isinstance(node, VdriveRedirectionNode)
-        self.handle = node.handle
-
-        # TODO: vdrive?
-        d = self._vdrive.callRemote("lookup_handle", self.handle)
-        d.addCallback(self._populate_from_data, node_maker)
-        return d
-
-    def is_mutable(self):
-        return True # TODO: maybe, maybe not
-
-    def create_node_now(self):
-        return VdriveRedirectionNode().new(self.handle)
-
-    def update_now(self, uploader):
-        f = StringIO()
-        self.serialize_subtree_to_file(f)
-        d = self._vdrive.callRemote("set_handle", self.handle, f.getvalue())
-        def _done(res):
-            return self.create_node_now()
-        d.addCallback(_done)
-        return d
-
-    def update(self, workqueue):
-        f, filename = workqueue.create_tempfile(".tovdrive")
-        self.serialize_subtree_to_file(f)
-        f.close()
-        workqueue.add_vdrive_update_handle(self.handle, filename)
-        workqueue.add_delete_tempfile(filename)
-        return None
-
-class VdriveOrLocalFileRedirectionNode(LocalFileRedirectionNode):
-    prefix = "VdriveOrLocalFileRedirection"
-
-class VdriveOrLocalFileRedirection(_BaseRedirection):
-    node_class = VdriveOrLocalFileRedirectionNode
-
-    def new(self, handle, child_node):
-        self.handle = handle
-        self.version = 0
-        self.child_node = child_node
-        # TODO
-        return self
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        # there is a local file which contains a bencoded serialized
-        # subtree specification. The vdrive also has a copy. Whomever has
-        # the higher version number wins.
-        assert isinstance(node, VdriveOrLocalFileRedirectionNode)
-        self.filename = self.handle = node.handle
-
-        f = open(self.filename, "rb")
-        #local_version, local_data = bencode.bdecode(f.read())
-        local_version_and_data = f.read()
-        f.close()
-
-        # TODO: vdrive?
-        # TODO: pubsub so we can cache the vdrive's results
-        d = self._vdrive.callRemote("lookup_handle", self.handle)
-        d.addCallback(self._choose_winner, local_version_and_data)
-        d.addCallback(self._populate_from_data, node_maker)
-        return d
-
-    def _choose_winner(self, vdrive_version_and_data, local_version_and_data):
-        vdrive_version, vdrive_data = bencode.bdecode(vdrive_version_and_data)
-        local_version, local_data = bencode.bdecode(local_version_and_data)
-        if vdrive_version > local_version:
-            data = vdrive_data
-            self.version = vdrive_version
-        else:
-            data = local_data
-            self.version = local_version
-        # NOTE: two layers of bencoding here, TODO
-        return data
-
-    def is_mutable(self):
-        return True
-
-    def create_node_now(self):
-        return VdriveOrLocalFileRedirectionNode().new(self.handle)
-
-    def _update(self):
-        self.version += 1
-        f = StringIO()
-        self.serialize_subtree_to_file(f)
-        version_and_data = bencode.bencode((self.version, f.getvalue()))
-        return version_and_data
-
-    def update_now(self, uploader):
-        version_and_data = self._update()
-        f = open(self.filename, "wb")
-        f.write(version_and_data)
-        f.close()
-
-        d = self._vdrive.callRemote("set_handle", self.handle, version_and_data)
-        def _done(res):
-            return self.create_node_now()
-        d.addCallback(_done)
-        return d
-
-    def update(self, workqueue):
-        version_and_data = self._update()
-        # TODO: this may have the same problem as LocalFileRedirection.update
-        f = open(self.filename, "wb")
-        f.write(version_and_data)
-        f.close()
-
-        f, filename = workqueue.create_tempfile(".tovdrive")
-        self.serialize_subtree_to_file(f)
-        f.close()
-        workqueue.add_vdrive_update_handle(self.handle, filename)
-        workqueue.add_delete_tempfile(filename)
-        return None
-
-class HTTPRedirectionNode(BaseDataNode):
-    prefix = "HTTPRedirection"
-
-    def new(self, url):
-        self.url = url
-        return self
-
-    def get_base_data(self):
-        return self.url
-    def set_base_data(self, data):
-        self.url = data
-
-    def is_leaf_subtree(self):
-        return False
-
-class HTTPRedirection(_BaseRedirection):
-    node_class = HTTPRedirectionNode
-
-    def new(self, url):
-        self.url = url
-
-    def populate_from_node(self, node, parent_is_mutable, node_maker, downloader):
-        # this specifies a URL at which there is a bencoded serialized
-        # subtree specification.
-        self.url = node.url
-        assert isinstance(node, HTTPRedirectionNode)
-        from twisted.web import client
-        d = client.getPage(self.url)
-        d.addCallback(self._populate_from_data, node_maker)
-        return d
-
-    def is_mutable(self):
-        return False
-
-    def create_node_now(self):
-        return HTTPRedirectionNode().new(self.url)
-
-    def update_now(self, uploader):
-        raise RuntimeError("HTTPRedirection is not mutable")
-
-    def update(self, workqueue):
-        raise RuntimeError("HTTPRedirection is not mutable")
diff --git a/src/allmydata/filetree/vdrive.py b/src/allmydata/filetree/vdrive.py
deleted file mode 100644 (file)
index 883a175..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-
-import os.path
-from zope.interface import implements
-from twisted.internet import defer
-from allmydata.filetree import directory, redirect
-from allmydata.filetree.interfaces import (
-    IVirtualDrive, ISubTreeMaker,
-    INodeMaker, INode, ISubTree, IFileNode, IDirectoryNode,
-    NoSuchDirectoryError, NoSuchChildError, PathAlreadyExistsError,
-    PathDoesNotExistError,
-    )
-from allmydata.interfaces import IDownloader, IUploader, IWorkQueue
-
-from allmydata.filetree.nodemaker import NodeMaker
-
-all_openable_subtree_types = [
-    directory.LocalFileSubTree,
-    directory.CHKDirectorySubTree,
-    directory.SSKDirectorySubTree,
-    redirect.LocalFileRedirection,
-    redirect.VdriveRedirection,
-    redirect.VdriveOrLocalFileRedirection,
-    redirect.HTTPRedirection,
-    ]
-
-class SubTreeMaker(object):
-    implements(ISubTreeMaker)
-
-    def __init__(self, downloader):
-        # this is created with everything it might need to download and
-        # create subtrees. That means a Downloader and in the future (?) a 
-       # reference to the vdrive.
-        assert IDownloader(downloader)
-        self._downloader = downloader
-        self._node_maker = NodeMaker()
-        self._cache = {}
-
-    def _create(self, node, parent_is_mutable):
-        assert INode(node)
-        assert INodeMaker(self._node_maker)
-        for subtree_class in all_openable_subtree_types:
-            if isinstance(node, subtree_class.node_class):
-                subtree = subtree_class()
-                d = subtree.populate_from_node(node,
-                                               parent_is_mutable,
-                                               self._node_maker,
-                                               self._downloader)
-                return d
-        raise RuntimeError("unable to handle subtree specification '%s'"
-                           % (node,))
-
-    def make_subtree_from_node(self, node, parent_is_mutable):
-        assert INode(node)
-        assert not isinstance(node, IDirectoryNode)
-
-        # is it in cache? To check this we need to use the node's serialized
-        # form, since nodes are instances and don't compare by value
-        node_s = node.serialize_node()
-        if node_s in self._cache:
-            return defer.succeed(self._cache[node_s])
-
-        d = defer.maybeDeferred(self._create, node, parent_is_mutable)
-        d.addCallback(self._add_to_cache, node_s)
-        return d
-
-    def _add_to_cache(self, subtree, node_s):
-        self._cache[node_s] = subtree
-        # TODO: remove things from the cache eventually
-        return subtree
-
-
-
-class VirtualDrive(object):
-    implements(IVirtualDrive)
-    debug = False
-
-    def __init__(self, workqueue, downloader, uploader, root_node):
-        assert IWorkQueue(workqueue)
-        assert IDownloader(downloader)
-        assert IUploader(uploader)
-        assert INode(root_node)
-        self.workqueue = workqueue
-        workqueue.set_vdrive(self)
-        workqueue.set_uploader(uploader)
-        self._downloader = downloader
-        self._uploader = uploader
-        self.root_node = root_node
-        self.subtree_maker = SubTreeMaker(downloader)
-
-    # these methods are used to walk through our subtrees
-
-    def _get_root(self):
-        return self.subtree_maker.make_subtree_from_node(self.root_node, False)
-
-    def _get_node(self, path):
-        d = self._get_closest_node(path)
-        def _got_node((node, remaining_path)):
-            if remaining_path:
-                return None
-            return node
-        d.addCallback(_got_node)
-        return d
-
-    def _get_closest_node(self, path):
-        """Find the closest directory node parent for the desired path.
-        Return a Deferred that fires with (node, remaining_path).
-        """
-        d = self._get_root()
-        d.addCallback(self._get_closest_node_1, path)
-        return d
-
-    def _get_closest_node_1(self, subtree, path):
-        (found_path, node, remaining_path) = subtree.get_node_for_path(path)
-        parent_is_mutable = subtree.is_mutable()
-        if IDirectoryNode.providedBy(node) or node.is_leaf_subtree():
-            # traversal done
-            return (node, remaining_path)
-        # otherwise, we must open and recurse into a new subtree
-        d = self.subtree_maker.make_subtree_from_node(node, parent_is_mutable)
-        def _opened(next_subtree):
-            next_subtree = ISubTree(next_subtree)
-            return self._get_closest_node_1(next_subtree, remaining_path)
-        d.addCallback(_opened)
-        return d
-
-    def _get_directory(self, path):
-        """Return a Deferred that fires with the IDirectoryNode at the given
-        path, or raise NoSuchDirectoryError if there is no such node. This
-        will traverse subtrees as necessary."""
-        d = self._get_node(path)
-        def _got_directory(node):
-            if not node:
-                raise NoSuchDirectoryError
-            assert IDirectoryNode(node)
-            return node
-        d.addCallback(_got_directory)
-        return d
-
-    def _get_file(self, path):
-        """Return a Deferred that files with an IFileNode at the given path,
-        or raises a NoSuchDirectoryError or NoSuchChildError, or some other
-        error if the path refers to something other than a file."""
-        d = self._get_node(path)
-        def _got_node(node):
-            if not node:
-                raise NoSuchChildError
-            return IFileNode(node)
-        d.addCallback(_got_node)
-        return d
-
-    def _get_file_uri(self, path):
-        d = self._get_file(path)
-        d.addCallback(lambda filenode: filenode.get_uri())
-        return d
-
-    def _child_should_not_exist(self, path):
-        d = self._get_node(path)
-        def _got_node(node):
-            if node is not None:
-                raise PathAlreadyExistsError
-        d.addCallback(_got_node)
-        return d
-
-    def _child_should_exist(self, path):
-        d = self._get_node(path)
-        def _got_node(node):
-            if node is None:
-                raise PathDoesNotExistError
-        d.addCallback(_got_node)
-        return d
-
-    def _get_closest_node_and_prepath(self, path):
-        d = self._get_closest_node(path)
-        def _got_closest((node, remaining_path)):
-            prepath_len = len(path) - len(remaining_path)
-            prepath = path[:prepath_len]
-            assert path[prepath_len:] == remaining_path, "um, path=%s, prepath=%s, prepath_len=%d, remaining_path=%s" % (path, prepath, prepath_len, remaining_path)
-            return (prepath, node, remaining_path)
-        d.addCallback(_got_closest)
-        return d
-
-    def get_subtrees_for_path(self, path):
-        # compute a list of [(subtree1, subpath1), ...], which represents
-        # which parts of 'path' traverse which subtrees. This can be used to
-        # present the virtual drive to the user in a form that includes
-        # redirection nodes (which do not consume path segments), or to
-        # figure out which subtrees need to be updated when the identity of a
-        # lower subtree (i.e. CHK) is changed.
-
-        # TODO: it might be useful to add some items to the return value.
-        # Like if there is a node already present at that path, to return it.
-        d = self._get_root()
-        results = []
-        d.addCallback(self._get_subtrees_for_path_1, results, path)
-        return d
-
-    def _get_subtrees_for_path_1(self, subtree, results, path):
-        (found_path, node, remaining_path) = subtree.get_node_for_path(path)
-        if IDirectoryNode.providedBy(node):
-            # traversal done. We are looking at the final subtree, and the
-            # entire path (found_path + remaining_path) will live in here.
-            r = (subtree, (found_path + remaining_path))
-            results.append(r)
-            return results
-        if node.is_leaf_subtree():
-            # for this assert to fail, we found a File or something where we
-            # were expecting to find another subdirectory.
-            assert len(remaining_path) == 0
-            results.append((subtree, found_path))
-            return results
-        # otherwise we must open and recurse into a new subtree
-        results.append((subtree, found_path))
-        parent_is_mutable = subtree.is_mutable()
-        d = self.subtree_maker.make_subtree_from_node(node, parent_is_mutable)
-        def _opened(next_subtree):
-            next_subtree = ISubTree(next_subtree)
-            return self._get_subtrees_for_path_1(next_subtree, results,
-                                                 remaining_path)
-        d.addCallback(_opened)
-        return d
-
-
-    # these are called by the workqueue
-
-    def addpath_with_node(self, path, new_node):
-        new_node_boxname = self.workqueue.create_boxname(new_node)
-        self.workqueue.add_delete_box(new_node_boxname)
-        return self.addpath(path, new_node_boxname)
-
-    def addpath(self, path, new_node_boxname):
-        # this adds a block of steps to the workqueue which, when complete,
-        # will result in the new_node existing in the virtual drive at
-        # 'path'.
-
-        # First we figure out which subtrees are involved
-        d = self.get_subtrees_for_path(path)
-
-        # then we walk through them from the bottom, arranging to modify them
-        # as necessary
-        def _got_subtrees(subtrees, new_node_boxname):
-            for (subtree, subpath) in reversed(subtrees):
-                if self.debug:
-                    print "SUBTREE", subtree, subpath
-                assert subtree.is_mutable()
-                must_update = subtree.mutation_modifies_parent()
-                subtree_node = subtree.create_node_now()
-                new_subtree_boxname = None
-                if must_update:
-                    new_subtree_boxname = self.workqueue.create_boxname()
-                    self.workqueue.add_delete_box(new_subtree_boxname)
-                    self.workqueue.add_modify_subtree(subtree_node, subpath,
-                                                      new_node_boxname,
-                                                      new_subtree_boxname)
-                    # the box filled by the modify_subtree will be propagated
-                    # upwards
-                    new_node_boxname = new_subtree_boxname
-                else:
-                    # the buck stops here
-                    self.workqueue.add_modify_subtree(subtree_node, subpath,
-                                                      new_node_boxname)
-                    return
-        d.addCallback(_got_subtrees, new_node_boxname)
-        return d
-
-    def deletepath(self, path):
-        if self.debug:
-            print "DELETEPATH(%s)" % (path,)
-        return self.addpath(path, None)
-
-    def modify_subtree(self, subtree_node, localpath, new_node,
-                       new_subtree_boxname=None):
-        # TODO: I'm lying here, we don't know who the parent is, so we can't
-        # really say whether they're mutable or not. But we're pretty sure
-        # that the new subtree is supposed to be mutable, because we asserted
-        # that earlier (although I suppose perhaps someone could change a
-        # VdriveRedirection or an SSK file while we're offline in the middle
-        # of our workqueue..). Tell the new subtree that their parent is
-        # mutable so we can be sure it will believe that it itself is
-        # mutable.
-        parent_is_mutable = True
-        d = self.subtree_maker.make_subtree_from_node(subtree_node,
-                                                      parent_is_mutable)
-        def _got_subtree(subtree):
-            assert subtree.is_mutable()
-            if new_node:
-                subtree.put_node_at_path(localpath, new_node)
-            else:
-                subtree.delete_node_at_path(localpath)
-            return subtree.update_now(self._uploader)
-        d.addCallback(_got_subtree)
-        if new_subtree_boxname:
-            d.addCallback(lambda new_subtree_node:
-                          self.workqueue.write_to_box(new_subtree_boxname,
-                                                      new_subtree_node))
-        return d
-
-
-    # these are user-visible
-
-    def list(self, path):
-        assert isinstance(path, list)
-        d = self._get_directory(path)
-        d.addCallback(lambda node: node.list())
-        return d
-
-    def download(self, path, target):
-        # TODO: does this mean download it right now? or schedule it in the
-        # workqueue for eventual download? should we add download steps to
-        # the workqueue?
-        assert isinstance(path, list)
-        d = self._get_file_uri(path)
-        d.addCallback(lambda uri: self._downloader.download(uri, target))
-        return d
-
-    def download_as_data(self, path):
-        # TODO: this is kind of goofy.. think of a better download API that
-        # is appropriate for this class
-        from allmydata import download
-        target = download.Data()
-        return self.download(path, target)
-
-    def upload_data(self, path, data):
-        assert isinstance(path, list)
-        f, tempfilename = self.workqueue.create_tempfile()
-        f.write(data)
-        f.close()
-        boxname = self.workqueue.create_boxname()
-        self.workqueue.add_upload_chk(tempfilename, boxname)
-        self.workqueue.add_addpath(boxname, path)
-        self.workqueue.add_delete_box(boxname)
-        self.workqueue.add_delete_tempfile(tempfilename)
-
-    def upload(self, path, filename):
-        assert isinstance(path, list)
-        filename = os.path.abspath(filename)
-        boxname = self.workqueue.create_boxname()
-        self.workqueue.add_upload_chk(filename, boxname)
-        self.workqueue.add_addpath(boxname, path)
-        self.workqueue.add_delete_box(boxname)
-
-    def delete(self, path):
-        assert isinstance(path, list)
-        self.workqueue.add_deletepath(path)
-
-    def add_node(self, path, node):
-        assert isinstance(path, list)
-        assert INode(node)
-        assert not IDirectoryNode.providedBy(node)
-        boxname = self.workqueue.create_boxname(node)
-        self.workqueue.add_addpath(boxname, path)
-        self.workqueue.add_delete_box(boxname)
-
diff --git a/src/allmydata/test/test_filetree_new.py b/src/allmydata/test/test_filetree_new.py
deleted file mode 100644 (file)
index 9925fb4..0000000
+++ /dev/null
@@ -1,667 +0,0 @@
-
-from zope.interface import implements
-from twisted.trial import unittest
-from twisted.internet import defer
-from allmydata.interfaces import IDownloader, IUploader
-#from allmydata.filetree.directory import (ImmutableDirectorySubTree,
-#                                          SubTreeNode,
-#                                          CHKDirectorySubTree)
-#from allmydata.filetree.specification import (CHKFileSpecification,
-#                                              CHKDirectorySpecification)
-from allmydata import workqueue
-from cStringIO import StringIO
-
-class FakeGrid(object):
-    implements(IDownloader, IUploader)
-
-"""
-class FakeOpener(object):
-    implements(IOpener)
-    def __init__(self, objects={}):
-        self.objects = objects
-    def open(self, subtree_specification, parent_is_mutable):
-        #print "open", subtree_specification, subtree_specification.serialize(), parent_is_mutable
-        return defer.succeed(self.objects[subtree_specification.serialize()])
-
-
-class FakeWorkQueue(object):
-    implements(workqueue.IWorkQueue)
-    def __init__(self):
-        self.first_commands = []
-        self.last_commands = []
-        self.tempfile_number = 0
-        self.boxname_number = 0
-    def dump_commands(self):
-        return self.first_commands + self.last_commands
-    def clear_commands(self):
-        self.first_commands = []
-        self.last_commands = []
-
-    def create_tempfile(self, suffix=""):
-        self.tempfile_number += 1
-        self.first_commands.append("create_tempfile-%d" % self.tempfile_number)
-        return (StringIO(), "dummy_filename-%d" % self.tempfile_number)
-    def create_boxname(self):
-        self.boxname_number += 1
-        self.first_commands.append("create_boxname-%d" % self.boxname_number)
-        return "dummy_boxname-%d" % self.boxname_number
-    def add_upload_chk(self, source_filename, stash_uri_in_boxname):
-        self.first_commands.append(("upload_chk", source_filename,
-                                    stash_uri_in_boxname))
-    def add_upload_ssk(self, source_filename, write_capability,
-                       previous_version):
-        self.first_commands.append(("upload_ssk", source_filename,
-                                    write_capability, previous_version))
-    def add_retain_ssk(self, read_capability):
-        self.last_commands.append(("retain_ssk", read_capability))
-    def add_unlink_ssk(self, write_capability):
-        self.last_commands.append(("unlink_ssk", write_capability))
-    def add_retain_uri_from_box(self, boxname):
-        self.last_commands.append(("retain_uri_from_box", boxname))
-    def add_addpath(self, boxname, path):
-        self.first_commands.append(("addpath", boxname, path))
-    def add_unlink_uri(self, uri):
-        self.last_commands.append(("unlink_uri", uri))
-    def add_delete_tempfile(self, filename):
-        self.first_commands.append(("delete_tempfile", filename))
-    def add_delete_box(self, boxname):
-        self.last_commands.append(("delete_box", boxname))
-
-
-
-class OneSubTree(unittest.TestCase):
-    def test_create_empty_immutable(self):
-        st = ImmutableDirectorySubTree()
-        st.new()
-        self.failIf(st.is_mutable())
-        d = st.get([], FakeOpener())
-        def _got_root(root):
-            self.failUnless(IDirectoryNode.providedBy(root))
-            self.failUnlessEqual(root.list(), [])
-        d.addCallback(_got_root)
-        return d
-
-    def test_immutable_1(self):
-        st = ImmutableDirectorySubTree()
-        st.new()
-        # now populate it (by modifying the internal data structures) with
-        # some internal directories
-        one = SubTreeNode(st)
-        two = SubTreeNode(st)
-        three = SubTreeNode(st)
-        st.root.node_children["one"] = one
-        st.root.node_children["two"] = two
-        two.node_children["three"] = three
-
-        # now examine it
-        self.failIf(st.is_mutable())
-        o = FakeOpener()
-        d = st.get([], o)
-        def _got_root(root):
-            self.failUnless(IDirectoryNode.providedBy(root))
-            self.failUnlessEqual(root.list(), ["one", "two"])
-        d.addCallback(_got_root)
-        d.addCallback(lambda res: st.get(["one"], o))
-        def _got_one(_one):
-            self.failUnlessIdentical(one, _one)
-            self.failUnless(IDirectoryNode.providedBy(_one))
-            self.failUnlessEqual(_one.list(), [])
-        d.addCallback(_got_one)
-        d.addCallback(lambda res: st.get(["two"], o))
-        def _got_two(_two):
-            self.failUnlessIdentical(two, _two)
-            self.failUnless(IDirectoryNode.providedBy(_two))
-            self.failUnlessEqual(_two.list(), ["three"])
-        d.addCallback(_got_two)
-        d.addCallback(lambda res: st.get(["two", "three"], o))
-        def _got_three(_three):
-            self.failUnlessIdentical(three, _three)
-            self.failUnless(IDirectoryNode.providedBy(_three))
-            self.failUnlessEqual(_three.list(), [])
-        d.addCallback(_got_three)
-        d.addCallback(lambda res: st.get(["missing"], o))
-        d.addCallback(self.failUnlessEqual, None)
-        return d
-
-    def test_mutable_1(self):
-        o = FakeOpener()
-        wq = FakeWorkQueue()
-        st = MutableCHKDirectorySubTree()
-        st.new()
-        st.set_uri(None)
-        self.failUnless(st.is_mutable())
-        d = st.get([], o)
-        def _got_root(root):
-            self.failUnless(IDirectoryNode.providedBy(root))
-            self.failUnlessEqual(root.list(), [])
-        d.addCallback(_got_root)
-        file_three = CHKFileSpecification()
-        file_three.set_uri("file_three_uri")
-        d.addCallback(lambda res: st.add(["one", "two", "three"], file_three,
-                                         o, wq))
-        d.addCallback(lambda res: st.get(["one"], o))
-        def _got_one(one):
-            self.failUnless(IDirectoryNode.providedBy(one))
-            self.failUnlessEqual(one.list(), ["two"])
-        d.addCallback(_got_one)
-        d.addCallback(lambda res: st.get(["one", "two"], o))
-        def _got_two(two):
-            self.failUnless(IDirectoryNode.providedBy(two))
-            self.failUnlessEqual(two.list(), ["three"])
-            self.failUnlessIdentical(two.child_specifications["three"],
-                                     file_three)
-        d.addCallback(_got_two)
-        return d
-
-    def test_addpath(self):
-        o = FakeOpener()
-        wq = FakeWorkQueue()
-        st = MutableCHKDirectorySubTree()
-        st.new()
-        st.set_uri(None)
-        file_three = CHKFileSpecification()
-        file_three.set_uri("file_three_uri")
-        d = st.add(["one", "two", "three"], file_three, o, wq)
-        def _done(res):
-            expected = [
-                "create_tempfile-1",
-                "create_boxname-1",
-                ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
-                ('delete_tempfile', 'dummy_filename-1'),
-                ('addpath', 'dummy_boxname-1', []),
-                ('retain_uri_from_box', 'dummy_boxname-1'),
-                ('delete_box', 'dummy_boxname-1'),
-                ('unlink_uri', None),
-                ]
-            self.failUnlessEqual(wq.dump_commands(), expected)
-            #print
-            #for c in wq.dump_commands():
-            #    print c
-        d.addCallback(_done)
-        return d
-
-    def test_serialize(self):
-        st = ImmutableDirectorySubTree()
-        st.new()
-        one = SubTreeNode(st)
-        two = SubTreeNode(st)
-        three = SubTreeNode(st)
-        st.root.node_children["one"] = one
-        st.root.node_children["two"] = two
-        two.node_children["three"] = three
-        file_four = CHKFileSpecification()
-        file_four.set_uri("file_four_uri")
-        two.child_specifications["four"] = file_four
-        data = st.serialize()
-        st_new = ImmutableDirectorySubTree()
-        st_new.unserialize(data)
-
-        st_four = ImmutableDirectorySubTree()
-        st_four.new()
-        st_four.root.node_children["five"] = SubTreeNode(st_four)
-
-        o = FakeOpener({("CHK-File", "file_four_uri"): st_four})
-        d = st.get([], o)
-        def _got_root(root):
-            self.failUnless(IDirectoryNode.providedBy(root))
-            self.failUnlessEqual(root.list(), ["one", "two"])
-        d.addCallback(_got_root)
-        d.addCallback(lambda res: st.get(["two"], o))
-        def _got_two(_two):
-            self.failUnless(IDirectoryNode.providedBy(_two))
-            self.failUnlessEqual(_two.list(), ["four", "three"])
-        d.addCallback(_got_two)
-
-        d.addCallback(lambda res: st.get(["two", "four"], o))
-        def _got_four(_four):
-            self.failUnless(IDirectoryNode.providedBy(_four))
-            self.failUnlessEqual(_four.list(), ["five"])
-        d.addCallback(_got_four)
-
-class MultipleSubTrees(unittest.TestCase):
-
-    def test_open(self):
-        st = ImmutableDirectorySubTree()
-        st.new()
-        # populate it with some internal directories and child links and see
-        # if we can follow them
-        one = SubTreeNode(st)
-        two = SubTreeNode(st)
-        three = SubTreeNode(st)
-        st.root.node_children["one"] = one
-        st.root.node_children["two"] = two
-        two.node_children["three"] = three
-
-    def test_addpath(self):
-        wq = FakeWorkQueue()
-        st1 = MutableCHKDirectorySubTree()
-        st1.new()
-        st1.set_uri(None)
-        one = SubTreeNode(st1)
-        two = SubTreeNode(st1)
-        st1.root.node_children["one"] = one
-        one.node_children["two"] = two
-        three = CHKDirectorySpecification()
-        three.set_uri("dir_three_uri")
-        two.child_specifications["three"] = three
-
-        st2 = MutableCHKDirectorySubTree()
-        st2.new()
-        st2.set_uri(None)
-        four = SubTreeNode(st2)
-        five = SubTreeNode(st2)
-        st2.root.node_children["four"] = four
-        four.node_children["five"] = five
-
-        file_six = CHKFileSpecification()
-        file_six.set_uri("file_six_uri")
-
-        o = FakeOpener({("CHK-Directory", "dir_three_uri"): st2})
-
-        d = defer.succeed(None)
-        d.addCallback(lambda res:
-                      st1.get(["one", "two", "three", "four", "five"], o))
-        def _got_five(res):
-            self.failUnless(IDirectoryNode.providedBy(res))
-            self.failUnlessIdentical(res, five)
-        d.addCallback(_got_five)
-
-        d.addCallback(lambda res:
-                      st1.add(["one", "two", "six"],
-                              file_six, o, wq))
-        def _done(res):
-            expected = [
-                "create_tempfile-1",
-                "create_boxname-1",
-                ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
-                ('delete_tempfile', 'dummy_filename-1'),
-                # one/two/six only modifies the top-most CHKDirectory, so
-                # the addpath that gets scheduled is targeted at the root
-                ('addpath', 'dummy_boxname-1', []),
-                ('retain_uri_from_box', 'dummy_boxname-1'),
-                ('delete_box', 'dummy_boxname-1'),
-                ('unlink_uri', None),
-                ]
-            self.failUnlessEqual(wq.dump_commands(), expected)
-            wq.clear_commands()
-        d.addCallback(_done)
-
-        d.addCallback(lambda res:
-                      st1.add(["one", "two", "three", "four", "six"],
-                              file_six, o, wq))
-        def _done2(res):
-            expected = [
-                "create_tempfile-2",
-                "create_boxname-2",
-                ('upload_chk', 'dummy_filename-2', 'dummy_boxname-2'),
-                ('delete_tempfile', 'dummy_filename-2'),
-                # one/two/three/four/six modifies the lower CHKDirectory, so
-                # we schedule an addpath of the link that points from the
-                # upper CHKDirectory to the lower one (at one/two/three).
-                ('addpath', 'dummy_boxname-2', ["one", "two", "three"]),
-                ('retain_uri_from_box', 'dummy_boxname-2'),
-                ('delete_box', 'dummy_boxname-2'),
-                ('unlink_uri', None),
-                ]
-            self.failUnlessEqual(wq.dump_commands(), expected)
-        d.addCallback(_done2)
-
-
-        return d
-
-del OneSubTree
-del MultipleSubTrees
-
-class Redirect(unittest.TestCase):
-    pass
-"""
-
-import os.path
-from twisted.python.failure import Failure
-from allmydata.filetree import directory, redirect, vdrive
-from allmydata.filetree.interfaces import (ISubTree, INode, IDirectoryNode,
-                                           IFileNode, NoSuchDirectoryError,
-                                           NoSuchChildError)
-from allmydata.filetree.file import CHKFileNode
-from allmydata import upload
-from allmydata.interfaces import IDownloader
-from allmydata.util import bencode
-
-class Utils(unittest.TestCase):
-    def test_in_pairs(self):
-        l = range(8)
-        pairs = list(directory.in_pairs(l))
-        self.failUnlessEqual(pairs, [(0,1), (2,3), (4,5), (6,7)])
-
-class FakeGrid(object):
-    implements(IDownloader, IUploader)
-    debug = False
-
-    def __init__(self):
-        self.files = {}
-
-    def upload(self, uploadable):
-        uri = "stub-uri-%d" % len(self.files)
-        if self.debug:
-            print "FakeGrid.upload -> %s" % uri
-        assert upload.IUploadable.providedBy(uploadable)
-        f = uploadable.get_filehandle()
-        data = f.read()
-        uploadable.close_filehandle(f)
-        self.files[uri] = data
-        return defer.succeed(uri)
-
-    def upload_filename(self, filename):
-        if self.debug:
-            print "FakeGrid.upload_filename(%s)" % filename
-        return self.upload(upload.FileName(filename))
-
-    def upload_data(self, data):
-        if self.debug:
-            print "FakeGrid.upload_data(%s)" % data
-        return self.upload(upload.Data(data))
-
-    def download(self, uri, target):
-        if self.debug:
-            print "FakeGrid.download(%s)" % uri
-        target.open()
-        target.write(self.files[uri])
-        target.close()
-        return defer.maybeDeferred(target.finish)
-
-
-class VDrive(unittest.TestCase):
-
-    def makeVirtualDrive(self, basedir, root_node=None, grid=None):
-        wq = workqueue.WorkQueue(os.path.join("test_filetree",
-                                              "VDrive",
-                                              basedir, "1.workqueue"))
-        if grid:
-            assert IUploader.providedBy(grid)
-            assert IDownloader.providedBy(grid)
-            dl = ul = grid
-        else:
-            dl = ul = FakeGrid()
-        if not root_node:
-            root_node = directory.LocalFileSubTreeNode()
-            root_node.new("rootdirtree.save")
-        v = vdrive.VirtualDrive(wq, dl, ul, root_node)
-        return v
-
-    def makeLocalTree(self, basename):
-        # create a LocalFileRedirection pointing at a LocalFileSubTree.
-        # Returns a VirtualDrive instance.
-        topdir = directory.LocalFileSubTree().new("%s-dirtree.save" % basename)
-        topdir.update_now(None)
-        root = redirect.LocalFileRedirection().new("%s-root" % basename,
-                                                   topdir.create_node_now())
-        root.update_now(None)
-        v = self.makeVirtualDrive("%s-vdrive" % basename,
-                                  root.create_node_now())
-        return v
-
-    def makeCHKTree(self, basename):
-        # create a LocalFileRedirection pointing at a CHKDirectorySubTree.
-        # Returns a VirtualDrive instance.
-        grid = FakeGrid()
-        topdir = directory.CHKDirectorySubTree().new()
-        d = topdir.update_now(grid)
-        def _updated(topnode):
-            root = redirect.LocalFileRedirection()
-            root.new("%s-root" % basename, topnode)
-            return root.update_now(grid)
-        d.addCallback(_updated)
-        d.addCallback(lambda rootnode:
-                      self.makeVirtualDrive("%s-vdrive" % basename,
-                                            rootnode, grid))
-        return d
-
-    def failUnlessListsAreEqual(self, list1, list2):
-        self.failUnlessEqual(sorted(list1), sorted(list2))
-
-    def failUnlessContentsAreEqual(self, c1, c2):
-        c1a = dict([(k,v.serialize_node()) for k,v in c1.items()])
-        c2a = dict([(k,v.serialize_node()) for k,v in c2.items()])
-        self.failUnlessEqual(c1a, c2a)
-
-    def testDirectory(self):
-        stm = vdrive.SubTreeMaker(FakeGrid())
-
-        # create an empty directory (stored locally)
-        subtree = directory.LocalFileSubTree()
-        subtree.new("dirtree.save")
-        self.failUnless(ISubTree.providedBy(subtree))
-
-        # get the root IDirectoryNode (which is still empty) and examine it
-        (found_path, root, remaining_path) = subtree.get_node_for_path([])
-        self.failUnlessEqual(found_path, [])
-        self.failUnlessEqual(remaining_path, [])
-        self.failUnless(INode.providedBy(root))
-        self.failUnless(IDirectoryNode.providedBy(root))
-        self.failUnlessListsAreEqual(root.list().keys(), [])
-        self.failUnlessIdentical(root.get_subtree(), subtree)
-
-        # now add some children to it
-        subdir1 = root.add_subdir("subdir1")
-        file1 = CHKFileNode()
-        file1.new("uri1")
-        root.add("foo.txt", file1)
-        self.failUnlessListsAreEqual(root.list().keys(),
-                                     ["foo.txt", "subdir1"])
-        self.failUnlessIdentical(root.get("foo.txt"), file1)
-        subdir1a = root.get("subdir1")
-        self.failUnlessIdentical(subdir1, subdir1a)
-        del subdir1a
-        self.failUnless(IDirectoryNode.providedBy(subdir1))
-        self.failUnlessListsAreEqual(subdir1.list().keys(), [])
-        self.failUnlessIdentical(subdir1.get_subtree(), subtree)
-
-        subdir2 = subdir1.add_subdir("subdir2")
-        subdir3 = subdir2.add_subdir("subdir3")
-        subdir4 = subdir2.add_subdir("subdir4")
-
-        subdir2.delete("subdir4")
-        self.failUnlessListsAreEqual(subdir2.list().keys(), ["subdir3"])
-
-        del root, subdir1, subdir2, subdir3, subdir4
-        # leaving file1 for later use
-
-        # now serialize it and examine the results
-        f = StringIO()
-        subtree.serialize_subtree_to_file(f)
-        data = f.getvalue()
-        #print data
-        unpacked = bencode.bdecode(data)
-        #print unpacked
-        del f, data, unpacked
-
-        node = subtree.create_node_now()
-        self.failUnless(isinstance(node, directory.LocalFileSubTreeNode))
-        node_s = node.serialize_node()
-        self.failUnless(isinstance(node_s, str))
-        self.failUnless(node_s.startswith("LocalFileDirectory:"))
-        self.failUnless("dirtree.save" in node_s)
-        del node, node_s
-
-        d = defer.maybeDeferred(subtree.update_now, None)
-        def _updated(node):
-            # now reconstruct it
-            return stm.make_subtree_from_node(node, False)
-        d.addCallback(_updated)
-
-        def _opened(new_subtree):
-            res = new_subtree.get_node_for_path([])
-            (found_path, root, remaining_path) = res
-            self.failUnlessEqual(found_path, [])
-            self.failUnlessEqual(remaining_path, [])
-            self.failUnless(INode.providedBy(root))
-            self.failUnless(IDirectoryNode.providedBy(root))
-            self.failUnlessListsAreEqual(root.list().keys(),
-                                         ["foo.txt", "subdir1"])
-            file1a = root.get("foo.txt")
-            self.failUnless(INode(file1a))
-            self.failUnless(isinstance(file1a, CHKFileNode))
-            self.failUnless(IFileNode(file1a))
-            self.failUnlessEqual(file1a.get_uri(), "uri1")
-            subdir1 = root.get("subdir1")
-            subdir2 = subdir1.get("subdir2")
-            self.failUnlessListsAreEqual(subdir2.list().keys(), ["subdir3"])
-            subdir2.delete("subdir3")
-            self.failUnlessListsAreEqual(subdir2.list().keys(), [])
-        d.addCallback(_opened)
-        return d
-
-    def shouldFail(self, res, expected_failure, which):
-        if isinstance(res, Failure):
-            res.trap(expected_failure)
-        else:
-            self.fail("%s was supposed to raise %s, not get '%s'" %
-                      (which, expected_failure, res))
-
-    def testVdrive(self):
-        v = self.makeLocalTree("vdrive")
-
-        d = v.list([])
-        def _listed(contents):
-            self.failUnlessEqual(contents, {})
-        d.addCallback(_listed)
-
-        child1 = CHKFileNode().new("uri1")
-        d.addCallback(lambda res: v.add_node(["a"], child1))
-        d.addCallback(lambda res: v.workqueue.flush())
-        d.addCallback(lambda res: v.list([]))
-        def _listed2(contents):
-            self.failUnlessListsAreEqual(contents.keys(), ["a"])
-            self.failUnlessContentsAreEqual(contents, {"a": child1})
-        d.addCallback(_listed2)
-        child2 = CHKFileNode().new("uri2")
-        child3 = CHKFileNode().new("uri3")
-        d.addCallback(lambda res: v.add_node(["b","c"], child2))
-        d.addCallback(lambda res: v.add_node(["b","d"], child3))
-        d.addCallback(lambda res: v.workqueue.flush())
-        d.addCallback(lambda res: v.list([]))
-        def _listed3(contents):
-            self.failUnlessListsAreEqual(contents.keys(), ["a","b"])
-        d.addCallback(_listed3)
-        d.addCallback(lambda res: v.list(["b"]))
-        def _listed4(contents):
-            self.failUnlessListsAreEqual(contents.keys(), ["c","d"])
-            self.failUnlessContentsAreEqual(contents,
-                                            {"c": child2, "d": child3})
-        d.addCallback(_listed4)
-
-        d.addCallback(lambda res: v._get_file_uri(["b","c"]))
-        d.addCallback(self.failUnlessEqual, "uri2")
-
-        d.addCallback(lambda res: v.list(["bogus"]))
-        d.addBoth(self.shouldFail, NoSuchDirectoryError, "list(bogus)")
-
-        d.addCallback(lambda res: v._get_file_uri(["b", "bogus"]))
-        d.addBoth(self.shouldFail, NoSuchChildError, "_get_file_uri(b/bogus)")
-
-        return d
-
-    def testUpload(self):
-        v = self.makeLocalTree("upload")
-        filename = "upload1"
-        DATA = "here is some data\n"
-        f = open(filename, "wb")
-        f.write(DATA)
-        f.close()
-
-        rc = v.upload(["a","b","upload1"], filename)
-        self.failUnlessIdentical(rc, None)
-
-        d = v.workqueue.flush()
-
-        d.addCallback(lambda res: v.list([]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["a"]))
-        d.addCallback(lambda res: v.list(["a"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["b"]))
-        d.addCallback(lambda res: v.list(["a","b"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(),
-                                                   ["upload1"]))
-        d.addCallback(lambda res: v.download_as_data(["a","b","upload1"]))
-        d.addCallback(self.failUnlessEqual, DATA)
-
-        return d
-
-    def testCHKDirUpload(self):
-        DATA = "here is some data\n"
-        filename = "upload1"
-        f = open(filename, "wb")
-        f.write(DATA)
-        f.close()
-
-        d = defer.maybeDeferred(self.makeCHKTree, "chk-upload")
-        def _made(v):
-            self.v = v
-
-            rc = v.upload(["a","b","upload1"], filename)
-            self.failUnlessIdentical(rc, None)
-
-            return v.workqueue.flush()
-        d.addCallback(_made)
-
-        d.addCallback(lambda res: self.v.list([]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["a"]))
-        d.addCallback(lambda res: self.v.list(["a"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["b"]))
-        d.addCallback(lambda res: self.v.list(["a","b"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(),
-                                                   ["upload1"]))
-        d.addCallback(lambda res: self.v.download_as_data(["a","b","upload1"]))
-        d.addCallback(self.failUnlessEqual, DATA)
-
-        return d
-
-    def testCHKDirDelete(self):
-        DATA = "here is some data\n"
-        filename = "upload1"
-        f = open(filename, "wb")
-        f.write(DATA)
-        f.close()
-
-        d = defer.maybeDeferred(self.makeCHKTree, "chk-delete")
-        def _made(v):
-            self.v = v
-        d.addCallback(_made)
-
-        d.addCallback(lambda r:
-                      self.v.upload(["a","b","upload1"], filename))
-        d.addCallback(lambda r:
-                      self.v.upload_data(["a","b","upload2"], DATA))
-        d.addCallback(lambda r:
-                      self.v.upload(["a","c","upload3"], filename))
-        d.addCallback(lambda r:
-                      self.v.workqueue.flush())
-
-        d.addCallback(lambda r: self.v.list([]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["a"]))
-        d.addCallback(lambda r: self.v.list(["a"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(), ["b","c"]))
-        d.addCallback(lambda r: self.v.list(["a","b"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(),
-                                                   ["upload1", "upload2"]))
-        #d.addCallback(lambda r: self.v.download_as_data(["a","b","upload1"]))
-        #d.addCallback(self.failUnlessEqual, DATA)
-
-        # now delete it
-        d.addCallback(lambda r: self.v.delete(["a","b","upload2"]))
-        d.addCallback(lambda r: self.v.workqueue.flush())
-        d.addCallback(lambda r: self.v.list(["a","b"]))
-        d.addCallback(lambda contents:
-                      self.failUnlessListsAreEqual(contents.keys(),
-                                                   ["upload1"]))
-
-
-        return d
index 472bffcdc05f29ac69e31a29600a77eaf12d428d..4ae201a9c61f7e7e51f914967909372ae302e1ec 100644 (file)
@@ -255,61 +255,3 @@ class Test(unittest.TestCase):
                              sorted(expected_keys))
         return res
 
-
-"""
-class Traverse(unittest.TestCase):
-    def make_tree(self, basedir):
-        os.makedirs(basedir)
-        root = LocalDirNode(basedir)
-        self.d1 = d1 = root.add_directory("d1")
-        self.d2 = d2 = root.add_directory("d2")
-        root.add_file("a", "a")
-        root.add_file("b", "b")
-        d1.add_file("1.a", "1.a")
-        d1.add_file("1.b", "1.b")
-        d2.add_file("2.a", "2.a")
-        d2.add_file("2.b", "2.b")
-        return root
-
-    def test_one(self):
-        basedir = "test_vdrive/one"
-        root = self.make_tree(basedir)
-        v = vdrive.VDrive()
-        v.set_root(root)
-
-        d = v.get_dir("")
-        d.addCallback(lambda dir: self.failUnlessEqual(dir, root))
-        d.addCallback(lambda res: v.get_dir("/d1"))
-        def _check(dir):
-            self.failUnless(isinstance(dir, LocalDirNode))
-            self.failUnlessEqual(dir._basedir, self.d1._basedir)
-        d.addCallback(_check)
-
-        
-        d.addCallback(lambda res: v.listdir(""))
-        d.addCallback(lambda files:
-                      self.failUnlessEqual(sorted(files),
-                                           ["a", "b", "d1", "d2"]))
-        d.addCallback(lambda res: v.listdir("/"))
-        d.addCallback(lambda files:
-                      self.failUnlessEqual(sorted(files),
-                                           ["a", "b", "d1", "d2"]))
-        d.addCallback(lambda res: v.listdir("d1"))
-        d.addCallback(lambda files:
-                      self.failUnlessEqual(sorted(files),
-                                           ["1.a", "1.b"]))
-
-        d.addCallback(lambda res: v.make_directory("", "d3"))
-        d.addCallback(lambda res: v.listdir(""))
-        d.addCallback(lambda files:
-                      self.failUnlessEqual(sorted(files),
-                                           ["a", "b", "d1", "d2", "d3"]))
-
-        d.addCallback(lambda res: v.make_directory("d2", "d2.1"))
-        d.addCallback(lambda res: v.listdir("/d2"))
-        d.addCallback(lambda files:
-                      self.failUnlessEqual(sorted(files),
-                                           ["2.a", "2.b", "d2.1"]))
-        return d
-del Traverse
-"""
diff --git a/src/allmydata/test/test_workqueue.py b/src/allmydata/test/test_workqueue.py
deleted file mode 100644 (file)
index 6f20594..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-
-import os
-from twisted.trial import unittest
-from twisted.internet import defer
-from allmydata import workqueue
-from allmydata.util import idlib
-from allmydata.filetree.file import CHKFileNode
-
-class FakeWorkQueue(workqueue.WorkQueue):
-
-    def __init__(self, basedir):
-        workqueue.WorkQueue.__init__(self, basedir)
-        self.dispatched_steps = []
-
-    def dispatch_step(self, steptype, lines):
-        self.dispatched_steps.append((steptype, lines))
-        return defer.succeed(None)
-
-class Reuse(unittest.TestCase):
-    def wq(self, testname):
-        return FakeWorkQueue("test_workqueue/Reuse/%s/workqueue" % testname)
-
-    def testOne(self):
-        wq = self.wq("testOne")
-        # steps must be retained from one session to the next
-        wq.add_upload_chk("source_filename", "box1")
-        wq.add_unlink_uri("someuri")
-        # files in the tmpdir are not: these are either in the process of
-        # being added or in the process of being removed.
-        tmpfile = os.path.join(wq.tmpdir, "foo")
-        f = open(tmpfile, "wb")
-        f.write("foo")
-        f.close()
-        # files created with create_tempfile *are* retained, however
-        f, filename = wq.create_tempfile()
-        filename = os.path.join(wq.filesdir, filename)
-        f.write("bar")
-        f.close()
-
-        del wq
-        wq2 = self.wq("testOne")
-        steps = wq2.get_all_steps()
-        self.failUnlessEqual(steps[0], ("upload_chk",
-                                        ["source_filename", "box1"]))
-        self.failUnlessEqual(steps[1], ("unlink_uri", ["someuri"]))
-        self.failIf(os.path.exists(tmpfile))
-        self.failUnless(os.path.exists(filename))
-
-
-class Items(unittest.TestCase):
-    def wq(self, testname):
-        return FakeWorkQueue("test_workqueue/Items/%s/workqueue" % testname)
-
-    def testTempfile(self):
-        wq = self.wq("testTempfile")
-        (f, filename) = wq.create_tempfile(".chkdir")
-        self.failUnless(filename.endswith(".chkdir"))
-        data = "this is some random data: %s\n" % idlib.b2a(os.urandom(15))
-        f.write(data)
-        f.close()
-        f2 = wq.open_tempfile(filename)
-        data2 = f2.read()
-        f2.close()
-        self.failUnlessEqual(data, data2)
-
-    def testBox(self):
-        wq = self.wq("testBox")
-        boxname = wq.create_boxname()
-        wq.write_to_box(boxname, CHKFileNode().new("uri goes here"))
-        out = wq.read_from_box(boxname)
-        self.failUnless(isinstance(out, CHKFileNode))
-        self.failUnlessEqual(out.get_uri(), "uri goes here")
-
-    def testCHK(self):
-        wq = self.wq("testCHK")
-        wq.add_upload_chk("source_filename", "box1")
-        wq.add_retain_uri_from_box("box1")
-        wq.add_addpath("box1", ["home", "warner", "foo.txt"])
-        wq.add_delete_box("box1")
-        wq.add_unlink_uri("olduri")
-
-        self.failUnlessEqual(wq.count_pending_steps(), 5)
-        stepname, steptype, lines = wq.get_next_step()
-        self.failUnlessEqual(steptype, "upload_chk")
-        steps = wq.get_all_steps()
-        self.failUnlessEqual(steps[0], ("upload_chk",
-                                        ["source_filename", "box1"]))
-        self.failUnlessEqual(steps[1], ("retain_uri_from_box",
-                                        ["box1"]))
-        self.failUnlessEqual(steps[2], ("addpath",
-                                        ["box1", "home", "warner", "foo.txt"]))
-        self.failUnlessEqual(steps[3], ("delete_box",
-                                        ["box1"]))
-        self.failUnlessEqual(steps[4], ("unlink_uri",
-                                        ["olduri"]))
-
-    def testCHK2(self):
-        wq = self.wq("testCHK2")
-        wq.add_upload_chk("source_filename", "box1")
-        wq.add_retain_uri_from_box("box1")
-        wq.add_addpath("box1", ["home", "warner", "foo.txt"])
-        wq.add_delete_box("box1")
-        wq.add_unlink_uri("olduri")
-
-        # then this batch happens a bit later
-        (f, tmpfilename) = wq.create_tempfile(".chkdir")
-        f.write("some data")
-        f.close()
-        wq.add_upload_chk(os.path.join(wq.filesdir, tmpfilename), "box2")
-        wq.add_delete_tempfile(tmpfilename)
-        wq.add_retain_uri_from_box("box2")
-        wq.add_delete_box("box2")
-        wq.add_unlink_uri("oldchk")
-
-        self.failUnlessEqual(wq.count_pending_steps(), 10)
-        steps = wq.get_all_steps()
-
-        self.failUnlessEqual(steps[0], ("upload_chk",
-                                        ["source_filename", "box1"]))
-        self.failUnlessEqual(steps[1], ("retain_uri_from_box",
-                                        ["box1"]))
-        self.failUnlessEqual(steps[2], ("addpath",
-                                        ["box1", "home", "warner", "foo.txt"]))
-        self.failUnlessEqual(steps[3],
-                             ("upload_chk",
-                              [os.path.join(wq.filesdir, tmpfilename),
-                               "box2"]))
-        self.failUnlessEqual(steps[4],
-                             ("retain_uri_from_box", ["box2"]))
-        self.failUnlessEqual(steps[5], ("delete_box",
-                                        ["box1"]))
-        self.failUnlessEqual(steps[6], ("unlink_uri",
-                                        ["olduri"]))
-        self.failUnlessEqual(steps[7],
-                             ("delete_tempfile", [tmpfilename]))
-        self.failUnlessEqual(steps[8], ("delete_box", ["box2"]))
-        self.failUnlessEqual(steps[9], ("unlink_uri", ["oldchk"]))
-
-    def testRun(self):
-        wq = self.wq("testRun")
-        wq.add_upload_chk("source_filename", "box1")
-        wq.add_retain_uri_from_box("box1")
-        wq.add_addpath("box1", ["home", "warner", "foo.txt"])
-        wq.add_delete_box("box1")
-        wq.add_unlink_uri("olduri")
-
-        # this tempfile should be deleted after the last step completes
-        (f, tmpfilename) = wq.create_tempfile(".dummy")
-        tmpfilename = os.path.join(wq.filesdir, tmpfilename)
-        f.write("stuff")
-        f.close()
-        self.failUnless(os.path.exists(tmpfilename))
-        # likewise this unreferenced box should get deleted
-        boxname = wq.create_boxname()
-        wq.write_to_box(boxname, CHKFileNode().new("uri here"))
-        boxfile = os.path.join(wq.boxesdir, boxname)
-        self.failUnless(os.path.exists(boxfile))
-
-        d = wq.flush()
-        def _check(res):
-            self.failUnlessEqual(len(wq.dispatched_steps), 5)
-            self.failUnlessEqual(wq.dispatched_steps[0][0], "upload_chk")
-            self.failIf(os.path.exists(tmpfilename))
-            self.failIf(os.path.exists(boxfile))
-        d.addCallback(_check)
-        return d
index bd11576c599ea6355489d6ad000130c46ed4fa5f..8a30e932fda8ef0bf7f4f5aa69693e574e517bbf 100644 (file)
@@ -3,10 +3,8 @@
 
 import os.path
 from zope.interface import implements
-from twisted.application import service
 from twisted.internet import defer
-from twisted.python import log
-from allmydata import upload, download, uri
+from allmydata import uri
 from allmydata.Crypto.Cipher import AES
 from allmydata.util import hashutil, idlib
 from allmydata.interfaces import IDirectoryNode, IFileNode
@@ -14,179 +12,6 @@ from allmydata.interfaces import IDirectoryNode, IFileNode
 class NotMutableError(Exception):
     pass
 
-class VDrive(service.MultiService):
-    name = "vdrive"
-
-    def set_server(self, vdrive_server):
-        self.gvd_server = vdrive_server
-    def set_root(self, root):
-        self.gvd_root = root
-
-    def dirpath(self, dir_or_path):
-        if isinstance(dir_or_path, str):
-            return self.get_dir(dir_or_path)
-        return defer.succeed(dir_or_path)
-
-    def get_dir(self, path):
-        """Return a Deferred that fires with a RemoteReference to a
-        MutableDirectoryNode at the given /-delimited path."""
-        d = defer.succeed(self.gvd_root)
-        if path.startswith("/"):
-            path = path[1:]
-        if path == "":
-            return d
-        for piece in path.split("/"):
-            d.addCallback(lambda parent: parent.callRemote("list"))
-            def _find(table, subdir):
-                for name,target in table:
-                    if name == subdir:
-                        return target
-                else:
-                    raise KeyError("no such directory '%s' in '%s'" %
-                                   (subdir, [t[0] for t in table]))
-            d.addCallback(_find, piece)
-        def _check(subdir):
-            assert not isinstance(subdir, str), "Hey, %s shouldn't be a string" % subdir
-            return subdir
-        d.addCallback(_check)
-        return d
-
-    def get_uri_from_parent(self, parent, filename):
-        assert not isinstance(parent, str), "'%s' isn't a directory node" % (parent,)
-        d = parent.callRemote("list")
-        def _find(table):
-            for name,target in table:
-                if name == filename:
-                    assert isinstance(target, str), "Hey, %s isn't a file" % filename
-                    return target
-            else:
-                raise KeyError("no such file '%s' in '%s'" %
-                               (filename, [t[0] for t in table]))
-        d.addCallback(_find)
-        return d
-
-    def get_root(self):
-        return self.gvd_root
-
-    def listdir(self, dir_or_path):
-        d = self.dirpath(dir_or_path)
-        d.addCallback(lambda parent: parent.callRemote("list"))
-        def _list(table):
-            return [t[0] for t in table]
-        d.addCallback(_list)
-        return d
-
-    def put_file(self, dir_or_path, name, uploadable):
-        """Upload an IUploadable and add it to the virtual drive (as an entry
-        called 'name', in 'dir_or_path') 'dir_or_path' must either be a
-        string like 'root/subdir1/subdir2', or a directory node (either the
-        root directory node returned by get_root(), or a subdirectory
-        returned by list() ).
-
-        The uploadable can be an instance of allmydata.upload.Data,
-        FileHandle, or FileName.
-
-        I return a deferred that will fire when the operation is complete.
-        """
-
-        log.msg("putting file to '%s'" % name)
-        ul = self.parent.getServiceNamed("uploader")
-        d = self.dirpath(dir_or_path)
-        def _got_dir(dirnode):
-            d1 = ul.upload(uploadable)
-            def _add(uri):
-                d2 = dirnode.callRemote("add_file", name, uri)
-                d2.addCallback(lambda res: uri)
-                return d2
-            d1.addCallback(_add)
-            return d1
-        d.addCallback(_got_dir)
-        def _done(res):
-            log.msg("finished putting file to '%s'" % name)
-            return res
-        d.addCallback(_done)
-        return d
-
-    def put_file_by_filename(self, dir_or_path, name, filename):
-        return self.put_file(dir_or_path, name, upload.FileName(filename))
-    def put_file_by_data(self, dir_or_path, name, data):
-        return self.put_file(dir_or_path, name, upload.Data(data))
-    def put_file_by_filehandle(self, dir_or_path, name, filehandle):
-        return self.put_file(dir_or_path, name, upload.FileHandle(filehandle))
-
-    def make_directory(self, dir_or_path, name):
-        d = self.dirpath(dir_or_path)
-        d.addCallback(lambda parent: parent.callRemote("add_directory", name))
-        return d
-
-    def remove(self, parent, name):
-        assert not isinstance(parent, str)
-        log.msg("vdrive removing %s" % name)
-        # first find the uri
-        d = self.get_uri_from_parent(parent, name)
-        def _got_uri(vid):
-            # TODO: delete the file's shares using this
-            pass
-        d.addCallback(_got_uri)
-        def _delete_from_parent(res):
-            return parent.callRemote("remove", name)
-        d.addCallback(_delete_from_parent)
-        def _done(res):
-            log.msg("vdrive done removing %s" % name)
-        d.addCallback(_done)
-        return d
-
-
-    def get_file(self, dir_and_name_or_path, download_target):
-        """Retrieve a file from the virtual drive and put it somewhere.
-
-        The file to be retrieved may either be specified as a (dir, name)
-        tuple or as a full /-delimited pathname. In the former case, 'dir'
-        can be either a DirectoryNode or a pathname.
-
-        The download target must be an IDownloadTarget instance like
-        allmydata.download.Data, .FileName, or .FileHandle .
-        """
-
-        log.msg("getting file from %s" % (dir_and_name_or_path,))
-        dl = self.parent.getServiceNamed("downloader")
-
-        if isinstance(dir_and_name_or_path, tuple):
-            dir_or_path, name = dir_and_name_or_path
-            d = self.dirpath(dir_or_path)
-            def _got_dir(dirnode):
-                return self.get_uri_from_parent(dirnode, name)
-            d.addCallback(_got_dir)
-        else:
-            rslash = dir_and_name_or_path.rfind("/")
-            if rslash == -1:
-                # we're looking for a file in the root directory
-                dir = self.gvd_root
-                name = dir_and_name_or_path
-                d = self.get_uri_from_parent(dir, name)
-            else:
-                dirpath = dir_and_name_or_path[:rslash]
-                name = dir_and_name_or_path[rslash+1:]
-                d = self.dirpath(dirpath)
-                d.addCallback(lambda dir:
-                              self.get_uri_from_parent(dir, name))
-
-        def _got_uri(uri):
-            return dl.download(uri, download_target)
-        d.addCallback(_got_uri)
-        def _done(res):
-            log.msg("finished getting file")
-            return res
-        d.addCallback(_done)
-        return d
-
-    def get_file_to_filename(self, from_where, filename):
-        return self.get_file(from_where, download.FileName(filename))
-    def get_file_to_data(self, from_where):
-        return self.get_file(from_where, download.Data())
-    def get_file_to_filehandle(self, from_where, filehandle):
-        return self.get_file(from_where, download.FileHandle(filehandle))
-
 
 def create_directory_node(client, diruri):
     assert uri.is_dirnode_uri(diruri)