def run_and_verify_update(wc_dir_name, output_tree, disk_tree, status_tree, error_re_string=None, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, check_props=0, *args): """Update WC_DIR_NAME. *ARGS are any extra optional args to the update subcommand. NOTE: If *ARGS is specified at all, explicit target paths must be passed in *ARGS as well (or a default `.' will be chosen by the 'svn' binary). This allows the caller to update many items in a single working copy dir, but still verify the entire working copy dir. If ERROR_RE_STRING, the update must exit with error, and the error message must match regular expression ERROR_RE_STRING. Else if ERROR_RE_STRING is None, then: The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() # Update and make a tree of the output. if len(args): output, errput = main.run_svn(error_re_string, 'up', *args) else: output, errput = main.run_svn(error_re_string, 'up', wc_dir_name, *args) if (error_re_string): rm = re.compile(error_re_string) for line in errput: match = rm.search(line) if match: return raise main.SVNUnmatchedError mytree = tree.build_tree_from_checkout(output) verify_update(mytree, wc_dir_name, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
def run_and_verify_update(wc_dir_name, output_tree, disk_tree, status_tree, error_re_string = None, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, check_props = 0, *args): """Update WC_DIR_NAME. *ARGS are any extra optional args to the update subcommand. NOTE: If *ARGS is specified at all, explicit target paths must be passed in *ARGS as well (or a default `.' will be chosen by the 'svn' binary). This allows the caller to update many items in a single working copy dir, but still verify the entire working copy dir. If ERROR_RE_STRING, the update must exit with error, and the error message must match regular expression ERROR_RE_STRING. Else if ERROR_RE_STRING is None, then: The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() # Update and make a tree of the output. if len(args): output, errput = main.run_svn (error_re_string, 'up', *args) else: output, errput = main.run_svn (error_re_string, 'up', wc_dir_name, *args) if (error_re_string): rm = re.compile(error_re_string) for line in errput: match = rm.search(line) if match: return raise main.SVNUnmatchedError mytree = tree.build_tree_from_checkout (output) verify_update (mytree, wc_dir_name, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
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
def run_and_verify_svn(message, expected_stdout, expected_stderr, *varargs): """Invokes main.run_svn with *VARARGS, return stdout and stderr as lists of lines. If EXPECTED_STDOUT or EXPECTED_STDERR is not 'None', invokes compare_and_display_lines with MESSAGE and the expected output. If the comparison fails, compare_and_display_lines will raise.""" ### TODO catch and throw particular exceptions from above want_err = None if expected_stderr is not None and expected_stderr is not []: want_err = 1 out, err = main.run_svn(want_err, *varargs) if type(expected_stdout) is type([]): compare_and_display_lines(message, 'STDOUT', expected_stdout, out) elif expected_stdout == SVNAnyOutput: if len(out) == 0: if message is not None: print message raise SVNExpectedStdout elif expected_stdout is not None: raise SVNIncorrectDatatype("Unexpected specification for stdout data") if type(expected_stderr) is type([]): compare_and_display_lines(message, 'STDERR', expected_stderr, err) elif expected_stderr == SVNAnyOutput: if len(err) == 0: if message is not None: print message raise SVNExpectedStderr elif expected_stderr is not None: raise SVNIncorrectDatatype("Unexpected specification for stderr data") return out, err
def run_and_verify_unquiet_status(wc_dir_name, output_tree, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None): """Run 'status' on WC_DIR_NAME and compare it with the expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns on success, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() output, errput = main.run_svn (None, 'status', '-v', '-u', wc_dir_name) mytree = tree.build_tree_from_status (output) # Verify actual output against expected output. if (singleton_handler_a or singleton_handler_b): tree.compare_trees (mytree, output_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton) else: tree.compare_trees (mytree, output_tree)
def run_and_verify_status(wc_dir_name, output_tree, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None): """Run 'status' on WC_DIR_NAME and compare it with the expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns on success, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() output, errput = main.run_svn(None, 'status', '-v', '-u', '-q', '--username', main.wc_author, '--password', main.wc_passwd, wc_dir_name) mytree = tree.build_tree_from_status(output) # Verify actual output against expected output. try: tree.compare_trees(mytree, output_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton) except tree.SVNTreeError: display_trees(None, 'STATUS OUTPUT TREE', output_tree, mytree) raise
def run_and_verify_unquiet_status(wc_dir_name, output_tree, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None): """Run 'status' on WC_DIR_NAME and compare it with the expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns on success, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() output, errput = main.run_svn(None, 'status', '-v', '-u', wc_dir_name) mytree = tree.build_tree_from_status(output) # Verify actual output against expected output. if (singleton_handler_a or singleton_handler_b): tree.compare_trees(mytree, output_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton) else: tree.compare_trees(mytree, output_tree)
def noninheritable_mergeinfo_test_set_up(sbox): """Starting with standard greek tree, copy 'A' to 'branch' in r2 and then made a file edit to A/B/lambda in r3. Return (expected_output, expected_mergeinfo_output, expected_elision_output, expected_status, expected_disk, expected_skip) for a merge of r3 from ^/A/B to branch/B.""" sbox.build() wc_dir = sbox.wc_dir lambda_path = sbox.ospath("A/B/lambda") B_branch_path = sbox.ospath("branch/B") # r2 - Branch ^/A to ^/branch. main.run_svn(None, "copy", sbox.repo_url + "/A", sbox.repo_url + "/branch", "-m", "make a branch") # r3 - Make an edit to A/B/lambda. main.file_write(lambda_path, "trunk edit.\n") main.run_svn(None, "commit", "-m", "file edit", wc_dir) main.run_svn(None, "up", wc_dir) expected_output = wc.State(B_branch_path, {"lambda": Item(status="U ")}) expected_mergeinfo_output = wc.State(B_branch_path, {"": Item(status=" U"), "lambda": Item(status=" U")}) expected_elision_output = wc.State(B_branch_path, {"lambda": Item(status=" U")}) expected_status = wc.State( B_branch_path, { "": Item(status=" M"), "lambda": Item(status="M "), "E": Item(status=" "), "E/alpha": Item(status=" "), "E/beta": Item(status=" "), "F": Item(status=" "), }, ) expected_status.tweak(wc_rev="3") expected_disk = wc.State( "", { "": Item(props={SVN_PROP_MERGEINFO: "/A/B:3"}), "lambda": Item("trunk edit.\n"), "E": Item(), "E/alpha": Item("This is the file 'alpha'.\n"), "E/beta": Item("This is the file 'beta'.\n"), "F": Item(), }, ) expected_skip = wc.State(B_branch_path, {}) return ( expected_output, expected_mergeinfo_output, expected_elision_output, expected_status, expected_disk, expected_skip, )
def noninheritable_mergeinfo_test_set_up(sbox): '''Starting with standard greek tree, copy 'A' to 'branch' in r2 and then made a file edit to A/B/lambda in r3. Return (expected_output, expected_mergeinfo_output, expected_elision_output, expected_status, expected_disk, expected_skip) for a merge of r3 from ^/A/B to branch/B.''' sbox.build() wc_dir = sbox.wc_dir lambda_path = sbox.ospath('A/B/lambda') B_branch_path = sbox.ospath('branch/B') # r2 - Branch ^/A to ^/branch. main.run_svn(None, 'copy', sbox.repo_url + '/A', sbox.repo_url + '/branch', '-m', 'make a branch') # r3 - Make an edit to A/B/lambda. main.file_write(lambda_path, "trunk edit.\n") main.run_svn(None, 'commit', '-m', 'file edit', wc_dir) main.run_svn(None, 'up', wc_dir) expected_output = wc.State(B_branch_path, { 'lambda': Item(status='U '), }) expected_mergeinfo_output = wc.State(B_branch_path, { '': Item(status=' U'), 'lambda': Item(status=' U'), }) expected_elision_output = wc.State(B_branch_path, { 'lambda': Item(status=' U'), }) expected_status = wc.State( B_branch_path, { '': Item(status=' M'), 'lambda': Item(status='M '), 'E': Item(status=' '), 'E/alpha': Item(status=' '), 'E/beta': Item(status=' '), 'F': Item(status=' '), }) expected_status.tweak(wc_rev='3') expected_disk = wc.State( '', { '': Item(props={SVN_PROP_MERGEINFO: '/A/B:3'}), 'lambda': Item("trunk edit.\n"), 'E': Item(), 'E/alpha': Item("This is the file 'alpha'.\n"), 'E/beta': Item("This is the file 'beta'.\n"), 'F': Item(), }) expected_skip = wc.State(B_branch_path, {}) return expected_output, expected_mergeinfo_output, expected_elision_output, \ expected_status, expected_disk, expected_skip
def get_props(paths): """Return a hash of hashes of props for PATHS, using the svn client. Convert each embedded end-of-line to a single LF character.""" # 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. files = {} filename = None exit_code, output, errput = main.run_svn(1, "proplist", "--verbose", *paths) properties_on_re = re.compile("^Properties on '(.+)':$") # Parse the output for line in output: line = line.rstrip('\r\n') # ignore stdout's EOL sequence match = properties_on_re.match(line) if match: filename = match.group(1) elif line.startswith(' '): # It's (part of) the value (strip the indentation) if filename is None: raise Exception("Missing 'Properties on' line: '" + line + "'") files.setdefault(filename, {})[name] += line[4:] + '\n' elif line.startswith(' '): # It's the name name = line[2:] # strip the indentation if filename is None: raise Exception("Missing 'Properties on' line: '" + line + "'") files.setdefault(filename, {})[name] = '' else: raise Exception("Malformed line from proplist: '" + line + "'") # Strip, from each property value, the final new-line that we added for filename in files: for name in files[filename]: files[filename][name] = files[filename][name][:-1] return files
def noninheritable_mergeinfo_test_set_up(sbox): '''Starting with standard greek tree, copy 'A' to 'branch' in r2 and then made a file edit to A/B/lambda in r3. Return (expected_output, expected_mergeinfo_output, expected_elision_output, expected_status, expected_disk, expected_skip) for a merge of r3 from ^/A/B to branch/B.''' sbox.build() wc_dir = sbox.wc_dir lambda_path = sbox.ospath('A/B/lambda') B_branch_path = sbox.ospath('branch/B') # r2 - Branch ^/A to ^/branch. main.run_svn(None, 'copy', sbox.repo_url + '/A', sbox.repo_url + '/branch', '-m', 'make a branch') # r3 - Make an edit to A/B/lambda. main.file_write(lambda_path, "trunk edit.\n") main.run_svn(None, 'commit', '-m', 'file edit', wc_dir) main.run_svn(None, 'up', wc_dir) expected_output = wc.State(B_branch_path, { 'lambda' : Item(status='U '), }) expected_mergeinfo_output = wc.State(B_branch_path, { '' : Item(status=' U'), 'lambda' : Item(status=' U'), }) expected_elision_output = wc.State(B_branch_path, { 'lambda' : Item(status=' U'), }) expected_status = wc.State(B_branch_path, { '' : Item(status=' M'), 'lambda' : Item(status='M '), 'E' : Item(status=' '), 'E/alpha' : Item(status=' '), 'E/beta' : Item(status=' '), 'F' : Item(status=' '), }) expected_status.tweak(wc_rev='3') expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:3'}), 'lambda' : Item("trunk edit.\n"), 'E' : Item(), 'E/alpha' : Item("This is the file 'alpha'.\n"), 'E/beta' : Item("This is the file 'beta'.\n"), 'F' : Item(), }) expected_skip = wc.State(B_branch_path, {}) return expected_output, expected_mergeinfo_output, expected_elision_output, \ expected_status, expected_disk, expected_skip
def get_props(paths): """Return a hash of hashes of props for PATHS, using the svn client. Convert each embedded end-of-line to a single LF character.""" # 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. files = {} filename = None exit_code, output, errput = main.run_svn(1, "proplist", "--verbose", *paths) properties_on_re = re.compile("^Properties on '(.+)':$") # Parse the output for line in output: line = line.rstrip('\r\n') # ignore stdout's EOL sequence match = properties_on_re.match(line) if match: filename = match.group(1) elif line.startswith(' '): # It's (part of) the value (strip the indentation) if filename is None: raise Exception("Missing 'Properties on' line: '"+line+"'") files.setdefault(filename, {})[name] += line[4:] + '\n' elif line.startswith(' '): # It's the name name = line[2:] # strip the indentation if filename is None: raise Exception("Missing 'Properties on' line: '"+line+"'") files.setdefault(filename, {})[name] = '' else: raise Exception("Malformed line from proplist: '"+line+"'") # Strip, from each property value, the final new-line that we added for filename in files: for name in files[filename]: files[filename][name] = files[filename][name][:-1] return files
def run_and_verify_update(wc_dir_name, output_tree, disk_tree, status_tree, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, check_props = 0, *args): """Update WC_DIR_NAME into a new directory WC_DIR_NAME. *ARGS are any extra optional args to the update subcommand. The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_OUTPUT_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. Return 0 if successful.""" # Update and make a tree of the output. output, errput = main.run_svn (None, 'up', wc_dir_name, *args) mytree = tree.build_tree_from_checkout (output) # Verify actual output against expected output. if tree.compare_trees (mytree, output_tree): return 1 # Create a tree by scanning the working copy mytree = tree.build_tree_from_wc (wc_dir_name, check_props) # Verify expected disk against actual disk. if tree.compare_trees (mytree, disk_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton): return 1 # Verify via 'status' command too, if possible. if status_tree: if run_and_verify_status(wc_dir_name, status_tree): return 1 return 0
def run_and_verify_svn(message, expected_stdout, expected_stderr, *varargs): """Invokes main.run_svn with *VARARGS, return stdout and stderr as lists of lines. For both EXPECTED_STDOUT and EXPECTED_STDERR, do this: - If it is an array of strings, invoke compare_and_display_lines() on MESSAGE, the expected output, and the actual output. - If it is a single string, invoke match_or_fail() on MESSAGE, the expected output, and the actual output. If EXPECTED_STDOUT is None, do not check stdout. EXPECTED_STDERR may not be None. If a comparison function fails, it will raise an error.""" ### TODO catch and throw particular exceptions from above if expected_stderr is None: raise SVNIncorrectDatatype("expected_stderr must not be None") want_err = None if expected_stderr is not None and expected_stderr is not []: want_err = 1 out, err = main.run_svn(want_err, *varargs) for (expected, actual, output_type, raisable) in ((expected_stderr, err, 'stderr', SVNExpectedStderr), (expected_stdout, out, 'stdout', SVNExpectedStdout)): if type(expected) is type([]): compare_and_display_lines(message, output_type.upper(), expected, actual) elif type(expected) is type(''): match_or_fail(message, output_type.upper(), expected, actual) elif expected == SVNAnyOutput: if len(actual) == 0: if message is not None: print message raise raisable elif expected is not None: raise SVNIncorrectDatatype("Unexpected type for %s data" % output_type) return out, err
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") for line in output: if line.startswith('Properties on '): continue name, value = line.split(' : ') name = string.strip(name) value = string.strip(value) props[name] = value return props
def run_and_verify_diff_summarize(output_tree, error_re_string=None, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, *args): """Run 'diff --summarize' with the arguments *ARGS. If ERROR_RE_STRING, the command must exit with error, and the error message must match regular expression ERROR_RE_STRING. Else if ERROR_RE_STRING is None, the subcommand output will be verified against OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns on success, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() output, errput = main.run_svn(None, 'diff', '--summarize', '--username', main.wc_author, '--password', main.wc_passwd, *args) if (error_re_string): rm = re.compile(error_re_string) for line in errput: match = rm.search(line) if match: return raise main.SVNUnmatchedError mytree = tree.build_tree_from_diff_summarize(output) # Verify actual output against expected output. try: tree.compare_trees(mytree, output_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton) except tree.SVNTreeError: display_trees(None, 'DIFF OUTPUT TREE', output_tree, mytree) raise
def run_and_verify_export(URL, export_dir_name, output_tree, disk_tree, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, *args): """Export the URL into a new directory WC_DIR_NAME. The subcommand output will be verified against OUTPUT_TREE, and the exported copy itself will be verified against DISK_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns if successful and raise on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() # Export and make a tree of the output, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn(None, 'export', '--username', main.wc_author, '--password', main.wc_passwd, URL, export_dir_name, *args) mytree = tree.build_tree_from_checkout(output) # Verify actual output against expected output. tree.compare_trees(mytree, output_tree) # Create a tree by scanning the working copy. Don't ignore # the .svn directories so that we generate an error if they # happen to show up. mytree = tree.build_tree_from_wc(export_dir_name, ignore_svn=0) # Verify expected disk against actual disk. tree.compare_trees(mytree, disk_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton)
def run_and_verify_export(URL, export_dir_name, output_tree, disk_tree, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, *args): """Export the URL into a new directory WC_DIR_NAME. The subcommand output will be verified against OUTPUT_TREE, and the exported copy itself will be verified against DISK_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns if successful and raise on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() # Export and make a tree of the output, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn (None, 'export', '--username', main.wc_author, '--password', main.wc_passwd, URL, export_dir_name, *args) mytree = tree.build_tree_from_checkout (output) # Verify actual output against expected output. tree.compare_trees (mytree, output_tree) # Create a tree by scanning the working copy. Don't ignore # the .svn directories so that we generate an error if they # happen to show up. mytree = tree.build_tree_from_wc (export_dir_name, ignore_svn=0) # Verify expected disk against actual disk. tree.compare_trees (mytree, disk_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton)
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") for line in output: if line.startswith('Properties on '): continue if line.startswith(' ') and line.find(' : ') >= 3: name, value = line.split(' : ') name = name[2:] value = value.rstrip("\r\n") props[name] = value else: # Multi-line property, so re-use the current name. # Keep the line endings consistent with what was done to the first # line by stripping whitespace and then appending a newline. This # prevents multiline props on Windows that must be stored as UTF8/LF # in the repository (e.g. svn:mergeinfo), say like this: # # "propname : propvalLine1<LF>propvalLine2<LF>propvalLine3" # # but that print to stdout like this: # # Properties on 'somepath':<CR><LF> # propname : propvalLine1<CR><CR><LF> # propvalLine1<CR><CR><LF> # propvalLine1<CR><LF> # # from looking like this in the returned PROPS hash: # # "propname" --> "propvalLine1<LF>propvalLine2<CR><LF>propvalLine3<LF>" props[name] = props[name] + "\n" + line.rstrip("\r\n") return props
def run_and_verify_switch(wc_dir_name, wc_target, switch_url, output_tree, disk_tree, status_tree, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, check_props = 0): """Switch WC_TARGET (in working copy dir WC_DIR_NAME) to SWITCH_URL. The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_OUTPUT_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() # Update and make a tree of the output. output, errput = main.run_svn (None, 'switch', '--username', main.wc_author, '--password', main.wc_passwd, switch_url, wc_target) mytree = tree.build_tree_from_checkout (output) verify_update (mytree, wc_dir_name, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
def run_and_verify_checkout(URL, wc_dir_name, output_tree, disk_tree, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None): """Checkout the the URL into a new directory WC_DIR_NAME. The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Return 0 if successful.""" # Remove dir if it's already there. main.remove_wc(wc_dir_name) # Checkout and make a tree of the output, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn (None, 'co', '--username', main.wc_author, '--password', main.wc_passwd, URL, '-d', wc_dir_name) mytree = tree.build_tree_from_checkout (output) # Verify actual output against expected output. if tree.compare_trees (mytree, output_tree): return 1 # Create a tree by scanning the working copy mytree = tree.build_tree_from_wc (wc_dir_name) # Verify expected disk against actual disk. if tree.compare_trees (mytree, disk_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton): return 1 return 0
def run_and_verify_switch(wc_dir_name, wc_target, switch_url, output_tree, disk_tree, status_tree, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, check_props=0): """Switch WC_TARGET (in working copy dir WC_DIR_NAME) to SWITCH_URL. The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_OUTPUT_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() # Update and make a tree of the output. output, errput = main.run_svn(None, 'switch', '--username', main.wc_author, '--password', main.wc_passwd, switch_url, wc_target) mytree = tree.build_tree_from_checkout(output) verify_update(mytree, wc_dir_name, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
def set_up_dir_replace(sbox): """Set up the working copy for directory replace tests, creating directory 'A/B/F/foo' with files 'new file' and 'new file2' within it (r2), and merging 'foo' onto 'C' (r3), then deleting 'A/B/F/foo' (r4).""" sbox.build() wc_dir = sbox.wc_dir C_path = sbox.ospath('A/C') F_path = sbox.ospath('A/B/F') F_url = sbox.repo_url + '/A/B/F' foo_path = os.path.join(F_path, 'foo') new_file = os.path.join(foo_path, "new file") new_file2 = os.path.join(foo_path, "new file 2") # Make directory foo in F, and add some files within it. actions.run_and_verify_svn(None, None, [], 'mkdir', foo_path) main.file_append(new_file, "Initial text in new file.\n") main.file_append(new_file2, "Initial text in new file 2.\n") main.run_svn(None, "add", new_file) main.run_svn(None, "add", new_file2) # Commit all the new content, creating r2. expected_output = wc.State(wc_dir, { 'A/B/F/foo' : Item(verb='Adding'), 'A/B/F/foo/new file' : Item(verb='Adding'), 'A/B/F/foo/new file 2' : Item(verb='Adding'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/foo' : Item(status=' ', wc_rev=2), 'A/B/F/foo/new file' : Item(status=' ', wc_rev=2), 'A/B/F/foo/new file 2' : Item(status=' ', wc_rev=2), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Merge foo onto C expected_output = wc.State(C_path, { 'foo' : Item(status='A '), 'foo/new file' : Item(status='A '), 'foo/new file 2' : Item(status='A '), }) expected_mergeinfo_output = wc.State(C_path, { '' : Item(status=' U'), }) expected_elision_output = wc.State(C_path, { }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}), 'foo' : Item(), 'foo/new file' : Item("Initial text in new file.\n"), 'foo/new file 2' : Item("Initial text in new file 2.\n"), }) expected_status = wc.State(C_path, { '' : Item(status=' M', wc_rev=1), 'foo' : Item(status='A ', wc_rev='-', copied='+'), 'foo/new file' : Item(status=' ', wc_rev='-', copied='+'), 'foo/new file 2' : Item(status=' ', wc_rev='-', copied='+'), }) expected_skip = wc.State(C_path, { }) actions.run_and_verify_merge(C_path, '1', '2', F_url, None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, None, None, None, None, None, 1) # Commit merge of foo onto C, creating r3. expected_output = wc.State(wc_dir, { 'A/C' : Item(verb='Sending'), 'A/C/foo' : Item(verb='Adding'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/foo' : Item(status=' ', wc_rev=2), 'A/C' : Item(status=' ', wc_rev=3), 'A/B/F/foo/new file' : Item(status=' ', wc_rev=2), 'A/B/F/foo/new file 2' : Item(status=' ', wc_rev=2), 'A/C/foo' : Item(status=' ', wc_rev=3), 'A/C/foo/new file' : Item(status=' ', wc_rev=3), 'A/C/foo/new file 2' : Item(status=' ', wc_rev=3), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Delete foo on F, creating r4. actions.run_and_verify_svn(None, None, [], 'rm', foo_path) expected_output = wc.State(wc_dir, { 'A/B/F/foo' : Item(verb='Deleting'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/C' : Item(status=' ', wc_rev=3), 'A/C/foo' : Item(status=' ', wc_rev=3), 'A/C/foo/new file' : Item(status=' ', wc_rev=3), 'A/C/foo/new file 2' : Item(status=' ', wc_rev=3), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir)
def guarantee_greek_repository(path): """Guarantee that a local svn repository exists at PATH, containing nothing but the greek-tree at revision 1.""" if path == main.pristine_dir: print "ERROR: attempt to overwrite the pristine repos! Aborting." sys.exit(1) # If there's no pristine repos, create one. if not os.path.exists(main.pristine_dir): main.create_repos(main.pristine_dir) # dump the greek tree to disk. main.greek_state.write_to_disk(main.greek_dump_dir) # build a URL for doing an import. url = main.test_area_url + '/' + main.pristine_dir if main.windows == 1: url = string.replace(url, '\\', '/') # import the greek tree, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn(None, 'import', '--username', main.wc_author, '--password', main.wc_passwd, '-m', 'Log message for revision 1.', main.greek_dump_dir, url) # check for any errors from the import if len(errput): display_lines("Errors during initial 'svn import':", 'STDERR', None, errput) sys.exit(1) # verify the printed output of 'svn import'. lastline = string.strip(output.pop()) cm = re.compile ("(Committed|Imported) revision [0-9]+.") match = cm.search (lastline) if not match: print "ERROR: import did not succeed, while creating greek repos." print "The final line from 'svn import' was:" print lastline sys.exit(1) output_tree = tree.build_tree_from_commit(output) ### due to path normalization in the .old_tree() method, we cannot ### prepend the necessary '.' directory. thus, let's construct an old ### tree manually from the greek_state. output_list = [] for greek_path in main.greek_state.desc.keys(): output_list.append([ os.path.join(main.greek_dump_dir, greek_path), None, {}, {'verb' : 'Adding'}]) expected_output_tree = tree.build_generic_tree(output_list) try: tree.compare_trees(output_tree, expected_output_tree) except tree.SVNTreeUnequal: display_trees("ERROR: output of import command is unexpected.", 'OUTPUT TREE', expected_output_tree, output_tree) sys.exit(1) # Now that the pristine repos exists, copy it to PATH. main.safe_rmtree(path) if main.copy_repos(main.pristine_dir, path, 1): print "ERROR: copying repository failed." sys.exit(1) # make the repos world-writeable, for mod_dav_svn's sake. main.chmod_tree(path, 0666, 0666)
def guarantee_greek_repository(path): """Guarantee that a local svn repository exists at PATH, containing nothing but the greek-tree at revision 1.""" if path == main.pristine_dir: print "ERROR: attempt to overwrite the pristine repos! Aborting." sys.exit(1) # If there's no pristine repos, create one. if not os.path.exists(main.pristine_dir): main.create_repos(main.pristine_dir) # dump the greek tree to disk. main.write_tree(main.greek_dump_dir, [[x[0], x[1]] for x in main.greek_tree]) # build a URL for doing an import. url = main.test_area_url + '/' + main.pristine_dir # import the greek tree, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn(None, 'import', '--username', main.wc_author, '--password', main.wc_passwd, '-m', 'Log message for revision 1.', url, main.greek_dump_dir) # check for any errors from the import if len(errput): print "Errors during initial 'svn import':" print errput sys.exit(1) # verify the printed output of 'svn import'. lastline = string.strip(output.pop()) cm = re.compile ("(Committed|Imported) revision [0-9]+.") match = cm.search (lastline) if not match: print "ERROR: import did not succeed, while creating greek repos." print "The final line from 'svn import' was:" print lastline sys.exit(1) output_tree = tree.build_tree_from_commit(output) output_list = [] path_list = [x[0] for x in main.greek_tree] for apath in path_list: item = [ os.path.join(".", apath), None, {}, {'verb' : 'Adding'}] output_list.append(item) expected_output_tree = tree.build_generic_tree(output_list) if tree.compare_trees(output_tree, expected_output_tree): print "ERROR: output of import command is unexpected." sys.exit(1) # Now that the pristine repos exists, copy it to PATH. if os.path.exists(path): shutil.rmtree(path) if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) shutil.copytree(main.pristine_dir, path) if os.path.exists(main.current_repo_dir): os.unlink(main.current_repo_dir) os.symlink(os.path.basename(path), main.current_repo_dir)
def set_up_dir_replace(sbox): """Set up the working copy for directory replace tests, creating directory 'A/B/F/foo' with files 'new file' and 'new file2' within it (r2), and merging 'foo' onto 'C' (r3), then deleting 'A/B/F/foo' (r4).""" sbox.build() wc_dir = sbox.wc_dir C_path = sbox.ospath("A/C") F_path = sbox.ospath("A/B/F") F_url = sbox.repo_url + "/A/B/F" foo_path = os.path.join(F_path, "foo") new_file = os.path.join(foo_path, "new file") new_file2 = os.path.join(foo_path, "new file 2") # Make directory foo in F, and add some files within it. actions.run_and_verify_svn(None, [], "mkdir", foo_path) main.file_append(new_file, "Initial text in new file.\n") main.file_append(new_file2, "Initial text in new file 2.\n") main.run_svn(None, "add", new_file) main.run_svn(None, "add", new_file2) # Commit all the new content, creating r2. expected_output = wc.State( wc_dir, { "A/B/F/foo": Item(verb="Adding"), "A/B/F/foo/new file": Item(verb="Adding"), "A/B/F/foo/new file 2": Item(verb="Adding"), }, ) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add( { "A/B/F/foo": Item(status=" ", wc_rev=2), "A/B/F/foo/new file": Item(status=" ", wc_rev=2), "A/B/F/foo/new file 2": Item(status=" ", wc_rev=2), } ) actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Merge foo onto C expected_output = wc.State( C_path, {"foo": Item(status="A "), "foo/new file": Item(status="A "), "foo/new file 2": Item(status="A ")} ) expected_mergeinfo_output = wc.State(C_path, {"": Item(status=" U")}) expected_elision_output = wc.State(C_path, {}) expected_disk = wc.State( "", { "": Item(props={SVN_PROP_MERGEINFO: "/A/B/F:2"}), "foo": Item(), "foo/new file": Item("Initial text in new file.\n"), "foo/new file 2": Item("Initial text in new file 2.\n"), }, ) expected_status = wc.State( C_path, { "": Item(status=" M", wc_rev=1), "foo": Item(status="A ", wc_rev="-", copied="+"), "foo/new file": Item(status=" ", wc_rev="-", copied="+"), "foo/new file 2": Item(status=" ", wc_rev="-", copied="+"), }, ) expected_skip = wc.State(C_path, {}) actions.run_and_verify_merge( C_path, "1", "2", F_url, None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True, ) # Commit merge of foo onto C, creating r3. expected_output = wc.State(wc_dir, {"A/C": Item(verb="Sending"), "A/C/foo": Item(verb="Adding")}) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add( { "A/B/F/foo": Item(status=" ", wc_rev=2), "A/C": Item(status=" ", wc_rev=3), "A/B/F/foo/new file": Item(status=" ", wc_rev=2), "A/B/F/foo/new file 2": Item(status=" ", wc_rev=2), "A/C/foo": Item(status=" ", wc_rev=3), "A/C/foo/new file": Item(status=" ", wc_rev=3), "A/C/foo/new file 2": Item(status=" ", wc_rev=3), } ) actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Delete foo on F, creating r4. actions.run_and_verify_svn(None, [], "rm", foo_path) expected_output = wc.State(wc_dir, {"A/B/F/foo": Item(verb="Deleting")}) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add( { "A/C": Item(status=" ", wc_rev=3), "A/C/foo": Item(status=" ", wc_rev=3), "A/C/foo/new file": Item(status=" ", wc_rev=3), "A/C/foo/new file 2": Item(status=" ", wc_rev=3), } ) actions.run_and_verify_commit(wc_dir, expected_output, expected_status)
def run_and_verify_merge(dir, rev1, rev2, url, output_tree, disk_tree, status_tree, skip_tree, error_re_string = None, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, check_props = 0, dry_run = 1, *args): """Run 'svn merge -rREV1:REV2 URL DIR' If ERROR_RE_STRING, the merge must exit with error, and the error message must match regular expression ERROR_RE_STRING. Else if ERROR_RE_STRING is None, then: The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_TREE is given, then 'svn status' output will be compared. The 'skipped' merge output will be compared to SKIP_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. If DRY_RUN is set then a --dry-run merge will be carried out first and the output compared with that of the full merge. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() if isinstance(skip_tree, wc.State): skip_tree = skip_tree.old_tree() merge_command = ('merge', '-r', rev1 + ':' + rev2, url, dir) if dry_run: pre_disk = tree.build_tree_from_wc(dir) dry_run_command = merge_command + ('--dry-run',) dry_run_command = dry_run_command + args out_dry, err_dry = main.run_svn(error_re_string, *dry_run_command) post_disk = tree.build_tree_from_wc(dir) try: tree.compare_trees(post_disk, pre_disk) except tree.SVNTreeError: print "=============================================================" print "Dry-run merge altered working copy" print "=============================================================" raise # Update and make a tree of the output. merge_command = merge_command + args out, err = main.run_svn (error_re_string, *merge_command) if (error_re_string): rm = re.compile(error_re_string) for line in err: match = rm.search(line) if match: return raise main.SVNUnmatchedError elif err: ### we should raise a less generic error here. which? raise Failure(err) if dry_run and out != out_dry: print "=============================================================" print "Merge outputs differ" print "The dry-run merge output:" map(sys.stdout.write, out_dry) print "The full merge output:" map(sys.stdout.write, out) print "=============================================================" raise main.SVNUnmatchedError def missing_skip(a, b): print "=============================================================" print "Merge failed to skip: " + a.path print "=============================================================" raise Failure def extra_skip(a, b): print "=============================================================" print "Merge unexpectedly skipped: " + a.path print "=============================================================" raise Failure myskiptree = tree.build_tree_from_skipped(out) tree.compare_trees(myskiptree, skip_tree, extra_skip, None, missing_skip, None) mytree = tree.build_tree_from_checkout(out) verify_update (mytree, dir, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
def set_up_dir_replace(sbox): """Set up the working copy for directory replace tests, creating directory 'A/B/F/foo' with files 'new file' and 'new file2' within it (r2), and merging 'foo' onto 'C' (r3), then deleting 'A/B/F/foo' (r4).""" sbox.build() wc_dir = sbox.wc_dir C_path = sbox.ospath('A/C') F_path = sbox.ospath('A/B/F') F_url = sbox.repo_url + '/A/B/F' foo_path = os.path.join(F_path, 'foo') new_file = os.path.join(foo_path, "new file") new_file2 = os.path.join(foo_path, "new file 2") # Make directory foo in F, and add some files within it. actions.run_and_verify_svn(None, None, [], 'mkdir', foo_path) main.file_append(new_file, "Initial text in new file.\n") main.file_append(new_file2, "Initial text in new file 2.\n") main.run_svn(None, "add", new_file) main.run_svn(None, "add", new_file2) # Commit all the new content, creating r2. expected_output = wc.State( wc_dir, { 'A/B/F/foo': Item(verb='Adding'), 'A/B/F/foo/new file': Item(verb='Adding'), 'A/B/F/foo/new file 2': Item(verb='Adding'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/foo': Item(status=' ', wc_rev=2), 'A/B/F/foo/new file': Item(status=' ', wc_rev=2), 'A/B/F/foo/new file 2': Item(status=' ', wc_rev=2), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Merge foo onto C expected_output = wc.State( C_path, { 'foo': Item(status='A '), 'foo/new file': Item(status='A '), 'foo/new file 2': Item(status='A '), }) expected_mergeinfo_output = wc.State(C_path, { '': Item(status=' U'), }) expected_elision_output = wc.State(C_path, {}) expected_disk = wc.State( '', { '': Item(props={SVN_PROP_MERGEINFO: '/A/B/F:2'}), 'foo': Item(), 'foo/new file': Item("Initial text in new file.\n"), 'foo/new file 2': Item("Initial text in new file 2.\n"), }) expected_status = wc.State( C_path, { '': Item(status=' M', wc_rev=1), 'foo': Item(status='A ', wc_rev='-', copied='+'), 'foo/new file': Item(status=' ', wc_rev='-', copied='+'), 'foo/new file 2': Item(status=' ', wc_rev='-', copied='+'), }) expected_skip = wc.State(C_path, {}) actions.run_and_verify_merge(C_path, '1', '2', F_url, None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, None, None, None, None, None, 1) # Commit merge of foo onto C, creating r3. expected_output = wc.State(wc_dir, { 'A/C': Item(verb='Sending'), 'A/C/foo': Item(verb='Adding'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/B/F/foo': Item(status=' ', wc_rev=2), 'A/C': Item(status=' ', wc_rev=3), 'A/B/F/foo/new file': Item(status=' ', wc_rev=2), 'A/B/F/foo/new file 2': Item(status=' ', wc_rev=2), 'A/C/foo': Item(status=' ', wc_rev=3), 'A/C/foo/new file': Item(status=' ', wc_rev=3), 'A/C/foo/new file 2': Item(status=' ', wc_rev=3), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Delete foo on F, creating r4. actions.run_and_verify_svn(None, None, [], 'rm', foo_path) expected_output = wc.State(wc_dir, { 'A/B/F/foo': Item(verb='Deleting'), }) expected_status = actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/C': Item(status=' ', wc_rev=3), 'A/C/foo': Item(status=' ', wc_rev=3), 'A/C/foo/new file': Item(status=' ', wc_rev=3), 'A/C/foo/new file 2': Item(status=' ', wc_rev=3), }) actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir)
def run_and_verify_commit(wc_dir_name, output_tree, status_output_tree, error_re_string = None, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, b_baton = None, *args): """Commit and verify results within working copy WC_DIR_NAME, sending ARGS to the commit subcommand. The subcommand output will be verified against OUTPUT_TREE. If optional STATUS_OUTPUT_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) If ERROR_RE_STRING is None, the commit must not exit with error. If ERROR_RE_STRING is a string, the commit must exit with error, and the error message must match regular expression ERROR_RE_STRING. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(status_output_tree, wc.State): status_output_tree = status_output_tree.old_tree() # Commit. output, errput = main.run_svn(error_re_string, 'ci', '-m', 'log msg', *args) if (error_re_string): rm = re.compile(error_re_string) for line in errput: match = rm.search(line) if match: return raise main.SVNUnmatchedError # Else not expecting error: # Remove the final output line, and verify that the commit succeeded. lastline = "" if len(output): lastline = string.strip(output.pop()) cm = re.compile("(Committed|Imported) revision [0-9]+.") match = cm.search(lastline) if not match: print "ERROR: commit did not succeed." print "The final line from 'svn ci' was:" print lastline raise main.SVNCommitFailure # The new 'final' line in the output is either a regular line that # mentions {Adding, Deleting, Sending, ...}, or it could be a line # that says "Transmitting file data ...". If the latter case, we # want to remove the line from the output; it should be ignored when # building a tree. if len(output): lastline = output.pop() tm = re.compile("Transmitting file data.+") match = tm.search(lastline) if not match: # whoops, it was important output, put it back. output.append(lastline) # Convert the output into a tree. mytree = tree.build_tree_from_commit (output) # Verify actual output against expected output. try: tree.compare_trees (mytree, output_tree) except tree.SVNTreeError: display_trees("Output of commit is unexpected.", "OUTPUT TREE", output_tree, mytree) raise # Verify via 'status' command too, if possible. if status_output_tree: run_and_verify_status(wc_dir_name, status_output_tree)
def guarantee_greek_repository(path): """Guarantee that a local svn repository exists at PATH, containing nothing but the greek-tree at revision 1.""" if path == main.pristine_dir: print "ERROR: attempt to overwrite the pristine repos! Aborting." sys.exit(1) # If there's no pristine repos, create one. if not os.path.exists(main.pristine_dir): main.create_repos(main.pristine_dir) # dump the greek tree to disk. main.greek_state.write_to_disk(main.greek_dump_dir) # build a URL for doing an import. url = main.test_area_url + '/' + main.pristine_dir if main.windows == 1: url = string.replace(url, '\\', '/') # import the greek tree, using l:foo/p:bar ### todo: svn should not be prompting for auth info when using ### repositories with no auth/auth requirements output, errput = main.run_svn(None, 'import', '--username', main.wc_author, '--password', main.wc_passwd, '-m', 'Log message for revision 1.', main.greek_dump_dir, url) # check for any errors from the import if len(errput): display_lines("Errors during initial 'svn import':", 'STDERR', None, errput) sys.exit(1) # verify the printed output of 'svn import'. lastline = string.strip(output.pop()) cm = re.compile("(Committed|Imported) revision [0-9]+.") match = cm.search(lastline) if not match: print "ERROR: import did not succeed, while creating greek repos." print "The final line from 'svn import' was:" print lastline sys.exit(1) output_tree = tree.build_tree_from_commit(output) ### due to path normalization in the .old_tree() method, we cannot ### prepend the necessary '.' directory. thus, let's construct an old ### tree manually from the greek_state. output_list = [] for greek_path in main.greek_state.desc.keys(): output_list.append([ os.path.join(main.greek_dump_dir, greek_path), None, {}, { 'verb': 'Adding' } ]) expected_output_tree = tree.build_generic_tree(output_list) try: tree.compare_trees(output_tree, expected_output_tree) except tree.SVNTreeUnequal: display_trees("ERROR: output of import command is unexpected.", 'OUTPUT TREE', expected_output_tree, output_tree) sys.exit(1) # Now that the pristine repos exists, copy it to PATH. main.safe_rmtree(path) if main.copy_repos(main.pristine_dir, path, 1): print "ERROR: copying repository failed." sys.exit(1) # make the repos world-writeable, for mod_dav_svn's sake. main.chmod_tree(path, 0666, 0666)
def run_and_verify_merge2(dir, rev1, rev2, url1, url2, output_tree, disk_tree, status_tree, skip_tree, error_re_string=None, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, check_props=0, dry_run=1, *args): """Run 'svn merge URL1@REV1 URL2@REV2 DIR' if URL2 is not None (for a three-way merge between URLs and WC). If URL2 is None, run 'svn merge -rREV1:REV2 URL1 DIR'. If ERROR_RE_STRING, the merge must exit with error, and the error message must match regular expression ERROR_RE_STRING. Else if ERROR_RE_STRING is None, then: The subcommand output will be verified against OUTPUT_TREE, and the working copy itself will be verified against DISK_TREE. If optional STATUS_TREE is given, then 'svn status' output will be compared. The 'skipped' merge output will be compared to SKIP_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. If CHECK_PROPS is set, then disk comparison will examine props. If DRY_RUN is set then a --dry-run merge will be carried out first and the output compared with that of the full merge. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() if isinstance(status_tree, wc.State): status_tree = status_tree.old_tree() if isinstance(skip_tree, wc.State): skip_tree = skip_tree.old_tree() if url2: merge_command = ("merge", url1 + "@" + str(rev1), url2 + "@" + str(rev2), dir) else: merge_command = ("merge", "-r", str(rev1) + ":" + str(rev2), url1, dir) if dry_run: pre_disk = tree.build_tree_from_wc(dir) dry_run_command = merge_command + ('--dry-run', ) dry_run_command = dry_run_command + args out_dry, err_dry = main.run_svn(error_re_string, *dry_run_command) post_disk = tree.build_tree_from_wc(dir) try: tree.compare_trees(post_disk, pre_disk) except tree.SVNTreeError: print "=============================================================" print "Dry-run merge altered working copy" print "=============================================================" raise # Update and make a tree of the output. merge_command = merge_command + args out, err = main.run_svn(error_re_string, *merge_command) if (error_re_string): rm = re.compile(error_re_string) for line in err: match = rm.search(line) if match: return raise main.SVNUnmatchedError elif err: ### we should raise a less generic error here. which? raise Failure(err) if dry_run and out != out_dry: print "=============================================================" print "Merge outputs differ" print "The dry-run merge output:" map(sys.stdout.write, out_dry) print "The full merge output:" map(sys.stdout.write, out) print "=============================================================" raise main.SVNUnmatchedError def missing_skip(a, b): print "=============================================================" print "Merge failed to skip: " + a.path print "=============================================================" raise Failure def extra_skip(a, b): print "=============================================================" print "Merge unexpectedly skipped: " + a.path print "=============================================================" raise Failure myskiptree = tree.build_tree_from_skipped(out) tree.compare_trees(myskiptree, skip_tree, extra_skip, None, missing_skip, None) mytree = tree.build_tree_from_checkout(out) verify_update(mytree, dir, output_tree, disk_tree, status_tree, singleton_handler_a, a_baton, singleton_handler_b, b_baton, check_props)
def run_and_verify_commit(wc_dir_name, output_tree, status_output_tree, error_re_string=None, singleton_handler_a=None, a_baton=None, singleton_handler_b=None, b_baton=None, *args): """Commit and verify results within working copy WC_DIR_NAME, sending ARGS to the commit subcommand. The subcommand output will be verified against OUTPUT_TREE. If optional STATUS_OUTPUT_TREE is given, then 'svn status' output will be compared. (This is a good way to check that revision numbers were bumped.) If ERROR_RE_STRING is None, the commit must not exit with error. If ERROR_RE_STRING is a string, the commit must exit with error, and the error message must match regular expression ERROR_RE_STRING. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will be passed to tree.compare_trees - see that function's doc string for more details. Returns if successful, raises on failure.""" if isinstance(output_tree, wc.State): output_tree = output_tree.old_tree() if isinstance(status_output_tree, wc.State): status_output_tree = status_output_tree.old_tree() # Commit. output, errput = main.run_svn(error_re_string, 'ci', '--username', main.wc_author, '--password', main.wc_passwd, '-m', 'log msg', *args) if (error_re_string): rm = re.compile(error_re_string) for line in errput: match = rm.search(line) if match: return raise main.SVNUnmatchedError # Else not expecting error: # Remove the final output line, and verify that the commit succeeded. lastline = "" if len(output): lastline = string.strip(output.pop()) cm = re.compile("(Committed|Imported) revision [0-9]+.") match = cm.search(lastline) if not match: print "ERROR: commit did not succeed." print "The final line from 'svn ci' was:" print lastline raise main.SVNCommitFailure # The new 'final' line in the output is either a regular line that # mentions {Adding, Deleting, Sending, ...}, or it could be a line # that says "Transmitting file data ...". If the latter case, we # want to remove the line from the output; it should be ignored when # building a tree. if len(output): lastline = output.pop() tm = re.compile("Transmitting file data.+") match = tm.search(lastline) if not match: # whoops, it was important output, put it back. output.append(lastline) # Convert the output into a tree. mytree = tree.build_tree_from_commit(output) # Verify actual output against expected output. try: tree.compare_trees(mytree, output_tree) except tree.SVNTreeError: display_trees("Output of commit is unexpected.", "OUTPUT TREE", output_tree, mytree) raise # Verify via 'status' command too, if possible. if status_output_tree: run_and_verify_status(wc_dir_name, status_output_tree)