subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1621978 - in /subversion/trunk/subversion/libsvn_wc: diff.h diff_editor.c diff_local.c
Date Tue, 02 Sep 2014 13:18:26 GMT
Author: julianfoad
Date: Tue Sep  2 13:18:26 2014
New Revision: 1621978

URL: http://svn.apache.org/r1621978
Log:
Implement changelist filtering in WC diffs by post-filtering.

This work was triggered by a bug report sent in by Peter Galcik, who noticed
that svn 1.8 crashed when requesting a repos-WC diff with changelist
filtering. In fixing that crash I noticed that the changelist filtering was
deficient in several other respects.

Changes are passed through a changelist-filtering 'diff processor'. This
approach is similar to how diff reversal and some other options are now
handled, and should be easier to get right and to maintain than embedding
changelist filtering in both of the diff implementations. On the other hand,
this approach will usually be less efficient than a pre-filtering approach.

TODO: We need tests for changelist filtering. I tested this patch by hand,
not comprehensively.

* subversion/libsvn_wc/diff.h
  (svn_wc__diff_local_only_file,
   svn_wc__diff_local_only_dir,
   svn_wc__diff_base_working_diff): Remove changelist filtering.
  (svn_wc__changelist_filter_tree_processor_create): New.

* subversion/libsvn_wc/diff_editor.c
  (edit_baton_t ,
   make_edit_baton,
   svn_wc__diff_base_working_diff,
   walk_local_nodes_diff,
   svn_wc__diff_local_only_file,
   svn_wc__diff_local_only_dir,
   handle_local_only): Remove changelist filtering.
  (close_file): Make sure we don't expect to see a valid checksum if we're
    skipping the node, as the sender may not have sent a diff at all.
  (svn_wc__get_diff_editor): Wrap the diff processor in a changelist
    filtering diff processor.
  (filter_tree_baton_t,
   filter_*,
   svn_wc__changelist_filter_tree_processor_create): New.

* subversion/libsvn_wc/diff_local.c
  (diff_baton,
   diff_status_callback): Remove changelist filtering.
  (svn_wc__diff7): Wrap the diff processor in a changelist

Modified:
    subversion/trunk/subversion/libsvn_wc/diff.h
    subversion/trunk/subversion/libsvn_wc/diff_editor.c
    subversion/trunk/subversion/libsvn_wc/diff_local.c

