You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/05 20:57:17 UTC

svn commit: r1442718 - in /subversion/trunk/subversion: include/private/svn_client_private.h libsvn_client/diff.c libsvn_client/diff_local.c

Author: stsp
Date: Tue Feb  5 19:57:17 2013
New Revision: 1442718

URL: http://svn.apache.org/viewvc?rev=1442718&view=rev
Log:
Add depth support to the 'arbitrary diff' mode of 'svn diff'.

Previously, arbitrary diffs could only be made with depth infinity, which
put arbitrary difff mode at odds with other modes in terms of feature parity.

* subversion/include/private/svn_client_private.h
  (svn_client__arbitrary_nodes_diff): Add DEPTH parameter, adjust docstring.

* subversion/libsvn_client/diff.c
  (do_diff,
   do_diff_summarize): Pass DEPTH to svn_client__arbitrary_nodes_diff().

* subversion/libsvn_client/diff_local.c
  (do_arbitrary_dirs_diff): Add DEPTH parameter, adjust docstring.
  (arbitrary_diff_this_dir): New helper, extract from arbitrary_diff_walker().
   The arbitrary_diff_walker() uses svn_io_dir_walk2() which doesn't support
   depth restriction. This helper function was factored out so that single
   directories can be diffed with distinct levels of depth.
   Use the io walker when diffing with depth infinity, else just use
   arbitrary_diff_this_dir() since we don't need to walk the filesystem.
  (arbitrary_diff_walker): Re-implement as wrapper of arbitrary_diff_this_dir().
  (svn_client__arbitrary_nodes_diff): Add DEPTH parameter. If DEPTH is unknown,
   default to depth infinity.

Modified:
    subversion/trunk/subversion/include/private/svn_client_private.h
    subversion/trunk/subversion/libsvn_client/diff.c
    subversion/trunk/subversion/libsvn_client/diff_local.c

Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1442718&r1=1442717&r2=1442718&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Tue Feb  5 19:57:17 2013
@@ -226,14 +226,15 @@ svn_client__wc_node_get_origin(svn_clien
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
-/* Produce a diff between two files or two directories at LOCAL_ABSPATH1
- * and LOCAL_ABSPATH2, using the provided diff callbacks to show changes
- * in files. The files and directories involved may be part of a working
- * copy or they may be unversioned. For versioned files, show property
- * changes, too. */
+/* Produce a diff with depth DEPTH between two files or two directories at
+ * LOCAL_ABSPATH1 and LOCAL_ABSPATH2, using the provided diff callbacks to
+ * show changes in files. The files and directories involved may be part of
+ * a working copy or they may be unversioned. For versioned files, show
+ * property changes, too. */
 svn_error_t *
 svn_client__arbitrary_nodes_diff(const char *local_abspath1,
                                  const char *local_abspath2,
+                                 svn_depth_t depth,
                                  const svn_wc_diff_callbacks4_t *callbacks,
                                  void *callback_baton,
                                  svn_client_ctx_t *ctx,

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=1442718&r1=1442717&r2=1442718&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Tue Feb  5 19:57:17 2013
@@ -2479,6 +2479,7 @@ do_diff(const svn_wc_diff_callbacks4_t *
               SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, pool));
 
               SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+                                                       depth,
                                                        callbacks,
                                                        callback_baton,
                                                        ctx, pool));
@@ -2784,6 +2785,7 @@ do_diff_summarize(svn_client_diff_summar
                      summarize_func, summarize_baton, pool));
 
              SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+                                                      depth,
                                                       callbacks,
                                                       callback_baton,
                                                       ctx, pool));

Modified: subversion/trunk/subversion/libsvn_client/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff_local.c?rev=1442718&r1=1442717&r2=1442718&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff_local.c Tue Feb  5 19:57:17 2013
@@ -287,9 +287,16 @@ arbitrary_diff_walker(void *baton, const
                       const apr_finfo_t *finfo,
                       apr_pool_t *scratch_pool);
 
