subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From phi...@apache.org
Subject svn commit: r1209521 [1/2] - in /subversion/branches/moves-scan-log: ./ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/tigris/sub...
Date Fri, 02 Dec 2011 14:59:01 GMT
Author: philip
Date: Fri Dec  2 14:59:00 2011
New Revision: 1209521

URL: http://svn.apache.org/viewvc?rev=1209521&view=rev
Log:
Sync the moves-scan-log branch with trunk@r1209517.

Added:
    subversion/branches/moves-scan-log/tools/server-side/mod_dontdothat/   (props changed)
      - copied from r1209517, subversion/trunk/tools/server-side/mod_dontdothat/
Removed:
    subversion/branches/moves-scan-log/contrib/server-side/mod_dontdothat/
Modified:
    subversion/branches/moves-scan-log/   (props changed)
    subversion/branches/moves-scan-log/CHANGES
    subversion/branches/moves-scan-log/build.conf
    subversion/branches/moves-scan-log/contrib/client-side/emacs/vc-svn.el
    subversion/branches/moves-scan-log/notes/repos-dictated-config
    subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
    subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/BasicTests.java
    subversion/branches/moves-scan-log/subversion/include/private/svn_wc_private.h
    subversion/branches/moves-scan-log/subversion/libsvn_client/diff.c
    subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c
    subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.c
    subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.h
    subversion/branches/moves-scan-log/subversion/libsvn_client/patch.c
    subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c
    subversion/branches/moves-scan-log/subversion/libsvn_diff/parse-diff.c
    subversion/branches/moves-scan-log/subversion/libsvn_fs_base/reps-strings.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/questions.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/util.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/wc.h
    subversion/branches/moves-scan-log/subversion/libsvn_wc/wc_db.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/wc_db.h
    subversion/branches/moves-scan-log/subversion/libsvn_wc/wc_db_pristine.c
    subversion/branches/moves-scan-log/subversion/libsvn_wc/workqueue.c
    subversion/branches/moves-scan-log/subversion/svn/main.c
    subversion/branches/moves-scan-log/subversion/svnlook/main.c
    subversion/branches/moves-scan-log/subversion/tests/cmdline/copy_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/depth_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/diff_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
    subversion/branches/moves-scan-log/subversion/tests/cmdline/merge_authz_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/merge_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/patch_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/special_tests.py
    subversion/branches/moves-scan-log/subversion/tests/cmdline/stat_tests.py
    subversion/branches/moves-scan-log/subversion/tests/libsvn_client/client-test.c
    subversion/branches/moves-scan-log/subversion/tests/libsvn_diff/parse-diff-test.c
    subversion/branches/moves-scan-log/subversion/tests/libsvn_wc/db-test.c
    subversion/branches/moves-scan-log/subversion/tests/libsvn_wc/op-depth-test.c

Propchange: subversion/branches/moves-scan-log/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Dec  2 14:59:00 2011
@@ -57,4 +57,4 @@
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
 /subversion/branches/uris-as-urls:1060426-1064427
-/subversion/trunk:1186288-1205966
+/subversion/trunk:1186288-1209517

Modified: subversion/branches/moves-scan-log/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/CHANGES?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/CHANGES (original)
+++ subversion/branches/moves-scan-log/CHANGES Fri Dec  2 14:59:00 2011
@@ -34,7 +34,7 @@ http://svn.apache.org/repos/asf/subversi
 
 
 Version 1.7.2
-(?? ??? 2011, from /branches/1.7.x)
+(02 Dec 2011, from /branches/1.7.x)
 http://svn.apache.org/repos/asf/subversion/tags/1.7.2
 
   User-visible changes:
@@ -52,8 +52,14 @@ http://svn.apache.org/repos/asf/subversi
    * fix nested <Location>s when using v2 protocol (r1203546, -651, -653)
    * make mod_dav_svn ignore non-Subversion POST requests (r1187695)
    * avoid reading freed memory (r1204478)
-   * recognize empty (only byte order mark) UTF-8 files as text (issue #4046)
-   * improve behavior when operating against a 1.0.x server (r1199876)
+   * recognize empty (only byte order mark) UTF-8 files as text (issue #4064)
+   * fix 1.7 client regression when operating against a 1.0.x server (r1199876)
+   * remove empty parent dirs of removed externals on update (issue #4044)
+   * make 'svn diff -c N' work for files added in rN (issue #2873)
+   * plug a memory leak in the bdb backend (r1205726)
+   * fix 'svn import' with native eol-style and inconsistent EOLs (r1205193)
+   * fix reading beyond the end of a string in bdb backend (r1205839, -48)
+   * don't assert when committing an incomplete directory (issue #4042)
 
   Developer-visible changes:
    * JavaHL: allow 'status -u' to function properly (r1189190, -395)
@@ -61,6 +67,7 @@ http://svn.apache.org/repos/asf/subversi
    * properly define WIN64 on Windows x64 builds (r1188609)
    * better adherence to C89 in enum definitions (r1189665)
    * bump copyright year in Windows DLLs (r1189261)
+   * log a better error when opening rep-cache.db fails (r1204610, -73)
 
 
 Version 1.7.1

Modified: subversion/branches/moves-scan-log/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/build.conf?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/build.conf (original)
+++ subversion/branches/moves-scan-log/build.conf Fri Dec  2 14:59:00 2011
@@ -362,6 +362,15 @@ libs = libsvn_repos libsvn_subr
 install = apache-mod
 msvc-libs = libhttpd.lib
 
+[mod_dontdothat]
+description = Apache Httpd module to block certain kinds of Apache Subversion requests
+type = apache-mod
+path = tools/server-side/mod_dontdothat
+nonlibs = mod_dav_svn apr aprutil
+libs = libsvn_subr
+install = apache-mod
+msvc-libs = libhttpd.lib
+
 # ----------------------------------------------------------------------------
 #
 # CONSTRUCTED HEADERS
@@ -1121,7 +1130,7 @@ type = project
 path = build/win32
 libs = svn svnadmin svndumpfilter svnlook svnmucc svnserve svnrdump svnsync
        svnversion
-       mod_authz_svn mod_dav_svn
+       mod_authz_svn mod_dav_svn mod_dontdothat
        svnauthz-validate svnraisetreeconflict
 
 [__ALL_TESTS__]

Modified: subversion/branches/moves-scan-log/contrib/client-side/emacs/vc-svn.el
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/contrib/client-side/emacs/vc-svn.el?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/contrib/client-side/emacs/vc-svn.el (original)
+++ subversion/branches/moves-scan-log/contrib/client-side/emacs/vc-svn.el Fri Dec  2 14:59:00 2011
@@ -3,18 +3,28 @@
 
 ;;; #########################################################################
 ;;; ##                                                                     ##
-;;; ##          NOTE: THIS IS NOT THE MASTER VERSION OF VC-SVN.EL          ##
+;;; ##                NOTE: THIS FILE IS ONLY FOR EMACS 21                 ##
 ;;; ##                                                                     ##
-;;; ## The canonical vc-svn.el now lives in the FSF Emacs tree, at         ##
-;;; ## http://savannah.gnu.org/cgi-bin/viewcvs/emacs/emacs/lisp/vc-svn.el. ##
-;;; ## The version here is maintained only because it is compatible with   ##
-;;; ## older releases of Emacs, since (as of this writing) the one in the  ##
-;;; ## FSF tree hasn't made it into an official release of Emacs yet.      ##
-;;; ## Eventually it will, though, and sometime after that the version     ##
-;;; ## here will go away.                                                  ##
+;;; ## Emacs 21 does not come with a working vc-mode for Subversion, and   ##
+;;; ## in particular, dsvn.el needs one. This file is provided for those   ##
+;;; ## who use that Emacs version.					   ##
 ;;; ##                                                                     ##
+;;; ## Emacs 22 and newer versions come with a Subversion-capable vc-mode  ##
+;;; ## and should not use this file.					   ##
+;;; ##									   ##
+;;; ## This file is a mild fork of vc-svn.el from the Emacs source tree.   ##
+;;; ## It may go away at some undetermined point in the future, when	   ##
+;;; ## support of Emacs 21 becomes completely irrelevant.		   ##
+;;; ## 									   ##
+;;; ## Maintenance of the vc-mode for Subversion should be done first and  ##
+;;; ## foremost in the Emacs tree, and changes done to this file only	   ##
+;;; ## when necessary.							   ##
+;;; ## 									   ##
 ;;; #########################################################################
 
+(if (> emacs-major-version 21)
+    (error "This file should only be used by Emacs versions 21 and earlier"))
+
 ;;; Writing this back end has shown up some problems in VC: bugs,
 ;;; shortcomings in the back end interface, and so on.  But I want to
 ;;; first produce code that Subversion users can use with an already

Modified: subversion/branches/moves-scan-log/notes/repos-dictated-config
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/notes/repos-dictated-config?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/notes/repos-dictated-config (original)
+++ subversion/branches/moves-scan-log/notes/repos-dictated-config Fri Dec  2 14:59:00 2011
@@ -1,58 +1,2 @@
-Some thoughts on repository-dictated configuration
-
-Introduction
-============
-Many software development shops of non-trivial size desire to have an enforce
-a uniform configuration environment among the various clients which commit
-to their repositories.  Although these shops may have the ability to control
-the environment on the client machines (dictating software versions, etc),
-relying upon the client for setting various configuration parameters can
-be time-consuming and problematic.
-
-Subversion already provides the means of enforcing much (but not all) of this
-configuration through the hook script mechanism.  What our users desire is
-some way of having the server dictate a default or recommended configuration
-to clients.  The parameters of interest typically come from the standard
-client-side config: things like global-excludes or auto-props.  Allowing the
-administrator to store a default config on the server, which then gets pushed
-to the clients, would save both time and frustration.
-
-
-Behavioral specification
-========================
-The high-level behavior for repository-dictated configuration is relatively
-simple: the repository maintains a list of configuration parameters and
-values, and upon request, provides these to the client who then applies them
-appropriately.
-
-It should be noted that the configuration the server dictates is only a
-*suggestion* to the client.  Clients may choose to override the suggestion
-with a configuration of their own, so appropriate server-side enforcement
-(often via hook scripts) is still recommended.
-
-
-Server-client transmission mechanism
-====================================
-As part of the OPTIONS request, the client will send to the server the 
-sha1 hash of the version of the server-dictated config that it current has
-cached.  If the server has a different version, it will send that to the
-client in the OPTIONS response.
-
-
-Server-side storage
-===================
-[TODO]
-
-
-Client-side storage
-===================
-The client current maintains a global configuration file in
-~/.subversion/config  This feature will introduce the ~/.subversion/repos/
-directory, which will hold additional subdirectories keyed on the UUID of the
-repository.  It is in this subdirectory that the cached version of the
-repository configuration will be stored.
-
-
-Configuration Hierarchy
-=======================
-[TODO]
+[  The contents and further evolution of this document have been moved to  ]
+[  http://wiki.apache.org/subversion/ServerDictatedConfiguration           ]

Modified: subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original)
+++ subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Fri Dec  2 14:59:00 2011
@@ -2737,7 +2737,7 @@ public class BasicTests extends SVNTests
             "## -0,0 +1 ##" + NL +
             "+Test property value." + NL;
 
-        setprop(aPath, "testprop", "Test property value.");
+        setprop(aPath, "testprop", "Test property value." + NL);
         client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, wcPath,
                     diffOutput.getPath(), Depth.infinity, null, true, true,
                     false, false);
@@ -2755,7 +2755,7 @@ public class BasicTests extends SVNTests
             "## -0,0 +1 ##" + NL +
             "+Test property value." + NL;
 
-        setprop(aPath, "testprop", "Test property value.");
+        setprop(aPath, "testprop", "Test property value." + NL);
         client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, aPath,
                     diffOutput.getPath(), Depth.infinity, null, true, true,
                     false, false);

Modified: subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/BasicTests.java?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/BasicTests.java (original)
+++ subversion/branches/moves-scan-log/subversion/bindings/javahl/tests/org/tigris/subversion/javahl/BasicTests.java Fri Dec  2 14:59:00 2011
@@ -2674,7 +2674,8 @@ public class BasicTests extends SVNTests
             "## -0,0 +1 ##" + NL +
             "+Test property value." + NL;
 
-        client.propertySet(aPath, "testprop", "Test property value.", false);
+        client.propertySet(aPath, "testprop", "Test property value." + NL,
+                           false);
         client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, wcPath,
                     diffOutput.getPath(), Depth.infinity, null, true, true,
                     false);
@@ -2692,7 +2693,8 @@ public class BasicTests extends SVNTests
             "## -0,0 +1 ##" + NL +
             "+Test property value." + NL;
 
-        client.propertySet(aPath, "testprop", "Test property value.", false);
+        client.propertySet(aPath, "testprop", "Test property value." + NL,
+                           false);
         client.diff(aPath, Revision.BASE, aPath, Revision.WORKING, aPath,
                     diffOutput.getPath(), Depth.infinity, null, true, true,
                     false);

Modified: subversion/branches/moves-scan-log/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/include/private/svn_wc_private.h?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/moves-scan-log/subversion/include/private/svn_wc_private.h Fri Dec  2 14:59:00 2011
@@ -947,19 +947,6 @@ svn_wc__min_max_revisions(svn_revnum_t *
                           svn_boolean_t committed,
                           apr_pool_t *scratch_pool);
 
-/* Indicate in @a *is_sparse_checkout whether any of the nodes within
- * @a local_abspath is sparse, using context @a wc_ctx.
- * Use @a scratch_pool for temporary allocations.
- *
- * This function provides a subset of the functionality of
- * svn_wc_revision_status2() and is more efficient if the caller
- * doesn't need all information returned by svn_wc_revision_status2(). */
-svn_error_t *
-svn_wc__is_sparse_checkout(svn_boolean_t *is_sparse_checkout,
-                           svn_wc_context_t *wc_ctx,
-                           const char *local_abspath,
-                           apr_pool_t *scratch_pool);
-
 /* Indicate in @a is_switched whether any node beneath @a local_abspath
  * is switched, using context @a wc_ctx.
  * Use @a scratch_pool for temporary allocations.

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/diff.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/diff.c Fri Dec  2 14:59:00 2011
@@ -147,18 +147,25 @@ display_mergeinfo_diff(const char *old_m
    If TOKEN is empty, or is already terminated by an EOL marker,
    return TOKEN unmodified. Else, return a new string consisting
    of the concatenation of TOKEN and the system's default EOL marker.
-   The new string is allocated from POOL. */
+   The new string is allocated from POOL.
+   If HAD_EOL is not NULL, indicate in *HAD_EOL if the token had a EOL. */
 static const svn_string_t *
-maybe_append_eol(const svn_string_t *token, apr_pool_t *pool)
+maybe_append_eol(const svn_string_t *token, svn_boolean_t *had_eol,
+                 apr_pool_t *pool)
 {
   const char *curp;
 
+  if (had_eol)
+    *had_eol = FALSE;
+
   if (token->len == 0)
     return token;
 
   curp = token->data + token->len - 1;
   if (*curp == '\r')
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
   else if (*curp != '\n')
@@ -167,6 +174,8 @@ maybe_append_eol(const svn_string_t *tok
     }
   else
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
 }
@@ -665,18 +674,19 @@ display_prop_diffs(const apr_array_heade
         const svn_string_t *tmp;
         const svn_string_t *orig;
         const svn_string_t *val;
+        svn_boolean_t val_has_eol;
 
         /* The last character in a property is often not a newline.
-           Since the diff is not useful anyway for patching properties an
-           eol character is appended when needed to remove those pescious
-           ' \ No newline at end of file' lines. */
+           An eol character is appended to prevent the diff API to add a
+           ' \ No newline at end of file' line. We add 
+           ' \ No newline at end of property' manually if needed. */
         tmp = original_value ? original_value 
                              : svn_string_create_empty(iterpool);
-        orig = maybe_append_eol(tmp, iterpool);
+        orig = maybe_append_eol(tmp, NULL, iterpool);
 
         tmp = propchange->value ? propchange->value :
                                   svn_string_create_empty(iterpool);
-        val = maybe_append_eol(tmp, iterpool);
+        val = maybe_append_eol(tmp, &val_has_eol, iterpool);
 
         SVN_ERR(svn_diff_mem_string_diff(&diff, orig, val, &options,
                                          iterpool));
@@ -695,7 +705,12 @@ display_prop_diffs(const apr_array_heade
                                            svn_dirent_local_style(path,
                                                                   iterpool),
                                            encoding, orig, val, iterpool));
-
+        if (!val_has_eol)
+          {
+            const char *s = "\\ No newline at end of property" APR_EOL_STR;
+            apr_size_t len = strlen(s);
+            SVN_ERR(svn_stream_write(outstream, s, &len));
+          }
       }
     }
   svn_pool_destroy(iterpool);

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c Fri Dec  2 14:59:00 2011
@@ -1315,8 +1315,8 @@ typedef struct conflict_resolver_baton_t
      resolution attempt was made. */
   apr_hash_t **conflicted_paths;
 
-  /* Pool used in notification_receiver() to avoid the iteration
-     sub-pool which is passed in, then subsequently destroyed. */
+  /* Pool with a sufficient lifetime to be used for output members such as
+   * *CONFLICTED_PATHS. */
   apr_pool_t *pool;
 } conflict_resolver_baton_t;
 
@@ -2682,8 +2682,8 @@ typedef struct notification_receiver_bat
   /* We use this to make a decision on merge begin line notifications. */
   merge_cmd_baton_t *merge_b;
 
-  /* Pool used in notification_receiver() to avoid the iteration
-     sub-pool which is passed in, then subsequently destroyed. */
+  /* Pool with a sufficient lifetime to be used for output members such as
+   * MERGED_ABSPATHS. */
   apr_pool_t *pool;
 
 } notification_receiver_baton_t;
@@ -2724,6 +2724,79 @@ find_nearest_ancestor(const apr_array_he
 }
 
 
+/* Notify that we're starting to record the merge of the
+ * revision range RANGE into TARGET_ABSPATH.  RANGE should be null if the
+ * merge sources are not from the same URL.
+ *
+ * This calls the client's notification receiver (as found in the client
+ * context), with a WC abspath.
+ */
+static void
+notify_merge_begin(const char *target_abspath,
+                   const svn_merge_range_t *range,
+                   merge_cmd_baton_t *merge_b,
+                   apr_pool_t *pool)
+{
+  if (merge_b->ctx->notify_func2)
+    {
+      svn_wc_notify_t *n
+        = svn_wc_create_notify(target_abspath,
+                               merge_b->same_repos
+                               ? svn_wc_notify_merge_begin
+                               : svn_wc_notify_foreign_merge_begin,
+                               pool);
+
+      n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL;
+      merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, n, pool);
+    }
+}
+
+/* Notify that we're starting to record mergeinfo for the merge of the
+ * revision range RANGE into TARGET_ABSPATH.  RANGE should be null if the
+ * merge sources are not from the same URL.
+ *
+ * This calls the client's notification receiver (as found in the client
+ * context), with a WC abspath.
+ */
+static void
+notify_mergeinfo_recording(const char *target_abspath,
+                           const svn_merge_range_t *range,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *pool)
+{
+  if (ctx->notify_func2)
+    {
+      svn_wc_notify_t *n = svn_wc_create_notify(
+        target_abspath, svn_wc_notify_merge_record_info_begin, pool);
+
+      n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL;
+      ctx->notify_func2(ctx->notify_baton2, n, pool);
+    }
+}
+
+/* Notify that we're completing the merge into TARGET_ABSPATH.
+ *
+ * This calls the client's notification receiver (as found in the client
+ * context), with a WC abspath.
+ */
+static void
+notify_merge_completed(const char *target_abspath,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *pool)
+{
+  if (ctx->notify_func2)
+    {
+      svn_wc_notify_t *n
+        = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed,
+                               pool);
+      n->kind = svn_node_none;
+      n->content_state = n->prop_state = svn_wc_notify_state_inapplicable;
+      n->lock_state = svn_wc_notify_lock_state_inapplicable;
+      n->revision = SVN_INVALID_REVNUM;
+      ctx->notify_func2(ctx->notify_baton2, n, pool);
+    }
+}
+
 /* Is the notification the result of a real operative merge? */
 #define IS_OPERATIVE_NOTIFICATION(notify)  \
                     (notify->content_state == svn_wc_notify_state_conflicted \
@@ -2735,7 +2808,20 @@ find_nearest_ancestor(const apr_array_he
                      || notify->action == svn_wc_notify_update_add \
                      || notify->action == svn_wc_notify_tree_conflict)
 
-/* Our svn_wc_notify_func2_t wrapper.*/
+/* Handle a diff notification by calling the client's notification callback
+ * and also by recording which paths changed (in BATON->*_abspaths).
+ *
+ * In some cases, notify that a merge is beginning, if we haven't already
+ * done so.  (### TODO: Harmonize this so it handles all cases.)
+ *
+ * The paths in NOTIFY are relpaths, relative to the root of the diff (the
+ * merge source). We convert these to abspaths in the merge target WC before
+ * passing the notification structure on to the client.
+ *
+ * This function is not used for 'starting a merge', 'starting to record
+ * mergeinfo' and 'completing a merge' notifications.
+ *
+ * Implements svn_wc_notify_func2_t.*/
 static void
 notification_receiver(void *baton, const svn_wc_notify_t *notify,
                       apr_pool_t *pool)
@@ -2749,8 +2835,7 @@ notification_receiver(void *baton, const
      We will already have skipped the actual addition or deletion, but will
      still get a notification callback for it. */
   if (notify_b->merge_b->record_only
-      && (notify->action != svn_wc_notify_update_update
-          && notify->action != svn_wc_notify_merge_record_info_begin))
+      && notify->action != svn_wc_notify_update_update)
     return;
 
   if (is_operative_notification)
@@ -2909,19 +2994,10 @@ notification_receiver(void *baton, const
                         * non-null earlier in this expression. See r872890. */
                        && child->remaining_ranges == 0))
                 {
-                  svn_wc_notify_t *notify_merge_begin;
-                  notify_merge_begin =
-                    svn_wc_create_notify(child->abspath,
-                                         notify_b->merge_b->same_repos
-                                           ? svn_wc_notify_merge_begin
-                                           : svn_wc_notify_foreign_merge_begin,
-                                         pool);
-                  notify_merge_begin->merge_range =
-                    APR_ARRAY_IDX(child->remaining_ranges, 0,
-                                  svn_merge_range_t *);
-                  if (notify_b->wrapped_func)
-                    (*notify_b->wrapped_func)(notify_b->wrapped_baton,
-                                              notify_merge_begin, pool);
+                  notify_merge_begin(child->abspath,
+                                     APR_ARRAY_IDX(child->remaining_ranges, 0,
+                                                   svn_merge_range_t *),
+                                     notify_b->merge_b, pool);
                 }
             }
         }
@@ -2931,16 +3007,8 @@ notification_receiver(void *baton, const
            && notify_b->nbr_operative_notifications == 1
            && is_operative_notification)
     {
-      svn_wc_notify_t *notify_merge_begin;
-      notify_merge_begin =
-        svn_wc_create_notify(notify_b->merge_b->target_abspath,
-                             notify_b->merge_b->same_repos
-                               ? svn_wc_notify_merge_begin
-                               : svn_wc_notify_foreign_merge_begin,
-                             pool);
-      if (notify_b->wrapped_func)
-        (*notify_b->wrapped_func)(notify_b->wrapped_baton, notify_merge_begin,
-                                  pool);
+      notify_merge_begin(notify_b->merge_b->target_abspath, NULL,
+                         notify_b->merge_b, pool);
     }
 
   if (notify_b->wrapped_func)
@@ -4460,9 +4528,9 @@ 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.  Set
-   *RANGELIST_INHERITANCE to the inheritability set.
+   Set *NON_INHERITABLE to TRUE if non-inheritable mergeinfo is needed to
+   describe a merge into LOCAL_ABSPATH at DEPTH.  Set *NON_INHERTIABLE to
+   FALSE otherwise.
 
    WC_PATH_IS_MERGE_TARGET is true if WC_PATH is the target of the merge,
    otherwise WC_PATH is a subtree.
@@ -4473,8 +4541,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,
+calculate_merge_inheritance(svn_boolean_t *non_inheritable,
                             const char *local_abspath,
                             svn_boolean_t wc_path_is_merge_target,
                             svn_boolean_t wc_path_has_missing_child,
@@ -4488,14 +4555,10 @@ calculate_merge_inheritance(apr_array_he
                            scratch_pool));
 
   /* Starting assumption. */
-  *rangelist_inheritance = TRUE;
+  *non_inheritable = FALSE;
 
-  if (path_kind == svn_node_file)
-    {
-      /* Files *never* have non-inheritable mergeinfo. */
-      svn_rangelist__set_inheritance(rangelist, TRUE);
-    }
-  else if (path_kind == svn_node_dir)
+  /* Only directories can have non-inheritable mergeinfo. */
+  if (path_kind == svn_node_dir)
     {
       if (wc_path_is_merge_target)
         {
@@ -4503,12 +4566,7 @@ calculate_merge_inheritance(apr_array_he
               || depth == svn_depth_files
               || depth == svn_depth_empty)
             {
-              svn_rangelist__set_inheritance(rangelist, FALSE);
-              *rangelist_inheritance = FALSE;
-            }
-          else /* depth == svn_depth_files || depth == svn_depth_empty */
-            {
-              svn_rangelist__set_inheritance(rangelist, TRUE);
+              *non_inheritable = TRUE;
             }
         }
       else /* WC_PATH is a directory subtree of the target. */
@@ -4516,12 +4574,7 @@ calculate_merge_inheritance(apr_array_he
           if (wc_path_has_missing_child
               || depth == svn_depth_immediates)
             {
-              svn_rangelist__set_inheritance(rangelist, FALSE);
-              *rangelist_inheritance = FALSE;
-            }
-          else /* depth == infinity */
-            {
-              svn_rangelist__set_inheritance(rangelist, TRUE);
+              *non_inheritable = TRUE;
             }
         }
     }
@@ -4678,11 +4731,11 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
 
    Record override mergeinfo on any paths skipped during a merge.
 
-   Set empty mergeinfo on each path in NOTIFY_B->SKIPPED_ABSPATHS so the path
+   Set empty mergeinfo on each path in SKIPPED_ABSPATHS so the path
    does not incorrectly inherit mergeinfo that will later be describing
    the merge.
 
-   MERGEINFO_PATH, NOTIFY_B, and MERGE_B are all cascaded from
+   MERGEINFO_PATH and MERGE_B are cascaded from
    arguments of the same name in the caller.
 
    IS_ROLLBACK is true if the caller is recording a reverse merge and false
@@ -4692,14 +4745,14 @@ static svn_error_t *
 record_skips(const char *mergeinfo_path,
              const apr_array_header_t *rangelist,
              svn_boolean_t is_rollback,
-             notification_receiver_baton_t *notify_b,
+             apr_hash_t *skipped_abspaths,
              merge_cmd_baton_t *merge_b,
              apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
   apr_hash_t *merges;
-  apr_size_t nbr_skips = (notify_b->skipped_abspaths != NULL ?
-                          apr_hash_count(notify_b->skipped_abspaths) : 0);
+  apr_size_t nbr_skips = (skipped_abspaths != NULL ?
+                          apr_hash_count(skipped_abspaths) : 0);
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   if (nbr_skips == 0)
@@ -4708,7 +4761,7 @@ record_skips(const char *mergeinfo_path,
   merges = apr_hash_make(scratch_pool);
 
   /* Override the mergeinfo for child paths which weren't actually merged. */
-  for (hi = apr_hash_first(scratch_pool, notify_b->skipped_abspaths); hi;
+  for (hi = apr_hash_first(scratch_pool, skipped_abspaths); hi;
        hi = apr_hash_next(hi))
     {
       const char *skipped_abspath = svn__apr_hash_index_key(hi);
@@ -5277,31 +5330,30 @@ single_file_merge_get_file(const char **
 /* Send a notification specific to a single-file merge if the states
    indicate there's something worth reporting.
 
-   If *HEADER_SENT is not set and HEADER_NOTIFICATION is not NULL, then
-   send the header notification before sending the state notification,
-   and set *HEADER_SENT to TRUE. */
+   If *HEADER_SENT is not set, then send a header notification for range R
+   before sending the state notification, and set *HEADER_SENT to TRUE. */
 static APR_INLINE void
 single_file_merge_notify(notification_receiver_baton_t *notify_baton,
-                         const char *local_abspath,
+                         const char *target_relpath,
                          svn_wc_notify_action_t action,
                          svn_wc_notify_state_t text_state,
                          svn_wc_notify_state_t prop_state,
-                         svn_wc_notify_t *header_notification,
+                         const svn_merge_range_t *r,
                          svn_boolean_t *header_sent,
                          apr_pool_t *pool)
 {
-  svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath, action, pool);
+  svn_wc_notify_t *notify = svn_wc_create_notify(target_relpath, action, pool);
   notify->kind = svn_node_file;
   notify->content_state = text_state;
   notify->prop_state = prop_state;
   if (notify->content_state == svn_wc_notify_state_missing)
     notify->action = svn_wc_notify_skip;
 
-  if (IS_OPERATIVE_NOTIFICATION(notify)
-      && header_notification
-      && (! *header_sent))
+  if (IS_OPERATIVE_NOTIFICATION(notify) && (! *header_sent))
     {
-      notification_receiver(notify_baton, header_notification, pool);
+      notify_merge_begin(notify_baton->merge_b->target_abspath,
+                         (notify_baton->merge_b->sources_ancestral ? r : NULL),
+                         notify_baton->merge_b, pool);
       *header_sent = TRUE;
     }
   notification_receiver(notify_baton, notify, pool);
@@ -5414,13 +5466,15 @@ insert_parent_and_sibs_of_sw_absent_del_
   parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath);
   if (parent)
     {
-      parent->missing_child = TRUE;
+      parent->missing_child = child->absent;
+      parent->switched_child = child->switched;
     }
   else
     {
       /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */
       parent = svn_client__merge_path_create(parent_abspath, pool);
-      parent->missing_child = TRUE;
+      parent->missing_child = child->absent;
+      parent->switched_child = child->switched;
       /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
       insert_child_to_merge(children_with_mergeinfo, parent, pool);
       /* Increment for loop index so we don't process the inserted element. */
@@ -6823,7 +6877,6 @@ do_file_merge(svn_mergeinfo_catalog_t re
         {
           svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, i,
                                                svn_merge_range_t *);
-          svn_wc_notify_t *n;
           svn_boolean_t header_sent = FALSE;
           svn_ra_session_t *ra_session1, *ra_session2;
           const char *tmpfile1, *tmpfile2;
@@ -6836,14 +6889,6 @@ do_file_merge(svn_mergeinfo_catalog_t re
 
           svn_pool_clear(iterpool);
 
-          n = svn_wc_create_notify(target_relpath,
-                                   merge_b->same_repos
-                                     ? svn_wc_notify_merge_begin
-                                     : svn_wc_notify_foreign_merge_begin,
-                                   iterpool);
-          if (merge_b->sources_ancestral)
-            n->merge_range = r;
-
           /* Issue #3174: If we are honoring mergeinfo, then URL1, URL2,
              REVISION1, and REVISION2 meet the conditions described in
              'MERGEINFO MERGE SOURCE NORMALIZATION'.  This means that
@@ -6904,7 +6949,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                          ? svn_wc_notify_tree_conflict
                                          : svn_wc_notify_update_delete,
                                        text_state, svn_wc_notify_state_unknown,
-                                       n, &header_sent, iterpool);
+                                       r, &header_sent, iterpool);
 
               /* ...plus add... */
               SVN_ERR(merge_file_added(&text_state, &prop_state,
@@ -6920,8 +6965,8 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                        tree_conflicted
                                          ? svn_wc_notify_tree_conflict
                                          : svn_wc_notify_update_add,
-                                       text_state, prop_state, n,
-                                       &header_sent, iterpool);
+                                       text_state, prop_state,
+                                       r, &header_sent, iterpool);
               /* ... equals replace. */
             }
           else
@@ -6938,8 +6983,8 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                        tree_conflicted
                                          ? svn_wc_notify_tree_conflict
                                          : svn_wc_notify_update_update,
-                                       text_state, prop_state, n,
-                                       &header_sent, iterpool);
+                                       text_state, prop_state,
+                                       r, &header_sent, iterpool);
             }
 
           /* Ignore if temporary file not found. It may have been renamed. */
@@ -6998,22 +7043,13 @@ do_file_merge(svn_mergeinfo_catalog_t re
           if (!squelch_mergeinfo_notifications)
             {
               /* Notify that we are recording mergeinfo describing a merge. */
-              svn_wc_notify_t *notify = svn_wc_create_notify(
-                target_abspath, svn_wc_notify_merge_record_info_begin,
-                iterpool);
-              svn_revnum_t youngest_rev;
-              svn_revnum_t oldest_rev;
-              SVN_ERR(svn_mergeinfo__get_range_endpoints(&youngest_rev,
-                                                         &oldest_rev,
-                                                         merges,
-                                                         iterpool));
-              notify->merge_range = apr_pcalloc(iterpool,
-                                                sizeof(svn_merge_range_t));
-              notify->merge_range->start = oldest_rev;
-              notify->merge_range->end = youngest_rev;
-              notify->merge_range->inheritable = TRUE;
-              merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
-                                         notify, iterpool);
+              svn_merge_range_t n_range;
+
+              SVN_ERR(svn_mergeinfo__get_range_endpoints(
+                        &n_range.end, &n_range.start, merges, iterpool));
+              n_range.inheritable = TRUE;
+              notify_mergeinfo_recording(target_abspath, &n_range,
+                                         merge_b->ctx, iterpool);
             }
 
           SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath,
@@ -7264,6 +7300,11 @@ log_find_operative_subtree_revs(void *ba
   apr_hash_t *immediate_children = baton;
   apr_hash_index_t *hi, *hi2;
 
+  /* It's possible that authz restrictions on the merge source prevent us
+     from knowing about any of the changes for LOG_ENTRY->REVISION. */
+  if (!log_entry->changed_paths2)
+    return SVN_NO_ERROR;
+
   for (hi = apr_hash_first(pool, log_entry->changed_paths2);
        hi;
        hi = apr_hash_next(hi))
@@ -7372,6 +7413,202 @@ get_inoperative_immediate_children(apr_h
   return SVN_NO_ERROR;
 }
 
+/* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of
+   NOTIFY_B->CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately
+   describe a merge, what inheritance type such new mergeinfo should have,
+   and what subtrees can be ignored altogether.
+
+   For each svn_client__merge_path_t CHILD in
+   NOTIFY_B->CHILDREN_WITH_MERGEINFO, set CHILD->RECORD_MERGEINFO and
+   CHILD->RECORD_NONINHERITABLE to true if the subtree needs mergeinfo
+   to describe the merge and if that mergeinfo should be non-inheritable
+   respectively.
+
+   If OPERATIVE_MERGE is true, then the merge being described is operative
+   as per subtree_touched_by_merge.  OPERATIVE_MERGE is false otherwise.
+
+   MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all
+   cascaded from record_mergeinfo_for_dir_merge's arguments of the same
+   names.
+
+   SCRATCH_POOL is used for temporary allocations.
+*/
+static svn_error_t *
+flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
+                                const svn_merge_range_t *merged_range,
+                                const char *mergeinfo_fspath,
+                                svn_depth_t depth,
+                                notification_receiver_baton_t *notify_b,
+                                merge_cmd_baton_t *merge_b,
+                                apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+  apr_hash_t *inoperative_immediate_children = NULL;
+
+  /* Find all issue #3642 children (i.e immediate child directories of the
+     merge target, with no pre-existing explicit mergeinfo, during a --depth
+     immediates merge).  Stash those that are inoperative at any depth in
+     INOPERATIVE_IMMEDIATE_CHILDREN. */
+  if (!merge_b->record_only
+      && merged_range->start <= merged_range->end
+      && depth == svn_depth_immediates)
+    SVN_ERR(get_inoperative_immediate_children(
+      &inoperative_immediate_children,
+      notify_b->children_with_mergeinfo,
+      mergeinfo_fspath, merged_range->start + 1, merged_range->end,
+      merge_b->target_abspath, merge_b->ra_session1,
+      scratch_pool, iterpool));
+
+  /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
+     order.  This way each child knows if it has operative missing/switched
+     children which necessitates non-inheritable mergeinfo. */
+  for (i = notify_b->children_with_mergeinfo->nelts - 1; i >= 0; i--)
+    {
+      svn_client__merge_path_t *child =
+                     APR_ARRAY_IDX(notify_b->children_with_mergeinfo, i,
+                                   svn_client__merge_path_t *);
+
+      /* Can't record mergeinfo on something that isn't here. */
+      if (child->absent)
+        continue;
+
+      /* Don't record mergeinfo on skipped paths. */
+      if (notify_b->skipped_abspaths
+          && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
+                          APR_HASH_KEY_STRING))
+        continue;
+
+      /* ### ptb: Yes, we could combine the follwing into a single
+         ### conditional, but clarity would suffer (even more than
+         ### it does now). */
+      if (i == 0)
+        {
+          /* Always record mergeinfo on the merge target. */
+          child->record_mergeinfo = TRUE;
+        }
+      else if (merge_b->record_only && !merge_b->reintegrate_merge)
+        {
+          /* Always record mergeinfo for --record-only merges. */
+          child->record_mergeinfo = TRUE;
+        }
+      else if (child->immediate_child_dir
+               && !child->pre_merge_mergeinfo
+               && inoperative_immediate_children
+               && !apr_hash_get(inoperative_immediate_children,
+                               child->abspath,
+                               APR_HASH_KEY_STRING))
+        {
+          /* We must record mergeinfo on those issue #3642 children
+             that are operative at a greater depth. */
+          child->record_mergeinfo = TRUE;
+        }
+
+      if (operative_merge)
+        {
+          svn_boolean_t child_is_deleted;
+
+          svn_pool_clear(iterpool);
+
+          /* If CHILD is deleted we don't need to set mergeinfo on it. */
+          SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
+                                                 merge_b->ctx->wc_ctx,
+                                                 child->abspath, iterpool));
+          if (!child_is_deleted
+              && subtree_touched_by_merge(child->abspath, notify_b,
+                                          iterpool))
+            {
+              /* This subtree was affected by the merge. */
+              child->record_mergeinfo = TRUE;
+
+              /* Were any CHILD's missing children skipped by the merge?
+                 If not, then CHILD's missing children don't need to be
+                 considered when recording mergeinfo describing the merge. */
+              if (!merge_b->reintegrate_merge
+                  && child->missing_child
+                  && !path_is_subtree(child->abspath,
+                                      notify_b->skipped_abspaths,
+                                      iterpool))
+                {
+                  child->missing_child = FALSE;
+                }
+
+              /* If CHILD has an immediate switched child or children and
+                 none of these were touched by the merge, then we don't need
+                 need to do any special handling of those switched subtrees
+                 (e.g. record non-inheritable mergeinfo) when recording
+                 mergeinfo desribing the merge. */
+              if (child->switched_child)
+                {
+                  int j;
+                  svn_boolean_t operative_switched_child = FALSE;
+
+                  for (j = i + 1;
+                       j < notify_b->children_with_mergeinfo->nelts;
+                       j++)
+                    {
+                      svn_client__merge_path_t *potential_child =
+                        APR_ARRAY_IDX(notify_b->children_with_mergeinfo, j,
+                                      svn_client__merge_path_t *);
+                      if (!svn_dirent_is_ancestor(child->abspath,
+                                                  potential_child->abspath))
+                        break;
+
+                      /* POTENTIAL_CHILD is a subtree of CHILD, but is it
+                         an immediate child? */
+                      if (strcmp(child->abspath,
+                                 svn_dirent_dirname(potential_child->abspath,
+                                                    iterpool)))
+                        continue;
+
+                      if (potential_child->switched
+                          && potential_child->record_mergeinfo)
+                        {
+                          operative_switched_child = TRUE;
+                          break;
+                        }
+                    }
+
+                  /* Can we treat CHILD as if it has no switched children? */
+                  if (!operative_switched_child)
+                    child->switched_child = FALSE;
+                }
+            }
+        }
+
+      if (child->record_mergeinfo)
+        {
+          SVN_ERR(calculate_merge_inheritance(&(child->record_noninheritable),
+                                              child->abspath,
+                                              i == 0,
+                                              (child->missing_child
+                                               || child->switched_child),
+                                              depth,
+                                              merge_b->ctx->wc_ctx,
+                                              iterpool));
+        }
+      else
+        {
+          /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
+             because it had no explicit mergeinfo of its own at the
+             start of the merge but is the child of of some path with
+             non-inheritable mergeinfo, then the explicit mergeinfo it
+             has *now* was set by get_mergeinfo_paths() -- see criteria
+             3 in that function's doc string.  So since CHILD->ABSPATH
+             was not touched by the merge we can remove the
+             mergeinfo. */
+          if (child->child_of_noninheritable)
+            SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
+                                                    NULL, FALSE,
+                                                    merge_b->ctx,
+                                                    iterpool));
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 /* Helper for do_directory_merge().
 
    If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
@@ -7389,6 +7626,8 @@ get_inoperative_immediate_children(apr_h
 
    DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS are all
    cascaded from do_directory_merge's arguments of the same names.
+
+   SCRATCH_POOL is used for temporary allocations.
 */
 static svn_error_t *
 record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog,
@@ -7398,24 +7637,19 @@ record_mergeinfo_for_dir_merge(svn_merge
                                svn_boolean_t squelch_mergeinfo_notifications,
                                notification_receiver_baton_t *notify_b,
                                merge_cmd_baton_t *merge_b,
-                               apr_pool_t *pool)
+                               apr_pool_t *scratch_pool)
 {
   int i;
   svn_boolean_t is_rollback = (merged_range->start > merged_range->end);
-  svn_boolean_t operative_merge = FALSE;
-  apr_hash_t *inoperative_immediate_children = NULL;
+  svn_boolean_t operative_merge;
 
   /* Update the WC mergeinfo here to account for our new
      merges, minus any unresolved conflicts and skips. */
 
   /* We need a scratch pool for iterations below. */
-  apr_pool_t *iterpool = svn_pool_create(pool);
-
-  svn_merge_range_t range;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  range.start = merged_range->start;
-  range.end = merged_range->end;
-  range.inheritable = merged_range->inheritable;
+  svn_merge_range_t range = *merged_range;
 
   /* Regardless of what subtrees in MERGE_B->TARGET_ABSPATH might be missing
      could this merge have been operative? */
@@ -7434,23 +7668,12 @@ record_mergeinfo_for_dir_merge(svn_merge
   remove_absent_children(merge_b->target_abspath,
                          notify_b->children_with_mergeinfo);
 
+  /* Determine which subtrees of interest need mergeinfo recorded... */
+  SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
+                                          mergeinfo_fspath, depth, notify_b,
+                                          merge_b, iterpool));
 
