You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2010/03/16 19:03:41 UTC

svn commit: r923910 [2/9] - in /subversion/branches/1.6.x-issue3432: ./ build/ build/ac-macros/ build/generator/ contrib/cgi/ contrib/client-side/emacs/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/server-side/ doc/user/ notes/ pack...

Modified: subversion/branches/1.6.x-issue3432/subversion/bindings/swig/python/tests/mergeinfo.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/bindings/swig/python/tests/mergeinfo.py?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/bindings/swig/python/tests/mergeinfo.py (original)
+++ subversion/branches/1.6.x-issue3432/subversion/bindings/swig/python/tests/mergeinfo.py Tue Mar 16 18:03:37 2010
@@ -107,10 +107,10 @@ class SubversionMergeinfoTestCase(unitte
                                        False, None, None)
     expected_mergeinfo = \
       { '/trunk' :
-          { 'branches/a' : [RevRange(2, 11)],
-            'branches/b' : [RevRange(9, 13)],
-            'branches/c' : [RevRange(2, 16)],
-            'trunk'      : [RevRange(1, 9)],  },
+          { '/branches/a' : [RevRange(2, 11)],
+            '/branches/b' : [RevRange(9, 13)],
+            '/branches/c' : [RevRange(2, 16)],
+            '/trunk'      : [RevRange(1, 9)],  },
       }
     self.compare_mergeinfo_catalogs(mergeinfo, expected_mergeinfo)
 

Modified: subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_client.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_client.rb?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_client.rb (original)
+++ subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_client.rb Tue Mar 16 18:03:37 2010
@@ -1013,7 +1013,7 @@ class SvnClientTest < Test::Unit::TestCa
       yield(ctx, branch, rev3, rev4, trunk)
       ctx.revert(trunk, false)
       ctx.resolve(:path=>trunk_path,
-                  :conflict_choice=>Svn::Wc::CONFLICT_CHOOSE_MINE_FULL)
+                  :conflict_choice=>Svn::Wc::CONFLICT_CHOOSE_MERGED)
       rev5 = ctx.commit(@wc_path).revision
       assert(File.exist?(trunk_path))
       ctx.up(@wc_path)

Modified: subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_core.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_core.rb?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_core.rb (original)
+++ subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/test_core.rb Tue Mar 16 18:03:37 2010
@@ -628,9 +628,8 @@ EOM
     assert_raises(Svn::Error::BadFilename) do
       Svn::Core::MimeType.detect(nonexistent_html_file)
     end
-    assert_raises(Svn::Error::BadFilename) do
-      Svn::Core::MimeType.detect(nonexistent_html_file, type_map)
-    end
+    assert_equal("text/html",
+                 Svn::Core::MimeType.detect(nonexistent_html_file, type_map))
 
     empty_html_file = File.join(@tmp_path, "empty.html")
     FileUtils.touch(empty_html_file)

Modified: subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/windows_util.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/windows_util.rb?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/windows_util.rb (original)
+++ subversion/branches/1.6.x-issue3432/subversion/bindings/swig/ruby/test/windows_util.rb Tue Mar 16 18:03:37 2010
@@ -67,9 +67,19 @@ module SvnTestUtil
             service_control('delete') if service_exists?
             FileUtils.rm_rf(svnserve_dir)
           end
-          targets = %w(svnserve.exe libsvn_subr-1.dll libsvn_repos-1.dll
+          
+          config = SetupEnvironment.gen_make_opts
+          apr_version_include = Pathname.new(config["--with-apr"])  +
+              'include' + 'apr_version.h'
+          %r'^\s*#define\s+APR_MAJOR_VERSION\s+(\d+)' =~ apr_version_include.read
+          apr_major_version = $1 == '0' ? '' : "-#{$1}"
+          
+          targets = %W(svnserve.exe libsvn_subr-1.dll libsvn_repos-1.dll
                        libsvn_fs-1.dll libsvn_delta-1.dll
-                       libaprutil.dll libapr.dll libapriconv.dll sqlite3.dll libdb44.dll libdb44d.dll)
+                       libaprutil#{apr_major_version}.dll 
+                       libapr#{apr_major_version}.dll 
+                       libapriconv#{apr_major_version}.dll
+                       libdb44.dll libdb44d.dll)
           ENV["PATH"].split(";").each do |path|
             found_targets = []
             targets.each do |target|
@@ -82,6 +92,9 @@ module SvnTestUtil
             targets -= found_targets
             break if targets.empty?
           end
