You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/05/19 15:55:52 UTC

svn commit: r946186 - in /subversion/trunk/subversion: include/svn_wc.h libsvn_client/diff.c libsvn_client/merge.c libsvn_client/repos_diff.c tests/cmdline/merge_tests.py

Author: stsp
Date: Wed May 19 13:55:51 2010
New Revision: 946186

URL: http://svn.apache.org/viewvc?rev=946186&view=rev
Log:
Stop flagging tree conflicts due to sparse working copies and skip
obstructed and missing (from disk) directories during merge.

Whenever a merge sees a child of a directory excluded due to depth
restrictions, it sets non-inheritable subtree mergeinfo on the sparse
directory. This means that later merges into a deeper working copy
will pull in any changes the current merge has missed.

Flagging conflicts in this case is counter-productive, because
no real conflict has occurred. A partial merge has happened, but
Subversion can track it just fine, and if the partial merge was
an accident another merge can be done to rectify the situation.

We still alert the user by reporting such children as skipped.
The subtree mergeinfo created by the merge should also raise
eyebrows if it is unexpected.

Obstructed or missing (from disk) files where already being skipped, rather
than causing a tree conflict. Skipping obstructed or missing (from disk)
directories (rather than flagging a tree conflict) makes the behaviour
regarding obstructed and missing nodes in the working copy consistent.

* subversion/include/svn_wc.h
  (svn_wc_diff_callbacks4_t): Add new output parameter SKIP_CHILDREN
   to the dir_opened() callback. If this is set to TRUE, the directory
   is not considered tree-conflicted, but its children will still be skipped.
   Previously we only skipped children of tree-conflicted directories.

* subversion/libsvn_client/diff.c
  (diff_dir_opened): Add SKIP_CHILDREN output parameter (always set to
   FALSE by this function).

* subversion/libsvn_client/merge.c
  (merge_file_changed): If the file isn't there due to depth restrictions,
   do not flag a conflict.
  (merge_dir_opened): Add SKIP_CHILDREN output parameter.
   This function was using a very simple heuristic:
    "It's not here -> flag a TC with local reason delete".
   Now we're being a bit more clever:
   If the directory is obstructed or missing, skip it. If the parent is
   too shallow to contain this directory, and the directory is not
   present on disk, skip it. Flag a tree conflict if the directory is locally
   deleted, or is missing in the DB as well as on disk, or if the DB says it
   should be on disk but it's not (e.g. due to a mixed-revision working copy).
   If there is a file here, flag a tree conflict with local reason 'replaced'.
   Because the merge is trying to open the directory, rather than adding it,
   the directory must have existed in the history of the target branch and
   has been replaced with a file.

* subversion/libsvn_client/repos_diff.c
  (dir_baton): Add SKIP_CHILDREN field, to be used by dir_opened() callback.
  (delete_entry, open_directory, add_file, open_file): If the parent has
   SKIP_CHILDREN set, set the SKIP flag in the baton and return immediately.
   Also make open_directory() pass SKIP_CHILDREN to the dir_opened() callback.
  (close_directory): Do not ask get_dir_abspath() to error out during dry-run.
   Fixes mismatching output during dry-run and real merge which triggered
   due to above changes.

* subversion/tests/cmdline/merge_tests.py
  (merge_to_sparse_directories, reintegrate_on_shallow_wc,
   tree_conflicts_on_merge_local_ci_4_1,
   tree_conflicts_merge_edit_onto_missing,
   tree_conflicts_merge_del_onto_missing): Adjust test expectations.
    The latter two tests trigger an apparent bug in the wc-ng work
    queue code. Committing from a WC where a subdirectory has been
    removed with rm -rf can corrupt a wc-ng working copy beyond repair.
    This should be looked at. The tests will start failing when this
    problem is fixed. See comments in tests for details.

Modified:
    subversion/trunk/subversion/include/svn_wc.h
    subversion/trunk/subversion/libsvn_client/diff.c
    subversion/trunk/subversion/libsvn_client/merge.c
    subversion/trunk/subversion/libsvn_client/repos_diff.c
    subversion/trunk/subversion/tests/cmdline/merge_tests.py

Modified: subversion/trunk/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=946186&r1=946185&r2=946186&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_wc.h (original)
+++ subversion/trunk/subversion/include/svn_wc.h Wed May 19 13:55:51 2010
@@ -2352,9 +2352,13 @@ typedef struct svn_wc_diff_callbacks4_t
    *
    * This function is called for @a path before any of the callbacks are
    * called for a child of @a path.
+   *
+   * If the callback returns @c TRUE in @a *skip_children, children
+   * of this directory will be skipped.
    */
   svn_error_t *(*dir_opened)(const char *local_dir_abspath,
                              svn_boolean_t *tree_conflicted,
+                             svn_boolean_t *skip_children,
                              const char *path,
                              svn_revnum_t rev,
                              void *diff_baton,

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=946186&r1=946185&r2=946186&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Wed May 19 13:55:51 2010
@@ -800,6 +800,7 @@ diff_dir_deleted(const char *local_dir_a
 static svn_error_t *
 diff_dir_opened(const char *local_dir_abspath,
                 svn_boolean_t *tree_conflicted,
+                svn_boolean_t *skip_children,
                 const char *path,
                 svn_revnum_t rev,
                 void *diff_baton,
@@ -807,6 +808,8 @@ diff_dir_opened(const char *local_dir_ab
 {
   if (tree_conflicted)
     *tree_conflicted = FALSE;
+  if (skip_children)
+    *skip_children = FALSE;
 
   /* Do nothing. */
 

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=946186&r1=946185&r2=946186&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Wed May 19 13:55:51 2010
@@ -1343,11 +1343,29 @@ merge_file_changed(const char *local_dir
   {
     svn_node_kind_t kind;
     svn_node_kind_t wc_kind;
+    svn_depth_t parent_depth;
 
     SVN_ERR(svn_wc_read_kind(&wc_kind, merge_b->ctx->wc_ctx, mine_abspath,
                              FALSE, subpool));
     SVN_ERR(svn_io_check_path(mine, &kind, subpool));
 
+    /* If the file isn't there due to depth restrictions, do not flag
+     * a conflict. Non-inheritable mergeinfo will be recorded, allowing
+     * future merges into non-shallow working copies to merge changes
+     * we missed this time around. */
+    SVN_ERR(svn_wc__node_get_depth(&parent_depth, merge_b->ctx->wc_ctx,
+                                   svn_dirent_dirname(mine_abspath, subpool),
+                                   subpool));
+    if (wc_kind == svn_node_none && parent_depth < svn_depth_files)
+      {
+        if (content_state)
+          *content_state = svn_wc_notify_state_missing;
+        if (prop_state)
+          *prop_state = svn_wc_notify_state_missing;
+        svn_pool_destroy(subpool);
+        return SVN_NO_ERROR;
+      }
+
     /* ### a future thought:  if the file is under version control,
        but the working file is missing, maybe we can 'restore' the
        working file from the text-base, and then allow the merge to run?  */
@@ -2380,13 +2398,26 @@ merge_dir_deleted(const char *local_dir_
 static svn_error_t *
 merge_dir_opened(const char *local_dir_abspath,
                  svn_boolean_t *tree_conflicted,
+                 svn_boolean_t *skip_children,
                  const char *path,
                  svn_revnum_t rev,
                  void *baton,
                  apr_pool_t *scratch_pool)
 {
+  merge_cmd_baton_t *merge_b = baton;
+  apr_pool_t *subpool = svn_pool_create(merge_b->pool);
+  const char *local_abspath;
+  svn_depth_t parent_depth;
+  svn_node_kind_t kind;
+  svn_node_kind_t kind_on_disk;
+  svn_wc_notify_state_t obstr_state;
+  svn_boolean_t is_deleted;
+  svn_error_t *err;
+
   if (tree_conflicted)
     *tree_conflicted = FALSE;
+  if (skip_children)
+    *skip_children = FALSE;
 
   if (local_dir_abspath == NULL)
     {
@@ -2397,58 +2428,121 @@ merge_dir_opened(const char *local_dir_a
        * additional tree conflicts for the child nodes inside. */
       /* ### TODO: Verify that this holds true for explicit targets that
        * # point deep into a nonexisting subtree. */
+      if (skip_children)
+        *skip_children = TRUE;
+      svn_pool_destroy(subpool);
       return SVN_NO_ERROR;
     }
 
-  /* Detect a tree-conflict, if any. */
-  {
-    merge_cmd_baton_t *merge_b = baton;
-    apr_pool_t *subpool = svn_pool_create(merge_b->pool);
-    svn_node_kind_t kind;
-    const char *local_abspath;
-    svn_boolean_t is_versioned;
-    svn_boolean_t is_deleted;
-    svn_error_t *err;
-
-    SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
-
-    /* Find out if this path is deleted and in asking this question also derive
-       the path's version-control state, we'll need to know both below. */
-    err = svn_wc__node_is_status_deleted(&is_deleted, merge_b->ctx->wc_ctx,
-                                         local_abspath, subpool);
-    if (err)
-      {
-        if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-          {
-            svn_error_clear(err);
-            err = NULL;
-            is_versioned = is_deleted = FALSE;
-          }
-        else
+  /* Check for an obstructed or missing node on disk. */
+  obstr_state = obstructed_or_missing(path, local_dir_abspath, merge_b,
+                                      subpool);
+  if (obstr_state != svn_wc_notify_state_inapplicable)
+    {
+      if (skip_children)
+        *skip_children = TRUE;
+      svn_pool_destroy(subpool);
+      return SVN_NO_ERROR;
+    }
+
+  err = svn_dirent_get_absolute(&local_abspath, path, subpool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        {
+          svn_pool_destroy(subpool);
           return svn_error_return(err);
-      }
-    else
-      {
-        is_versioned = TRUE;
-      }
+        }
+    }
+
+  SVN_ERR(svn_wc_read_kind(&kind, merge_b->ctx->wc_ctx,
+                           local_abspath, TRUE, subpool));
+  SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, subpool));
+
+  /* If the parent is too shallow to contain this directory,
+   * and the directory is not present on disk, skip it.
+   * Non-inheritable mergeinfo will be recorded, allowing
+   * future merges into non-shallow working copies to merge
+   * changes we missed this time around. */
+  err = svn_wc__node_get_depth(&parent_depth, merge_b->ctx->wc_ctx,
+                               local_dir_abspath, subpool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          parent_depth = svn_depth_unknown;
+        }
+      else
+        {
+          svn_pool_destroy(subpool);
+          return svn_error_return(err);
+        }
+    }
+  if (kind == svn_node_none &&
+      parent_depth != svn_depth_unknown &&
+      parent_depth < svn_depth_immediates)
+    {
+      if (skip_children)
+        *skip_children = TRUE;
+      svn_pool_destroy(subpool);
+      return SVN_NO_ERROR;
+    }
+   
+  /* Find out if this path is deleted. */
+  err = svn_wc__node_is_status_deleted(&is_deleted, merge_b->ctx->wc_ctx,
+                                       local_abspath, subpool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          is_deleted = FALSE;
+        }
+      else
+        {
+          svn_pool_destroy(subpool);
+          return svn_error_return(err);
+        }
+    }
 
-    SVN_ERR(svn_io_check_path(path, &kind, subpool));
+  /* Check for tree conflicts, if any. */
 
-    /* If we're trying to open a directory that's not a directory,
-     * raise a tree conflict. */
-    if (!is_versioned || is_deleted
-        || kind != svn_node_dir)
-      {
-        SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
-                              svn_wc_conflict_action_edit,
-                              svn_wc_conflict_reason_deleted));
-        if (tree_conflicted)
-          *tree_conflicted = TRUE;
-      }
+  /* If we're trying to open a file, the reason for the conflict is
+   * 'replaced'. Because the merge is trying to open the directory,
+   * rather than adding it, the directory must have existed in the
+   * history of the target branch and has been replaced with a file. */
+  if (kind == svn_node_file)
+    {
+      SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
+                            svn_wc_conflict_action_edit,
+                            svn_wc_conflict_reason_replaced));
+      if (tree_conflicted)
+        *tree_conflicted = TRUE;
+    }
 
-    svn_pool_destroy(subpool);
-  }
+  /* If we're trying to open a directory that's locally deleted,
+   * or not present because it was deleted in the history of the
+   * target branch, the reason for the conflict is 'deleted'.
+   *
+   * If the DB says something should be here, but there is
+   * nothing on disk, we're probably in a mixed-revision
+   * working copy and the parent has an outdated idea about
+   * the state of its child. Flag a tree conflict in this case
+   * forcing the user to sanity-check the merge result. */
+  else if (is_deleted || kind == svn_node_none ||
+           (kind_on_disk != kind && kind_on_disk == svn_node_none))
+    {
+      SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
+                            svn_wc_conflict_action_edit,
+                            svn_wc_conflict_reason_deleted));
+      if (tree_conflicted)
+        *tree_conflicted = TRUE;
+    }
 
+  svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/trunk/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/repos_diff.c?rev=946186&r1=946185&r2=946186&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/repos_diff.c Wed May 19 13:55:51 2010
@@ -111,10 +111,13 @@ struct dir_baton {
   svn_boolean_t tree_conflicted;
 
   /* If TRUE, this node is skipped entirely.
-   * This is currently used to skip all children of a tree-conflicted
+   * This is used to skip all children of a tree-conflicted
    * directory without setting TREE_CONFLICTED to TRUE everywhere. */
   svn_boolean_t skip;
 
+  /* If TRUE, all children of this directory are skipped. */
+  svn_boolean_t skip_children;
+
   /* The path of the directory within the repository */
   const char *path;
 
@@ -210,6 +213,7 @@ make_dir_baton(const char *path,
   dir_baton->added = added;
   dir_baton->tree_conflicted = FALSE;
   dir_baton->skip = FALSE;
+  dir_baton->skip_children = FALSE;
   dir_baton->pool = pool;
   dir_baton->path = apr_pstrdup(pool, path);
   dir_baton->wcpath = svn_dirent_join(edit_baton->target, path, pool);
@@ -455,7 +459,7 @@ delete_entry(const char *path,
   svn_boolean_t tree_conflicted = FALSE;
 
   /* Skip *everything* within a newly tree-conflicted directory. */
-  if (pb->skip || pb->tree_conflicted)
+  if (pb->skip || pb->tree_conflicted || pb->skip_children)
     return SVN_NO_ERROR;
 
   /* We need to know if this is a directory or a file */
@@ -557,7 +561,7 @@ add_directory(const char *path,
   *child_baton = b;
 
   /* Skip *everything* within a newly tree-conflicted directory. */
-  if (pb->skip || pb->tree_conflicted)
+  if (pb->skip || pb->tree_conflicted || pb->skip_children)
     {
       b->skip = TRUE;
       return SVN_NO_ERROR;
@@ -643,8 +647,9 @@ open_directory(const char *path,
   b = make_dir_baton(path, pb, pb->edit_baton, FALSE, pool);
   *child_baton = b;
 
-  /* Skip *everything* within a newly tree-conflicted directory. */
-  if (pb->skip || pb->tree_conflicted)
+  /* Skip *everything* within a newly tree-conflicted directory
+   * or directories the children of which should be skipped. */
+  if (pb->skip || pb->tree_conflicted || pb->skip_children)
     {
       b->skip = TRUE;
       return SVN_NO_ERROR;
@@ -656,8 +661,8 @@ open_directory(const char *path,
                           pool));
 
   SVN_ERR(eb->diff_callbacks->dir_opened
-          (local_dir_abspath, &b->tree_conflicted, b->wcpath, base_revision,
-           b->edit_baton->diff_cmd_baton, pool));
+          (local_dir_abspath, &b->tree_conflicted, &b->skip_children,
+           b->wcpath, base_revision, b->edit_baton->diff_cmd_baton, pool));
 
   return SVN_NO_ERROR;
 }
@@ -681,7 +686,7 @@ add_file(const char *path,
   *file_baton = b;
 
   /* Skip *everything* within a newly tree-conflicted directory. */
-  if (pb->skip || pb->tree_conflicted)
+  if (pb->skip || pb->tree_conflicted || pb->skip_children)
     {
       b->skip = TRUE;
       return SVN_NO_ERROR;
@@ -707,7 +712,7 @@ open_file(const char *path,
   *file_baton = b;
 
   /* Skip *everything* within a newly tree-conflicted directory. */
-  if (pb->skip || pb->tree_conflicted)
+  if (pb->skip || pb->tree_conflicted || pb->skip_children)
     {
       b->skip = TRUE;
       return SVN_NO_ERROR;
@@ -945,7 +950,7 @@ close_directory(void *dir_baton,
     svn_hash__clear(svn_client__dry_run_deletions(eb->diff_cmd_baton), pool);
 
   err = get_dir_abspath(&local_dir_abspath, eb->wc_ctx, b->wcpath,
-                        eb->dry_run, b->pool);
+                        FALSE, b->pool);
 
   if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
     {

Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=946186&r1=946185&r2=946186&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Wed May 19 13:55:51 2010
@@ -8111,14 +8111,11 @@ def merge_to_sparse_directories(sbox):
   # 'C', and 'D' are checked out at depth empty; the two of these affected
   # by the merge, 'B' and 'D', get non-inheritable mergeinfo for r4:9.
   # The root and 'D' do should also get the changes
-  # that affect them directly (the prop adds from r8 and r9).  Changes
-  # deeper than the immediate children raise tree conflicts.
+  # that affect them directly (the prop adds from r8 and r9).
   expected_output = wc.State(immediates_dir, {
     'D'   : Item(status=' U'),
-    'D/H' : Item(status='  ', treeconflict='C'),
     'mu'  : Item(status='U '),
     ''    : Item(status=' U'),
-    'B/E' : Item(status='  ', treeconflict='C'),
     })
   expected_mergeinfo_output = wc.State(immediates_dir, {
     ''  : Item(status=' U'),
@@ -8130,11 +8127,9 @@ def merge_to_sparse_directories(sbox):
   expected_status = wc.State(immediates_dir, {
     ''          : Item(status=' M', wc_rev=9),
     'B'         : Item(status=' M', wc_rev=9),
-    'B/E'       : Item(status='! ', treeconflict='C'),
     'mu'        : Item(status='M ', wc_rev=9),
     'C'         : Item(status='  ', wc_rev=9),
     'D'         : Item(status=' M', wc_rev=9),
-    'D/H'       : Item(status='! ', treeconflict='C'),
     })
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-9',
@@ -8145,7 +8140,10 @@ def merge_to_sparse_directories(sbox):
     'D'         : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-9*',
                               "prop:name" : "propval"}),
     })
-  expected_skip = wc.State(immediates_dir, {})
+  expected_skip = svntest.wc.State(immediates_dir, {
+    'D/H'               : Item(),
+    'B/E'               : Item(),
+    })
   svntest.actions.run_and_verify_merge(immediates_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
                                        expected_output,
@@ -8175,12 +8173,10 @@ def merge_to_sparse_directories(sbox):
   # The root of the files WC should get non-inheritable r4:9 and its one
   # present child 'mu' should get the same but inheritable.  The root
   # should also get the change that affects it directly (the prop add
-  # from r9).  Changes into shallow subtrees should raise tree conflicts.
+  # from r9).
   expected_output = wc.State(files_dir, {
     'mu' : Item(status='U '),
     ''   : Item(status=' U'),
-    'B'  : Item(status='  ', treeconflict='C'),
-    'D'  : Item(status='  ', treeconflict='C'),
     })
   expected_mergeinfo_output = wc.State(files_dir, {
     ''   : Item(status=' U'),
@@ -8191,8 +8187,6 @@ def merge_to_sparse_directories(sbox):
   expected_status = wc.State(files_dir, {
     ''          : Item(status=' M', wc_rev=9),
     'mu'        : Item(status='MM', wc_rev=9),
-    'B'         : Item(status='! ', treeconflict='C'),
-    'D'         : Item(status='! ', treeconflict='C'),
     })
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-9*',
@@ -8200,7 +8194,10 @@ def merge_to_sparse_directories(sbox):
     'mu'        : Item("New content",
                        props={SVN_PROP_MERGEINFO : '/A/mu:5-9'}),
     })
-  expected_skip = wc.State(files_dir, {})
+  expected_skip = svntest.wc.State(files_dir, {
+    'D'               : Item(),
+    'B'               : Item(),
+    })
   svntest.actions.run_and_verify_merge(files_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
                                        expected_output,
@@ -8225,12 +8222,8 @@ def merge_to_sparse_directories(sbox):
   # Merge r4:9 into the empty WC.
   # The root of the files WC should get non-inheritable r4:9 and also get
   # the one change that affects it directly (the prop add from r9).
-  # Changes into the missing subtrees should raise tree conflicts.
   expected_output = wc.State(empty_dir, {
     ''   : Item(status=' U'),
-    'mu' : Item(status='  ', treeconflict='C'),
-    'B'  : Item(status='  ', treeconflict='C'),
-    'D'  : Item(status='  ', treeconflict='C'),
     })
   expected_mergeinfo_output = wc.State(empty_dir, {
     '' : Item(status=' U'),
@@ -8239,15 +8232,16 @@ def merge_to_sparse_directories(sbox):
     })
   expected_status = wc.State(empty_dir, {
     ''          : Item(status=' M', wc_rev=9),
-    'mu'        : Item(status='! ', treeconflict='C'),
-    'B'         : Item(status='! ', treeconflict='C'),
-    'D'         : Item(status='! ', treeconflict='C'),
     })
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-9*',
                               "prop:name" : "propval"}),
     })
-  expected_skip = wc.State(empty_dir, {})
+  expected_skip = svntest.wc.State(empty_dir, {
+    'mu'               : Item(),
+    'D'               : Item(),
+    'B'               : Item(),
+    })
   svntest.actions.run_and_verify_merge(empty_dir, '4', '9',
                                        sbox.repo_url + '/A', None,
                                        expected_output,
@@ -11169,7 +11163,7 @@ def reintegrate_on_shallow_wc(sbox):
     'C'         : Item(),
     'D'         : Item(), # Don't expect anything under D, its depth is empty!
     })
-  expected_A_skip = wc.State(A_COPY_path, {})
+  expected_A_skip = wc.State(A_path, {})
   svntest.actions.run_and_verify_merge(A_path, None, None,
                                        sbox.repo_url + '/A_COPY', None,
                                        expected_output,
@@ -11184,27 +11178,23 @@ def reintegrate_on_shallow_wc(sbox):
   # Now revert the reintegrate and make a second change on the
   # branch in r4, but this time change a subtree that corresponds
   # to the missing (shallow) portion of the source.  The reintegrate
-  # should still succeed, albeit with a tree-conflict.
+  # should still succeed, albeit skipping some paths.
   svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
   svntest.main.file_write(psi_COPY_path, "more branch work")
   svntest.main.run_svn(None, 'commit', '-m',
                        'Some more work on the A_COPY branch', wc_dir)
-  # Reuse the same expectations as the prior merge, except that...
-  #
-  # ...a tree conflict occurs...
-  expected_output.add({
-      'D/H' : Item(status='  ', treeconflict='C')
-      })
-  expected_A_status.add({
-      'D/H' : Item(status='! ', treeconflict='C')
-      })
-  # ...non-inheritable mergeinfo is set on the root of the missing subtree...
+  # Reuse the same expectations as the prior merge, except that
+  # non-inheritable mergeinfo is set on the root of the missing subtree...
   expected_mergeinfo_output.add({
       'D' : Item(status=' U')
       })
   expected_A_status.tweak('D', status=' M')
   expected_A_disk.tweak('D', props={SVN_PROP_MERGEINFO : '/A_COPY/D:2-4*'})
-  # ...the mergeinfo on the target root includes the latest rev on the branch.
+  # ... a depth-restricted item is skipped ...
+  expected_A_skip.add({
+      'D/H' : Item()
+  })
+  # ... and the mergeinfo on the target root includes the latest rev on the branch.
   expected_A_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-4'})
   svntest.actions.run_and_verify_merge(A_path, None, None,
                                        sbox.repo_url + '/A_COPY', None,
@@ -15200,8 +15190,7 @@ def tree_conflicts_on_merge_local_ci_4_1
     'DDF/D1'            : Item(status='! ', treeconflict='C'),
     })
 
-  expected_skip = svntest.wc.State('', {
-    })
+  expected_skip = svntest.wc.State('', { })
 
   svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,
     [ DeepTreesTestCase("local_tree_del_incoming_leaf_edit",
@@ -17004,12 +16993,6 @@ def tree_conflicts_merge_edit_onto_missi
   # local tree missing (via shell delete), incoming leaf edit
 
   expected_output = wc.State('', {
-#  'F/alpha'           : Item(status='  ', treeconflict='C'),
-  'D/D1'              : Item(status='  ', treeconflict='C'),
-  'DF/D1'             : Item(status='  ', treeconflict='C'),
-  'DD/D1'             : Item(status='  ', treeconflict='C'),
-  'DDF/D1'            : Item(status='  ', treeconflict='C'),
-  'DDD/D1'            : Item(status='  ', treeconflict='C'),
   })
 
   expected_disk = state_after_tree_del
@@ -17019,19 +17002,19 @@ def tree_conflicts_merge_edit_onto_missi
     'F'                 : Item(status='  ', wc_rev=3),
     'F/alpha'           : Item(status='!M', wc_rev=3),
     'D'                 : Item(status='  ', wc_rev=3),
-    'D/D1'              : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'D/D1'              : Item(status='! ', wc_rev='?'),
     'DF'                : Item(status='  ', wc_rev=3),
-    'DF/D1'             : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DF/D1'             : Item(status='! ', wc_rev='?'),
     'DF/D1/beta'        : Item(status='  '),
     'DD'                : Item(status='  ', wc_rev=3),
-    'DD/D1'             : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DD/D1'             : Item(status='! ', wc_rev='?'),
     'DD/D1/D2'          : Item(status='  '),
     'DDF'               : Item(status='  ', wc_rev=3),
-    'DDF/D1'            : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DDF/D1'            : Item(status='! ', wc_rev='?'),
     'DDF/D1/D2'         : Item(status='  '),
     'DDF/D1/D2/gamma'   : Item(status='  '),
     'DDD'               : Item(status='  ', wc_rev=3),
-    'DDD/D1'            : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DDD/D1'            : Item(status='! ', wc_rev='?'),
     'DDD/D1/D2'         : Item(status='  '),
     'DDD/D1/D2/D3'      : Item(status='  '),
     })
@@ -17040,6 +17023,7 @@ def tree_conflicts_merge_edit_onto_missi
     'F/alpha'           : Item(),
     })
 
+
   svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox,
     [ DeepTreesTestCase(
                "local_tree_missing_incoming_leaf_edit",
@@ -17049,6 +17033,17 @@ def tree_conflicts_merge_edit_onto_missi
                expected_disk,
                expected_status,
                expected_skip,
+
+               ### This should not happening!
+               ### The commit succeeds (it only commits mergeinfo).
+               ### But then the work queue freaks out while trying to install
+               ### F/alpha into the WC, because F/alpha is missing from disk.
+               ### We end up with a working copy that cannot be cleaned up.
+               ### To make this test pass for now we'll expect this error.
+               ### When the problem is fixed this test will start to fail
+               ### and should be adjusted.
+               commit_block_string=".*Error bumping revisions post-commit",
+
              ) ], False)
 
 def tree_conflicts_merge_del_onto_missing(sbox):
@@ -17057,12 +17052,6 @@ def tree_conflicts_merge_del_onto_missin
   # local tree missing (via shell delete), incoming leaf edit
 
   expected_output = wc.State('', {
-#  'F/alpha'           : Item(status='  ', treeconflict='C'),
-#  'D/D1'              : Item(status='  ', treeconflict='C'),
-  'DF/D1'             : Item(status='  ', treeconflict='C'),
-  'DD/D1'             : Item(status='  ', treeconflict='C'),
-  'DDF/D1'            : Item(status='  ', treeconflict='C'),
-  'DDD/D1'            : Item(status='  ', treeconflict='C'),
   })
 
   expected_disk = state_after_tree_del
@@ -17074,17 +17063,17 @@ def tree_conflicts_merge_del_onto_missin
     'D'                 : Item(status='  ', wc_rev=3),
     'D/D1'              : Item(status='! ', wc_rev='?'),
     'DF'                : Item(status='  ', wc_rev=3),
-    'DF/D1'             : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DF/D1'             : Item(status='! ', wc_rev='?'),
     'DF/D1/beta'        : Item(status='  '),
     'DD'                : Item(status='  ', wc_rev=3),
-    'DD/D1'             : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DD/D1'             : Item(status='! ', wc_rev='?'),
     'DD/D1/D2'          : Item(status='  '),
     'DDF'               : Item(status='  ', wc_rev=3),
-    'DDF/D1'            : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DDF/D1'            : Item(status='! ', wc_rev='?'),
     'DDF/D1/D2'         : Item(status='  '),
     'DDF/D1/D2/gamma'   : Item(status='  '),
     'DDD'               : Item(status='  ', wc_rev=3),
-    'DDD/D1'            : Item(status='! ', wc_rev='?', treeconflict='C'),
+    'DDD/D1'            : Item(status='! ', wc_rev='?'),
     'DDD/D1/D2'         : Item(status='  '),
     'DDD/D1/D2/D3'      : Item(status='  '),
     })
@@ -17103,7 +17092,17 @@ def tree_conflicts_merge_del_onto_missin
                expected_disk,
                expected_status,
                expected_skip,
-               commit_block_string = ".*missing.*"
+
+               ### This should not happening!
+               ### The commit succeeds (it only commits mergeinfo).
+               ### But then the work queue freaks out while trying to install
+               ### F/alpha into the WC, because F/alpha is missing from disk.
+               ### We end up with a working copy that cannot be cleaned up.
+               ### To make this test pass for now we'll expect this error.
+               ### When the problem is fixed this test will start to fail
+               ### and should be adjusted.
+               commit_block_string=".*Error bumping revisions post-commit",
+
              ) ], False)
 
 #----------------------------------------------------------------------



Re: svn commit: r946186 - new output parameter SKIP_CHILDREN

Posted by Stefan Sperling <st...@elego.de>.
On Thu, May 20, 2010 at 12:14:22AM +0100, Julian Foad wrote:
> On Wed, 2010-05-19, stsp@apache.org wrote:
> > Author: stsp
> > Date: Wed May 19 13:55:51 2010
> > New Revision: 946186
> > 
> > URL: http://svn.apache.org/viewvc?rev=946186&view=rev
> 
> > * subversion/include/svn_wc.h
> >   (svn_wc_diff_callbacks4_t): Add new output parameter SKIP_CHILDREN
> >    to the dir_opened() callback. [...]
> 
> This new parameter also needs to be added to the wrap_4to3_dir_opened()
> in 'deprecated.c'.  ("subversion/libsvn_wc/deprecated.c:1672: warning:
> initialization from incompatible pointer type")

Thank you, r946495.

Stefan

Re: svn commit: r946186 - new output parameter SKIP_CHILDREN

Posted by Julian Foad <ju...@btopenworld.com>.
On Wed, 2010-05-19, stsp@apache.org wrote:
> Author: stsp
> Date: Wed May 19 13:55:51 2010
> New Revision: 946186
> 
> URL: http://svn.apache.org/viewvc?rev=946186&view=rev

> * subversion/include/svn_wc.h
>   (svn_wc_diff_callbacks4_t): Add new output parameter SKIP_CHILDREN
>    to the dir_opened() callback. [...]

This new parameter also needs to be added to the wrap_4to3_dir_opened()
in 'deprecated.c'.  ("subversion/libsvn_wc/deprecated.c:1672: warning:
initialization from incompatible pointer type")

- Julian


> Modified: subversion/trunk/subversion/include/svn_wc.h
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=946186&r1=946185&r2=946186&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/include/svn_wc.h (original)
> +++ subversion/trunk/subversion/include/svn_wc.h Wed May 19 13:55:51 2010
> @@ -2352,9 +2352,13 @@ typedef struct svn_wc_diff_callbacks4_t
>     *
>     * This function is called for @a path before any of the callbacks are
>     * called for a child of @a path.
> +   *
> +   * If the callback returns @c TRUE in @a *skip_children, children
> +   * of this directory will be skipped.
>     */
>    svn_error_t *(*dir_opened)(const char *local_dir_abspath,
>                               svn_boolean_t *tree_conflicted,
> +                             svn_boolean_t *skip_children,
>                               const char *path,
>                               svn_revnum_t rev,
>                               void *diff_baton,
> 
> Modified: subversion/trunk/subversion/libsvn_client/diff.c
> URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=946186&r1=946185&r2=946186&view=diff
> ==============================================================================
> --- subversion/trunk/subversion/libsvn_client/diff.c (original)
> +++ subversion/trunk/subversion/libsvn_client/diff.c Wed May 19 13:55:51 2010
> @@ -800,6 +800,7 @@ diff_dir_deleted(const char *local_dir_a
>  static svn_error_t *
>  diff_dir_opened(const char *local_dir_abspath,
>                  svn_boolean_t *tree_conflicted,
> +                svn_boolean_t *skip_children,
>                  const char *path,
>                  svn_revnum_t rev,
>                  void *diff_baton,
> @@ -807,6 +808,8 @@ diff_dir_opened(const char *local_dir_ab
>  {
>    if (tree_conflicted)
>      *tree_conflicted = FALSE;
> +  if (skip_children)
> +    *skip_children = FALSE;
>  
>    /* Do nothing. */
>