-  /* Find all issue #3642 children (i.e immediate child directories of the
-     merge target, with no pre-existing explicit mergeinfo, during a --depth
-     immediates merge).  Stash those that are inoperative at any depth in
-     INOPERATIVE_IMMEDIATE_CHILDREN. */
-  if (!merge_b->record_only && range.start <= range.end
-      && depth == svn_depth_immediates)
-    SVN_ERR(get_inoperative_immediate_children(
-      &inoperative_immediate_children,
-      notify_b->children_with_mergeinfo,
-      mergeinfo_fspath, range.start + 1, range.end,
-      merge_b->target_abspath, merge_b->ra_session1,
-      pool, iterpool));
-
-  /* Record mergeinfo on any subtree affected by the merge or for
-     every subtree if this is a --record-only merge.  Always record
-     mergeinfo on the merge target CHILDREN_WITH_MERGEINFO[0]. */
+  /* ...and then record it. */
   for (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++)
     {
       const char *child_repos_path;
@@ -7462,60 +7685,10 @@ record_mergeinfo_for_dir_merge(svn_merge
                                    svn_client__merge_path_t *);
       SVN_ERR_ASSERT(child);
 
-      /* Can't record mereginfo on something that isn't here. */
-      if (child->absent)
-        continue;
-
       svn_pool_clear(iterpool);
 
-      /* If CHILD is a subtree, this is not a record only merge, and
-         CHILD was not affected by the merge then we don't need to
-         record mergeinfo.  If this is a record only merge being done
-         as part of a reintegrate merge then we need to check if CHILD
-         was affected by the merge. */
-      if (i > 0 /* Always record mergeinfo on the merge target. */
-          && (!merge_b->record_only || merge_b->reintegrate_merge)
-          && (!child->immediate_child_dir || child->pre_merge_mergeinfo)
-          && (!operative_merge
-              || !subtree_touched_by_merge(child->abspath, notify_b,
-                                           iterpool)))
+      if (child->record_mergeinfo)
         {
-          /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
-             because it had no explicit mergeinfo of its own at the
-             start of the merge but is the child of of some path with
-             non-inheritable mergeinfo, then the explicit mergeinfo it
-             has *now* was set by get_mergeinfo_paths() -- see criteria
-             3 in that function's doc string.  So since CHILD->ABSPATH
-             was not touched by the merge we can remove the
-             mergeinfo. */
-          if (child->child_of_noninheritable)
-            {
-              SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
-                                                      NULL, FALSE,
-                                                      merge_b->ctx,
-                                                      iterpool));
-            }
-        }
-      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,
-                                                 merge_b->ctx->wc_ctx,
-                                                 child->abspath, iterpool));
-          if (child_is_deleted)
-            continue;
-
-          /* We don't need to record mergeinfo on those issue #3642 children
-             that are inoperative at any depth. */
-          if (inoperative_immediate_children
-              && apr_hash_get(inoperative_immediate_children,
-                              child->abspath,
-                             APR_HASH_KEY_STRING))
-            continue;
-
           child_repos_path = svn_dirent_skip_ancestor(merge_b->target_abspath,
                                                       child->abspath);
           SVN_ERR_ASSERT(child_repos_path != NULL);
