[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] optionally disable normalization of working copy files in diff invocations

From: Stefan Sperling <stsp_at_elego.de>
Date: Thu, 17 Jul 2014 14:49:29 +0200

On Thu, Jul 17, 2014 at 01:22:19PM +0200, Matthias Gerstner wrote:
> Hello,
>
> attached is a patch against the current subversion trunk state (revision
> 1611327) that fixes a problem when using external diff programs that's
> also been described years ago here:
>
> http://svn.haxx.se/users/archive-2008-10/0664.shtml
>
> ----
> When passing the new diff command line option --no-normalization then
> svn diff won't create and pass on a temporary, normalized version of a
> file for local working copy files.
>
> This normalization is the default behaviour when svn diff encounters
> files that have the svn:keywords or svn:eol-style properties set, such
> that the base version and the working copy version of the file have the
> same format.
>
> This makes it impossible to edit diffed files when using an external
> --diff-cmd that supports editing, because the file passed to the
> external tool is a temporary file that will be deleted afterwards,
> instead of the original working copy file.
>
> When passing --no-normalization the original file is passed to the diff
> tool instead. External tools that can ignore whitespace differences
> (present due to svn:eol-style) can still display decent diffs and the
> benefit of editing the diffed files in place is helpful.
> ----
>
> Best regards,
>
> Matthias Gerstner

I'd hope we could address this without public API changes and
without adding yet another command line option.

How about we make this the default if a third party diff tool is used?
This way, third party diff tools will always display differences in
keywords, and possibly EOLs. I don't think this is much of a problem,
except for cases where all lines are considered different because of
end-of-line differences. I would hope most 3rd party tools have
options to control this behaviour. But perhaps my idea is controversial,
in which case we won't get by without adding a new option for this.

In terms of coding style, I'd use a boolean that switches normal
form on, rather than off. I find it easier to keep track of this way.

The interaction between use_text_base and your new no_normalization
flag isn't made clear. You can't have both!

Also, your change only addresses BASE->WORKING diffs, as far as I can tell.
What about REPOS->WORKING or WORKING->REPOS diffs?