-/* Produce a diff between two arbitrary directories at LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2, using the provided diff callbacks to show file changes
- * and, for versioned nodes, property changes.
+/* Another forward declaration. */
+static svn_error_t *
+arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
+                        const char *local_abspath,
+                        svn_depth_t depth,
+                        apr_pool_t *scratch_pool);
+
+/* Produce a diff of depth DEPTH between two arbitrary directories at
+ * LOCAL_ABSPATH1 and LOCAL_ABSPATH2, using the provided diff callbacks
+ * to show file changes and, for versioned nodes, property changes.
  *
  * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs
  * relative to these roots, rather than relative to LOCAL_ABSPATH1 and
@@ -300,6 +307,7 @@ do_arbitrary_dirs_diff(const char *local
                        const char *local_abspath2,
                        const char *root_abspath1,
                        const char *root_abspath2,
+                       svn_depth_t depth,
                        const svn_wc_diff_callbacks4_t *callbacks,
                        void *diff_baton,
                        svn_client_ctx_t *ctx,
@@ -331,22 +339,25 @@ do_arbitrary_dirs_diff(const char *local
                                    NULL, svn_io_file_del_on_pool_cleanup,
                                    scratch_pool, scratch_pool));
 
-  SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2
-                                                            : local_abspath1,
-                           0, arbitrary_diff_walker, &b, scratch_pool));
-
+  if (depth <= svn_depth_immediates)
+    SVN_ERR(arbitrary_diff_this_dir(&b, local_abspath1, depth, scratch_pool));
+  else if (depth == svn_depth_infinity)
+    SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2
+                                                              : local_abspath1,
+                             0, arbitrary_diff_walker, &b, scratch_pool));
   return SVN_NO_ERROR;
 }
 
-/* An implementation of svn_io_walk_func_t.
- * Note: LOCAL_ABSPATH is the path being crawled and can be on either side
+/* Produce a diff of depth DEPTH for the directory at LOCAL_ABSPATH,
+ * using information from the arbitrary_diff_walker_baton B.
+ * LOCAL_ABSPATH is the path being crawled and can be on either side
  * of the diff depending on baton->recursing_within_added_subtree. */
 static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
-                      const apr_finfo_t *finfo,
-                      apr_pool_t *scratch_pool)
+arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
+                        const char *local_abspath,
+                        svn_depth_t depth,
+                        apr_pool_t *scratch_pool)
 {
-  struct arbitrary_diff_walker_baton *b = baton;
   const char *local_abspath1;
   const char *local_abspath2;
   svn_node_kind_t kind1;
@@ -359,12 +370,6 @@ arbitrary_diff_walker(void *baton, const
   int i;
   apr_pool_t *iterpool;
 
-  if (b->ctx->cancel_func)
-    SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
-
-  if (finfo->filetype != APR_DIR)
-    return SVN_NO_ERROR;
-
   if (b->recursing_within_adm_dir)
     {
       if (svn_dirent_skip_ancestor(b->adm_dir_abspath, local_abspath))
@@ -398,12 +403,15 @@ arbitrary_diff_walker(void *baton, const
                                    scratch_pool);
   SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
 
-  if (kind1 == svn_node_dir)
-    SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1,
-                                TRUE, /* only_check_type */
-                                scratch_pool, scratch_pool));
-  else
-    dirents1 = apr_hash_make(scratch_pool);
+  if (depth > svn_depth_empty)
+    {
+      if (kind1 == svn_node_dir)
+        SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1,
+                                    TRUE, /* only_check_type */
+                                    scratch_pool, scratch_pool));
+      else
+        dirents1 = apr_hash_make(scratch_pool);
+    }
 
   if (kind2 == svn_node_dir)
     {
@@ -425,14 +433,20 @@ arbitrary_diff_walker(void *baton, const
                                                 b->diff_baton,
                                                 scratch_pool));
 
-      /* Read directory entries. */
-      SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2,
-                                  TRUE, /* only_check_type */
-                                  scratch_pool, scratch_pool));
+      if (depth > svn_depth_empty)
+        {
+          /* Read directory entries. */
+          SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2,
+                                      TRUE, /* only_check_type */
+                                      scratch_pool, scratch_pool));
+        }
     }