@@ -7532,41 +7705,21 @@ record_mergeinfo_for_dir_merge(svn_merge
             continue;
 
           if (!squelch_mergeinfo_notifications)
-            {
-              svn_wc_notify_t *notify = svn_wc_create_notify(
-                child->abspath,
-                svn_wc_notify_merge_record_info_begin,
-                iterpool);
-              notify->merge_range = svn_merge_range_dup(merged_range,
-                                                        iterpool);
-              merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                                         iterpool);
-            }
+            notify_mergeinfo_recording(child->abspath, merged_range,
+                                      merge_b->ctx, iterpool);
 
           /* If we are here we know we will be recording some mergeinfo, but
-             before we do set override mergeinfo on skipped paths so they
-             don't incorrectly inherit the mergeinfo we are about to set.
-             We only need to do this once.  If we are dealing with a subtree
-             (i.e. i != 0) that was skipped then don't record mergeinfo on
-             it.  The earlier call to record_skips will already have taken
-             care of this. */
+             before we do, set override mergeinfo on skipped paths so they
+             don't incorrectly inherit the mergeinfo we are about to set. */
           if (i == 0)
-            SVN_ERR(record_skips(mergeinfo_fspath,
-                                 child_merge_rangelist,
-                                 is_rollback, notify_b, merge_b, iterpool));
-          else if (notify_b->skipped_abspaths
-                   && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
-                                   APR_HASH_KEY_STRING))
-            continue;
-
-          SVN_ERR(calculate_merge_inheritance(child_merge_rangelist,
-                                              &rangelist_inheritance,
-                                              child->abspath,
-                                              i == 0,
-                                              child->missing_child,
-                                              depth,
-                                              merge_b->ctx->wc_ctx,
-                                              iterpool));
+            SVN_ERR(record_skips(mergeinfo_fspath, child_merge_rangelist,
+                                 is_rollback, notify_b->skipped_abspaths,
+                                 merge_b, iterpool));
+
+          /* We may need to record non-inheritable mergeinfo that applies
+             only to CHILD->ABSPATH. */
+          if (child->record_noninheritable)
+            svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
 
           /* If CHILD has inherited mergeinfo set it before
              recording the first merge range. */
@@ -7674,7 +7827,7 @@ record_mergeinfo_for_dir_merge(svn_merge
                                                   child_merge_rangelist,
                                                   child_merge_src_rangelist,
                                                   FALSE, iterpool));
-                  if (!rangelist_inheritance)
+                  if (child->record_noninheritable)
                     svn_rangelist__set_inheritance(child_merge_rangelist,
                                                    FALSE);
                 }