The diff below (compile-tested but otherwise untested) shows how
I would try to address this without any public API changes.
Does this do what you want?

Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h (revision 1611309)
+++ subversion/include/private/svn_wc_private.h (working copy)
@@ -1578,6 +1578,10 @@ svn_wc__get_switch_editor(const svn_delta_editor_t
  * Normally, the difference from repository->working_copy is shown.
  * If @a reverse_order is TRUE, then show working_copy->repository diffs.
  *
+ * If @a use_normal_form is TRUE, normalize file content to repository-normal
+ * form before comparison. If @a use_text_base is TRUE then @use_normal_form
+ * has no effect since pristine content is always in normal form.
+ *
  * If @a cancel_func is non-NULL, it will be used along with @a cancel_baton
  * to periodically check if the client has canceled the operation.
  *
@@ -1623,6 +1627,7 @@ svn_wc__get_diff_editor(const svn_delta_editor_t *
                         svn_boolean_t use_text_base,
                         svn_boolean_t reverse_order,
                         svn_boolean_t server_performs_filtering,
+ svn_boolean_t use_normal_form,
                         const apr_array_header_t *changelist_filter,
                         const svn_diff_tree_processor_t *diff_processor,
                         svn_cancel_func_t cancel_func,
@@ -1845,6 +1850,7 @@ svn_wc__diff7(const char **root_relpath,
               const char *local_abspath,
               svn_depth_t depth,
               svn_boolean_t ignore_ancestry,
+ svn_boolean_t use_normal_form,
               const apr_array_header_t *changelist_filter,
               const svn_diff_tree_processor_t *diff_processor,
               svn_cancel_func_t cancel_func,
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c (revision 1611309)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -1638,6 +1638,7 @@ diff_wc_wc(const char **root_relpath,
            apr_pool_t *scratch_pool)
 {
   const char *abspath1;
+ diff_writer_info_t *dwi = diff_processor->baton;
 
   SVN_ERR_ASSERT(! svn_path_is_url(path1));
   SVN_ERR_ASSERT(! svn_path_is_url(path2));
@@ -1670,7 +1671,9 @@ diff_wc_wc(const char **root_relpath,
 
   SVN_ERR(svn_wc__diff7(root_relpath, root_is_dir,
                         ctx->wc_ctx, abspath1, depth,
- ignore_ancestry, changelists,
+ ignore_ancestry,
+ dwi->diff_cmd != NULL, /* use_normal_form */
+ changelists,
                         diff_processor,
                         ctx->cancel_func, ctx->cancel_baton,
                         result_pool, scratch_pool));
@@ -1890,6 +1893,7 @@ diff_repos_wc(const char **root_relpath,
   const char *copy_root_abspath;
   const char *target_url;
   svn_client__pathrev_t *loc1;
+ diff_writer_info_t *dwi = diff_processor->baton;
 
   SVN_ERR_ASSERT(! svn_path_is_url(path2));
 
@@ -2052,6 +2056,7 @@ diff_repos_wc(const char **root_relpath,
                                   rev2_is_base,
                                   reverse,
                                   server_supports_depth,
+ dwi->diff_cmd != NULL, /* use_normal_form */
                                   changelists,
                                   diff_processor,
                                   ctx->cancel_func, ctx->cancel_baton,
Index: subversion/libsvn_wc/deprecated.c
===================================================================
--- subversion/libsvn_wc/deprecated.c (revision 1611309)
+++ subversion/libsvn_wc/deprecated.c (working copy)
@@ -2031,7 +2031,7 @@ svn_wc_get_diff_editor6(const svn_delta_editor_t *
                             depth,
                             use_git_diff_format, use_text_base,
                             reverse_order, server_performs_filtering,
- changelist_filter,
+ TRUE, changelist_filter,
                             diff_processor,
                             cancel_func, cancel_baton,
                             result_pool, scratch_pool));
Index: subversion/libsvn_wc/diff.h
===================================================================
--- subversion/libsvn_wc/diff.h (revision 1611309)
+++ subversion/libsvn_wc/diff.h (working copy)
@@ -136,6 +136,7 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
+ svn_boolean_t use_normal_form,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool);
Index: subversion/libsvn_wc/diff_editor.c
===================================================================
--- subversion/libsvn_wc/diff_editor.c (revision 1611309)
+++ subversion/libsvn_wc/diff_editor.c (working copy)
@@ -115,6 +115,9 @@ struct edit_baton_t
   /* Possibly diff repos against text-bases instead of working files. */
   svn_boolean_t diff_pristine;
 
+ /* Use repository-normal form of working files. */
+ svn_boolean_t use_normal_form;
+
   /* Hash whose keys are const char * changelist names. */
   apr_hash_t *changelist_hash;
 
@@ -238,7 +241,9 @@ struct file_baton_t
  * IGNORE_ANCESTRY defines whether to utilize node ancestry when
  * calculating diffs. USE_TEXT_BASE defines whether to compare
  * against working files or text-bases. REVERSE_ORDER defines which
- * direction to perform the diff.
+ * direction to perform the diff. USE_NORMAL_FORM says whether to
+ * normalize WORKING files to repository-normal form for diffing
+ * (i.e. it only matters if USE_TEXT_BASE is FALSE).
  *
  * CHANGELIST_FILTER is a list of const char * changelist names, used to
  * filter diff output responses to only those items in one of the
@@ -255,6 +260,7 @@ make_edit_baton(struct edit_baton_t **edit_baton,
                 svn_boolean_t ignore_ancestry,
                 svn_boolean_t use_text_base,
                 svn_boolean_t reverse_order,
+ svn_boolean_t use_normal_form,
                 const apr_array_header_t *changelist_filter,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
@@ -278,6 +284,7 @@ make_edit_baton(struct edit_baton_t **edit_baton,
   eb->ignore_ancestry = ignore_ancestry;
   eb->local_before_remote = reverse_order;
   eb->diff_pristine = use_text_base;
+ eb->use_normal_form = use_normal_form;
   eb->changelist_hash = changelist_hash;
   eb->cancel_func = cancel_func;
   eb->cancel_baton = cancel_baton;
@@ -396,6 +403,7 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
                                const svn_diff_tree_processor_t *processor,
                                void *processor_dir_baton,
                                svn_boolean_t diff_pristine,
+ svn_boolean_t use_normal_form,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool)
@@ -505,7 +513,7 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
                                          db, local_abspath,
                                          working_checksum,
                                          scratch_pool, scratch_pool));
- else if (! (had_props || props_mod))
+ else if (! (had_props || props_mod) || ! (files_same || use_normal_form))
     local_file = local_abspath;
   else if (files_same)
     local_file = pristine_file;
@@ -817,6 +825,7 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
                                                 eb->changelist_hash,
                                                 eb->processor, dir_baton,
                                                 eb->diff_pristine,
+ eb->use_normal_form,
                                                 eb->cancel_func,
                                                 eb->cancel_baton,
                                                 scratch_pool));
@@ -2243,6 +2252,7 @@ svn_wc__get_diff_editor(const svn_delta_editor_t *
                         svn_boolean_t use_text_base,
                         svn_boolean_t reverse_order,
                         svn_boolean_t server_performs_filtering,
+ svn_boolean_t use_normal_form,
                         const apr_array_header_t *changelist_filter,
                         const svn_diff_tree_processor_t *diff_processor,
                         svn_cancel_func_t cancel_func,
@@ -2265,7 +2275,8 @@ svn_wc__get_diff_editor(const svn_delta_editor_t *
                           anchor_abspath, target,
                           diff_processor,
                           depth, ignore_ancestry,
- use_text_base, reverse_order, changelist_filter,
+ use_text_base, reverse_order, use_normal_form,
+ changelist_filter,
                           cancel_func, cancel_baton,
                           result_pool));
 
Index: subversion/libsvn_wc/diff_local.c
===================================================================
--- subversion/libsvn_wc/diff_local.c (revision 1611309)
+++ subversion/libsvn_wc/diff_local.c (working copy)
@@ -89,6 +89,9 @@ struct diff_baton
   /* Should this diff ignore node ancestry? */
   svn_boolean_t ignore_ancestry;
 
+ /* Should this diff use repos-normal form for working files? */
+ svn_boolean_t use_normal_form;
+
   /* Hash whose keys are const char * changelist names. */
   apr_hash_t *changelist_hash;
 
@@ -364,6 +367,7 @@ diff_status_callback(void *baton,
                                                         ? eb->cur->baton
                                                         : NULL,
                                                    FALSE,
+ eb->use_normal_form,
                                                    eb->cancel_func,
                                                    eb->cancel_baton,
                                                    scratch_pool));
@@ -435,6 +439,7 @@ svn_wc__diff7(const char **root_relpath,
               const char *local_abspath,
               svn_depth_t depth,
               svn_boolean_t ignore_ancestry,
+ svn_boolean_t use_normal_form,
               const apr_array_header_t *changelist_filter,
               const svn_diff_tree_processor_t *diff_processor,
               svn_cancel_func_t cancel_func,
@@ -478,6 +483,7 @@ svn_wc__diff7(const char **root_relpath,
   eb.db = wc_ctx->db;
   eb.processor = diff_processor;
   eb.ignore_ancestry = ignore_ancestry;
+ eb.use_normal_form = use_normal_form;
   eb.pool = scratch_pool;
 
   if (changelist_filter && changelist_filter->nelts)
@@ -564,6 +570,7 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
                                        wc_ctx, local_abspath,
                                        depth,
                                        ignore_ancestry,
+ TRUE, /* use_normal_form */
                                        changelist_filter,
                                        processor,
                                        cancel_func, cancel_baton,
Received on 2014-07-17 14:50:04 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.