Author: stsp
Date: Wed Aug 17 10:33:12 2011
New Revision: 1158617

URL: http://svn.apache.org/viewvc?rev=1158617&view=rev
Log:
Remove reverted copied files and directories from disk, if they weren't
modified after being copied.

To achieve this we add more columns to rows in the revert list:
the node kind, the repos_id (which is not NULL for copies),
the op_root, and, if the node is a file, the pristine checksum.

While restoring the BASE on-disk state, process nodes in the revert list
marked as copies in a special way: Compare reverted copied files with
their pristines, and remove the ones that match from disk. Next, remove
any reverted copied directories which are left empty as a result.

This commit addresses issues #3101 and #876, and my own annoyance at
unversioned things left behind in my testing WCs (been testing 'svn move'
with subsequent 'revert' a lot lately).

We could take this further and remove copied files which were modified
post-copy (after all, we also destroy textual modifications to files which
were not copied). But that's a decision for another day.

Review by: julianfoad

* subversion/tests/cmdline/merge_tests.py
  (merge_away_subtrees_noninheritable_ranges): No longer need to remove
   unversioned files after revert.

* subversion/tests/cmdline/depth_tests.py
  (excluded_path_misc_operation): No longer need to remove unversioned files
   after revert.

* subversion/tests/cmdline/revert_tests.py
  (status_of_missing_dir_after_revert_replaced_with_history_dir): No longer 
   need to remove unversioned files. And don't expect them in status output.

* subversion/libsvn_wc/adm_ops.c
  (revert_restore_handle_copied_file, revert_restore_handle_copied_dirs,
   compare_revert_list_copied_children): New.
  (revert_restore): When reverting copies, remove their remains from disk,
   except for files which were modified after being copied, and directories
   that contain unversioned files.

* subversion/libsvn_wc/wc-queries.sql
  (revert_list): Add new columns OP_DEPTH, REPOS_ID, KIND, CHECKSUM.
   Copy values from rows deleted from the NODES table into them.
   Nothing changes for actual-only nodes.
  (STMT_SELECT_REVERT_LIST): Get the new columns.
  (STMT_SELECT_REVERT_LIST_COPIED_CHILDREN): New statement which returns
   all copied children within a given reverted local_relpath.

* subversion/libsvn_wc/wc.h
  (svn_wc__compare_file_with_pristine): Declare.

* subversion/libsvn_wc/questions.c
  (compare_and_verify): Renamed to ...
  (svn_wc__compare_file_with_pristine): ... this, so the revert code can
   access this function. No modifications were made to the implementation.
  (svn_wc__internal_file_modified_p): Track above function rename.

* subversion/libsvn_wc/wc_db.c
  (revert_list_read_baton): Add COPIED_HERE, KIND, and PRISTINE_CHECKSUM.
  (revert_list_read): Populate the new baton fields.
  (svn_wc__db_revert_list_read): Add COPIED_HERE, KIND, and PRISTINE_CHECKSUM
   output parameters.
  (revert_list_read_copied_children_baton): New.
  (revert_list_read_copied_children): New. Returns a list of all copied
   children which existed within a reverted subtree.
  (svn_wc__db_revert_list_read_copied_children): Exposes the 
   revert_list_read_copied_children() function, wrapping it in an sqlite
   transaction.

* subversion/libsvn_wc/wc_db.h
  (svn_wc__db_revert_list_read): Declare new output parameters COPIED_HERE,
   KIND, and PRISTINE_CHECKSUM. Update docstring.
  (svn_wc__db_revert_list_read_copied_children): Declare.

Modified:
    subversion/trunk/subversion/libsvn_wc/adm_ops.c
    subversion/trunk/subversion/libsvn_wc/questions.c
    subversion/trunk/subversion/libsvn_wc/wc-queries.sql
    subversion/trunk/subversion/libsvn_wc/wc.h
    subversion/trunk/subversion/libsvn_wc/wc_db.c
    subversion/trunk/subversion/libsvn_wc/wc_db.h
    subversion/trunk/subversion/tests/cmdline/depth_tests.py
    subversion/trunk/subversion/tests/cmdline/merge_tests.py
    subversion/trunk/subversion/tests/cmdline/revert_tests.py

Modified: subversion/trunk/subversion/libsvn_wc/adm_ops.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/adm_ops.c?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/trunk/subversion/libsvn_wc/adm_ops.c Wed Aug 17 10:33:12 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/trunk/subversion/libsvn_wc/questions.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/questions.c?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/questions.c (original)
+++ subversion/trunk/subversion/libsvn_wc/questions.c Wed Aug 17 10:33:12 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/trunk/subversion/libsvn_wc/wc-queries.sql
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed Aug 17 10:33:12 
2011
@@ -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/trunk/subversion/libsvn_wc/wc.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc.h?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc.h Wed Aug 17 10:33:12 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/trunk/subversion/libsvn_wc/wc_db.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed Aug 17 10:33:12 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,

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Wed Aug 17 10:33:12 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.
  *

Modified: subversion/trunk/subversion/tests/cmdline/depth_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/depth_tests.py?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/depth_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/depth_tests.py Wed Aug 17 
10:33:12 2011
@@ -2229,10 +2229,6 @@ def excluded_path_misc_operation(sbox):
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'revert', '--depth=infinity', L_path)
 
-  # Get rid of A/L.
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'rm', '--force', L_path)
-
   # copy A/B to A/L and then cp A/L to A/M, excluded entry should be
   # copied both times
   expected_output = ['A         '+L_path+'\n']

Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Wed Aug 17 
10:33:12 2011
@@ -7482,7 +7482,6 @@ def merge_away_subtrees_noninheritable_r
   #
   # First revert all local changes and remove A_COPY/C/nu from disk.
   svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
-  os.remove(os.path.join(wc_dir, "A_COPY", "nu"))
 
   # Make a text change to A_COPY_2/mu in r11 and then merge that
   # change to A/mu in r12.  This will create mergeinfo of '/A_COPY_2/mu:11'

Modified: subversion/trunk/subversion/tests/cmdline/revert_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/revert_tests.py?rev=1158617&r1=1158616&r2=1158617&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/revert_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/revert_tests.py Wed Aug 17 
10:33:12 2011
@@ -890,13 +890,7 @@ def status_of_missing_dir_after_revert_r
   svntest.actions.run_and_verify_svn(None, expected_output, [], "revert", "-R",
                                      G_path)
 
-
-  # Revert leaves these added nodes as unversioned
-  expected_output = svntest.verify.UnorderedOutput(
-    ["?       " + 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, [],
+  svntest.actions.run_and_verify_svn(None, [], [],
                                      "status", wc_dir)
 
   svntest.main.safe_rmtree(G_path)
@@ -1464,8 +1458,6 @@ def revert_tree_conflicts_with_replaceme
 
   # Remove a few unversioned files that revert left behind.
   os.remove(wc('A/B/E/loc_beta'))
-  os.remove(wc('A/D/G/rho'))
-  os.remove(wc('A/D/G/tau'))
   os.remove(wc('A/D/H/loc_psi'))
 
   # The update operation should have put all incoming items in place.


Reply via email to