[ disclaimer: I'm not familiar with wc internals yet; sorry; hope I'll
learn something while reviewing this ]

Daniel Becroft wrote on Thu, Feb 10, 2011 at 07:21:30 +1000:
> >
> Hey Stefan,
> 
> It was only partially bypassing the work queue. The items to update the
> executable bit (and read/write bits) is always done at the end of the
> svn_wc_merge4() function, so that's why the test started passing. However,
> you are correct - I should have been using the svn_wc__wq_build_file_install
> workqueue task to copy the file across (this is what happens when a conflict
> is resolved with "theirs-full").
> 
> An updated patch is attached.
> 
> [[[
> Fix issue #3686 - executable bit not set during merge.
> 
> The cause was the special case in libsvn_client, which bypassed the
> use of the workqueue. This logic has now been moved into libsvn_wc.
> 
> Additionally, this change allows the status of binary files (during
> a dry-run merge) to be reported correctly (previously, all binary
> files were reported as conflicted).
> 

Well written.

> * subversion/libsvn_client/merge.c
>  (merge_file_changed): Removed binary-merge special case (now in libsvn_wc).
>    Removed merge_required variable (resulting in indentation changes).
> 

Two spaces before (.  [I guess it was right when you sent it, since your
mail mis-wrapped the above paragraphs as well]

> * subversion/libsvn_wc/merge.c
>  (merge_binary_file): Added dry_run parameter. Add the special case merging
>   of binary files.
>  (svn_wc__internal_merge): Removed dry_run check for binary files, and
>  pass to merge_binary_file instead.
> 

Use present tense please.

> * subversion/tests/cmdline/merge_tests.py
>  (merge_change_to_file_with_executable): Remove @XFail decorator.
> ]]]
> 
> Cheers,
> Daniel B
> (who is not a C programmer by trade ...)

> Index: subversion/libsvn_wc/merge.c
> ===================================================================
> --- subversion/libsvn_wc/merge.c      (revision 1068136)
> +++ subversion/libsvn_wc/merge.c      (working copy)
> @@ -1094,6 +1094,7 @@
>                    const char *left_label,
>                    const char *right_label,
>                    const char *target_label,
> +                  svn_boolean_t dry_run,

It would have been easier to review the patch if you'd attached
a version generated with 'svn diff -x-pw'.

> Index: subversion/libsvn_wc/merge.c
> ===================================================================
> --- subversion/libsvn_wc/merge.c      (revision 1069789)
> +++ subversion/libsvn_wc/merge.c      (working copy)
> @@ -1094,6 +1094,7 @@ merge_binary_file(svn_skel_t **work_items,
>                    const char *left_label,
>                    const char *right_label,
>                    const char *target_label,
> +                  svn_boolean_t dry_run,
>                    const svn_wc_conflict_version_t *left_version,
>                    const svn_wc_conflict_version_t *right_version,
>                    const char *detranslated_target_abspath,
> @@ -1118,6 +1120,33 @@ merge_binary_file(svn_skel_t **work_items,
>  
>    svn_dirent_split(&merge_dirpath, &merge_filename, target_abspath, pool);
>  
> +  /* Attempt to merge the binary file. At the moment, we can only 
> +     handle the special case: if the LEFT side of the merge is equal
> +     to WORKING, then we can copy RIGHT directly. */

The comment in libsvn_client mentioned two special case, what happened
to the other one?  Does the existing wc code already handle it? (I'd be
surprised)

  -         Alternately, if the 'left' side of the merge doesn't exist in
  -         the repository, and the 'right' side of the merge is
  -         identical to the WC, pretend we did the merge (a no-op).

> +  SVN_ERR(svn_io_files_contents_same_p(&same_contents,
> +                                      left_abspath,
> +                                      target_abspath,
> +                                      scratch_pool));
> +
> +  if (same_contents)
> +    {
> +      if (!dry_run)
> +        {
> +          svn_skel_t *work_item;
> +

subversion/libsvn_wc/merge.c: In function ‘merge_binary_file’:
subversion/libsvn_wc/merge.c:1135: warning: declaration of ‘work_item’ shadows 
a previous local
subversion/libsvn_wc/merge.c:1114: warning: shadowed declaration is here

> +          SVN_ERR(svn_wc__wq_build_file_install(&work_item,
> +                                                db, target_abspath,
> +                                                right_abspath,
> +                                                FALSE /* use_commit_times */,
> +                                                FALSE /* record_fileinfo */,

About RECORD_FILEINFO:

* Why are you passing FALSE?  (I see that other calls do this too, so
  this is for my education mainly))  A quick scan makes me expect that
  parameter to control the mtime/size caches for modification detection.

* In update_editor.c there are two places that pass NULL (not FALSE) for
  that, and have above them comment that says that "If %s, we want to
  pass FALSE".  What is going on there?
  (this is to the list, not specifically at Daniel)

> +                                                result_pool, scratch_pool));
> +          *work_items = svn_wc__wq_merge(*work_items, work_item, 
> result_pool);

Don't you need to convert the next svn_wc__wq_build_file_install() to
use this 'build-then-merge' approach too?  Otherwise, won't it overwrite
your WORK_ITEMS?

> +        }
> +
> +      *merge_outcome = svn_wc_merge_merged;
> +      return SVN_NO_ERROR;
> +    }
> +
>    /* Give the conflict resolution callback a chance to clean
>       up the conflict before we mark the file 'conflicted' */
>    if (conflict_func)
> @@ -1357,10 +1386,6 @@ svn_wc__internal_merge(svn_skel_t **work_items,
>  
>    if (is_binary)
>      {
> -      if (dry_run)
> -        /* in dry-run mode, binary files always conflict */
> -        *merge_outcome = svn_wc_merge_conflict;
> -      else
>          SVN_ERR(merge_binary_file(work_items,
>                                    merge_outcome,
>                                    db,
> @@ -1370,6 +1395,7 @@ svn_wc__internal_merge(svn_skel_t **work_items,
>                                    left_label,
>                                    right_label,
>                                    target_label,
> +                                dry_run,
>                                    left_version,
>                                    right_version,
>                                    detranslated_target_abspath,
> Index: subversion/libsvn_client/merge.c
> ===================================================================
> --- subversion/libsvn_client/merge.c  (revision 1069789)
> +++ subversion/libsvn_client/merge.c  (working copy)
> @@ -1300,7 +1300,6 @@ merge_file_changed(const char *local_dir_abspath,
>  {
>    merge_cmd_baton_t *merge_b = baton;
>    apr_pool_t *subpool = svn_pool_create(merge_b->pool);
> -  svn_boolean_t merge_required = TRUE;
>    enum svn_wc_merge_outcome_t merge_outcome;
>  
>    SVN_ERR_ASSERT(mine_abspath && svn_dirent_is_absolute(mine_abspath));
> @@ -1449,45 +1448,7 @@ merge_file_changed(const char *local_dir_abspath,
>    if (older_abspath)
>      {
>        svn_boolean_t has_local_mods;
> -      SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, merge_b->ctx->wc_ctx,
> -                                      mine_abspath, FALSE, subpool));
>  
> -      /* Special case:  if a binary file's working file is
> -         exactly identical to the 'left' side of the merge, then don't
> -         allow svn_wc_merge to produce a conflict.  Instead, just
> -         overwrite the working file with the 'right' side of the
> -         merge.  Why'd we check for local mods above?  Because we want
> -         to do a different notification depending on whether or not
> -         the file was locally modified.
> -
> -         Alternately, if the 'left' side of the merge doesn't exist in
> -         the repository, and the 'right' side of the merge is
> -         identical to the WC, pretend we did the merge (a no-op). */
> -      if ((mimetype1 && svn_mime_type_is_binary(mimetype1))
> -          || (mimetype2 && svn_mime_type_is_binary(mimetype2)))
> -        {
> -          /* For adds, the 'left' side of the merge doesn't exist. */
> -          svn_boolean_t older_revision_exists =
> -              !merge_b->add_necessitated_merge;
> -          svn_boolean_t same_contents;
> -          SVN_ERR(svn_io_files_contents_same_p(&same_contents,
> -                                               (older_revision_exists ?
> -                                                older_abspath : 
> yours_abspath),
> -                                               mine_abspath, subpool));
> -          if (same_contents)
> -            {
> -              if (older_revision_exists && !merge_b->dry_run)
> -                {
> -                  SVN_ERR(svn_io_file_move(yours_abspath, mine_abspath,
> -                                           subpool));
> -                }
> -              merge_outcome = svn_wc_merge_merged;
> -              merge_required = FALSE;
> -            }
> -        }
> -
> -      if (merge_required)
> -        {
>            /* xgettext: the '.working', '.merge-left.r%ld' and
>               '.merge-right.r%ld' strings are used to tag onto a file
>               name in case of a merge conflict */
> @@ -1502,6 +1463,9 @@ merge_file_changed(const char *local_dir_abspath,
>            const svn_wc_conflict_version_t *left;
>            const svn_wc_conflict_version_t *right;
>  
> +      SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, merge_b->ctx->wc_ctx,
> +                                      mine_abspath, FALSE, subpool));
> +

You only need HAS_LOCAL_MODS now when CONTENT_STATE is set.  Shouldn't
you skip this call when CONTENT_STATE is NULL then?  (It may perform
stat() or read().)

>            conflict_baton.wrapped_func = merge_b->ctx->conflict_func;
>            conflict_baton.wrapped_baton = merge_b->ctx->conflict_baton;
>            conflict_baton.conflicted_paths = &merge_b->conflicted_paths;
> @@ -1519,7 +1483,6 @@ merge_file_changed(const char *local_dir_abspath,
>                                  merge_b->ctx->cancel_func,
>                                  merge_b->ctx->cancel_baton,
>                                  subpool));
> -        }
>  
>        if (content_state)
>          {

Reply via email to