subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1161147 [4/9] - in /subversion/branches/revprop-packing: ./ build/ build/ac-macros/ notes/ subversion/bindings/ctypes-python/csvn/ subversion/bindings/ctypes-python/test/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/or...
Date Wed, 24 Aug 2011 15:16:55 GMT
Modified: subversion/branches/revprop-packing/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/merge.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/merge.c Wed Aug 24 15:16:50 2011
@@ -427,7 +427,6 @@ perform_obstruction_check(svn_wc_notify_
                                          kind,
                                          added,
                                          deleted,
-                                         NULL,
                                          wc_ctx, local_abspath,
                                          check_root,
                                          scratch_pool));
@@ -1347,6 +1346,67 @@ merge_file_opened(svn_boolean_t *tree_co
   return SVN_NO_ERROR;
 }
 
+
+/* Indicate in *MOVED_AWAY whether the node at LOCAL_ABSPATH was
+ * moved away locally. Do not raise an error if the node at LOCAL_ABSPATH
+ * does not exist. */
+static svn_error_t *
+check_moved_away(svn_boolean_t *moved_away,
+                 svn_wc_context_t *wc_ctx,
+                 const char *local_abspath,
+                 apr_pool_t *scratch_pool)
+{
+  const char *moved_to_abspath;
+  svn_error_t *err;
+  
+  *moved_away = FALSE;
+
+  err = svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
+                                    wc_ctx, local_abspath,
+                                    scratch_pool, scratch_pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
+  else if (moved_to_abspath)
+    *moved_away = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
+/* Indicate in *MOVED_HERE whether the node at LOCAL_ABSPATH was
+ * moved here locally. Do not raise an error if the node at LOCAL_ABSPATH
+ * does not exist. */
+static svn_error_t *
+check_moved_here(svn_boolean_t *moved_here,
+                 svn_wc_context_t *wc_ctx,
+                 const char *local_abspath,
+                 apr_pool_t *scratch_pool)
+{
+  const char *moved_from_abspath;
+  svn_error_t *err;
+  
+  *moved_here = FALSE;
+
+  err = svn_wc__node_was_moved_here(&moved_from_abspath, NULL,
+                                    wc_ctx, local_abspath,
+                                    scratch_pool, scratch_pool);
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
+  else if (moved_from_abspath)
+    *moved_here = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
 /* An svn_wc_diff_callbacks4_t function. */
 static svn_error_t *
 merge_file_changed(svn_wc_notify_state_t *content_state,
@@ -1400,6 +1460,9 @@ merge_file_changed(svn_wc_notify_state_t
      way svn_wc_merge4() can do the merge. */
   if (wc_kind != svn_node_file || is_deleted)
     {
+      svn_boolean_t moved_away;
+      svn_wc_conflict_reason_t reason;
+
       /* Maybe the node is excluded via depth filtering? */
 
       if (wc_kind == svn_node_none)
@@ -1428,9 +1491,16 @@ merge_file_changed(svn_wc_notify_state_t
       /* This is use case 4 described in the paper attached to issue
        * #2282.  See also notes/tree-conflicts/detection.txt
        */
+      SVN_ERR(check_moved_away(&moved_away, merge_b->ctx->wc_ctx,
+                               mine_abspath, scratch_pool));
+      if (moved_away)
+        reason = svn_wc_conflict_reason_moved_away;
+      else if (is_deleted)
+        reason = svn_wc_conflict_reason_deleted;
+      else
+        reason = svn_wc_conflict_reason_missing;
       SVN_ERR(tree_conflict(merge_b, mine_abspath, svn_node_file,
-                            svn_wc_conflict_action_edit,
-                            svn_wc_conflict_reason_missing));
+                            svn_wc_conflict_action_edit, reason));
       if (tree_conflicted)
         *tree_conflicted = TRUE;
       if (content_state)
@@ -1697,14 +1767,21 @@ merge_file_added(svn_wc_notify_state_t *
                                               merge_b->pool));
             if (existing_conflict)
               {
+                svn_boolean_t moved_here;
+                svn_wc_conflict_reason_t reason;
+
                 /* Possibly collapse the existing conflict into a 'replace'
                  * tree conflict. The conflict reason is 'added' because
                  * the now-deleted tree conflict victim must have been
                  * added in the history of the merge target. */
+                SVN_ERR(check_moved_here(&moved_here, merge_b->ctx->wc_ctx,
+                                         mine_abspath, scratch_pool));
+                reason = moved_here ? svn_wc_conflict_reason_moved_here
+                                    : svn_wc_conflict_reason_added;
                 SVN_ERR(tree_conflict_on_add(merge_b, mine_abspath,
                                              svn_node_file,
                                              svn_wc_conflict_action_add,
-                                             svn_wc_conflict_reason_added));
+                                             reason));
                 if (tree_conflicted)
                   *tree_conflicted = TRUE;
               }
@@ -1770,14 +1847,20 @@ merge_file_added(svn_wc_notify_state_t *
               }
             else
               {
+                svn_boolean_t moved_here;
+                svn_wc_conflict_reason_t reason;
+
                 /* The file add the merge wants to carry out is obstructed by
                  * a versioned file. This file must have been added in the
                  * history of the merge target, hence we flag a tree conflict
                  * with reason 'added'. */
+                SVN_ERR(check_moved_here(&moved_here, merge_b->ctx->wc_ctx,
+                                         mine_abspath, scratch_pool));
+                reason = moved_here ? svn_wc_conflict_reason_moved_here
+                                    : svn_wc_conflict_reason_added;
                 SVN_ERR(tree_conflict_on_add(
                           merge_b, mine_abspath, svn_node_file,
-                          svn_wc_conflict_action_add,
-                          svn_wc_conflict_reason_added));
+                          svn_wc_conflict_action_add, reason));
 
                 if (tree_conflicted)
                   *tree_conflicted = TRUE;
@@ -1855,7 +1938,7 @@ files_same_p(svn_boolean_t *same,
       /* Compare the file content, translating 'mine' to 'normal' form. */
       SVN_ERR(svn_client__get_normalized_stream(&mine_stream, wc_ctx,
                                                 mine_abspath, &working_rev,
-                                                FALSE, NULL, NULL,
+                                                FALSE, TRUE, NULL, NULL,
                                                 scratch_pool, scratch_pool));
 
       SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath,
@@ -1884,6 +1967,8 @@ merge_file_deleted(svn_wc_notify_state_t
 {
   merge_cmd_baton_t *merge_b = baton;
   svn_node_kind_t kind;
+  svn_boolean_t moved_away;
+  svn_wc_conflict_reason_t reason;
 
   if (merge_b->dry_run)
     {
@@ -1976,9 +2061,12 @@ merge_file_deleted(svn_wc_notify_state_t
        * This is use case 6 described in the paper attached to issue
        * #2282.  See also notes/tree-conflicts/detection.txt
        */
+      SVN_ERR(check_moved_away(&moved_away, merge_b->ctx->wc_ctx,
+                               mine_abspath, scratch_pool));
+      reason = moved_away ? svn_wc_conflict_reason_moved_away
+                          : svn_wc_conflict_reason_deleted;
       SVN_ERR(tree_conflict(merge_b, mine_abspath, svn_node_file,
-                            svn_wc_conflict_action_delete,
-                            svn_wc_conflict_reason_deleted));
+                            svn_wc_conflict_action_delete, reason));
       if (tree_conflicted)
         *tree_conflicted = TRUE;
       if (state)
@@ -2143,11 +2231,18 @@ merge_dir_added(svn_wc_notify_state_t *s
             }
           else
             {
+              svn_boolean_t moved_here;
+              svn_wc_conflict_reason_t reason;
+
               /* This is a tree conflict. */
+              SVN_ERR(check_moved_here(&moved_here, merge_b->ctx->wc_ctx,
+                                       local_abspath, scratch_pool));
+              reason = moved_here ? svn_wc_conflict_reason_moved_here
+                                  : svn_wc_conflict_reason_added;
               SVN_ERR(tree_conflict_on_add(merge_b, local_abspath,
                                            svn_node_dir,
                                            svn_wc_conflict_action_add,
-                                           svn_wc_conflict_reason_added));
+                                           reason));
               if (tree_conflicted)
                 *tree_conflicted = TRUE;
               if (state)
@@ -2203,6 +2298,9 @@ merge_dir_deleted(svn_wc_notify_state_t 
   svn_error_t *err;
   svn_boolean_t is_versioned;
   svn_boolean_t is_deleted;
+  svn_boolean_t moved_away;
+  svn_wc_conflict_reason_t reason;
+
 
   /* Easy out: We are only applying mergeinfo differences. */
   if (merge_b->record_only)
@@ -2287,9 +2385,12 @@ merge_dir_deleted(svn_wc_notify_state_t 
           {
             /* Dir is already not under version control at this path. */
             /* Raise a tree conflict. */
+            SVN_ERR(check_moved_away(&moved_away, merge_b->ctx->wc_ctx,
+                                     local_abspath, scratch_pool));
+            reason = moved_away ? svn_wc_conflict_reason_moved_away
+                                : svn_wc_conflict_reason_deleted;
             SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
-                                  svn_wc_conflict_action_delete,
-                                  svn_wc_conflict_reason_deleted));
+                                  svn_wc_conflict_action_delete, reason));
             if (tree_conflicted)
               *tree_conflicted = TRUE;
           }
@@ -2303,9 +2404,12 @@ merge_dir_deleted(svn_wc_notify_state_t 
       /* Dir is already non-existent. This is use case 6 as described in
        * notes/tree-conflicts/detection.txt.
        * This case was formerly treated as no-op. */
+      SVN_ERR(check_moved_away(&moved_away, merge_b->ctx->wc_ctx,
+                               local_abspath, scratch_pool));
+      reason = moved_away ? svn_wc_conflict_reason_moved_away
+                          : svn_wc_conflict_reason_deleted;
       SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
-                            svn_wc_conflict_action_delete,
-                            svn_wc_conflict_reason_deleted));
+                            svn_wc_conflict_action_delete, reason));
       if (tree_conflicted)
         *tree_conflicted = TRUE;
       if (state)
@@ -2400,9 +2504,15 @@ merge_dir_opened(svn_boolean_t *tree_con
        * forcing the user to sanity-check the merge result. */
       else if (is_deleted || wc_kind == svn_node_none)
         {
+          svn_boolean_t moved_away;
+          svn_wc_conflict_reason_t reason;
+
+          SVN_ERR(check_moved_away(&moved_away, merge_b->ctx->wc_ctx,
+                                   local_abspath, scratch_pool));
+          reason = moved_away ? svn_wc_conflict_reason_moved_away
+                              : svn_wc_conflict_reason_deleted;
           SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
-                                svn_wc_conflict_action_edit,
-                                svn_wc_conflict_reason_deleted));
+                                svn_wc_conflict_action_edit, reason));
           if (tree_conflicted)
             *tree_conflicted = TRUE;
         }
@@ -4481,7 +4591,8 @@ populate_remaining_ranges(apr_array_head
 /* Helper for record_mergeinfo_for_dir_merge().
 
    Adjust, in place, the inheritability of the ranges in RANGELIST to
-   describe a merge of RANGELIST into WC_WCPATH at depth DEPTH.
+   describe a merge of RANGELIST into WC_WCPATH at depth DEPTH.  Set
+   *RANGELIST_INHERITANCE to the inheritability set.
 
    WC_PATH_IS_MERGE_TARGET is true if WC_PATH is the target of the merge,
    otherwise WC_PATH is a subtree.
@@ -4493,6 +4604,7 @@ populate_remaining_ranges(apr_array_head
    Perform any temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
 calculate_merge_inheritance(apr_array_header_t *rangelist,
+                            svn_boolean_t *rangelist_inheritance,
                             const char *local_abspath,
                             svn_boolean_t wc_path_is_merge_target,
                             svn_boolean_t wc_path_has_missing_child,
@@ -4504,6 +4616,10 @@ calculate_merge_inheritance(apr_array_he
 
   SVN_ERR(svn_wc_read_kind(&path_kind, wc_ctx, local_abspath, FALSE,
                            scratch_pool));
+
+  /* Starting assumption. */
+  *rangelist_inheritance = TRUE;
+
   if (path_kind == svn_node_file)
     {
       /* Files *never* have non-inheritable mergeinfo. */
@@ -4516,17 +4632,27 @@ calculate_merge_inheritance(apr_array_he
           if (wc_path_has_missing_child
               || depth == svn_depth_files
               || depth == svn_depth_empty)
-            svn_rangelist__set_inheritance(rangelist, FALSE);
+            {
+              svn_rangelist__set_inheritance(rangelist, FALSE);
+              *rangelist_inheritance = FALSE;
+            }
           else /* depth == svn_depth_files || depth == svn_depth_empty */
-            svn_rangelist__set_inheritance(rangelist, TRUE);
+            {
+              svn_rangelist__set_inheritance(rangelist, TRUE);
+            }
         }
       else /* WC_PATH is a directory subtree of the target. */
         {
           if (wc_path_has_missing_child
               || depth == svn_depth_immediates)
-            svn_rangelist__set_inheritance(rangelist, FALSE);
+            {
+              svn_rangelist__set_inheritance(rangelist, FALSE);
+              *rangelist_inheritance = FALSE;
+            }
           else /* depth == infinity */
-            svn_rangelist__set_inheritance(rangelist, TRUE);
+            {
+              svn_rangelist__set_inheritance(rangelist, TRUE);
+            }
         }
     }
   return SVN_NO_ERROR;
@@ -5023,7 +5149,8 @@ drive_merge_report_editor(const char *ta
                                       merge_b->ctx->wc_ctx, target_abspath,
                                       depth,
                                       merge_b->ra_session2, revision1,
-                                      FALSE,
+                                      FALSE /* walk_deleted_dirs */,
+                                      TRUE /* text_deltas */,
                                       &merge_callbacks, merge_b,
                                       merge_b->ctx->cancel_func,
                                       merge_b->ctx->cancel_baton,
@@ -5673,10 +5800,10 @@ pre_merge_status_cb(void *baton,
      2) Path is switched.
      3) Path is a subtree of the merge target (i.e. is not equal to
         MERGE_CMD_BATON->TARGET_ABSPATH) and has no mergeinfo of its own but
-        its parent has mergeinfo with non-inheritable ranges.  If this isn't a
-        dry-run and the merge is between differences in the same repository,
-        then this function will set working mergeinfo on the path equal to
-        the mergeinfo inheritable from its parent.
+        its immediate parent has mergeinfo with non-inheritable ranges.  If
+        this isn't a dry-run and the merge is between differences in the same
+        repository, then this function will set working mergeinfo on the path
+        equal to the mergeinfo inheritable from its parent.
      4) Path has an immediate child (or children) missing from the WC because
         the child is switched or absent from the WC, or due to a sparse
         checkout.
@@ -7600,6 +7727,7 @@ record_mergeinfo_for_dir_merge(svn_merge
       else /* Record mergeinfo on CHILD. */
         {
           svn_boolean_t child_is_deleted;
+          svn_boolean_t rangelist_inheritance;
 
           /* If CHILD is deleted we don't need to set mergeinfo on it. */
           SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
@@ -7662,6 +7790,7 @@ record_mergeinfo_for_dir_merge(svn_merge
             continue;
 
           SVN_ERR(calculate_merge_inheritance(child_merge_rangelist,
+                                              &rangelist_inheritance,
                                               child->abspath,
                                               i == 0,
                                               child->missing_child,
@@ -7695,6 +7824,66 @@ record_mergeinfo_for_dir_merge(svn_merge
             }
 
           child_merges = apr_hash_make(iterpool);
+
+          /* If CHILD is the merge target we then know that the mergeinfo
+             described by MERGE_SOURCE_PATH:MERGED_RANGE->START-
+             MERGED_RANGE->END describes existent path-revs in the repository,
+             see normalize_merge_sources() and the global comment
+             'MERGEINFO MERGE SOURCE NORMALIZATION'.
+
+             If CHILD is a subtree of the merge target however, then no such
+             guarantee holds.  The mergeinfo described by
+             (MERGE_SOURCE_PATH + CHILD_REPOS_PATH):MERGED_RANGE->START-
+             MERGED_RANGE->END might contain merge sources which don't
+             exist or refer to unrelated lines of history. */
+          if (i > 0
+              && (!merge_b->record_only || merge_b->reintegrate_merge)
+              && (!is_rollback))
+            {
+              svn_opt_revision_t peg_revision;
+              svn_mergeinfo_t subtree_history_as_mergeinfo;
+              apr_array_header_t *child_merge_src_rangelist;
+              const char *old_session_url;
+              const char *subtree_mergeinfo_url =
+                svn_path_url_add_component2(merge_b->repos_root_url,
+                                            child_merge_src_canon_path + 1,
+                                            iterpool);
+
+              /* Confirm that the naive mergeinfo we want to set on
+                 CHILD->ABSPATH both exists and is part of
+                 (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's
+                 history. */
+              peg_revision.kind = svn_opt_revision_number;
+
+              /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START
+                 because we only do this for forward merges. */
+              peg_revision.value.number = merged_range->end;
+              SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                                        merge_b->ra_session2,
+                                                        subtree_mergeinfo_url,
+                                                        iterpool));
+              SVN_ERR(svn_client__get_history_as_mergeinfo(
+                &subtree_history_as_mergeinfo, NULL,
+                subtree_mergeinfo_url, &peg_revision,
+                MAX(merged_range->start, merged_range->end),
+                MIN(merged_range->start, merged_range->end),
+                merge_b->ra_session2, merge_b->ctx, iterpool));
+
+              if (old_session_url)
+                SVN_ERR(svn_ra_reparent(merge_b->ra_session2,
+                                        old_session_url, iterpool));
+              child_merge_src_rangelist = apr_hash_get(
+                subtree_history_as_mergeinfo,
+                child_merge_src_canon_path,
+                APR_HASH_KEY_STRING);
+              SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist,
+                                              child_merge_rangelist,
+                                              child_merge_src_rangelist,
+                                              FALSE, iterpool));
+              if (!rangelist_inheritance)
+                svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
+            }
+
           apr_hash_set(child_merges, child->abspath, APR_HASH_KEY_STRING,
                        child_merge_rangelist);
           SVN_ERR(update_wc_mergeinfo(result_catalog,
@@ -7748,18 +7937,17 @@ record_mergeinfo_for_dir_merge(svn_merge
 
 /* Helper for do_directory_merge().
 
-   Similar to record_mergeinfo_for_dir_merge in that it records mergeinfo
-   describing a merge of MERGED_RANGE->START:MERGED_RANGE->END from the
-   repository relative path MERGEINFO_PATH to MERGE->TARGET_ABSPATH.
-   Unlike record_mergeinfo_for_dir_merge() though, this
-   funtion only records mergeinfo on *new* subtrees added by the merge which
-   are children of paths with non-inheritable ranges or which have missing
-   siblings - see criteria 3 and 5 in the doc string for get_mergeinfo_paths.
-   See also issue #2829
-   http://subversion.tigris.org/issues/show_bug.cgi?id=2829#desc14.
+   Record mergeinfo describing a merge of
+   MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
+   MERGEINFO_PATH to each path in NOTIFY_B->ADDED_ABSPATHS which has explicit
+   mergeinfo or is the immediate child of a parent with explicit
+   non-inheritable mergeinfo.
 
    DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS, are
    cascaded from do_directory_merge's arguments of the same names.
+
+   Note: This is intended to support forward merges only, i.e.
+   MERGED_RANGE->START must be older than MERGED_RANGE->END.
 */
 static svn_error_t *
 record_mergeinfo_for_added_subtrees(
@@ -7778,6 +7966,8 @@ record_mergeinfo_for_added_subtrees(
   if (!notify_b->added_abspaths)
     return SVN_NO_ERROR;
 
+  SVN_ERR_ASSERT(merged_range->start < merged_range->end);
+
   iterpool = svn_pool_create(pool);
   for (hi = apr_hash_first(pool, notify_b->added_abspaths); hi;
        hi = apr_hash_next(hi))
@@ -7785,34 +7975,48 @@ record_mergeinfo_for_added_subtrees(
       const char *added_abspath = svn__apr_hash_index_key(hi);
       const char *dir_abspath;
       svn_mergeinfo_t parent_mergeinfo;
+      svn_mergeinfo_t added_path_mergeinfo;
       svn_boolean_t inherited; /* used multiple times, but ignored */
 
       apr_pool_clear(iterpool);
       dir_abspath = svn_dirent_dirname(added_abspath, iterpool);
 
-      /* Does ADDED_ABSPATH's immediate parent have non-inheritable
-         mergeinfo? */
-      SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, &inherited,
+      /* Grab the added path's explicit mergeinfo. */
+      SVN_ERR(svn_client__get_wc_mergeinfo(&added_path_mergeinfo, &inherited,
                                            svn_mergeinfo_explicit,
-                                           dir_abspath, NULL, NULL, FALSE,
-                                           merge_b->ctx,
-                                           iterpool, iterpool));
-      if (svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool))
+                                           added_abspath, NULL, NULL, FALSE,
+                                           merge_b->ctx, iterpool, iterpool));
+
+      /* If the added path doesn't have explicit mergeinfo, does its immediate
+         parent have non-inheritable mergeinfo? */
+      if (!added_path_mergeinfo)
+        SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, &inherited,
+                                             svn_mergeinfo_explicit,
+                                             dir_abspath, NULL, NULL, FALSE,
+                                             merge_b->ctx,
+                                             iterpool, iterpool));
+
+      if (added_path_mergeinfo
+          || svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool))
         {
           svn_client__merge_path_t *target_merge_path =
             APR_ARRAY_IDX(notify_b->children_with_mergeinfo, 0,
                           svn_client__merge_path_t *);
           svn_merge_range_t *rng;
           svn_node_kind_t added_path_kind;
-          svn_mergeinfo_t merge_mergeinfo, added_path_mergeinfo;
+          svn_mergeinfo_t merge_mergeinfo;
+          svn_mergeinfo_t adds_history_as_mergeinfo;
           apr_array_header_t *rangelist;
           const char *rel_added_path;
           const char *added_path_mergeinfo_path;
+          const char *old_session_url;
+          const char *added_path_mergeinfo_url;
+          svn_opt_revision_t peg_revision;
 
           SVN_ERR(svn_wc_read_kind(&added_path_kind, merge_b->ctx->wc_ctx,
                                    added_abspath, FALSE, iterpool));
 
-          /* Calculate the mergeinfo resulting from this merge. */
+          /* Calculate the naive mergeinfo describing the merge. */
           merge_mergeinfo = apr_hash_make(iterpool);
           rangelist = apr_array_make(iterpool, 1, sizeof(svn_merge_range_t *));
           rng = svn_merge_range_dup(merged_range, iterpool);
@@ -7839,14 +8043,46 @@ record_mergeinfo_for_added_subtrees(
           apr_hash_set(merge_mergeinfo, added_path_mergeinfo_path,
                        APR_HASH_KEY_STRING, rangelist);
 
-          /* Get any explicit mergeinfo the added path has. */
-          SVN_ERR(svn_client__get_wc_mergeinfo(
-            &added_path_mergeinfo, &inherited,
-            svn_mergeinfo_explicit, added_abspath,
-            NULL, NULL, FALSE, merge_b->ctx, iterpool, iterpool));
+          /* Don't add new mergeinfo to describe the merge if that mergeinfo
+             contains non-existent merge sources.
+
+             We know that MERGEINFO_PATH/rel_added_path's history does not
+             span MERGED_RANGE->START:MERGED_RANGE->END but rather that it
+             was added at some revions greater than MERGED_RANGE->START
+             (assuming this is a forward merge).  It may have been added,
+             deleted, and re-added many times.  The point is that we cannot
+             blindly apply the naive mergeinfo calculated above because it
+             will describe non-existent merge sources. To avoid this we get
+             take the intersection of the naive mergeinfo with
+             MERGEINFO_PATH/rel_added_path's history. */
+          added_path_mergeinfo_url =
+            svn_path_url_add_component2(merge_b->repos_root_url,
+                                        added_path_mergeinfo_path + 1,
+                                        iterpool);
+          peg_revision.kind = svn_opt_revision_number;
+          peg_revision.value.number = MAX(merged_range->start,
+                                          merged_range->end);
+          SVN_ERR(svn_client__ensure_ra_session_url(
+            &old_session_url, merge_b->ra_session2,
+            added_path_mergeinfo_url, iterpool));
+          SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &adds_history_as_mergeinfo, NULL,
+            added_path_mergeinfo_url, &peg_revision,
+            MAX(merged_range->start, merged_range->end),
+            MIN(merged_range->start, merged_range->end),
+            merge_b->ra_session2, merge_b->ctx, iterpool));
+
+          if (old_session_url)
+            SVN_ERR(svn_ra_reparent(merge_b->ra_session2,
+                                    old_session_url, iterpool));
+
+          SVN_ERR(svn_mergeinfo_intersect2(&merge_mergeinfo,
+                                           merge_mergeinfo,
+                                           adds_history_as_mergeinfo,
+                                           FALSE, iterpool, iterpool));
 
           /* Combine the explict mergeinfo on the added path (if any)
-             with the mergeinfo for this merge. */
+             with the mergeinfo describing this merge. */
           if (added_path_mergeinfo)
             SVN_ERR(svn_mergeinfo_merge(merge_mergeinfo, added_path_mergeinfo,
                                         iterpool));
@@ -8609,7 +8845,9 @@ do_directory_merge(svn_mergeinfo_catalog
          So here we look at the root path of each subtree added during the
          merge and set explicit mergeinfo on it if it meets the aforementioned
          conditions. */
-      if (err == SVN_NO_ERROR)
+      if (err == SVN_NO_ERROR
+          && (range.start < range.end)) /* Nothing to record on added subtrees
+                                           resulting from reverse merges. */
         {
           err = record_mergeinfo_for_added_subtrees(
                   &range, mergeinfo_path, depth,
@@ -10572,6 +10810,7 @@ merge_reintegrate_locked(const char *sou
   const char *target_url;
   svn_revnum_t target_base_rev;
   svn_node_kind_t kind;
+  svn_opt_revision_t no_rev;
 
   /* Make sure the target is really there. */
   SVN_ERR(svn_io_check_path(target_abspath, &kind, scratch_pool));
@@ -10643,20 +10882,16 @@ merge_reintegrate_locked(const char *sou
                               NULL, ctx, scratch_pool, scratch_pool));
 
   /* Open two RA sessions, one to our source and one to our target. */
+  no_rev.kind = svn_opt_revision_unspecified;
+  SVN_ERR(svn_client__ra_session_from_path(&source_ra_session, &rev2, &url2,
+                                           url2, NULL, peg_revision, &no_rev,
+                                           ctx, scratch_pool));
   SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, target_abspath,
                                scratch_pool, scratch_pool));
   SVN_ERR(svn_client__open_ra_session_internal(&target_ra_session, NULL,
                                                target_url,
                                                NULL, NULL, FALSE, FALSE,
                                                ctx, scratch_pool));
-  SVN_ERR(svn_client__open_ra_session_internal(&source_ra_session, NULL,
-                                               url2, NULL, NULL, FALSE, FALSE,
-                                               ctx, scratch_pool));
-
-  SVN_ERR(svn_client__get_revision_number(&rev2, NULL, ctx->wc_ctx,
-                                          "",
-                                          source_ra_session, peg_revision,
-                                          scratch_pool));
 
   SVN_ERR(calculate_left_hand_side(&url1, &rev1,
                                    &merged_to_source_mergeinfo_catalog,

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.c Wed Aug 24 15:16:50 2011
@@ -476,28 +476,66 @@ svn_client__get_repos_mergeinfo_catalog(
   apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
-  svn_mergeinfo_t repos_mergeinfo;
+  svn_mergeinfo_t repos_mergeinfo_cat;
   apr_array_header_t *rel_paths = apr_array_make(scratch_pool, 1,
                                                  sizeof(rel_path));
 
   APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;
 
   /* Fetch the mergeinfo. */
-  err = svn_ra_get_mergeinfo2(ra_session, &repos_mergeinfo, rel_paths, rev,
-                              inherit, validate_inherited_mergeinfo,
+  err = svn_ra_get_mergeinfo2(ra_session, &repos_mergeinfo_cat, rel_paths,
+                              rev, inherit, validate_inherited_mergeinfo,
                               include_descendants, result_pool);
   if (err)
     {
       if (squelch_incapable && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
         {
           svn_error_clear(err);
-          repos_mergeinfo = NULL;
+          *mergeinfo_cat = NULL;
         }
       else
         return svn_error_trace(err);
     }
 
-  *mergeinfo_cat = repos_mergeinfo;
+  if (repos_mergeinfo_cat == NULL)
+    {
+      *mergeinfo_cat = NULL;
+    }
+  else
+    {
+      const char *repos_root;
+      const char *session_url;
+
+      SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, scratch_pool));
+      SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
+
+      if (strcmp(repos_root, session_url) == 0)
+        {
+          *mergeinfo_cat = repos_mergeinfo_cat;
+        }
+      else
+        {
+          apr_hash_index_t *hi;
+          svn_mergeinfo_catalog_t rekeyed_mergeinfo_cat =
+            apr_hash_make(result_pool);
+
+          for (hi = apr_hash_first(scratch_pool, repos_mergeinfo_cat);
+               hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *path =
+                svn_path_url_add_component2(session_url,
+                                            svn__apr_hash_index_key(hi),
+                                            scratch_pool);
+              SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &path,
+                                                       path,
+                                                       result_pool));
+              apr_hash_set(rekeyed_mergeinfo_cat, path, APR_HASH_KEY_STRING,
+                           svn__apr_hash_index_val(hi));
+            }
+          *mergeinfo_cat = rekeyed_mergeinfo_cat;
+        }
+    }
   return SVN_NO_ERROR;
 }
 
@@ -560,6 +598,8 @@ svn_client__get_wc_or_repos_mergeinfo_ca
   const char *local_abspath;
   const char *repos_root;
   const char *repos_relpath;
+  svn_mergeinfo_catalog_t target_mergeinfo_cat_wc = NULL;
+  svn_mergeinfo_catalog_t target_mergeinfo_cat_repos = NULL;
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, target_wcpath,
                                   scratch_pool));
