⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.py

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 PY
📖 第 1 页 / 共 2 页
字号:
#!/usr/bin/env python##  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, 2006 CollabNet.  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.#######################################################################import reimport stringimport os.pathimport main  # the general svntest routines in this module.from svntest import Failure# Tree Exceptions.# All tree exceptions should inherit from SVNTreeErrorclass SVNTreeError(Failure):  "Exception raised if you screw up in the tree module."  passclass SVNTreeUnequal(SVNTreeError):  "Exception raised if two trees are unequal."  passclass SVNTreeIsNotDirectory(SVNTreeError):  "Exception raised if get_child is passed a file."  passclass SVNTypeMismatch(SVNTreeError):  "Exception raised if one node is file and other is dir"  pass#========================================================================# ===>  Overview of our Datastructures  <===# The general idea here is that many, many things can be represented by# a tree structure:#   - a working copy's structure and contents#   - the output of 'svn status'#   - the output of 'svn checkout/update'#   - the output of 'svn commit'# The idea is that a test function creates a "expected" tree of some# kind, and is then able to compare it to an "actual" tree that comes# from running the Subversion client.  This is what makes a test# automated; if an actual and expected tree match exactly, then the test# has passed.  (See compare_trees() below.)# The SVNTreeNode class is the fundamental data type used to build tree# structures.  The class contains a method for "dropping" a new node# into an ever-growing tree structure. (See also create_from_path()).# We have four parsers in this file for the four use cases listed above:# each parser examines some kind of input and returns a tree of# SVNTreeNode objects.  (See build_tree_from_checkout(),# build_tree_from_commit(), build_tree_from_status(), and# build_tree_from_wc()).  These trees are the "actual" trees that result# from running the Subversion client.# Also necessary, of course, is a convenient way for a test to create an# "expected" tree.  The test *could* manually construct and link a bunch# of SVNTreeNodes, certainly.  But instead, all the tests are using the# build_generic_tree() routine instead.# build_generic_tree() takes a specially-formatted list of lists as# input, and returns a tree of SVNTreeNodes.  The list of lists has this# structure:#   [ ['/full/path/to/item', 'text contents', {prop-hash}, {att-hash}],#     [...],#     [...],#     ...   ]# You can see that each item in the list essentially defines an# SVNTreeNode.  build_generic_tree() instantiates a SVNTreeNode for each# item, and then drops it into a tree by parsing each item's full path.# So a typical test routine spends most of its time preparing lists of# this format and sending them to build_generic_tree(), rather than# building the "expected" trees directly.#   ### Note: in the future, we'd like to remove this extra layer of#   ### abstraction.  We'd like the SVNTreeNode class to be more#   ### directly programmer-friendly, providing a number of accessor#   ### routines, so that tests can construct trees directly.# The first three fields of each list-item are self-explanatory.  It's# the fourth field, the "attribute" hash, that needs some explanation.# The att-hash is used to place extra information about the node itself,# depending on the parsing context:#   - in the 'svn co/up' use-case, each line of output starts with two#     characters from the set of (A, D, G, U, C, _) or 'Restored'.  The#     status code is stored in a attribute named 'status'.  In the case#     of a restored file, the word 'Restored' is stored in an attribute#     named 'verb'.#   - in the 'svn ci/im' use-case, each line of output starts with one#      of the words (Adding, Deleting, Sending).  This verb is stored in#      an attribute named 'verb'.#   - in the 'svn status' use-case (which is always run with the -v#     (--verbose) flag), each line of output contains a working revision#     number and a two-letter status code similar to the 'svn co/up'#     case.  This information is stored in attributes named 'wc_rev'#     and 'status'.  The repository revision is also printed, but it#     is ignored.#   - in the working-copy use-case, the att-hash is ignored.# Finally, one last explanation: the file 'actions.py' contain a number# of helper routines named 'run_and_verify_FOO'.  These routines take# one or more "expected" trees as input, then run some svn subcommand,# then push the output through an appropriate parser to derive an# "actual" tree.  Then it runs compare_trees() and raises an exception# on failure.  This is why most tests typically end with a call to# run_and_verify_FOO().#========================================================================# A node in a tree.## If CHILDREN is None, then the node is a file.  Otherwise, CHILDREN# is a list of the nodes making up that directory's children.## NAME is simply the name of the file or directory.  CONTENTS is a# string that contains the file's contents (if a file), PROPS are# properties attached to files or dirs, and ATTS is a dictionary of# other metadata attached to the node.class SVNTreeNode:  def __init__(self, name, children=None, contents=None, props={}, atts={}):    self.name = name    self.children = children    self.contents = contents    self.props = props    self.atts = atts    self.path = name# TODO: Check to make sure contents and children are mutually exclusive  def add_child(self, newchild):    if self.children is None:  # if you're a file,      self.children = []     # become an empty dir.    child_already_exists = 0    for a in self.children:      if a.name == newchild.name:        child_already_exists = 1        break    if child_already_exists == 0:      self.children.append(newchild)      newchild.path = os.path.join (self.path, newchild.name)    # If you already have the node,    else:      if newchild.children is None:        # this is the 'end' of the chain, so copy any content here.        a.contents = newchild.contents        a.props = newchild.props        a.atts = newchild.atts        a.path = os.path.join (self.path, newchild.name)      else:        # try to add dangling children to your matching node        for i in newchild.children:          a.add_child(i)  def pprint(self):    print " * Node name:  ", self.name    print "    Path:      ", self.path    print "    Contents:  ", self.contents    print "    Properties:", self.props    print "    Attributes:", self.atts    ### FIXME: I'd like to be able to tell the difference between    ### self.children is None (file) and self.children == [] (empty    ### directory), but it seems that most places that construct    ### SVNTreeNode objects don't even try to do that.  --xbc    ###    ### See issue #1611 about this problem.  -kfogel    if self.children is not None:      print "    Children:  ", len(self.children)    else:      print "    Children: is a file."# reserved name of the root of the treeroot_node_name = "__SVN_ROOT_NODE"# helper funcdef add_elements_as_path(top_node, element_list):  """Add the elements in ELEMENT_LIST 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.  #  prev_node = top_node  for i in element_list:    new_node = SVNTreeNode(i, None)    prev_node.add_child(new_node)    prev_node = new_node# Sorting function -- sort 2 nodes by their names.def node_is_greater(a, b):  "Sort the names of two nodes."  # Interal use only  if a.name == b.name:    return 0  if a.name > b.name:    return 1  else:    return -1# Helper for compare_treesdef compare_file_nodes(a, b):  """Compare two nodes' names, contents, and properties, ignoring  children.  Return 0 if the same, 1 otherwise."""  if a.name != b.name:    return 1  if a.contents != b.contents:    return 1  if a.props != b.props:    return 1  if a.atts != b.atts:    return 1# Internal utility used by most build_tree_from_foo() routines.## (Take the output and .add_child() it to a root node.)def create_from_path(path, contents=None, props={}, atts={}):  """Create and return a linked list of treenodes, given a PATH  representing a single entry into that tree.  CONTENTS and PROPS are  optional arguments that will be deposited in the tail node."""  # get a list of all the names in the path  # each of these will be a child of the former  if os.sep != "/":    path = string.replace(path, os.sep, "/")  elements = path.split("/")  if len(elements) == 0:    ### we should raise a less generic error here. which?    raise SVNTreeError  root_node = SVNTreeNode(elements[0], None)  add_elements_as_path(root_node, elements[1:])  # deposit contents in the very last node.  node = root_node  while 1:    if node.children is None:      node.contents = contents      node.props = props      node.atts = atts      break    node = node.children[0]  return root_node# helper for handle_dir(), which is a helper for build_tree_from_wc()def get_props(path):  "Return a hash of props for PATH, using the svn client."  # It's not kosher to look inside .svn/ and try to read the internal  # property storage format.  Instead, we use 'svn proplist'.  After  # all, this is the only way the user can retrieve them, so we're  # respecting the black-box paradigm.  props = {}  output, errput = main.run_svn(1, "proplist", path, "--verbose")  first_value = 0  for line in output:    if line.startswith('Properties on '):      continue    # Not a misprint; "> 0" really is preferable to ">= 0" in this case.    if line.find(' : ') > 0:      name, value = line.split(' : ')      name = string.strip(name)      value = string.strip(value)      props[name] = value      first_value = 1    else:    # Multi-line property, so re-use the current name.      if first_value:        # Undo, as best we can, the strip(value) that was done before        # we knew this was a multiline property.        props[name] = props[name] + "\n"        first_value = 0      props[name] = props[name] + line  return props# helper for handle_dir(), which helps build_tree_from_wc()def get_text(path):  "Return a string with the textual contents of a file at PATH."  # sanity check  if not os.path.isfile(path):    return None  fp = open(path, 'r')  contents = fp.read()  fp.close()  return contents# main recursive helper for build_tree_from_wc()def handle_dir(path, current_parent, load_props, ignore_svn):  # 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) != main.get_admin_name()):      dirs.append(f)    elif os.path.isfile(f):      files.append(f)  # add each file as a child of CURRENT_PARENT  for f in files:    fcontents = get_text(f)    if load_props:      fprops = get_props(f)    else:      fprops = {}    current_parent.add_child(SVNTreeNode(os.path.basename(f), None,                                         fcontents, fprops))  # for each subdir, create a node, walk its tree, add it as a child  for d in dirs:    if load_props:      dprops = get_props(d)    else:      dprops = {}    new_dir_node = SVNTreeNode(os.path.basename(d), None, None, dprops)    handle_dir(d, new_dir_node, load_props, ignore_svn)    current_parent.add_child(new_dir_node)def get_child(node, name):  """If SVNTreeNode NODE contains a child named NAME, return child;  else, return None. If SVNTreeNode is not a directory, raise a  SVNTreeIsNotDirectory exception"""

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -