This patch is a followup of the following thread. All tests pass with this patch.
http://svn.haxx.se/dev/archive-2011-01/0210.shtml Log [[[ Make 'svn blame' continue processing targets after printing warning if one or more of the targets is a non-existent URL or wc-entry. Also return a non-zero error code and print an error message at the end in those situations. * subversion/svn/blame-cmd.c (svn_cl__blame): If one of the targets is a non-existent URL or wc-entry, don't bail out. Just warn and move on to the next target. Also return a non-zero error code and print an error message at the end in those situations. * subversion/tests/cmdline/blame_tests.py (blame_non_existent_wc_target, blame_non_existent_url_target): New tests. (test_list): Add reference to new tests. Patch by: Noorul Islam K M <noorul{_AT_}collab.net> ]]]
Index: subversion/tests/cmdline/blame_tests.py =================================================================== --- subversion/tests/cmdline/blame_tests.py (revision 1071585) +++ subversion/tests/cmdline/blame_tests.py (working copy) @@ -25,7 +25,7 @@ ###################################################################### # General modules -import os, sys +import os, sys, re # Our testing module import svntest @@ -710,7 +710,69 @@ svntest.actions.run_and_verify_svn(None, expected_output, [], 'blame', '-g', mu_path) +def blame_non_existent_wc_target(sbox): + "blame non existent wc target" + sbox.build() + + # First, make a new revision of iota. + iota = os.path.join(sbox.wc_dir, 'iota') + non_existent = os.path.join(sbox.wc_dir, 'non-existent') + svntest.main.file_append(iota, "New contents for iota\n") + svntest.main.run_svn(None, 'ci', + '-m', '', iota) + + expected_output = [ + " 1 jrandom This is the file 'iota'.\n", + " 2 jrandom New contents for iota\n", + ] + + expected_err = "svn: warning: W155010: The node '" + \ + re.escape(os.path.abspath(non_existent)) + "' was not found.\n" + \ + ".*\nsvn: E200009: Could not perform blame on all targets " + \ + "because some targets don't exist\n" + expected_err_re = re.compile(expected_err) + + exit_code, output, error = svntest.main.run_svn(1, 'blame', + non_existent, iota) + + # Verify error + if not expected_err_re.match("".join(error)): + raise svntest.Failure('blame failed: expected error "%s", but received ' + '"%s"' % (expected_err, "".join(error))) + +def blame_non_existent_url_target(sbox): + "blame non existent url target" + + sbox.build() + + # First, make a new revision of iota. + iota = os.path.join(sbox.wc_dir, 'iota') + iota_url = sbox.repo_url + '/iota' + non_existent = sbox.repo_url + '/non-existent' + svntest.main.file_append(iota, "New contents for iota\n") + svntest.main.run_svn(None, 'ci', + '-m', '', iota) + + expected_output = [ + " 1 jrandom This is the file 'iota'.\n", + " 2 jrandom New contents for iota\n", + ] + + expected_err = "svn: warning: W160017: '/non-existent' " + \ + "is not a file in revision 2\n" + \ + ".*\nsvn: E200009: Could not perform blame on all targets " + \ + "because some targets don't exist\n" + expected_err_re = re.compile(expected_err) + + exit_code, output, error = svntest.main.run_svn(1, 'blame', + non_existent, iota_url) + + # Verify error + if not expected_err_re.match("".join(error)): + raise svntest.Failure('blame failed: expected error "%s", but received ' + '"%s"' % (expected_err, "".join(error))) + ######################################################################## # Run the tests @@ -731,6 +793,8 @@ blame_peg_rev_file_not_in_head, blame_file_not_in_head, blame_output_after_merge, + blame_non_existent_wc_target, + blame_non_existent_url_target, ] if __name__ == '__main__': Index: subversion/svn/blame-cmd.c =================================================================== --- subversion/svn/blame-cmd.c (revision 1071585) +++ subversion/svn/blame-cmd.c (working copy) @@ -245,6 +245,7 @@ int i; svn_boolean_t end_revision_unspecified = FALSE; svn_diff_file_options_t *diff_options = svn_diff_file_options_create(pool); + svn_boolean_t seen_nonexistent_target = FALSE; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, @@ -377,6 +378,14 @@ _("Skipping binary file: '%s'\n"), target)); } + else if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || + err->apr_err == SVN_ERR_FS_NOT_FILE) + { + svn_handle_warning2(stderr, err, "svn: "); + svn_error_clear(err); + err = NULL; + seen_nonexistent_target = TRUE; + } else { return svn_error_return(err); @@ -396,5 +405,11 @@ if (opt_state->xml && ! opt_state->incremental) SVN_ERR(svn_cl__xml_print_footer("blame", pool)); - return SVN_NO_ERROR; + if (seen_nonexistent_target) + return svn_error_create( + SVN_ERR_ILLEGAL_TARGET, NULL, + _("Could not perform blame on all targets because some " + "targets don't exist")); + else + return SVN_NO_ERROR; }