@@ -581,23 +621,37 @@ svn_client__get_wc_or_repos_mergeinfo_ca
   else
     url = NULL;
 
+  if (!repos_only)
+    {
+      SVN_ERR(svn_client__get_wc_mergeinfo_catalog(&target_mergeinfo_cat_wc,
+                                                   inherited,
+                                                   include_descendants,
+                                                   inherit,
+                                                   local_abspath,
+                                                   NULL, NULL,
+                                                   ignore_invalid_mergeinfo,
+                                                   ctx,
+                                                   result_pool,
+                                                   scratch_pool));
+
+      /* If we want LOCAL_ABSPATH's inherited mergeinfo, were we able to
+         get it from the working copy?  If not, then we must ask the
+         repository. */
+      if (! ((*inherited)
+             || (inherit == svn_mergeinfo_explicit)
+             || (repos_relpath
+                 && target_mergeinfo_cat_wc
+                 && apr_hash_get(target_mergeinfo_cat_wc, repos_relpath,
+                                 APR_HASH_KEY_STRING))))
+        {
+          repos_only = TRUE;
+          /* We already have any subtree mergeinfo from the working copy, no
+             need to ask the server for it again. */
+          include_descendants = FALSE;
+        }
+    }
+
   if (repos_only)
-    *target_mergeinfo_catalog = NULL;
-  else
-    SVN_ERR(svn_client__get_wc_mergeinfo_catalog(target_mergeinfo_catalog,
-                                                 inherited,
-                                                 include_descendants,
-                                                 inherit,
-                                                 local_abspath,
-                                                 NULL, NULL,
-                                                 ignore_invalid_mergeinfo,
-                                                 ctx,
-                                                 result_pool, scratch_pool));
-
-  /* If there is no WC mergeinfo check the repository for inherited
-     mergeinfo, unless TARGET_WCPATH is a local addition or has a
-     local modification which has removed all of its pristine mergeinfo. */
-  if (*target_mergeinfo_catalog == NULL)
     {
       /* No need to check the repos if this is a local addition. */
       if (url != NULL)
@@ -631,13 +685,14 @@ svn_client__get_wc_or_repos_mergeinfo_ca
                 }
 
               SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
-                        target_mergeinfo_catalog, ra_session,
+                        &target_mergeinfo_cat_repos, ra_session,
                         "", target_rev, inherit,
-                        TRUE, FALSE, TRUE,
+                        TRUE, include_descendants, TRUE,
                         result_pool, scratch_pool));
 
-              if (*target_mergeinfo_catalog
-                  && apr_hash_get(*target_mergeinfo_catalog, "",
+              if (target_mergeinfo_cat_repos
+                  && apr_hash_get(target_mergeinfo_cat_repos,
+                                  repos_relpath,
                                   APR_HASH_KEY_STRING))
                 {
                   *inherited = TRUE;
@@ -660,6 +715,25 @@ svn_client__get_wc_or_repos_mergeinfo_ca
             }
         }
     }
+
+  /* Combine the mergeinfo from the working copy and repository as needed. */
+  if (target_mergeinfo_cat_wc)
+    {
+      *target_mergeinfo_catalog = target_mergeinfo_cat_wc;
+      if (target_mergeinfo_cat_repos)
+        SVN_ERR(svn_mergeinfo_catalog_merge(*target_mergeinfo_catalog,
+                                            target_mergeinfo_cat_repos,
+                                            result_pool, scratch_pool));
+    }
+  else if (target_mergeinfo_cat_repos)
+    {
+      *target_mergeinfo_catalog = target_mergeinfo_cat_repos;
+    }
+  else
+    {
+      *target_mergeinfo_catalog = NULL;
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -1074,41 +1148,11 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
 
   if (use_url)
     {
-      svn_mergeinfo_catalog_t tmp_catalog;
-
       rev = peg_rev;
       SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
-        &tmp_catalog, ra_session, "", rev, svn_mergeinfo_inherited,
+        mergeinfo_catalog, ra_session, "", rev, svn_mergeinfo_inherited,
         FALSE, include_descendants, TRUE,
         result_pool, scratch_pool));
-
-      /* If we're not querying the root of the repository, the catalog
-         we fetched will be keyed on paths relative to the session
-         URL.  But our caller is expecting repository relpaths.  So we
-         do a little dance...  */
-      if (tmp_catalog && (strcmp(url, *repos_root) != 0))
-        {
-          apr_hash_index_t *hi;
-
-          *mergeinfo_catalog = apr_hash_make(result_pool);
-
-          for (hi = apr_hash_first(scratch_pool, tmp_catalog);
-               hi; hi = apr_hash_next(hi))
-            {
-              /* session-relpath -> repos-url -> repos-relpath */
-              const char *path =
-                svn_path_url_add_component2(url, svn__apr_hash_index_key(hi),
-                                            scratch_pool);
-              SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &path, path,
-                                                       result_pool));
-              apr_hash_set(*mergeinfo_catalog, path, APR_HASH_KEY_STRING,
-                           svn__apr_hash_index_val(hi));
-            }
-        }
-      else
-        {
-          *mergeinfo_catalog = tmp_catalog;
-        }
     }
   else /* ! svn_path_is_url() */
     {
@@ -1312,6 +1356,8 @@ find_nearest_ancestor(const apr_array_he
    svn_log_entry_receiver_t callback. */
 struct filter_log_entry_baton_t
 {
+  /* Is TRUE if RANGELIST describes potentially merged revisions, is FALSE
+     if RANGELIST describes potentially eligible revisions. */
   svn_boolean_t filtering_merged;
 
   /* Unsorted array of repository relative paths representing the merge
@@ -1329,8 +1375,9 @@ struct filter_log_entry_baton_t
      TARGET_MERGEINFO_CATALOG. */
   apr_array_header_t *depth_first_catalog_index;
 
-  /* A rangelist describing all the ranges merged to ABS_REPOS_TARGET_PATH
-     from the */
+  /* A rangelist describing all the revisions potentially merged or
+     potentially eligible for merging (see FILTERING_MERGED) based on
+     the target's explicit or inherited mergeinfo. */
   const apr_array_header_t *rangelist;
 
   /* The wrapped svn_log_entry_receiver_t callback and baton which
@@ -1345,9 +1392,18 @@ struct filter_log_entry_baton_t
    `struct filter_log_entry_baton_t *'.
 
    Call the wrapped log receiver BATON->log_receiver (with
-   BATON->log_receiver_baton), only if the log entry falls within the
-   ranges in BATON->rangelist.
- */
+   BATON->log_receiver_baton) if:
+   
+   BATON->FILTERING_MERGED is FALSE and the changes represented by LOG_ENTRY
+   have been fully merged from BATON->MERGE_SOURCE_PATHS to the WC target
+   based on the mergeinfo for the WC contained in BATON->TARGET_MERGEINFO_CATALOG.
+
+   Or
+
+   BATON->FILTERING_MERGED is TRUE and the changes represented by LOG_ENTRY
+   have not been merged, or only partially merged, from
+   BATON->MERGE_SOURCE_PATHS to the WC target based on the mergeinfo for the
+   WC contained in BATON->TARGET_MERGEINFO_CATALOG. */
 static svn_error_t *
 filter_log_entry_with_rangelist(void *baton,
                                 svn_log_entry_t *log_entry,
@@ -1410,6 +1466,7 @@ filter_log_entry_with_rangelist(void *ba
           apr_hash_index_t *hi2;
           svn_boolean_t found_this_revision = FALSE;
           const char *merge_source_rel_target;
+          const char *merge_source_path;
 
           svn_pool_clear(iterpool);
 
@@ -1417,8 +1474,8 @@ filter_log_entry_with_rangelist(void *ba
              merge sources.  If not then ignore this path.  */
           for (i = 0; i < fleb->merge_source_paths->nelts; i++)
             {
-              const char *merge_source_path
-                = APR_ARRAY_IDX(fleb->merge_source_paths, i, const char *);
+              merge_source_path = APR_ARRAY_IDX(fleb->merge_source_paths,
+                                                i, const char *);
 
               merge_source_rel_target
                 = svn_fspath__skip_ancestor(merge_source_path, path);
@@ -1452,20 +1509,33 @@ filter_log_entry_with_rangelist(void *ba
                    hi2;
                    hi2 = apr_hash_next(hi2))
                 {
+                  const char *mergeinfo_path = svn__apr_hash_index_key(hi2);
                   apr_array_header_t *rangelist = svn__apr_hash_index_val(hi2);
-                  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist,
-                                                  this_rev_rangelist, FALSE,
-                                                  iterpool));
-                  if (intersection->nelts)
+
+                  /* Does the mergeinfo for PATH reflect if
+                     LOG_ENTRY->REVISION was previously merged
+                     from MERGE_SOURCE_PATH? */
+                  if (svn_fspath__is_ancestor(merge_source_path,
+                                              mergeinfo_path))
                     {
+                      /* Something was merged from MERGE_SOURCE_PATH, does
+                         it include LOG_ENTRY->REVISION? */
                       SVN_ERR(svn_rangelist_intersect(&intersection,
                                                       rangelist,
                                                       this_rev_rangelist,
-                                                      TRUE, iterpool));
+                                                      FALSE,
+                                                      iterpool));
                       if (intersection->nelts)
                         {
-                          found_this_revision = TRUE;
-                          break;
+                          SVN_ERR(svn_rangelist_intersect(&intersection,
+                                                          rangelist,
+                                                          this_rev_rangelist,
+                                                          TRUE, iterpool));
+                          if (intersection->nelts)
+                            {
+                              found_this_revision = TRUE;
+                              break;
+                            }
                         }
                     }
                 }

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.h?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/mergeinfo.h Wed Aug 24 15:16:50 2011
@@ -186,7 +186,7 @@ svn_client__get_repos_mergeinfo(svn_ra_s
 /* If INCLUDE_DESCENDANTS is FALSE, behave exactly like
    svn_client__get_repos_mergeinfo() except the mergeinfo for REL_PATH
    is put in the mergeinfo catalog MERGEINFO_CAT, with the key being
-   REL_PATH itself.
+   the repository root-relative path of REL_PATH.
 
    If INCLUDE_DESCENDANTS is true, then any subtrees under REL_PATH
    with explicit mergeinfo are also included in MERGEINFO_CAT.  The

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/patch.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/patch.c Wed Aug 24 15:16:50 2011
@@ -365,7 +365,7 @@ obtain_eol_and_keywords_for_file(apr_has
 static svn_error_t *
 resolve_target_path(patch_target_t *target,
                     const char *path_from_patchfile,
-                    const char *local_abspath,
+                    const char *wcroot_abspath,
                     int strip_count,
                     svn_boolean_t prop_changes_only,
                     svn_wc_context_t *wc_ctx,
@@ -398,7 +398,8 @@ resolve_target_path(patch_target_t *targ
 
   if (svn_dirent_is_absolute(stripped_path))
     {
-      target->local_relpath = svn_dirent_is_child(local_abspath, stripped_path,
+      target->local_relpath = svn_dirent_is_child(wcroot_abspath,
+                                                  stripped_path,
                                                   result_pool);
 
       if (! target->local_relpath)
@@ -419,7 +420,7 @@ resolve_target_path(patch_target_t *targ
   /* Make sure the path is secure to use. We want the target to be inside
    * of the working copy and not be fooled by symlinks it might contain. */
   SVN_ERR(svn_dirent_is_under_root(&under_root,
-                                   &target->local_abspath, local_abspath,
+                                   &target->local_abspath, wcroot_abspath,
                                    target->local_relpath, result_pool));
 
   if (! under_root)
@@ -478,11 +479,32 @@ resolve_target_path(patch_target_t *targ
       return SVN_NO_ERROR;
     }
 
-  /* ### Shouldn't libsvn_wc flag an obstruction in this case? */
-  if (target->locally_deleted && target->kind_on_disk != svn_node_none)
+  if (target->locally_deleted)
     {
-      target->skipped = TRUE;
-      return SVN_NO_ERROR;
+      const char *moved_to_abspath;
+
+      SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
+                                          wc_ctx, target->local_abspath,
+                                          result_pool, scratch_pool));
+      if (moved_to_abspath)
+        {
+          target->local_abspath = moved_to_abspath;
+          target->local_relpath = svn_dirent_skip_ancestor(wcroot_abspath,
+                                                          moved_to_abspath);
+          SVN_ERR_ASSERT(target->local_relpath &&
+                         target->local_relpath[0] != '\0');
+
+          /* As far as we are concerned this target is not locally deleted. */
+          target->locally_deleted = FALSE;
+
+          SVN_ERR(svn_io_check_path(target->local_abspath,
+                                    &target->kind_on_disk, scratch_pool));
+        }
+      else if (target->kind_on_disk != svn_node_none)
+        {
+          target->skipped = TRUE;
+          return SVN_NO_ERROR;
+        }
     }
 
   return SVN_NO_ERROR;
@@ -828,7 +850,7 @@ choose_target_filename(const svn_patch_t
 static svn_error_t *
 init_patch_target(patch_target_t **patch_target,
                   const svn_patch_t *patch,
-                  const char *base_dir,
+                  const char *wcroot_abspath,
                   svn_wc_context_t *wc_ctx, int strip_count,
                   svn_boolean_t remove_tempfiles,
                   apr_pool_t *result_pool, apr_pool_t *scratch_pool)
@@ -873,7 +895,7 @@ init_patch_target(patch_target_t **patch
   target->prop_targets = apr_hash_make(result_pool);
 
   SVN_ERR(resolve_target_path(target, choose_target_filename(patch),
-                              base_dir, strip_count, prop_changes_only,
+                              wcroot_abspath, strip_count, prop_changes_only,
                               wc_ctx, result_pool, scratch_pool));
   if (! target->skipped)
     {

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff.c Wed Aug 24 15:16:50 2011
@@ -98,6 +98,9 @@ struct edit_baton {
      FALSE otherwise. */
   svn_boolean_t walk_deleted_repos_dirs;
 
+  /* Whether to report text deltas */
+  svn_boolean_t text_deltas;
+
   /* A callback used to see if the client wishes to cancel the running
      operation. */
   svn_cancel_func_t cancel_func;
@@ -315,11 +318,19 @@ get_file_mime_types(const char **mimetyp
 }
 
 
-/* Get revision REVISION of the file described by B from the repository.
- * Set B->path_start_revision to the path of a new temporary file containing
- * the file's text.  Set B->pristine_props to a new hash containing the
- * file's properties.  Install a pool cleanup handler on B->pool to delete
- * the file.
+/* Get revision B->base_revision of the file described by B from the
+ * repository, through B->edit_baton->ra_session.
+ *
+ * Unless PROPS_ONLY is true:
+ *   Set B->path_start_revision to the path of a new temporary file containing
+ *   the file's text.
+ *   Set B->start_md5_checksum to that file's MD-5 checksum.
+ *   Install a pool cleanup handler on B->pool to delete the file.
+ *
+ * Always:
+ *   Set B->pristine_props to a new hash containing the file's properties.
+ *
+ * Allocate all results in B->pool.
  */
 static svn_error_t *
 get_file_from_ra(struct file_baton *b,
@@ -332,7 +343,7 @@ get_file_from_ra(struct file_baton *b,
 
       SVN_ERR(svn_stream_open_unique(&fstream, &(b->path_start_revision), NULL,
                                      svn_io_file_del_on_pool_cleanup,
-                                     scratch_pool, scratch_pool));
+                                     b->pool, scratch_pool));
 
       fstream = svn_stream_checksummed2(fstream, NULL, &b->start_md5_checksum,
                                         svn_checksum_md5, TRUE, scratch_pool);
@@ -453,7 +464,7 @@ get_empty_file(struct edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
-/* An editor function. The root of the comparison hierarchy */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 set_target_revision(void *edit_baton,
                     svn_revnum_t target_revision,
@@ -465,7 +476,7 @@ set_target_revision(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function. The root of the comparison hierarchy */
+/* An svn_delta_editor_t function. The root of the comparison hierarchy */
 static svn_error_t *
 open_root(void *edit_baton,
           svn_revnum_t base_revision,
@@ -475,9 +486,6 @@ open_root(void *edit_baton,
   struct edit_baton *eb = edit_baton;
   struct dir_baton *b = make_dir_baton("", NULL, eb, FALSE, pool);
 
-  /* Override the wcpath in our baton. */
-  b->wcpath = apr_pstrdup(pool, eb->target);
-
   SVN_ERR(get_dirprops_from_ra(b, base_revision));
 
   *root_baton = b;
@@ -485,7 +493,7 @@ open_root(void *edit_baton,
 }
 
 /* Recursively walk tree rooted at DIR (at REVISION) in the repository,
- * reporting all files as deleted.  Part of a workaround for issue 2333.
+ * reporting all children as deleted.  Part of a workaround for issue 2333.
  *
  * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
  * must be a valid revision number, not SVN_INVALID_REVNUM.  EB is the
@@ -554,20 +562,27 @@ diff_deleted_dir(const char *dir,
         }
 
       if (dirent->kind == svn_node_dir)
-        SVN_ERR(diff_deleted_dir(path,
-                                 revision,
-                                 ra_session,
-                                 eb,
-                                 cancel_func,
-                                 cancel_baton,
-                                 iterpool));
+        {
+          const char *wcpath = svn_dirent_join(eb->target, path, iterpool);
+
+          SVN_ERR(eb->diff_callbacks->dir_deleted(
+                                NULL, NULL, wcpath,
+                                eb->diff_cmd_baton, iterpool));
+          SVN_ERR(diff_deleted_dir(path,
+                                   revision,
+                                   ra_session,
+                                   eb,
+                                   cancel_func,
+                                   cancel_baton,
+                                   iterpool));
+        }
     }
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 delete_entry(const char *path,
              svn_revnum_t base_revision,
@@ -668,7 +683,7 @@ delete_entry(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 add_directory(const char *path,
               void *parent_baton,
@@ -758,7 +773,7 @@ add_directory(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 open_directory(const char *path,
                void *parent_baton,
@@ -792,7 +807,7 @@ open_directory(const char *path,
 }
 
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 add_file(const char *path,
          void *parent_baton,
@@ -822,7 +837,7 @@ add_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 open_file(const char *path,
           void *parent_baton,
@@ -872,7 +887,7 @@ window_handler(svn_txdelta_window_t *win
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 apply_textdelta(void *file_baton,
                 const char *base_md5_digest,
@@ -939,7 +954,7 @@ apply_textdelta(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  When the file is closed we have a temporary
+/* An svn_delta_editor_t function.  When the file is closed we have a temporary
  * file containing a pristine version of the repository file. This can
  * be compared against the working copy.
  *
@@ -969,7 +984,7 @@ close_file(void *file_baton,
 
   scratch_pool = b->pool;
 
-  if (expected_md5_digest)
+  if (expected_md5_digest && eb->text_deltas)
     {
       svn_checksum_t *expected_md5_checksum;
 
@@ -1086,7 +1101,13 @@ close_file(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Report any accumulated prop changes via the 'dir_props_changed' callback,
+ * and then call the 'dir_closed' callback.  Notify about any deleted paths
+ * within this directory that have not already been notified, and then about
+ * this directory itself (unless it was added, in which case the notification
+ * was done at that time).
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 close_directory(void *dir_baton,
                 apr_pool_t *pool)
@@ -1110,6 +1131,7 @@ close_directory(void *dir_baton,
   if (!b->added && b->propchanges->nelts > 0)
     remove_non_prop_changes(b->pristine_props, b->propchanges);
 
+  /* Report any prop changes. */
   if (b->propchanges->nelts > 0)
     {
       svn_boolean_t tree_conflicted = FALSE;
@@ -1134,8 +1156,8 @@ close_directory(void *dir_baton,
                                          b->edit_baton->diff_cmd_baton,
                                          scratch_pool));
 
-  /* Don't notify added directories as they triggered notification
-     in add_directory. */
+  /* Notify about any deleted paths within this directory that have not
+   * already been notified. */
   if (!skipped && !b->added && eb->notify_func)
     {
       apr_hash_index_t *hi;
@@ -1157,6 +1179,8 @@ close_directory(void *dir_baton,
         }
     }
 
+  /* Notify about this directory itself (unless it was added, in which
+   * case the notification was done at that time). */
   if (!b->added && eb->notify_func)
     {
       svn_wc_notify_t *notify;
@@ -1188,7 +1212,9 @@ close_directory(void *dir_baton,
 }
 
 
-/* An editor function.  */
+/* Record a prop change, which we will report later in close_file().
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -1209,7 +1235,9 @@ change_file_prop(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Make a note of this prop change, to be reported when the dir is closed.
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_dir_prop(void *dir_baton,
                 const char *name,
@@ -1231,7 +1259,7 @@ change_dir_prop(void *dir_baton,
 }
 
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 close_edit(void *edit_baton,
            apr_pool_t *pool)
@@ -1243,7 +1271,8 @@ close_edit(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_directory(const char *path,
                  void *parent_baton,
@@ -1272,7 +1301,8 @@ absent_directory(const char *path,
 }
 
 
-/* An editor function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_file(const char *path,
             void *parent_baton,
@@ -1310,6 +1340,7 @@ svn_client__get_diff_editor(const svn_de
                             svn_ra_session_t *ra_session,
                             svn_revnum_t revision,
                             svn_boolean_t walk_deleted_dirs,
+                            svn_boolean_t text_deltas,
                             const svn_wc_diff_callbacks4_t *diff_callbacks,
                             void *diff_cmd_baton,
                             svn_cancel_func_t cancel_func,
@@ -1340,6 +1371,7 @@ svn_client__get_diff_editor(const svn_de
   eb->notify_func = notify_func;
   eb->notify_baton = notify_baton;
   eb->walk_deleted_repos_dirs = walk_deleted_dirs;
+  eb->text_deltas = text_deltas;
   eb->cancel_func = cancel_func;
   eb->cancel_baton = cancel_baton;
 

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff_summarize.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff_summarize.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/repos_diff_summarize.c Wed Aug 24 15:16:50 2011
@@ -1,5 +1,5 @@
 /*
- * repos_diff_summarize.c -- The diff summarize editor for summarizing
+ * repos_diff_summarize.c -- The diff callbacks for summarizing
  * the differences of two repository versions
  *
  * ====================================================================
@@ -30,9 +30,9 @@
 #include "client.h"
 
 
-/* Overall crawler editor baton.  */
-struct edit_baton {
-  /* The target of the diff, relative to the root of the edit */
+/* Diff callbacks baton.  */
+struct summarize_baton_t {
+  /* The target path of the diff, relative to the anchor; "" if target == anchor. */
   const char *target;
 
   /* The summarize callback passed down from the API */
@@ -41,412 +41,295 @@ struct edit_baton {
   /* The summarize callback baton */
   void *summarize_func_baton;
 
-  /* An RA session used to check the kind of deleted paths */
-  svn_ra_session_t *ra_session;
-
-  /* The start revision for the comparison */
-  svn_revnum_t revision;
-
-  /* TRUE if the operation needs to walk deleted dirs on the "old" side.
-     FALSE otherwise. */
-  svn_boolean_t walk_deleted_repos_dirs;
-
-  /* A callback used to see if the client wishes to cancel the running
-     operation. */
-  svn_cancel_func_t cancel_func;
-
-  /* A baton to pass to the cancellation callback. */
-  void *cancel_baton;
-
+  /* Which paths have a prop change. Key is a (const char *) path; the value
+   * is any non-null pointer to indicate that this path has a prop change. */
+  apr_hash_t *prop_changes;
 };
 
 
-/* Item baton. */
-struct item_baton {
-  /* The overall crawler editor baton */
-  struct edit_baton *edit_baton;
-
-  /* The summarize filled by the editor calls, NULL if this item hasn't
-     been modified (yet) */
-  svn_client_diff_summarize_t *summarize;
-
-  /* The path of the file or directory within the repository */
-  const char *path;
-
-  /* The kind of this item */
-  svn_node_kind_t node_kind;
-
-  /* The file/directory pool */
-  apr_pool_t *item_pool;
-};
-
-
-/* Create an item baton, with the fields initialized to EDIT_BATON, PATH,
- * NODE_KIND and POOL, respectively.  Allocate the returned structure in POOL.
- */
-static struct item_baton *
-create_item_baton(struct edit_baton *edit_baton,
-                  const char *path,
-                  svn_node_kind_t node_kind,
-                  apr_pool_t *pool)
-{
-  struct item_baton *b = apr_pcalloc(pool, sizeof(*b));
-
-  b->edit_baton = edit_baton;
-  /* Issue #2765: b->path is supposed to be relative to the target.
-     If the target is a file, just use an empty path.  This way the
-     receiver can just concatenate this path to the original path
-     without doing any extra checks. */
-  if (node_kind == svn_node_file && strcmp(path, edit_baton->target) == 0)
-    b->path =  "";
-  else
-    b->path = apr_pstrdup(pool, path);
-  b->node_kind = node_kind;
-  b->item_pool = pool;
-
-  return b;
-}
-
-/* Make sure that this item baton contains a summarize struct.
- * If it doesn't before this call, allocate a new struct in the item's pool,
- * initializing the diff kind to normal.
- * All other fields are also initialized from IB or to NULL/invalid values. */
-static void
-ensure_summarize(struct item_baton *ib)
-{
-  svn_client_diff_summarize_t *sum;
-  if (ib->summarize)
-    return;
-
-  sum = apr_pcalloc(ib->item_pool, sizeof(*sum));
-
-  sum->node_kind = ib->node_kind;
-  sum->summarize_kind = svn_client_diff_summarize_kind_normal;
-  sum->path = ib->path;
-
-  ib->summarize = sum;
-}
-
-
-/* An editor function. The root of the comparison hierarchy */
+/* Call B->summarize_func with B->summarize_func_baton, passing it a
+ * summary object composed from PATH (but made to be relative to the target
+ * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an
+ * add or delete) and NODE_KIND. */
 static svn_error_t *
-open_root(void *edit_baton,
-          svn_revnum_t base_revision,
-          apr_pool_t *pool,
-          void **root_baton)
+send_summary(struct summarize_baton_t *b,
+             const char *path,
+             svn_client_diff_summarize_kind_t summarize_kind,
+             svn_boolean_t prop_changed,
+             svn_node_kind_t node_kind,
+             apr_pool_t *scratch_pool)
 {
-  struct item_baton *ib = create_item_baton(edit_baton, "",
-                                            svn_node_dir, pool);
+  svn_client_diff_summarize_t *sum = apr_pcalloc(scratch_pool, sizeof(*sum));
 
-  *root_baton = ib;
-  return SVN_NO_ERROR;
-}
+  /* PATH is relative to the anchor of the diff, but SUM->path needs to be
+     relative to the target of the diff. */
+  sum->path = svn_relpath_skip_ancestor(b->target, path);
+  sum->summarize_kind = summarize_kind;
+  if (summarize_kind == svn_client_diff_summarize_kind_modified
+      || summarize_kind == svn_client_diff_summarize_kind_normal)
+    sum->prop_changed = prop_changed;
+  sum->node_kind = node_kind;
 
-/* Recursively walk the tree rooted at DIR (at REVISION) in the
- * repository, reporting all files as deleted.  Part of a workaround
- * for issue 2333.
- *
- * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
- * may be NULL, in which case it defaults to HEAD.  EDIT_BATON is the
- * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
- * should refer to a cancellation function (along with CANCEL_BATON).
- */
-/* ### TODO: Handle depth. */
-static svn_error_t *
-diff_deleted_dir(const char *dir,
-                 svn_revnum_t revision,
-                 svn_ra_session_t *ra_session,
-                 void *edit_baton,
-                 svn_cancel_func_t cancel_func,
-                 void *cancel_baton,
-                 apr_pool_t *pool)
-{
-  struct edit_baton *eb = edit_baton;
-  apr_hash_t *dirents;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_hash_index_t *hi;
-
-  if (cancel_func)
-    SVN_ERR(cancel_func(cancel_baton));
-
-  SVN_ERR(svn_ra_get_dir2(ra_session,
-                          &dirents,
-                          NULL, NULL,
-                          dir,
-                          revision,
-                          SVN_DIRENT_KIND,
-                          pool));
-
-  for (hi = apr_hash_first(pool, dirents); hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *path;
-      const char *name = svn__apr_hash_index_key(hi);
-      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
-      svn_node_kind_t kind;
-      svn_client_diff_summarize_t *sum;
-
-      svn_pool_clear(iterpool);
-
-      path = svn_relpath_join(dir, name, iterpool);
-
-      SVN_ERR(svn_ra_check_path(eb->ra_session,
-                                path,
-                                eb->revision,
-                                &kind,
-                                iterpool));
-
-      sum = apr_pcalloc(iterpool, sizeof(*sum));
-      sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
-      sum->path = path;
-      sum->node_kind = kind;
-
-      SVN_ERR(eb->summarize_func(sum,
-                                 eb->summarize_func_baton,
-                                 iterpool));
-
-      if (dirent->kind == svn_node_dir)
-        SVN_ERR(diff_deleted_dir(path,
-                                 revision,
-                                 ra_session,
-                                 eb,
-                                 cancel_func,
-                                 cancel_baton,
-                                 iterpool));
-    }
-
-  svn_pool_destroy(iterpool);
+  SVN_ERR(b->summarize_func(sum, b->summarize_func_baton, scratch_pool));
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
-static svn_error_t *
-delete_entry(const char *path,
-             svn_revnum_t base_revision,
-             void *parent_baton,
-             apr_pool_t *pool)
-{
-  struct item_baton *ib = parent_baton;
-  struct edit_baton *eb = ib->edit_baton;
-  svn_client_diff_summarize_t *sum;
-  svn_node_kind_t kind;
-
-  /* We need to know if this is a directory or a file */
-  SVN_ERR(svn_ra_check_path(eb->ra_session,
-                            path,
-                            eb->revision,
-                            &kind,
-                            pool));
-
-  sum = apr_pcalloc(pool, sizeof(*sum));
-  sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
-  sum->path = path;
-  sum->node_kind = kind;
-
-  SVN_ERR(eb->summarize_func(sum, eb->summarize_func_baton, pool));
-
-  if (kind == svn_node_dir)
-        SVN_ERR(diff_deleted_dir(path,
-                                 eb->revision,
-                                 eb->ra_session,
-                                 eb,
-                                 eb->cancel_func,
-                                 eb->cancel_baton,
-                                 pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* An editor function.  */
-static svn_error_t *
-add_directory(const char *path,
-              void *parent_baton,
-              const char *copyfrom_path,
-              svn_revnum_t copyfrom_rev,
-              apr_pool_t *pool,
-              void **child_baton)
+/* Are there any changes to relevant (normal) props in PROPCHANGES? */
+static svn_boolean_t
+props_changed(const apr_array_header_t *propchanges,
+              apr_pool_t *scratch_pool)
 {
-  struct item_baton *pb = parent_baton;
-  struct item_baton *cb;
+  apr_array_header_t *props;
 
-  cb = create_item_baton(pb->edit_baton, path, svn_node_dir, pool);
-  ensure_summarize(cb);
-  cb->summarize->summarize_kind = svn_client_diff_summarize_kind_added;
-
-  *child_baton = cb;
-  return SVN_NO_ERROR;
+  svn_error_clear(svn_categorize_props(propchanges, NULL, NULL, &props,
+                                       scratch_pool));
+  return (props->nelts != 0);
 }
 
-/* An editor function.  */
+
 static svn_error_t *
-open_directory(const char *path,
-               void *parent_baton,
-               svn_revnum_t base_revision,
-               apr_pool_t *pool,
-               void **child_baton)
+cb_dir_deleted(svn_wc_notify_state_t *state,
+               svn_boolean_t *tree_conflicted,
+               const char *path,
+               void *diff_baton,
+               apr_pool_t *scratch_pool)
 {
-  struct item_baton *pb = parent_baton;
-  struct item_baton *cb;
+  struct summarize_baton_t *b = diff_baton;
 
-  cb = create_item_baton(pb->edit_baton, path, svn_node_dir, pool);
+  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
+                       FALSE, svn_node_dir, scratch_pool));
 
-  *child_baton = cb;
+  if (state)
+    *state = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
   return SVN_NO_ERROR;
 }
 
-
-/* An editor function.  */
 static svn_error_t *
-close_directory(void *dir_baton,
-                apr_pool_t *pool)
+cb_file_deleted(svn_wc_notify_state_t *state,
+                svn_boolean_t *tree_conflicted,
+                const char *path,
+                const char *tmpfile1,
+                const char *tmpfile2,
+                const char *mimetype1,
+                const char *mimetype2,
+                apr_hash_t *originalprops,
+                void *diff_baton,
+                apr_pool_t *scratch_pool)
 {
-  struct item_baton *ib = dir_baton;
-  struct edit_baton *eb = ib->edit_baton;
+  struct summarize_baton_t *b = diff_baton;
 
-  if (ib->summarize)
-    SVN_ERR(eb->summarize_func(ib->summarize, eb->summarize_func_baton,
-                               pool));
+  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
+                       FALSE, svn_node_file, scratch_pool));
 
+  if (state)
+    *state = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
   return SVN_NO_ERROR;
 }
 
-
-/* An editor function.  */
 static svn_error_t *
-add_file(const char *path,
-         void *parent_baton,
-         const char *copyfrom_path,
-         svn_revnum_t copyfrom_rev,
-         apr_pool_t *pool,
-         void **file_baton)
+cb_dir_added(svn_wc_notify_state_t *state,
+             svn_boolean_t *tree_conflicted,
+             svn_boolean_t *skip,
+             svn_boolean_t *skip_children,
+             const char *path,
+             svn_revnum_t rev,
+             const char *copyfrom_path,
+             svn_revnum_t copyfrom_revision,
+             void *diff_baton,
+             apr_pool_t *scratch_pool)
 {
-  struct item_baton *pb = parent_baton;
-  struct item_baton *cb;
-
-  cb = create_item_baton(pb->edit_baton, path, svn_node_file, pool);
-  ensure_summarize(cb);
-  cb->summarize->summarize_kind = svn_client_diff_summarize_kind_added;
-
-  *file_baton = cb;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+  if (skip)
+    *skip = FALSE;
+  if (skip_children)
+    *skip_children = FALSE;
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
 static svn_error_t *
-open_file(const char *path,
-          void *parent_baton,
-          svn_revnum_t base_revision,
-          apr_pool_t *pool,
-          void **file_baton)
+cb_dir_opened(svn_boolean_t *tree_conflicted,
+              svn_boolean_t *skip,
+              svn_boolean_t *skip_children,
+              const char *path,
+              svn_revnum_t rev,
+              void *diff_baton,
+              apr_pool_t *scratch_pool)
 {
-  struct item_baton *pb = parent_baton;
-  struct item_baton *cb;
-
-  cb = create_item_baton(pb->edit_baton, path, svn_node_file, pool);
-
-  *file_baton = cb;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+  if (skip)
+    *skip = FALSE;
+  if (skip_children)
+    *skip_children = FALSE;
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
 static svn_error_t *
-apply_textdelta(void *file_baton,
-                const char *base_checksum,
-                apr_pool_t *pool,
-                svn_txdelta_window_handler_t *handler,
-                void **handler_baton)
+cb_dir_closed(svn_wc_notify_state_t *contentstate,
+              svn_wc_notify_state_t *propstate,
+              svn_boolean_t *tree_conflicted,
+              const char *path,
+              svn_boolean_t dir_was_added,
+              void *diff_baton,
+              apr_pool_t *scratch_pool)
 {
-  struct item_baton *ib = file_baton;
+  struct summarize_baton_t *b = diff_baton;
+  svn_boolean_t prop_change;
 
-  ensure_summarize(ib);
-  if (ib->summarize->summarize_kind == svn_client_diff_summarize_kind_normal)
-    ib->summarize->summarize_kind = svn_client_diff_summarize_kind_modified;
-
-  *handler = svn_delta_noop_window_handler;
-  *handler_baton = NULL;
+  prop_change = apr_hash_get(b->prop_changes, path, APR_HASH_KEY_STRING) != NULL;
+  if (dir_was_added || prop_change)
+    SVN_ERR(send_summary(b, path,
+                         dir_was_added ? svn_client_diff_summarize_kind_added
+                                       : svn_client_diff_summarize_kind_normal,
+                         prop_change, svn_node_dir, scratch_pool));
 
+  if (contentstate)
+    *contentstate = svn_wc_notify_state_inapplicable;
+  if (propstate)
+    *propstate = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
   return SVN_NO_ERROR;
 }
 
-
-/* An editor function.  */
 static svn_error_t *
-close_file(void *file_baton,
-           const char *text_checksum,
-           apr_pool_t *pool)
-{
-  struct item_baton *fb = file_baton;
-  struct edit_baton *eb = fb->edit_baton;
-
-  if (fb->summarize)
-    SVN_ERR(eb->summarize_func(fb->summarize, eb->summarize_func_baton,
-                               pool));
-
+cb_file_added(svn_wc_notify_state_t *contentstate,
+              svn_wc_notify_state_t *propstate,
+              svn_boolean_t *tree_conflicted,
+              const char *path,
+              const char *tmpfile1,
+              const char *tmpfile2,
+              svn_revnum_t rev1,
+              svn_revnum_t rev2,
+              const char *mimetype1,
+              const char *mimetype2,
+              const char *copyfrom_path,
+              svn_revnum_t copyfrom_revision,
+              const apr_array_header_t *propchanges,
+              apr_hash_t *originalprops,
+              void *diff_baton,
+              apr_pool_t *scratch_pool)
+{
+  struct summarize_baton_t *b = diff_baton;
+
+  SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_added,
+                       props_changed(propchanges, scratch_pool),
+                       svn_node_file, scratch_pool));
+
+  if (contentstate)
+    *contentstate = svn_wc_notify_state_inapplicable;
+  if (propstate)
+    *propstate = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_opened(svn_boolean_t *tree_conflicted,
+               svn_boolean_t *skip,
+               const char *path,
+               svn_revnum_t rev,
+               void *diff_baton,
+               apr_pool_t *scratch_pool)
+{
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+  if (skip)
+    *skip = FALSE;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_changed(svn_wc_notify_state_t *contentstate,
+                svn_wc_notify_state_t *propstate,
+                svn_boolean_t *tree_conflicted,
+                const char *path,
+                const char *tmpfile1,
+                const char *tmpfile2,
+                svn_revnum_t rev1,
+                svn_revnum_t rev2,
+                const char *mimetype1,
+                const char *mimetype2,
+                const apr_array_header_t *propchanges,
+                apr_hash_t *originalprops,
+                void *diff_baton,
+                apr_pool_t *scratch_pool)
+{
+  struct summarize_baton_t *b = diff_baton;
+  svn_boolean_t text_change = (tmpfile2 != NULL);
+
+  SVN_ERR(send_summary(b, path,
+                       text_change ? svn_client_diff_summarize_kind_modified
+                                   : svn_client_diff_summarize_kind_normal,
+                       props_changed(propchanges, scratch_pool),
+                       svn_node_file, scratch_pool));
+
+  if (contentstate)
+    *contentstate = svn_wc_notify_state_inapplicable;
+  if (propstate)
+    *propstate = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_dir_props_changed(svn_wc_notify_state_t *propstate,
+                     svn_boolean_t *tree_conflicted,
+                     const char *path,
+                     svn_boolean_t dir_was_added,
+                     const apr_array_header_t *propchanges,
+                     apr_hash_t *original_props,
+                     void *diff_baton,
+                     apr_pool_t *scratch_pool)
+{
+  struct summarize_baton_t *b = diff_baton;
+
+  if (props_changed(propchanges, scratch_pool))
+    apr_hash_set(b->prop_changes, path, APR_HASH_KEY_STRING, path);
+
+  if (propstate)
+    *propstate = svn_wc_notify_state_inapplicable;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_client__get_diff_summarize_callbacks(
+                        svn_wc_diff_callbacks4_t **callbacks,
+                        void **callback_baton,
+                        const char *target,
+                        svn_client_diff_summarize_func_t summarize_func,
+                        void *summarize_baton,
+                        apr_pool_t *pool)
+{
+  svn_wc_diff_callbacks4_t *cb = apr_palloc(pool, sizeof(*cb));
+  struct summarize_baton_t *b = apr_palloc(pool, sizeof(*b));
+
+  b->target = target;
+  b->summarize_func = summarize_func;
+  b->summarize_func_baton = summarize_baton;
+  b->prop_changes = apr_hash_make(pool);
+
+  cb->file_opened = cb_file_opened;
+  cb->file_changed = cb_file_changed;
+  cb->file_added = cb_file_added;
+  cb->file_deleted = cb_file_deleted;
+  cb->dir_deleted = cb_dir_deleted;
+  cb->dir_opened = cb_dir_opened;
+  cb->dir_added = cb_dir_added;
+  cb->dir_props_changed = cb_dir_props_changed;
+  cb->dir_closed = cb_dir_closed;
 
-/* An editor function, implementing both change_file_prop and
- * change_dir_prop.  */
-static svn_error_t *
-change_prop(void *entry_baton,
-            const char *name,
-            const svn_string_t *value,
-            apr_pool_t *pool)
-{
-  struct item_baton *ib = entry_baton;
-
-  if (svn_property_kind(NULL, name) == svn_prop_regular_kind)
-    {
-      ensure_summarize(ib);
-
-      if (ib->summarize->summarize_kind != svn_client_diff_summarize_kind_added)
-        ib->summarize->prop_changed = TRUE;
-    }
+  *callbacks = cb;
+  *callback_baton = b;
 
   return SVN_NO_ERROR;
 }
-
-/* Create a repository diff summarize editor and baton.  */
-svn_error_t *
-svn_client__get_diff_summarize_editor(const char *target,
-                                      svn_client_diff_summarize_func_t
-                                      summarize_func,
-                                      void *summarize_baton,
-                                      svn_ra_session_t *ra_session,
-                                      svn_revnum_t revision,
-                                      svn_cancel_func_t cancel_func,
-                                      void *cancel_baton,
-                                      const svn_delta_editor_t **editor,
-                                      void **edit_baton,
-                                      apr_pool_t *pool)
-{
-  svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
-  struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
-
-  eb->target = target;
-  eb->summarize_func = summarize_func;
-  eb->summarize_func_baton = summarize_baton;
-  eb->ra_session = ra_session;
-  eb->revision = revision;
-  eb->walk_deleted_repos_dirs = TRUE;
-  eb->cancel_func = cancel_func;
-  eb->cancel_baton = cancel_baton;
-
-  tree_editor->open_root = open_root;
-  tree_editor->delete_entry = delete_entry;
-  tree_editor->add_directory = add_directory;
-  tree_editor->open_directory = open_directory;
-  tree_editor->change_dir_prop = change_prop;
-  tree_editor->close_directory = close_directory;
-
-  tree_editor->add_file = add_file;
-  tree_editor->open_file = open_file;
-  tree_editor->apply_textdelta = apply_textdelta;
-  tree_editor->change_file_prop = change_prop;
-  tree_editor->close_file = close_file;
-
-  return svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
-                                           tree_editor, eb, editor, edit_baton,
-                                           pool);
-}

Modified: subversion/branches/revprop-packing/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/status.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_client/status.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_client/status.c Wed Aug 24 15:16:50 2011
@@ -85,12 +85,23 @@ tweak_status(void *baton,
   /* If the status item has an entry, but doesn't belong to one of the
      changelists our caller is interested in, we filter out this status
      transmission.  */
-  if (sb->changelist_hash
-      && (! status->changelist
-          || ! apr_hash_get(sb->changelist_hash, status->changelist,
-                            APR_HASH_KEY_STRING)))
+  /* ### duplicated in ../libsvn_wc/diff_local.c */
+  if (sb->changelist_hash)
     {
-      return SVN_NO_ERROR;
+      if (status->changelist)
+        {
+          /* Skip unless the caller requested this changelist. */
+          if (! apr_hash_get(sb->changelist_hash, status->changelist,
+                             APR_HASH_KEY_STRING))
+            return SVN_NO_ERROR;
+        }
+      else
+        {
+          /* Skip unless the caller requested changelist-lacking items. */
+          if (! apr_hash_get(sb->changelist_hash, "",
+                             APR_HASH_KEY_STRING))
+            return SVN_NO_ERROR;
+        }
     }
 
   /* If we know that the target was deleted in HEAD of the repository,
@@ -385,7 +396,7 @@ svn_client_status5(svn_revnum_t *result_
           svn_boolean_t added;
 
           /* Our status target does not exist in HEAD.  If we've got
-             it localled added, that's okay.  But if it was previously
+             it locally added, that's okay.  But if it was previously
              versioned, then it must have since been deleted from the
              repository.  (Note that "locally replaced" doesn't count
              as "added" in this case.)  */
@@ -563,6 +574,13 @@ svn_client_status_dup(const svn_client_s
                                                              result_pool);
     }
 
+  if (status->moved_from_abspath)
+    st->moved_from_abspath =
+      apr_pstrdup(result_pool, status->moved_from_abspath);
+
+  if (status->moved_to_abspath)
+    st->moved_to_abspath = apr_pstrdup(result_pool, status->moved_to_abspath);
+
   return st;
 }
 
@@ -667,6 +685,9 @@ svn_client__create_status(svn_client_sta
         (*cst)->node_status = svn_wc_status_conflicted;
     }
 
+  (*cst)->moved_from_abspath = status->moved_from_abspath;
+  (*cst)->moved_to_abspath = status->moved_to_abspath;
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/revprop-packing/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_fs_fs/tree.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_fs_fs/tree.c Wed Aug 24 15:16:50 2011
@@ -2925,7 +2925,7 @@ prev_location(const char **prev_path,
               const char *path,
               apr_pool_t *pool)
 {
-  const char *copy_path, *copy_src_path, *remainder = "";
+  const char *copy_path, *copy_src_path, *remainder_path = "";
   svn_fs_root_t *copy_root;
   svn_revnum_t copy_src_rev;
 
@@ -2955,8 +2955,8 @@ prev_location(const char **prev_path,
   SVN_ERR(fs_copied_from(&copy_src_rev, &copy_src_path,
                          copy_root, copy_path, pool));
   if (strcmp(copy_path, path) != 0)
-    remainder = svn_relpath__is_child(copy_path, path, pool);
-  *prev_path = svn_fspath__join(copy_src_path, remainder, pool);
+    remainder_path = svn_relpath__is_child(copy_path, path, pool);
+  *prev_path = svn_fspath__join(copy_src_path, remainder_path, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;
 }
@@ -3184,7 +3184,7 @@ history_prev(void *baton, apr_pool_t *po
 
   if (copyroot_rev > commit_rev)
     {
-      const char *remainder;
+      const char *remainder_path;
       const char *copy_dst, *copy_src;
       svn_fs_root_t *copyroot_root;
 
@@ -3202,11 +3202,11 @@ history_prev(void *baton, apr_pool_t *po
          one of these other criteria ... ### for now just fallback to
          the old copy hunt algorithm. */
       if (strcmp(path, copy_dst) == 0)
-        remainder = "";
+        remainder_path = "";
       else
-        remainder = svn_relpath__is_child(copy_dst, path, pool);
+        remainder_path = svn_relpath__is_child(copy_dst, path, pool);
 
-      if (remainder)
+      if (remainder_path)
         {
           /* If we get here, then our current path is the destination
              of, or the child of the destination of, a copy.  Fill
@@ -3215,7 +3215,7 @@ history_prev(void *baton, apr_pool_t *po
           SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copy_src, node, pool));
 
           dst_rev = copyroot_rev;
-          src_path = svn_fspath__join(copy_src, remainder, pool);
+          src_path = svn_fspath__join(copy_src, remainder_path, pool);
         }
     }
 

Modified: subversion/branches/revprop-packing/subversion/libsvn_ra_neon/fetch.c
URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_ra_neon/fetch.c?rev=1161147&r1=1161146&r2=1161147&view=diff
==============================================================================
--- subversion/branches/revprop-packing/subversion/libsvn_ra_neon/fetch.c (original)
+++ subversion/branches/revprop-packing/subversion/libsvn_ra_neon/fetch.c Wed Aug 24 15:16:50 2011
@@ -528,7 +528,10 @@ static svn_error_t *simple_fetch_file(sv
                              TRUE, pool));
 
   /* close the handler, since the file reading completed successfully. */
-  return (*frc.handler)(NULL, frc.handler_baton);
+  if (frc.stream)
+    return svn_stream_close(frc.stream);
+  else
+    return (*frc.handler)(NULL, frc.handler_baton);
 }
 
 /* Helper for svn_ra_neon__get_file.  This implements



Mime
View raw message