On Fri, Feb 11, 2011 at 11:26 PM, Daniel Shahaf <d...@daniel.shahaf.name>wrote:

> [ 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'.
>

I wasn't aware of these options. Thanks.


>  > 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).
>

I've been trying to think of a valid scenario for this to occur, but I can't
seem to think of one. There's a comment further up:

  /* Other easy outs:  if the merge target isn't under version
     control, or is just missing from disk, fogettaboutit.  There's no
     way svn_wc_merge4() can do the merge. */

This should apply to all situations (binary and text files), so I think this
second "special case" is redundant.


> > +  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
>

Oops, fixed.


> > +          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.
>

I copied this directly from the call further down, where a file is copied
depending on which version to use in a conflict. Even if "theirs" is used,
we still pass in FALSE for record_fileinfo.

The RECORD_FILEINFO flag controls whether the file's information should be
recorded into the wc.db. It seems that we only pass TRUE to this if we are
installing a fresh file. It makes sense to pass in FALSE during a merge,
otherwise the file won't be seen as modified.

PS: The two calls in update_editor.c don't pass in NULL, but pass in a value
based on comparing against NULL.

    record_fileinfo = new_contents == NULL;
    record_fileinfo = install_from == NULL;

 * 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?
>

Which svn_wc__wq_build_file_install() call do you mean?

We return SVN_NO_ERROR immediately after building adding this workqueue
item, so the other one for the binary file conflict resolution will not get
called.


> > +        }
> > +
> > +      *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().)
>

Agreed, however this was always the case. The only change I made to this
section was indentation
due to removing the surrounding if (merge_required) { } clause. I didn't
want to make other changes
that would be clouded.

I can submit a follow-up patch that fixes this as well, if necessary.


>  >            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)
> >          {
>

Thanks for the review, Daniel.

Cheers,
Daniel^2.

Reply via email to