[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

test the on-disk wc

From: Sam TH <sam_at_uchicago.edu>
Date: 2001-04-19 17:41:48 CEST

Ok, I couldn't use os.path.walk, but I've written some python code to
build a tree of the same type I mentioned yesterday out of the actual
files on the disk. You just make a call like this:

      tree = svn_tree.build_tree_from_wc(wc-path)

and voila, it works. I've attached a patch to xml_tests.py, which
includes a new test (which passes, yay) using this method, and the new
version of svn_tree.py.

Index: xml_tests.py
===================================================================
RCS file: /cvs/subversion/subversion/tests/clients/cmdline/xml_tests.py,v
retrieving revision 1.2
diff -u -r1.2 xml_tests.py
--- xml_tests.py 2001/04/16 22:18:01 1.2
+++ xml_tests.py 2001/04/19 15:26:30
@@ -158,12 +158,36 @@
 
   return 0 # final success
 
+#-----------------------------------------------------------------------------
 
+def xml_test_3():
+ """checkout a wc from co1-inline.xml - 2"""
+
+ import svn_tree
+
+ wc_dir = 'wc-t3'
+
+ # actually do the check out
+ svn_test_main.run_svn ('co', '-d', wc_dir, \
+ '--xml-file', XML_DIR + '/co1-inline.xml', \
+ '-r 1', ANCESTOR_PATH)
+
+
+ exp_tree = svn_tree.build_tree_from_paths(greek_paths)
+ result_tree = svn_tree.build_tree_from_wc(wc_dir)
+
+ if svn_tree.compare_trees(exp_tree, result_tree):
+ return 0
+ else:
+ return 1
+
+
 ########################################################################
 ## List all tests here, starting with None:
 test_list = [ None,
               xml_test_1,
- xml_test_2
+ xml_test_2,
+ xml_test_3
              ]
 
 ## And run the main test routine on them:

----- new file begins here

#!/usr/bin/env python
#
# svn_tree.py: tools for comparing directory trees
#
# Subversion is a tool for revision control.
# See http://subversion.tigris.org for more information.
#
# ====================================================================
# Copyright (c) 2001 Sam Tobin-Hochstadt. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
######################################################################

# A node in the directory tree.
#
# If CHILDREN is None, then the node is a file.
# Otherwise, CHILDREN is a list of the nodes making up that
# directorie's children.
#
# NAME is simply the name of the file of directory

class SVNTreeNode:
    def __init__(self, name, children=None):
        self.name = name
        self.children = children

    def __cmp__(self, other):
        "Allows comparison on trees. Only compares the names."

        # could this be rewritten as 'return
        # self.name.__cmp__(other.name)' ??
        if self.name == other.name:
            return 0
        if self.name > other.name:
            return 1
        else:
            return -1

    def add_child(self, newchild):
        """Add a child to a node. If the child already exists. merget
        the new node's children with the current child node's
        children. The merge is done recursively."""
        if self.children is None:
            self.children = []
        n = 0
        for a in self.children:
            if a.name == newchild.name:
                n = 1
                break
        if n == 0:
            self.children.append(newchild)
        elif not (newchild.children is None):
            for i in newchild.children:
                a.add_child(i)

# reserved name of the root of the tree

root_node_name = "__SVN_ROOT_NODE"

# Exception raised if you screw up in this module.

class SVNTreeError(Exception): pass

# Exception raised if two trees are unequal

class SVNTreeUnequal(Exception): pass

########################################################################
# Code for handling creating trees from lists of pathnames. This will
# most likely be used for generating expected trees. Also useful for
# handling the output of SVN commands
#

def create_from_path(path):
    """Create and return a new tree, given a path representing a single
    entry into that tree."""
    # internal use only

    # get a list of all the names in the path
    # each of these will be a child of the former
    elements = path.split("/")
    if len(elements) == 0:
        raise SVNTreeError

    root_node = SVNTreeNode(elements[0], None)

    add_elements_as_path(root_node, elements[1:])

    return root_node

def add_elements_as_path(top_node, path_list):
    """Add the elements in PATH as if they were a single path below
    TOP_NODE."""
    
    # The idea of this function is to take a list like so:
    # ['A', 'B', 'C'] and a top node, say 'Z', and generate a tree
    # like this:
    #
    # Z -> A -> B -> C
    #
    # where 1 -> 2 means 2 is a child of 1.
    #
    # It's sort of hard to describe clearly, but it's quite useful.
    
    prev_node = top_node
    for i in path_list:
        new_node = SVNTreeNode(i, None)
        prev_node.add_child(new_node)
        prev_node = new_node

def build_tree_from_paths(paths):
    "Take PATHS and create a tree from them."

    root = SVNTreeNode(root_node_name, None)
    
    for i in paths:
        root.add_child(create_from_path(i))

    return root

#######################################################################
# Code for creating trees from the actual on-disk files. This is the
# most fundamental result, and (obviously) the most important for SVN
# to get right.
#

import os.path # lots of stuff
import os
import copy

def handle_dir(path, current_parent):

    # get a list of all the files

    all_files = os.listdir(path)
    files = []
    dirs = []

    # put dirs and files in their own lists, and remove SVN dirs

    for f in all_files:
        f = os.path.join(path, f)
        if os.path.isdir(f) and os.path.basename(f) != 'SVN':
            dirs.append(f)
        elif os.path.isfile(f):
            files.append(f)

    # add each file as a child of CURRENT_PARENT

    for f in files:
        current_parent.add_child(SVNTreeNode(os.path.basename(f)))

    # for each subdir, create a node, walk its tree, add it as a child

    for d in dirs:
        new_dir_node = SVNTreeNode(os.path.basename(d))
        handle_dir(d, new_dir_node)
        current_parent.add_child(new_dir_node)

def build_tree_from_wc(wc_path):
    """Takes WC_PATH as the path to a working copy. Walks the tree below
    that path, and creates the tree based on the actual found
    files."""

    root = SVNTreeNode(root_node_name, None)

    # Walk the tree recursively
    handle_dir(os.path.normpath(wc_path), root)

    return root

#######################################################################
# Code for handling trees generally.
#

def compare_trees(a, b):
    """Check whether A and B are the equal as trees. This comparison
    does not take into account the order of children."""
    try:
        if a.name != b.name:
            print "Error: %s is not the same as %s." % (a.name, b.name)
            raise SVNTreeUnequal
        if a.children is None:
            if b.children is None:
                # They are both files with the same name, and so are equal.
                return 1
            else:
                # A is a file and B is a dir.
                raise SVNTreeUnequal
        if b.children is None:
            # B is a file and A is a dir.
            raise SVNTreeUnequal

        # order of children doesn't matter
        a.children.sort()
        b.children.sort()
        for i in range(max(len(a.children), len(b.children))):
            compare_trees(a.children[i], b.children[i])
    except IndexError:
        # We ran off the end of one of the lists
        print "Error: unequal number of children"
        # Propogate the error upward
        raise SVNTreeUnequal
    except SVNTreeUnequal:
        if a.name == root_node_name:
            return 0
        else:
            # TODO Some nice pretty-printing of structure here
            print "Unequal at node %s" % a.name
            raise SVNTreeUnequal
    return 1

    

def dump_tree(n,indent=""):
    "Print out a nice representation of the tree."
    # Code partially stolen from Dave Beazley

    # We have to take the len(n.children), so we use a substitute.
    if n.children is None:
        tmp_children = []
    else:
        tmp_children = n.children

    if n.name == root_node_name:
        print "%s%s" % (indent, "Top of the tree")
    else:
        print "%s%s" % (indent, n.name)

    # Shift the lines over
    indent = indent.replace("-"," ")
    indent = indent.replace("+"," ")
    for i in range(len(tmp_children)):
        c = tmp_children[i]
        if i == len(tmp_children)-1:
            # We're at the end of the list
            dump_tree(c,indent + " +-- ")
        else:
            dump_tree(c,indent + " |-- ")

#########################################
## Test code -- to be removed

greek_paths = ['iota', 'A', 'A/mu', 'A/B', 'A/B/lambda', 'A/B/E',
               'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/C', 'A/D',
               'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
               'A/D/H', 'A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega']

greek_paths2 = ['iota', 'A', 'A/mu', 'A/B', 'A/B/lambda', 'A/B/E',
                'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
                'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/C', 'A/D',
                'A/D/H', 'A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega']

greek_paths3 = ['iota', 'A', 'A/mu', 'A/B', 'A/B/lambda', 'A/B/E',
                'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
                'A/B/E/alpha', 'A/B/E/beta', 'A/B/F', 'A/C', 'A/D',
                'A/D/H', 'A/D/H/chi', 'A/D/H/psi', 'A/D/H/omegafoo']

if __name__ == '__main__':
    # We were invoked on the command line
    test_tree = build_tree_from_paths(greek_paths)
    test_tree2 = build_tree_from_paths(greek_paths2)
    test_tree3 = build_tree_from_paths(greek_paths3)
    
    dump_tree(test_tree)
    dump_tree(test_tree2)
    
    if 1 == compare_trees(test_tree, test_tree3):
        print "they are equal"
    else:
        print "they are not equal"

### End of file.
# local variables:
# eval: (load-file "../../../svn-dev.el")
# end:
    

           
sam th --- sam_at_uchicago.edu --- http://www.abisource.com/~sam/
OpenPGP Key: CABD33FC --- http://samth.dyndns.org/key
DeCSS: http://samth.dyndns.org/decss

  • application/pgp-signature attachment: stored
Received on Sat Oct 21 14:36:29 2006

This is an archived mail posted to the Subversion Dev mailing list.