subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1663282 [12/12] - in /subversion/branches/move-tracking-2: ./ build/ build/generator/ subversion/ subversion/bindings/swig/ subversion/bindings/swig/include/ subversion/bindings/swig/python/libsvn_swig_py/ subversion/bindings/swig/python/t...
Date Mon, 02 Mar 2015 12:26:01 GMT
Modified: subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/op-depth-test.c?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/op-depth-test.c Mon Mar  2 12:25:58 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,
@@ -3727,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));
@@ -7238,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;
@@ -8383,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));
   }
 
 
@@ -8414,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? */
@@ -8426,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}
     };
@@ -8684,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;
@@ -9547,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[] = {
@@ -9571,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},
@@ -9584,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},
@@ -9613,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;
@@ -9633,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;
@@ -9653,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;
@@ -10111,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,
@@ -11241,6 +11477,8 @@ make_copy_mixed(const svn_test_opts_t *o
     SVN_ERR(check_db_rows(&b, "", nodes));
   }
 
+  SVN_ERR(verify_db(&b));
+
   return SVN_NO_ERROR;
 }
 
@@ -11344,7 +11582,7 @@ make_copy_and_delete_mixed(const svn_tes
   }
 
   SVN_ERR(svn_wc__db_base_remove(b.wc_ctx->db, sbox_wc_path(&b, "A"),
-                                 TRUE, FALSE, FALSE, 99,
+                                 TRUE, TRUE, FALSE, 99,
                                  NULL, NULL, pool));
 
   {
@@ -11380,7 +11618,7 @@ make_copy_and_delete_mixed(const svn_tes
       {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/H",      "base-deleted", NO_COPY_FROM, "H"},
       {4, "A/B/G/J",      "normal",       NO_COPY_FROM},
 
       {0}
@@ -11391,13 +11629,147 @@ make_copy_and_delete_mixed(const svn_tes
     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[] =
   {
@@ -11543,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)"),
@@ -11565,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"),
@@ -11577,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"),
@@ -11605,8 +11977,10 @@ static struct svn_test_descriptor_t test
                        "move deep bump"),
     SVN_TEST_OPTS_PASS(make_copy_mixed,
                        "make a copy of a mixed revision tree"),
-    SVN_TEST_OPTS_XFAIL(make_copy_and_delete_mixed,
+    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/move-tracking-2/subversion/tests/libsvn_wc/wc-test-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/wc-test-queries.sql?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/wc-test-queries.sql (original)
+++ subversion/branches/move-tracking-2/subversion/tests/libsvn_wc/wc-test-queries.sql Mon Mar  2 12:25:58 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')

Propchange: subversion/branches/move-tracking-2/tools/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Mar  2 12:25:58 2015
@@ -82,4 +82,4 @@
 /subversion/branches/verify-at-commit/tools:1462039-1462408
 /subversion/branches/verify-keep-going/tools:1439280-1546110
 /subversion/branches/wc-collate-path/tools:1402685-1480384
-/subversion/trunk/tools:1606692-1661488
+/subversion/trunk/tools:1606692-1663280

Modified: subversion/branches/move-tracking-2/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh (original)
+++ subversion/branches/move-tracking-2/tools/buildbot/slaves/svn-sparc-solaris/svncheck.sh Mon Mar  2 12:25:58 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/move-tracking-2/tools/client-side/bash_completion
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/client-side/bash_completion?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/client-side/bash_completion (original)
+++ subversion/branches/move-tracking-2/tools/client-side/bash_completion Mon Mar  2 12:25:58 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/move-tracking-2/tools/client-side/bash_completion_test
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/client-side/bash_completion_test?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/client-side/bash_completion_test (original)
+++ subversion/branches/move-tracking-2/tools/client-side/bash_completion_test Mon Mar  2 12:25:58 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/move-tracking-2/tools/dist/backport.pl
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/dist/backport.pl?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/dist/backport.pl (original)
+++ subversion/branches/move-tracking-2/tools/dist/backport.pl Mon Mar  2 12:25:58 2015
@@ -28,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 ();
@@ -201,8 +203,9 @@ is not parsed; only its presence or abse
 
 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 
+at least one of the revisions enumerated in the entry title had neither been
+merged from $TRUNK to the branch root, nor been committed
+directly to the backport branch, 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.)
 
@@ -318,9 +321,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();
@@ -434,15 +474,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:
@@ -845,7 +896,8 @@ sub validate_branch_contains_named_revis
 
   my $shell_escaped_branch = shell_escape($entry{branch});
   %present = do {
-    my @present = `$SVN mergeinfo --show-revs=merged -- $TRUNK $BRANCHES/$shell_escaped_branch`;
+    my @present = `$SVN mergeinfo --show-revs=merged -- $TRUNK $BRANCHES/$shell_escaped_branch &&
+                   $SVN mergeinfo --show-revs=eligible -- $BRANCHES/$shell_escaped_branch`;
     chomp @present;
     @present = map /(\d+)/g, @present;
     map +($_ => 1), @present;
@@ -881,7 +933,7 @@ sub handle_entry {
     unless (@vetoes) {
       if ($MAY_COMMIT and $in_approved) {
         # svn-role mode
-        merge %entry if validate_branch_contains_named_revisions %entry;
+        merge \%entry if validate_branch_contains_named_revisions %entry;
       } elsif (!$MAY_COMMIT) {
         # Scan-for-conflicts mode
 
@@ -890,7 +942,14 @@ sub handle_entry {
         # block.
         validate_branch_contains_named_revisions %entry;
 
-        merge %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`;
 
@@ -951,7 +1010,7 @@ sub handle_entry {
                    verbose => 1, extra => qr/[+-]/) {
       when (/^y/i) {
         #validate_branch_contains_named_revisions %entry;
-        merge %entry;
+        merge \%entry;
         while (1) {
           given (prompt "Shall I open a subshell? [ydN] ", verbose => 1) {
             when (/^y/i) {

Copied: subversion/branches/move-tracking-2/tools/dist/backport_branch_with_original_revision.dump (from r1663280, subversion/trunk/tools/dist/backport_branch_with_original_revision.dump)
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/dist/backport_branch_with_original_revision.dump?p2=subversion/branches/move-tracking-2/tools/dist/backport_branch_with_original_revision.dump&p1=subversion/trunk/tools/dist/backport_branch_with_original_revision.dump&r1=1663280&r2=1663282&rev=1663282&view=diff
==============================================================================
    (empty)

Modified: subversion/branches/move-tracking-2/tools/dist/backport_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/dist/backport_tests.py?rev=1663282&r1=1663281&r2=1663282&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/dist/backport_tests.py (original)
+++ subversion/branches/move-tracking-2/tools/dist/backport_tests.py Mon Mar  2 12:25:58 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('     '
@@ -382,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.*'
@@ -396,9 +405,25 @@ 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
@@ -455,6 +480,116 @@ def backport_branch_contains(sbox):
 
 
 #----------------------------------------------------------------------
+@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)
+
+
+
+#----------------------------------------------------------------------
+@BackportTest('76cee987-25c9-4d6c-ad40-000000000009')
+def backport_branch_with_original_revision(sbox):
+  "branch with original revision"
+
+  # 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: original revision on branch
+  sbox.simple_update()
+  sbox.simple_mkdir('subversion/branches/r4/dir-created-on-backport-branch')
+  sbox.simple_commit(message='An original revision on the backport branch')
+
+  # r10: nominate the branch with r9 listed
+  approved_entries = [
+    make_entry([4, 9], branch="r4")
+  ]
+  sbox.simple_append(STATUS, serialize_STATUS(approved_entries))
+  sbox.simple_commit(message='Nominate r4+r9')
+
+  # r11, r12: Run it.
+  run_backport(sbox)
+
+
+#----------------------------------------------------------------------
 
 ########################################################################
 # Run the tests
@@ -468,6 +603,8 @@ test_list = [ None,
               backport_multirevisions,
               backport_conflicts_detection,
               backport_branch_contains,
+              backport_double_conflict,
+              backport_branch_with_original_revision,
               # When adding a new test, include the test number in the last
               # 6 bytes of the UUID.
              ]



Mime
View raw message