Modified: subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c Fri Sep 11 15:51:30 2015 @@ -128,9 +128,10 @@ svn_cl__accept_from_word(const char *wor /* Print on stdout a diff that shows incoming conflicting changes - * corresponding to the conflict described in DESC. */ + * corresponding to the conflict described in CONFLICT. */ static svn_error_t * -show_diff(const svn_wc_conflict_description2_t *desc, +show_diff(const svn_client_conflict_t *conflict, + const char *merged_abspath, const char *path_prefix, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -141,10 +142,13 @@ show_diff(const svn_wc_conflict_descript svn_diff_t *diff; svn_stream_t *output; svn_diff_file_options_t *options; - const char *merged_file; + const char *my_abspath; + const char *their_abspath; - merged_file = svn_client_conflict_get_merged_file(desc); - if (merged_file) + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, NULL, + &their_abspath, + conflict, pool, pool)); + if (merged_abspath) { /* For conflicts recorded by the 'merge' operation, show a diff between * 'mine' (the working version of the file as it appeared before the @@ -158,26 +162,26 @@ show_diff(const svn_wc_conflict_descript * * This way, the diff is always minimal and clearly identifies changes * brought into the working copy by the update/switch/merge operation. */ - if (svn_client_conflict_get_operation(desc) == svn_wc_operation_merge) + if (svn_client_conflict_get_operation(conflict) == svn_wc_operation_merge) { - path1 = svn_client_conflict_get_my_abspath(desc); + path1 = my_abspath; label1 = _("MINE"); } else { - path1 = svn_client_conflict_get_their_abspath(desc); + path1 = their_abspath; label1 = _("THEIRS"); } - path2 = merged_file; + path2 = merged_abspath; label2 = _("MERGED"); } else { /* There's no merged file, but we can show the difference between mine and theirs. */ - path1 = svn_client_conflict_get_their_abspath(desc); + path1 = their_abspath; label1 = _("THEIRS"); - path2 = svn_client_conflict_get_my_abspath(desc); + path2 = my_abspath; label2 = _("MINE"); } @@ -206,9 +210,9 @@ show_diff(const svn_wc_conflict_descript /* Print on stdout just the conflict hunks of a diff among the 'base', 'their' - * and 'my' files of DESC. */ + * and 'my' files of CONFLICT. */ static svn_error_t * -show_conflicts(const svn_wc_conflict_description2_t *desc, +show_conflicts(const svn_client_conflict_t *conflict, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -216,22 +220,22 @@ show_conflicts(const svn_wc_conflict_des svn_diff_t *diff; svn_stream_t *output; svn_diff_file_options_t *options; - + const char *base_abspath; + const char *my_abspath; + const char *their_abspath; + + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, &their_abspath, + conflict, pool, pool)); options = svn_diff_file_options_create(pool); options->ignore_eol_style = TRUE; SVN_ERR(svn_stream_for_stdout(&output, pool)); - SVN_ERR(svn_diff_file_diff3_2(&diff, - svn_client_conflict_get_base_abspath(desc), - svn_client_conflict_get_my_abspath(desc), - svn_client_conflict_get_their_abspath(desc), + SVN_ERR(svn_diff_file_diff3_2(&diff, base_abspath, my_abspath, their_abspath, options, pool)); /* ### Consider putting the markers/labels from ### svn_wc__merge_internal in the conflict description. */ return svn_diff_file_output_merge3( - output, diff, - svn_client_conflict_get_base_abspath(desc), - svn_client_conflict_get_my_abspath(desc), - svn_client_conflict_get_their_abspath(desc), + output, diff, base_abspath, my_abspath, their_abspath, _("||||||| ORIGINAL"), _("<<<<<<< MINE (select with 'mc')"), _(">>>>>>> THEIRS (select with 'tc')"), @@ -245,61 +249,49 @@ show_conflicts(const svn_wc_conflict_des /* Perform a 3-way merge of the conflicting values of a property, * and write the result to the OUTPUT stream. * - * If MERGED_ABSPATH is non-NULL, use it as 'my' version instead of - * DESC->MY_ABSPATH. + * If MERGED_PROPVAL is non-NULL, use it as 'my' version instead of + * MY_ABSPATH. * * Assume the values are printable UTF-8 text. */ static svn_error_t * merge_prop_conflict(svn_stream_t *output, - const svn_wc_conflict_description2_t *desc, - const char *merged_abspath, + const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, + const svn_string_t *merged_propval, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); svn_diff_file_options_t *options = svn_diff_file_options_create(pool); svn_diff_t *diff; - /* If any of the property values is missing, use an empty file instead + /* If any of the property values is missing, use an empty value instead * for the purpose of showing a diff. */ - if (! base_abspath || ! my_abspath || ! their_abspath) - { - const char *empty_file; - - SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file, - NULL, svn_io_file_del_on_pool_cleanup, - pool, pool)); - if (! base_abspath) - base_abspath = empty_file; - if (! my_abspath) - my_abspath = empty_file; - if (! their_abspath) - their_abspath = empty_file; - } - + if (base_propval == NULL) + base_propval = svn_string_create_empty(pool); + if (my_propval == NULL) + my_propval = svn_string_create_empty(pool); + if (my_propval == NULL) + my_propval = svn_string_create_empty(pool); + options->ignore_eol_style = TRUE; - SVN_ERR(svn_diff_file_diff3_2(&diff, - base_abspath, - merged_abspath ? merged_abspath : my_abspath, - their_abspath, - options, pool)); - SVN_ERR(svn_diff_file_output_merge3(output, diff, - base_abspath, - merged_abspath ? merged_abspath - : my_abspath, - their_abspath, - _("||||||| ORIGINAL"), - _("<<<<<<< MINE"), - _(">>>>>>> THEIRS"), - "=======", - svn_diff_conflict_display_modified_original_latest, - cancel_func, - cancel_baton, - pool)); + SVN_ERR(svn_diff_mem_string_diff3(&diff, base_propval, + merged_propval ? + merged_propval : my_propval, + their_propval, options, pool)); + SVN_ERR(svn_diff_mem_string_output_merge3( + output, diff, base_propval, + merged_propval ? merged_propval : my_propval, their_propval, + _("||||||| ORIGINAL"), + _("<<<<<<< MINE"), + _(">>>>>>> THEIRS"), + "=======", + svn_diff_conflict_display_modified_original_latest, + cancel_func, + cancel_baton, + pool)); return SVN_NO_ERROR; } @@ -312,8 +304,10 @@ merge_prop_conflict(svn_stream_t *output * Assume the values are printable UTF-8 text. */ static svn_error_t * -show_prop_conflict(const svn_wc_conflict_description2_t *desc, - const char *merged_abspath, +show_prop_conflict(const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, + const svn_string_t *merged_propval, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -321,13 +315,13 @@ show_prop_conflict(const svn_wc_conflict svn_stream_t *output; SVN_ERR(svn_stream_for_stdout(&output, pool)); - SVN_ERR(merge_prop_conflict(output, desc, merged_abspath, - cancel_func, cancel_baton, pool)); + SVN_ERR(merge_prop_conflict(output, base_propval, my_propval, their_propval, + merged_propval, cancel_func, cancel_baton, pool)); return SVN_NO_ERROR; } -/* Run an external editor, passing it the MERGED_FILE, or, if the +/* Run an external editor, passing it the MERGED_ABSPATH, or, if the * 'merged' file is null, return an error. The tool to use is determined by * B->editor_cmd, B->config and environment variables; see * svn_cl__edit_file_externally() for details. @@ -338,15 +332,15 @@ show_prop_conflict(const svn_wc_conflict * return that error. */ static svn_error_t * open_editor(svn_boolean_t *performed_edit, - const char *merged_file, + const char *merged_abspath, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *pool) { svn_error_t *err; - if (merged_file) + if (merged_abspath) { - err = svn_cmdline__edit_file_externally(merged_file, b->editor_cmd, + err = svn_cmdline__edit_file_externally(merged_abspath, b->editor_cmd, b->config, pool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR || err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)) @@ -371,12 +365,16 @@ open_editor(svn_boolean_t *performed_edi return SVN_NO_ERROR; } -/* Run an external editor, passing it the 'merged' property in DESC. +/* Run an external editor on the merged property value with conflict markers. + * Return the edited result in *MERGED_PROPVAL. + * If the edit is aborted, set *MERGED_ABSPATH and *MERGED_PROPVAL to NULL. * The tool to use is determined by B->editor_cmd, B->config and * environment variables; see svn_cl__edit_file_externally() for details. */ static svn_error_t * -edit_prop_conflict(const char **merged_file_path, - const svn_wc_conflict_description2_t *desc, +edit_prop_conflict(const svn_string_t **merged_propval, + const svn_string_t *base_propval, + const svn_string_t *my_propval, + const svn_string_t *their_propval, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -391,14 +389,23 @@ edit_prop_conflict(const char **merged_f result_pool, scratch_pool)); merged_prop = svn_stream_from_aprfile2(file, TRUE /* disown */, scratch_pool); - SVN_ERR(merge_prop_conflict(merged_prop, desc, NULL, + SVN_ERR(merge_prop_conflict(merged_prop, base_propval, my_propval, + their_propval, NULL, b->pb->cancel_func, b->pb->cancel_baton, scratch_pool)); SVN_ERR(svn_stream_close(merged_prop)); SVN_ERR(svn_io_file_flush(file, scratch_pool)); SVN_ERR(open_editor(&performed_edit, file_path, b, scratch_pool)); - *merged_file_path = (performed_edit ? file_path : NULL); + if (performed_edit) + { + svn_stringbuf_t *buf; + + SVN_ERR(svn_stringbuf_from_file2(&buf, file_path, scratch_pool)); + *merged_propval = svn_string_create_from_buf(buf, result_pool); + } + else + *merged_propval = NULL; return SVN_NO_ERROR; } @@ -695,13 +702,13 @@ prompt_user(const resolver_option_t **op return SVN_NO_ERROR; } -/* Ask the user what to do about the text conflict described by DESC. +/* Ask the user what to do about the text conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_text_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *scratch_pool) { @@ -715,15 +722,19 @@ handle_text_conflict(svn_wc_conflict_res give them a rational basis for choosing (r)esolved? */ svn_boolean_t knows_something = FALSE; const char *local_relpath; - const char *local_abspath = svn_client_conflict_get_local_abspath(desc); - svn_boolean_t is_binary = svn_client_conflict_get_is_binary(desc); - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); - const char *merged_file = svn_client_conflict_get_merged_file(desc); - - SVN_ERR_ASSERT(svn_client_conflict_get_kind(desc) == - svn_wc_conflict_kind_text); + const char *local_abspath = svn_client_conflict_get_local_abspath(conflict); + const char *mime_type = svn_client_conflict_text_get_mime_type(conflict); + svn_boolean_t is_binary = mime_type ? svn_mime_type_is_binary(mime_type) + : FALSE; + const char *base_abspath; + const char *my_abspath; + const char *their_abspath; + const char *merged_abspath = svn_client_conflict_get_local_abspath(conflict); + + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, &their_abspath, + conflict, scratch_pool, + scratch_pool)); local_relpath = svn_cl__local_style_skip_ancestor(b->path_prefix, local_abspath, @@ -747,7 +758,7 @@ handle_text_conflict(svn_wc_conflict_res scenario), or if no base is available, we can show a diff between mine and theirs. */ if (!is_binary && - ((merged_file && base_abspath) + ((merged_abspath && base_abspath) || (!base_abspath && my_abspath && their_abspath))) diff_allowed = TRUE; @@ -833,7 +844,7 @@ handle_text_conflict(svn_wc_conflict_res "files not available.\n\n"))); continue; } - SVN_ERR(show_conflicts(desc, + SVN_ERR(show_conflicts(conflict, b->pb->cancel_func, b->pb->cancel_baton, iterpool)); @@ -850,14 +861,14 @@ handle_text_conflict(svn_wc_conflict_res continue; } - SVN_ERR(show_diff(desc, b->path_prefix, + SVN_ERR(show_diff(conflict, merged_abspath, b->path_prefix, b->pb->cancel_func, b->pb->cancel_baton, iterpool)); knows_something = TRUE; } else if (strcmp(opt->code, "e") == 0 || strcmp(opt->code, ":-E") == 0) { - SVN_ERR(open_editor(&performed_edit, merged_file, b, iterpool)); + SVN_ERR(open_editor(&performed_edit, merged_abspath, b, iterpool)); if (performed_edit) knows_something = TRUE; } @@ -878,7 +889,7 @@ handle_text_conflict(svn_wc_conflict_res err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, NULL, iterpool); if (err) @@ -893,7 +904,7 @@ handle_text_conflict(svn_wc_conflict_res base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->path_prefix, b->editor_cmd, @@ -931,9 +942,9 @@ handle_text_conflict(svn_wc_conflict_res { /* ### This check should be earlier as it's nasty to offer an option * and then when the user chooses it say 'Invalid option'. */ - /* ### 'merged_file' shouldn't be necessary *before* we launch the + /* ### 'merged_abspath' shouldn't be necessary *before* we launch the * resolver: it should be the *result* of doing so. */ - if (base_abspath && their_abspath && my_abspath && merged_file) + if (base_abspath && their_abspath && my_abspath && merged_abspath) { svn_error_t *err; char buf[1024]; @@ -942,7 +953,7 @@ handle_text_conflict(svn_wc_conflict_res err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, NULL, iterpool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL || @@ -973,7 +984,7 @@ handle_text_conflict(svn_wc_conflict_res base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->path_prefix, b->editor_cmd, @@ -1022,41 +1033,40 @@ handle_text_conflict(svn_wc_conflict_res return SVN_NO_ERROR; } -/* Ask the user what to do about the property conflict described by DESC. +/* Ask the user what to do about the property conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_prop_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_pool_t *iterpool; const char *message; - const char *merged_file_path = NULL; + const svn_string_t *merged_propval = NULL; svn_boolean_t resolved_allowed = FALSE; - - /* ### Work around a historical bug in the provider: the path to the - * conflict description file was put in the 'theirs' field, and - * 'theirs' was put in the 'merged' field. */ - ((svn_wc_conflict_description2_t *)desc)->their_abspath = desc->merged_file; - ((svn_wc_conflict_description2_t *)desc)->merged_file = NULL; - - SVN_ERR_ASSERT(svn_client_conflict_get_kind(desc) == - svn_wc_conflict_kind_property); + const svn_string_t *base_propval; + const svn_string_t *my_propval; + const svn_string_t *their_propval; + + SVN_ERR(svn_client_conflict_prop_get_propvals(NULL, &my_propval, + &base_propval, &their_propval, + conflict, scratch_pool)); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, _("Conflict for property '%s' discovered" " on '%s'.\n"), - svn_client_conflict_get_property_name(desc), + svn_client_conflict_prop_get_propname(conflict), svn_cl__local_style_skip_ancestor( b->path_prefix, - svn_client_conflict_get_local_abspath(desc), + svn_client_conflict_get_local_abspath(conflict), scratch_pool))); - SVN_ERR(svn_cl__get_human_readable_prop_conflict_description(&message, desc, + SVN_ERR(svn_cl__get_human_readable_prop_conflict_description(&message, + conflict, scratch_pool)); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", message)); @@ -1094,15 +1104,17 @@ handle_prop_conflict(svn_wc_conflict_res } else if (strcmp(opt->code, "dc") == 0) { - SVN_ERR(show_prop_conflict(desc, merged_file_path, + SVN_ERR(show_prop_conflict(base_propval, my_propval, their_propval, + merged_propval, b->pb->cancel_func, b->pb->cancel_baton, scratch_pool)); } else if (strcmp(opt->code, "e") == 0) { - SVN_ERR(edit_prop_conflict(&merged_file_path, desc, b, - result_pool, scratch_pool)); - resolved_allowed = (merged_file_path != NULL); + SVN_ERR(edit_prop_conflict(&merged_propval, + base_propval, my_propval, their_propval, + b, result_pool, scratch_pool)); + resolved_allowed = (merged_propval != NULL); } else if (strcmp(opt->code, "r") == 0) { @@ -1114,7 +1126,7 @@ handle_prop_conflict(svn_wc_conflict_res continue; } - result->merged_file = merged_file_path; + result->merged_value = merged_propval; result->choice = svn_wc_conflict_choose_merged; break; } @@ -1129,43 +1141,58 @@ handle_prop_conflict(svn_wc_conflict_res return SVN_NO_ERROR; } -/* Ask the user what to do about the tree conflict described by DESC. +/* Ask the user what to do about the tree conflict described by CONFLICT. * Return the answer in RESULT. B is the conflict baton for this * conflict resolution session. * SCRATCH_POOL is used for temporary allocations. */ static svn_error_t * handle_tree_conflict(svn_wc_conflict_result_t *result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, svn_cl__interactive_conflict_baton_t *b, apr_pool_t *scratch_pool) { const char *readable_desc; const char *src_left_version; const char *src_right_version; + const char *repos_root_url; + const char *repos_relpath; + svn_revnum_t peg_rev; + svn_node_kind_t node_kind; apr_pool_t *iterpool; - + SVN_ERR(svn_cl__get_human_readable_tree_conflict_description( - &readable_desc, desc, scratch_pool)); + &readable_desc, conflict, scratch_pool)); SVN_ERR(svn_cmdline_fprintf( stderr, scratch_pool, _("Tree conflict on '%s'\n > %s\n"), svn_cl__local_style_skip_ancestor(b->path_prefix, - svn_client_conflict_get_local_abspath(desc), scratch_pool), + svn_client_conflict_get_local_abspath(conflict), scratch_pool), readable_desc)); + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, conflict, + scratch_pool, scratch_pool)); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); src_left_version = - svn_cl__node_description( - svn_client_conflict_get_src_left_version(desc), - svn_client_conflict_get_src_left_version(desc)->repos_url, - scratch_pool); + svn_cl__node_description(repos_root_url, repos_relpath, peg_rev, + node_kind, repos_root_url, scratch_pool); if (src_left_version) SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s: %s\n", _("Source left"), src_left_version)); + + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(&repos_relpath, + &peg_rev, + &node_kind, + conflict, + scratch_pool, + scratch_pool)); src_right_version = - svn_cl__node_description( - svn_client_conflict_get_src_right_version(desc), - svn_client_conflict_get_src_right_version(desc)->repos_url, - scratch_pool); + svn_cl__node_description(repos_root_url, repos_relpath, peg_rev, + node_kind, repos_root_url, scratch_pool); if (src_right_version) SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s: %s\n", _("Source right"), src_right_version)); @@ -1180,12 +1207,14 @@ handle_tree_conflict(svn_wc_conflict_res tc_opts = tree_conflict_options; - if (svn_client_conflict_get_operation(desc) == svn_wc_operation_update || - svn_client_conflict_get_operation(desc) == svn_wc_operation_switch) + if (svn_client_conflict_get_operation(conflict) == + svn_wc_operation_update || + svn_client_conflict_get_operation(conflict) == + svn_wc_operation_switch) { svn_wc_conflict_reason_t reason; - reason = svn_client_conflict_get_local_change(desc); + reason = svn_client_conflict_get_local_change(conflict); if (reason == svn_wc_conflict_reason_moved_away) { tc_opts = tree_conflict_options_update_moved_away; @@ -1193,9 +1222,10 @@ handle_tree_conflict(svn_wc_conflict_res else if (reason == svn_wc_conflict_reason_deleted || reason == svn_wc_conflict_reason_replaced) { - if (svn_client_conflict_get_incoming_change(desc) == + if (svn_client_conflict_get_incoming_change(conflict) == svn_wc_conflict_action_edit && - svn_client_conflict_get_node_kind(desc) == svn_node_dir) + svn_client_conflict_tree_get_victim_node_kind(conflict) == + svn_node_dir) tc_opts = tree_conflict_options_update_edit_deleted_dir; } } @@ -1225,17 +1255,24 @@ handle_tree_conflict(svn_wc_conflict_res /* The body of svn_cl__conflict_func_interactive(). */ static svn_error_t * conflict_func_interactive(svn_wc_conflict_result_t **result, - const svn_wc_conflict_description2_t *desc, + const svn_client_conflict_t *conflict, void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_cl__interactive_conflict_baton_t *b = baton; svn_error_t *err; - const char *base_abspath = svn_client_conflict_get_base_abspath(desc); - const char *my_abspath = svn_client_conflict_get_my_abspath(desc); - const char *their_abspath = svn_client_conflict_get_their_abspath(desc); - const char *merged_file = svn_client_conflict_get_merged_file(desc); + const char *base_abspath = NULL; + const char *my_abspath = NULL; + const char *their_abspath = NULL; + const char *merged_abspath = svn_client_conflict_get_local_abspath(conflict); + + if (svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_text) + SVN_ERR(svn_client_conflict_text_get_contents(NULL, &my_abspath, + &base_abspath, + &their_abspath, + conflict, scratch_pool, + scratch_pool)); /* Start out assuming we're going to postpone the conflict. */ *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, @@ -1254,10 +1291,6 @@ conflict_func_interactive(svn_wc_conflic (*result)->choice = svn_wc_conflict_choose_base; return SVN_NO_ERROR; case svn_cl__accept_working: - /* If the caller didn't merge the property values, then I guess - * 'choose working' means 'choose mine'... */ - if (! merged_file) - (*result)->merged_file = my_abspath; (*result)->choice = svn_wc_conflict_choose_merged; return SVN_NO_ERROR; case svn_cl__accept_mine_conflict: @@ -1273,7 +1306,7 @@ conflict_func_interactive(svn_wc_conflic (*result)->choice = svn_wc_conflict_choose_theirs_full; return SVN_NO_ERROR; case svn_cl__accept_edit: - if (merged_file) + if (merged_abspath) { if (b->external_failed) { @@ -1281,7 +1314,7 @@ conflict_func_interactive(svn_wc_conflic return SVN_NO_ERROR; } - err = svn_cmdline__edit_file_externally(merged_file, + err = svn_cmdline__edit_file_externally(merged_abspath, b->editor_cmd, b->config, scratch_pool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR || @@ -1304,7 +1337,7 @@ conflict_func_interactive(svn_wc_conflic /* else, fall through to prompting. */ break; case svn_cl__accept_launch: - if (base_abspath && their_abspath && my_abspath && merged_file) + if (base_abspath && their_abspath && my_abspath && merged_abspath) { svn_boolean_t remains_in_conflict; const char *local_abspath; @@ -1315,11 +1348,11 @@ conflict_func_interactive(svn_wc_conflic return SVN_NO_ERROR; } - local_abspath = svn_client_conflict_get_local_abspath(desc); + local_abspath = svn_client_conflict_get_local_abspath(conflict); err = svn_cl__merge_file_externally(base_abspath, their_abspath, my_abspath, - merged_file, + merged_abspath, local_abspath, b->config, &remains_in_conflict, @@ -1364,16 +1397,18 @@ conflict_func_interactive(svn_wc_conflic Conflicting edits on a file's text, or Conflicting edits on a property. */ - if (((svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_text) - && (svn_client_conflict_get_incoming_change(desc) == + if (((svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_text) + && (svn_client_conflict_get_incoming_change(conflict) == svn_wc_conflict_action_edit) - && (svn_client_conflict_get_local_change(desc) == + && (svn_client_conflict_get_local_change(conflict) == svn_wc_conflict_reason_edited))) - SVN_ERR(handle_text_conflict(*result, desc, b, scratch_pool)); - else if (svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_property) - SVN_ERR(handle_prop_conflict(*result, desc, b, result_pool, scratch_pool)); - else if (svn_client_conflict_get_kind(desc) == svn_wc_conflict_kind_tree) - SVN_ERR(handle_tree_conflict(*result, desc, b, scratch_pool)); + SVN_ERR(handle_text_conflict(*result, conflict, b, scratch_pool)); + else if (svn_client_conflict_get_kind(conflict) == + svn_wc_conflict_kind_property) + SVN_ERR(handle_prop_conflict(*result, conflict, b, result_pool, + scratch_pool)); + else if (svn_client_conflict_get_kind(conflict) == svn_wc_conflict_kind_tree) + SVN_ERR(handle_tree_conflict(*result, conflict, b, scratch_pool)); else /* other types of conflicts -- do nothing about them. */ { @@ -1391,8 +1426,12 @@ svn_cl__conflict_func_interactive(svn_wc apr_pool_t *scratch_pool) { svn_cl__interactive_conflict_baton_t *b = baton; + svn_client_conflict_t *conflict; - SVN_ERR(conflict_func_interactive(result, desc, baton, + SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, desc, + scratch_pool, + scratch_pool)); + SVN_ERR(conflict_func_interactive(result, conflict, baton, result_pool, scratch_pool)); /* If we are resolving a conflict, adjust the summary of conflicts. */ @@ -1400,11 +1439,11 @@ svn_cl__conflict_func_interactive(svn_wc { const char *local_path = svn_cl__local_style_skip_ancestor( - b->path_prefix, svn_client_conflict_get_local_abspath(desc), + b->path_prefix, svn_client_conflict_get_local_abspath(conflict), scratch_pool); svn_cl__conflict_stats_resolved(b->conflict_stats, local_path, - svn_client_conflict_get_kind(desc)); + svn_client_conflict_get_kind(conflict)); } return SVN_NO_ERROR; }
Modified: subversion/branches/reuse-ra-session/subversion/svn/help-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/help-cmd.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/help-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/help-cmd.c Fri Sep 11 15:51:30 2015 @@ -53,8 +53,9 @@ svn_cl__help(apr_getopt_t *os, N_("usage: svn <subcommand> [options] [args]\n" "Subversion command-line client.\n" "Type 'svn help <subcommand>' for help on a specific subcommand.\n" - "Type 'svn --version' to see the program version and RA modules\n" - " or 'svn --version --quiet' to see just the version number.\n" + "Type 'svn --version' to see the program version and RA modules,\n" + " 'svn --version --verbose' to see dependency versions as well,\n" + " 'svn --version --quiet' to see just the version number.\n" "\n" "Most subcommands take file and/or directory arguments, recursing\n" "on the directories. If no arguments are supplied to such a\n" Modified: subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/info-cmd.c Fri Sep 11 15:51:30 2015 @@ -391,15 +391,24 @@ print_info_xml(void *baton, if (info->wc_info && info->wc_info->conflicts) { int i; + apr_pool_t *iterpool; + iterpool = svn_pool_create(pool); for (i = 0; i < info->wc_info->conflicts->nelts; i++) { - const svn_wc_conflict_description2_t *conflict = + const svn_wc_conflict_description2_t *desc = APR_ARRAY_IDX(info->wc_info->conflicts, i, const svn_wc_conflict_description2_t *); + svn_client_conflict_t *conflict; - SVN_ERR(svn_cl__append_conflict_info_xml(sb, conflict, pool)); + svn_pool_clear(iterpool); + + SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, desc, + iterpool, + iterpool)); + SVN_ERR(svn_cl__append_conflict_info_xml(sb, conflict, iterpool)); } + svn_pool_destroy(iterpool); } if (info->lock) @@ -581,27 +590,37 @@ print_info(void *baton, if (info->wc_info->conflicts) { - svn_boolean_t printed_prop_conflict_file = FALSE; svn_boolean_t printed_tc = FALSE; + svn_stringbuf_t *conflicted_props = NULL; int i; + apr_pool_t *iterpool; + iterpool = svn_pool_create(pool); for (i = 0; i < info->wc_info->conflicts->nelts; i++) { - const svn_wc_conflict_description2_t *conflict = + const svn_wc_conflict_description2_t *desc2 = APR_ARRAY_IDX(info->wc_info->conflicts, i, const svn_wc_conflict_description2_t *); const char *desc; - const char *base_abspath; - const char *my_abspath; - const char *their_abspath; - - base_abspath = svn_client_conflict_get_base_abspath(conflict); - my_abspath = svn_client_conflict_get_my_abspath(conflict); - their_abspath = svn_client_conflict_get_their_abspath(conflict); - + const char *base_abspath = NULL; + const char *my_abspath = NULL; + const char *their_abspath = NULL; + svn_client_conflict_t *conflict; + + svn_pool_clear(iterpool); + + SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, + desc2, + iterpool, + iterpool)); switch (svn_client_conflict_get_kind(conflict)) { case svn_wc_conflict_kind_text: + + SVN_ERR(svn_client_conflict_text_get_contents( + NULL, &my_abspath, &base_abspath, &their_abspath, + conflict, pool, pool)); + if (base_abspath) SVN_ERR(svn_cmdline_printf(pool, _("Conflict Previous Base File: %s\n"), @@ -628,15 +647,18 @@ print_info(void *baton, break; case svn_wc_conflict_kind_property: - if (! printed_prop_conflict_file) - SVN_ERR(svn_cmdline_printf(pool, - _("Conflict Properties File: %s\n"), - svn_cl__local_style_skip_ancestor( - receiver_baton->path_prefix, - svn_client_conflict_get_prop_reject_abspath( - conflict), - pool))); - printed_prop_conflict_file = TRUE; + { + const char *name; + + name = svn_client_conflict_prop_get_propname(conflict); + if (conflicted_props == NULL) + conflicted_props = svn_stringbuf_create(name, pool); + else + { + svn_stringbuf_appendbyte(conflicted_props, ' '); + svn_stringbuf_appendcstr(conflicted_props, name); + } + } break; case svn_wc_conflict_kind_tree: @@ -650,6 +672,11 @@ print_info(void *baton, break; } } + svn_pool_destroy(iterpool); + + if (conflicted_props) + SVN_ERR(svn_cmdline_printf(pool, _("Conflicted Properties: %s\n"), + conflicted_props->data)); /* We only store one left and right version for all conflicts, which is referenced from all conflicts. @@ -658,10 +685,18 @@ print_info(void *baton, { const char *src_left_version; const char *src_right_version; - const svn_wc_conflict_description2_t *conflict = + const char *repos_root_url; + const char *repos_relpath; + svn_revnum_t peg_rev; + svn_node_kind_t node_kind; + const svn_wc_conflict_description2_t *desc2 = APR_ARRAY_IDX(info->wc_info->conflicts, 0, const svn_wc_conflict_description2_t *); + svn_client_conflict_t *conflict; + + SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, desc2, + pool, pool)); if (!printed_tc) { const char *desc; @@ -669,21 +704,28 @@ print_info(void *baton, SVN_ERR(svn_cl__get_human_readable_action_description(&desc, svn_wc_conflict_action_edit, svn_client_conflict_get_operation(conflict), - svn_client_conflict_get_node_kind(conflict), pool)); + info->kind, + pool)); SVN_ERR(svn_cmdline_printf(pool, "%s: %s\n", _("Conflict Details"), desc)); } + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, NULL, + conflict, pool, pool)); + SVN_ERR(svn_client_conflict_get_incoming_old_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + pool, pool)); src_left_version = - svn_cl__node_description( - svn_client_conflict_get_src_left_version(conflict), - info->repos_root_URL, pool); + svn_cl__node_description(repos_root_url, repos_relpath, + peg_rev, node_kind, info->repos_root_URL, pool); + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location( + &repos_relpath, &peg_rev, &node_kind, conflict, + pool, pool)); src_right_version = - svn_cl__node_description( - svn_client_conflict_get_src_right_version(conflict), - info->repos_root_URL, pool); + svn_cl__node_description(repos_root_url, repos_relpath, + peg_rev, node_kind, info->repos_root_URL, pool); if (src_left_version) SVN_ERR(svn_cmdline_printf(pool, " %s: %s\n", Modified: subversion/branches/reuse-ra-session/subversion/svn/lock-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/lock-cmd.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/lock-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/lock-cmd.c Fri Sep 11 15:51:30 2015 @@ -80,6 +80,29 @@ get_comment(const char **comment, svn_cl return SVN_NO_ERROR; } +/* Baton for notify_lock_handler */ +struct notify_lock_baton_t +{ + void *inner_baton; + svn_wc_notify_func2_t inner_notify; + svn_boolean_t had_failure; +}; + +/* Implements svn_wc_notify_func2_t for svn_cl__lock */ +static void +notify_lock_handler(void *baton, + const svn_wc_notify_t *notify, + apr_pool_t *scratch_pool) +{ + struct notify_lock_baton_t *nlb = baton; + + if (notify->action == svn_wc_notify_failed_lock) + nlb->had_failure = TRUE; + + if (nlb->inner_notify) + nlb->inner_notify(nlb->inner_baton, notify, scratch_pool); +} + /* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__lock(apr_getopt_t *os, @@ -90,6 +113,7 @@ svn_cl__lock(apr_getopt_t *os, svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; const char *comment; + struct notify_lock_baton_t nlb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, @@ -106,5 +130,18 @@ svn_cl__lock(apr_getopt_t *os, SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); - return svn_client_lock(targets, comment, opt_state->force, ctx, pool); + nlb.inner_notify = ctx->notify_func2; + nlb.inner_baton = ctx->notify_baton2; + nlb.had_failure = FALSE; + + ctx->notify_func2 = notify_lock_handler; + ctx->notify_baton2 = &nlb; + + SVN_ERR(svn_client_lock(targets, comment, opt_state->force, ctx, pool)); + + if (nlb.had_failure) + return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, + _("One or more locks could not be obtained")); + + return SVN_NO_ERROR; } Modified: subversion/branches/reuse-ra-session/subversion/svn/status.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/status.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/status.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/status.c Fri Sep 11 15:51:30 2015 @@ -282,11 +282,16 @@ print_status(const char *target_abspath, if (tree_conflicted) { - const svn_wc_conflict_description2_t *tree_conflict; - SVN_ERR(svn_wc__get_tree_conflict(&tree_conflict, ctx->wc_ctx, + const svn_wc_conflict_description2_t *desc2; + svn_client_conflict_t *tree_conflict; + + SVN_ERR(svn_wc__get_tree_conflict(&desc2, ctx->wc_ctx, local_abspath, pool, pool)); - SVN_ERR_ASSERT(tree_conflict != NULL); + SVN_ERR_ASSERT(desc2 != NULL); + SVN_ERR(svn_client_conflict_from_wc_description2_t(&tree_conflict, + desc2, + pool, pool)); tree_status_code = 'C'; SVN_ERR(svn_cl__get_human_readable_tree_conflict_description( &desc, tree_conflict, pool)); Modified: subversion/branches/reuse-ra-session/subversion/svn/svn.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/svn.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/svn.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/svn.c Fri Sep 11 15:51:30 2015 @@ -415,7 +415,39 @@ const apr_getopt_option_t svn_cl__option " " "current revision (recommended when tagging)")}, {"show-item", opt_show_item, 1, - N_("print only the item identified by ARG")}, + N_("print only the item identified by ARG:\n" + " " + " 'kind' node kind of TARGET\n" + " " + " 'url' URL of TARGET in the repository\n" + " " + " 'relative-url'\n" + " " + " repository-relative URL of TARGET\n" + " " + " 'repos-root-url'\n" + " " + " root URL of repository\n" + " " + " 'repos-uuid' UUID of repository\n" + " " + " 'revision' specified or implied revision\n" + " " + " 'last-changed-revision'\n" + " " + " last change of TARGET at or before\n" + " " + " 'revision'\n" + " " + " 'last-changed-date'\n" + " " + " date of 'last-changed-revision'\n" + " " + " 'last-changed-author'\n" + " " + " author of 'last-changed-revision'\n" + " " + " 'wc-root' root of TARGET's working copy")}, /* Long-opt Aliases * @@ -726,23 +758,12 @@ const svn_opt_subcommand_desc2_t svn_cl_ "usage: info [TARGET[@REV]...]\n" "\n" " Print information about each TARGET (default: '.').\n" - " TARGET may be either a working-copy path or URL. If specified, REV\n" - " determines in which revision the target is first looked up.\n" + " TARGET may be either a working-copy path or a URL. If specified, REV\n" + " determines in which revision the target is first looked up; the default\n" + " is HEAD for a URL or BASE for a WC path.\n" "\n" " With --show-item, print only the value of one item of information\n" - " about TARGET. One of the following items can be selected:\n" - " kind the kind of TARGET\n" - " url the URL of TARGET in the repository\n" - " relative-url the repository-relative URL\n" - " repos-root-url the repository root URL\n" - " repos-uuid the repository UUID\n" - " revision the revision of TARGET (defaults to BASE\n" - " for working copy paths and HEAD for URLs)\n" - " last-changed-revision the most recent revision in which TARGET\n" - " was changed\n" - " last-changed-date the date of the last-changed revision\n" - " last-changed-author the author of the last-changed revision\n" - " wc-root the root of TARGET's working copy"), + " about TARGET.\n"), {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml, opt_changelist, opt_include_externals, opt_show_item, opt_no_newline} }, Modified: subversion/branches/reuse-ra-session/subversion/svn/unlock-cmd.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/unlock-cmd.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/unlock-cmd.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/unlock-cmd.c Fri Sep 11 15:51:30 2015 @@ -39,6 +39,29 @@ /*** Code. ***/ +/* Baton for notify_unlock_handler */ +struct notify_unlock_baton_t +{ + void *inner_baton; + svn_wc_notify_func2_t inner_notify; + svn_boolean_t had_failure; +}; + +/* Implements svn_wc_notify_func2_t for svn_cl__unlock */ +static void +notify_unlock_handler(void *baton, + const svn_wc_notify_t *notify, + apr_pool_t *scratch_pool) +{ + struct notify_unlock_baton_t *nub = baton; + + if (notify->action == svn_wc_notify_failed_unlock) + nub->had_failure = TRUE; + + if (nub->inner_notify) + nub->inner_notify(nub->inner_baton, notify, scratch_pool); +} + /* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * @@ -49,6 +72,7 @@ svn_cl__unlock(apr_getopt_t *os, svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; + struct notify_unlock_baton_t nub; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, @@ -63,6 +87,18 @@ svn_cl__unlock(apr_getopt_t *os, SVN_ERR(svn_cl__assert_homogeneous_target_type(targets)); - return svn_error_trace( - svn_client_unlock(targets, opt_state->force, ctx, scratch_pool)); + nub.inner_notify = ctx->notify_func2; + nub.inner_baton = ctx->notify_baton2; + nub.had_failure = FALSE; + + ctx->notify_func2 = notify_unlock_handler; + ctx->notify_baton2 = &nub; + + SVN_ERR(svn_client_unlock(targets, opt_state->force, ctx, scratch_pool)); + + if (nub.had_failure) + return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, + _("One or more locks could not be released")); + + return SVN_NO_ERROR; } Modified: subversion/branches/reuse-ra-session/subversion/svn/util.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/util.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svn/util.c (original) +++ subversion/branches/reuse-ra-session/subversion/svn/util.c Fri Sep 11 15:51:30 2015 @@ -907,14 +907,17 @@ svn_cl__time_cstring_to_human_cstring(co } const char * -svn_cl__node_description(const svn_wc_conflict_version_t *node, +svn_cl__node_description(const char *repos_root_url, + const char *repos_relpath, + svn_revnum_t peg_rev, + svn_node_kind_t node_kind, const char *wc_repos_root_URL, apr_pool_t *pool) { const char *root_str = "^"; const char *path_str = "..."; - if (!node) + if (!repos_root_url || !repos_relpath || !SVN_IS_VALID_REVNUM(peg_rev)) /* Printing "(none)" the harder way to ensure conformity (mostly with * translations). */ return apr_psprintf(pool, "(%s)", @@ -923,18 +926,18 @@ svn_cl__node_description(const svn_wc_co /* Construct a "caret notation" ^/URL if NODE matches WC_REPOS_ROOT_URL. * Otherwise show the complete URL, and if we can't, show dots. */ - if (node->repos_url && + if (repos_root_url && (wc_repos_root_URL == NULL || - strcmp(node->repos_url, wc_repos_root_URL) != 0)) - root_str = node->repos_url; + strcmp(repos_root_url, wc_repos_root_URL) != 0)) + root_str = repos_root_url; - if (node->path_in_repos) - path_str = node->path_in_repos; + if (repos_relpath) + path_str = repos_relpath; return apr_psprintf(pool, "(%s) %s@%ld", - svn_cl__node_kind_str_human_readable(node->node_kind), + svn_cl__node_kind_str_human_readable(node_kind), svn_path_url_add_component2(root_str, path_str, pool), - node->peg_rev); + peg_rev); } svn_error_t * Modified: subversion/branches/reuse-ra-session/subversion/svnadmin/svnadmin.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svnadmin/svnadmin.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/svnadmin/svnadmin.c (original) +++ subversion/branches/reuse-ra-session/subversion/svnadmin/svnadmin.c Fri Sep 11 15:51:30 2015 @@ -166,11 +166,13 @@ static svn_opt_subcommand_t subcommand_delrevprop, subcommand_deltify, subcommand_dump, + subcommand_dump_revprops, subcommand_freeze, subcommand_help, subcommand_hotcopy, subcommand_info, subcommand_load, + subcommand_load_revprops, subcommand_list_dblogs, subcommand_list_unused_dblogs, subcommand_lock, @@ -392,6 +394,15 @@ static const svn_opt_subcommand_desc2_t "changed in those revisions.)\n"), {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M'} }, + {"dump-revprops", subcommand_dump_revprops, {0}, N_ + ("usage: svnadmin dump-revprops REPOS_PATH [-r LOWER[:UPPER]]\n\n" + "Dump the revision properties of filesystem to stdout in a 'dumpfile'\n" + "portable format, sending feedback to stderr. Dump revisions\n" + "LOWER rev through UPPER rev. If no revisions are given, dump the\n" + "properties for all revisions. If only LOWER is given, dump the\n" + "properties for that one revision.\n"), + {'r', 'q'} }, + {"freeze", subcommand_freeze, {0}, N_ ("usage: 1. svnadmin freeze REPOS_PATH PROGRAM [ARG...]\n" " 2. svnadmin freeze -F FILE PROGRAM [ARG...]\n\n" @@ -444,6 +455,15 @@ static const svn_opt_subcommand_desc2_t svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook, svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} }, + {"load-revprops", subcommand_load_revprops, {0}, N_ + ("usage: svnadmin load-revprops REPOS_PATH\n\n" + "Read a 'dumpfile'-formatted stream from stdin, setting the revision\n" + "properties in the repository's filesystem. Revisions not found in the\n" + "repository will cause an error. Progress feedback is sent to stdout.\n" + "If --revision is specified, limit the loaded revisions to only those\n" + "in the dump stream whose revision numbers match the specified range.\n"), + {'q', 'r', svnadmin__force_uuid, svnadmin__bypass_prop_validation} }, + {"lock", subcommand_lock, {0}, N_ ("usage: svnadmin lock REPOS_PATH PATH USERNAME COMMENT-FILE [TOKEN]\n\n" "Lock PATH by USERNAME setting comments from COMMENT-FILE.\n" @@ -864,25 +884,60 @@ err_cleanup(void *data) return APR_SUCCESS; } -struct repos_notify_handler_baton { - /* Stream to write progress and other non-error output to. */ - svn_stream_t *feedback_stream; - - /* Suppress notifications that are neither errors nor warnings. */ - svn_boolean_t silent_running; - - /* Whether errors contained in notifications should be printed along - with the notification. If FALSE, any errors will only be - summarized. */ - svn_boolean_t silent_errors; +struct repos_verify_callback_baton +{ + /* Should we continue after receiving a first verification error? */ + svn_boolean_t keep_going; /* List of errors encountered during 'svnadmin verify --keep-going'. */ apr_array_header_t *error_summary; - /* Pool for data collected during notifications. */ + /* Pool for data collected during callback invocations. */ apr_pool_t *result_pool; }; +/* Implementation of svn_repos_verify_callback_t to handle errors coming + from svn_repos_verify_fs3(). */ +static svn_error_t * +repos_verify_callback(void *baton, + svn_revnum_t revision, + svn_error_t *verify_err, + apr_pool_t *scratch_pool) +{ + struct repos_verify_callback_baton *b = baton; + + if (revision == SVN_INVALID_REVNUM) + { + SVN_ERR(svn_cmdline_fputs(_("* Error verifying repository metadata.\n"), + stderr, scratch_pool)); + } + else + { + SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, + _("* Error verifying revision %ld.\n"), + revision)); + } + + if (b->keep_going) + { + struct verification_error *verr; + + svn_handle_error2(verify_err, stderr, FALSE, "svnadmin: "); + + /* Remember the error in B->ERROR_SUMMARY. */ + verr = apr_palloc(b->result_pool, sizeof(*verr)); + verr->rev = revision; + verr->err = svn_error_dup(verify_err); + apr_pool_cleanup_register(b->result_pool, verr->err, err_cleanup, + apr_pool_cleanup_null); + APR_ARRAY_PUSH(b->error_summary, struct verification_error *) = verr; + + return SVN_NO_ERROR; + } + else + return svn_error_trace(svn_error_dup(verify_err)); +} + /* Implementation of svn_repos_notify_func_t to wrap the output to a response stream for svn_repos_dump_fs2(), svn_repos_verify_fs(), svn_repos_hotcopy3() and others. */ @@ -891,16 +946,7 @@ repos_notify_handler(void *baton, const svn_repos_notify_t *notify, apr_pool_t *scratch_pool) { - struct repos_notify_handler_baton *b = baton; - svn_stream_t *feedback_stream = b->feedback_stream; - - /* Don't print anything if the feedback stream isn't provided. - Only print errors and warnings in silent mode. */ - if (!feedback_stream - || (b->silent_running - && notify->action != svn_repos_notify_warning - && notify->action != svn_repos_notify_failure)) - return; + svn_stream_t *feedback_stream = baton; switch (notify->action) { @@ -910,32 +956,6 @@ repos_notify_handler(void *baton, notify->warning_str)); return; - case svn_repos_notify_failure: - if (notify->revision != SVN_INVALID_REVNUM) - svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool, - _("* Error verifying revision %ld.\n"), - notify->revision)); - if (notify->err) - { - if (!b->silent_errors) - svn_handle_error2(notify->err, stderr, FALSE /* non-fatal */, - "svnadmin: "); - - if (b->error_summary && notify->revision != SVN_INVALID_REVNUM) - { - struct verification_error *verr; - - verr = apr_palloc(b->result_pool, sizeof(*verr)); - verr->rev = notify->revision; - verr->err = svn_error_dup(notify->err); - apr_pool_cleanup_register(b->result_pool, verr->err, err_cleanup, - apr_pool_cleanup_null); - APR_ARRAY_PUSH(b->error_summary, - struct verification_error *) = verr; - } - } - return; - case svn_repos_notify_dump_rev_end: svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool, _("* Dumped revision %ld.\n"), @@ -1126,6 +1146,24 @@ repos_notify_handler(void *baton, _("* Copied revisions from %ld to %ld.\n"), notify->start_revision, notify->end_revision)); } + return; + + case svn_repos_notify_pack_noop: + /* For best backward compatibility, we keep silent if there were just + no more shards to pack. */ + if (notify->shard == -1) + { + svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool, + _("svnadmin: Warning - this repository is not sharded." + " Packing has no effect.\n"))); + } + return; + + case svn_repos_notify_load_revprop_set: + svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool, + _("Properties set on revision %ld.\n"), + notify->new_revision)); + return; default: return; @@ -1172,57 +1210,106 @@ recode_stream_create(FILE *std_stream, a return rw_stream; } - -/* This implements `svn_opt_subcommand_t'. */ -static svn_error_t * -subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool) +/* Read the min / max revision from the OPT_STATE, verify them against REPOS + and return them in *LOWER and *UPPER, respectively. Use SCRATCH_POOL + for temporary allocations. */ +static svn_error_t * +get_dump_range(svn_revnum_t *lower, + svn_revnum_t *upper, + svn_repos_t *repos, + struct svnadmin_opt_state *opt_state, + apr_pool_t *scratch_pool) { - struct svnadmin_opt_state *opt_state = baton; - svn_repos_t *repos; svn_fs_t *fs; - svn_stream_t *stdout_stream; - svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM; svn_revnum_t youngest; - struct repos_notify_handler_baton notify_baton = { 0 }; - /* Expect no more arguments. */ - SVN_ERR(parse_args(NULL, os, 0, 0, pool)); + *lower = SVN_INVALID_REVNUM; + *upper = SVN_INVALID_REVNUM; - SVN_ERR(open_repos(&repos, opt_state->repository_path, pool)); fs = svn_repos_fs(repos); - SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool)); + SVN_ERR(svn_fs_youngest_rev(&youngest, fs, scratch_pool)); /* Find the revision numbers at which to start and end. */ - SVN_ERR(get_revnum(&lower, &opt_state->start_revision, - youngest, repos, pool)); - SVN_ERR(get_revnum(&upper, &opt_state->end_revision, - youngest, repos, pool)); + SVN_ERR(get_revnum(lower, &opt_state->start_revision, + youngest, repos, scratch_pool)); + SVN_ERR(get_revnum(upper, &opt_state->end_revision, + youngest, repos, scratch_pool)); /* Fill in implied revisions if necessary. */ - if (lower == SVN_INVALID_REVNUM) + if (*lower == SVN_INVALID_REVNUM) { - lower = 0; - upper = youngest; + *lower = 0; + *upper = youngest; } - else if (upper == SVN_INVALID_REVNUM) + else if (*upper == SVN_INVALID_REVNUM) { - upper = lower; + *upper = *lower; } - if (lower > upper) + if (*lower > *upper) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("First revision cannot be higher than second")); + return SVN_NO_ERROR; +} + +/* This implements `svn_opt_subcommand_t'. */ +static svn_error_t * +subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool) +{ + struct svnadmin_opt_state *opt_state = baton; + svn_repos_t *repos; + svn_stream_t *stdout_stream; + svn_revnum_t lower, upper; + svn_stream_t *feedback_stream = NULL; + + /* Expect no more arguments. */ + SVN_ERR(parse_args(NULL, os, 0, 0, pool)); + + SVN_ERR(open_repos(&repos, opt_state->repository_path, pool)); + SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool)); + SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool)); /* Progress feedback goes to STDERR, unless they asked to suppress it. */ if (! opt_state->quiet) - notify_baton.feedback_stream = recode_stream_create(stderr, pool); + feedback_stream = recode_stream_create(stderr, pool); - SVN_ERR(svn_repos_dump_fs3(repos, stdout_stream, lower, upper, + SVN_ERR(svn_repos_dump_fs4(repos, stdout_stream, lower, upper, opt_state->incremental, opt_state->use_deltas, + TRUE, TRUE, + !opt_state->quiet ? repos_notify_handler : NULL, + feedback_stream, check_cancel, NULL, pool)); + + return SVN_NO_ERROR; +} + +/* This implements `svn_opt_subcommand_t'. */ +static svn_error_t * +subcommand_dump_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool) +{ + struct svnadmin_opt_state *opt_state = baton; + svn_repos_t *repos; + svn_stream_t *stdout_stream; + svn_revnum_t lower, upper; + svn_stream_t *feedback_stream = NULL; + + /* Expect no more arguments. */ + SVN_ERR(parse_args(NULL, os, 0, 0, pool)); + + SVN_ERR(open_repos(&repos, opt_state->repository_path, pool)); + SVN_ERR(get_dump_range(&lower, &upper, repos, opt_state, pool)); + + SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool)); + + /* Progress feedback goes to STDERR, unless they asked to suppress it. */ + if (! opt_state->quiet) + feedback_stream = recode_stream_create(stderr, pool); + + SVN_ERR(svn_repos_dump_fs4(repos, stdout_stream, lower, upper, + FALSE, FALSE, TRUE, FALSE, !opt_state->quiet ? repos_notify_handler : NULL, - ¬ify_baton, check_cancel, NULL, pool)); + feedback_stream, check_cancel, NULL, pool)); return SVN_NO_ERROR; } @@ -1362,43 +1449,57 @@ optrev_to_revnum(svn_revnum_t *revnum, c return SVN_NO_ERROR; } - -/* This implements `svn_opt_subcommand_t'. */ +/* Read the min / max revision from the OPT_STATE, verify them and return + them in *LOWER and *UPPER, respectively. */ static svn_error_t * -subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool) +get_load_range(svn_revnum_t *lower, + svn_revnum_t *upper, + struct svnadmin_opt_state *opt_state) { - svn_error_t *err; - struct svnadmin_opt_state *opt_state = baton; - svn_repos_t *repos; - svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM; - svn_stream_t *stdin_stream; - struct repos_notify_handler_baton notify_baton = { 0 }; - - /* Expect no more arguments. */ - SVN_ERR(parse_args(NULL, os, 0, 0, pool)); - /* Find the revision numbers at which to start and end. We only support a limited set of revision kinds: number and unspecified. */ - SVN_ERR(optrev_to_revnum(&lower, &opt_state->start_revision)); - SVN_ERR(optrev_to_revnum(&upper, &opt_state->end_revision)); + SVN_ERR(optrev_to_revnum(lower, &opt_state->start_revision)); + SVN_ERR(optrev_to_revnum(upper, &opt_state->end_revision)); /* Fill in implied revisions if necessary. */ - if ((upper == SVN_INVALID_REVNUM) && (lower != SVN_INVALID_REVNUM)) + if ((*upper == SVN_INVALID_REVNUM) && (*lower != SVN_INVALID_REVNUM)) { - upper = lower; + *upper = *lower; } - else if ((upper != SVN_INVALID_REVNUM) && (lower == SVN_INVALID_REVNUM)) + else if ((*upper != SVN_INVALID_REVNUM) && (*lower == SVN_INVALID_REVNUM)) { - lower = upper; + *lower = *upper; } /* Ensure correct range ordering. */ - if (lower > upper) + if (*lower > *upper) { return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("First revision cannot be higher than second")); } + return SVN_NO_ERROR; +} + + +/* This implements `svn_opt_subcommand_t'. */ +static svn_error_t * +subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool) +{ + svn_error_t *err; + struct svnadmin_opt_state *opt_state = baton; + svn_repos_t *repos; + svn_revnum_t lower, upper; + svn_stream_t *stdin_stream; + svn_stream_t *feedback_stream = NULL; + + /* Expect no more arguments. */ + SVN_ERR(parse_args(NULL, os, 0, 0, pool)); + + /* Find the revision numbers at which to start and end. We only + support a limited set of revision kinds: number and unspecified. */ + SVN_ERR(get_load_range(&lower, &upper, opt_state)); + SVN_ERR(open_repos(&repos, opt_state->repository_path, pool)); /* Read the stream from STDIN. Users can redirect a file. */ @@ -1406,7 +1507,7 @@ subcommand_load(apr_getopt_t *os, void * /* Progress feedback goes to STDOUT, unless they asked to suppress it. */ if (! opt_state->quiet) - notify_baton.feedback_stream = recode_stream_create(stdout, pool); + feedback_stream = recode_stream_create(stdout, pool); err = svn_repos_load_fs5(repos, stdin_stream, lower, upper, opt_state->uuid_action, opt_state->parent_dir, @@ -1415,7 +1516,7 @@ subcommand_load(apr_getopt_t *os, void * !opt_state->bypass_prop_validation, opt_state->ignore_dates, opt_state->quiet ? NULL : repos_notify_handler, - ¬ify_baton, check_cancel, NULL, pool); + feedback_stream, check_cancel, NULL, pool); if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE) return svn_error_quick_wrap(err, _("Invalid property value found in " @@ -1425,6 +1526,48 @@ subcommand_load(apr_getopt_t *os, void * return err; } +static svn_error_t * +subcommand_load_revprops(apr_getopt_t *os, void *baton, apr_pool_t *pool) +{ + svn_error_t *err; + struct svnadmin_opt_state *opt_state = baton; + svn_repos_t *repos; + svn_revnum_t lower, upper; + svn_stream_t *stdin_stream; + + svn_stream_t *feedback_stream = NULL; + + /* Expect no more arguments. */ + SVN_ERR(parse_args(NULL, os, 0, 0, pool)); + + /* Find the revision numbers at which to start and end. We only + support a limited set of revision kinds: number and unspecified. */ + SVN_ERR(get_load_range(&lower, &upper, opt_state)); + + SVN_ERR(open_repos(&repos, opt_state->repository_path, pool)); + + /* Read the stream from STDIN. Users can redirect a file. */ + SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool)); + stdin_stream = svn_stream_wrap_buffered_read(stdin_stream, pool); + + /* Progress feedback goes to STDOUT, unless they asked to suppress it. */ + if (! opt_state->quiet) + feedback_stream = recode_stream_create(stdout, pool); + + err = svn_repos_load_fs_revprops(repos, stdin_stream, lower, upper, + !opt_state->bypass_prop_validation, + opt_state->ignore_dates, + opt_state->quiet ? NULL + : repos_notify_handler, + feedback_stream, check_cancel, NULL, pool); + if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE) + return svn_error_quick_wrap(err, + _("Invalid property value found in " + "dumpstream; consider repairing the source " + "or using --bypass-prop-validation while " + "loading.")); + return err; +} /* This implements `svn_opt_subcommand_t'. */ static svn_error_t * @@ -1462,12 +1605,12 @@ subcommand_recover(apr_getopt_t *os, voi svn_repos_t *repos; svn_error_t *err; struct svnadmin_opt_state *opt_state = baton; - struct repos_notify_handler_baton notify_baton = { 0 }; + svn_stream_t *feedback_stream = NULL; /* Expect no more arguments. */ SVN_ERR(parse_args(NULL, os, 0, 0, pool)); - SVN_ERR(svn_stream_for_stdout(¬ify_baton.feedback_stream, pool)); + SVN_ERR(svn_stream_for_stdout(&feedback_stream, pool)); /* Restore default signal handlers until after we have acquired the * exclusive lock so that the user interrupt before we actually @@ -1475,7 +1618,7 @@ subcommand_recover(apr_getopt_t *os, voi setup_cancellation_signals(SIG_DFL); err = svn_repos_recover4(opt_state->repository_path, TRUE, - repos_notify_handler, ¬ify_baton, + repos_notify_handler, feedback_stream, check_cancel, NULL, pool); if (err) { @@ -1493,7 +1636,7 @@ subcommand_recover(apr_getopt_t *os, voi " another process has it open?\n"))); SVN_ERR(svn_cmdline_fflush(stdout)); SVN_ERR(svn_repos_recover4(opt_state->repository_path, FALSE, - repos_notify_handler, ¬ify_baton, + repos_notify_handler, feedback_stream, check_cancel, NULL, pool)); } @@ -1779,7 +1922,7 @@ subcommand_pack(apr_getopt_t *os, void * { struct svnadmin_opt_state *opt_state = baton; svn_repos_t *repos; - struct repos_notify_handler_baton notify_baton = { 0 }; + svn_stream_t *feedback_stream = NULL; /* Expect no more arguments. */ SVN_ERR(parse_args(NULL, os, 0, 0, pool)); @@ -1788,11 +1931,11 @@ subcommand_pack(apr_getopt_t *os, void * /* Progress feedback goes to STDOUT, unless they asked to suppress it. */ if (! opt_state->quiet) - notify_baton.feedback_stream = recode_stream_create(stdout, pool); + feedback_stream = recode_stream_create(stdout, pool); return svn_error_trace( svn_repos_fs_pack2(repos, !opt_state->quiet ? repos_notify_handler : NULL, - ¬ify_baton, check_cancel, NULL, pool)); + feedback_stream, check_cancel, NULL, pool)); } @@ -1804,10 +1947,8 @@ subcommand_verify(apr_getopt_t *os, void svn_repos_t *repos; svn_fs_t *fs; svn_revnum_t youngest, lower, upper; - struct repos_notify_handler_baton notify_baton = { 0 }; - struct repos_notify_handler_baton *notify_baton_p = ¬ify_baton; - svn_repos_notify_func_t notify_func = repos_notify_handler; - svn_error_t *verify_err; + svn_stream_t *feedback_stream = NULL; + struct repos_verify_callback_baton verify_baton = { 0 }; /* Expect no more arguments. */ SVN_ERR(parse_args(NULL, os, 0, 0, pool)); @@ -1851,42 +1992,27 @@ subcommand_verify(apr_getopt_t *os, void upper = lower; } - /* Set up the notification handler. */ - if (!opt_state->quiet || opt_state->keep_going) - { - if (opt_state->quiet) - { - notify_baton.silent_running = TRUE; - notify_baton.feedback_stream = recode_stream_create(stderr, pool); - } - else - notify_baton.feedback_stream = recode_stream_create(stdout, pool); - - if (opt_state->keep_going) - notify_baton.error_summary = - apr_array_make(pool, 0, sizeof(struct verification_error *)); - else - notify_baton.silent_errors = TRUE; - - notify_baton.result_pool = pool; - } - else - { - notify_func = NULL; - notify_baton_p = NULL; - } + if (!opt_state->quiet) + feedback_stream = recode_stream_create(stdout, pool); - verify_err = svn_repos_verify_fs3(repos, lower, upper, - opt_state->keep_going, - opt_state->check_normalization, - opt_state->metadata_only, - notify_func, notify_baton_p, - check_cancel, NULL, pool); + verify_baton.keep_going = opt_state->keep_going; + verify_baton.error_summary = + apr_array_make(pool, 0, sizeof(struct verification_error *)); + verify_baton.result_pool = pool; + + SVN_ERR(svn_repos_verify_fs3(repos, lower, upper, + opt_state->check_normalization, + opt_state->metadata_only, + !opt_state->quiet + ? repos_notify_handler : NULL, + feedback_stream, + repos_verify_callback, &verify_baton, + check_cancel, NULL, pool)); /* Show the --keep-going error summary. */ if (!opt_state->quiet && opt_state->keep_going - && notify_baton.error_summary->nelts > 0) + && verify_baton.error_summary->nelts > 0) { int rev_maxlength; svn_revnum_t end_revnum; @@ -1894,15 +2020,15 @@ subcommand_verify(apr_getopt_t *os, void int i; svn_error_clear( - svn_stream_puts(notify_baton.feedback_stream, + svn_stream_puts(feedback_stream, _("\n-----Summary of corrupt revisions-----\n"))); /* The standard column width for the revision number is 6 characters. If the revision number can potentially be larger (i.e. if end_revnum is larger than 1000000), we increase the column width as needed. */ rev_maxlength = 6; - end_revnum = APR_ARRAY_IDX(notify_baton.error_summary, - notify_baton.error_summary->nelts - 1, + end_revnum = APR_ARRAY_IDX(verify_baton.error_summary, + verify_baton.error_summary->nelts - 1, struct verification_error *)->rev; while (end_revnum >= 1000000) { @@ -1911,7 +2037,7 @@ subcommand_verify(apr_getopt_t *os, void } iterpool = svn_pool_create(pool); - for (i = 0; i < notify_baton.error_summary->nelts; i++) + for (i = 0; i < verify_baton.error_summary->nelts; i++) { struct verification_error *verr; svn_error_t *err; @@ -1919,29 +2045,40 @@ subcommand_verify(apr_getopt_t *os, void svn_pool_clear(iterpool); - verr = APR_ARRAY_IDX(notify_baton.error_summary, i, + verr = APR_ARRAY_IDX(verify_baton.error_summary, i, struct verification_error *); - rev_str = apr_psprintf(iterpool, "r%ld", verr->rev); - rev_str = apr_psprintf(iterpool, "%*s", rev_maxlength, rev_str); - for (err = svn_error_purge_tracing(verr->err); - err != SVN_NO_ERROR; err = err->child) - { - char buf[512]; - const char *message; - message = svn_err_best_message(err, buf, sizeof(buf)); - svn_error_clear(svn_stream_printf(notify_baton.feedback_stream, - iterpool, - "%s: E%06d: %s\n", - rev_str, err->apr_err, - message)); + if (verr->rev != SVN_INVALID_REVNUM) + { + rev_str = apr_psprintf(iterpool, "r%ld", verr->rev); + rev_str = apr_psprintf(iterpool, "%*s", rev_maxlength, rev_str); + for (err = svn_error_purge_tracing(verr->err); + err != SVN_NO_ERROR; err = err->child) + { + char buf[512]; + const char *message; + + message = svn_err_best_message(err, buf, sizeof(buf)); + svn_error_clear(svn_stream_printf(feedback_stream, iterpool, + "%s: E%06d: %s\n", + rev_str, err->apr_err, + message)); + } } } svn_pool_destroy(iterpool); } - return svn_error_trace(verify_err); + if (verify_baton.error_summary->nelts > 0) + { + return svn_error_createf(SVN_ERR_CL_REPOS_VERIFY_FAILED, NULL, + _("Failed to verify repository '%s'"), + svn_dirent_local_style( + opt_state->repository_path, pool)); + } + + return SVN_NO_ERROR; } /* This implements `svn_opt_subcommand_t'. */ @@ -1949,7 +2086,7 @@ svn_error_t * subcommand_hotcopy(apr_getopt_t *os, void *baton, apr_pool_t *pool) { struct svnadmin_opt_state *opt_state = baton; - struct repos_notify_handler_baton notify_baton = { 0 }; + svn_stream_t *feedback_stream = NULL; apr_array_header_t *targets; const char *new_repos_path; @@ -1960,12 +2097,12 @@ subcommand_hotcopy(apr_getopt_t *os, voi /* Progress feedback goes to STDOUT, unless they asked to suppress it. */ if (! opt_state->quiet) - notify_baton.feedback_stream = recode_stream_create(stdout, pool); + feedback_stream = recode_stream_create(stdout, pool); return svn_repos_hotcopy3(opt_state->repository_path, new_repos_path, opt_state->clean_logs, opt_state->incremental, !opt_state->quiet ? repos_notify_handler : NULL, - ¬ify_baton, check_cancel, NULL, pool); + feedback_stream, check_cancel, NULL, pool); } svn_error_t * @@ -1976,6 +2113,7 @@ subcommand_info(apr_getopt_t *os, void * svn_fs_t *fs; int fs_format; const char *uuid; + svn_revnum_t head_rev; /* Expect no more arguments. */ SVN_ERR(parse_args(NULL, os, 0, 0, pool)); @@ -1988,6 +2126,9 @@ subcommand_info(apr_getopt_t *os, void * SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool)); SVN_ERR(svn_cmdline_printf(pool, _("UUID: %s\n"), uuid)); + + SVN_ERR(svn_fs_youngest_rev(&head_rev, fs, pool)); + SVN_ERR(svn_cmdline_printf(pool, _("Revisions: %ld\n"), head_rev)); { int repos_format, minor; svn_version_t *repos_version, *fs_version; @@ -2349,18 +2490,18 @@ subcommand_upgrade(apr_getopt_t *os, voi { svn_error_t *err; struct svnadmin_opt_state *opt_state = baton; - struct repos_notify_handler_baton notify_baton = { 0 }; + svn_stream_t *feedback_stream = NULL; /* Expect no more arguments. */ SVN_ERR(parse_args(NULL, os, 0, 0, pool)); - SVN_ERR(svn_stream_for_stdout(¬ify_baton.feedback_stream, pool)); + SVN_ERR(svn_stream_for_stdout(&feedback_stream, pool)); /* Restore default signal handlers. */ setup_cancellation_signals(SIG_DFL); err = svn_repos_upgrade2(opt_state->repository_path, TRUE, - repos_notify_handler, ¬ify_baton, pool); + repos_notify_handler, feedback_stream, pool); if (err) { if (APR_STATUS_IS_EAGAIN(err->apr_err)) @@ -2378,7 +2519,7 @@ subcommand_upgrade(apr_getopt_t *os, voi " another process has it open?\n"))); SVN_ERR(svn_cmdline_fflush(stdout)); SVN_ERR(svn_repos_upgrade2(opt_state->repository_path, FALSE, - repos_notify_handler, ¬ify_baton, + repos_notify_handler, feedback_stream, pool)); } else if (err->apr_err == SVN_ERR_FS_UNSUPPORTED_UPGRADE)
