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 2011/08/17 20:25:09 UTC

svn commit: r1158860 [1/2] - in /subversion/branches/issue-3975: ./ subversion/bindings/ctypes-python/test/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/tigris/subver...

Author: pburba
Date: Wed Aug 17 18:25:07 2011
New Revision: 1158860

URL: http://svn.apache.org/viewvc?rev=1158860&view=rev
Log:
On the issue-3975 branch: Sync with ^/subversion/trunk.



Added:
    subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/JNIError.java
      - copied unchanged from r1158857, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/JNIError.java
Removed:
    subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/JNIError.java
Modified:
    subversion/branches/issue-3975/   (props changed)
    subversion/branches/issue-3975/CHANGES
    subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/setup_path.py
    subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/svntypes.py
    subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.cpp
    subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.h
    subversion/branches/issue-3975/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp
    subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java
    subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java
    subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/SVNClient.java
    subversion/branches/issue-3975/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
    subversion/branches/issue-3975/subversion/bindings/swig/python/svn/repos.py
    subversion/branches/issue-3975/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py
    subversion/branches/issue-3975/subversion/include/svn_client.h
    subversion/branches/issue-3975/subversion/include/svn_ra.h
    subversion/branches/issue-3975/subversion/include/svn_wc.h
    subversion/branches/issue-3975/subversion/libsvn_client/cat.c
    subversion/branches/issue-3975/subversion/libsvn_client/client.h
    subversion/branches/issue-3975/subversion/libsvn_client/merge.c
    subversion/branches/issue-3975/subversion/libsvn_client/repos_diff.c
    subversion/branches/issue-3975/subversion/libsvn_client/status.c
    subversion/branches/issue-3975/subversion/libsvn_ra_serf/locks.c
    subversion/branches/issue-3975/subversion/libsvn_wc/adm_ops.c
    subversion/branches/issue-3975/subversion/libsvn_wc/questions.c
    subversion/branches/issue-3975/subversion/libsvn_wc/status.c
    subversion/branches/issue-3975/subversion/libsvn_wc/wc-metadata.sql
    subversion/branches/issue-3975/subversion/libsvn_wc/wc-queries.sql
    subversion/branches/issue-3975/subversion/libsvn_wc/wc.h
    subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.c
    subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.h
    subversion/branches/issue-3975/subversion/libsvn_wc/wc_db_wcroot.c
    subversion/branches/issue-3975/subversion/libsvn_wc/workqueue.c
    subversion/branches/issue-3975/subversion/svn/main.c
    subversion/branches/issue-3975/subversion/svn/status.c
    subversion/branches/issue-3975/subversion/svnversion/main.c
    subversion/branches/issue-3975/subversion/tests/cmdline/depth_tests.py
    subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py
    subversion/branches/issue-3975/subversion/tests/cmdline/revert_tests.py
    subversion/branches/issue-3975/subversion/tests/cmdline/special_tests.py
    subversion/branches/issue-3975/subversion/tests/cmdline/svntest/main.py
    subversion/branches/issue-3975/subversion/tests/cmdline/svnversion_tests.py
    subversion/branches/issue-3975/tools/dev/benchmarks/suite1/run

Propchange: subversion/branches/issue-3975/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Aug 17 18:25:07 2011
@@ -54,4 +54,4 @@
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
 /subversion/branches/uris-as-urls:1060426-1064427
-/subversion/trunk:1152931-1157415
+/subversion/trunk:1152931-1158857

Modified: subversion/branches/issue-3975/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/CHANGES?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/CHANGES (original)
+++ subversion/branches/issue-3975/CHANGES Wed Aug 17 18:25:07 2011
@@ -2,6 +2,9 @@ Version 1.8.0
 (?? ??? 2011, from /branches/1.8.x)
 http://svn.apache.org/repos/asf/subversion/tags/1.8.0
 
+ User-visible changes:
+    * don't leave unversioned files when reverting copies (issue #3101)
+
  Developer-visible changes:
   - API changes:
     * fix inconsistent handling of log revs without changed paths (issue #3694)
@@ -182,6 +185,7 @@ the 1.6 release:  http://subversion.apac
     * notifications sent when mergeinfo changes (r877588)
     * add information on text and property mods in log APIs (r877688)
     * fixed: svn_ra_local__get_file() leaks file descriptors (issue #3290)
+    * swig-py: always set ChangedPath.path (issue #2630)
 
   - Bindings:
     * New JavaHL package: org.apache.subversion

Modified: subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/setup_path.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/setup_path.py?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/setup_path.py (original)
+++ subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/setup_path.py Wed Aug 17 18:25:07 2011
@@ -25,8 +25,8 @@
 import sys
 import os
 
-src_swig_python_tests_dir = os.path.dirname(os.path.dirname(__file__))
-sys.path[0:0] = [ src_swig_python_tests_dir ]
+src_ctypes_python_tests_dir = os.path.dirname(os.path.dirname(__file__))
+sys.path[0:0] = [ src_ctypes_python_tests_dir ]
 
 import csvn.core
 csvn.core.svn_cmdline_init("", csvn.core.stderr)

Modified: subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/svntypes.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/svntypes.py?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/svntypes.py (original)
+++ subversion/branches/issue-3975/subversion/bindings/ctypes-python/test/svntypes.py Wed Aug 17 18:25:07 2011
@@ -21,8 +21,24 @@ import setup_path
 import unittest
 from csvn.core import *
 import csvn.types as _types
+from csvn.types import SvnDate, Hash, Array, APRFile, Stream, SvnStringPtr
 
-class TypesTestCase(unittest.TestCase):
+class SvnDateTestCase(unittest.TestCase):
+
+    def test_as_apr_time_t(self):
+        d1 = SvnDate('1999-12-31T23:59:59.000000Z')
+        d2 = SvnDate('2000-01-01T00:00:00.000000Z')
+        t1 = d1.as_apr_time_t().value
+        t2 = d2.as_apr_time_t().value
+        self.assertEqual(t1 + 1000000, t2)
+
+    def test_as_human_string(self):
+        d1 = SvnDate('1999-12-31T23:59:59.000000Z')
+        s1 = d1.as_human_string()
+        self.assertEqual(s1[:27], '1999-12-31 23:59:59 +0000 (')
+
+
+class HashTestCase(unittest.TestCase):
 
     def test_hash(self):
         self.pydict = {"bruce":"batman", "clark":"superman",
@@ -35,6 +51,34 @@ class TypesTestCase(unittest.TestCase):
         self.assertNotEqual(self.svnhash["clark"].value,
             self.pydict["bruce"])
 
+    def test_insert_delete(self):
+        h = Hash(c_char_p)
+        h['foo'] = 'f'
+        h['bar'] = 'b'
+        self.assertEqual(len(h), 2)
+        self.assertEqual(h['foo'].value, 'f')
+        self.assertEqual(h['bar'].value, 'b')
+        h['bar'] = 'b'
+        self.assertEqual(len(h), 2)
+        del h['foo']
+        self.assertEqual(len(h), 1)
+        self.assertEqual(h['bar'].value, 'b')
+
+    def test_iter(self):
+        h = Hash(c_char_p, { 'foo': 'f', 'bar': 'b' })
+        keys = sorted(h.keys())
+        self.assertEqual(keys, ['bar', 'foo'])
+        vals = []
+        for k in h:
+            vals += [ h[k].value ]
+        self.assertEqual(sorted(vals), ['b', 'f'])
+        vals = []
+        for k,v in h.items():
+            vals += [ v.value ]
+        self.assertEqual(sorted(vals), ['b', 'f'])
+
+class ArrayTestCase(unittest.TestCase):
+
     def test_array(self):
         self.pyarray = ["vini", "vidi", "vici"]
         self.svnarray = _types.Array(c_char_p, self.pyarray)
@@ -43,7 +87,11 @@ class TypesTestCase(unittest.TestCase):
         self.assertEqual(self.svnarray[1], "vidi")
 
 def suite():
-    return unittest.makeSuite(TypesTestCase, 'test')
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(SvnDateTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(HashTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(ArrayTestCase, 'test'))
+    return suite
 
 if __name__ == '__main__':
     runner = unittest.TextTestRunner()

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.cpp?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.cpp (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.cpp Wed Aug 17 18:25:07 2011
@@ -898,7 +898,9 @@ void SVNClient::propertySetLocal(Targets
                                          ctx, subPool.getPool()), );
 }
 
-void SVNClient::propertySetRemote(const char *path, const char *name,
+void SVNClient::propertySetRemote(const char *path, long base_rev,
+                                  const char *name,
+                                  CommitMessage *message,
                                   JNIByteArray &value, bool force,
                                   RevpropTable &revprops,
                                   CommitCallback *callback)
@@ -916,12 +918,12 @@ void SVNClient::propertySetRemote(const 
     Path intPath(path, subPool);
     SVN_JNI_ERR(intPath.error_occured(), );
 
-    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
+    svn_client_ctx_t *ctx = context.getContext(message, subPool);
     if (ctx == NULL)
         return;
 
     SVN_JNI_ERR(svn_client_propset_remote(name, val, intPath.c_str(),
-                                          force, SVN_INVALID_REVNUM,
+                                          force, base_rev,
                                           revprops.hash(subPool),
                                           CommitCallback::callback, callback,
                                           ctx, subPool.getPool()), );

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.h (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/native/SVNClient.h Wed Aug 17 18:25:07 2011
@@ -81,7 +81,8 @@ class SVNClient :public SVNBase
   void propertySetLocal(Targets &targets, const char *name, JNIByteArray &value,
                         svn_depth_t depth, StringArray &changelists,
                         bool force);
-  void propertySetRemote(const char *path, const char *name,
+  void propertySetRemote(const char *path, long base_rev, const char *name,
+                         CommitMessage *message,
                          JNIByteArray &value, bool force,
                          RevpropTable &revprops, CommitCallback *callback);
   void properties(const char *path, Revision &revision,

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/native/org_apache_subversion_javahl_SVNClient.cpp Wed Aug 17 18:25:07 2011
@@ -922,8 +922,9 @@ Java_org_apache_subversion_javahl_SVNCli
 
 JNIEXPORT void JNICALL
 Java_org_apache_subversion_javahl_SVNClient_propertySetRemote
-(JNIEnv *env, jobject jthis, jstring jpath, jstring jname,
- jbyteArray jvalue, jboolean jforce, jobject jrevpropTable, jobject jcallback)
+(JNIEnv *env, jobject jthis, jstring jpath, jlong jbaseRev, jstring jname,
+ jbyteArray jvalue, jobject jmessage, jboolean jforce, jobject jrevpropTable,
+ jobject jcallback)
 {
   JNIEntry(SVNClient, propertySet);
   SVNClient *cl = SVNClient::getCppObject(jthis);
@@ -940,6 +941,10 @@ Java_org_apache_subversion_javahl_SVNCli
   if (JNIUtil::isExceptionThrown())
     return;
 
+  CommitMessage message(jmessage);
+  if (JNIUtil::isExceptionThrown())
+    return;
+
   JNIByteArray value(jvalue);
   if (JNIUtil::isExceptionThrown())
     return;
@@ -949,8 +954,9 @@ Java_org_apache_subversion_javahl_SVNCli
     return;
 
   CommitCallback callback(jcallback);
-  cl->propertySetRemote(path, name, value, jforce ? true:false, revprops,
-                        jcallback ? &callback : NULL);
+  cl->propertySetRemote(path, jbaseRev, name, &message, value,
+                        jforce ? true:false,
+                        revprops, jcallback ? &callback : NULL);
 }
 
 JNIEXPORT void JNICALL

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNClient.java Wed Aug 17 18:25:07 2011
@@ -649,7 +649,8 @@ public interface ISVNClient
                           boolean force)
             throws ClientException;
 
-    void propertySetRemote(String path, String name, byte[] value,
+    void propertySetRemote(String path, long baseRev, String name,
+                           byte[] value, CommitMessageCallback handler,
                            boolean force, Map<String, String> revpropTable,
                            CommitCallback callback)
             throws ClientException;

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNClient.java Wed Aug 17 18:25:07 2011
@@ -307,7 +307,9 @@ public class SVNClient implements ISVNCl
                                         boolean force)
             throws ClientException;
 
-    public native void propertySetRemote(String path, String name, byte[] value,
+    public native void propertySetRemote(String path, long baseRev,
+                                         String name, byte[] value,
+                                         CommitMessageCallback handler,
                                          boolean force,
                                          Map<String, String> revpropTable,
                                          CommitCallback callback)

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/SVNClient.java
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/SVNClient.java?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/SVNClient.java (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/src/org/tigris/subversion/javahl/SVNClient.java Wed Aug 17 18:25:07 2011
@@ -1878,8 +1878,12 @@ public class SVNClient implements SVNCli
         {
             if (Path.isURL(path))
             {
-                aSVNClient.propertySetRemote(path, name,
+                Info2[] infos = info2(path, Revision.HEAD, Revision.HEAD,
+                                      false);
+
+                aSVNClient.propertySetRemote(path, infos[0].getRev(), name,
                                        value == null ? null : value.getBytes(),
+                                       cachedHandler,
                                        force, revpropTable, null);
             }
             else

Modified: subversion/branches/issue-3975/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original)
+++ subversion/branches/issue-3975/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Wed Aug 17 18:25:07 2011
@@ -130,6 +130,35 @@ public class BasicTests extends SVNTests
     }
 
     /**
+     * Test the JNIError class functionality
+     * @throws Throwable
+     */
+    public void testJNIError() throws Throwable
+    {
+        // build the test setup.
+        OneTest thisTest = new OneTest();
+
+        // Create a client, dispose it, then try to use it later
+        ISVNClient tempclient = new SVNClient();
+        tempclient.dispose();
+
+        // create Y and Y/Z directories in the repository
+        addExpectedCommitItem(null, thisTest.getUrl().toString(), "Y", NodeKind.none,
+                              CommitItemStateFlags.Add);
+        Set<String> urls = new HashSet<String>(1);
+        urls.add(thisTest.getUrl() + "/Y");
+        try 
+        {
+            tempclient.mkdir(urls, false, null, new ConstMsg("log_msg"), null);
+        } 
+        catch(JNIError e)
+        {
+	        return; // Test passes!
+        }
+        fail("A JNIError should have been thrown here.");
+    }
+
+    /**
      * Tests Mergeinfo and RevisionRange classes.
      * @since 1.5
      */
@@ -3081,6 +3110,53 @@ public class BasicTests extends SVNTests
     }
 
     /**
+     * Test the basic SVNClient.propertySetRemote functionality.
+     * @throws Throwable
+     */
+    public void testPropEdit() throws Throwable
+    {
+        final String PROP = "abc";
+        final byte[] VALUE = new String("def").getBytes();
+        final byte[] NEWVALUE = new String("newvalue").getBytes();
+        // create the test working copy
+        OneTest thisTest = new OneTest();
+
+        Set<String> pathSet = new HashSet<String>();
+        // set a property on A/D/G/rho file
+        pathSet.clear();
+        pathSet.add(thisTest.getWCPath()+"/A/D/G/rho");
+        client.propertySetLocal(pathSet, PROP, VALUE,
+                                Depth.infinity, null, false);
+        thisTest.getWc().setItemPropStatus("A/D/G/rho", Status.Kind.modified);
+
+        // test the status of the working copy
+        thisTest.checkStatus();
+
+        // commit the changes
+        checkCommitRevision(thisTest, "wrong revision number from commit", 2,
+                            thisTest.getWCPathSet(), "log msg", Depth.infinity,
+                            false, false, null, null);
+
+        thisTest.getWc().setItemPropStatus("A/D/G/rho", Status.Kind.normal);
+
+        // check the status of the working copy
+        thisTest.checkStatus();
+        
+        // now edit the propval directly in the repository
+        long baseRev = 2L;
+        client.propertySetRemote(thisTest.getUrl()+"/A/D/G/rho", baseRev, PROP, NEWVALUE,
+                                 new ConstMsg("edit prop"), false, null, null);
+        
+        // update the WC and verify that the property was changed
+        client.update(thisTest.getWCPathSet(), Revision.HEAD, Depth.infinity, false, false,
+                      false, false);
+        byte[] propVal = client.propertyGet(thisTest.getWCPath()+"/A/D/G/rho", PROP, null, null);
+
+        assertEquals(new String(propVal), new String(NEWVALUE));
+
+    }
+
+    /**
      * Test tolerance of unversioned obstructions when adding paths with
      * {@link org.apache.subversion.javahl.SVNClient#checkout()},
      * {@link org.apache.subversion.javahl.SVNClient#update()}, and

Modified: subversion/branches/issue-3975/subversion/bindings/swig/python/svn/repos.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/swig/python/svn/repos.py?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/swig/python/svn/repos.py (original)
+++ subversion/branches/issue-3975/subversion/bindings/swig/python/svn/repos.py Wed Aug 17 18:25:07 2011
@@ -72,12 +72,28 @@ class ChangedPath:
 
 
 class ChangeCollector(_svndelta.Editor):
-  """Available Since: 1.2.0
+  """An editor that, when driven, walks a revision or a transaction and
+  incrementally invokes a callback with ChangedPath instances corresponding to
+  paths changed in that revision.
+
+  Available Since: 1.2.0
   """
 
   # BATON FORMAT: [path, base_path, base_rev]
 
   def __init__(self, fs_ptr, root, pool=None, notify_cb=None):
+    """Construct a walker over the svn_fs_root_t ROOT, which must
+    be in the svn_fs_t FS_PTR.  Invoke NOTIFY_CB with a single argument
+    of type ChangedPath for each change under ROOT.
+
+    At this time, two ChangedPath objects will be passed for a path that had
+    been replaced in the revision/transaction.  This may change in the future.
+  
+    ### Can't we deduce FS_PTR from ROOT?
+
+    ### POOL is unused
+    """
+
     self.fs_ptr = fs_ptr
     self.changes = { } # path -> ChangedPathEntry()
     self.roots = { } # revision -> svn_svnfs_root_t
@@ -136,9 +152,9 @@ class ChangeCollector(_svndelta.Editor):
     self.changes[path] = ChangedPath(item_type,
                                      False,
                                      False,
-                                     base_path,
+                                     base_path,       # base_path
                                      parent_baton[2], # base_rev
-                                     None,            # (new) path
+                                     path,            # path
                                      False,           # added
                                      CHANGE_ACTION_DELETE,
                                      )

Modified: subversion/branches/issue-3975/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py (original)
+++ subversion/branches/issue-3975/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py Wed Aug 17 18:25:07 2011
@@ -407,7 +407,7 @@ class SubversionChangeset(Changeset):
                 else:
                     base_path = None
             action = ''
-            if not change.path:
+            if change.action == repos.CHANGE_ACTION_DELETE:
                 action = Changeset.DELETE
                 deletions[change.base_path] = idx
             elif change.added:

Modified: subversion/branches/issue-3975/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/include/svn_client.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/include/svn_client.h (original)
+++ subversion/branches/issue-3975/subversion/include/svn_client.h Wed Aug 17 18:25:07 2011
@@ -2207,18 +2207,38 @@ typedef struct svn_client_status_t
   const void *backwards_compatibility_baton;
 
   /** Set to the local absolute path that this node was moved from, if this
-   * file or directory has been moved here locally. */
+   * file or directory has been moved here locally and is the root of that
+   * move. Otherwise set to NULL.
+   *
+   * This will be NULL for moved-here nodes that are just part of a subtree
+   * that was moved along (and are not themselves a root of a different move
+   * operation).
+   * 
+   * @since New in 1.8. */
   const char *moved_from_abspath;
 
   /** Set to the local absolute path that this node was moved to, if this file
-   * or directory has been moved away locally. */
+   * or directory has been moved away locally and corresponds to the root
+   * of the destination side of the move. Otherwise set to NULL.
+   *
+   * Note: Saying just "root" here could be misleading. For example:
+   *   svn mv A AA;
+   *   svn mv AA/B BB;
+   * creates a situation where A/B is moved-to BB, but one could argue that
+   * the move source's root actually was AA/B. Note that, as far as the
+   * working copy is concerned, above case is exactly identical to:
+   *   svn mv A/B BB;
+   *   svn mv A AA;
+   * In both situations, @a moved_to_abspath would be set for nodes A (moved
+   * to AA) and A/B (moved to BB), only.
+   *
+   * This will be NULL for moved-away nodes that were just part of a subtree
+   * that was moved along (and are not themselves a root of a different move
+   * operation).
+   *
+   * @since New in 1.8. */
   const char *moved_to_abspath;
 
-  /* If this file or directory has been moved away locally, set this to the
-   * local absolute path that was the root of the move-away, i.e. to the
-   * op-root of the delete-half of the move operation. */
-  const char *moved_to_op_root_abspath;
-
   /* NOTE! Please update svn_client_status_dup() when adding new fields here. */
 } svn_client_status_t;
 

Modified: subversion/branches/issue-3975/subversion/include/svn_ra.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/include/svn_ra.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/include/svn_ra.h (original)
+++ subversion/branches/issue-3975/subversion/include/svn_ra.h Wed Aug 17 18:25:07 2011
@@ -1695,7 +1695,8 @@ svn_ra_get_file_revs(svn_ra_session_t *s
 /**
  * Lock each path in @a path_revs, which is a hash whose keys are the
  * paths to be locked, and whose values are the corresponding base
- * revisions for each path.
+ * revisions for each path.  The keys are (const char *) and the
+ * revisions are (svn_revnum_t *).
  *
  * Note that locking is never anonymous, so any server implementing
  * this function will have to "pull" a username from the client, if

Modified: subversion/branches/issue-3975/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/include/svn_wc.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/include/svn_wc.h (original)
+++ subversion/branches/issue-3975/subversion/include/svn_wc.h Wed Aug 17 18:25:07 2011
@@ -1755,7 +1755,7 @@ typedef struct svn_wc_conflict_descripti
   /** Info on the "merge-right source" or "their" version of incoming change. */
   const svn_wc_conflict_version_t *src_right_version;
 
-  /* Remember to adjust svn_wc__conflict_description_dup()
+  /* Remember to adjust svn_wc__conflict_description2_dup()
    * if you add new fields to this struct. */
 } svn_wc_conflict_description2_t;
 
@@ -1849,8 +1849,6 @@ typedef struct svn_wc_conflict_descripti
    * @since New in 1.6. */
   svn_wc_conflict_version_t *src_right_version;
 
-  /* Remember to adjust svn_wc__conflict_description_dup()
-   * if you add new fields to this struct. */
 } svn_wc_conflict_description_t;
 
 /**
@@ -3620,18 +3618,38 @@ typedef struct svn_wc_status3_t
   /** @} */
 
   /** Set to the local absolute path that this node was moved from, if this
-   * file or directory has been moved here locally. */
+   * file or directory has been moved here locally and is the root of that
+   * move. Otherwise set to NULL.
+   *
+   * This will be NULL for moved-here nodes that are just part of a subtree
+   * that was moved along (and are not themselves a root of a different move
+   * operation).
+   * 
+   * @since New in 1.8. */
   const char *moved_from_abspath;
 
   /** Set to the local absolute path that this node was moved to, if this file
-   * or directory has been moved away locally. */
+   * or directory has been moved away locally and corresponds to the root
+   * of the destination side of the move. Otherwise set to NULL.
+   *
+   * Note: Saying just "root" here could be misleading. For example:
+   *   svn mv A AA;
+   *   svn mv AA/B BB;
+   * creates a situation where A/B is moved-to BB, but one could argue that
+   * the move source's root actually was AA/B. Note that, as far as the
+   * working copy is concerned, above case is exactly identical to:
+   *   svn mv A/B BB;
+   *   svn mv A AA;
+   * In both situations, @a moved_to_abspath would be set for nodes A (moved
+   * to AA) and A/B (moved to BB), only.
+   *
+   * This will be NULL for moved-away nodes that were just part of a subtree
+   * that was moved along (and are not themselves a root of a different move
+   * operation).
+   *
+   * @since New in 1.8. */
   const char *moved_to_abspath;
 
-  /* If this file or directory has been moved away locally, set this to the
-   * local absolute path that was the root of the move-away, i.e. to the
-   * op-root of the delete-half of the move operation. */
-  const char *moved_to_op_root_abspath;
-
   /* NOTE! Please update svn_wc_dup_status3() when adding new fields here. */
 } svn_wc_status3_t;
 

Modified: subversion/branches/issue-3975/subversion/libsvn_client/cat.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/cat.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/cat.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/cat.c Wed Aug 17 18:25:07 2011
@@ -50,6 +50,7 @@ svn_client__get_normalized_stream(svn_st
                                   const char *local_abspath,
                                   const svn_opt_revision_t *revision,
                                   svn_boolean_t expand_keywords,
+                                  svn_boolean_t normalize_eols,
                                   svn_cancel_func_t cancel_func,
                                   void *cancel_baton,
                                   apr_pool_t *result_pool,
@@ -163,8 +164,10 @@ svn_client__get_normalized_stream(svn_st
 
   /* Wrap the output stream if translation is needed. */
   if (eol != NULL || kw != NULL)
-    input = svn_subst_stream_translated(input, eol, FALSE, kw, expand_keywords,
-                                        result_pool);
+    input = svn_subst_stream_translated(
+      input,
+      (eol_style && normalize_eols) ? SVN_SUBST_NATIVE_EOL_STR : eol,
+      FALSE, kw, expand_keywords, result_pool);
 
   *normal_stream = input;
 
@@ -211,7 +214,7 @@ svn_client_cat2(svn_stream_t *out,
 
       SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
       SVN_ERR(svn_client__get_normalized_stream(&normal_stream, ctx->wc_ctx,
-                                            local_abspath, revision, TRUE,
+                                            local_abspath, revision, TRUE, FALSE,
                                             ctx->cancel_func, ctx->cancel_baton,
                                             pool, pool));
 

Modified: subversion/branches/issue-3975/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/client.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/client.h (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/client.h Wed Aug 17 18:25:07 2011
@@ -1051,13 +1051,21 @@ svn_client__ensure_revprop_table(apr_has
 
 /* Return a potentially translated version of local file LOCAL_ABSPATH
    in NORMAL_STREAM.  REVISION must be one of the following: BASE, COMMITTED,
-   WORKING.  Uses SCRATCH_POOL for temporary allocations. */
+   WORKING.
+
+   EXPAND_KEYWORDS operates as per the EXPAND argument to
+   svn_subst_stream_translated, which see.  If NORMALIZE_EOLS is TRUE and
+   LOCAL_ABSPATH requires translation, then normalize the line endings in
+   *NORMAL_STREAM.
+
+   Uses SCRATCH_POOL for temporary allocations. */
 svn_error_t *
 svn_client__get_normalized_stream(svn_stream_t **normal_stream,
                                   svn_wc_context_t *wc_ctx,
                                   const char *local_abspath,
                                   const svn_opt_revision_t *revision,
                                   svn_boolean_t expand_keywords,
+                                  svn_boolean_t normalize_eols,
                                   svn_cancel_func_t cancel_func,
                                   void *cancel_baton,
                                   apr_pool_t *result_pool,

Modified: subversion/branches/issue-3975/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/merge.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/merge.c Wed Aug 17 18:25:07 2011
@@ -1854,7 +1854,7 @@ files_same_p(svn_boolean_t *same,
       /* Compare the file content, translating 'mine' to 'normal' form. */
       SVN_ERR(svn_client__get_normalized_stream(&mine_stream, wc_ctx,
                                                 mine_abspath, &working_rev,
-                                                FALSE, NULL, NULL,
+                                                FALSE, TRUE, NULL, NULL,
                                                 scratch_pool, scratch_pool));
 
       SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath,

Modified: subversion/branches/issue-3975/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/repos_diff.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/repos_diff.c Wed Aug 17 18:25:07 2011
@@ -1086,7 +1086,13 @@ close_file(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An svn_delta_editor_t function.  */
+/* Report any accumulated prop changes via the 'dir_props_changed' callback,
+ * and then call the 'dir_closed' callback.  Notify about any deleted paths
+ * within this directory that have not already been notified, and then about
+ * this directory itself (unless it was added, in which case the notification
+ * was done at that time).
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 close_directory(void *dir_baton,
                 apr_pool_t *pool)
@@ -1110,6 +1116,7 @@ close_directory(void *dir_baton,
   if (!b->added && b->propchanges->nelts > 0)
     remove_non_prop_changes(b->pristine_props, b->propchanges);
 
+  /* Report any prop changes. */
   if (b->propchanges->nelts > 0)
     {
       svn_boolean_t tree_conflicted = FALSE;
@@ -1134,8 +1141,8 @@ close_directory(void *dir_baton,
                                          b->edit_baton->diff_cmd_baton,
                                          scratch_pool));
 
-  /* Don't notify added directories as they triggered notification
-     in add_directory. */
+  /* Notify about any deleted paths within this directory that have not
+   * already been notified. */
   if (!skipped && !b->added && eb->notify_func)
     {
       apr_hash_index_t *hi;
@@ -1157,6 +1164,8 @@ close_directory(void *dir_baton,
         }
     }
 
+  /* Notify about this directory itself (unless it was added, in which
+   * case the notification was done at that time). */
   if (!b->added && eb->notify_func)
     {
       svn_wc_notify_t *notify;
@@ -1188,7 +1197,9 @@ close_directory(void *dir_baton,
 }
 
 
-/* An svn_delta_editor_t function.  */
+/* Record a prop change, which we will report later in close_file().
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -1209,7 +1220,9 @@ change_file_prop(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An svn_delta_editor_t function.  */
+/* Make a note of this prop change, to be reported when the dir is closed.
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_dir_prop(void *dir_baton,
                 const char *name,
@@ -1243,7 +1256,8 @@ close_edit(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* An svn_delta_editor_t function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_directory(const char *path,
                  void *parent_baton,
@@ -1272,7 +1286,8 @@ absent_directory(const char *path,
 }
 
 
-/* An svn_delta_editor_t function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_file(const char *path,
             void *parent_baton,

Modified: subversion/branches/issue-3975/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/status.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/status.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/status.c Wed Aug 17 18:25:07 2011
@@ -570,10 +570,6 @@ svn_client_status_dup(const svn_client_s
   if (status->moved_to_abspath)
     st->moved_to_abspath = apr_pstrdup(result_pool, status->moved_to_abspath);
 
-  if (status->moved_to_op_root_abspath)
-    st->moved_to_op_root_abspath =
-      apr_pstrdup(result_pool, status->moved_to_op_root_abspath);
-
   return st;
 }
 
@@ -680,7 +676,6 @@ svn_client__create_status(svn_client_sta
 
   (*cst)->moved_from_abspath = status->moved_from_abspath;
   (*cst)->moved_to_abspath = status->moved_to_abspath;
-  (*cst)->moved_to_op_root_abspath = status->moved_to_op_root_abspath;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/issue-3975/subversion/libsvn_ra_serf/locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_ra_serf/locks.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_ra_serf/locks.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_ra_serf/locks.c Wed Aug 17 18:25:07 2011
@@ -580,6 +580,8 @@ svn_ra_serf__lock(svn_ra_session_t *ra_s
 
   subpool = svn_pool_create(pool);
 
+  /* ### TODO for issue 2263: Send all the locks over the wire at once.  This
+     loop is just a temporary shim. */
   for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
     {
       svn_ra_serf__handler_t *handler;
@@ -683,6 +685,8 @@ svn_ra_serf__unlock(svn_ra_session_t *ra
 
   subpool = svn_pool_create(pool);
 
+  /* ### TODO for issue 2263: Send all the locks over the wire at once.  This
+     loop is just a temporary shim. */
   for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
     {
       svn_ra_serf__handler_t *handler;

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/adm_ops.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/adm_ops.c Wed Aug 17 18:25:07 2011
@@ -29,6 +29,7 @@
 
 
 #include <string.h>
+#include <stdlib.h>
 
 #include <apr_pools.h>
 #include <apr_tables.h>
@@ -1291,6 +1292,186 @@ remove_conflict_file(svn_boolean_t *noti
 }
 
 
+/* Remove the reverted copied file at LOCAL_ABSPATH from disk if it was
+ * not modified after being copied. Use FILESIZE and PRISTINE_CHECKSUM to
+ * detect modification.
+ * If NEW_KIND is not NULL, return the resulting on-disk kind of the node
+ * at LOCAL_ABSPATH in *NEW_KIND. */
+static svn_error_t *
+revert_restore_handle_copied_file(svn_node_kind_t *new_kind,
+                                  svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  svn_filesize_t filesize,
+                                  const svn_checksum_t *pristine_checksum,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_stream_t *pristine_stream;
+  svn_filesize_t pristine_size;
+  svn_boolean_t has_text_mods;
+
+  if (new_kind)
+    *new_kind = svn_node_file;
+
+  SVN_ERR(svn_wc__db_pristine_read(&pristine_stream, &pristine_size,
+                                   db, local_abspath, pristine_checksum,
+                                   scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__compare_file_with_pristine(&has_text_mods, db,
+                                             local_abspath,
+                                             filesize,
+                                             pristine_stream,
+                                             pristine_size,
+                                             FALSE, FALSE, FALSE,
+                                             scratch_pool));
+
+  if (!has_text_mods)
+    {
+      SVN_ERR(svn_io_remove_file2(local_abspath, FALSE, scratch_pool));
+      if (new_kind)
+        *new_kind = svn_node_none;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Sort copied children obtained from the revert list based on
+ * their paths in descending order (longest paths first). */
+static int
+compare_revert_list_copied_children(const void *a, const void *b)
+{
+  const svn_wc__db_revert_list_copied_child_info_t *ca = a;
+  const svn_wc__db_revert_list_copied_child_info_t *cb = b;
+  int i;
+
+  i = svn_path_compare_paths(ca->abspath, cb->abspath);
+
+  /* Reverse the result of svn_path_compare_paths() to achieve
+   * descending order. */
+  return -i;
+}
+
+
+/* Remove as many reverted copied children as possible from the directory at
+ * LOCAL_ABSPATH. If REMOVE_SELF is TRUE, also remove LOCAL_ABSPATH itself
+ * if possible (REMOVE_SELF should be set if LOCAL_ABSPATH is itself a
+ * reverted copy).
+ *
+ * All reverted copied file children not modified after being copied are
+ * removed from disk. Reverted copied directories left empty as a result
+ * are also removed from disk.
+ *
+ * If NEW_KIND is not NULL, return the resulting on-disk kind of the node
+ * at LOCAL_ABSPATH in *NEW_KIND. */
+static svn_error_t *
+revert_restore_handle_copied_dirs(svn_node_kind_t *new_kind,
+                                  svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  svn_boolean_t remove_self,
+                                  svn_cancel_func_t cancel_func,
+                                  void *cancel_baton,
+                                  apr_pool_t *scratch_pool)
+{
+  const apr_array_header_t *copied_children;
+  svn_wc__db_revert_list_copied_child_info_t *child_info;
+  int i;
+  apr_finfo_t finfo;
+  apr_pool_t *iterpool;
+  svn_error_t *err;
+
+  if (new_kind)
+    *new_kind = svn_node_dir;
+
+  SVN_ERR(svn_wc__db_revert_list_read_copied_children(&copied_children,
+                                                      db, local_abspath,
+                                                      scratch_pool,
+                                                      scratch_pool));
+  iterpool = svn_pool_create(scratch_pool);
+
+  /* Remove all file children, if possible. */
+  for (i = 0; i < copied_children->nelts; i++)
+    {
+      child_info = APR_ARRAY_IDX(
+                     copied_children, i,
+                     svn_wc__db_revert_list_copied_child_info_t *);
+
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+
+      if (child_info->kind != svn_wc__db_kind_file)
+        continue;
+
+      svn_pool_clear(iterpool);
+
+      err = svn_io_stat(&finfo, child_info->abspath,
+                        APR_FINFO_TYPE | APR_FINFO_SIZE,
+                        iterpool);
+      if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
+        {
+          svn_error_clear(err);
+          continue;
+        }
+      else
+        SVN_ERR(err);
+
+      if (finfo.filetype != APR_REG)
+        continue;
+
+      SVN_ERR(revert_restore_handle_copied_file(NULL, db, child_info->abspath,
+                                                finfo.size,
+                                                child_info->pristine_checksum,
+                                                iterpool));
+    }
+
+  /* Try to delete every child directory, ignoring errors.
+   * This is a bit crude but good enough for our purposes.
+   *
+   * We cannot delete children recursively since we want to keep any files
+   * that still exist on disk. So sort the children list such that longest
+   * paths come first and try to remove each child directory in order. */
+  qsort(copied_children->elts, copied_children->nelts,
+        sizeof(svn_wc__db_revert_list_copied_child_info_t *),
+        compare_revert_list_copied_children);
+  for (i = 0; i < copied_children->nelts; i++)
+    {
+      child_info = APR_ARRAY_IDX(
+                     copied_children, i,
+                     svn_wc__db_revert_list_copied_child_info_t *);
+
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+
+      if (child_info->kind != svn_wc__db_kind_dir)
+        continue;
+
+      svn_pool_clear(iterpool);
+
+      svn_error_clear(svn_io_dir_remove_nonrecursive(child_info->abspath,
+                                                     iterpool));
+    }
+
+  if (remove_self)
+    {
+      apr_hash_t *remaining_children;
+
+      /* Delete LOCAL_ABSPATH itself if no children are left. */
+      SVN_ERR(svn_io_get_dirents3(&remaining_children, local_abspath, TRUE,
+                                  iterpool, iterpool));
+      if (apr_hash_count(remaining_children) == 0)
+        {
+          SVN_ERR(svn_io_remove_dir2(local_abspath, FALSE, NULL, NULL,
+                                     iterpool));
+          if (new_kind)
+            *new_kind = svn_node_none;
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Make the working tree under LOCAL_ABSPATH to depth DEPTH match the
    versioned tree.  This function is called after svn_wc__db_op_revert
    has done the database revert and created the revert list.  Notifies
@@ -1321,6 +1502,9 @@ revert_restore(svn_wc__db_t *db,
 #ifdef HAVE_SYMLINK
   svn_boolean_t special;
 #endif
+  svn_boolean_t copied_here;
+  svn_wc__db_kind_t reverted_kind;
+  const svn_checksum_t *pristine_checksum;
 
   if (cancel_func)
     SVN_ERR(cancel_func(cancel_baton));
@@ -1328,6 +1512,8 @@ revert_restore(svn_wc__db_t *db,
   SVN_ERR(svn_wc__db_revert_list_read(&notify_required,
                                       &conflict_old, &conflict_new,
                                       &conflict_working, &prop_reject,
+                                      &copied_here, &reverted_kind,
+                                      &pristine_checksum,
                                       db, local_abspath,
                                       scratch_pool, scratch_pool));
 
@@ -1342,17 +1528,21 @@ revert_restore(svn_wc__db_t *db,
     {
       svn_error_clear(err);
 
-      if (notify_func && notify_required)
-        notify_func(notify_baton,
-                    svn_wc_create_notify(local_abspath, svn_wc_notify_revert,
-                                         scratch_pool),
-                    scratch_pool);
-
-      if (notify_func)
-        SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
-                                              db, local_abspath,
-                                              scratch_pool));
-      return SVN_NO_ERROR;
+      if (!copied_here)
+        {
+          if (notify_func && notify_required)
+            notify_func(notify_baton,
+                        svn_wc_create_notify(local_abspath,
+                                             svn_wc_notify_revert,
+                                             scratch_pool),
+                        scratch_pool);
+
+          if (notify_func)
+            SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
+                                                  db, local_abspath,
+                                                  scratch_pool));
+          return SVN_NO_ERROR;
+        }
     }
   else if (err)
     return svn_error_trace(err);
@@ -1387,6 +1577,21 @@ revert_restore(svn_wc__db_t *db,
 #endif
     }
 
+  if (copied_here)
+    {
+      /* The revert target itself is the op-root of a copy. */
+      if (reverted_kind == svn_wc__db_kind_file && on_disk == svn_node_file)
+        SVN_ERR(revert_restore_handle_copied_file(&on_disk, db, local_abspath,
+                                                  finfo.size,
+                                                  pristine_checksum,
+                                                  scratch_pool));
+      else if (reverted_kind == svn_wc__db_kind_dir && on_disk == svn_node_dir)
+        SVN_ERR(revert_restore_handle_copied_dirs(&on_disk, db, local_abspath,
+                                                  TRUE, 
+                                                  cancel_func, cancel_baton,
+                                                  scratch_pool));
+    }
+
   /* If we expect a versioned item to be present then check that any
      item on disk matches the versioned item, if it doesn't match then
      fix it or delete it.  */
@@ -1567,6 +1772,10 @@ revert_restore(svn_wc__db_t *db,
       const apr_array_header_t *children;
       int i;
 
+      SVN_ERR(revert_restore_handle_copied_dirs(NULL, db, local_abspath, FALSE,
+                                                cancel_func, cancel_baton,
+                                                iterpool));
+
       SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
                                                        local_abspath,
                                                        scratch_pool,

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/questions.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/questions.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/questions.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/questions.c Wed Aug 17 18:25:07 2011
@@ -79,38 +79,17 @@
 */
 
 
-/* Set *MODIFIED_P to TRUE if (after translation) VERSIONED_FILE_ABSPATH
- * (of VERSIONED_FILE_SIZE bytes) differs from PRISTINE_STREAM (of
- * PRISTINE_SIZE bytes), else to FALSE if not.
- *
- * If EXACT_COMPARISON is FALSE, translate VERSIONED_FILE_ABSPATH's EOL
- * style and keywords to repository-normal form according to its properties,
- * and compare the result with PRISTINE_STREAM.  If EXACT_COMPARISON is
- * TRUE, translate PRISTINE_STREAM's EOL style and keywords to working-copy
- * form according to VERSIONED_FILE_ABSPATH's properties, and compare the
- * result with VERSIONED_FILE_ABSPATH.
- *
- * HAS_PROPS should be TRUE if the file had properties when it was not
- * modified, otherwise FALSE.
- *
- * PROPS_MOD should be TRUE if the file's properties have been changed,
- * otherwise FALSE.
- *
- * PRISTINE_STREAM will be closed before a successful return.
- *
- * DB is a wc_db; use SCRATCH_POOL for temporary allocation.
- */
-static svn_error_t *
-compare_and_verify(svn_boolean_t *modified_p,
-                   svn_wc__db_t *db,
-                   const char *versioned_file_abspath,
-                   svn_filesize_t versioned_file_size,
-                   svn_stream_t *pristine_stream,
-                   svn_filesize_t pristine_size,
-                   svn_boolean_t has_props,
-                   svn_boolean_t props_mod,
-                   svn_boolean_t exact_comparison,
-                   apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__compare_file_with_pristine(svn_boolean_t *modified_p,
+                                   svn_wc__db_t *db,
+                                   const char *versioned_file_abspath,
+                                   svn_filesize_t versioned_file_size,
+                                   svn_stream_t *pristine_stream,
+                                   svn_filesize_t pristine_size,
+                                   svn_boolean_t has_props,
+                                   svn_boolean_t props_mod,
+                                   svn_boolean_t exact_comparison,
+                                   apr_pool_t *scratch_pool)
 {
   svn_boolean_t same;
   svn_subst_eol_style_t eol_style;
@@ -337,12 +316,12 @@ svn_wc__internal_file_modified_p(svn_boo
   /* Check all bytes, and verify checksum if requested. */
   {
     svn_error_t *err;
-    err = compare_and_verify(modified_p, db,
-                             local_abspath, dirent->filesize,
-                             pristine_stream, pristine_size,
-                             has_props, props_mod,
-                             exact_comparison,
-                             scratch_pool);
+    err = svn_wc__compare_file_with_pristine(modified_p, db,
+                                             local_abspath, dirent->filesize,
+                                             pristine_stream, pristine_size,
+                                             has_props, props_mod,
+                                             exact_comparison,
+                                             scratch_pool);
 
     /* At this point we already opened the pristine file, so we know that
        the access denied applies to the working copy path */

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/status.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/status.c Wed Aug 17 18:25:07 2011
@@ -273,6 +273,68 @@ read_info(const struct svn_wc__db_info_t
                                        &mtb->lock, NULL, NULL,
                                        db, local_abspath,
                                        result_pool, scratch_pool));
+
+      if (mtb->status == svn_wc__db_status_deleted)
+        {
+          const char *moved_to_abspath;
+          const char *moved_to_op_root_abspath;
+          
+          /* NOTE: we can't use op-root-ness as a condition here since a base
+           * node can be the root of a move and still not be an explicit
+           * op-root (having a working node with op_depth == pathelements).
+           *
+           * Both these (almost identical) situations showcase this:
+           *   svn mv a/b bb
+           *   svn del a
+           * and
+           *   svn mv a aa  
+           *   svn mv aa/b bb
+           * In both, 'bb' is moved from 'a/b', but 'a/b' has no op_depth>0
+           * node at all, as its parent 'a' is locally deleted. */
+
+          SVN_ERR(svn_wc__db_scan_deletion(NULL,
+                                           &moved_to_abspath,
+                                           NULL,
+                                           &moved_to_op_root_abspath,
+                                           db, local_abspath,
+                                           scratch_pool, scratch_pool));
+          if (moved_to_abspath != NULL
+              && moved_to_op_root_abspath != NULL
+              && strcmp(moved_to_abspath, moved_to_op_root_abspath) == 0)
+            {
+              mtb->moved_to_abspath = apr_pstrdup(result_pool,
+                                                  moved_to_abspath);
+            }
+          /* ### ^^^ THIS SUCKS. For at least two reasons:
+           * 1) We scan the node deletion and that's technically not necessary.
+           *    We'd be fine to know if this is an actual root of a move.
+           * 2) From the elaborately calculated results, we backwards-guess
+           *    whether this is a root.
+           * It works ok, and this code only gets called when a node is an
+           * explicit target of a 'status'. But it would be better to do this
+           * differently.
+           * We could return moved-to via svn_wc__db_base_get_info() (called
+           * just above), but as moved-to is only intended to be returned for
+           * roots of a move, that doesn't fit too well. */
+        }
+    }
+
+  /* ### svn_wc__db_read_info() could easily return the moved-here flag. But
+   * for now... (The per-dir query for recursive status is far more optimal.)
+   * Note that this actually scans around to get the full path, for a bool.
+   * This bool then gets returned, later is evaluated, and if true leads to
+   * the same paths being scanned again. We'd want to obtain this bool here as
+   * cheaply as svn_wc__db_read_children_info() does. */
+  if (mtb->status == svn_wc__db_status_added)
+    {
+      const char *moved_from_abspath = NULL;
+      SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL,
+                                       &moved_from_abspath,
+                                       NULL,
+                                       db, local_abspath,
+                                       result_pool, scratch_pool));
+      mtb->moved_here = (moved_from_abspath != NULL);
     }
 
   mtb->has_checksum = (checksum != NULL);
@@ -404,8 +466,6 @@ assemble_status(svn_wc_status3_t **statu
   const char *repos_root_url;
   const char *repos_uuid;
   const char *moved_from_abspath = NULL;
-  const char *moved_to_abspath = NULL;
-  const char *moved_to_op_root_abspath = NULL;
   svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
                                 ? dirent->filesize
                                 : SVN_INVALID_FILESIZE;
@@ -426,17 +486,13 @@ assemble_status(svn_wc_status3_t **statu
       /* A node is switched if it doesn't have the implied repos_relpath */
       const char *name = svn_relpath_skip_ancestor(parent_repos_relpath,
                                                    info->repos_relpath);
-      switched_p = !name || (strcmp(name, svn_dirent_basename(local_abspath, NULL)) != 0);
+      switched_p = !name || (strcmp(name,
+                                    svn_dirent_basename(local_abspath, NULL))
+                             != 0);
     }
 
-  /* Examine whether our target is missing or obstructed.
-
-     While we are not completely in single-db mode yet, data about
-     obstructed or missing nodes might be incomplete here. This is
-     reported by svn_wc_db_status_obstructed_XXXX. In single-db
-     mode these obstructions are no longer reported and we have
-     to detect obstructions by looking at the on disk status in DIRENT.
-     */
+  /* Examine whether our target is missing or obstructed. To detect
+   * obstructions, we have to look at the on-disk status in DIRENT. */
   if (info->kind == svn_wc__db_kind_dir)
     {
       if (info->status == svn_wc__db_status_incomplete)
@@ -608,26 +664,20 @@ assemble_status(svn_wc_status3_t **statu
               else if (schedule == svn_wc_schedule_replace)
                 node_status = svn_wc_status_replaced;
             }
+
+          /* Get moved-from info (only for potential op-roots of a move). */
+          if (node_status == svn_wc_status_added
+              && info->moved_here
+              && info->op_root)
+            SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
+                                             NULL, NULL, NULL, NULL,
+                                             &moved_from_abspath,
+                                             NULL,
+                                             db, local_abspath,
+                                             result_pool, scratch_pool));
         }
     }
 
-  /* Get moved-to info. */
-  if (info->status == svn_wc__db_status_deleted)
-    SVN_ERR(svn_wc__db_scan_deletion(NULL,
-                                     &moved_to_abspath,
-                                     NULL,
-                                     &moved_to_op_root_abspath,
-                                     db, local_abspath,
-                                     result_pool, scratch_pool));
-
-  /* Get moved-from info. */
-  if (info->status == svn_wc__db_status_added)
-    SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL,
-                                     &moved_from_abspath,
-                                     NULL,
-                                     db, local_abspath,
-                                     result_pool, scratch_pool));
 
   if (node_status == svn_wc_status_normal)
     node_status = text_status;
@@ -722,8 +772,7 @@ assemble_status(svn_wc_status3_t **statu
   stat->repos_uuid = repos_uuid;
 
   stat->moved_from_abspath = moved_from_abspath;
-  stat->moved_to_abspath = moved_to_abspath;
-  stat->moved_to_op_root_abspath = moved_to_op_root_abspath;
+  stat->moved_to_abspath = info->moved_to_abspath;
 
   *status = stat;
 
@@ -1082,8 +1131,8 @@ get_dir_status(const struct walk_status_
          don't all map the same types, but only the keys of the result
          hash are subsequently used. */
       SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
-                                        wb->db, local_abspath,
-                                        subpool, iterpool));
+                                            wb->db, local_abspath,
+                                            subpool, iterpool));
 
       all_children = apr_hash_overlay(subpool, nodes, dirents);
       if (apr_hash_count(conflicts) > 0)
@@ -2624,10 +2673,6 @@ svn_wc_dup_status3(const svn_wc_status3_
     new_stat->moved_to_abspath
       = apr_pstrdup(pool, orig_stat->moved_to_abspath);
 
-  if (orig_stat->moved_to_op_root_abspath)
-    new_stat->moved_to_op_root_abspath
-      = apr_pstrdup(pool, orig_stat->moved_to_op_root_abspath);
-
   /* Return the new hotness. */
   return new_stat;
 }

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc-metadata.sql?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc-metadata.sql Wed Aug 17 18:25:07 2011
@@ -316,8 +316,8 @@ CREATE TABLE NODES (
      BASE node, the location of the initial checkout.
 
      When op_depth != 0, they indicate where this node was copied/moved from.
-     In this case, the fields are set only on the root of the operation,
-     and are NULL for all children. */
+     In this case, the fields are set for the root of the operation and for all
+     children. */
   repos_id  INTEGER REFERENCES REPOSITORY (id),
   repos_path  TEXT,
   revision  INTEGER,

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc-queries.sql?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc-queries.sql Wed Aug 17 18:25:07 2011
@@ -119,7 +119,7 @@ WHERE wc_id = ?1 AND local_relpath = ?2 
 SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision,
   checksum, translated_size, changed_revision, changed_date, changed_author,
   depth, symlink_target, last_mod_time, properties, lock_token, lock_owner,
-  lock_comment, lock_date, local_relpath
+  lock_comment, lock_date, local_relpath, moved_here, moved_to
 FROM nodes
 LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id
   AND nodes.repos_path = lock.repos_relpath
@@ -1112,14 +1112,20 @@ CREATE TEMPORARY TABLE revert_list (
    conflict_working TEXT,
    prop_reject TEXT,
    notify INTEGER,         /* 1 if an actual row had props or tree conflict */
+   op_depth INTEGER,
+   repos_id INTEGER,
+   kind TEXT,
+   checksum TEXT,
    PRIMARY KEY (local_relpath, actual)
    );
 DROP TRIGGER IF EXISTS   trigger_revert_list_nodes;
 CREATE TEMPORARY TRIGGER trigger_revert_list_nodes
 BEFORE DELETE ON nodes
 BEGIN
-   INSERT OR REPLACE INTO revert_list(local_relpath, actual)
-   SELECT OLD.local_relpath, 0;
+   INSERT OR REPLACE INTO revert_list(local_relpath, actual, op_depth,
+                                      repos_id, kind, checksum)
+   SELECT OLD.local_relpath, 0, OLD.op_depth, OLD.repos_id, OLD.kind,
+          OLD.checksum;
 END;
 DROP TRIGGER IF EXISTS   trigger_revert_list_actual_delete;
 CREATE TEMPORARY TRIGGER trigger_revert_list_actual_delete
@@ -1156,11 +1162,20 @@ DROP TRIGGER IF EXISTS trigger_revert_li
 DROP TRIGGER IF EXISTS trigger_revert_list_actual_update
 
 -- STMT_SELECT_REVERT_LIST
-SELECT conflict_old, conflict_new, conflict_working, prop_reject, notify, actual
+SELECT conflict_old, conflict_new, conflict_working, prop_reject, notify,
+       actual, op_depth, repos_id, kind, checksum
 FROM revert_list
 WHERE local_relpath = ?1
 ORDER BY actual DESC
 
+-- STMT_SELECT_REVERT_LIST_COPIED_CHILDREN
+SELECT local_relpath, kind, checksum
+FROM revert_list
+WHERE local_relpath LIKE ?1 ESCAPE '#'
+  AND op_depth >= ?2
+  AND repos_id IS NOT NULL
+ORDER BY local_relpath
+
 -- STMT_DELETE_REVERT_LIST
 DELETE FROM revert_list WHERE local_relpath = ?1
 

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc.h (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc.h Wed Aug 17 18:25:07 2011
@@ -725,6 +725,39 @@ svn_wc__perform_file_merge(svn_skel_t **
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool);
 
+/* Set *MODIFIED_P to TRUE if (after translation) VERSIONED_FILE_ABSPATH
+ * (of VERSIONED_FILE_SIZE bytes) differs from PRISTINE_STREAM (of
+ * PRISTINE_SIZE bytes), else to FALSE if not.
+ *
+ * If EXACT_COMPARISON is FALSE, translate VERSIONED_FILE_ABSPATH's EOL
+ * style and keywords to repository-normal form according to its properties,
+ * and compare the result with PRISTINE_STREAM.  If EXACT_COMPARISON is
+ * TRUE, translate PRISTINE_STREAM's EOL style and keywords to working-copy
+ * form according to VERSIONED_FILE_ABSPATH's properties, and compare the
+ * result with VERSIONED_FILE_ABSPATH.
+ *
+ * HAS_PROPS should be TRUE if the file had properties when it was not
+ * modified, otherwise FALSE.
+ *
+ * PROPS_MOD should be TRUE if the file's properties have been changed,
+ * otherwise FALSE.
+ *
+ * PRISTINE_STREAM will be closed before a successful return.
+ *
+ * DB is a wc_db; use SCRATCH_POOL for temporary allocation.
+ */
+svn_error_t *
+svn_wc__compare_file_with_pristine(svn_boolean_t *modified_p,
+                                   svn_wc__db_t *db,
+                                   const char *versioned_file_abspath,
+                                   svn_filesize_t versioned_file_size,
+                                   svn_stream_t *pristine_stream,
+                                   svn_filesize_t pristine_size,
+                                   svn_boolean_t has_props,
+                                   svn_boolean_t props_mod,
+                                   svn_boolean_t exact_comparison,
+                                   apr_pool_t *scratch_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.c Wed Aug 17 18:25:07 2011
@@ -5471,6 +5471,9 @@ struct revert_list_read_baton {
   const char **conflict_new;
   const char **conflict_working;
   const char **prop_reject;
+  svn_boolean_t *copied_here;
+  svn_wc__db_kind_t *kind;
+  const svn_checksum_t **pristine_checksum;
   apr_pool_t *result_pool;
 };
 
@@ -5487,6 +5490,9 @@ revert_list_read(void *baton,
   *(b->reverted) = FALSE;
   *(b->conflict_new) = *(b->conflict_old) = *(b->conflict_working) = NULL;
   *(b->prop_reject) = NULL;
+  *(b->copied_here) = FALSE;
+  *(b->pristine_checksum) = NULL;
+  *(b->kind) = svn_wc__db_kind_unknown;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_REVERT_LIST));
@@ -5527,10 +5533,30 @@ revert_list_read(void *baton,
 
           SVN_ERR(svn_sqlite__step(&another_row, stmt));
           if (another_row)
-            *(b->reverted) = TRUE;
+            {
+              *(b->reverted) = TRUE;
+              *(b->kind) = svn_sqlite__column_token(stmt, 8,
+                                                    kind_map);
+              if (!svn_sqlite__column_is_null(stmt, 9))
+                SVN_ERR(svn_sqlite__column_checksum(b->pristine_checksum,
+                                                    stmt, 9,
+                                                    b->result_pool));
+            }
         }
       else
-        *(b->reverted) = TRUE;
+        {
+          *(b->reverted) = TRUE;
+          if (!svn_sqlite__column_is_null(stmt, 7))
+            {
+              apr_int64_t op_depth = svn_sqlite__column_int64(stmt, 6);
+              *(b->copied_here) = (op_depth == relpath_depth(local_relpath));
+            }
+          *(b->kind) = svn_sqlite__column_token(stmt, 8, kind_map);
+          if (!svn_sqlite__column_is_null(stmt, 9))
+            SVN_ERR(svn_sqlite__column_checksum(b->pristine_checksum,
+                                                stmt, 9, b->result_pool));
+        }
+
     }
   SVN_ERR(svn_sqlite__reset(stmt));
 
@@ -5551,6 +5577,9 @@ svn_wc__db_revert_list_read(svn_boolean_
                             const char **conflict_new,
                             const char **conflict_working,
                             const char **prop_reject,
+                            svn_boolean_t *copied_here,
+                            svn_wc__db_kind_t *kind,
+                            const svn_checksum_t **pristine_checksum,
                             svn_wc__db_t *db,
                             const char *local_abspath,
                             apr_pool_t *result_pool,
@@ -5560,6 +5589,7 @@ svn_wc__db_revert_list_read(svn_boolean_
   const char *local_relpath;
   struct revert_list_read_baton b = {reverted, conflict_old, conflict_new,
                                      conflict_working, prop_reject,
+                                     copied_here, kind, pristine_checksum,
                                      result_pool};
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
@@ -5571,6 +5601,85 @@ svn_wc__db_revert_list_read(svn_boolean_
   return SVN_NO_ERROR;
 }
 
+
+struct revert_list_read_copied_children_baton {
+  const apr_array_header_t **children;
+  apr_pool_t *result_pool;
+};
+
+static svn_error_t *
+revert_list_read_copied_children(void *baton,
+                                 svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 apr_pool_t *scratch_pool)
+{
+  struct revert_list_read_copied_children_baton *b = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_array_header_t *children;
+
+  children =
+    apr_array_make(b->result_pool, 0,
+                  sizeof(svn_wc__db_revert_list_copied_child_info_t *));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_REVERT_LIST_COPIED_CHILDREN));
+  SVN_ERR(svn_sqlite__bindf(stmt, "si",
+                            construct_like_arg(local_relpath, scratch_pool),
+                            relpath_depth(local_relpath)));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      svn_wc__db_revert_list_copied_child_info_t *child_info;
+      const char *child_relpath;
+
+      child_info = apr_palloc(b->result_pool, sizeof(*child_info));
+
+      child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+      child_info->abspath = svn_dirent_join(wcroot->abspath, child_relpath,
+                                            b->result_pool);
+      child_info->kind = svn_sqlite__column_token(stmt, 1, kind_map);
+      if (svn_sqlite__column_is_null(stmt, 2))
+        child_info->pristine_checksum = NULL;
+      else
+        SVN_ERR(svn_sqlite__column_checksum(&child_info->pristine_checksum,
+                                             stmt, 2, b->result_pool));
+       APR_ARRAY_PUSH(
+         children,
+         svn_wc__db_revert_list_copied_child_info_t *) = child_info;
+
+       SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+   SVN_ERR(svn_sqlite__reset(stmt));
+
+  *b->children = children;
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_revert_list_read_copied_children(const apr_array_header_t **children,
+                                            svn_wc__db_t *db,
+                                            const char *local_abspath,
+                                            apr_pool_t *result_pool,
+                                            apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  struct revert_list_read_copied_children_baton b = {children, result_pool};
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                              db, local_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath,
+                              revert_list_read_copied_children, &b,
+                              scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_wc__db_revert_list_notify(svn_wc_notify_func2_t notify_func,
                               void *notify_baton,
@@ -7038,18 +7147,27 @@ read_children_info(void *baton,
 
       if (op_depth == 0)
         {
+          const char *moved_to_relpath;
+
           child_item->info.have_base = TRUE;
 
-          /* Get the lock info. The query only reports lock info in the row at
-            * op_depth 0. */
-          if (op_depth == 0)
-            child_item->info.lock = lock_from_columns(stmt, 15, 16, 17, 18,
-                                                      result_pool);
+          /* Get the lock info, available only at op_depth 0. */
+          child_item->info.lock = lock_from_columns(stmt, 15, 16, 17, 18,
+                                                    result_pool);
+
+          /* Moved-to is only stored at op_depth 0. */
+          moved_to_relpath = svn_sqlite__column_text(stmt, 21, NULL); 
+          if (moved_to_relpath)
+            child_item->info.moved_to_abspath =
+              svn_dirent_join(wcroot->abspath, moved_to_relpath, result_pool);
         }
       else
         {
           child_item->nr_layers++;
           child_item->info.have_more_work = (child_item->nr_layers > 1);
+
+          /* Moved-here can only exist at op_depth > 0. */
+          child_item->info.moved_here = svn_sqlite__column_boolean(stmt, 20);
         }
 
       err = svn_sqlite__step(&have_row, stmt);
@@ -9580,7 +9698,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          const char **original_uuid,
                          svn_revnum_t *original_revision,
                          const char **moved_from_abspath,
-                         const char **delete_op_root_abspath,
+                         const char **moved_from_op_root_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
@@ -9632,14 +9750,15 @@ svn_wc__db_scan_addition(svn_wc__db_stat
         *moved_from_abspath = NULL;
     }
 
-  if (delete_op_root_abspath)
+  if (moved_from_op_root_abspath)
     {
       if (moved_from_op_root_relpath)
-        *delete_op_root_abspath = svn_dirent_join(wcroot->abspath,
-                                                  moved_from_op_root_relpath,
-                                                  result_pool);
+        *moved_from_op_root_abspath =
+          svn_dirent_join(wcroot->abspath,
+                          moved_from_op_root_relpath,
+                          result_pool);
       else
-        *delete_op_root_abspath = NULL;
+        *moved_from_op_root_abspath = NULL;
     }
 
   return SVN_NO_ERROR;
@@ -9668,6 +9787,7 @@ scan_deletion_txn(void *baton,
   svn_wc__db_status_t child_presence;
   svn_boolean_t child_has_base = FALSE;
   apr_int64_t local_op_depth, op_depth;
+  svn_boolean_t found_moved_to = FALSE;
 
   /* Initialize all the OUT parameters.  */
   if (sd_baton->base_del_relpath != NULL)
@@ -9794,9 +9914,12 @@ scan_deletion_txn(void *baton,
              gimmick, not a real node that may have been deleted.  */
         }
 
-      if ((sd_baton->moved_to_relpath != NULL
-                || sd_baton->moved_to_op_root_relpath != NULL
-                || sd_baton->base_del_relpath != NULL)
+      /* Evaluate moved-to information. Once moved-to info has been found, it
+       * must not be overwritten with ancestors' moved-to info. */
+      if ((! found_moved_to)
+          && (sd_baton->moved_to_relpath != NULL
+              || sd_baton->moved_to_op_root_relpath != NULL
+              || sd_baton->base_del_relpath != NULL)
           && !svn_sqlite__column_is_null(stmt, 2 /* moved_to */))
         {
           const char *moved_to_op_root_relpath;
@@ -9887,6 +10010,13 @@ scan_deletion_txn(void *baton,
             *sd_baton->moved_to_op_root_relpath = moved_to_op_root_relpath ?
               apr_pstrdup(sd_baton->result_pool, moved_to_op_root_relpath)
               : NULL;
+
+          /* If all other out parameters are irrelevant, stop scanning.
+           * Happens to be only WORK_DEL_RELPATH. */
+          if (sd_baton->work_del_relpath == NULL)
+            break;
+
+          found_moved_to = TRUE;
         }
 
       op_depth = svn_sqlite__column_int64(stmt, 3);

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.h?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc_db.h Wed Aug 17 18:25:07 2011
@@ -1506,6 +1506,13 @@ svn_wc__db_op_revert(svn_wc__db_t *db,
  * path was reverted.  Set *CONFLICT_OLD, *CONFLICT_NEW,
  * *CONFLICT_WORKING and *PROP_REJECT to the names of the conflict
  * files, or NULL if the names are not stored.
+ * 
+ * Set *COPIED_HERE if the reverted node was copied here and is the
+ * operation root of the copy.
+ * Set *KIND to the node kind of the reverted node.
+ * If the node was a file, set *PRISTINE_CHECKSUM to the checksum
+ * of the pristine associated with the node. If the file had no
+ * pristine set *PRISTINE_CHECKSUM to NULL.
  *
  * Removes the row for LOCAL_ABSPATH from the revert list.
  */
@@ -1515,11 +1522,34 @@ svn_wc__db_revert_list_read(svn_boolean_
                             const char **conflict_new,
                             const char **conflict_working,
                             const char **prop_reject,
+                            svn_boolean_t *copied_here,
+                            svn_wc__db_kind_t *kind,
+                            const svn_checksum_t **pristine_checksum,
                             svn_wc__db_t *db,
                             const char *local_abspath,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool);
 
+/* The type of elements in the array returned by
+ * svn_wc__db_revert_list_read_copied_children(). */
+typedef struct svn_wc__db_revert_list_copied_child_info_t {
+  const char *abspath;
+  svn_wc__db_kind_t kind;
+  const svn_checksum_t *pristine_checksum;
+} svn_wc__db_revert_list_copied_child_info_t ;
+
+/* Return in *CHILDREN a list of reverted copied children within the
+ * reverted tree rooted at LOCAL_ABSPATH.
+ * Allocate *COPIED_CHILDREN and its elements in RESULT_POOL.
+ * The elements are of type svn_wc__db_revert_list_copied_child_info_t. */
+svn_error_t *
+svn_wc__db_revert_list_read_copied_children(const apr_array_header_t **children,
+                                            svn_wc__db_t *db,
+                                            const char *local_abspath,
+                                            apr_pool_t *result_pool,
+                                            apr_pool_t *scratch_pool);
+
+
 /* Make revert notifications for all paths in the revert list that are
  * equal to LOCAL_ABSPATH or below LOCAL_ABSPATH.
  *
@@ -1842,6 +1872,9 @@ struct svn_wc__db_info_t {
 
   svn_boolean_t locked;     /* WC directory lock */
   svn_wc__db_lock_t *lock;  /* Repository file lock */
+
+  const char *moved_to_abspath; /* Only on op-roots. See svn_wc_status3_t. */
+  svn_boolean_t moved_here;     /* On both op-roots and children. */
 };
 
 /* Return in *NODES a hash mapping name->struct svn_wc__db_info_t for

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/wc_db_wcroot.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/wc_db_wcroot.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/wc_db_wcroot.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/wc_db_wcroot.c Wed Aug 17 18:25:07 2011
@@ -100,11 +100,13 @@ get_old_version(int *version,
    of LOCAL_ABSPATH, using DB and SCRATCH_POOL as needed.
 
    This function may do strange things, but at long as it comes up with the
-   Right Answer, we should be happy.  */
+   Right Answer, we should be happy.
+
+   Sets *KIND to svn_node_dir for symlinks. */
 static svn_error_t *
-get_path_kind(svn_wc__db_t *db,
+get_path_kind(svn_node_kind_t *kind,
+              svn_wc__db_t *db,
               const char *local_abspath,
-              svn_node_kind_t *kind,
               apr_pool_t *scratch_pool)
 {
   svn_boolean_t special;
@@ -132,7 +134,11 @@ get_path_kind(svn_wc__db_t *db,
     }
 
   SVN_ERR(svn_io_check_special_path(local_abspath, &db->parse_cache.kind,
-                                    &special /* unused */, scratch_pool));
+                                    &special, scratch_pool));
+
+  /* The wcroot could be a symlink to a directory. (Issue #2557, #3987) */
+  if (special)
+    db->parse_cache.kind = svn_node_dir;
   *kind = db->parse_cache.kind;
 
   return SVN_NO_ERROR;
@@ -395,7 +401,7 @@ svn_wc__db_wcroot_parse_local_abspath(sv
      ### rid of this stat() call. it is going to happen for EVERY call
      ### into wc_db which references a file. calls for directories could
      ### get an early-exit in the hash lookup just above.  */
-  SVN_ERR(get_path_kind(db, local_abspath, &kind, scratch_pool));
+  SVN_ERR(get_path_kind(&kind, db, local_abspath, scratch_pool));
   if (kind != svn_node_dir)
     {
       /* If the node specified by the path is NOT present, then it cannot

Modified: subversion/branches/issue-3975/subversion/libsvn_wc/workqueue.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_wc/workqueue.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_wc/workqueue.c Wed Aug 17 18:25:07 2011
@@ -733,10 +733,7 @@ run_file_install(svn_wc__db_t *db,
                            cancel_func, cancel_baton,
                            scratch_pool));
 
-  /* ### post-commit feature: avoid overwrite if same as working file.  */
-
   /* All done. Move the file into place.  */
-  /* ### fix this. we should delay the rename.  */
 
   {
     svn_error_t *err;
@@ -750,7 +747,7 @@ run_file_install(svn_wc__db_t *db,
       {
         svn_error_t *err2;
 
-        err2 = svn_io_make_dir_recursively(svn_dirent_dirname(dst_abspath,
+        err2 = svn_io_make_dir_recursively(svn_dirent_dirname(local_abspath,
                                                               scratch_pool),
                                            scratch_pool);
 

Modified: subversion/branches/issue-3975/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/svn/main.c?rev=1158860&r1=1158859&r2=1158860&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/svn/main.c (original)
+++ subversion/branches/issue-3975/subversion/svn/main.c Wed Aug 17 18:25:07 2011
@@ -1184,7 +1184,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "usage: revert PATH...\n"
      "\n"
      "  Note:  this subcommand does not require network access, and resolves\n"
-     "  any conflicted states.  However, it does not restore removed directories.\n"),
+     "  any conflicted states.\n"),
     {opt_targets, 'R', opt_depth, 'q', opt_changelist} },
 
   { "status", svn_cl__status, {"stat", "st"}, N_