Modified: subversion/trunk/subversion/libsvn_wc/diff.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff.h?rev=1621978&r1=1621977&r2=1621978&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff.h (original)
+++ subversion/trunk/subversion/libsvn_wc/diff.h Tue Sep  2 13:18:26 2014
@@ -47,9 +47,6 @@ extern "C" {
    svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
    version of LOCAL_ABSPATH as ADDED. In this case an
    svn_wc__db_status_deleted may shadow an added or deleted node.
-
-   If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
-   in the changelist, don't report the node.
  */
 svn_error_t *
 svn_wc__diff_local_only_file(svn_wc__db_t *db,
@@ -57,7 +54,6 @@ svn_wc__diff_local_only_file(svn_wc__db_
                              const char *relpath,
                              const svn_diff_tree_processor_t *processor,
                              void *processor_parent_baton,
-                             apr_hash_t *changelist_hash,
                              svn_boolean_t diff_pristine,
                              svn_cancel_func_t cancel_func,
                              void *cancel_baton,
@@ -73,9 +69,6 @@ svn_wc__diff_local_only_file(svn_wc__db_
    svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
    version of LOCAL_ABSPATH as ADDED. In this case an
    svn_wc__db_status_deleted may shadow an added or deleted node.
-
-   If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
-   in the changelist, don't report the node.
  */
 svn_error_t *
 svn_wc__diff_local_only_dir(svn_wc__db_t *db,
@@ -84,7 +77,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
                             svn_depth_t depth,
                             const svn_diff_tree_processor_t *processor,
                             void *processor_parent_baton,
-                            apr_hash_t *changelist_hash,
                             svn_boolean_t diff_pristine,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
@@ -132,7 +124,6 @@ svn_wc__diff_base_working_diff(svn_wc__d
                                const char *local_abspath,
                                const char *relpath,
                                svn_revnum_t revision,
-                               apr_hash_t *changelist_hash,
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
@@ -140,6 +131,32 @@ svn_wc__diff_base_working_diff(svn_wc__d
                                void *cancel_baton,
                                apr_pool_t *scratch_pool);
 
+/* Return a tree processor filter that filters by changelist membership.
+ *
+ * This filter only passes on the changes for a file if the file's path
+ * (in the WC) is assigned to one of the changelists in @a changelist_hash.
+ * It also passes on the opening and closing of each directory that contains
+ * such a change, and possibly also of other directories, but not addition
+ * or deletion or changes to a directory.
+ *
+ * If @a changelist_hash is null then no filtering is performed and the
+ * returned diff processor is driven exactly like the input @a processor.
+ *
+ * @a wc_ctx is the WC context and @a root_local_abspath is the WC path of
+ * the root of the diff (for which relpath = "" in the diff processor).
+ *
+ * Allocate the returned diff processor in @a result_pool, or if no
+ * filtering is required then the input pointer @a processor itself may be
+ * returned.
+ */
+const svn_diff_tree_processor_t *
+svn_wc__changelist_filter_tree_processor_create(
+                                const svn_diff_tree_processor_t *processor,
+                                svn_wc_context_t *wc_ctx,
+                                const char *root_local_abspath,
+                                apr_hash_t *changelist_hash,
+                                apr_pool_t *result_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/trunk/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff_editor.c?rev=1621978&r1=1621977&r2=1621978&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/diff_editor.c Tue Sep  2 13:18:26 2014
@@ -115,9 +115,6 @@ struct edit_baton_t
   /* Possibly diff repos against text-bases instead of working files. */
   svn_boolean_t diff_pristine;
 
-  /* Hash whose keys are const char * changelist names. */
-  apr_hash_t *changelist_hash;
-
   /* Cancel function/baton */
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
@@ -239,11 +236,6 @@ struct file_baton_t
  * calculating diffs.  USE_TEXT_BASE defines whether to compare
  * against working files or text-bases.  REVERSE_ORDER defines which
  * direction to perform the diff.
- *
- * CHANGELIST_FILTER is a list of const char * changelist names, used to
- * filter diff output responses to only those items in one of the
- * specified changelists, empty (or NULL altogether) if no changelist
- * filtering is requested.
  */
 static svn_error_t *
 make_edit_baton(struct edit_baton_t **edit_baton,
@@ -255,20 +247,14 @@ make_edit_baton(struct edit_baton_t **ed
                 svn_boolean_t ignore_ancestry,
                 svn_boolean_t use_text_base,
                 svn_boolean_t reverse_order,
-                const apr_array_header_t *changelist_filter,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
                 apr_pool_t *pool)
 {
-  apr_hash_t *changelist_hash = NULL;
   struct edit_baton_t *eb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
 
-  if (changelist_filter && changelist_filter->nelts)
-    SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
-                                       pool));
-
   eb = apr_pcalloc(pool, sizeof(*eb));
   eb->db = db;
   eb->anchor_abspath = apr_pstrdup(pool, anchor_abspath);
@@ -278,7 +264,6 @@ make_edit_baton(struct edit_baton_t **ed
   eb->ignore_ancestry = ignore_ancestry;
   eb->local_before_remote = reverse_order;
   eb->diff_pristine = use_text_base;
-  eb->changelist_hash = changelist_hash;
   eb->cancel_func = cancel_func;
   eb->cancel_baton = cancel_baton;
   eb->pool = pool;
@@ -392,7 +377,6 @@ svn_wc__diff_base_working_diff(svn_wc__d
                                const char *local_abspath,
                                const char *relpath,
                                svn_revnum_t revision,
-                               apr_hash_t *changelist_hash,
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
@@ -419,12 +403,11 @@ svn_wc__diff_base_working_diff(svn_wc__d
   apr_hash_t *base_props;
   apr_hash_t *local_props;
   apr_array_header_t *prop_changes;
-  const char *changelist;
 
   SVN_ERR(svn_wc__db_read_info(&status, NULL, &db_revision, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, &working_checksum, NULL,
                                NULL, NULL, NULL, NULL, NULL, &recorded_size,
-                               &recorded_time, &changelist, NULL, NULL,
+                               &recorded_time, NULL, NULL, NULL,
                                &had_props, &props_mod, NULL, NULL, NULL,
                                db, local_abspath, scratch_pool, scratch_pool));
   checksum = working_checksum;
@@ -433,12 +416,6 @@ svn_wc__diff_base_working_diff(svn_wc__d
          || status == svn_wc__db_status_added
          || (status == svn_wc__db_status_deleted && diff_pristine));
 
-  /* If the item is not a member of a specified changelist (and there are
-     some specified changelists), skip it. */
-  if (changelist_hash && !svn_hash_gets(changelist_hash, changelist))
-    return SVN_NO_ERROR;
-
-
   if (status != svn_wc__db_status_normal)
     {
       SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db_revision,
@@ -768,7 +745,6 @@ walk_local_nodes_diff(struct edit_baton_
                 SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
                                                      child_relpath,
                                                      eb->processor, dir_baton,
-                                                     eb->changelist_hash,
                                                      eb->diff_pristine,
                                                      eb->cancel_func,
                                                      eb->cancel_baton,
@@ -778,7 +754,6 @@ walk_local_nodes_diff(struct edit_baton_
                                                     child_relpath,
                                                     depth_below_here,
                                                     eb->processor, dir_baton,
-                                                    eb->changelist_hash,
                                                     eb->diff_pristine,
                                                     eb->cancel_func,
                                                     eb->cancel_baton,
@@ -814,7 +789,6 @@ walk_local_nodes_diff(struct edit_baton_
                                                 db, child_abspath,
                                                 child_relpath,
                                                 eb->revnum,
-                                                eb->changelist_hash,
                                                 eb->processor, dir_baton,
                                                 eb->diff_pristine,
                                                 eb->cancel_func,
@@ -837,7 +811,6 @@ walk_local_nodes_diff(struct edit_baton_
                 SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
                                                      child_relpath,
                                                      eb->processor, dir_baton,
-                                                     eb->changelist_hash,
                                                      eb->diff_pristine,
                                                      eb->cancel_func,
                                                      eb->cancel_baton,
@@ -846,7 +819,6 @@ walk_local_nodes_diff(struct edit_baton_
                 SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
                                                      child_relpath, depth_below_here,
                                                      eb->processor, dir_baton,
-                                                     eb->changelist_hash,
                                                      eb->diff_pristine,
                                                      eb->cancel_func,
                                                      eb->cancel_baton,
@@ -858,13 +830,9 @@ walk_local_nodes_diff(struct edit_baton_
   if (compared)
     return SVN_NO_ERROR;
 
-    /* Check for local property mods on this directory, if we haven't
-     already reported them and we aren't changelist-filted.
-     ### it should be noted that we do not currently allow directories
-     ### to be part of changelists, so if a changelist is provided, the
-     ### changelist check will always fail. */
+  /* Check for local property mods on this directory, if we haven't
+     already reported them. */
   if (! skip
-      && ! eb->changelist_hash
       && ! in_anchor_not_target
       && props_mod)
     {
@@ -907,7 +875,6 @@ svn_wc__diff_local_only_file(svn_wc__db_
                              const char *relpath,
                              const svn_diff_tree_processor_t *processor,
                              void *processor_parent_baton,
-                             apr_hash_t *changelist_hash,
                              svn_boolean_t diff_pristine,
                              svn_cancel_func_t cancel_func,
                              void *cancel_baton,
@@ -920,7 +887,6 @@ svn_wc__diff_local_only_file(svn_wc__db_
   const svn_checksum_t *checksum;
   const char *original_repos_relpath;
   svn_revnum_t original_revision;
-  const char *changelist;
   svn_boolean_t had_props;
   svn_boolean_t props_mod;
   apr_hash_t *pristine_props;
@@ -936,7 +902,7 @@ svn_wc__diff_local_only_file(svn_wc__db_
                                NULL, NULL, NULL, NULL, &checksum, NULL,
                                &original_repos_relpath, NULL, NULL,
                                &original_revision, NULL, NULL, NULL,
-                               &changelist, NULL, NULL, &had_props,
+                               NULL, NULL, NULL, &had_props,
                                &props_mod, NULL, NULL, NULL,
                                db, local_abspath,
                                scratch_pool, scratch_pool));
@@ -947,10 +913,6 @@ svn_wc__diff_local_only_file(svn_wc__db_
              || (status == svn_wc__db_status_deleted && diff_pristine)));
 
 
-  if (changelist && changelist_hash
-      && !svn_hash_gets(changelist_hash, changelist))
-    return SVN_NO_ERROR;
-
   if (status == svn_wc__db_status_deleted)
     {
       assert(diff_pristine);
@@ -1053,7 +1015,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
                             svn_depth_t depth,
                             const svn_diff_tree_processor_t *processor,
                             void *processor_parent_baton,
-                            apr_hash_t *changelist_hash,
                             svn_boolean_t diff_pristine,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
@@ -1127,6 +1088,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
                                 processor_parent_baton,
                                 processor,
                                 scratch_pool, iterpool));
+  /* ### skip_children is not used */
 
   SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath,
                                         FALSE /* base_tree_only */,
@@ -1172,7 +1134,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
           SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
                                                child_relpath,
                                                processor, pdb,
-                                               changelist_hash,
                                                diff_pristine,
                                                cancel_func, cancel_baton,
                                                scratch_pool));
@@ -1184,7 +1145,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
               SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
                                                   child_relpath, depth_below_here,
                                                   processor, pdb,
-                                                  changelist_hash,
                                                   diff_pristine,
                                                   cancel_func, cancel_baton,
                                                   iterpool));
@@ -1282,7 +1242,6 @@ handle_local_only(struct dir_baton_t *pb
                       svn_relpath_join(pb->relpath, name, scratch_pool),
                       repos_delete ? svn_depth_infinity : depth,
                       eb->processor, pb->pdb,
-                      eb->changelist_hash,
                       eb->diff_pristine,
                       eb->cancel_func, eb->cancel_baton,
                       scratch_pool));
@@ -1293,7 +1252,6 @@ handle_local_only(struct dir_baton_t *pb
                       svn_dirent_join(pb->local_abspath, name, scratch_pool),
                       svn_relpath_join(pb->relpath, name, scratch_pool),
                       eb->processor, pb->pdb,
-                      eb->changelist_hash,
                       eb->diff_pristine,
                       eb->cancel_func, eb->cancel_baton,
                       scratch_pool));
@@ -2068,7 +2026,14 @@ close_file(void *file_baton,
   const char *repos_file;
   apr_hash_t *repos_props;
 
-  if (!fb->skip && expected_md5_digest != NULL)
+  if (fb->skip)
+    {
+      svn_pool_destroy(fb->pool); /* destroys scratch_pool and fb */
+      SVN_ERR(maybe_done(pb));
+      return SVN_NO_ERROR;
+    }
+
+  if (expected_md5_digest != NULL)
     {
       svn_checksum_t *expected_checksum;
       const svn_checksum_t *result_checksum;
@@ -2123,11 +2088,7 @@ close_file(void *file_baton,
       }
   }
 
-  if (fb->skip)
-    {
-      /* Diff processor requested skipping information */
-    }
-  else if (fb->repos_only)
+  if (fb->repos_only)
     {
       SVN_ERR(eb->processor->file_deleted(fb->relpath,
                                           fb->left_src,
@@ -2307,12 +2268,24 @@ svn_wc__get_diff_editor(const svn_delta_
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
 
+  /* Apply changelist filtering to the output */
+  if (changelist_filter && changelist_filter->nelts)
+    {
+      apr_hash_t *changelist_hash;
+
+      SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
+                                         result_pool));
+      diff_processor = svn_wc__changelist_filter_tree_processor_create(
+                         diff_processor, wc_ctx, anchor_abspath,
+                         changelist_hash, result_pool);
+    }
+
   SVN_ERR(make_edit_baton(&eb,
                           wc_ctx->db,
                           anchor_abspath, target,
                           diff_processor,
                           depth, ignore_ancestry,
-                          use_text_base, reverse_order, changelist_filter,
+                          use_text_base, reverse_order,
                           cancel_func, cancel_baton,
                           result_pool));
 
@@ -2778,3 +2751,346 @@ svn_wc__wrap_diff_callbacks(const svn_di
   *diff_processor = processor;
   return SVN_NO_ERROR;
 }
+
+/* =====================================================================
+ * A tree processor filter that filters by changelist membership
+ * =====================================================================
+ *
+ * The current implementation queries the WC for the changelist of each
+ * file as it comes through, and sets the 'skip' flag for a non-matching
+ * file.
+ *
+ * (It doesn't set the 'skip' flag for a directory, as we need to receive
+ * the changed/added/deleted/closed call to know when it is closed, in
+ * order to preserve the strict open-close semantics for the wrapped tree
+ * processor.)
+ *
+ * It passes on the opening and closing of every directory, even if there
+ * are no file changes to be passed on inside that directory.
+ */
+
+typedef struct filter_tree_baton_t
+{
+  const svn_diff_tree_processor_t *processor;
+  svn_wc_context_t *wc_ctx;
+  /* WC path of the root of the diff (where relpath = "") */
+  const char *root_local_abspath;
+  /* Hash whose keys are const char * changelist names. */
+  apr_hash_t *changelist_hash;
+} filter_tree_baton_t;
+
+static svn_error_t *
+filter_dir_opened(void **new_dir_baton,
+                  svn_boolean_t *skip,
+                  svn_boolean_t *skip_children,
+                  const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  const svn_diff_source_t *copyfrom_source,
+                  void *parent_dir_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children,
+                                    relpath,
+                                    left_source, right_source,
+                                    copyfrom_source,
+                                    parent_dir_baton,
+                                    fb->processor,
+                                    result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_added(const char *relpath,
+                 const svn_diff_source_t *copyfrom_source,
+                 const svn_diff_source_t *right_source,
+                 /*const*/ apr_hash_t *copyfrom_props,
+                 /*const*/ apr_hash_t *right_props,
+                 void *dir_baton,
+                 const svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->dir_closed(relpath,
+                                    NULL,
+                                    right_source,
+                                    dir_baton,
+                                    fb->processor,
+                                    scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_deleted(const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   /*const*/ apr_hash_t *left_props,
+                   void *dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->dir_closed(relpath,
+                                    left_source,
+                                    NULL,
+                                    dir_baton,
+                                    fb->processor,
+                                    scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_changed(const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   /*const*/ apr_hash_t *left_props,
+                   /*const*/ apr_hash_t *right_props,
+                   const apr_array_header_t *prop_changes,
+                   void *dir_baton,
+                   const struct svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->dir_closed(relpath,
+                                    left_source,
+                                    right_source,
+                                    dir_baton,
+                                    fb->processor,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_closed(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  void *dir_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->dir_closed(relpath,
+                                    left_source,
+                                    right_source,
+                                    dir_baton,
+                                    fb->processor,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_opened(void **new_file_baton,
+                   svn_boolean_t *skip,
+                   const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   const svn_diff_source_t *copyfrom_source,
+                   void *dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+  const char *local_abspath
+    = svn_dirent_join(fb->root_local_abspath, relpath, scratch_pool);
+  const char *changelist;
+  svn_error_t *err;
+
+  /* Skip if not a member of a given changelist*/
+  err = svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, &changelist, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL,
+                             fb->wc_ctx->db, local_abspath,
+                             scratch_pool, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      changelist = NULL;
+    }
+  else
+    SVN_ERR(err);
+  if (fb->changelist_hash
+      && (!changelist || !svn_hash_gets(fb->changelist_hash, changelist)))
+    {
+      *skip = TRUE;
+      SVN_DBG(("filter: skipping '%s'", relpath));
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(fb->processor->file_opened(new_file_baton,
+                                     skip,
+                                     relpath,
+                                     left_source,
+                                     right_source,
+                                     copyfrom_source,
+                                     dir_baton,
+                                     fb->processor,
+                                     result_pool,
+                                     scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_added(const char *relpath,
+                  const svn_diff_source_t *copyfrom_source,
+                  const svn_diff_source_t *right_source,
+                  const char *copyfrom_file,
+                  const char *right_file,
+                  /*const*/ apr_hash_t *copyfrom_props,
+                  /*const*/ apr_hash_t *right_props,
+                  void *file_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->file_added(relpath,
+                                    copyfrom_source,
+                                    right_source,
+                                    copyfrom_file,
+                                    right_file,
+                                    copyfrom_props,
+                                    right_props,
+                                    file_baton,
+                                    fb->processor,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_deleted(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const char *left_file,
+                    /*const*/ apr_hash_t *left_props,
+                    void *file_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->file_deleted(relpath,
+                                      left_source,
+                                      left_file,
+                                      left_props,
+                                      file_baton,
+                                      fb->processor,
+                                      scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_changed(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    const char *left_file,
+                    const char *right_file,
+                    /*const*/ apr_hash_t *left_props,
+                    /*const*/ apr_hash_t *right_props,
+                    svn_boolean_t file_modified,
+                    const apr_array_header_t *prop_changes,
+                    void *file_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->file_changed(relpath,
+                                      left_source,
+                                      right_source,
+                                      left_file,
+                                      right_file,
+                                      left_props,
+                                      right_props,
+                                      file_modified,
+                                      prop_changes,
+                                      file_baton,
+                                      fb->processor,
+                                      scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_closed(const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   void *file_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->file_closed(relpath,
+                                     left_source,
+                                     right_source,
+                                     file_baton,
+                                     fb->processor,
+                                     scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_node_absent(const char *relpath,
+                   void *dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct filter_tree_baton_t *fb = processor->baton;
+
+  SVN_ERR(fb->processor->node_absent(relpath,
+                                     dir_baton,
+                                     fb->processor,
+                                     scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+const svn_diff_tree_processor_t *
+svn_wc__changelist_filter_tree_processor_create(
+                                const svn_diff_tree_processor_t *processor,
+                                svn_wc_context_t *wc_ctx,
+                                const char *root_local_abspath,
+                                apr_hash_t *changelist_hash,
+                                apr_pool_t *result_pool)
+{
+  struct filter_tree_baton_t *fb;
+  svn_diff_tree_processor_t *filter;
+
+  if (! changelist_hash)
+    return processor;
+
+  fb = apr_pcalloc(result_pool, sizeof(*fb));
+  fb->processor = processor;
+  fb->wc_ctx = wc_ctx;
+  fb->root_local_abspath = root_local_abspath;
+  fb->changelist_hash = changelist_hash;
+
+  filter = svn_diff__tree_processor_create(fb, result_pool);
+  filter->dir_opened   = filter_dir_opened;
+  filter->dir_added    = filter_dir_added;
+  filter->dir_deleted  = filter_dir_deleted;
+  filter->dir_changed  = filter_dir_changed;
+  filter->dir_closed   = filter_dir_closed;
+
+  filter->file_opened   = filter_file_opened;
+  filter->file_added    = filter_file_added;
+  filter->file_deleted  = filter_file_deleted;
+  filter->file_changed  = filter_file_changed;
+  filter->file_closed   = filter_file_closed;
+
+  filter->node_absent   = filter_node_absent;
+
+  return filter;
+}
+

Modified: subversion/trunk/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff_local.c?rev=1621978&r1=1621977&r2=1621978&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_wc/diff_local.c Tue Sep  2 13:18:26 2014
@@ -89,9 +89,6 @@ struct diff_baton
   /* Should this diff ignore node ancestry? */
   svn_boolean_t ignore_ancestry;
 
-  /* Hash whose keys are const char * changelist names. */
-  apr_hash_t *changelist_hash;
-
   /* Cancel function/baton */
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
@@ -249,11 +246,6 @@ diff_status_callback(void *baton,
   if (eb->cur && eb->cur->skip_children)
     return SVN_NO_ERROR;
 
-  if (eb->changelist_hash != NULL
-      && (!status->changelist
-          || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
-    return SVN_NO_ERROR; /* Filtered via changelist */
-
   /* This code does about the same thing as the inner body of
      walk_local_nodes_diff() in diff_editor.c, except that
      it is already filtered by the status walker, doesn't have to
@@ -358,7 +350,6 @@ diff_status_callback(void *baton,
             SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
                                                    child_relpath,
                                                    SVN_INVALID_REVNUM,
-                                                   eb->changelist_hash,
                                                    eb->processor,
                                                    eb->cur
                                                         ? eb->cur->baton
@@ -402,7 +393,6 @@ diff_status_callback(void *baton,
                                                child_relpath,
                                                eb->processor,
                                                eb->cur ? eb->cur->baton : NULL,
-                                               eb->changelist_hash,
                                                FALSE,
                                                eb->cancel_func,
                                                eb->cancel_baton,
@@ -412,7 +402,6 @@ diff_status_callback(void *baton,
                                               child_relpath, depth_below_here,
                                               eb->processor,
                                               eb->cur ? eb->cur->baton : NULL,
-                                              eb->changelist_hash,
                                               FALSE,
                                               eb->cancel_func,
                                               eb->cancel_baton,
@@ -475,15 +464,23 @@ svn_wc__diff7(const char **root_relpath,
   if (root_is_dir)
     *root_is_dir = (kind == svn_node_dir);
 
+  /* Apply changelist filtering to the output */
+  if (changelist_filter && changelist_filter->nelts)
+    {
+      apr_hash_t *changelist_hash;
+
+      SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
+                                         result_pool));
+      diff_processor = svn_wc__changelist_filter_tree_processor_create(
+                         diff_processor, wc_ctx, local_abspath,
+                         changelist_hash, result_pool);
+    }
+
   eb.db = wc_ctx->db;
   eb.processor = diff_processor;
   eb.ignore_ancestry = ignore_ancestry;
   eb.pool = scratch_pool;
 
-  if (changelist_filter && changelist_filter->nelts)
-    SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
-                                       scratch_pool));
-
   if (ignore_ancestry)
     get_all = TRUE; /* We need unmodified descendants of copies */
   else



Mime
View raw message