Modified: subversion/branches/1.9.x/subversion/tests/libsvn_wc/op-depth-test.c URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/subversion/tests/libsvn_wc/op-depth-test.c?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/subversion/tests/libsvn_wc/op-depth-test.c (original) +++ subversion/branches/1.9.x/subversion/tests/libsvn_wc/op-depth-test.c Sat Feb 28 10:37:27 2015 @@ -128,6 +128,7 @@ typedef struct conflict_info_t { #define NO_COPY_FROM SVN_INVALID_REVNUM, NULL, FALSE #define MOVED_HERE FALSE, NULL, TRUE #define NOT_MOVED FALSE, NULL, FALSE +#define FILE_EXTERNAL TRUE /* Return a comma-separated list of the prop names in PROPS, in lexically * ascending order, or NULL if PROPS is empty or NULL. (Here, we don't @@ -176,13 +177,17 @@ print_row(const nodes_row_t *row, else moved_to_str = ""; - if (row->moved_here) + if (row->moved_here && !row->file_external && !row->moved_to) moved_here_str = ", MOVED_HERE"; + else if (row->moved_to) + moved_here_str = ", TRUE"; else moved_here_str = ""; if (row->file_external) - file_external_str = ", file-external"; + file_external_str = ", FILE_EXTERNAL"; + else if (row->moved_to || row->props) + file_external_str = ", FALSE"; else file_external_str = ""; @@ -194,14 +199,14 @@ print_row(const nodes_row_t *row, if (row->repo_revnum == SVN_INVALID_REVNUM) return apr_psprintf(result_pool, "%d, %-20s%-15s NO_COPY_FROM%s%s%s%s", row->op_depth, relpath_str, presence_str, - moved_here_str, moved_to_str, - file_external_str, props); + file_external_str, moved_here_str, moved_to_str, + props); else return apr_psprintf(result_pool, "%d, %-20s%-15s %d, \"%s\"%s%s%s%s", row->op_depth, relpath_str, presence_str, (int)row->repo_revnum, row->repo_relpath, - moved_here_str, moved_to_str, - file_external_str, props); + file_external_str, moved_here_str, moved_to_str, + props); } /* A baton to pass through svn_hash_diff() to compare_nodes_rows(). */ typedef struct comparison_baton_t { @@ -562,6 +567,34 @@ check_db_conflicts(svn_test__sandbox_t * return comparison_baton.errors; } +static svn_error_t * +verify_db_callback(void *baton, + const char *wc_abspath, + const char *local_relpath, + int op_depth, + int id, + const char *msg, + apr_pool_t *scratch_pool) +{ + if (op_depth >= 0) + return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, + "Verify: %s: %s (%d): SV%04d %s", + wc_abspath, local_relpath, op_depth, id, msg); + else + return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, + "DB-VRFY: %s: %s: SV%04d %s", + wc_abspath, local_relpath, id, msg); +} + +static svn_error_t * +verify_db(svn_test__sandbox_t *b) +{ + SVN_ERR(svn_wc__db_verify_db_full(b->wc_ctx->db, b->wc_abspath, + verify_db_callback, NULL, b->pool)); + + return SVN_NO_ERROR; +} + /* ---------------------------------------------------------------------- */ /* The test functions */ @@ -1267,6 +1300,34 @@ insert_dirs(svn_test__sandbox_t *b, ? svn_relpath_dirname(nodes->local_relpath, b->pool) : NULL)); + + if (nodes->moved_to) + SVN_ERR(svn_sqlite__bind_text(stmt, 7, nodes->moved_to)); + if (nodes->moved_here) + SVN_ERR(svn_sqlite__bind_int(stmt, 8, 1)); + if (nodes->props) + { + int i; + apr_hash_t *props = apr_hash_make(b->pool); + apr_array_header_t *names = svn_cstring_split(nodes->props, ",", + TRUE, b->pool); + + for (i = 0; i < names->nelts; i++) + { + const char *name = APR_ARRAY_IDX(names, i, const char *); + svn_hash_sets(props, name, svn_string_create(name, b->pool)); + } + + SVN_ERR(svn_sqlite__bind_properties(stmt, 9, props, b->pool)); + } + else if (nodes->repo_relpath + && strcmp(nodes->presence, "normal") == 0) + { + SVN_ERR(svn_sqlite__bind_text(stmt, 9, "()")); + } + + /* File externals? */ + SVN_ERR(svn_sqlite__step_done(stmt)); ++nodes; } @@ -1317,9 +1378,7 @@ base_dir_insert_remove(svn_test__sandbox SVN_ERR(check_db_rows(b, "", after)); SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath, - FALSE /* keep_as_Working */, - FALSE /* queue_deletes */, - FALSE /* remove_locks */, + FALSE, FALSE, FALSE, SVN_INVALID_REVNUM, NULL, NULL, b->pool)); SVN_ERR(svn_wc__wq_run(b->wc_ctx->db, dir_abspath, @@ -2031,6 +2090,9 @@ insert_actual(svn_test__sandbox_t *b, SVN_ERR(svn_sqlite__step_done(stmt)); if (actual->changelist) { + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_ENSURE_EMPTY_PRISTINE)); + SVN_ERR(svn_sqlite__step_done(stmt)); SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_NODES_SET_FILE)); SVN_ERR(svn_sqlite__bindf(stmt, "s", actual->local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); @@ -2780,8 +2842,8 @@ test_children_of_replaced_dir(const svn_ &children_array, b.wc_ctx->db, A_abspath, pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, working_children_inc_hidden, pool)); - SVN_ERR(svn_wc__node_get_children(&children_array, b.wc_ctx, A_abspath, - TRUE /* show_hidden */, pool, pool)); + SVN_ERR(svn_wc__db_read_children(&children_array, b.wc_ctx->db, A_abspath, + pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, all_children_inc_hidden, pool)); /* I am not testing svn_wc__node_get_children(show_hidden=FALSE) because @@ -2790,12 +2852,7 @@ test_children_of_replaced_dir(const svn_ * a 'hidden' child of the working dir (so should be excluded). */ SVN_ERR(svn_wc__node_get_children_of_working_node( - &children_array, b.wc_ctx, A_abspath, TRUE /* show_hidden */, - pool, pool)); - SVN_ERR(CHECK_ARRAY(children_array, working_children_inc_hidden, pool)); - - SVN_ERR(svn_wc__node_get_children_of_working_node( - &children_array, b.wc_ctx, A_abspath, FALSE /* show_hidden */, + &children_array, b.wc_ctx, A_abspath, pool, pool)); SVN_ERR(CHECK_ARRAY(children_array, working_children_exc_hidden, pool)); @@ -3729,6 +3786,8 @@ incomplete_switch(const svn_test_opts_t }; SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(svn_io_remove_dir2(sbox_wc_path(&b, "A/B/C/D"), FALSE, + NULL, NULL, pool)); SVN_ERR(check_db_rows(&b, "", before)); SVN_ERR(sbox_wc_update(&b, "", 4)); SVN_ERR(check_db_rows(&b, "", after_update)); @@ -6914,6 +6973,31 @@ commit_moved_descendant(const svn_test_o shadowed, like in this case. The commit processing doesn't support this yet though*/ + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 2, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 2, "A/A/A/A/A/A"}, + {0, "A_copied", "normal", 2, "A_copied"}, + {0, "A_copied/A", "normal", 2, "A_copied/A"}, + {0, "A_copied/A/A", "normal", 2, "A_copied/A/A"}, + {0, "A_copied/A/A/A", "normal", 2, "A_copied/A/A/A"}, + {0, "A_copied/A/A/A/A", "normal", 2, "A_copied/A/A/A/A"}, + {0, "A_copied/A/A/A/A/A","normal", 2, "A_copied/A/A/A/A/A"}, + {0, "AAA_moved", "normal", 2, "AAA_moved"}, + {0, "AAA_moved/A", "normal", 2, "AAA_moved/A"}, + {0, "AAA_moved/A/A", "normal", 2, "AAA_moved/A/A"}, + {0, "AAA_moved/A/A/A", "normal", 2, "AAA_moved/A/A/A"}, + + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + return SVN_NO_ERROR; } @@ -6936,10 +7020,63 @@ commit_moved_away_descendant(const svn_t SVN_ERR(sbox_wc_delete(&b, "A/A")); SVN_ERR(sbox_wc_copy(&b, "A_copied/A", "A/A")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 1, "A/A"}, + {0, "A/A/A", "normal", 1, "A/A/A"}, + {0, "A/A/A/A", "normal", 1, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "A_copied", "normal", 1, "A"}, + {1, "A_copied/A", "normal", 1, "A/A"}, + {1, "A_copied/A/A", "normal", 1, "A/A/A"}, + {1, "A_copied/A/A/A", "normal", 1, "A/A/A/A"}, + {1, "A_copied/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "A_copied/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "AAA_moved", "normal", 1, "A/A/A", MOVED_HERE}, + {1, "AAA_moved/A", "normal", 1, "A/A/A/A", MOVED_HERE}, + {1, "AAA_moved/A/A", "normal", 1, "A/A/A/A/A", MOVED_HERE}, + {1, "AAA_moved/A/A/A", "normal", 1, "A/A/A/A/A/A", MOVED_HERE}, + {2, "A/A", "normal", 1, "A/A"}, + {2, "A/A/A", "normal", 1, "A/A/A", FALSE, "AAA_moved"}, + {2, "A/A/A/A", "normal", 1, "A/A/A/A"}, + {2, "A/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {2, "A/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + /* And now I want to make sure that I can't commit A, without also committing AAA_moved, as that would break the move*/ SVN_ERR(sbox_wc_commit(&b, "A")); + { + nodes_row_t nodes[] = { + {0, "", "normal", 0, ""}, + {0, "A", "normal", 1, "A"}, + {0, "A/A", "normal", 2, "A/A"}, + {0, "A/A/A", "normal", 2, "A/A/A"}, + {0, "A/A/A/A", "normal", 2, "A/A/A/A"}, + {0, "A/A/A/A/A", "normal", 2, "A/A/A/A/A"}, + {0, "A/A/A/A/A/A", "normal", 2, "A/A/A/A/A/A"}, + {1, "A_copied", "normal", 1, "A"}, + {1, "A_copied/A", "normal", 1, "A/A"}, + {1, "A_copied/A/A", "normal", 1, "A/A/A"}, + {1, "A_copied/A/A/A", "normal", 1, "A/A/A/A"}, + {1, "A_copied/A/A/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "A_copied/A/A/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {1, "AAA_moved", "normal", 1, "A/A/A"}, + {1, "AAA_moved/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_moved/A/A", "normal", 1, "A/A/A/A/A"}, + {1, "AAA_moved/A/A/A", "normal", 1, "A/A/A/A/A/A"}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + } + return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "The commit should have failed"); @@ -7162,11 +7299,23 @@ move_away_delete_update(const svn_test_o {0, "", "normal", 2, ""}, {0, "A", "normal", 2, "A"}, {0, "P", "normal", 2, "P"}, - {1, "C2", "normal", 1, "A/B/C"}, + {1, "C2", "normal", 1, "A/B/C", MOVED_HERE}, {1, "Q2", "normal", 1, "P/Q"}, + + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C"}, + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "C2"}, + {0} + }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_edited}}, + {"P/Q", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_moved_away, "P/Q"}}, {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } return SVN_NO_ERROR; @@ -8307,7 +8456,15 @@ move_retract(const svn_test_opts_t *opts {0} }; + conflict_info_t conflicts[] = { + {"A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "A/A"}}, + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + { 0 }, + }; SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } @@ -8338,9 +8495,21 @@ move_retract(const svn_test_opts_t *opts /* Still conflicted */ {1, "D", "normal", 1, "A/B/A/D", MOVED_HERE }, + {4, "A/B/A/C", "normal", 1, "A/A/A/C"}, + + {0} }; + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"A/B/A/C", FALSE, FALSE, {svn_wc_conflict_action_delete, + svn_wc_conflict_reason_edited}}, + {0} + }; + SVN_ERR(check_db_rows(&b, "", nodes)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } /* ### TODO: Resolve via which specific target? */ @@ -8350,7 +8519,7 @@ move_retract(const svn_test_opts_t *opts { nodes_row_t nodes[] = { - {1, "D", "normal", 2, "A/B/A/D", MOVED_HERE }, + {1, "D", "normal", 1, "A/B/A/D", MOVED_HERE }, {0} }; @@ -8608,36 +8777,46 @@ move_update_parent_replace(const svn_tes SVN_ERR(sbox_wc_update(&b, "", 2)); { nodes_row_t nodes[] = { - {0, "", "normal", 2, ""}, - {0, "A", "normal", 2, "A"}, - {0, "A/B", "normal", 2, "A/B"}, - {2, "A/C", "normal", 1, "A/B/C"}, + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + + {2, "A/C", "normal", 1, "A/B/C", MOVED_HERE}, + + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C", FALSE}, + + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "A/C"}, + {0} }; - actual_row_t actual[] = { - {"A/B", NULL}, + conflict_info_t conflicts[] = { + {"A/B", FALSE, FALSE, {svn_wc_conflict_action_replace, + svn_wc_conflict_reason_edited}}, {0} }; SVN_ERR(check_db_rows(&b, "", nodes)); - SVN_ERR(check_db_actual(&b, actual)); + SVN_ERR(check_db_conflicts(&b, "", conflicts)); } SVN_ERR(sbox_wc_resolve(&b, "A/B", svn_depth_infinity, - svn_wc_conflict_choose_mine_conflict)); + svn_wc_conflict_choose_merged)); { nodes_row_t nodes[] = { - {0, "", "normal", 2, ""}, - {0, "A", "normal", 2, "A"}, - {0, "A/B", "normal", 2, "A/B"}, - {2, "A/C", "normal", 1, "A/B/C"}, - {0} - }; - actual_row_t actual[] = { + {0, "", "normal", 2, ""}, + {0, "A", "normal", 2, "A"}, + {0, "A/B", "normal", 2, "A/B"}, + {2, "A/C", "normal", 1, "A/B/C", MOVED_HERE}, + {2, "A/B", "normal", 1, "A/B"}, + {2, "A/B/C", "normal", 1, "A/B/C", FALSE}, + {3, "A/B/C", "base-deleted", NO_COPY_FROM, "A/C"}, + {0} }; + SVN_ERR(check_db_rows(&b, "", nodes)); - SVN_ERR(check_db_actual(&b, actual)); + SVN_ERR(check_db_conflicts(&b, "", NULL)); } return SVN_NO_ERROR; @@ -9471,8 +9650,14 @@ del4_update_edit_AAA(const svn_test_opts SVN_ERR(check_db_conflicts(&b, "", conflicts)); } + /* This breaks the move A/A/A -> AAA_1 */ + SVN_ERR(sbox_wc_resolve(&b, "A", svn_depth_empty, svn_wc_conflict_choose_merged)); + /* This breaks the move B -> A */ + SVN_ERR(sbox_wc_resolve(&b, "B", svn_depth_empty, svn_wc_conflict_choose_merged)); + /* This breaks the move C/A/A -> A/A */ + SVN_ERR(sbox_wc_resolve(&b, "C/A", svn_depth_empty, svn_wc_conflict_choose_merged)); /* This breaks the move from D/A/A -> A/A/A */ - SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); + SVN_ERR(sbox_wc_resolve(&b, "D/A/A", svn_depth_empty, svn_wc_conflict_choose_merged)); { nodes_row_t nodes[] = { @@ -9495,12 +9680,12 @@ del4_update_edit_AAA(const svn_test_opts {0, "D/A/A/A", "normal", 2, "D/A/A/A", NOT_MOVED, "key"}, {1, "A", "normal", 1, "B"}, {1, "A/A", "normal", 1, "B/A"}, - {1, "A/A/A", "normal", 1, "B/A/A", FALSE, "AAA_1"}, + {1, "A/A/A", "normal", 1, "B/A/A", FALSE}, {1, "A/A/A/A", "normal", 1, "B/A/A/A"}, - {1, "AAA_1", "normal", 1, "A/A/A", MOVED_HERE}, - {1, "AAA_1/A", "normal", 1, "A/A/A/A", MOVED_HERE}, - {1, "AAA_2", "normal", 1, "B/A/A"}, - {1, "AAA_2/A", "normal", 1, "B/A/A/A"}, + {1, "AAA_1", "normal", 1, "A/A/A"}, + {1, "AAA_1/A", "normal", 1, "A/A/A/A"}, + {1, "AAA_2", "normal", 1, "B/A/A", MOVED_HERE}, + {1, "AAA_2/A", "normal", 1, "B/A/A/A", MOVED_HERE}, {1, "AAA_3", "normal", 1, "C/A/A", MOVED_HERE}, {1, "AAA_3/A", "normal", 1, "C/A/A/A", MOVED_HERE}, {1, "B", "base-deleted", NO_COPY_FROM}, @@ -9508,7 +9693,7 @@ del4_update_edit_AAA(const svn_test_opts {1, "B/A/A", "base-deleted", NO_COPY_FROM}, {1, "B/A/A/A", "base-deleted", NO_COPY_FROM}, {2, "A/A", "normal", 1, "C/A"}, - {2, "A/A/A", "normal", 1, "C/A/A"}, + {2, "A/A/A", "normal", 1, "C/A/A", FALSE, "AAA_2"}, {2, "A/A/A/A", "normal", 1, "C/A/A/A"}, {2, "C/A", "base-deleted", NO_COPY_FROM}, {2, "C/A/A", "base-deleted", NO_COPY_FROM}, @@ -9537,12 +9722,53 @@ del4_update_delete_AAA(const svn_test_op /* Update and resolve via mine strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Go back to start position */ SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Update and resolve via their strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); return SVN_NO_ERROR; @@ -9557,12 +9783,53 @@ del4_update_add_AAA(const svn_test_opts_ /* Update and resolve via mine strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Go back to start position */ SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Update and resolve via their strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); return SVN_NO_ERROR; @@ -9577,12 +9844,57 @@ del4_update_replace_AAA(const svn_test_o /* Update and resolve via mine strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Go back to start position */ SVN_ERR(sbox_wc_update(&b, "", 1)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_mine_conflict)); /* Update and resolve via their strategy */ SVN_ERR(sbox_wc_update(&b, "", 2)); + { + conflict_info_t conflicts[] = { + {"A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_replaced}}, + {"B", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "B"}}, + {"C/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "C/A"}}, + {"D/A/A", FALSE, FALSE, {svn_wc_conflict_action_edit, + svn_wc_conflict_reason_moved_away, "D/A/A"}}, + {0} + }; + + SVN_ERR(check_db_conflicts(&b, "", conflicts)); + } SVN_ERR(sbox_wc_resolve(&b, "", svn_depth_infinity, svn_wc_conflict_choose_merged)); return SVN_NO_ERROR; @@ -10035,7 +10347,7 @@ move4_update_delself_AAA(const svn_test_ conflict_info_t conflicts[] = { {"A", FALSE, FALSE, { svn_wc_conflict_action_edit, - svn_wc_conflict_reason_moved_away, "A"}}, + svn_wc_conflict_reason_replaced}}, {"B", FALSE, FALSE, { svn_wc_conflict_action_edit, svn_wc_conflict_reason_moved_away, "B"}}, {"C/A", FALSE, FALSE, { svn_wc_conflict_action_edit, @@ -10990,10 +11302,474 @@ move_deep_bump(const svn_test_opts_t *op return SVN_NO_ERROR; } + +static svn_error_t * +make_copy_mixed(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "make_copy_mixed", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/O")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_propset(&b, "k", "r2", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r3", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r4", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r5", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_update(&b, "", 5)); + SVN_ERR(sbox_wc_update(&b, "A", 4)); + SVN_ERR(sbox_wc_update(&b, "A/B", 3)); + SVN_ERR(sbox_wc_update(&b, "A/B/C", 2)); + SVN_ERR(sbox_wc_update(&b, "A/B/K", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/O", 3)); + + SVN_ERR(sbox_wc_delete(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_delete(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + + SVN_ERR(sbox_wc_update(&b, "A/N/P", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1)); + SVN_ERR(sbox_wc_delete(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q")); + SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H")); + + /* And something that can't be represented */ + SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1)); + SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"}, + {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(svn_wc__db_op_make_copy(b.wc_ctx->db, sbox_wc_path(&b, "A"), + NULL, NULL, pool)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "A", "normal", 4, "A"}, + {1, "A/B", "not-present", 3, "A/B"}, + {1, "A/B/C", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C/D", "base-deleted", NO_COPY_FROM}, + {1, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {1, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {1, "A/B/G/I", "base-deleted", NO_COPY_FROM}, + {1, "A/B/G/J", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K/L", "base-deleted", NO_COPY_FROM}, + {1, "A/B/K/M", "base-deleted", NO_COPY_FROM}, + {1, "A/N", "normal", 4, "A/N"}, + {1, "A/N/O", "not-present", 3, "A/N/O"}, + {1, "A/N/P", "not-present", 1, "A/N/P"}, + {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE, "Q"}, + {1, "A/R", "normal", 4, "A/R"}, + {1, "A/R/S", "normal", 4, "A/R/S"}, + {1, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {2, "A/B", "normal", 3, "A/B"}, + {2, "A/B/C", "not-present", 2, "A/B/C"}, + {2, "A/B/G", "normal", 3, "A/B/G"}, + {2, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {2, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {2, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {2, "A/B/K", "not-present", 1, "A/B/K"}, + {3, "A/B/C", "normal", 2, "A/B/C"}, + {3, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {3, "A/B/C/E", "not-present", 1, "A/B/C/E"}, + {3, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {3, "A/B/K", "normal", 1, "A/B/K"}, + {3, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {3, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {3, "A/N/O", "normal", 3, "A/N/O"}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(verify_db(&b)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +make_copy_and_delete_mixed(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "make_copy_and_del_mixed", opts, pool)); + + SVN_ERR(sbox_wc_mkdir(&b, "A")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/O")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S")); + SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_update(&b, "", 1)); + SVN_ERR(sbox_wc_propset(&b, "k", "r2", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r3", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r4", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + SVN_ERR(sbox_wc_propset(&b, "k", "r5", "")); + SVN_ERR(sbox_wc_commit(&b, "")); + + SVN_ERR(sbox_wc_update(&b, "", 5)); + SVN_ERR(sbox_wc_update(&b, "A", 4)); + SVN_ERR(sbox_wc_update(&b, "A/B", 3)); + SVN_ERR(sbox_wc_update(&b, "A/B/C", 2)); + SVN_ERR(sbox_wc_update(&b, "A/B/K", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/O", 3)); + + SVN_ERR(sbox_wc_delete(&b, "A/B/C/F")); + SVN_ERR(sbox_wc_delete(&b, "A/B/G/J")); + SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J")); + + SVN_ERR(sbox_wc_update(&b, "A/N/P", 1)); + SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1)); + SVN_ERR(sbox_wc_delete(&b, "A/N/P")); + SVN_ERR(sbox_wc_mkdir(&b, "A/N/P")); + SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q")); + SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H")); + + /* And something that can't be represented */ + SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1)); + SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E")); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "normal", 4, "A"}, + {0, "A/B", "normal", 3, "A/B"}, + {0, "A/B/C", "normal", 2, "A/B/C"}, + {0, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {0, "A/B/C/E", "normal", 1, "A/B/C/E"}, + {0, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {0, "A/B/G", "normal", 3, "A/B/G"}, + {0, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {0, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {0, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {0, "A/B/K", "normal", 1, "A/B/K"}, + {0, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {0, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {0, "A/N", "normal", 4, "A/N"}, + {0, "A/N/O", "normal", 3, "A/N/O"}, + {0, "A/N/P", "normal", 1, "A/N/P"}, + {0, "A/N/Q", "normal", 1, "A/N/Q"}, + {0, "A/R", "normal", 4, "A/R"}, + {0, "A/R/S", "normal", 4, "A/R/S"}, + {0, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"}, + {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(svn_wc__db_base_remove(b.wc_ctx->db, sbox_wc_path(&b, "A"), + TRUE, TRUE, FALSE, 99, + NULL, NULL, pool)); + + { + nodes_row_t nodes[] = { + {0, "", "normal", 5, "", NOT_MOVED, "k"}, + {0, "A", "not-present", 99, "A"}, + {1, "A", "normal", 4, "A"}, + {1, "A/B", "not-present", 3, "A/B"}, + {1, "A/N", "normal", 4, "A/N"}, + {1, "A/N/O", "not-present", 3, "A/N/O"}, + {1, "A/N/P", "not-present", 1, "A/N/P"}, + {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE}, + {1, "A/R", "normal", 4, "A/R"}, + {1, "A/R/S", "normal", 4, "A/R/S"}, + {1, "A/R/S/T", "normal", 4, "A/R/S/T"}, + {1, "E", "normal", 1, "A/B/C/E"}, + {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE}, + {1, "Q", "normal", 1, "A/N/Q"}, + {2, "A/B", "normal", 3, "A/B"}, + {2, "A/B/C", "not-present", 2, "A/B/C"}, + {2, "A/B/G", "normal", 3, "A/B/G"}, + {2, "A/B/G/H", "normal", 3, "A/B/G/H"}, + {2, "A/B/G/I", "normal", 3, "A/B/G/I"}, + {2, "A/B/G/J", "normal", 3, "A/B/G/J"}, + {3, "A/B/C", "normal", 2, "A/B/C"}, + {3, "A/B/C/D", "normal", 2, "A/B/C/D"}, + {3, "A/B/C/E", "not-present", 1, "A/B/C/E"}, + {3, "A/B/C/F", "normal", 2, "A/B/C/F"}, + {2, "A/B/K", "not-present", 1, "A/B/K"}, + {3, "A/B/K", "normal", 1, "A/B/K"}, + {3, "A/B/K/L", "normal", 1, "A/B/K/L"}, + {3, "A/B/K/M", "normal", 1, "A/B/K/M"}, + {3, "A/N/O", "normal", 3, "A/N/O"}, + {3, "A/N/P", "normal", NO_COPY_FROM}, + {4, "A/B/C/F", "base-deleted", NO_COPY_FROM}, + {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"}, + {4, "A/B/G/J", "normal", NO_COPY_FROM}, + + {0} + }; + + /* This currently fails because Q and E are still marked as moved, + while there is nothing to be moved. */ + SVN_ERR(check_db_rows(&b, "", nodes)); + } + + SVN_ERR(verify_db(&b)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_global_commit(const svn_test_opts_t *opts, apr_pool_t *pool) +{ + svn_test__sandbox_t b; + + SVN_ERR(svn_test__sandbox_create(&b, "global_commit", opts, pool)); + + { + nodes_row_t before[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 2, "A/B" }, + { 0, "A/B/C", "normal", 2, "A/B/C" }, + { 0, "A/B/D", "normal", 2, "A/B/D" }, + { 0, "A/B/D/E", "normal", 2, "A/B/D/E" }, + { 0, "A/F", "normal", 2, "A/F" }, + { 0, "A/F/G", "normal", 2, "A/F/G" }, + { 0, "A/F/H", "normal", 2, "A/F/H" }, + { 0, "A/F/E", "normal", 2, "A/F/E" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "C", "normal", 2, "A/B/C", MOVED_HERE}, + { 1, "E", "normal", 2, "A/B/D/E", MOVED_HERE}, + { 2, "A/B", "normal", 3, "some", MOVED_HERE }, + { 2, "A/B/C", "base-deleted", NO_COPY_FROM, "C" }, + { 2, "A/B/D", "normal", 3, "some/D", MOVED_HERE}, + { 2, "A/B/D/E", "not-present", 3, "some/D/E", FALSE, "E", TRUE}, + { 3, "A/B/C", "normal", NO_COPY_FROM}, + { 2, "A/F", "normal", 1, "S2" }, + { 2, "A/F/G", "normal", 1, "S2/G" }, + { 2, "A/F/H", "not-present", 1, "S2/H" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, + { 1, "some", "normal", 3, "some", FALSE, "A/B"}, + { 0 } + }; + SVN_ERR(insert_dirs(&b, before)); + SVN_ERR(check_db_rows(&b, "", before)); /* Check move insertion logic */ + SVN_ERR(verify_db(&b)); + } + + /* This should break the moves */ + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B"), + 5, 5, 700, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 0, "A/F", "normal", 2, "A/F" }, + { 0, "A/F/G", "normal", 2, "A/F/G" }, + { 0, "A/F/H", "normal", 2, "A/F/H" }, + { 0, "A/F/E", "normal", 2, "A/F/E" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "C", "normal", 2, "A/B/C"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "some", "normal", 3, "some"}, + { 3, "A/B/C", "normal", NO_COPY_FROM}, + { 2, "A/F", "normal", 1, "S2" }, + { 2, "A/F/G", "normal", 1, "S2/G" }, + { 2, "A/F/H", "not-present", 1, "S2/H" }, + { 2, "A/F/E", "base-deleted", NO_COPY_FROM }, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/F"), + 6, 6, 800, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 0, "A/F", "normal", 6, "A/F" }, + { 0, "A/F/G", "normal", 6, "A/F/G" }, + { 0, "A/F/H", "not-present", 6, "A/F/H" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "C", "normal", 2, "A/B/C"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "some", "normal", 3, "some"}, + { 3, "A/B/C", "normal", NO_COPY_FROM }, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + SVN_ERR(svn_wc__db_global_commit(b.wc_ctx->db, + sbox_wc_path(&b, "A/B/C"), + 7, 7, 900, "me", NULL, NULL, + FALSE, FALSE, NULL, pool)); + + { + nodes_row_t after[] = { + { 0, "", "normal", 2, "" }, + { 0, "A", "normal", 2, "A" }, + { 0, "A/B", "normal", 5, "A/B" }, + { 0, "A/B/C", "normal", 7, "A/B/C"}, + { 0, "A/B/D", "normal", 5, "A/B/D"}, + { 0, "A/B/D/E", "not-present", 5, "A/B/D/E"}, + { 0, "A/F", "normal", 6, "A/F" }, + { 0, "A/F/G", "normal", 6, "A/F/G" }, + { 0, "A/F/H", "not-present", 6, "A/F/H" }, + { 0, "A/X", "normal", 2, "A/X" }, + { 0, "A/X/Y", "incomplete", 2, "A/X/Y" }, + { 1, "some", "normal", 3, "some"}, + { 1, "E", "normal", 2, "A/B/D/E"}, + { 1, "C", "normal", 2, "A/B/C"}, + { 0 } + }; + + SVN_ERR(check_db_rows(&b, "", after)); + SVN_ERR(verify_db(&b)); + } + + return SVN_NO_ERROR; +} + /* ---------------------------------------------------------------------- */ /* The list of test functions */ -static int max_threads = 2; +static int max_threads = 4; static struct svn_test_descriptor_t test_funcs[] = { @@ -11139,7 +11915,7 @@ static struct svn_test_descriptor_t test "move_parent_into_child (issue 4333)"), SVN_TEST_OPTS_PASS(move_depth_expand, "move depth expansion"), - SVN_TEST_OPTS_PASS(move_retract, + SVN_TEST_OPTS_XFAIL(move_retract, "move retract (issue 4336)"), SVN_TEST_OPTS_PASS(move_delete_file_externals, "move/delete file externals (issue 4293)"), @@ -11161,11 +11937,11 @@ static struct svn_test_descriptor_t test "move twice and then delete"), SVN_TEST_OPTS_PASS(del4_update_edit_AAA, "del4: edit AAA"), - SVN_TEST_OPTS_PASS(del4_update_delete_AAA, + SVN_TEST_OPTS_XFAIL(del4_update_delete_AAA, "del4: delete AAA"), - SVN_TEST_OPTS_PASS(del4_update_add_AAA, + SVN_TEST_OPTS_XFAIL(del4_update_add_AAA, "del4: add AAA"), - SVN_TEST_OPTS_PASS(del4_update_replace_AAA, + SVN_TEST_OPTS_XFAIL(del4_update_replace_AAA, "del4: replace AAA"), SVN_TEST_OPTS_PASS(del4_update_delself_AAA, "del4: delete self AAA"), @@ -11173,11 +11949,11 @@ static struct svn_test_descriptor_t test "del4: replace self AAA"), SVN_TEST_OPTS_PASS(move4_update_edit_AAA, "move4: edit AAA"), - SVN_TEST_OPTS_PASS(move4_update_delete_AAA, + SVN_TEST_OPTS_XFAIL(move4_update_delete_AAA, "move4: delete AAA"), - SVN_TEST_OPTS_PASS(move4_update_add_AAA, + SVN_TEST_OPTS_XFAIL(move4_update_add_AAA, "move4: add AAA"), - SVN_TEST_OPTS_PASS(move4_update_replace_AAA, + SVN_TEST_OPTS_XFAIL(move4_update_replace_AAA, "move4: replace AAA"), SVN_TEST_OPTS_PASS(move4_update_delself_AAA, "move4: delete self AAA"), @@ -11199,6 +11975,12 @@ static struct svn_test_descriptor_t test "move edit obstruction"), SVN_TEST_OPTS_PASS(move_deep_bump, "move deep bump"), + SVN_TEST_OPTS_PASS(make_copy_mixed, + "make a copy of a mixed revision tree"), + SVN_TEST_OPTS_PASS(make_copy_and_delete_mixed, + "make a copy of a mixed revision tree and del"), + SVN_TEST_OPTS_PASS(test_global_commit, + "test global commit"), SVN_TEST_NULL };
Modified: subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.c URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.c?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.c (original) +++ subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.c Sat Feb 28 10:37:27 2015 @@ -33,7 +33,7 @@ #include "../../libsvn_wc/wc-queries.h" #define SVN_WC__I_AM_WC_DB #include "../../libsvn_wc/wc_db_private.h" - +#include "../../libsvn_wc/token-map.h" svn_error_t * svn_test__create_client_ctx(svn_client_ctx_t **ctx, svn_test__sandbox_t *sbox, @@ -122,6 +122,9 @@ WC_QUERIES_SQL_DECLARE_STATEMENTS(statem svn_error_t * svn_test__create_fake_wc(const char *wc_abspath, const char *extra_statements, + const svn_test__nodes_data_t nodes[], + const svn_test__actual_data_t actuals[], + apr_pool_t *scratch_pool) { const char *dotsvn_abspath = svn_dirent_join(wc_abspath, ".svn", @@ -129,6 +132,8 @@ svn_test__create_fake_wc(const char *wc_ svn_sqlite__db_t *sdb; const char **my_statements; int i; + svn_sqlite__stmt_t *stmt; + const apr_int64_t wc_id = 1; /* Allocate MY_STATEMENTS in RESULT_POOL because the SDB will continue to * refer to it over its lifetime. */ @@ -153,6 +158,110 @@ svn_test__create_fake_wc(const char *wc_ SVN_ERR(svn_sqlite__close(sdb)); + if (!nodes && !actuals) + return SVN_NO_ERROR; + + /* Re-open with normal set of statements */ + SVN_ERR(svn_wc__db_util_open_db(&sdb, wc_abspath, "wc.db", + svn_sqlite__mode_readwrite, + FALSE /* exclusive */, 0 /* timeout */, + statements, + scratch_pool, scratch_pool)); + + if (nodes) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_INSERT_NODE)); + + for (i = 0; nodes[i].local_relpath; i++) + { + SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnns", + wc_id, + nodes[i].local_relpath, + nodes[i].op_depth, + nodes[i].local_relpath[0] + ? svn_relpath_dirname(nodes[i].local_relpath, + scratch_pool) + : NULL, + nodes[i].presence)); + + if (nodes[i].repos_relpath) + { + SVN_ERR(svn_sqlite__bind_int64(stmt, 5, nodes[i].repos_id)); + SVN_ERR(svn_sqlite__bind_text(stmt, 6, nodes[i].repos_relpath)); + SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, nodes[i].revision)); + } + + if (nodes[i].depth) + SVN_ERR(svn_sqlite__bind_text(stmt, 9, nodes[i].depth)); + + if (nodes[i].kind != 0) + SVN_ERR(svn_sqlite__bind_token(stmt, 10, kind_map, nodes[i].kind)); + + if (nodes[i].last_author || nodes[i].last_date) + { + SVN_ERR(svn_sqlite__bind_revnum(stmt, 11, nodes[i].last_revision)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 12, nodes[i].last_date)); + SVN_ERR(svn_sqlite__bind_text(stmt, 13, nodes[i].last_author)); + } + + if (nodes[i].checksum) + SVN_ERR(svn_sqlite__bind_text(stmt, 14, nodes[i].checksum)); + + if (nodes[i].properties) + SVN_ERR(svn_sqlite__bind_text(stmt, 15, nodes[i].properties)); + + if (nodes[i].recorded_size || nodes[i].recorded_time) + { + SVN_ERR(svn_sqlite__bind_int64(stmt, 16, nodes[i].recorded_size)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 17, nodes[i].recorded_time)); + } + + /* 18 is DAV cache */ + + if (nodes[i].symlink_target) + SVN_ERR(svn_sqlite__bind_text(stmt, 19, nodes[i].symlink_target)); + + if (nodes[i].file_external) + SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1)); + + if (nodes[i].moved_to) + SVN_ERR(svn_sqlite__bind_text(stmt, 21, nodes[i].moved_to)); + + if (nodes[i].moved_here) + SVN_ERR(svn_sqlite__bind_int(stmt, 22, 1)); + + if (nodes[i].inherited_props) + SVN_ERR(svn_sqlite__bind_text(stmt, 23, nodes[i].inherited_props)); + + SVN_ERR(svn_sqlite__step_done(stmt)); + } + } + + if (actuals) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, + STMT_INSERT_ACTUAL_NODE)); + + for (i = 0; actuals[i].local_relpath; i++) + { + SVN_ERR(svn_sqlite__bindf(stmt, "isssss", + wc_id, + actuals[i].local_relpath, + actuals[i].local_relpath[0] + ? svn_relpath_dirname(actuals[i].local_relpath, + scratch_pool) + : NULL, + actuals[i].properties, + actuals[i].changelist, + actuals[i].conflict_data)); + + SVN_ERR(svn_sqlite__step_done(stmt)); + } + } + + SVN_ERR(svn_sqlite__close(sdb)); + return SVN_NO_ERROR; } @@ -284,6 +393,7 @@ sbox_wc_copy_url(svn_test__sandbox_t *b, FALSE /* copy_as_child */, FALSE /* make_parents */, FALSE /* ignore_externals */, + FALSE /* metadata_only */, FALSE, NULL /* pin_external */, NULL /* revprops */, NULL, NULL, /* commit_callback */ Modified: subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.h URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.h?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.h (original) +++ subversion/branches/1.9.x/subversion/tests/libsvn_wc/utils.h Sat Feb 28 10:37:27 2015 @@ -179,6 +179,39 @@ sbox_wc_propset(svn_test__sandbox_t *b, svn_error_t * sbox_add_and_commit_greek_tree(svn_test__sandbox_t *b); +/* Initial data to store in NODES */ +typedef struct svn_test__nodes_data_t +{ + int op_depth; + const char *local_relpath; + const char *presence; + int repos_id; + const char *repos_relpath; + svn_revnum_t revision; + svn_boolean_t moved_here; + const char *moved_to; + svn_node_kind_t kind; + const char *properties; + const char *depth; + const char *checksum; + const char *symlink_target; + svn_revnum_t last_revision; + apr_time_t last_date; + const char *last_author; + svn_boolean_t file_external; + const char *inherited_props; + svn_filesize_t recorded_size; + apr_time_t recorded_time; +} svn_test__nodes_data_t; + +/* Initial data to store in ACTUAL */ +typedef struct svn_test__actual_data_t +{ + const char *local_relpath; + const char *properties; + const char *changelist; + const char *conflict_data; +} svn_test__actual_data_t; /* Create a WC directory at WC_ABSPATH containing a fake WC DB, generated by * executing the SQL statements EXTRA_STATEMENTS in addition to the standard @@ -186,6 +219,8 @@ sbox_add_and_commit_greek_tree(svn_test_ svn_error_t * svn_test__create_fake_wc(const char *wc_abspath, const char *extra_statements, + const svn_test__nodes_data_t nodes[], + const svn_test__actual_data_t actuals[], apr_pool_t *scratch_pool); Modified: subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-queries-test.c URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-queries-test.c?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-queries-test.c (original) +++ subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-queries-test.c Sat Feb 28 10:37:27 2015 @@ -984,6 +984,59 @@ test_schema_statistics(apr_pool_t *scrat return SVN_NO_ERROR; } +/* An SQLite application defined function that allows SQL queries to + use "relpath_depth(local_relpath)". */ +static void relpath_depth_sqlite(sqlite3_context* context, + int argc, + sqlite3_value* values[]) +{ + SVN_ERR_MALFUNCTION_NO_RETURN(); /* STUB! */ +} + +/* Parse all verify/check queries */ +static svn_error_t * +test_verify_parsable(apr_pool_t *scratch_pool) +{ + sqlite3 *sdb; + int i; + + SVN_ERR(create_memory_db(&sdb, scratch_pool)); + + SQLITE_ERR(sqlite3_create_function(sdb, "relpath_depth", 1, SQLITE_ANY, NULL, + relpath_depth_sqlite, NULL, NULL)); + + for (i=STMT_VERIFICATION_TRIGGERS; wc_queries[i]; i++) + { + sqlite3_stmt *stmt; + const char *text = wc_queries[i]; + + /* Some of our statement texts contain multiple queries. We prepare + them all. */ + while (*text != '\0') + { + const char *tail; + int r = sqlite3_prepare_v2(sdb, text, -1, &stmt, &tail); + + if (r != SQLITE_OK) + return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL, + "Preparing %s failed: %s\n%s", + wc_query_info[i][0], + sqlite3_errmsg(sdb), + text); + + SQLITE_ERR(sqlite3_finalize(stmt)); + + /* Continue after the current statement */ + text = tail; + } + } + + SQLITE_ERR(sqlite3_close(sdb)); /* Close the DB if ok; otherwise leaked */ + + return SVN_NO_ERROR; +} + + static int max_threads = 1; static struct svn_test_descriptor_t test_funcs[] = @@ -999,6 +1052,8 @@ static struct svn_test_descriptor_t test "test query duplicates"), SVN_TEST_PASS2(test_schema_statistics, "test schema statistics"), + SVN_TEST_PASS2(test_verify_parsable, + "verify queries are parsable"), SVN_TEST_NULL }; Modified: subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-test-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-test-queries.sql?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-test-queries.sql (original) +++ subversion/branches/1.9.x/subversion/tests/libsvn_wc/wc-test-queries.sql Sat Feb 28 10:37:27 2015 @@ -44,8 +44,10 @@ DELETE FROM nodes; -- STMT_INSERT_NODE INSERT INTO nodes (local_relpath, op_depth, presence, repos_path, - revision, parent_relpath, wc_id, repos_id, kind, depth) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, 1, + revision, parent_relpath, moved_to, moved_here, + properties, wc_id, repos_id, kind, + depth) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, 1, CASE WHEN ?3 != 'base-deleted' THEN 1 END, 'dir', CASE WHEN ?3 in ('normal', 'incomplete') @@ -58,8 +60,18 @@ DELETE FROM actual_node; INSERT INTO actual_node (local_relpath, parent_relpath, changelist, wc_id) VALUES (?1, ?2, ?3, 1) +-- STMT_ENSURE_EMPTY_PRISTINE +INSERT OR IGNORE INTO pristine (checksum, md5_checksum, size, refcount) + VALUES ('$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', + '$md5 $d41d8cd98f00b204e9800998ecf8427e', + 0, 0) + -- STMT_NODES_SET_FILE -UPDATE nodes SET kind = 'file' WHERE wc_id = 1 and local_relpath = ?1 +UPDATE nodes + SET kind = 'file', + checksum = '$sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709', + depth = NULL +WHERE wc_id = 1 and local_relpath = ?1 -- STMT_SELECT_ALL_ACTUAL SELECT local_relpath FROM actual_node WHERE wc_id = 1 Modified: subversion/branches/1.9.x/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh (original) +++ subversion/branches/1.9.x/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh Sat Feb 28 10:37:27 2015 @@ -30,10 +30,10 @@ export LD_PRELOAD_64 if [ $SVN_VER_MINOR -eq 9 ]; then echo "============ make svnserveautocheck" - make svnserveautocheck CLEANUP=1 PARALLEL=30 THREADED=1 + make svnserveautocheck CLEANUP=1 PARALLEL=30 THREADED=1 || exit $? else echo "============ make check" - make check CLEANUP=1 PARALLEL=30 THREADED=1 + make check CLEANUP=1 PARALLEL=30 THREADED=1 || exit $? fi exit 0 Modified: subversion/branches/1.9.x/tools/client-side/bash_completion URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/tools/client-side/bash_completion?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/tools/client-side/bash_completion (original) +++ subversion/branches/1.9.x/tools/client-side/bash_completion Sat Feb 28 10:37:27 2015 @@ -781,7 +781,7 @@ _svn() # otherwise build possible options for the command pOpts="--username --password --no-auth-cache --non-interactive \ - --trust-server-cert --trust-unknown-ca --trust-cn-mismatch \ + --trust-unknown-ca --trust-cn-mismatch \ --trust-expired --trust-not-yet-valid --trust-other-failure \ --force-interactive" mOpts="-m --message -F --file --encoding --force-log --with-revprop" @@ -829,7 +829,7 @@ _svn() ;; copy|cp) cmdOpts="$mOpts $rOpts $qOpts --editor-cmd $pOpts --parents \ - --ignore-externals" + --ignore-externals --pin-externals" ;; delete|del|remove|rm) cmdOpts="--force $mOpts $qOpts --targets --editor-cmd $pOpts \ @@ -856,7 +856,8 @@ _svn() ;; info) cmdOpts="$pOpts $rOpts --targets -R --recursive --depth \ - --include-externals --incremental --xml $cOpts" + --include-externals --incremental --xml \ + --show-item --no-newline $cOpts" ;; list|ls) cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \ @@ -876,7 +877,7 @@ _svn() merge) cmdOpts="$rOpts $nOpts $qOpts --force --dry-run --diff3-cmd \ $pOpts --ignore-ancestry -c --change -x --extensions \ - --record-only --accept --reintegrate \ + --record-only --accept \ --allow-mixed-revisions -v --verbose" ;; mergeinfo) @@ -905,7 +906,7 @@ _svn() cmdOpts="$cmdOpts --revprop $rOpts" ;; propget|pget|pg) - cmdOpts="-v --verbose -R --recursive $rOpts --strict \ + cmdOpts="-v --verbose -R --recursive $rOpts --no-newline \ $pOpts $cOpts --depth --xml --show-inherited-props" [[ $isRevProp || ! $prop ]] && cmdOpts="$cmdOpts --revprop" ;; Modified: subversion/branches/1.9.x/tools/client-side/bash_completion_test URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/tools/client-side/bash_completion_test?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/tools/client-side/bash_completion_test (original) +++ subversion/branches/1.9.x/tools/client-side/bash_completion_test Sat Feb 28 10:37:27 2015 @@ -114,14 +114,18 @@ get_svn_subcommands() { # Usage: get_svn_options SUBCMD get_svn_options() { { svn help "$1" | + # Remove deprecated options + grep -v deprecated | # Find the relevant lines; remove "arg" and description. sed -n -e '1,/^Valid options:$/d;/^ -/!d' \ -e 's/\( ARG\)* * : .*//;p' | # Remove brackets; put each word on its own line. tr -d '] ' | tr '[' '\n' # The following options are always accepted but not listed in the help - echo "-h" - echo "--help" + if [ "$1" != "help" ] ; then + echo "-h" + echo "--help" + fi } | sort } Modified: subversion/branches/1.9.x/tools/dist/backport.pl URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/tools/dist/backport.pl?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/tools/dist/backport.pl (original) +++ subversion/branches/1.9.x/tools/dist/backport.pl Sat Feb 28 10:37:27 2015 @@ -3,6 +3,8 @@ use warnings; use strict; use feature qw/switch say/; +#no warnings 'experimental::smartmatch'; + # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -26,6 +28,8 @@ use Term::ReadKey qw/ReadMode ReadKey/; use File::Basename qw/basename dirname/; use File::Copy qw/copy move/; use File::Temp qw/tempfile/; +use IO::Select (); +use IPC::Open3 qw/open3/; use POSIX qw/ctermid strftime isprint isspace/; use Text::Wrap qw/wrap/; use Tie::File (); @@ -97,6 +101,7 @@ unless (defined $AVAILID) { my $STATUS = './STATUS'; my $STATEFILE = './.backports1'; my $BRANCHES = '^/subversion/branches'; +my $TRUNK = '^/subversion/trunk'; $ENV{LC_ALL} = "C"; # since we parse 'svn info' output and use isprint() # Globals. @@ -178,12 +183,30 @@ to open a shell, and manually run 'svn c in the environment before running the script, in which case answering 'y' to the first prompt will not only run the merge but also commit it. -There is also a batch mode (normally used only by cron jobs and buildbot tasks, -rather than interactively): when \$YES and \$MAY_COMMIT are defined to '1' in -the environment, this script will iterate the "Approved:" section, and merge -and commit each entry therein. If only \$YES is defined, the script will -merge every nomination (including unapproved and vetoed ones), and complain -to stderr if it notices any conflicts. +There are two batch modes. The first mode is used by the nightly svn-role +mergebot. It is enabled by setting \$YES and \$MAY_COMMIT to '1' in the +environment. In this mode, the script will iterate the "Approved changes:" +section and merge and commit each entry therein. To prevent an entry from +being auto-merged, veto it or move it to a new section named "Approved, but +merge manually:". + +The second batch mode is used by the hourly conflicts detector bot. It is +triggered by having \$YES defined in the environment to '1' and \$MAY_COMMIT +undefined. In this mode, the script will locally merge every nomination +(including unapproved and vetoed ones), and complain to stderr if the merge +failed due to a conflict. This mode never commits anything. + +The hourly conflicts detector bot turns red if any entry produced a merge +conflict. When entry A depends on entry B for a clean merge, put a "Depends:" +header on entry A to instruct the bot not to turn red due to A. (The header +is not parsed; only its presence or absence matters.) + +Both batch modes also perform a basic sanity-check on entries that declare +backport branches (via the "Branch:" header): if a backport branch is used, but +at least one of the revisions enumerated in the entry title had not been merged +from $TRUNK to the branch root, the hourly bot will turn red and +nightly bot will skip the entry and email its admins. (The nightly bot does +not email the list on failure, since it doesn't use buildbot.) The 'svn' binary defined by the environment variable \$SVN, or otherwise the 'svn' found in \$PATH, will be used to manage the working copy. @@ -286,7 +309,7 @@ sub shell_escape { sub shell_safe_path_or_url($) { local $_ = shift; - return m{^[A-Za-z0-9._:+/-]+$} and !/^-|^[+]/; + return (m{^[A-Za-z0-9._:+/-]+$} and !/^-|^[+]/); } # Shell-safety-validating wrapper for File::Temp::tempfile @@ -297,9 +320,46 @@ sub my_tempfile { return ($fh, $fn); } +# The first argument is a shell script. Run it and return the shell's +# exit code, and stdout and stderr as references to arrays of lines. +sub run_in_shell($) { + my $script = shift; + my $pid = open3 \*SHELL_IN, \*SHELL_OUT, \*SHELL_ERR, qw#/bin/sh#; + # open3 raises exception when it fails; no need to error check + + print SHELL_IN $script; + close SHELL_IN; + + # Read loop: tee stdout,stderr to arrays. + my $select = IO::Select->new(\*SHELL_OUT, \*SHELL_ERR); + my (@readable, $outlines, $errlines); + while (@readable = $select->can_read) { + for my $fh (@readable) { + my $line = <$fh>; + $select->remove($fh) if eof $fh or not defined $line; + next unless defined $line; + + if ($fh == \*SHELL_OUT) { + push @$outlines, $line; + print STDOUT $line; + } + if ($fh == \*SHELL_ERR) { + push @$errlines, $line; + print STDERR $line; + } + } + } + waitpid $pid, 0; # sets $? + return $?, $outlines, $errlines; +} + +# EXPECTED_ERROR_P is subref called with EXIT_CODE, OUTLINES, ERRLINES, +# expected to return TRUE if the error should be considered fatal (cause +# backport.pl to exit non-zero) or not. It may be undef for default behaviour. sub merge { - my %entry = @_; + my %entry = %{ +shift }; + my $expected_error_p = shift // sub { 0 }; # by default, errors are unexpected my $parno = $entry{parno} - scalar grep { $_->{parno} < $entry{parno} } @MERGES_TODAY; my ($logmsg_fh, $logmsg_filename) = my_tempfile(); @@ -413,15 +473,26 @@ EOF revert(verbose => 0, discard_STATUS => $MAY_COMMIT); $MERGED_SOMETHING++; - open SHELL, '|-', qw#/bin/sh# or die "$! (in '$entry{header}')"; - print SHELL $script; - close SHELL or do { - warn "$0: sh($?): $! (in '$entry{header}')"; - die "Lost track of paragraph numbers; aborting" if $MAY_COMMIT - }; - $ERRORS{$entry{id}} = [\%entry, "sh($?): $!"] if $?; + my ($exit_code, $outlines, $errlines) = run_in_shell $script; + unless ($! == 0) { + die "system() failed to spawn subshell ($!); aborting"; + } + unless ($exit_code == 0) { + warn "$0: subshell exited with code $exit_code (in '$entry{header}') " + ."(maybe due to 'set -e'?)"; + + # If we're committing, don't attempt to guess the problem and gracefully + # continue; just abort. + if ($MAY_COMMIT) { + die "Lost track of paragraph numbers; aborting"; + } + + # Record the error, unless the caller wants not to. + $ERRORS{$entry{id}} = [\%entry, "subshell exited with code $exit_code"] + unless $expected_error_p->($exit_code, $outlines, $errlines); + } - unlink $logmsg_filename unless $? or $!; + unlink $logmsg_filename unless $exit_code; } # Input formats: @@ -810,6 +881,37 @@ sub exit_stage_left { exit scalar keys %ERRORS; } +# Given an ENTRY, check whether all ENTRY->{revisions} have been merged +# into ENTRY->{branch}, if it has one. If revisions are missing, record +# a warning in $ERRORS. Return TRUE If the entry passed the validation +# and FALSE otherwise. +sub validate_branch_contains_named_revisions { + my %entry = @_; + return 1 unless defined $entry{branch}; + my %present; + + return "Why are you running so old versions?" # true in boolean context + if $SVNvsn < 1_005_000; # doesn't have the 'mergeinfo' subcommand + + my $shell_escaped_branch = shell_escape($entry{branch}); + %present = do { + my @present = `$SVN mergeinfo --show-revs=merged -- $TRUNK $BRANCHES/$shell_escaped_branch`; + chomp @present; + @present = map /(\d+)/g, @present; + map +($_ => 1), @present; + }; + + my @absent = grep { not exists $present{$_} } @{$entry{revisions}}; + + if (@absent) { + $ERRORS{$entry{id}} //= [\%entry, + sprintf("Revisions '%s' nominated but not included in branch", + (join ", ", map { "r$_" } @absent)), + ]; + } + return @absent ? 0 : 1; +} + sub handle_entry { my $in_approved = shift; my $approved = shift; @@ -829,10 +931,23 @@ sub handle_entry { unless (@vetoes) { if ($MAY_COMMIT and $in_approved) { # svn-role mode - merge %entry; + merge \%entry if validate_branch_contains_named_revisions %entry; } elsif (!$MAY_COMMIT) { # Scan-for-conflicts mode - merge %entry; + + # First, sanity-check the entry. We ignore the result; even if it + # failed, we do want to check for conflicts, in the remainder of this + # block. + validate_branch_contains_named_revisions %entry; + + # E155015 is SVN_ERR_WC_FOUND_CONFLICT + my $expected_error_p = sub { + my ($exit_code, $outlines, $errlines) = @_; + ($exit_code == 0) + or + (grep /svn: E155015:/, @$errlines) + }; + merge \%entry, ($entry{depends} ? $expected_error_p : undef); my $output = `$SVN status`; @@ -892,7 +1007,8 @@ sub handle_entry { given (prompt 'Run a merge? [y,l,v,±1,±0,q,e,a, ,N] ', verbose => 1, extra => qr/[+-]/) { when (/^y/i) { - merge %entry; + #validate_branch_contains_named_revisions %entry; + merge \%entry; while (1) { given (prompt "Shall I open a subshell? [ydN] ", verbose => 1) { when (/^y/i) { Modified: subversion/branches/1.9.x/tools/dist/backport_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/1.9.x/tools/dist/backport_tests.py?rev=1662916&r1=1662915&r2=1662916&view=diff ============================================================================== --- subversion/branches/1.9.x/tools/dist/backport_tests.py (original) +++ subversion/branches/1.9.x/tools/dist/backport_tests.py Sat Feb 28 10:37:27 2015 @@ -110,7 +110,8 @@ class BackportTest(object): verify_backport(sbox, expected_dump_file, self.uuid) return wrapped_test_func -def make_entry(revisions=None, logsummary=None, notes=None, branch=None, votes=None): +def make_entry(revisions=None, logsummary=None, notes=None, branch=None, + depends=None, votes=None): assert revisions if logsummary is None: logsummary = "default logsummary" @@ -122,6 +123,7 @@ def make_entry(revisions=None, logsummar 'logsummary': logsummary, 'notes': notes, 'branch': branch, + 'depends': depends, 'votes': votes, } @@ -143,6 +145,9 @@ def serialize_entry(entry): # branch ' Branch: %s\n' % (entry['branch'],) if entry['branch'] else '', + # depends + ' Depends: %s\n' % (entry['depends'],) if entry['depends'] else '', + # votes ' Votes:\n', ''.join(' ' @@ -210,12 +215,12 @@ def verify_backport(sbox, expected_dump_ # mirror repository in preparation for the comparison dump. svntest.actions.enable_revprop_changes(sbox.repo_dir) for revnum in range(0, 1+int(sbox.youngest())): - svntest.actions.run_and_verify_svnadmin(None, [], [], + svntest.actions.run_and_verify_svnadmin([], [], "delrevprop", "-r", revnum, sbox.repo_dir, "svn:date") # Create a dump file from the mirror repository. dest_dump = open(expected_dump_file).readlines() - svntest.actions.run_and_verify_svnadmin(None, None, [], + svntest.actions.run_and_verify_svnadmin(None, [], 'setuuid', '--', sbox.repo_dir, uuid) src_dump = svntest.actions.run_and_verify_dump(sbox.repo_dir) @@ -265,7 +270,7 @@ def backport_two_approveds(sbox): # Now back up and do three entries. # r9: revert r7, r8 - svntest.actions.run_and_verify_svnlook(None, ["8\n"], [], + svntest.actions.run_and_verify_svnlook(["8\n"], [], 'youngest', sbox.repo_dir) sbox.simple_update() svntest.main.run_svn(None, 'merge', '-r8:6', @@ -342,6 +347,8 @@ def backport_branches(sbox): # Run it. run_backport(sbox) + # This also serves as the 'success mode' part of backport_branch_contains(). + #---------------------------------------------------------------------- @BackportTest('76cee987-25c9-4d6c-ad40-000000000005') @@ -380,7 +387,11 @@ def backport_conflicts_detection(sbox): # Choose conflicts mode: ["MAY_COMMIT=0"]) - # Verify + # Verify the conflict is detected. + expected_output = svntest.verify.RegexOutput( + 'Index: iota', + match_all=False, + ) expected_errput = ( r'(?ms)' # re.MULTILINE | re.DOTALL r'.*Warning summary.*' @@ -394,9 +405,151 @@ def backport_conflicts_detection(sbox): ], match_all=False) svntest.verify.verify_outputs(None, output, errput, - svntest.verify.AnyOutput, expected_errput) + expected_output, expected_errput) + svntest.verify.verify_exit_code(None, exit_code, 1) + + ## Now, let's test the "Depends:" annotation silences the error. + + # Re-nominate. + approved_entries = [ + make_entry([4], depends="World peace."), + ] + sbox.simple_append(STATUS, serialize_STATUS(approved_entries), truncate=True) + sbox.simple_commit(message='Re-nominate r4') + + # Detect conflicts. + exit_code, output, errput = run_backport(sbox, extra_env=["MAY_COMMIT=0"]) + + # Verify stdout. (exit_code and errput were verified by run_backport().) + svntest.verify.verify_outputs(None, output, errput, + "Conflicts found.*, as expected.", []) + + +#---------------------------------------------------------------------- +@BackportTest(None) # would be 000000000007 +def backport_branch_contains(sbox): + "branch must contain the revisions" + + # r6: conflicting change on branch + sbox.simple_append('branch/iota', 'Conflicts with first change') + sbox.simple_commit(message="Conflicting change on iota") + + # r7: backport branch + sbox.simple_update() + sbox.simple_copy('branch', 'subversion/branches/r4') + sbox.simple_commit(message='Create a backport branch') + + # r8: merge into backport branch + sbox.simple_update() + svntest.main.run_svn(None, 'merge', '--record-only', '-c4', + '^/subversion/trunk', sbox.ospath('subversion/branches/r4')) + sbox.simple_mkdir('subversion/branches/r4/A_resolved') + sbox.simple_append('subversion/branches/r4/iota', "resolved\n", truncate=1) + sbox.simple_commit(message='Conflict resolution via mkdir') + + # r9: nominate r4,r5 with branch that contains not all of them + approved_entries = [ + make_entry([4,5], branch="r4") + ] + sbox.simple_append(STATUS, serialize_STATUS(approved_entries)) + sbox.simple_commit(message='Nominate r4') + + # Run it. + exit_code, output, errput = run_backport(sbox, error_expected=True) + + # Verify the error message. + expected_errput = svntest.verify.RegexOutput( + ".*Revisions 'r5' nominated but not included in branch", + match_all=False, + ) + svntest.verify.verify_outputs(None, output, errput, + [], expected_errput) svntest.verify.verify_exit_code(None, exit_code, 1) + # Verify no commit occurred. + svntest.actions.run_and_verify_svnlook(["9\n"], [], + 'youngest', sbox.repo_dir) + + # Verify the working copy has been reverted. + svntest.actions.run_and_verify_svn([], [], 'status', '-q', + sbox.repo_dir) + + # The sibling test backport_branches() verifies the success mode. + + + + +#---------------------------------------------------------------------- +@BackportTest(None) # would be 000000000008 +def backport_double_conflict(sbox): + "two-revisioned entry with two conflicts" + + # r6: conflicting change on branch + sbox.simple_append('branch/iota', 'Conflicts with first change') + sbox.simple_commit(message="Conflicting change on iota") + + # r7: further conflicting change to same file + sbox.simple_update() + sbox.simple_append('subversion/trunk/iota', 'Third line\n') + sbox.simple_commit(message="iota's third line") + + # r8: nominate + approved_entries = [ + make_entry([4,7], depends="World peace.") + ] + sbox.simple_append(STATUS, serialize_STATUS(approved_entries)) + sbox.simple_commit(message='Nominate the r4 group') + + # Run it, in conflicts mode. + exit_code, output, errput = run_backport(sbox, True, ["MAY_COMMIT=0"]) + + # Verify the failure mode: "merge conflict" error on stderr, but backport.pl + # itself exits with code 0, since conflicts were confined to Depends:-ed + # entries. + # + # The error only happens with multi-pass merges where the first pass + # conflicts and the second pass touches the conflict victim. + # + # The error would be: + # subversion/libsvn_client/merge.c:5499: (apr_err=SVN_ERR_WC_FOUND_CONFLICT) + # svn: E155015: One or more conflicts were produced while merging r3:4 + # into '/tmp/stw/working_copies/backport_tests-8/branch' -- resolve all + # conflicts and rerun the merge to apply the remaining unmerged revisions + # ... + # Warning summary + # =============== + # + # r4 (default logsummary): subshell exited with code 256 + # And backport.pl would exit with exit code 1. + + expected_output = 'Conflicts found.*, as expected.' + expected_errput = svntest.verify.RegexOutput( + ".*svn: E155015:.*", # SVN_ERR_WC_FOUND_CONFLICT + match_all=False, + ) + svntest.verify.verify_outputs(None, output, errput, + expected_output, expected_errput) + svntest.verify.verify_exit_code(None, exit_code, 0) + if any("Warning summary" in line for line in errput): + raise svntest.verify.SVNUnexpectedStderr(errput) + + ## Now, let's ensure this does get detected if not silenced. + # r9: Re-nominate + approved_entries = [ + make_entry([4,7]) # no depends= + ] + sbox.simple_append(STATUS, serialize_STATUS(approved_entries), truncate=True) + sbox.simple_commit(message='Re-nominate the r4 group') + + exit_code, output, errput = run_backport(sbox, True, ["MAY_COMMIT=0"]) + + # [1-9]\d+ matches non-zero exit codes + expected_errput = r'r4 .*: subshell exited with code (?:[1-9]\d+)' + svntest.verify.verify_exit_code(None, exit_code, 1) + svntest.verify.verify_outputs(None, output, errput, + svntest.verify.AnyOutput, expected_errput) + + #---------------------------------------------------------------------- @@ -411,6 +564,8 @@ test_list = [ None, backport_branches, backport_multirevisions, backport_conflicts_detection, + backport_branch_contains, + backport_double_conflict, # When adding a new test, include the test number in the last # 6 bytes of the UUID. ]