+          # Remove optional targets instead of raising below.  If they are really
+          # needed, svnserve won't start anyway.
+          targets -= %W[libapriconv#{apr_major_version}.dll]
           unless targets.empty?
             raise "can't find libraries to work svnserve: #{targets.join(' ')}"
           end
@@ -128,6 +141,7 @@ exit 1
 
     module SetupEnvironment
       def setup_test_environment(top_dir, base_dir, ext_dir)
+        @@top_dir = top_dir
 
         build_type = ENV["BUILD_TYPE"] || "Release"
 
@@ -157,6 +171,30 @@ exit 1
         end
       end
 
+      def gen_make_opts
+        @gen_make_opts ||= begin
+          lines = []
+          gen_make_opts = File.join(@@top_dir, "gen-make.opts")
+          lines = File.read(gen_make_opts).to_a if File.exists?(gen_make_opts)
+          config = Hash.new do |hash, key|
+            if /^--with-(.*)$/ =~ key
+              hash[key] = File.join(@@top_dir, $1)
+            end
+          end
+       
+          lines.each do |line|
+            name, value = line.chomp.split(/\s*=\s*/, 2)
+            if value
+              config[name] = Pathname.new(value).absolute? ?
+                value :
+                File.join(@@top_dir, value)
+            end
+          end
+          config
+        end
+      end
+      module_function :gen_make_opts
+
       private
       def setup_dll_wrapper_util(dll_dir, util)
         libsvn_swig_ruby_dll_dir = File.join(dll_dir, "libsvn_swig_ruby")
@@ -174,29 +212,18 @@ add_path.call(#{dll_dir.dump})
 add_path.call(#{libsvn_swig_ruby_dll_dir.dump})
 EOC
       end
-
+      
       def add_depended_dll_path_to_dll_wrapper_util(top_dir, build_type, util)
-        lines = []
-        gen_make_opts = File.join(top_dir, "gen-make.opts")
-        lines = File.read(gen_make_opts).to_a if File.exists?(gen_make_opts)
-        config = {}
-        lines.each do |line|
-          name, value = line.chomp.split(/\s*=\s*/, 2)
-          config[name] = value if value
-        end
-
         [
          ["apr", build_type],
          ["apr-util", build_type],
          ["apr-iconv", build_type],
          ["berkeley-db", "bin"],
-         ["sqlite", "bin"],
+         ["libintl", "bin"],
+         ["sasl", "lib"],
         ].each do |lib, sub_dir|
-          lib_dir = Pathname.new(config["--with-#{lib}"] || lib)
-          dll_dir = lib_dir.absolute? ?
-                        lib_dir :
-                        Pathname.new(top_dir) + lib_dir
-          dll_dir += sub_dir
+          lib_dir = Pathname.new(gen_make_opts["--with-#{lib}"])
+          dll_dir = lib_dir + sub_dir
           dll_dir = dll_dir.expand_path
           util.puts("add_path.call(#{dll_dir.to_s.dump})")
         end

Modified: subversion/branches/1.6.x-issue3432/subversion/bindings/swig/svn_client.i
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/bindings/swig/svn_client.i?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/bindings/swig/svn_client.i (original)
+++ subversion/branches/1.6.x-issue3432/subversion/bindings/swig/svn_client.i Tue Mar 16 18:03:37 2010
@@ -63,9 +63,12 @@
 %apply apr_array_header_t *SOURCES {
   apr_array_header_t *sources
 }
+#endif
 
+#if defined(SWIGRUBY) || defined(SWIGPYTHON)
 %apply apr_array_header_t *REVISION_RANGE_LIST {
-  apr_array_header_t *ranges_to_merge
+  const apr_array_header_t *ranges_to_merge,
+  const apr_array_header_t *revision_ranges
 }
 #endif
 

Modified: subversion/branches/1.6.x-issue3432/subversion/include/private/svn_mergeinfo_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/include/private/svn_mergeinfo_private.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/include/private/svn_mergeinfo_private.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/include/private/svn_mergeinfo_private.h Tue Mar 16 18:03:37 2010
@@ -93,7 +93,10 @@ svn_mergeinfo__remove_prefix_from_catalo
    appropriate newline terminated string.  If KEY_PREFIX is not NULL then
    prepend KEY_PREFIX to each key (path) in *OUTPUT.  if VAL_PREFIX is not
    NULL then prepend VAL_PREFIX to each merge source:rangelist line in
-   *OUTPUT. */
+   *OUTPUT.
+
+   Any relative merge source paths in the mergeinfo in CATALOG are converted
+   to absolute paths in *OUTPUT. */
 svn_error_t *
 svn_mergeinfo__catalog_to_formatted_string(svn_string_t **output,
                                            svn_mergeinfo_catalog_t catalog,
@@ -105,7 +108,10 @@ svn_mergeinfo__catalog_to_formatted_stri
    Unlike svn_mergeinfo_to_string(), NULL MERGEINFO is tolerated and results
    in *OUTPUT set to "\n".  If SVN_DEBUG is true, then NULL or empty MERGEINFO
    causes *OUTPUT to be set to an appropriate newline terminated string.  If
-   PREFIX is not NULL then prepend PREFIX to each line in *OUTPUT. */
+   PREFIX is not NULL then prepend PREFIX to each line in *OUTPUT.
+
+   Any relative merge source paths in MERGEINFO are converted to absolute
+   paths in *OUTPUT.*/
 svn_error_t *
 svn_mergeinfo__to_formatted_string(svn_string_t **output,
                                    svn_mergeinfo_t mergeinfo,

Modified: subversion/branches/1.6.x-issue3432/subversion/include/private/svn_opt_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/include/private/svn_opt_private.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/include/private/svn_opt_private.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/include/private/svn_opt_private.h Tue Mar 16 18:03:37 2010
@@ -32,15 +32,23 @@
 extern "C" {
 #endif /* __cplusplus */
 
-/* Extract the peg revision, if any, from UTF8_TARGET. Return the peg
- * revision in *PEG_REVISION and the true target portion in *TRUE_TARGET.
+/* Extract the peg revision, if any, from UTF8_TARGET.
+ *
+ * If PEG_REVISION is not NULL, return the peg revision in *PEG_REVISION.
  * *PEG_REVISION will be an empty string if no peg revision is found.
+ * Return the true target portion in *TRUE_TARGET.
  *
  * UTF8_TARGET need not be canonical. *TRUE_TARGET will not be canonical
  * unless UTF8_TARGET is.
  *
+ * It is an error if *TRUE_TARGET results in the empty string after the
+ * split, which happens in case UTF8_TARGET has a leading '@' character
+ * with no additional '@' characters to escape the first '@'.
+ *
  * Note that *PEG_REVISION will still contain the '@' symbol as the first
- * character if a peg revision was found.
+ * character if a peg revision was found. If a trailing '@' symbol was
+ * used to escape other '@' characters in UTF8_TARGET, *PEG_REVISION will
+ * point to the string "@", containing only a single character.
  *
  * All allocations are done in POOL.
  */
@@ -106,6 +114,27 @@ svn_opt__args_to_target_array(apr_array_
                               apr_array_header_t *known_targets,
                               apr_pool_t *pool);
 
+/* Return, in @a *true_targets_p, a copy of @a targets with peg revision
+ * specifiers snipped off the end of each element.
+ *
+ * This function is useful for subcommands for which peg revisions
+ * do not make any sense. Such subcommands still need to allow peg
+ * revisions to be specified on the command line so that users of
+ * the command line client can consistently escape '@' characters
+ * in filenames by appending an '@' character, regardless of the
+ * subcommand being used.
+ *
+ * If a peg revision is present but cannot be parsed, an error is thrown.
+ * The user has likely forgotten to escape an '@' character in a filename.
+ *
+ * It is safe to pass the address of @a targets as @a true_targets_p.
+ *
+ * Do all allocations in @a pool. */
+svn_error_t *
+svn_opt__eat_peg_revisions(apr_array_header_t **true_targets_p,
+                           apr_array_header_t *targets,
+                           apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/1.6.x-issue3432/subversion/include/svn_mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/include/svn_mergeinfo.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/include/svn_mergeinfo.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/include/svn_mergeinfo.h Tue Mar 16 18:03:37 2010
@@ -152,6 +152,9 @@ typedef apr_hash_t *svn_mergeinfo_catalo
  * inheritability are also allowed, but will be combined into a single
  * range when placed into @a *mergeinfo.
  *
+ * @a input may contain relative merge source paths, but these are
+ * converted to absolute paths in @a *mergeinfo.
+ *
  * @since New in 1.5.
  */
 svn_error_t *
@@ -363,6 +366,9 @@ svn_mergeinfo_inheritable(svn_mergeinfo_
  *  mergeinfo in *OUTPUT.  If INPUT contains no elements, return the
  *  empty string.
  *
+ * @a mergeinput may contain relative merge source paths, but these are
+ * converted to absolute paths in @a *output.
+ *
  * @since New in 1.5.
 */
 svn_error_t *

Modified: subversion/branches/1.6.x-issue3432/subversion/include/svn_opt.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/include/svn_opt.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/include/svn_opt.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/include/svn_opt.h Tue Mar 16 18:03:37 2010
@@ -621,11 +621,14 @@ svn_opt_parse_all_args(apr_array_header_
  *    "foo/bar@1:2"                  -> error
  *    "foo/bar@baz"                  -> error
  *    "foo/bar@"                     -> "foo/bar",       (base)
+ *    "foo/@bar@"                    -> "foo/@bar",      (base)
  *    "foo/bar/@13"                  -> "foo/bar/",      (number, 13)
  *    "foo/bar@@13"                  -> "foo/bar@",      (number, 13)
  *    "foo/@bar@HEAD"                -> "foo/@bar",      (head)
  *    "foo@/bar"                     -> "foo@/bar",      (unspecified)
  *    "foo@HEAD/bar"                 -> "foo@HEAD/bar",  (unspecified)
+ *    "@foo/bar"                     -> error
+ *    "@foo/bar@"                    -> "@foo/bar",      (unspecified)
  *
  *   [*] Syntactically valid but probably not semantically useful.
  *

Modified: subversion/branches/1.6.x-issue3432/subversion/include/svn_version.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/include/svn_version.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/include/svn_version.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/include/svn_version.h Tue Mar 16 18:03:37 2010
@@ -66,7 +66,7 @@ extern "C" {
  *
  * @since New in 1.1.
  */
-#define SVN_VER_PATCH      4
+#define SVN_VER_PATCH      10
 
 
 /** @deprecated Provided for backward compatibility with the 1.0 API. */

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c Tue Mar 16 18:03:37 2010
@@ -248,11 +248,6 @@ password_get_gnome_keyring(const char **
 {
   char *default_keyring = NULL;
 
-  if (non_interactive)
-    {
-      return FALSE;
-    }
-
   if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
     {
       return FALSE;
@@ -327,11 +322,6 @@ password_set_gnome_keyring(apr_hash_t *c
 {
   char *default_keyring = NULL;
 
-  if (non_interactive)
-    {
-      return FALSE;
-    }
-
   if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
     {
       return FALSE;
@@ -387,6 +377,7 @@ simple_gnome_keyring_first_creds(void **
   svn_boolean_t non_interactive = apr_hash_get(parameters,
                                                SVN_AUTH_PARAM_NON_INTERACTIVE,
                                                APR_HASH_KEY_STRING) != NULL;
+  const char *default_keyring = get_default_keyring_name(pool);
   if (! non_interactive)
     {
       svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
@@ -398,7 +389,6 @@ simple_gnome_keyring_first_creds(void **
                      APR_HASH_KEY_STRING);
 
       char *keyring_password;
-      const char *default_keyring = get_default_keyring_name(pool);
 
       if (check_keyring_is_locked(default_keyring))
         {
@@ -414,12 +404,22 @@ simple_gnome_keyring_first_creds(void **
         }
     }
 
-  return svn_auth__simple_first_creds_helper(credentials,
-                                             iter_baton, provider_baton,
-                                             parameters, realmstring,
-                                             password_get_gnome_keyring,
-                                             SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
-                                             pool);
+  if (check_keyring_is_locked(default_keyring))
+    {
+      return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
+                              _("GNOME Keyring is locked and "
+                                "we are non-interactive"));
+    }
+  else
+    {
+      return svn_auth__simple_first_creds_helper
+               (credentials,
+                iter_baton, provider_baton,
+                parameters, realmstring,
+                password_get_gnome_keyring,
+                SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+                pool);
+    }
 }
 
 /* Save encrypted credentials to the simple provider's cache. */
@@ -434,6 +434,7 @@ simple_gnome_keyring_save_creds(svn_bool
   svn_boolean_t non_interactive = apr_hash_get(parameters,
                                                SVN_AUTH_PARAM_NON_INTERACTIVE,
                                                APR_HASH_KEY_STRING) != NULL;
+  const char *default_keyring = get_default_keyring_name(pool);
   if (! non_interactive)
     {
       svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
@@ -445,7 +446,6 @@ simple_gnome_keyring_save_creds(svn_bool
                      APR_HASH_KEY_STRING);
 
       char *keyring_password;
-      const char *default_keyring = get_default_keyring_name(pool);
 
       if (check_keyring_is_locked(default_keyring))
         {
@@ -460,13 +460,22 @@ simple_gnome_keyring_save_creds(svn_bool
             }
         }
     }
-
-  return svn_auth__simple_save_creds_helper(saved, credentials,
-                                            provider_baton, parameters,
-                                            realmstring,
-                                            password_set_gnome_keyring,
-                                            SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
-                                            pool);
+  if (check_keyring_is_locked(default_keyring))
+    {
+      return svn_error_create(SVN_ERR_AUTHN_CREDS_NOT_SAVED, NULL,
+                              _("GNOME Keyring is locked and "
+                                "we are non-interactive"));
+    }
+  else
+    {
+      return svn_auth__simple_save_creds_helper
+               (saved, credentials,
+                provider_baton, parameters,
+                realmstring,
+                password_set_gnome_keyring,
+                SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+                pool);
+    }
 }
 
 static void
@@ -518,6 +527,7 @@ ssl_client_cert_pw_gnome_keyring_first_c
   svn_boolean_t non_interactive = apr_hash_get(parameters,
                                                SVN_AUTH_PARAM_NON_INTERACTIVE,
                                                APR_HASH_KEY_STRING) != NULL;
+  const char *default_keyring = get_default_keyring_name(pool);
   if (! non_interactive)
     {
       svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
@@ -529,7 +539,6 @@ ssl_client_cert_pw_gnome_keyring_first_c
                      APR_HASH_KEY_STRING);
 
       char *keyring_password;
-      const char *default_keyring = get_default_keyring_name(pool);
 
       if (check_keyring_is_locked(default_keyring))
         {
@@ -544,14 +553,22 @@ ssl_client_cert_pw_gnome_keyring_first_c
             }
         }
     }
-
-  return svn_auth__ssl_client_cert_pw_file_first_creds_helper
-           (credentials,
-            iter_baton, provider_baton,
-            parameters, realmstring,
-            password_get_gnome_keyring,
-            SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
-            pool);
+  if (check_keyring_is_locked(default_keyring))
+    {
+      return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
+                              _("GNOME Keyring is locked and "
+                                "we are non-interactive"));
+    }
+  else
+    {
+      return svn_auth__ssl_client_cert_pw_file_first_creds_helper
+               (credentials,
+                iter_baton, provider_baton,
+                parameters, realmstring,
+                password_get_gnome_keyring,
+                SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+                pool);
+    }
 }
 
 /* Save encrypted credentials to the ssl client cert password provider's
@@ -567,6 +584,7 @@ ssl_client_cert_pw_gnome_keyring_save_cr
   svn_boolean_t non_interactive = apr_hash_get(parameters,
                                                SVN_AUTH_PARAM_NON_INTERACTIVE,
                                                APR_HASH_KEY_STRING) != NULL;
+  const char *default_keyring = get_default_keyring_name(pool);
   if (! non_interactive)
     {
       svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
@@ -578,7 +596,6 @@ ssl_client_cert_pw_gnome_keyring_save_cr
                      APR_HASH_KEY_STRING);
 
       char *keyring_password;
-      const char *default_keyring = get_default_keyring_name(pool);
 
       if (check_keyring_is_locked(default_keyring))
         {
@@ -593,14 +610,22 @@ ssl_client_cert_pw_gnome_keyring_save_cr
             }
         }
     }
-
-  return svn_auth__ssl_client_cert_pw_file_save_creds_helper
-           (saved, credentials,
-            provider_baton, parameters,
-            realmstring,
-            password_set_gnome_keyring,
-            SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
-            pool);
+  if (check_keyring_is_locked(default_keyring))
+    {
+      return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
+                              _("GNOME Keyring is locked and "
+                                "we are non-interactive"));
+    }
+  else
+    {
+      return svn_auth__ssl_client_cert_pw_file_save_creds_helper
+               (saved, credentials,
+                provider_baton, parameters,
+                realmstring,
+                password_set_gnome_keyring,
+                SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+                pool);
+    }
 }
 
 static const svn_auth_provider_t gnome_keyring_ssl_client_cert_pw_provider = {

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/add.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/add.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/add.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/add.c Tue Mar 16 18:03:37 2010
@@ -82,6 +82,23 @@ trim_string(char **pstr)
   str[i] = '\0';
 }
 
+/* Remove leading and trailing single- or double quotes from a C string,
+ * in place. */
+static void
+unquote_string(char **pstr)
+{
+  char *str = *pstr;
+  size_t i = strlen(str);
+
+  if (i > 0 && ((*str == '"' && str[i - 1] == '"') ||
+                (*str == '\'' && str[i - 1] == '\'')))
+    {
+      str[i - 1] = '\0';
+      str++;
+    }
+  *pstr = str;
+}
+
 /* Split PROPERTY and store each individual value in PROPS.
    Allocates from POOL. */
 static void
@@ -163,6 +180,7 @@ auto_props_enumerator(const char *name,
           *equal_sign = '\0';
           equal_sign++;
           trim_string(&equal_sign);
+          unquote_string(&equal_sign);
           this_value = equal_sign;
         }
       else
@@ -291,13 +309,26 @@ add_file(const char *path,
         {
           const void *pname;
           void *pval;
+          svn_error_t *err;
 
           apr_hash_this(hi, &pname, NULL, &pval);
           /* It's probably best to pass 0 for force, so that if
              the autoprops say to set some weird combination,
              we just error and let the user sort it out. */
-          SVN_ERR(svn_wc_prop_set3(pname, pval, path, adm_access, FALSE,
-                                   NULL, NULL, pool));
+          err = svn_wc_prop_set3(pname, pval, path, adm_access, FALSE,
+                                 NULL, NULL, pool);
+          if (err)
+            {
+              /* Don't leave the job half-done. If we fail to set a property,
+               * (try to) un-add the file. */
+              svn_error_clear(svn_wc_revert3(path, adm_access,
+                                             svn_depth_empty,
+                                             FALSE /* use_commit_times */,
+                                             NULL /* changelists */,
+                                             NULL, NULL, NULL, NULL,
+                                             pool));
+              return err;
+            }
         }
     }
 

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/commit_util.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/commit_util.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/commit_util.c Tue Mar 16 18:03:37 2010
@@ -314,10 +314,10 @@ bail_on_tree_conflicted_ancestor(svn_wc_
   while(1)
     {
       /* Here, ADM_ACCESS refers to PATH. */
-      svn_wc__strictly_is_wc_root(&wc_root,
-                                  path,
-                                  adm_access,
-                                  scratch_pool);
+      SVN_ERR(svn_wc__strictly_is_wc_root(&wc_root,
+                                          path,
+                                          adm_access,
+                                          scratch_pool));
 
       if (adm_access != first_ancestor)
         svn_wc_adm_close2(adm_access, scratch_pool);
@@ -335,8 +335,8 @@ bail_on_tree_conflicted_ancestor(svn_wc_
                                scratch_pool));
       /* Now, ADM_ACCESS refers to PARENT_PATH. */
 
-      svn_wc_conflicted_p2(NULL, NULL, &tree_conflicted,
-                           path, adm_access, scratch_pool);
+      SVN_ERR(svn_wc_conflicted_p2(NULL, NULL, &tree_conflicted,
+                                   path, adm_access, scratch_pool));
 
       if (tree_conflicted)
         return svn_error_createf(
@@ -461,6 +461,9 @@ harvest_committables(apr_hash_t *committ
          svn_path_local_style(path, scratch_pool));
     }
 
+  if (entry->file_external_path && copy_mode)
+    return SVN_NO_ERROR;
+
   if (entry->kind == svn_node_dir)
     {
       /* Read the dir's own entries for use when recursing. */
@@ -723,6 +726,14 @@ harvest_committables(apr_hash_t *committ
           if (this_entry->depth == svn_depth_exclude)
             continue;
 
+          /* Skip schedule-delete children inside of schedule-replace
+           * directories which were deleted pre-replace.
+           * Attempting to commit such nodes causes an out-of-date error.
+           * See issue #3281. */
+          if (entry->schedule == svn_wc_schedule_replace &&
+              this_entry->schedule == svn_wc_schedule_delete)
+            continue;
+
           name_uri = svn_path_uri_encode(name, iterpool);
 
           full_path = svn_path_join(path, name, iterpool);

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/copy.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/copy.c Tue Mar 16 18:03:37 2010
@@ -67,7 +67,7 @@
    *TARGET_MERGEINFO.  ADM_ACCESS may be NULL, if SRC_PATH_OR_URL is an
    URL.  If NO_REPOS_ACCESS is set, this function is disallowed from
    consulting the repository about anything.  RA_SESSION may be NULL but
-   only if NO_REPOS_ACCESS is true. */
+   only if NO_REPOS_ACCESS is true.  */
 static svn_error_t *
 calculate_target_mergeinfo(svn_ra_session_t *ra_session,
                            apr_hash_t **target_mergeinfo,
@@ -109,19 +109,22 @@ calculate_target_mergeinfo(svn_ra_sessio
 
   if (! locally_added)
     {
-      const char *mergeinfo_path;
-
       if (! no_repos_access)
         {
-          /* Fetch any existing (explicit) mergeinfo. */
-          SVN_ERR(svn_client__path_relative_to_root(&mergeinfo_path, src_url,
-                                                    entry ? entry->repos : NULL,
-                                                    FALSE, ra_session,
-                                                    adm_access, pool));
+          /* Fetch any existing (explicit) mergeinfo.  We'll temporarily
+             reparent to the target URL here, just to keep the code simple.
+             We could, as an alternative, first see if the target URL was a
+             child of the session URL and use the relative "remainder", 
+             falling back to this reparenting as necessary.  */
+          const char *old_session_url = NULL;
+          SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                                    ra_session, src_url, pool));
           SVN_ERR(svn_client__get_repos_mergeinfo(ra_session, &src_mergeinfo,
-                                                  mergeinfo_path, src_revnum,
+                                                  "", src_revnum,
                                                   svn_mergeinfo_inherited,
                                                   TRUE, pool));
+          if (old_session_url)
+            SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
         }
       else
         {

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/delete.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/delete.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/delete.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/delete.c Tue Mar 16 18:03:37 2010
@@ -109,7 +109,7 @@ delete_urls(svn_commit_info_t **commit_i
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
 {
-  svn_ra_session_t *ra_session;
+  svn_ra_session_t *ra_session = NULL;
   const svn_delta_editor_t *editor;
   void *edit_baton;
   void *commit_baton;
@@ -162,30 +162,47 @@ delete_urls(svn_commit_info_t **commit_i
   SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
                                            log_msg, ctx, pool));
 
-  /* Open an RA session for the URL. Note that we don't have a local
-     directory, nor a place to put temp files. */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, common, NULL,
-                                               NULL, NULL, FALSE, TRUE,
-                                               ctx, pool));
-
   /* Verify that each thing to be deleted actually exists (to prevent
      the creation of a revision that has no changes, since the
-     filesystem allows for no-op deletes). */
+     filesystem allows for no-op deletes).  While here, we'll
+     URI-decode our targets.  */
   for (i = 0; i < targets->nelts; i++)
     {
       const char *path = APR_ARRAY_IDX(targets, i, const char *);
+      const char *item_url;
+
       svn_pool_clear(subpool);
+      item_url = svn_path_url_add_component2(common, path, subpool);
       path = svn_path_uri_decode(path, pool);
       APR_ARRAY_IDX(targets, i, const char *) = path;
-      SVN_ERR(svn_ra_check_path(ra_session, path, SVN_INVALID_REVNUM,
+
+      /* If we've not yet done so, open an RA session for the
+         URL. Note that we don't have a local directory, nor a place
+         to put temp files.  Otherwise, reparent our existing
+         session.  */
+      if (! ra_session)
+        {
+          SVN_ERR(svn_client__open_ra_session_internal(&ra_session, item_url,
+                                                       NULL, NULL, NULL, FALSE,
+                                                       TRUE, ctx, pool));
+        }
+      else
+        {
+          SVN_ERR(svn_ra_reparent(ra_session, item_url, subpool));
+        }
+
+      SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM,
                                 &kind, subpool));
       if (kind == svn_node_none)
         return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
                                  "URL '%s' does not exist",
-                                 svn_path_local_style(path, pool));
+                                 svn_path_local_style(item_url, pool));
     }
   svn_pool_destroy(subpool);
 
+  /* Reparent the RA_session to the common parent of our deletees. */
+  SVN_ERR(svn_ra_reparent(ra_session, common, pool));
+
   /* Fetch RA commit editor */
   SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/externals.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/externals.c Tue Mar 16 18:03:37 2010
@@ -769,13 +769,14 @@ handle_external_item_change(const void *
                                                new_item->url, NULL,
                                                &(new_item->peg_revision),
                                                &(new_item->revision), ib->ctx,
-                                               ib->pool));
+                                               ib->iter_pool));
 
-      SVN_ERR(svn_ra_get_uuid2(ra_session, &ra_cache.repos_uuid, ib->pool));
+      SVN_ERR(svn_ra_get_uuid2(ra_session, &ra_cache.repos_uuid,
+                               ib->iter_pool));
       SVN_ERR(svn_ra_get_repos_root2(ra_session, &ra_cache.repos_root_url,
-                                     ib->pool));
+                                     ib->iter_pool));
       SVN_ERR(svn_ra_check_path(ra_session, "", ra_cache.ra_revnum, &kind,
-                                ib->pool));
+                                ib->iter_pool));
 
       if (svn_node_none == kind)
         return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/log.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/log.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/log.c Tue Mar 16 18:03:37 2010
@@ -317,6 +317,7 @@ svn_client_log5(const apr_array_header_t
   pre_15_receiver_baton_t rb = {0};
   apr_pool_t *iterpool;
   int i;
+  svn_opt_revision_t peg_rev;
 
   if (revision_ranges->nelts == 0)
     {
@@ -325,6 +326,11 @@ svn_client_log5(const apr_array_header_t
          _("Missing required revision specification"));
     }
 
+  /* Make a copy of PEG_REVISION, we may need to change it to a
+     default value. */
+  peg_rev.kind = peg_revision->kind;
+  peg_rev.value = peg_revision->value;
+
   /* Use the passed URL, if there is one.  */
   url_or_path = APR_ARRAY_IDX(targets, 0, const char *);
   is_url = svn_path_is_url(url_or_path);
@@ -362,7 +368,7 @@ svn_client_log5(const apr_array_header_t
           /* Default to any specified peg revision.  Otherwise, if the
            * first target is an URL, then we default to HEAD:0.  Lastly,
            * the default is BASE:0 since WC@HEAD may not exist. */
-          if (peg_revision->kind == svn_opt_revision_unspecified)
+          if (peg_rev.kind == svn_opt_revision_unspecified)
             {
               if (svn_path_is_url(url_or_path))
                 range->start.kind = svn_opt_revision_head;
@@ -370,7 +376,7 @@ svn_client_log5(const apr_array_header_t
                 range->start.kind = svn_opt_revision_base;
             }
           else
-            range->start = *peg_revision;
+            range->start = peg_rev;
 
           if (range->end.kind == svn_opt_revision_unspecified)
             {
@@ -453,6 +459,11 @@ svn_client_log5(const apr_array_header_t
                                 _("When specifying working copy paths, only "
                                   "one target may be given"));
 
+      /* An unspecified PEG_REVISION for a working copy path defautls
+         to svn_opt_revision_working. */
+      if (peg_rev.kind == svn_opt_revision_unspecified)
+          peg_rev.kind = svn_opt_revision_working;
+
       /* Get URLs for each target */
       target_urls = apr_array_make(pool, 1, sizeof(const char *));
       real_targets = apr_array_make(pool, 1, sizeof(const char *));
@@ -504,14 +515,14 @@ svn_client_log5(const apr_array_header_t
     /* If this is a revision type that requires access to the working copy,
      * we use our initial target path to figure out where to root the RA
      * session, otherwise we use our URL. */
-    if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+    if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_rev.kind))
       SVN_ERR(svn_path_condense_targets(&ra_target, NULL, targets, TRUE, pool));
     else
       ra_target = url_or_path;
 
     SVN_ERR(svn_client__ra_session_from_path(&ra_session, &ignored_revnum,
                                              &actual_url, ra_target, NULL,
-                                             peg_revision, &session_opt_rev,
+                                             &peg_rev, &session_opt_rev,
                                              ctx, pool));
 
     SVN_ERR(svn_ra_has_capability(ra_session, &has_log_revprops,

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/merge.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/merge.c Tue Mar 16 18:03:37 2010
@@ -30,6 +30,7 @@
 #include "svn_wc.h"
 #include "svn_delta.h"
 #include "svn_diff.h"
+#include "svn_dirent_uri.h"
 #include "svn_mergeinfo.h"
 #include "svn_client.h"
 #include "svn_string.h"
@@ -441,38 +442,24 @@ obstructed_or_missing(const char *path,
     return svn_wc_notify_state_obstructed;
 }
 
-/* Record a tree conflict in the WC, unless this is a dry run or a record-
- * only merge.
- *
- * The tree conflict, with its victim specified by VICTIM_PATH, is
- * assumed to have happened during a merge using merge baton MERGE_B.
- *
- * ADM_ACCESS must correspond to the victim's parent directory (even if
- * the victim is a directory).
- *
- * NODE_KIND must be the node kind of "old" and "theirs" and "mine";
- * this function cannot cope with node kind clashes.
- * ACTION and REASON correspond to the fields
- * of the same names in svn_wc_tree_conflict_description_t.
+/* Create a tree-conflict description in *CONFLICT.
+ * See tree_conflict() for function parameters.
  */
 static svn_error_t*
-tree_conflict(merge_cmd_baton_t *merge_b,
-              svn_wc_adm_access_t *adm_access,
-              const char *victim_path,
-              svn_node_kind_t node_kind,
-              svn_wc_conflict_action_t action,
-              svn_wc_conflict_reason_t reason)
+make_tree_conflict(svn_wc_conflict_description_t **conflict,
+                   merge_cmd_baton_t *merge_b,
+                   svn_wc_adm_access_t *adm_access,
+                   const char *victim_path,
+                   svn_node_kind_t node_kind,
+                   svn_wc_conflict_action_t action,
+                   svn_wc_conflict_reason_t reason)
 {
-  svn_wc_conflict_description_t *conflict;
   const char *src_repos_url;  /* root URL of source repository */
   const char *left_url;
   const char *right_url;
   svn_wc_conflict_version_t *left;
   svn_wc_conflict_version_t *right;
 
-  if (merge_b->record_only || merge_b->dry_run)
-    return SVN_NO_ERROR;
-
   SVN_ERR(svn_ra_get_repos_root2(merge_b->ra_session1, &src_repos_url,
                                  merge_b->pool));
 
@@ -504,17 +491,110 @@ tree_conflict(merge_cmd_baton_t *merge_b
             svn_path_is_child(src_repos_url, right_url, merge_b->pool),
             merge_b->merge_source.rev2, node_kind, merge_b->pool);
 
-  conflict = svn_wc_conflict_description_create_tree(
+  *conflict = svn_wc_conflict_description_create_tree(
     victim_path, adm_access, node_kind, svn_wc_operation_merge,
     left, right, merge_b->pool);
 
-  conflict->action = action;
-  conflict->reason = reason;
+  (*conflict)->action = action;
+  (*conflict)->reason = reason;
+
+  return SVN_NO_ERROR;
+}
+
+/* Record a tree conflict in the WC, unless this is a dry run or a record-
+ * only merge.
+ *
+ * The tree conflict, with its victim specified by VICTIM_PATH, is
+ * assumed to have happened during a merge using merge baton MERGE_B.
+ *
+ * ADM_ACCESS must correspond to the victim's parent directory (even if
+ * the victim is a directory).
+ *
+ * NODE_KIND must be the node kind of "old" and "theirs" and "mine";
+ * this function cannot cope with node kind clashes.
+ * ACTION and REASON correspond to the fields
+ * of the same names in svn_wc_tree_conflict_description_t.
+ */
+static svn_error_t*
+tree_conflict(merge_cmd_baton_t *merge_b,
+              svn_wc_adm_access_t *adm_access,
+              const char *victim_path,
+              svn_node_kind_t node_kind,
+              svn_wc_conflict_action_t action,
+              svn_wc_conflict_reason_t reason)
+{
+  svn_wc_conflict_description_t *conflict;
+
+  if (merge_b->record_only || merge_b->dry_run)
+    return SVN_NO_ERROR;
+
+  /* Construct the new conflict first to get the proper conflict->path */
+  SVN_ERR(make_tree_conflict(&conflict, merge_b, adm_access, victim_path,
+                             node_kind, action, reason));
 
   SVN_ERR(svn_wc__add_tree_conflict(conflict, adm_access, merge_b->pool));
   return SVN_NO_ERROR;
 }
 
+/* The same as tree_conflict(), but this one is called from
+   merge_*_added() and possibly collapses a new tree-conflict
+   with an existing one. */
+static svn_error_t*
+tree_conflict_on_add(merge_cmd_baton_t *merge_b,
+                     svn_wc_adm_access_t *adm_access,
+                     const char *victim_path,
+                     svn_node_kind_t node_kind,
+                     svn_wc_conflict_action_t action,
+                     svn_wc_conflict_reason_t reason)
+{
+  svn_wc_conflict_description_t *existing_conflict;
+  svn_wc_conflict_description_t *conflict;
+
+  if (merge_b->record_only || merge_b->dry_run)
+    return SVN_NO_ERROR;
+
+  /* Construct the new conflict first to get the proper conflict->path,
+     and also to compare the new conflict with a possibly existing one. */
+  SVN_ERR(make_tree_conflict(&conflict, merge_b, adm_access, victim_path,
+                             node_kind, action, reason));
+
+  SVN_ERR(svn_wc__get_tree_conflict(&existing_conflict, conflict->path,
+                                    adm_access, merge_b->pool));
+
+  if (existing_conflict == NULL)
+    {
+      /* There is no existing tree conflict so it is safe to add one. */
+      SVN_ERR(svn_wc__add_tree_conflict(conflict, adm_access, merge_b->pool));
+    }
+  else if (existing_conflict->action == svn_wc_conflict_action_delete &&
+           conflict->action == svn_wc_conflict_action_add)
+    {
+      /* There is already a tree conflict raised by a previous incoming
+       * change that attempted to delete the item (whether in this same
+       * merge operation or not). Change the existing conflict to note
+       * that the incoming change is replacement. */
+
+      /* Remove the existing tree-conflict so we can add a new one.*/
+      SVN_ERR(svn_wc__del_tree_conflict(conflict->path,
+                                        adm_access,
+                                        merge_b->pool));
+
+      /* Preserve the reason which caused the first conflict,
+       * re-label the incoming change as 'delete', and update
+       * version info for the left version of the conflict. */
+      conflict->reason = existing_conflict->reason;
+      conflict->action = svn_wc_conflict_action_delete;
+      conflict->src_left_version = svn_wc_conflict_version_dup(
+                                     existing_conflict->src_left_version,
+                                     merge_b->pool);
+
+      SVN_ERR(svn_wc__add_tree_conflict(conflict, adm_access, merge_b->pool));
+    }
+
+  /* In any other cases, we don't touch the existing conflict. */
+  return SVN_NO_ERROR;
+}
+
 /* Set *HONOR_MERGEINFO and *RECORD_MERGEINFO (if non-NULL) based on the
    merge being performed as described in MERGE_B.
 
@@ -1459,6 +1539,7 @@ merge_file_added(svn_wc_adm_access_t *ad
             const char *copyfrom_url = NULL;
             svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
             svn_stream_t *new_base_contents;
+            svn_wc_conflict_description_t *existing_conflict;
 
             /* If this is a merge from the same repository as our working copy,
                we handle adds as add-with-history.  Otherwise, we'll use a pure
@@ -1480,20 +1561,39 @@ merge_file_added(svn_wc_adm_access_t *ad
             SVN_ERR(svn_stream_open_readonly(&new_base_contents, yours,
                                              subpool, subpool));
 
-            /* Since 'mine' doesn't exist, and this is
-               'merge_file_added', I hope it's safe to assume that
-               'older' is empty, and 'yours' is the full file.  Merely
-               copying 'yours' to 'mine', isn't enough; we need to get
-               the whole text-base and props installed too, just as if
-               we had called 'svn cp wc wc'. */
-            /* ### would be nice to have cancel/notify funcs to pass */
-            SVN_ERR(svn_wc_add_repos_file3(
-                        mine, adm_access,
-                        new_base_contents, NULL, new_props, NULL,
-                        copyfrom_url, copyfrom_rev,
-                        NULL, NULL, NULL, NULL, subpool));
+            SVN_ERR(svn_wc__get_tree_conflict(&existing_conflict,
+                                              mine, adm_access,
+                                              merge_b->pool));
+            if (existing_conflict)
+              {
+                /* 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(tree_conflict_on_add(merge_b, adm_access, mine,
+                                             svn_node_file,
+                                             svn_wc_conflict_action_add,
+                                             svn_wc_conflict_reason_added));
+                if (tree_conflicted)
+                  *tree_conflicted = TRUE;
+              }
+            else
+              {
+                /* Since 'mine' doesn't exist, and this is
+                   'merge_file_added', I hope it's safe to assume that
+                   'older' is empty, and 'yours' is the full file.  Merely
+                   copying 'yours' to 'mine', isn't enough; we need to get
+                   the whole text-base and props installed too, just as if
+                   we had called 'svn cp wc wc'. */
+                /* ### would be nice to have cancel/notify funcs to pass */
+                SVN_ERR(svn_wc_add_repos_file3(
+                            mine, adm_access,
+                            new_base_contents, NULL, new_props, NULL,
+                            copyfrom_url, copyfrom_rev,
+                            NULL, NULL, NULL, NULL, subpool));
 
-            /* ### delete 'yours' ? */
+                /* ### delete 'yours' ? */
+              }
           }
         if (content_state)
           *content_state = svn_wc_notify_state_changed;
@@ -1507,10 +1607,10 @@ merge_file_added(svn_wc_adm_access_t *ad
        * conflict victim.
        * See notes about obstructions in notes/tree-conflicts/detection.txt.
        */
-      SVN_ERR(tree_conflict(merge_b, adm_access, mine,
-                            svn_node_file,
-                            svn_wc_conflict_action_add,
-                            svn_wc_conflict_reason_obstructed));
+      SVN_ERR(tree_conflict_on_add(merge_b, adm_access, mine,
+                                   svn_node_file,
+                                   svn_wc_conflict_action_add,
+                                   svn_wc_conflict_reason_obstructed));
       if (tree_conflicted)
         *tree_conflicted = TRUE;
       if (content_state)
@@ -1536,14 +1636,14 @@ merge_file_added(svn_wc_adm_access_t *ad
             else
               {
                 /* The file add the merge wants to carry out is obstructed by
-                 * a versioned file, so the file the merge wants to add is a
-                 * tree conflict victim. See notes about obstructions in
-                 * notes/tree-conflicts/detection.txt.
-                 */
-                SVN_ERR(tree_conflict(merge_b, adm_access, mine,
-                                      svn_node_file,
-                                      svn_wc_conflict_action_add,
-                                      svn_wc_conflict_reason_obstructed));
+                 * 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(tree_conflict_on_add(
+                          merge_b, adm_access, mine, svn_node_file,
+                          svn_wc_conflict_action_add,
+                          svn_wc_conflict_reason_added));
+
                 if (tree_conflicted)
                   *tree_conflicted = TRUE;
               }
@@ -1879,10 +1979,10 @@ merge_dir_added(svn_wc_adm_access_t *adm
           else
             {
               /* This is a tree conflict. */
-              SVN_ERR(tree_conflict(merge_b, adm_access, path,
-                                    svn_node_dir,
-                                    svn_wc_conflict_action_add,
-                                    svn_wc_conflict_reason_added));
+              SVN_ERR(tree_conflict_on_add(merge_b, adm_access, path,
+                                           svn_node_dir,
+                                           svn_wc_conflict_action_add,
+                                           svn_wc_conflict_reason_added));
               if (tree_conflicted)
                 *tree_conflicted = TRUE;
               if (state)
@@ -1906,10 +2006,10 @@ merge_dir_added(svn_wc_adm_access_t *adm
         {
           /* Obstructed: we can't add a dir because there's a file here
            * (whatever the entry says should be here). */
-          SVN_ERR(tree_conflict(merge_b, adm_access, path,
-                                svn_node_dir,
-                                svn_wc_conflict_action_add,
-                                svn_wc_conflict_reason_obstructed));
+          SVN_ERR(tree_conflict_on_add(merge_b, adm_access, path,
+                                       svn_node_dir,
+                                       svn_wc_conflict_action_add,
+                                       svn_wc_conflict_reason_obstructed));
           if (tree_conflicted)
             *tree_conflicted = TRUE;
           if (state)
@@ -2006,9 +2106,19 @@ merge_dir_deleted(svn_wc_adm_access_t *a
                                         merge_b->ctx, subpool);
             if (err)
               {
-                if (state)
-                  *state = svn_wc_notify_state_obstructed;
                 svn_error_clear(err);
+
+                /* If the attempt to delete an existing directory failed,
+                 * the directory has local modifications (e.g. locally added
+                 * files, or property changes). Flag a tree conflict. */
+                SVN_ERR(tree_conflict(merge_b, adm_access, path,
+                                      svn_node_dir,
+                                      svn_wc_conflict_action_delete,
+                                      svn_wc_conflict_reason_edited));
+                if (tree_conflicted)
+                  *tree_conflicted = TRUE;
+                if (state)
+                  *state = svn_wc_notify_state_conflicted;
               }
             else
               {
@@ -2742,7 +2852,7 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
       svn_boolean_t inherited;
       SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(recorded_mergeinfo, entry,
                                                     &inherited, FALSE,
-                                                    inherit, ra_session,
+                                                    inherit, NULL,
                                                     target_wcpath,
                                                     adm_access, ctx, pool));
       if (indirect)
@@ -2838,11 +2948,11 @@ get_full_mergeinfo(svn_mergeinfo_t *reco
   return SVN_NO_ERROR;
 }
 
-/* Helper for filter_merged_revisions().
+/* Helper for ensure_implicit_mergeinfo().
 
    PARENT, CHILD, REVISION1, REVISION2, RA_SESSION, ADM_ACCESS, and CTX
    are all cascaded from the arguments of the same names in
-   calculate_remaining_ranges().  PARENT and CHILD must both exist, i.e.
+   ensure_implicit_mergeinfo().  PARENT and CHILD must both exist, i.e.
    this function should never be called where CHILD is the merge target.
 
    If PARENT->IMPLICIT_MERGEINFO is NULL, obtain it from the server.
@@ -2861,7 +2971,7 @@ inherit_implicit_mergeinfo_from_parent(s
                                        svn_client_ctx_t *ctx,
                                        apr_pool_t *pool)
 {
-  const char *path_diff;
+  const char *path_diff, *common_ancestor;
 
   /* This only works on subtrees! */
   SVN_ERR_ASSERT(parent);
@@ -2879,7 +2989,21 @@ inherit_implicit_mergeinfo_from_parent(s
 
   /* Let CHILD inherit PARENT's implicit mergeinfo. */
   child->implicit_mergeinfo = apr_hash_make(pool);
-  path_diff = svn_path_basename(child->path, pool);
+
+  /* Find the longest common ancestor path*/
+  common_ancestor = svn_dirent_get_longest_ancestor(child->path,
+                                                    parent->path, pool);
+
+  /* PARENT->PATH better be an ancestor of CHILD->PATH! */
+  SVN_ERR_ASSERT(common_ancestor);
+
+  /* Calculate the pathwise difference between the longest common ancestor
+     and CHILD->PATH. */
+  path_diff = apr_pstrdup(pool, (child->path + strlen(common_ancestor)));
+
+  if (path_diff[0] == '/') /* Remove any leading '/'. */
+    path_diff++;
+
   SVN_ERR(svn_client__adjust_mergeinfo_source_paths(
     child->implicit_mergeinfo, path_diff,
     parent->implicit_mergeinfo, pool));
@@ -2889,8 +3013,10 @@ inherit_implicit_mergeinfo_from_parent(s
 /* Helper of filter_merged_revisions().
 
    If we have deferred obtaining CHILD->IMPLICIT_MERGEINFO, then get
-   it now, allocating it in RESULT_POOL.  Use SCRATCH_POOL for all
-   temporary allocations.
+   it now, allocating it in RESULT_POOL.  If CHILD_INHERITS_PARENT is true
+   then set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from
+   PARNET->IMPLICIT_MERGEINFO, otherwise contact the repository.  Use
+   SCRATCH_POOL for all temporary allocations.
 
    PARENT, CHILD, ENTRY, REVISION1, REVISION2, RA_SESSION, ADM_ACCESS, and
    CTX are all cascased from the arguments of the same name in
@@ -2899,6 +3025,7 @@ inherit_implicit_mergeinfo_from_parent(s
 static svn_error_t *
 ensure_implicit_mergeinfo(svn_client__merge_path_t *parent,
                           svn_client__merge_path_t *child,
+                          svn_boolean_t child_inherits_parent,
                           const svn_wc_entry_t *entry,
                           svn_revnum_t revision1,
                           svn_revnum_t revision2,
@@ -2914,15 +3041,7 @@ ensure_implicit_mergeinfo(svn_client__me
   if (child->implicit_mergeinfo)
     return SVN_NO_ERROR;
 
-
-  /* If CHILD has explicit mergeinfo only because its parent has
-     non-inheritable mergeinfo (see criteria 3 in
-     get_mergeinfo_paths() then CHILD can inherit PARENT's
-     implicit mergeinfo and we can avoid contacting the server.
-
-     If child->child_of_noninheritable is true, it implies that
-     PARENT must exist per the rules of get_mergeinfo_paths(). */
-  if (child->child_of_noninheritable)
+  if (child_inherits_parent)
     SVN_ERR(inherit_implicit_mergeinfo_from_parent(parent,
                                                    child,
                                                    revision1,
@@ -2956,9 +3075,14 @@ ensure_implicit_mergeinfo(svn_client__me
    CHILD->REMAINING_RANGES that have not alreay been merged to CHILD->PATH.
 
    CHILD represents a working copy path which is the merge target or one of
-   target's subtrees, if not NULL, PARENT is CHILD's nearest path-wise
+   the target's subtrees.  If not NULL, PARENT is CHILD's nearest path-wise
    ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'.
 
+   If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
+   CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
+   mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO.  Otherwise contact
+   the repository for CHILD->IMPLICIT_MERGEINFO.
+
    NOTE: If PARENT is present then this function must have previously been
    called for PARENT, i.e. if populate_remaining_ranges() is calling this
    function for a set of svn_client__merge_path_t* the calls must be made
@@ -2987,6 +3111,7 @@ filter_merged_revisions(svn_client__merg
                         svn_mergeinfo_t target_mergeinfo,
                         svn_revnum_t revision1,
                         svn_revnum_t revision2,
+                        svn_boolean_t child_inherits_implicit,
                         svn_ra_session_t *ra_session,
                         svn_wc_adm_access_t *adm_access,
                         svn_client_ctx_t *ctx,
@@ -3075,6 +3200,7 @@ filter_merged_revisions(svn_client__merg
 
           SVN_ERR(ensure_implicit_mergeinfo(parent,
                                             child,
+                                            child_inherits_implicit,
                                             entry,
                                             revision1,
                                             revision2,
@@ -3161,9 +3287,10 @@ filter_merged_revisions(svn_client__merg
         {
           /* Based on CHILD's TARGET_MERGEINFO there are ranges to merge.
              Check CHILD's implicit mergeinfo to see if these remaining
-             ranges are represented there.  */
+             ranges are represented there. */
           SVN_ERR(ensure_implicit_mergeinfo(parent,
                                             child,
+                                            child_inherits_implicit,
                                             entry,
                                             revision1,
                                             revision2,
@@ -3216,6 +3343,11 @@ filter_merged_revisions(svn_client__merg
    normalization conditions do not necessarily hold.  IS_SUBTREE should
    always be FALSE when calling from do_file_merge().
 
+   If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
+   CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
+   mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO.  Otherwise contact
+   the repository for CHILD->IMPLICIT_MERGEINFO.
+
    If IS_SUBTREE is FALSE then PARENT is ignored, otherwise PARENT must
    represent the nearest working copy ancestor of CHILD.
 
@@ -3245,6 +3377,7 @@ calculate_remaining_ranges(svn_client__m
                            svn_mergeinfo_t target_mergeinfo,
                            apr_array_header_t *implicit_src_gap,
                            svn_boolean_t is_subtree,
+                           svn_boolean_t child_inherits_implicit,
                            svn_ra_session_t *ra_session,
                            const svn_wc_entry_t *entry,
                            svn_wc_adm_access_t *adm_access,
@@ -3293,17 +3426,33 @@ calculate_remaining_ranges(svn_client__m
   SVN_ERR(filter_merged_revisions(parent, child, entry, mergeinfo_path,
                                   adjusted_target_mergeinfo,
                                   revision1, revision2,
+                                  child_inherits_implicit,
                                   ra_session, adm_access, ctx, pool));
 
   if (is_subtree)
     {
       apr_array_header_t *deleted_rangelist, *added_rangelist;
+      svn_boolean_t is_rollback = revision2 < revision1;
+
+      /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
+         so it will work with the svn_rangelist_diff API. */
+      if (is_rollback)
+        {
+          SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, pool));
+          SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, pool));
+        }
 
       SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
                                  child->remaining_ranges,
                                  parent->remaining_ranges,
                                  TRUE, pool));
 
+      if (is_rollback)
+        {
+          SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, pool));
+          SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, pool));
+        }
+
       /* If CHILD is the merge target we then know that primary_url,
          REVISION1, and REVISION2 are provided by normalize_merge_sources()
          -- see 'MERGEINFO MERGE SOURCE NORMALIZATION'.  Due to this
@@ -3630,6 +3779,7 @@ populate_remaining_ranges(apr_array_head
       svn_client__merge_path_t *child =
         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
       svn_client__merge_path_t *parent = NULL;
+      svn_boolean_t child_inherits_implicit;
 
       /* If the path is absent don't do subtree merge either. */
       SVN_ERR_ASSERT(child);
@@ -3680,6 +3830,13 @@ populate_remaining_ranges(apr_array_head
           SVN_ERR_ASSERT(parent);
         }
 
+      /* Issue #3443 - Can CHILD inherit PARENT's implicit mergeinfo, saving
+         us from having to ask the repos?  The only time we can't do this is if
+         CHILD is the merge target and so there is no PARENT to inherit from
+         or if CHILD is the root of a switched subtree, in which case PARENT
+         exists but is not CHILD's repository parent. */
+      child_inherits_implicit = (parent && !child->switched);
+
       SVN_ERR(calculate_remaining_ranges(parent, child,
                                          source_root_url,
                                          child_url1, revision1,
@@ -3687,6 +3844,7 @@ populate_remaining_ranges(apr_array_head
                                          child->pre_merge_mergeinfo,
                                          merge_b->implicit_src_gap,
                                          i > 0, /* is subtree */
+                                         child_inherits_implicit,
                                          ra_session, child_entry,
                                          adm_access, merge_b->ctx,
                                          pool));
@@ -5309,7 +5467,6 @@ get_mergeinfo_paths(apr_array_header_t *
                       child_of_noninheritable =
                         apr_pcalloc(pool,
                                     sizeof(*child_of_noninheritable));
-                      child_of_noninheritable->child_of_noninheritable = TRUE;
                       child_of_noninheritable->path =
                         apr_pstrdup(pool,
                                     child_path);
@@ -6018,7 +6175,7 @@ do_file_merge(const char *url1,
                                              url1, revision1, url2, revision2,
                                              target_mergeinfo,
                                              merge_b->implicit_src_gap, FALSE,
-                                             merge_b->ra_session1,
+                                             FALSE, merge_b->ra_session1,
                                              entry, adm_access, ctx, pool));
           remaining_ranges = merge_target->remaining_ranges;
         }
@@ -7851,6 +8008,9 @@ ensure_all_missing_ranges_are_phantoms(s
    path@TARGET_REV.  Effectively this is the mergeinfo catalog on the
    reintegrate target.
 
+   YC_ANCESTOR_REV is the revision of the youngest common ancestor of the
+   reintegrate source and the reintegrate target.
+
    SOURCE_REPOS_REL_PATH is the path of the reintegrate source relative to
    the root of the repository.  TARGET_REPOS_REL_PATH is the path of the
    reintegrate target relative to the root of the repository.
@@ -7884,6 +8044,7 @@ static svn_error_t *
 find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
                         svn_boolean_t *never_synched,
                         svn_revnum_t *youngest_merged_rev,
+                        svn_revnum_t yc_ancestor_rev,
                         svn_mergeinfo_catalog_t source_catalog,
                         apr_hash_t *target_segments_hash,
                         const char *source_repos_rel_path,
@@ -7933,6 +8094,16 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
                                                   segments,
                                                   iterpool));
 
+      /* Remove any target history that is also part of the source's history,
+         i.e. their common ancestry.  By definition this has already been
+         "merged" from the target to the source.  If the source has explict
+         self referential mergeinfo it would intersect with the target's
+         history below, making it appear that some merges had been done from
+         the target to the source, when this might not actually be the case. */
+      SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
+        &target_history_as_mergeinfo, target_history_as_mergeinfo,
+        source_rev, yc_ancestor_rev, iterpool));
+
       /* Look for any explicit mergeinfo on the source path corresponding to
          the target path.  If we find any remove that from SOURCE_CATALOG.
          When this iteration over TARGET_SEGMENTS_HASH is complete all that
@@ -8222,6 +8393,9 @@ calculate_left_hand_side(const char **ur
   apr_hash_t *segments_hash = apr_hash_make(pool);
   svn_boolean_t never_synced;
   svn_revnum_t youngest_merged_rev;
+  const char *yc_ancestor_path;
+  const char *source_url;
+  const char *target_url;
 
   /* Get the history (segments) for the target and any of its subtrees
      with explicit mergeinfo. */
@@ -8246,6 +8420,26 @@ calculate_left_hand_side(const char **ur
                    APR_HASH_KEY_STRING, segments);
     }
 
+  /* Check that SOURCE_URL@SOURCE_REV and TARGET_URL@TARGET_REV are
+     actually related, we can't reintegrate if they are not.  Also
+     get an initial value for *REV_LEFT. */
+  source_url = svn_path_url_add_component2(source_repos_root,
+                                           source_repos_rel_path,
+                                           subpool),
+  target_url = svn_path_url_add_component2(source_repos_root,
+                                           target_repos_rel_path,
+                                           subpool);
+  SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_ancestor_path,
+                                                   rev_left,
+                                                   source_url, source_rev,
+                                                   target_url, target_rev,
+                                                   ctx, subpool));
+  if (!(yc_ancestor_path && SVN_IS_VALID_REVNUM(*rev_left)))
+    return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
+                             _("'%s@%ld' must be ancestrally related to "
+                               "'%s@%ld'"), source_url, source_rev,
+                             target_url, target_rev);
+
   /* Get the mergeinfo from the source, including its descendants
      with differing explicit mergeinfo. */
   APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *)
@@ -8263,6 +8457,7 @@ calculate_left_hand_side(const char **ur
   SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
                                   &never_synced,
                                   &youngest_merged_rev,
+                                  *rev_left,
                                   mergeinfo_catalog,
                                   segments_hash,
                                   source_repos_rel_path,
@@ -8282,24 +8477,6 @@ calculate_left_hand_side(const char **ur
   if (never_synced)
     {
       /* We never merged to the source.  Just return the branch point. */
-      const char *yc_ancestor_path,
-        *source_url = svn_path_url_add_component2(source_repos_root,
-                                                  source_repos_rel_path,
-                                                  subpool),
-        *target_url = svn_path_url_add_component2(source_repos_root,
-                                                  target_repos_rel_path,
-                                                  subpool);
-
-      SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_ancestor_path,
-                                                       rev_left,
-                                                       source_url, source_rev,
-                                                       target_url, target_rev,
-                                                       ctx, subpool));
-      if (!(yc_ancestor_path && SVN_IS_VALID_REVNUM(*rev_left)))
-        return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
-                                 _("'%s@%ld' must be ancestrally related to "
-                                   "'%s@%ld'"), source_url, source_rev,
-                                 target_url, target_rev);
       *url_left = svn_path_url_add_component2(source_repos_root,
                                               yc_ancestor_path, pool);
     }

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.c Tue Mar 16 18:03:37 2010
@@ -304,15 +304,10 @@ svn_client__get_repos_mergeinfo(svn_ra_s
 {
   svn_error_t *err;
   svn_mergeinfo_t repos_mergeinfo;
-  const char *old_session_url;
   apr_array_header_t *rel_paths = apr_array_make(pool, 1, sizeof(rel_path));
 
   APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;
 
-  /* Temporarily point the session at the root of the repository. */
-  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
-                                            NULL, pool));
-
   /* Fetch the mergeinfo. */
   err = svn_ra_get_mergeinfo(ra_session, &repos_mergeinfo, rel_paths, rev,
                              inherit, FALSE, pool);
@@ -327,10 +322,6 @@ svn_client__get_repos_mergeinfo(svn_ra_s
         return err;
     }
 
-  /* If we reparented the session, put it back where our caller had it. */
-  if (old_session_url)
-    SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
-
   /* Grab only the mergeinfo provided for REL_PATH. */
   if (repos_mergeinfo)
     *target_mergeinfo = apr_hash_get(repos_mergeinfo, rel_path,
@@ -392,21 +383,28 @@ svn_client__get_wc_or_repos_mergeinfo(sv
                                                NULL, ctx, pool));
           if (apr_hash_get(props, target_wcpath, APR_HASH_KEY_STRING) == NULL)
             {
-              const char *repos_rel_path;
+              const char *session_url = NULL;
+              apr_pool_t *sesspool = NULL;
 
-              if (ra_session == NULL)
-                SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url,
-                                                             NULL, NULL, NULL,
-                                                             FALSE, TRUE, ctx,
-                                                             pool));
-
-              SVN_ERR(svn_client__path_relative_to_root(&repos_rel_path, url,
-                                                        entry->repos, FALSE,
-                                                        ra_session, NULL,
-                                                        pool));
+              if (ra_session)
+                {
+                  SVN_ERR(svn_client__ensure_ra_session_url(&session_url,
+                                                            ra_session,
+                                                            url, pool));
+                }
+              else
+                {
+                  sesspool = svn_pool_create(pool);
+                  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url,
+                                                               NULL, NULL, NULL,
+                                                               FALSE, TRUE,
+                                                               ctx,
+                                                               sesspool));
+                }
+              
               SVN_ERR(svn_client__get_repos_mergeinfo(ra_session,
                                                       &repos_mergeinfo,
-                                                      repos_rel_path,
+                                                      "",
                                                       target_rev,
                                                       inherit,
                                                       TRUE,
@@ -416,6 +414,18 @@ svn_client__get_wc_or_repos_mergeinfo(sv
                   *target_mergeinfo = repos_mergeinfo;
                   *indirect = TRUE;
                 }
+
+              /* If we created an RA_SESSION above, destroy it.
+                 Otherwise, if reparented an existing session, point
+                 it back where it was when we were called. */
+              if (sesspool)
+                {
+                  svn_pool_destroy(sesspool);
+                }
+              else if (session_url)
+                {
+                  SVN_ERR(svn_ra_reparent(ra_session, session_url, pool));
+                }
             }
         }
     }

Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_client/mergeinfo.h Tue Mar 16 18:03:37 2010
@@ -45,11 +45,6 @@ typedef struct svn_client__merge_path_t
   svn_boolean_t absent;              /* PATH is absent from the WC, probably
                                         due to authz restrictions. */
 
-  svn_boolean_t child_of_noninheritable; /* PATH has no explict mergeinfo
-                                            itself but is the child of a
-                                            path with noniheritable
-                                            mergeinfo. */
-
   /* The remaining ranges to be merged to PATH.  When describing a forward
      merge this rangelist adheres to the rules for rangelists described in
      svn_mergeinfo.h.  However, when describing reverse merges this
@@ -108,11 +103,9 @@ svn_client__get_wc_mergeinfo(svn_mergein
                              svn_client_ctx_t *ctx,
                              apr_pool_t *pool);
 
-/* Obtain any mergeinfo for the root-relative repository filesystem path
-   REL_PATH from the repository, and set it in *TARGET_MERGEINFO.
-   RA_SESSION should be an open RA session pointing at the URL that REL_PATH
-   is relative to, or NULL, in which case this function will open its own
-   temporary session.
+/* Obtain any mergeinfo for repository filesystem path REL_PATH
+   (relative to RA_SESSION's session URL) from the repository, and set
+   it in *TARGET_MERGEINFO.
 
    INHERIT indicates whether explicit, explicit or inherited, or only
    inherited mergeinfo for REL_PATH is obtained.
@@ -138,18 +131,18 @@ svn_client__get_repos_mergeinfo(svn_ra_s
    target has no info of its own.
 
    If no mergeinfo can be obtained from the WC or REPOS_ONLY is TRUE,
-   get it from the repository.  RA_SESSION should be an open RA session
-   pointing at ENTRY->URL, or NULL, in which case this function will open
-   its own temporary session.
+   get it from the repository.  RA_SESSION should be an open RA
+   session pointing at ENTRY->URL, or NULL, in which case this
+   function will open its own temporary session.
 
    (opening a new RA session if RA_SESSION
    is NULL).  Store any mergeinfo obtained for TARGET_WCPATH -- which
    is reflected by ENTRY -- in *TARGET_MERGEINFO, if no mergeinfo is
    found *TARGET_MERGEINFO is NULL.
 
-   Like svn_client__get_wc_mergeinfo, this function considers no inherited
-   mergeinfo to be found in the WC when trying to crawl into a parent path
-   with a different working revision.
+   Like svn_client__get_wc_mergeinfo(), this function considers no
+   inherited mergeinfo to be found in the WC when trying to crawl into
+   a parent path with a different working revision.
 
    INHERIT indicates whether explicit, explicit or inherited, or only
    inherited mergeinfo for TARGET_WCPATH is retrieved.