@@ -7971,6 +8124,11 @@ log_noop_revs(void *baton,
 
   revision = log_entry->revision;
 
+  /* It's possible that authz restrictions on the merge source prevent us
+     from knowing about any of the changes for LOG_ENTRY->REVISION. */
+  if (!log_entry->changed_paths2)
+    return SVN_NO_ERROR;
+
   /* Unconditionally add LOG_ENTRY->REVISION to BATON->OPERATIVE_MERGES. */
   SVN_ERR(rangelist_merge_revision(log_gap_baton->operative_ranges,
                                    revision,
@@ -8351,7 +8509,8 @@ do_directory_merge(svn_mergeinfo_catalog
      the target thanks to depth-first ordering. */
   target_merge_path = APR_ARRAY_IDX(notify_b->children_with_mergeinfo, 0,
                                     svn_client__merge_path_t *);
-  merge_b->target_missing_child = target_merge_path->missing_child;
+  merge_b->target_missing_child = (target_merge_path->missing_child
+                                   || target_merge_path->switched_child);
 
   /* If we are honoring mergeinfo, then for each item in
      NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
@@ -8956,18 +9115,7 @@ do_merge(apr_hash_t **modified_subtrees,
     }
 
   /* Let everyone know we're finished here. */
-  if (ctx->notify_func2)
-    {
-      svn_wc_notify_t *notify
-        = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed,
-                               iterpool);
-      notify->kind = svn_node_none;
-      notify->content_state = notify->prop_state
-        = svn_wc_notify_state_inapplicable;
-      notify->lock_state = svn_wc_notify_lock_state_inapplicable;
-      notify->revision = SVN_INVALID_REVNUM;
-      (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool);
-    }
+  notify_merge_completed(target_abspath, ctx, iterpool);
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
@@ -9066,14 +9214,12 @@ merge_cousins_and_supplement_mergeinfo(c
      source, that was made in prior merges. */
   if (same_repos && !dry_run)
     {
-      svn_wc_notify_t *notify = svn_wc_create_notify(
-        target_abspath, svn_wc_notify_merge_record_info_begin, scratch_pool);
       svn_mergeinfo_catalog_t add_result_catalog =
         apr_hash_make(scratch_pool);
       svn_mergeinfo_catalog_t remove_result_catalog =
         apr_hash_make(scratch_pool);
 
-      ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+      notify_mergeinfo_recording(target_abspath, NULL, ctx, scratch_pool);
       svn_pool_clear(subpool);
       SVN_ERR(do_merge(NULL, add_result_catalog, add_sources, target_abspath,
                        TRUE, TRUE, same_repos,
@@ -9609,6 +9755,11 @@ log_find_operative_revs(void *baton,
   apr_hash_index_t *hi;
   svn_revnum_t revision;
 
+  /* It's possible that authz restrictions on the merge source prevent us
+     from knowing about any of the changes for LOG_ENTRY->REVISION. */
+  if (!log_entry->changed_paths2)
+    return SVN_NO_ERROR;
+
   revision = log_entry->revision;
 
   for (hi = apr_hash_first(pool, log_entry->changed_paths2);

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.c Fri Dec  2 14:59:00 2011
@@ -819,7 +819,7 @@ should_elide_mergeinfo(svn_boolean_t *el
                        svn_mergeinfo_t parent_mergeinfo,
                        svn_mergeinfo_t child_mergeinfo,
                        const char *path_suffix,
-                       apr_pool_t *pool)
+                       apr_pool_t *scratch_pool)
 {
   /* Easy out: No child mergeinfo to elide. */
   if (child_mergeinfo == NULL)
@@ -844,20 +844,18 @@ should_elide_mergeinfo(svn_boolean_t *el
       /* Both CHILD_MERGEINFO and PARENT_MERGEINFO are non-NULL and
          non-empty. */
       svn_mergeinfo_t path_tweaked_parent_mergeinfo;
-      apr_pool_t *subpool = svn_pool_create(pool);
 
       /* If we need to adjust the paths in PARENT_MERGEINFO do it now. */
       if (path_suffix)
         SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
                   &path_tweaked_parent_mergeinfo, parent_mergeinfo,
-                  path_suffix, subpool, subpool));
+                  path_suffix, scratch_pool, scratch_pool));
       else
         path_tweaked_parent_mergeinfo = parent_mergeinfo;
 
       SVN_ERR(svn_mergeinfo__equals(elides,
                                     path_tweaked_parent_mergeinfo,
-                                    child_mergeinfo, TRUE, subpool));
-      svn_pool_destroy(subpool);
+                                    child_mergeinfo, TRUE, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1123,142 +1121,74 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
 }
 
 /*** In-memory mergeinfo elision ***/
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_dir_baton {
-  const char *inherited_mergeinfo_path;
-  svn_mergeinfo_t mergeinfo_catalog;
-};
-
-/* The root doesn't have mergeinfo (unless it is actually one of the
-   paths passed to svn_delta_path_driver, in which case the callback
-   is called directly instead of this). */
-static svn_error_t *
-elide_mergeinfo_catalog_open_root(void *eb,
-                                  svn_revnum_t base_revision,
-                                  apr_pool_t *dir_pool,
-                                  void **root_baton)
-{
-  struct elide_mergeinfo_catalog_dir_baton *b = apr_pcalloc(dir_pool,
-                                                            sizeof(*b));
-  b->mergeinfo_catalog = eb;
-  *root_baton = b;
-  return SVN_NO_ERROR;
-}
-
-/* Make a directory baton for PATH.  It should have the same
-   inherited_mergeinfo_path as its parent... unless we just called
-   elide_mergeinfo_catalog_cb on its parent with its path. */
-static svn_error_t *
-elide_mergeinfo_catalog_open_directory(const char *path,
-                                       void *parent_baton,
-                                       svn_revnum_t base_revision,
-                                       apr_pool_t *dir_pool,
-                                       void **child_baton)
-{
-  struct elide_mergeinfo_catalog_dir_baton *b, *pb = parent_baton;
-
-  b = apr_pcalloc(dir_pool, sizeof(*b));
-  b->mergeinfo_catalog = pb->mergeinfo_catalog;
-
-  if (apr_hash_get(b->mergeinfo_catalog, path, APR_HASH_KEY_STRING))
-    b->inherited_mergeinfo_path = apr_pstrdup(dir_pool, path);
-  else
-    b->inherited_mergeinfo_path = pb->inherited_mergeinfo_path;
-
-  *child_baton = b;
-  return SVN_NO_ERROR;
-}
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_cb_baton {
-  apr_array_header_t *elidable_paths;
-  svn_mergeinfo_t mergeinfo_catalog;
-  apr_pool_t *result_pool;
-};
-
-/* Implements svn_delta_path_driver_cb_func_t. */
-static svn_error_t *
-elide_mergeinfo_catalog_cb(void **dir_baton,
-                           void *parent_baton,
-                           void *callback_baton,
-                           const char *path,
-                           apr_pool_t *pool)
+svn_error_t *
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+                                    apr_pool_t *scratch_pool)
 {
-  struct elide_mergeinfo_catalog_cb_baton *cb = callback_baton;
-  struct elide_mergeinfo_catalog_dir_baton *pb = parent_baton;
-  const char *path_suffix;
-  svn_boolean_t elides;
+  apr_array_header_t *sorted_hash;
+  apr_array_header_t *elidable_paths = apr_array_make(scratch_pool, 1,
+                                                      sizeof(const char *));
+  apr_array_header_t *dir_stack = apr_array_make(scratch_pool, 1,
+                                                 sizeof(const char *));
+  apr_pool_t *iterpool;
+  int i;
 
-  /* pb == NULL would imply that there was an *empty* path in the
-     paths given to the driver (which is different from "/"). */
-  SVN_ERR_ASSERT(pb != NULL);
-
-  /* We'll just act like everything is a file. */
-  *dir_baton = NULL;
-
-  /* Is there even any inherited mergeinfo to elide? */
-  /* (Note that svn_delta_path_driver will call open_directory before
-     the callback for the root (only).) */
-  if (!pb->inherited_mergeinfo_path
-      || strcmp(path, "/") == 0)
-    return SVN_NO_ERROR;
+  /* Here's the general algorithm:
+     Walk through the paths sorted in tree order.  For each path, pop
+     the dir_stack until it is either empty or the top item contains a parent
+     of the current path. Check to see if that mergeinfo is then elidable,
+     and build the list of elidable mergeinfo based upon that determination.
+     Finally, push the path of interest onto the stack, and continue. */
+  sorted_hash = svn_sort__hash(mergeinfo_catalog,
+                               svn_sort_compare_items_as_paths,
+                               scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i,
+                                              svn_sort__item_t);
+      const char *path = item->key;
 
-  path_suffix = svn_dirent_is_child(pb->inherited_mergeinfo_path,
-                                    path, NULL);
-  SVN_ERR_ASSERT(path_suffix != NULL);
+      if (dir_stack->nelts > 0)
+        {
+          const char *top;
+          const char *path_suffix;
+          svn_boolean_t elides = FALSE;
+          
+          svn_pool_clear(iterpool);
 
-  SVN_ERR(should_elide_mergeinfo(&elides,
-                                 apr_hash_get(cb->mergeinfo_catalog,
-                                              pb->inherited_mergeinfo_path,
-                                              APR_HASH_KEY_STRING),
-                                 apr_hash_get(cb->mergeinfo_catalog,
-                                              path,
-                                              APR_HASH_KEY_STRING),
-                                 path_suffix,
-                                 pool));
+          /* Pop off any paths which are not ancestors of PATH. */
+          do
+            {
+              top = APR_ARRAY_IDX(dir_stack, dir_stack->nelts - 1,
+                                          const char *);
+              path_suffix = svn_dirent_is_child(top, path, NULL);
 
-  if (elides)
-    APR_ARRAY_PUSH(cb->elidable_paths, const char *) =
-      apr_pstrdup(cb->result_pool, path);
+              if (!path_suffix)
+                apr_array_pop(dir_stack);
+            }
+          while (dir_stack->nelts > 0 && !path_suffix);
 
-  return SVN_NO_ERROR;
-}
+          /* If we have a path suffix, it means we haven't popped the stack
+             clean. */
+          if (path_suffix)
+            {
+              SVN_ERR(should_elide_mergeinfo(&elides,
+                                         apr_hash_get(mergeinfo_catalog, top,
+                                                      APR_HASH_KEY_STRING),
+                                         apr_hash_get(mergeinfo_catalog, path,
+                                                      APR_HASH_KEY_STRING),
+                                         path_suffix,
+                                         iterpool));
 
-svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
-                                    apr_pool_t *pool)
-{
-  apr_array_header_t *paths;
-  apr_array_header_t *elidable_paths = apr_array_make(pool, 1,
-                                                      sizeof(const char *));
-  svn_delta_editor_t *editor = svn_delta_default_editor(pool);
-  struct elide_mergeinfo_catalog_cb_baton cb = { 0 };
-  void *eb;
-  int i;
-  svn_delta_shim_callbacks_t *shim_callbacks =
-                                     svn_delta_shim_callbacks_default(pool);
+              if (elides)
+                APR_ARRAY_PUSH(elidable_paths, const char *) = path;
+            }
+        }
 
-  cb.elidable_paths = elidable_paths;
-  cb.mergeinfo_catalog = mergeinfo_catalog;
-  cb.result_pool = pool;
-
-  editor->open_root = elide_mergeinfo_catalog_open_root;
-  editor->open_directory = elide_mergeinfo_catalog_open_directory;
-
-  eb = mergeinfo_catalog;
-  SVN_ERR(svn_editor__insert_shims((const svn_delta_editor_t **)&editor, &eb,
-                                   editor, eb, shim_callbacks, pool, pool));
-
-  /* Walk over the paths, and build up a list of elidable ones. */
-  SVN_ERR(svn_hash_keys(&paths, mergeinfo_catalog, pool));
-  SVN_ERR(svn_delta_path_driver(editor,
-                                eb,
-                                SVN_INVALID_REVNUM,
-                                paths,
-                                elide_mergeinfo_catalog_cb,
-                                &cb,
-                                pool));
+      APR_ARRAY_PUSH(dir_stack, const char *) = path;
+    }
+  svn_pool_destroy(iterpool);
 
   /* Now remove the elidable paths from the catalog. */
   for (i = 0; i < elidable_paths->nelts; i++)

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.h?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/mergeinfo.h Fri Dec  2 14:59:00 2011
@@ -40,7 +40,9 @@ typedef struct svn_client__merge_path_t
 {
   const char *abspath;               /* Absolute working copy path. */
   svn_boolean_t missing_child;       /* ABSPATH has an immediate child which
-                                        is missing. */
+                                        is missing, but is not switched. */
+  svn_boolean_t switched_child;      /* ABSPATH has an immediate child which
+                                        is switched. */
   svn_boolean_t switched;            /* ABSPATH is switched. */
   svn_boolean_t has_noninheritable;  /* ABSPATH has svn:mergeinfo set on it
                                         which includes non-inheritable
@@ -79,6 +81,13 @@ typedef struct svn_client__merge_path_t
                                            to the merge, and the operational
                                            depth of the merge is
                                            svn_depth_immediates. */
+  svn_boolean_t record_mergeinfo;       /* Mergeinfo needs to be recorded
+                                           on ABSPATH to describe the
+                                           merge. */
+  svn_boolean_t record_noninheritable;  /* Non-inheritable mergeinfo needs to
+                                           be recorded on ABSPATH to describe
+                                           the merge. Implies RECORD_MERGEINFO
+                                           is true. */
 } svn_client__merge_path_t;
 
 /* Return a deep copy of the merge-path structure OLD, allocated in POOL. */
@@ -367,10 +376,18 @@ svn_client__elide_mergeinfo(const char *
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool);
 
-/* TODO(reint): Document. */
+/* Simplify a mergeinfo catalog, if possible, via elision.
+
+   For each path in MERGEINFO_CATALOG, check if the path's mergeinfo can
+   elide to the path's nearest path-wise parent in MERGEINFO_CATALOG.  If
+   so, remove that path from MERGEINFO_CATALOG.  Elidability is determined
+   as per svn_client__elide_mergeinfo except that elision to the repository
+   is not considered.
+
+   SCRATCH_POOL is used for temporary allocations. */
 svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
-                                    apr_pool_t *pool);
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+                                    apr_pool_t *scratch_pool);
 
 /* Set *MERGEINFO_CHANGES to TRUE if LOCAL_ABSPATH has locally modified
    mergeinfo, set *MERGEINFO_CHANGES to FALSE otherwise. */

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/patch.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/patch.c Fri Dec  2 14:59:00 2011
@@ -1699,7 +1699,7 @@ apply_hunk(patch_target_t *target, targe
                                                    &eol_str, &eof,
                                                    iterpool, iterpool));
       lines_read++;
-      if (! eof && lines_read > hi->fuzz &&
+      if (lines_read > hi->fuzz &&
           lines_read <= svn_diff_hunk_get_modified_length(hi->hunk) - hi->fuzz)
         {
           apr_size_t len;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c Fri Dec  2 14:59:00 2011
@@ -1384,7 +1384,13 @@ complete_cb(void *baton,
   /* Drive the tree we've created. */
   err = drive_tree(&eb->root, eb->deditor, eb->make_abs_paths, scratch_pool);
   if (!err)
-     err = eb->deditor->close_edit(eb->dedit_baton, scratch_pool);
+     {
+       err = eb->deditor->close_directory(eb->root.baton, scratch_pool);
+       err = svn_error_compose_create(err, eb->deditor->close_edit(
+                                                            eb->dedit_baton,
+                                                            scratch_pool));
+     }
+
   if (err)
     svn_error_clear(eb->deditor->abort_edit(eb->dedit_baton, scratch_pool));
 

Modified: subversion/branches/moves-scan-log/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_diff/parse-diff.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_diff/parse-diff.c Fri Dec  2 14:59:00 2011
@@ -590,11 +590,19 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
   svn_boolean_t eof, in_hunk, hunk_seen;
   apr_off_t pos, last_line;
   apr_off_t start, end;
+  apr_off_t original_end;
+  apr_off_t modified_end;
   svn_linenum_t original_lines;
   svn_linenum_t modified_lines;
   svn_linenum_t leading_context;
   svn_linenum_t trailing_context;
   svn_boolean_t changed_line_seen;
+  enum {
+    noise_line,
+    original_line,
+    modified_line,
+    context_line
+  } last_line_type;
   apr_pool_t *iterpool;
 
   *prop_operation = svn_diff_op_unchanged;
@@ -615,12 +623,17 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
   leading_context = 0;
   trailing_context = 0;
   changed_line_seen = FALSE;
+  original_end = 0;
+  modified_end = 0;
   *hunk = apr_pcalloc(result_pool, sizeof(**hunk));
 
   /* Get current seek position -- APR has no ftell() :( */
   pos = 0;
   SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, scratch_pool));
 
+  /* Start out assuming noise. */
+  last_line_type = noise_line;
+
   iterpool = svn_pool_create(scratch_pool);
   do
     {
@@ -632,17 +645,58 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
       SVN_ERR(readline(apr_file, &line, NULL, &eof, APR_SIZE_MAX,
                        iterpool, iterpool));
 
-      if (! eof)
-        {
-          /* Update line offset for next iteration. */
-          pos = 0;
-          SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, iterpool));
-        }
+      /* Update line offset for next iteration. */
+      pos = 0;
+      SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, iterpool));
 
       /* Lines starting with a backslash are comments, such as
        * "\ No newline at end of file". */
       if (line->data[0] == '\\')
-        continue;
+        {
+          if (in_hunk &&
+              ((!*is_property &&
+                strcmp(line->data, "\\ No newline at end of file") == 0) ||
+               (*is_property &&
+                strcmp(line->data, "\\ No newline at end of property") == 0)))
+            {
+              char eolbuf[2];
+              apr_size_t len;
+              apr_off_t off;
+              apr_off_t hunk_text_end;
+
+              /* Comment terminates the hunk text and says the hunk text
+               * has no trailing EOL. Snip off trailing EOL which is part
+               * of the patch file but not part of the hunk text. */
+              off = last_line - 2;
+              SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &off, iterpool));
+              len = sizeof(eolbuf);
+              SVN_ERR(svn_io_file_read_full2(apr_file, eolbuf, len, &len,
+                                             &eof, iterpool));
+              if (eolbuf[0] == '\r' && eolbuf[1] == '\n')
+                hunk_text_end = last_line - 2;
+              else if (eolbuf[1] == '\n' || eolbuf[1] == '\r')
+                hunk_text_end = last_line - 1;
+              else
+                hunk_text_end = last_line;
+
+              if (last_line_type == original_line && original_end == 0)
+                original_end = hunk_text_end;
+              else if (last_line_type == modified_line && modified_end == 0)
+                modified_end = hunk_text_end;
+              else if (last_line_type == context_line)
+                {
+                  if (original_end == 0)
+                    original_end = hunk_text_end;
+                  if (modified_end == 0)
+                    modified_end = hunk_text_end;
+                  break;
+                }
+
+              SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
+            }
+
+          continue;
+        }
 
       if (in_hunk)
         {
@@ -673,6 +727,7 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context++;
               else
                 leading_context++;
+              last_line_type = context_line;
             }
           else if (original_lines > 0 && c == del)
             {
@@ -686,6 +741,7 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context = 0;
 
               original_lines--;
+              last_line_type = original_line;
             }
           else if (modified_lines > 0 && c == add)
             {
@@ -699,13 +755,26 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context = 0;
 
               modified_lines--;
+              last_line_type = modified_line;
             }
           else
             {
-              /* The start of the current line marks the first byte
-               * after the hunk text. */
-              end = last_line;
+              if (eof)
+                {
+                  /* The hunk ends at EOF. */
+                  end = pos;
+                }
+              else
+                {
+                  /* The start of the current line marks the first byte
+                   * after the hunk text. */
+                  end = last_line;
+                }
 
+              if (original_end == 0)
+                original_end = end;
+              if (modified_end == 0)
+                modified_end = end;
               break; /* Hunk was empty or has been read. */
             }
         }
@@ -785,10 +854,10 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
       (*hunk)->diff_text_range.end = end;
       (*hunk)->original_text_range.start = start;
       (*hunk)->original_text_range.current = start;
-      (*hunk)->original_text_range.end = end;
+      (*hunk)->original_text_range.end = original_end;
       (*hunk)->modified_text_range.start = start;
       (*hunk)->modified_text_range.current = start;
-      (*hunk)->modified_text_range.end = end;
+      (*hunk)->modified_text_range.end = modified_end;
     }
   else
     /* Something went wrong, just discard the result. */

Modified: subversion/branches/moves-scan-log/subversion/libsvn_fs_base/reps-strings.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_fs_base/reps-strings.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_fs_base/reps-strings.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_fs_base/reps-strings.c Fri Dec  2 14:59:00 2011
@@ -489,8 +489,7 @@ rep_read_range(svn_fs_t *fs,
           /* Make a list of all the rep's we need to undeltify this range.
              We'll have to read them within this trail anyway, so we might
              as well do it once and up front. */
-          apr_array_header_t *reps =  /* ### what constant here? */
-            apr_array_make(pool, 666, sizeof(rep));
+          apr_array_header_t *reps = apr_array_make(pool, 30, sizeof(rep));
           do
             {
               const rep_delta_chunk_t *const first_chunk

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/questions.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/questions.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/questions.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/questions.c Fri Dec  2 14:59:00 2011
@@ -531,19 +531,6 @@ svn_wc__min_max_revisions(svn_revnum_t *
 
 
 svn_error_t *
-svn_wc__is_sparse_checkout(svn_boolean_t *is_sparse_checkout,
-                           svn_wc_context_t *wc_ctx,
-                           const char *local_abspath,
-                           apr_pool_t *scratch_pool)
-{
-  return svn_error_trace(svn_wc__db_is_sparse_checkout(is_sparse_checkout,
-                                                       wc_ctx->db,
-                                                       local_abspath,
-                                                       scratch_pool));
-}
-
-
-svn_error_t *
 svn_wc__has_switched_subtrees(svn_boolean_t *is_switched,
                               svn_wc_context_t *wc_ctx,
                               const char *local_abspath,

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c Fri Dec  2 14:59:00 2011
@@ -2549,6 +2549,7 @@ svn_wc_get_status_editor5(const svn_delt
   sfb = apr_palloc(result_pool, sizeof(*sfb));
   sfb->db = wc_ctx->db;
   sfb->base_abspath = eb->target_abspath;
+  sfb->fetch_base = FALSE;
 
   shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
   shim_callbacks->fetch_kind_baton = sfb;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c Fri Dec  2 14:59:00 2011
@@ -5340,6 +5340,7 @@ make_editor(svn_revnum_t *target_revisio
   sfb = apr_palloc(result_pool, sizeof(*sfb));
   sfb->db = db;
   sfb->base_abspath = eb->target_abspath;
+  sfb->fetch_base = TRUE;
 
   shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
   shim_callbacks->fetch_kind_baton = sfb;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/util.c?rev=1209521&r1=1209520&r2=1209521&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/util.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/util.c Fri Dec  2 14:59:00 2011
@@ -567,8 +567,12 @@ svn_wc__fetch_props_func(apr_hash_t **pr
                                               scratch_pool);
   svn_error_t *err;
 
-  err = svn_wc__db_read_props(props, sfb->db, local_abspath,
-                              result_pool, scratch_pool);
+  if (sfb->fetch_base)
+    err = svn_wc__db_base_get_props(props, sfb->db, local_abspath, result_pool,
+                                    scratch_pool);
+  else
+    err = svn_wc__db_read_props(props, sfb->db, local_abspath,
+                                result_pool, scratch_pool);
 
   /* If the path doesn't exist, just return an empty set of props. */
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)



Mime
View raw message