-  else
+  else if (depth > svn_depth_empty)
     dirents2 = apr_hash_make(scratch_pool);
 
+  if (depth <= svn_depth_empty)
+    return SVN_NO_ERROR;
+
   /* Compare dirents1 to dirents2 and show added/deleted/changed files. */
   merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2,
                                   NULL, NULL);
@@ -482,7 +496,25 @@ arbitrary_diff_walker(void *baton, const
 
       if (dirent1->kind == svn_node_dir &&
           dirent2->kind == svn_node_dir)
-        continue;
+        {
+          if (depth == svn_depth_immediates)
+            {
+              /* Not using the walker, so show property diffs on these dirs. */
+              SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
+                                             b->root1_abspath, b->root2_abspath,
+                                             svn_depth_empty,
+                                             b->callbacks, b->diff_baton,
+                                             b->ctx, iterpool));
+            }
+          else
+            {
+              /* Either the walker will visit these directories (with
+               * depth=infinity) and they will be processed as 'this dir'
+               * later, or we're showing file children only (depth=files). */
+              continue;
+            }
+
+        }
 
       /* Files that exist only in dirents1. */
       if (dirent1->kind == svn_node_file &&
@@ -521,10 +553,14 @@ arbitrary_diff_walker(void *baton, const
 
       /* Directories that only exist in dirents2. These aren't crawled
        * by this walker so we have to crawl them separately. */
-      if (dirent2->kind == svn_node_dir &&
+      if (depth > svn_depth_files &&
+          dirent2->kind == svn_node_dir &&
           (dirent1->kind == svn_node_file || dirent1->kind == svn_node_none))
         SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
                                        b->root1_abspath, b->root2_abspath,
+                                       depth <= svn_depth_immediates
+                                         ? svn_depth_empty
+                                         : svn_depth_infinity ,
                                        b->callbacks, b->diff_baton,
                                        b->ctx, iterpool));
     }
@@ -534,14 +570,32 @@ arbitrary_diff_walker(void *baton, const
   return SVN_NO_ERROR;
 }
 
-/* Produce a diff between two files or two directories at LOCAL_ABSPATH1
- * and LOCAL_ABSPATH2, using the provided diff callbacks to show changes
- * in files. The files and directories involved may be part of a working
- * copy or they may be unversioned. For versioned files, show property
- * changes, too. */
+/* An implementation of svn_io_walk_func_t.
+ * Note: LOCAL_ABSPATH is the path being crawled and can be on either side
+ * of the diff depending on baton->recursing_within_added_subtree. */
+static svn_error_t *
+arbitrary_diff_walker(void *baton, const char *local_abspath,
+                      const apr_finfo_t *finfo,
+                      apr_pool_t *scratch_pool)
+{
+  struct arbitrary_diff_walker_baton *b = baton;
+
+  if (b->ctx->cancel_func)
+    SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+
+  if (finfo->filetype != APR_DIR)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(arbitrary_diff_this_dir(b, local_abspath, svn_depth_infinity,
+                                  scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_client__arbitrary_nodes_diff(const char *local_abspath1,
                                  const char *local_abspath2,
+                                 svn_depth_t depth,
                                  const svn_wc_diff_callbacks4_t *callbacks,
                                  void *diff_baton,
                                  svn_client_ctx_t *ctx,
@@ -558,6 +612,9 @@ svn_client__arbitrary_nodes_diff(const c
                              _("'%s' is not the same node kind as '%s'"),
                              local_abspath1, local_abspath2);
 
+  if (depth == svn_depth_unknown)
+    depth = svn_depth_infinity;
+
   if (kind1 == svn_node_file)
     SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2,
                                     svn_dirent_basename(local_abspath1,
@@ -567,7 +624,7 @@ svn_client__arbitrary_nodes_diff(const c
                                     ctx, scratch_pool));
   else if (kind1 == svn_node_dir)
     SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2,
-                                   NULL, NULL,
+                                   NULL, NULL, depth,
                                    callbacks, diff_baton,
                                    ctx, scratch_pool));
   else