📄 tree.py
字号:
if node.children == None: raise SVNTreeIsNotDirectory for n in node.children: if (name == n.name): return n return None# Helpers for compare_treesdef default_singleton_handler_a(a, baton): "Printing SVNTreeNode A's name, then raise SVNTreeUnequal." print "Got singleton from actual tree:", a.name a.pprint() raise SVNTreeUnequaldef default_singleton_handler_b(b, baton): "Printing SVNTreeNode B's name, then raise SVNTreeUnequal." print "Got singleton from expected tree:", b.name b.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 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 SVNTreeUnequal; 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_a if (singleton_handler_b is None): singleton_handler_b = default_singleton_handler_b 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 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 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 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) 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: raise SVNTreeUnequal else: print "Unequal at node %s" % a.name raise SVNTreeUnequal# Visually show a tree's structuredef 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 = string.replace(indent, "-", " ") indent = string.replace(indent, "+", " ") 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, a 'status' att, and a# 'writelocked' 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) rm1 = re.compile ('^([MAGCUD_ ][MAGCUD_ ])([B ])\s+(.+)') # There may be other verbs we need to match, in addition to # "Restored". If so, add them as alternatives in the first match # group below. rm2 = re.compile ('^(Restored)\s+\'(.+)\'') for line in lines: match = rm1.search(line) if match and match.groups(): new_branch = create_from_path(match.group(3), None, {}, {'status' : match.group(1)}) root.add_child(new_branch) else: match = rm2.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 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+( \(bin\))?)\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(3), 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',# ... and possibly 'locked', 'copied', 'writelocked',# IFF columns non-empty.#def build_tree_from_status(lines): "Return a tree derived by parsing the output LINES from 'st -vuq'." root = SVNTreeNode(root_node_name) # 'status -v' output looks like this: # # "%c%c%c%c%c%c %c %6s %6s %-12s %s\n" # # (Taken from 'print_status' in subversion/svn/status.c.) # # Here are the parameters. The middle number in parens is the # match.group(), followed by a brief description of the field: # # - text status (1) (single letter) # - prop status (1) (single letter) # - wc-lockedness flag (2) (single letter: "L" or " ") # - copied flag (3) (single letter: "+" or " ") # - switched flag (4) (single letter: "S" or " ") # - repos lock status (5) (single letter: "K", "O", "B", "T", " ") # # [one space] # # - out-of-date flag (6) (single letter: "*" or " ") # # [three spaces] # # - working revision (7) (either digits or "-") # # [one space] # # - last-changed revision (8) (either digits or "?") # # [one space] # # - last author (9) (string of non-whitespace characters) # # [one space] # # - path (10) (string of characters until newline) # Try http://www.wordsmith.org/anagram/anagram.cgi?anagram=ACDRMGU rm = re.compile('^([!MACDRUG_ ][MACDRUG_ ])([L ])([+ ])([S ])([KOBT ]) ([* ]) [^0-9-]*(\d+|-|\?) +(\d|-|\?)+ +(\S+) +(.+)') for line in lines: # Quit when we hit an externals status announcement (### someday we can fix # the externals tests to expect the additional flood of externals status # data). if re.match(r'^Performing', line): break match = rm.search(line) if match and match.groups(): if match.group(9) != '-': # ignore items that only exist on repos atthash = {'status' : match.group(1), 'wc_rev' : match.group(7)} if match.group(2) != ' ': atthash['locked'] = match.group(2) if match.group(3) != ' ': atthash['copied'] = match.group(3) if match.group(4) != ' ': atthash['switched'] = match.group(4) if match.group(5) != ' ': atthash['writelocked'] = match.group(5) new_branch = create_from_path(match.group(10), None, {}, atthash) root.add_child(new_branch) return root# Parse merge "skipped" outputdef build_tree_from_skipped(lines): root = SVNTreeNode(root_node_name) ### Will get confused by spaces in the filename rm = re.compile ("^Skipped.* '([^ ]+)'\n") for line in lines: match = rm.search(line) if match and match.groups(): new_branch = create_from_path(match.group(1)) root.add_child(new_branch) return rootdef build_tree_from_diff_summarize(lines): "Build a tree from output of diff --summarize" root = SVNTreeNode(root_node_name) rm = re.compile ("^([MAD ][M ]) (.+)\n") for line in lines: match = rm.search(line) if match and match.groups(): new_branch = create_from_path(match.group(2), atts={'status': match.group(1)}) 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 admin 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -