📄 svn_tree.py
字号:
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) != '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:
fcontents = get_text(f)
if load_props:
fprops = get_props(f)
else:
fprops = {}
c = SVNTreeNode(os.path.basename(f), None,
fcontents, fprops)
c.mtime = os.stat(f)[stat.ST_MTIME]
current_parent.add_child(c)
# 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, dprops)
handle_dir(d, new_dir_node, load_props, ignore_svn)
new_dir_node.mtime = os.stat(f)[stat.ST_MTIME]
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"""
if node.children == None:
raise SVNTreeIsNotDirectory
for n in node.children:
if (name == n.name):
return n
return None
# Helper for compare_trees
def default_singleton_handler(a, baton):
"Printing SVNTreeNode A's name, then raise SVNTreeUnequal."
print "Got singleton", a.name
a.pprint()
raise SVNTreeUnequal
###########################################################################
###########################################################################
# EXPORTED ROUTINES ARE BELOW
# Main tree comparison routine!
def compare_trees(a, b,
singleton_handler_a = None,
a_baton = None,
singleton_handler_b = None,
b_baton = None):
"""Compare SVNTreeNodes A and B, expressing differences using FUNC_A
and FUNC_B. FUNC_A and FUNC_B are functions of two arguments (a
SVNTreeNode and a context baton), and may raise exception
SVNTreeUnequal. Their return value is ignored.
If A and B are both files, then return 0 if their contents,
properties, and names are all the same; else raise a SVNTreeUnequal.
If A is a file and B is a directory, raise a SVNTypeMismatch; same
vice-versa. If both are directories, then for each entry that
exists in both, call compare_trees on the two entries; otherwise, if
the entry exists only in A, invoke FUNC_A on it, and likewise for
B with FUNC_B."""
def display_nodes(a, b):
'Display two nodes, expected and actual.'
print "============================================================="
print "Expected", b.name, "and actual", a.name, "are different!"
print "============================================================="
print "EXPECTED NODE TO BE:"
print "============================================================="
b.pprint()
print "============================================================="
print "ACTUAL NODE FOUND:"
print "============================================================="
a.pprint()
# Setup singleton handlers
if (singleton_handler_a is None):
singleton_handler_a = default_singleton_handler
if (singleton_handler_b is None):
singleton_handler_b = default_singleton_handler
try:
# A and B are both files.
if ((a.children is None) and (b.children is None)):
if compare_file_nodes(a, b):
display_nodes(a, b)
raise main.SVNTreeUnequal
# One is a file, one is a directory.
elif (((a.children is None) and (b.children is not None))
or ((a.children is not None) and (b.children is None))):
display_nodes(a, b)
raise main.SVNTypeMismatch
# They're both directories.
else:
# First, compare the directories' two hashes.
if (a.props != b.props) or (a.atts != b.atts):
display_nodes(a, b)
raise main.SVNTreeUnequal
accounted_for = []
# For each child of A, check and see if it's in B. If so, run
# compare_trees on the two children and add b's child to
# accounted_for. If not, run FUNC_A on the child. Next, for each
# child of B, check and see if it's in accounted_for. If it is,
# do nothing. If not, run FUNC_B on it.
for a_child in a.children:
b_child = get_child(b, a_child.name)
if b_child:
accounted_for.append(b_child)
compare_trees(a_child, b_child,
singleton_handler_a, a_baton,
singleton_handler_b, b_baton)
else:
singleton_handler_a(a_child, a_baton)
for b_child in b.children:
if (b_child not in accounted_for):
singleton_handler_b(b_child, b_baton)
return 0
except SVNTypeMismatch:
print 'Unequal Types: one Node is a file, the other is a directory'
raise SVNTreeUnequal
except SVNTreeIsNotDirectory:
print "Error: Foolish call to get_child."
sys.exit(1)
except IndexError:
print "Error: unequal number of children"
raise SVNTreeUnequal
except SVNTreeUnequal:
if a.name == root_node_name:
return 1
else:
print "Unequal at node %s" % a.name
raise SVNTreeUnequal
return 0
# Visually show a tree's structure
def dump_tree(n,indent=""):
"Print out a nice representation of the tree's structure."
# Code partially stolen from Dave Beazley
if n.children is None:
tmp_children = []
else:
tmp_children = n.children
if n.name == root_node_name:
print "%s%s" % (indent, "ROOT")
else:
print "%s%s" % (indent, n.name)
indent = indent.replace("-"," ")
indent = indent.replace("+"," ")
for i in range(len(tmp_children)):
c = tmp_children[i]
if i == len(tmp_children
)-1:
dump_tree(c,indent + " +-- ")
else:
dump_tree(c,indent + " |-- ")
###################################################################
###################################################################
# PARSERS that return trees made of SVNTreeNodes....
###################################################################
# Build an "expected" static tree from a list of lists
# Create a list of lists, of the form:
#
# [ [path, contents, props, atts], ... ]
#
# and run it through this parser. PATH is a string, a path to the
# object. CONTENTS is either a string or None, and PROPS and ATTS are
# populated dictionaries or {}. Each CONTENTS/PROPS/ATTS will be
# attached to the basename-node of the associated PATH.
def build_generic_tree(nodelist):
"Given a list of lists of a specific format, return a tree."
root = SVNTreeNode(root_node_name)
for list in nodelist:
new_branch = create_from_path(list[0], list[1], list[2], list[3])
root.add_child(new_branch)
return root
####################################################################
# Build trees from different kinds of subcommand output.
# Parse co/up output into a tree.
#
# Tree nodes will contain no contents, and only one 'status' att.
def build_tree_from_checkout(lines):
"Return a tree derived by parsing the output LINES from 'co' or 'up'."
root = SVNTreeNode(root_node_name)
rm = re.compile ('^([MAGCUD_ ][MAGCUD_ ]) (.+)')
for line in lines:
match = rm.search(line)
if match and match.groups():
new_branch = create_from_path(match.group(2), None, {},
{'status' : match.group(1)})
root.add_child(new_branch)
return root
# Parse ci/im output into a tree.
#
# Tree nodes will contain no contents, and only one 'verb' att.
def build_tree_from_commit(lines):
"Return a tree derived by parsing the output LINES from 'ci' or 'im'."
# Lines typically have a verb followed by whitespace then a path.
root = SVNTreeNode(root_node_name)
rm1 = re.compile ('^(\w+)\s+(.+)')
rm2 = re.compile ('^Transmitting')
for line in lines:
match = rm2.search(line)
if not match:
match = rm1.search(line)
if match and match.groups():
new_branch = create_from_path(match.group(2), None, {},
{'verb' : match.group(1)})
root.add_child(new_branch)
return root
# Parse status output into a tree.
#
# Tree nodes will contain no contents, and these atts:
#
# 'status', 'wc_rev', 'repos_rev'
# ... and possibly 'locked', 'copied', IFF columns non-empty.
#
def build_tree_from_status(lines):
"Return a tree derived by parsing the output LINES from 'st'."
root = SVNTreeNode(root_node_name)
rm = re.compile ('^.+\:.+(\d+)')
lastline = string.strip(lines.pop())
match = rm.search(lastline)
if match and match.groups():
repos_rev = match.group(1)
else:
repos_rev = '?'
# Try http://www.wordsmith.org/anagram/anagram.cgi?anagram=ACDRMGU
rm = re.compile ('^([MACDRUG_ ][MACDRUG_ ])(.)(.) . [^0-9-]+(\d+|-)(.{23})(.+)')
for line in lines:
match = rm.search(line)
if match and match.groups():
if match.group(5) != '-': # ignore items that only exist on repos
atthash = {'status' : match.group(1),
'wc_rev' : match.group(4),
'repos_rev' : repos_rev}
if match.group(2) != ' ':
atthash['locked'] = match.group(2)
if match.group(3) != ' ':
atthash['copied'] = match.group(3)
new_branch = create_from_path(match.group(6), None, {}, atthash)
root.add_child(new_branch)
return root
####################################################################
# Build trees by looking at the working copy
# The reason the 'load_props' flag is off by default is because it
# creates a drastic slowdown -- we spawn a new 'svn proplist'
# process for every file and dir in the working copy!
def build_tree_from_wc(wc_path, load_props=0, ignore_svn=1):
"""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. If IGNORE_SVN is true, then exclude SVN dirs from the tree.
If LOAD_PROPS is true, the props will be added to the tree."""
root = SVNTreeNode(root_node_name, None)
# if necessary, store the root dir's props in the root node.
if load_props:
root.props = get_props(wc_path)
# Walk the tree recursively
handle_dir(os.path.normpath(wc_path), root, load_props, ignore_svn)
return root
### End of file.
# local variables:
# eval: (load-file "../../../../../tools/dev/svn-dev.el")
# end:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -