You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/07 15:59:43 UTC

svn commit: r993368 [4/4] - in /subversion/branches/javahl-ra: ./ notes/wc-ng/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/l...

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/externals_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/externals_tests.py Tue Sep  7 13:59:41 2010
@@ -1471,6 +1471,104 @@ def wc_repos_file_externals(sbox):
                                         None, None, None, None, None,
                                         True)
 
+#----------------------------------------------------------------------
+def merge_target_with_externals(sbox):
+  "merge target with externals"
+
+  # Test for a problem the plagued Subversion in the pre-1.7-single-DB world:
+  # Externals in a merge target would get meaningless explicit mergeinfo set
+  # on them.  See http://svn.haxx.se/dev/archive-2010-08/0088.shtml
+  externals_test_setup(sbox)
+  wc_dir = sbox.wc_dir
+  repo_url = sbox.repo_url
+
+  # Some paths we'll care about
+  A_path              = os.path.join(wc_dir, "A")
+  A_branch_path       = os.path.join(wc_dir, "A-branch")
+  A_gamma_branch_path = os.path.join(wc_dir, "A-branch", "D", "gamma")
+  
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'checkout',
+                                     repo_url, wc_dir)
+
+  # Branch A@1 to A-branch and make a simple text change on the latter in r8.
+  svntest.actions.run_and_verify_svn(None, None, [], 'copy', A_path + '@1',
+                                     A_branch_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     '-m', 'make a copy', wc_dir)
+  svntest.main.file_write(A_gamma_branch_path, "The new gamma!\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
+                                     '-m', 'branch edit', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+
+  # Merge r8 from A-branch back to A.  There should be explicit mergeinfo
+  # only at the root of A; the externals should not get any.
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-c8',
+                                     repo_url + '/A-branch', A_path)
+  svntest.actions.run_and_verify_svn(
+    "Unexpected subtree mergeinfo created",
+    ["Properties on '" + A_path + "':\n",
+     "  svn:mergeinfo\n",
+     "    /A-branch:8\n"],
+    [], 'pg', svntest.main.SVN_PROP_MERGEINFO, '-vR', wc_dir)
+
+def update_modify_file_external(sbox):
+  "update that modifies a file external"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Setup A/external as file external to A/mu
+  externals_prop = "^/A/mu external\n"
+  change_external(sbox.ospath('A'), externals_prop)
+  expected_output = svntest.wc.State(wc_dir, {
+      'A/external'      : Item(status='E '),
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'A'          : Item(props={'svn:externals':externals_prop}),
+    'A/external' : Item("This is the file 'mu'.\n"),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+    'A/external' : Item(status='  ', wc_rev='2', switched='X'),
+    })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None, None, None,
+                                        True)
+
+  # Modify A/mu
+  svntest.main.file_append(sbox.ospath('A/mu'), 'appended mu text')
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu' : Item(verb='Sending'),
+    })
+  expected_status.tweak('A/mu', wc_rev=3)
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status,
+                                        None,
+                                        wc_dir)
+
+  # Update to modify the file external, this asserts in update_editor.c
+  expected_output = svntest.wc.State(wc_dir, {
+      'A/external'      : Item(status='E '),
+    })
+  expected_disk.tweak('A/mu', 'A/external',
+                      contents=expected_disk.desc['A/mu'].contents
+                      + 'appended mu text')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.add({
+    'A/external' : Item(status='  ', wc_rev='3', switched='X'),
+    })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None, None, None,
+                                        True)
 
 ########################################################################
 # Run the tests
@@ -1501,6 +1599,8 @@ test_list = [ None,
               export_sparse_wc_with_externals,
               relegate_external,
               wc_repos_file_externals,
+              merge_target_with_externals,
+              XFail(update_modify_file_external),
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/merge_authz_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/merge_authz_tests.py Tue Sep  7 13:59:41 2010
@@ -82,13 +82,6 @@ def mergeinfo_and_skipped_paths(sbox):
   #   2) Destination of merge is inaccessible due to authz restrictions.
   #   3) Source *and* destination of merge is inaccessible due to authz
   #      restrictions.
-  #   4) File path is versioned but is missing from disk due to OS deletion.
-  #      This isn't technically part of issue #2893 but we handle this case
-  #      and it didn't warrant its own test).
-  #
-  # Eventually we should also test(?):
-  #
-  #   5) Dir path is versioned but is missing from disk due to an OS deletion.
 
   sbox.build()
   wc_dir = sbox.wc_dir
@@ -122,27 +115,20 @@ def mergeinfo_and_skipped_paths(sbox):
   omega_path = os.path.join(wc_restricted, "A_COPY", "D", "H", "omega")
   zeta_path = os.path.join(wc_dir, "A", "D", "H", "zeta")
 
-  # Restrict access to some more of the merge destination the
-  # old fashioned way, delete it via the OS.
-  ### TODO: Delete a versioned directory?
-  os.remove(omega_path)
-
   # Merge r4:8 into the restricted WC's A_COPY.
   #
   # We expect A_COPY/B/E to be skipped because we can't access the source
   # and A_COPY/D/H/omega because it is missing.  Since we have A_COPY/B/E
   # we should override it's inherited mergeinfo, giving it just what it
-  # inherited from A_COPY before the merge.  omega is missing, but since
-  # it is a file we can record the fact that it is missing in its parent
-  # directory A_COPY/D/H.
+  # inherited from A_COPY before the merge.
   expected_output = wc.State(A_COPY_path, {
     'D/G/rho'   : Item(status='U '),
     'D/H/psi'   : Item(status='U '),
+    'D/H/omega' : Item(status='U '),
     })
   expected_mergeinfo_output = wc.State(A_COPY_path, {
     ''          : Item(status=' U'),
     'B/E'       : Item(status=' U'),
-    'D/H/omega' : Item(status=' U'),
     })
   expected_elision_output = wc.State(A_COPY_path, {
     })
@@ -150,7 +136,7 @@ def mergeinfo_and_skipped_paths(sbox):
     ''          : Item(status=' M', wc_rev=8),
     'D/H/chi'   : Item(status='  ', wc_rev=8),
     'D/H/psi'   : Item(status='M ', wc_rev=8),
-    'D/H/omega' : Item(status='!M', wc_rev=8),
+    'D/H/omega' : Item(status='M ', wc_rev=8),
     'D/H'       : Item(status='  ', wc_rev=8),
     'D/G/pi'    : Item(status='  ', wc_rev=8),
     'D/G/rho'   : Item(status='M ', wc_rev=8),
@@ -171,9 +157,7 @@ def mergeinfo_and_skipped_paths(sbox):
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}),
     'D/H/psi'   : Item("New content"),
     'D/H/chi'   : Item("This is the file 'chi'.\n"),
-     # 'D/H/omega' : run_and_verify_merge() doesn't support checking
-     #               the props on a missing path, so we do that
-     #               manually (see below).
+    'D/H/omega' : Item("New content"),
     'D/H'       : Item(),
     'D/G/pi'    : Item("This is the file 'pi'.\n"),
     'D/G/rho'   : Item("New content"),
@@ -192,7 +176,6 @@ def mergeinfo_and_skipped_paths(sbox):
     })
   expected_skip = wc.State(A_COPY_path, {
     'B/E'       : Item(),
-    'D/H/omega' : Item(),
     })
   svntest.actions.run_and_verify_merge(A_COPY_path, '4', '8',
                                        sbox.repo_url + '/A', None,
@@ -205,10 +188,6 @@ def mergeinfo_and_skipped_paths(sbox):
                                        None, None, None, None,
                                        None, 1)
 
-  # Manually check the props on A_COPY/D/H/omega.
-  svntest.actions.run_and_verify_svn(None, ['\n'], [],
-                                    'pg', SVN_PROP_MERGEINFO, omega_path)
-
   # Merge r4:8 into the restricted WC's A_COPY_2.
   #
   # As before we expect A_COPY_2/B/E to be skipped because we can't access the

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tests.py Tue Sep  7 13:59:41 2010
@@ -1733,6 +1733,10 @@ def merge_into_missing(sbox):
       'Q/baz'    : Item(status='! ', wc_rev='3'),
     })    
 
+  # Use --ignore-ancestry because merge tracking aware merges raise an
+  # error when the merge target is missing subtrees due to OS-level
+  # deletes.
+
   ### Need to real and dry-run separately since real merge notifies Q
   ### twice!
   svntest.actions.run_and_verify_merge(F_path, '1', '2', F_url, None,
@@ -1743,23 +1747,20 @@ def merge_into_missing(sbox):
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       0, 0, '--dry-run', F_path)
+                                       0, 0, '--dry-run',
+                                       '--ignore-ancestry', F_path)
 
   expected_status = wc.State(F_path, {
-    ''      : Item(status=' M', wc_rev=1),
-    'foo'   : Item(status='!M', wc_rev=2),
+    ''      : Item(status='  ', wc_rev=1),
+    'foo'   : Item(status='! ', wc_rev=2),
     'Q'     : Item(status='! ', wc_rev='?'),
     })
   expected_mergeinfo_output = wc.State(F_path, {
-    ''    : Item(status=' U'),
-    'foo' : Item(status=' U'), # Mergeinfo is set on missing/obstructed files.
     })
     
   if single_db:
     # Revision is known and we can record mergeinfo
     expected_status.tweak('Q', wc_rev='2', entry_rev='?')
-    expected_mergeinfo_output.add({'Q' : Item(status=' U')})
-    # Missing data still available
     expected_status.add({
       'Q/R'      : Item(status='! ', wc_rev='3'),
       'Q/R/bar'  : Item(status='! ', wc_rev='3'),
@@ -1774,7 +1775,8 @@ def merge_into_missing(sbox):
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       0, 0)
+                                       0, 0,
+                                       '--ignore-ancestry', F_path)
 
   # This merge fails when it attempts to descend into the missing
   # directory.  That's OK, there is no real need to support merge into
@@ -1789,8 +1791,8 @@ def merge_into_missing(sbox):
   # Check working copy is not locked.
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.add({
-    'A/B/F'     : Item(status=' M', wc_rev=1),
-    'A/B/F/foo' : Item(status='!M', wc_rev=2),
+    'A/B/F'     : Item(status='  ', wc_rev=1),
+    'A/B/F/foo' : Item(status='! ', wc_rev=2),
     'A/B/F/Q'   : Item(status='! ', wc_rev='?'),
     })
   if single_db:
@@ -14995,6 +14997,7 @@ def skipped_files_get_correct_mergeinfo(
 
   # Some paths we'll care about
   A_COPY_path   = os.path.join(wc_dir, "A_COPY")
+  H_COPY_path   = os.path.join(wc_dir, "A_COPY", "D", "H")
   psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi")
   psi_path      = os.path.join(wc_dir, "A", "D", "H", "psi")
 
@@ -15022,15 +15025,21 @@ def skipped_files_get_correct_mergeinfo(
     [], 'merge', '-c3', sbox.repo_url + '/A', A_COPY_path)
   svntest.main.run_svn(None, 'commit', '-m', 'initial merge', wc_dir)
 
-  # Update WC to uniform revision and then delete, via the OS, A_COPY/D/H/psi
-  # and then merge all available revisions from A to A_COPY.  A_COPY/D/H/psi
-  # should be reported as skipped and get explicit mergeinfo set on it
-  # reflecting what it previously inherited from A_COPY after the first
-  # merge, i.e. '/A/D/H/psi:3'.  Issue #3440 occurred when empty mergeinfo
-  # was set on A_COPY/D/H/psi, making it appear that r3 was never merged.
+  # Update WC to uniform revision and then set the depth on A_COPY/D/H to
+  # empty.  Then merge all available revisions from A to A_COPY.
+  # A_COPY/D/H/psi and A_COPY/D/H/omega are not present due to their
+  # parent's depth and should be reported as skipped.  A_COPY/D/H should
+  # get explicit mergeinfo set on it reflecting what it previously inherited
+  # from A_COPY after the first merge, i.e. '/A/D/H:3', plus non-inheritable
+  # mergeinfo describing what was done during this merge,
+  # i.e. '/A/D/H:2*,4-8*'.
+  #
+  # Issue #3440 occurred when empty mergeinfo was set on A_COPY/D/H, making
+  # it appear that r3 was never merged.
   svntest.actions.run_and_verify_svn(None, ["At revision 8.\n"], [],
                                      'up', wc_dir)
-  os.remove(psi_COPY_path)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'up', '--set-depth=empty', H_COPY_path)
   expected_status = wc.State(A_COPY_path, {
     ''          : Item(status=' M'),
     'B'         : Item(status='  '),
@@ -15047,10 +15056,7 @@ def skipped_files_get_correct_mergeinfo(
     'D/G/rho'   : Item(status='M '),
     'D/G/tau'   : Item(status='  '),
     'D/gamma'   : Item(status='  '),
-    'D/H'       : Item(status='  '),
-    'D/H/chi'   : Item(status='  '),
-    'D/H/psi'   : Item(status='!M'),
-    'D/H/omega' : Item(status='M '),
+    'D/H'       : Item(status=' M'),
     })
   expected_status.tweak(wc_rev=8)
   expected_disk = wc.State('', {
@@ -15069,71 +15075,18 @@ def skipped_files_get_correct_mergeinfo(
     'D/G/rho'   : Item("New content"),
     'D/G/tau'   : Item("This is the file 'tau'.\n"),
     'D/gamma'   : Item("This is the file 'gamma'.\n"),
-    'D/H'       : Item(),
-    'D/H/chi'   : Item("This is the file 'chi'.\n"),
-    #'D/H/psi'  : Nothing here, this file was deleted via the OS.
-    'D/H/omega' : Item("New content"),
+    'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:2*,3,4-8*'}),
     })
   expected_skip = wc.State(A_COPY_path,
-                           {'D/H/psi' : Item()})
+                           {'D/H/psi'   : Item(),
+                            'D/H/omega' : Item()})
   expected_output = wc.State(A_COPY_path,
                              {'B/E/beta'  : Item(status='U '),
-                              'D/G/rho'   : Item(status='U '),
-                              'D/H/omega' : Item(status='U '),})
-  expected_mergeinfo_output = wc.State(A_COPY_path, {
-    ''        : Item(status=' U'),
-    'D/H/psi' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(A_COPY_path, {
-    })
-  svntest.actions.run_and_verify_merge(A_COPY_path, None, None,
-                                       sbox.repo_url + '/A', None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, 1)
-  # run_and_verify_merge cannot check the properties on A_COPY/D/H/psi
-  # since that file is not on disk, so we'll check the file's mergeinfo
-  # directly with svn propget.
-  svntest.actions.run_and_verify_svn(
-    'Incorrect override mergeinfo set on skipped path',
-    ["/A/D/H/psi:3\n"], [], 'pg', 'svn:mergeinfo', psi_COPY_path)
-
-  # Now test another aspect of issue #3440, that a skipped path with
-  # explicit mergeinfo doesn't get it's mergeinfo updated.
-  #
-  # First revert all changes to the WC and then merge -r2:6 from A/D/H/psi
-  # to A_COPY/D/H/psi, creating explicit mergeinfo of '/A/D/H/psi:3-6' on
-  # the latter.  Commit this merge as r9 and then update the WC.
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'revert', '-R', wc_dir)
-  svntest.actions.run_and_verify_svn(
-    None,
-    expected_merge_output([[3,6]],
-                          [' U   ' + psi_COPY_path + '\n',
-                           ' G   ' + psi_COPY_path + '\n']),
-    [], 'merge', '-r2:6', sbox.repo_url + '/A/D/H/psi', psi_COPY_path)
-  svntest.main.run_svn(None, 'commit', '-m',
-                       'subtree merge to create explicit mergeinfo',
-                       wc_dir)
-  svntest.actions.run_and_verify_svn(None, ["At revision 9.\n"], [],
-                                     'up', wc_dir)
-
-  # Remove A_COPY/D/H/psi again and then merge all available revisions
-  # from A to A_COPY.  The results should be mostly similar to the
-  # previous merge we did above, execept that A_COPY/D/H/psi should not
-  # have it's mergeinfo changed.
-  os.remove(psi_COPY_path)
-  expected_status.tweak(wc_rev=9)
-  expected_status.tweak('D/H/psi', status='! ')
-  expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A:2-9'})
+                              'D/G/rho'   : Item(status='U ')})
   expected_mergeinfo_output = wc.State(A_COPY_path, {
-    ''        : Item(status=' U'),
-    'D/H/psi' : Item(status=' U'),
+    ''    : Item(status=' U'),
+    'D/H' : Item(status=' G'), # ' G' because override mergeinfo gets set
+                               # on this, the root of a 'missing' subtree.
     })
   expected_elision_output = wc.State(A_COPY_path, {
     })
@@ -15148,16 +15101,6 @@ def skipped_files_get_correct_mergeinfo(
                                        None, None, None, None, None,
                                        1, 1)
 
-  # run_and_verify_merge cannot check the properties on A_COPY/D/H/psi
-  # since that file is not on disk, so we'll check the file's mergeinfo
-  # directly with svn propget.  Issue #3440 also occurred here, when an
-  # the missing file's mergeinfo was updated, making it appear that r2
-  # and r7-9 were also merged into A_COPY/D/H/psi, which is clearly not
-  # the case since psi isn't present.
-  svntest.actions.run_and_verify_svn(
-    'Mergeinfo on skipped path altered',
-    ["/A/D/H/psi:3-6\n"], [], 'pg', 'svn:mergeinfo', psi_COPY_path)
-
 #----------------------------------------------------------------------
 # Test for issue #3115 'Case only renames resulting from merges don't
 # work or break the WC on case-insensitive file systems'.
@@ -15899,6 +15842,87 @@ def merge_into_locally_added_directory(s
                                        True, True, new_dir_path)
   sbox.simple_commit()
 
+#----------------------------------------------------------------------
+# Test for issue #2915 'Handle mergeinfo for subtrees missing due to removal
+# by non-svn command'
+def merge_with_os_deleted_subtrees(sbox):
+  "merge tracking fails if target missing subtrees"
+
+  # r1: Create a greek tree.
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # r2 - r6: Copy A to A_COPY and then make some text changes under A.
+  set_up_branch(sbox)
+
+  # Some paths we'll care about
+  A_COPY_path   = os.path.join(wc_dir, "A_COPY")
+  C_COPY_path   = os.path.join(wc_dir, "A_COPY", "C")
+  psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi")
+  mu_COPY_path  = os.path.join(wc_dir, "A_COPY", "mu")
+  G_COPY_path   = os.path.join(wc_dir, "A_COPY", "D", "G")
+
+  # Remove several subtrees from disk.
+  svntest.main.safe_rmtree(C_COPY_path)
+  svntest.main.safe_rmtree(G_COPY_path)
+  os.remove(psi_COPY_path)
+  os.remove(mu_COPY_path)
+
+  # Be sure the regex paths are properly escaped on Windows, see the
+  # note about "The Backslash Plague" in expected_merge_output().
+  if sys.platform == 'win32':
+    re_sep = '\\\\'
+  else:
+    re_sep = os.sep
+
+  # Common part of the expected error message for all cases we will test.
+  err_re = "svn: Merge tracking not allowed with missing subtrees; " + \
+           "try restoring these items first:"                        + \
+           "|(\n)"                                                   + \
+           "|(.*apr_err.*\n)" # In case of debug build
+
+  # Case 1: Infinite depth merge into infinite depth WC target.
+  # Every missing subtree under the target should be reported as missing.
+  missing = "|(.*A_COPY" + re_sep + "mu\n)"                                + \
+            "|(.*A_COPY" + re_sep + "D" + re_sep + "G\n)"                  + \
+            "|(.*A_COPY" + re_sep + "C\n)"                                 + \
+            "|(.*A_COPY" + re_sep + "D" + re_sep + "H" + re_sep + "psi\n)"
+  exit_code, out, err = svntest.actions.run_and_verify_svn(
+    "Missing subtrees should raise error", [], svntest.verify.AnyOutput,
+    'merge', sbox.repo_url + '/A', A_COPY_path)
+  svntest.verify.verify_outputs("Merge failed but not in the way expected",
+                                err, None, err_re + missing, None,
+                                True) # Match *all* lines of stderr
+
+  # Case 2: Immediates depth merge into infinite depth WC target.
+  # Only the two immediate children of the merge target should be reported
+  # as missing.
+  missing = "|(.*A_COPY" + re_sep + "mu\n)" + \
+            "|(.*A_COPY" + re_sep + "C\n)"
+  exit_code, out, err = svntest.actions.run_and_verify_svn(
+    "Missing subtrees should raise error", [], svntest.verify.AnyOutput,
+    'merge', sbox.repo_url + '/A', A_COPY_path, '--depth=immediates')
+  svntest.verify.verify_outputs("Merge failed but not in the way expected",
+                                err, None, err_re + missing, None, True)
+
+  # Case 3: Files depth merge into infinite depth WC target.
+  # Only the single file child of the merge target should be reported
+  # as missing.
+  missing = "|(.*A_COPY" + re_sep + "mu\n)"
+  exit_code, out, err = svntest.actions.run_and_verify_svn(
+    "Missing subtrees should raise error", [], svntest.verify.AnyOutput,
+    'merge', sbox.repo_url + '/A', A_COPY_path, '--depth=files')
+  svntest.verify.verify_outputs("Merge failed but not in the way expected",
+                                err, None, err_re + missing, None, True)
+
+  # Case 4: Empty depth merge into infinite depth WC target.
+  # Only the...oh, wait, the target is present and that is as deep
+  # as the merge goes, so this merge should succeed!
+  svntest.actions.run_and_verify_svn(
+    "Depth empty merge should succeed as long at the target is present",
+    svntest.verify.AnyOutput, [], 'merge', sbox.repo_url + '/A',
+    A_COPY_path, '--depth=empty')
+
 ########################################################################
 # Run the tests
 
@@ -16087,6 +16111,7 @@ test_list = [ None,
               copy_causes_phantom_eol_conflict,
               merge_into_locally_added_file,
               merge_into_locally_added_directory,
+              merge_with_os_deleted_subtrees,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/merge_tree_conflict_tests.py Tue Sep  7 13:59:41 2010
@@ -1272,16 +1272,28 @@ def tree_conflicts_merge_edit_onto_missi
 
   # local tree missing (via shell delete), incoming leaf edit
 
+  # Note: In 1.7 merge tracking aware merges raise an error if the
+  # merge target has subtrees missing due to a shell delete.  To
+  # preserve the original intent of this test we'll run the merge
+  # with the --ignore-ancestry option, which neither considers nor
+  # records mergeinfo.  With this option the merge should "succeed"
+  # while skipping the missing paths.  Of course with no mergeinfo
+  # recorded and everything skipped, there is nothing to commit, so
+  # unlike most of the tree conflict tests we don't bother with the
+  # final commit step.
+
   sbox.build()
   expected_output = wc.State('', {
   })
 
   expected_disk = disk_after_tree_del
 
+  # Don't expect any mergeinfo property changes because we run
+  # the merge with the --ignore-ancestry option.
   expected_status = svntest.wc.State('', {
-    ''                  : Item(status=' M', wc_rev=3),
+    ''                  : Item(status='  ', wc_rev=3),
     'F'                 : Item(status='  ', wc_rev=3),
-    'F/alpha'           : Item(status='!M', wc_rev=3),
+    'F/alpha'           : Item(status='! ', wc_rev=3),
     'D'                 : Item(status='  ', wc_rev=3),
     'D/D1'              : Item(status='! ', wc_rev='?'),
     'DF'                : Item(status='  ', wc_rev=3),
@@ -1327,18 +1339,7 @@ def tree_conflicts_merge_edit_onto_missi
                expected_disk,
                expected_status,
                expected_skip,
-
-               ### This should not be happening!
-               ### The commit succeeds (it only commits mergeinfo).
-               ### But then the work queue freaks out while trying to install
-               ### F/alpha into the WC, because F/alpha is missing from disk.
-               ### We end up with a working copy that cannot be cleaned up.
-               ### To make this test pass for now we'll expect this error.
-               ### When the problem is fixed this test will start to fail
-               ### and should be adjusted.
-               commit_block_string=".*Error bumping revisions post-commit",
-
-             ) ], False)
+             ) ], False, do_commit_conflicts=False, ignore_ancestry=True)
 
 #----------------------------------------------------------------------
 def tree_conflicts_merge_del_onto_missing(sbox):
@@ -1346,16 +1347,28 @@ def tree_conflicts_merge_del_onto_missin
 
   # local tree missing (via shell delete), incoming leaf edit
 
+  # Note: In 1.7 merge tracking aware merges raise an error if the
+  # merge target has subtrees missing due to a shell delete.  To
+  # preserve the original intent of this test we'll run the merge
+  # with the --ignore-ancestry option, which neither considers nor
+  # records mergeinfo.  With this option the merge should "succeed"
+  # while skipping the missing paths.  Of course with no mergeinfo
+  # recorded and everything skipped, there is nothing to commit, so
+  # unlike most of the tree conflict tests we don't bother with the
+  # final commit step.
+
   sbox.build()
   expected_output = wc.State('', {
   })
 
   expected_disk = disk_after_tree_del
 
+  # Don't expect any mergeinfo property changes because we run
+  # the merge with the --ignore-ancestry option.
   expected_status = svntest.wc.State('', {
-    ''                  : Item(status=' M', wc_rev=3),
+    ''                  : Item(status='  ', wc_rev=3),
     'F'                 : Item(status='  ', wc_rev=3),
-    'F/alpha'           : Item(status='!M', wc_rev=3),
+    'F/alpha'           : Item(status='! ', wc_rev=3),
     'D'                 : Item(status='  ', wc_rev=3),
     'D/D1'              : Item(status='! ', wc_rev='?'),
     'DF'                : Item(status='  ', wc_rev=3),
@@ -1401,18 +1414,7 @@ def tree_conflicts_merge_del_onto_missin
                expected_disk,
                expected_status,
                expected_skip,
-
-               ### This should not be happening!
-               ### The commit succeeds (it only commits mergeinfo).
-               ### But then the work queue freaks out while trying to install
-               ### F/alpha into the WC, because F/alpha is missing from disk.
-               ### We end up with a working copy that cannot be cleaned up.
-               ### To make this test pass for now we'll expect this error.
-               ### When the problem is fixed this test will start to fail
-               ### and should be adjusted.
-               commit_block_string=".*Error bumping revisions post-commit",
-
-             ) ], False)
+             ) ], False, do_commit_conflicts=False, ignore_ancestry=True)
 
 #----------------------------------------------------------------------
 def merge_replace_setup(sbox):

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/revert_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/revert_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/revert_tests.py Tue Sep  7 13:59:41 2010
@@ -851,29 +851,37 @@ def status_of_missing_dir_after_revert_r
                   os.path.join(G_path, 'alpha'),
                   os.path.join(G_path, 'beta')]
 
+  if svntest.main.wc_is_singledb(wc_dir):
+    # These nodes are not lost in single-db
+    revert_paths += [ os.path.join(G_path, 'pi'),
+                      os.path.join(G_path, 'rho'),
+                      os.path.join(G_path, 'tau')]
+
   expected_output = svntest.verify.UnorderedOutput([
     "Reverted '%s'\n" % path for path in revert_paths])
 
   svntest.actions.run_and_verify_svn(None, expected_output, [], "revert", "-R",
                                      G_path)
 
-  ### GS (Oct 11): this is stupid. after a revert, there should be
-  ###              *NO* status whatsoever. ugh. this status behavior
-  ###              has been twiddled over the 1.6/1.7 dev cycle, but
-  ###              it "should" just disappear.
 
-  ### Is it a bug that we'd need to run revert twice to finish the job?
+  # Revert leaves these added nodes as unversioned
   expected_output = svntest.verify.UnorderedOutput(
-    ["A       " + os.path.join(G_path, "pi") + "\n",
-     "A       " + os.path.join(G_path, "rho") + "\n",
-     "A       " + os.path.join(G_path, "tau") + "\n"])
+    ["?       " + os.path.join(G_path, "pi") + "\n",
+     "?       " + os.path.join(G_path, "rho") + "\n",
+     "?       " + os.path.join(G_path, "tau") + "\n"])
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      "status", wc_dir)
 
   svntest.main.safe_rmtree(G_path)
 
-  expected_output = svntest.verify.UnorderedOutput(
-    ["!       " + G_path + "\n"])
+  if svntest.main.wc_is_singledb(wc_dir):
+    expected_output = svntest.verify.UnorderedOutput(
+      ["!       " + G_path + "\n",
+       "!       " + os.path.join(G_path, "alpha") + "\n",
+       "!       " + os.path.join(G_path, "beta") + "\n"])
+  else:
+    expected_output = svntest.verify.UnorderedOutput(
+      ["!       " + G_path + "\n"])
   svntest.actions.run_and_verify_svn(None, expected_output, [], "status",
                                      wc_dir)
 
@@ -1054,8 +1062,7 @@ test_list = [ None,
               revert_propdel__file,
               revert_replaced_with_history_file_1,
               status_of_missing_dir_after_revert,
-              Wimp("revert behavior needs better definition",
-                   status_of_missing_dir_after_revert_replaced_with_history_dir),
+              status_of_missing_dir_after_revert_replaced_with_history_dir,
               revert_replaced_with_history_file_2,
               revert_tree_conflicts_in_updated_files,
               revert_add_over_not_present_dir,

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/svntest/actions.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/svntest/actions.py Tue Sep  7 13:59:41 2010
@@ -2680,7 +2680,9 @@ def deep_trees_run_tests_scheme_for_swit
 
 
 def deep_trees_run_tests_scheme_for_merge(sbox, greater_scheme,
-                                          do_commit_local_changes):
+                                          do_commit_local_changes,
+                                          do_commit_conflicts=True,
+                                          ignore_ancestry=False):
   """
   Runs a given list of tests for conflicts occuring at a merge operation.
 
@@ -2714,12 +2716,14 @@ def deep_trees_run_tests_scheme_for_merg
       Then, in effect, the local changes are committed as well.
 
    8) In each test case subdir, the "incoming" subdir is merged into the
-      "local" subdir.
-      This causes conflicts between the "local" state in the working
-      copy and the "incoming" state from the incoming subdir.
-
-   9) A commit is performed in each separate container, to verify
-      that each tree-conflict indeed blocks a commit.
+      "local" subdir.  If ignore_ancestry is True, then the merge is done
+      with the --ignore-ancestry option, so mergeinfo is neither considered
+      nor recorded.  This causes conflicts between the "local" state in the
+      working copy and the "incoming" state from the incoming subdir.
+
+   9) If do_commit_conflicts is True, then a commit is performed in each
+      separate container, to verify that each tree-conflict indeed blocks
+      a commit.
 
   The sbox parameter is just the sbox passed to a test function. No need
   to call sbox.build(), since it is called (once) within this function.
@@ -2851,10 +2855,15 @@ def deep_trees_run_tests_scheme_for_merg
         x_skip.copy()
         x_skip.wc_dir = local
 
+      varargs = (local,)
+      if ignore_ancestry:
+        varargs = varargs + ('--ignore-ancestry',)
+
       run_and_verify_merge(local, None, None, incoming, None,
                            x_out, None, None, x_disk, None, x_skip,
-                           error_re_string = test_case.error_re_string,
-                           dry_run = False)
+                           test_case.error_re_string,
+                           None, None, None, None,
+                           False, False, *varargs)
       run_and_verify_unquiet_status(local, x_status)
     except:
       print("ERROR IN: Tests scheme for merge: "
@@ -2864,21 +2873,22 @@ def deep_trees_run_tests_scheme_for_merg
 
   # 9) Verify that commit fails.
 
-  for test_case in greater_scheme:
-    try:
-      local = j(wc_dir, test_case.name, 'local')
-
-      x_status = test_case.expected_status
-      if x_status != None:
-        x_status.copy()
-        x_status.wc_dir = local
-
-      run_and_verify_commit(local, None, x_status,
-                            test_case.commit_block_string,
-                            local)
-    except:
-      print("ERROR IN: Tests scheme for merge: "
-          + "while checking commit-blocking in '%s'" % test_case.name)
-      raise
+  if do_commit_conflicts:
+    for test_case in greater_scheme:
+      try:
+        local = j(wc_dir, test_case.name, 'local')
+
+        x_status = test_case.expected_status
+        if x_status != None:
+          x_status.copy()
+          x_status.wc_dir = local
+
+        run_and_verify_commit(local, None, x_status,
+                              test_case.commit_block_string,
+                              local)
+      except:
+        print("ERROR IN: Tests scheme for merge: "
+            + "while checking commit-blocking in '%s'" % test_case.name)
+        raise
 
 

Modified: subversion/branches/javahl-ra/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/cmdline/update_tests.py?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/javahl-ra/subversion/tests/cmdline/update_tests.py Tue Sep  7 13:59:41 2010
@@ -5683,6 +5683,44 @@ def add_moved_file_has_props2(sbox):
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 
+# A regression test for a 1.7-dev crash upon updating a WC to a different
+# revision when it contained an excluded dir.
+def update_with_excluded_subdir(sbox):
+  """update with an excluded subdir"""
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  G = os.path.join(os.path.join(wc_dir, 'A', 'D', 'G'))
+
+  # Make the directory 'G' excluded.
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/D/G' : Item(status='D '),
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
+  svntest.actions.run_and_verify_update(wc_dir, expected_output,
+                                        expected_disk, expected_status,
+                                        None, None, None, None, None, False,
+                                        '--set-depth=exclude', G)
+
+  # Commit a new revision so there is something to update to.
+  svntest.main.run_svn(None, 'mkdir', '-m', '', sbox.repo_url + '/New')
+
+  # Test updating the WC.
+  expected_output = svntest.wc.State(wc_dir, {
+    'New' : Item(status='A ') })
+  expected_disk.add({
+    'New' : Item() })
+  expected_status.add({
+    'New' : Item(status='  ') })
+  expected_status.tweak(wc_rev=2)
+  svntest.actions.run_and_verify_update(wc_dir, expected_output,
+                                        expected_disk, expected_status)
+
+
 #######################################################################
 # Run the tests
 
@@ -5753,6 +5791,7 @@ test_list = [ None,
               mergeinfo_updates_merge_with_local_mods,
               add_moved_file_has_props,
               XFail(add_moved_file_has_props2),
+              update_with_excluded_subdir,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/javahl-ra/subversion/tests/libsvn_wc/db-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/tests/libsvn_wc/db-test.c?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/tests/libsvn_wc/db-test.c (original)
+++ subversion/branches/javahl-ra/subversion/tests/libsvn_wc/db-test.c Tue Sep  7 13:59:41 2010
@@ -324,6 +324,9 @@ create_fake_wc(const char *subdir, int f
 #ifdef SVN_WC__NODE_DATA
     statements[STMT_CREATE_NODE_DATA],
 #endif
+#ifdef SVN_WC__NODES
+    statements[STMT_CREATE_NODES],
+#endif
     TESTING_DATA,
     NULL
   };
@@ -1288,8 +1291,7 @@ test_global_relocate(apr_pool_t *pool)
   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
 
   /* Test relocating to a repos not existant in the db */
-  SVN_ERR(svn_wc__db_global_relocate(db, local_abspath, ROOT_THREE, TRUE,
-                                     pool));
+  SVN_ERR(svn_wc__db_global_relocate(db, local_abspath, ROOT_THREE, pool));
   SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
                                &repos_relpath, &repos_root_url, &repos_uuid,
                                NULL, NULL, NULL, NULL,

Modified: subversion/branches/javahl-ra/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/tools/dev/unix-build/Makefile.svn?rev=993368&r1=993367&r2=993368&view=diff
==============================================================================
--- subversion/branches/javahl-ra/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/javahl-ra/tools/dev/unix-build/Makefile.svn Tue Sep  7 13:59:41 2010
@@ -37,7 +37,8 @@ GNU_ICONV_VER	= 1.13.1
 APR_UTIL_VER	= 1.3.9
 HTTPD_VER	= 2.2.15
 NEON_VER	= 0.29.3
-SERF_VER	= 0.6.x
+SERF_VER	= 0.7.x
+CYRUS_SASL_VER	= 2.1.23
 SQLITE_VER	= 3.6.23.1
 
 BDB_DIST	= db-$(BDB_VER).tar.gz
@@ -46,6 +47,7 @@ GNU_ICONV_DIST	= libiconv-$(GNU_ICONV_VE
 NEON_DIST	= neon-$(NEON_VER).tar.gz
 #SERF_DIST	= serf-$(SERF_VER).tar.gz
 SQLITE_DIST	= sqlite-$(SQLITE_VER).tar.gz
+CYRUS_SASL_DIST	= cyrus-sasl-$(CYRUS_SASL_VER).tar.gz
 HTTPD_DIST	= httpd-$(HTTPD_VER).tar.bz2
 
 DISTFILES	= $(DISTDIR)/$(NEON_DIST) \
@@ -53,7 +55,8 @@ DISTFILES	= $(DISTDIR)/$(NEON_DIST) \
 		$(DISTDIR)/$(SQLITE_DIST) \
 		$(DISTDIR)/$(HTTPD_DIST) \
 		$(DISTDIR)/$(APR_ICONV_DIST) \
-		$(DISTDIR)/$(GNU_ICONV_DIST)
+		$(DISTDIR)/$(GNU_ICONV_DIST) \
+		$(DISTDIR)/$(CYRUS_SASL_DIST)
 
 FETCH_CMD	= wget -c
 
@@ -68,6 +71,7 @@ NEON_URL	= http://webdav.org/neon/$(NEON
 #SERF_URL	= http://serf.googlecode.com/files/$(SERF_DIST)
 SERF_URL	= http://serf.googlecode.com/svn/branches/$(SERF_VER)
 SQLITE_URL	= http://www.sqlite.org/$(SQLITE_DIST)
+CYRUS_SASL_URL	= ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/$(CYRUS_SASL_DIST)
 
 BDB_SRCDIR	= $(SRCDIR)/db-$(BDB_VER)
 APR_SRCDIR	= $(SRCDIR)/apr-$(APR_VER)
@@ -78,6 +82,7 @@ HTTPD_SRCDIR	= $(SRCDIR)/httpd-$(HTTPD_V
 NEON_SRCDIR	= $(SRCDIR)/neon-$(NEON_VER)
 SERF_SRCDIR	= $(SRCDIR)/serf-$(SERF_VER)
 SQLITE_SRCDIR	= $(SRCDIR)/sqlite-$(SQLITE_VER)
+CYRUS_SASL_SRCDIR	= $(SRCDIR)/cyrus-sasl-$(CYRUS_SASL_VER)
 SVN_SRCDIR	= $(SVN_WC)
 
 BDB_OBJDIR	= $(OBJDIR)/db-$(BDB_VER)
@@ -89,6 +94,7 @@ HTTPD_OBJDIR	= $(OBJDIR)/httpd-$(HTTPD_V
 NEON_OBJDIR	= $(OBJDIR)/neon-$(NEON_VER)
 SERF_OBJDIR	= $(OBJDIR)/serf-$(SERF_VER)
 SQLITE_OBJDIR	= $(OBJDIR)/sqlite-$(SQLITE_VER)
+CYRUS_SASL_OBJDIR	= $(OBJDIR)/cyrus-sasl-$(CYRUS_SASL_VER)
 SVN_OBJDIR	= $(OBJDIR)/$(SVN_REL_WC)
 
 # Tweak this for out-of-tree builds. Note that running individual
@@ -103,16 +109,17 @@ svn_builddir	?=$(SVN_WC)
 .PHONY: all reset clean nuke
 
 all: dirs-create bdb-install apr-install iconv-install apr-util-install \
-	httpd-install neon-install serf-install sqlite-install svn-install \
-	svn-bindings-install
+	httpd-install neon-install serf-install sqlite-install \
+	cyrus-sasl-install svn-install svn-bindings-install
 
 # Use these to start a build from the beginning.
 reset: dirs-reset bdb-reset apr-reset iconv-reset apr-util-reset \
-	httpd-reset neon-reset serf-reset sqlite-reset svn-reset
+	httpd-reset neon-reset serf-reset sqlite-reset cyrus-sasl-reset \
+	svn-reset
 
 # Use to save disc space.
 clean: bdb-clean apr-clean iconv-clean apr-util-clean httpd-clean \
-	neon-clean serf-clean svn-clean
+	neon-clean serf-clean cyrus-sasl-clean svn-clean
 
 # Nukes everything (including installed binaries!)
 # Use this to start ALL OVER AGAIN! Use with caution!
@@ -656,6 +663,56 @@ $(SQLITE_OBJDIR)/.installed: $(SQLITE_OB
 	touch $@
 
 #######################################################################
+# cyrus-sasl
+#######################################################################
+
+cyrus-sasl-retrieve:	$(CYRUS_SASL_OBJDIR)/.retrieved
+cyrus-sasl-configure:	$(CYRUS_SASL_OBJDIR)/.configured
+cyrus-sasl-compile:	$(CYRUS_SASL_OBJDIR)/.compiled
+cyrus-sasl-install:	$(CYRUS_SASL_OBJDIR)/.installed
+cyrus-sasl-reset:
+	$(foreach f, .retrieved .configured .compiled .installed, \
+		rm -f $(CYRUS_SASL_OBJDIR)/$(f);)
+
+cyrus-sasl-clean:
+	-(cd $(CYRUS_SASL_OBJDIR) && make clean)
+
+# fetch distfile for cyrus-sasl
+$(DISTDIR)/$(CYRUS_SASL_DIST):
+	cd $(DISTDIR) && $(FETCH_CMD) $(CYRUS_SASL_URL)
+
+# retrieve cyrus-sasl
+$(CYRUS_SASL_OBJDIR)/.retrieved: $(DISTDIR)/$(CYRUS_SASL_DIST)
+	[ -d $(CYRUS_SASL_OBJDIR) ] || mkdir -p $(CYRUS_SASL_OBJDIR)
+	tar -C $(SRCDIR) -zxf $(DISTDIR)/$(CYRUS_SASL_DIST)
+	touch $@
+
+# configure cyrus-sasl
+$(CYRUS_SASL_OBJDIR)/.configured: $(CYRUS_SASL_OBJDIR)/.retrieved
+	cd $(CYRUS_SASL_OBJDIR) \
+		&& env CFLAGS="-g" $(CYRUS_SASL_SRCDIR)/configure \
+		--with-dbpath=$(PREFIX)/cyrus-sasl/etc/sasldb2 \
+		--with-plugindir=$(PREFIX)/cyrus-sasl/lib/sasl2 \
+		--with-configdir=$(PREFIX)/cyrus-sasl/lib/sasl2 \
+		--with-bdb-libdir=$(PREFIX)/bdb/lib \
+		--with-bdb-incdir=$(PREFIX)/bdb/include \
+		--with-dblib=berkeley \
+		--with-sqlite=$(PREFIX)/sqlite \
+		--prefix=$(PREFIX)/cyrus-sasl
+	touch $@
+
+# compile cyrus-sasl
+$(CYRUS_SASL_OBJDIR)/.compiled: $(CYRUS_SASL_OBJDIR)/.configured
+	(cd $(CYRUS_SASL_OBJDIR) && make)
+	touch $@
+
+# install cyrus-sasl
+$(CYRUS_SASL_OBJDIR)/.installed: $(CYRUS_SASL_OBJDIR)/.compiled
+	(cd $(CYRUS_SASL_OBJDIR) && make install)
+	touch $@
+
+
+#######################################################################
 # svn
 #######################################################################
 
@@ -746,7 +803,7 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)
 			--with-serf="$(PREFIX)/serf" \
 			--with-sqlite="$(PREFIX)/sqlite" \
 			--with-berkeley-db="$(BDB_FLAG)" \
-			--with-sasl="no" \
+			--with-sasl="$(PREFIX)/cyrus-sasl" \
 			--with-ruby-sitedir="$(SVN_PREFIX)/lib/ruby/site_ruby" \
 			--disable-mod-activation \
 			$(JAVAHL_FLAG)