On 10/16/07, cacknin@tigris.org <cacknin@tigris.org> wrote:
> Author: cacknin
> Date: Tue Oct 16 13:02:16 2007
> New Revision: 27222
>
> Log:
> Attempt to fix 'svn patch' copy/move behavior using copyfrom argument
> from WC-WC serialiazed diff.
>
> * subversion/libsvn_client/patch.c:
> (create_empty_file): put a forward declaration at the beginning.
> (add_file_with_history): new function to help merge_file_added in its
> quest for both correctness and clarity.
> (merge_file_added): make use of add_file_with_history and a large
> amount of indent adjustments.
> (merge_file_deleted): prevent svn_client__wc_delete from deleting the
> file when it has local modifications.
>
>
> Modified:
> branches/svnpatch-diff/subversion/libsvn_client/patch.c
>
> Modified: branches/svnpatch-diff/subversion/libsvn_client/patch.c
> URL: http://svn.collab.net/viewvc/svn/branches/svnpatch-diff/subversion/libsvn_client/patch.c?pathrev=27222&r1=27221&r2=27222
> ==============================================================================
> --- branches/svnpatch-diff/subversion/libsvn_client/patch.c (original)
> +++ branches/svnpatch-diff/subversion/libsvn_client/patch.c Tue Oct 16 13:02:16 2007
> @@ -59,6 +59,14 @@
> /*-----------------------------------------------------------------------*/
>
>
> +/* Forward declaration to keep things organised. */
> +static svn_error_t *
> +create_empty_file(apr_file_t **file,
> + const char **empty_file_path,
> + svn_wc_adm_access_t *adm_access,
> + svn_io_file_del_t delete_when,
> + apr_pool_t *pool);
> +
create_empty_file doesn't call anything else in this file... maybe
just move it up itself? (Or does that throw off the organization of
the whole file?)
> struct patch_cmd_baton {
> svn_boolean_t force;
> svn_boolean_t dry_run;
> @@ -283,6 +291,85 @@
> return SVN_NO_ERROR;
> }
>
> +/* This is to keep merge_file_added() clean. We're dealing with a
> + * schedule-add-with-history operation where @a copyfrom_path is the
> + * source and @a path the destination. @a adm_access is @a path's
> + * parent access baton. This is either a file move or a file copy.
> + * When the former, what we do depend on whether (a) the source path has
> + * local modifications and (b) the delete-entry call is past or
> + * forthcoming. If the copyfrom file has no local modification and the
> + * delete-entry is past, then it was removed from disk thus we use it's
> + * text-base instead as we're offline. */
It doesn't actually look like the local-mods issues are dealt with
here... or does svn_wc_copy2 handle that? (Is this situation tested?
In general, are any of the corner cases tested?)
> +static svn_error_t *
> +add_file_with_history(const char *path,
> + svn_wc_adm_access_t *adm_access,
> + const char *copyfrom_path,
> + void *patch_baton,
> + apr_pool_t *pool)
> +{
> + svn_node_kind_t copyfrom_kind, copyfrom_textbase_kind;
> + const char *copyfrom_textbase_path;
> + struct patch_cmd_baton *patch_b = patch_baton;
> + const char *path_basename = svn_path_basename(path, pool);
> +
> + SVN_ERR(svn_io_check_path(copyfrom_path, ©from_kind, pool));
> +
> + if (copyfrom_kind == svn_node_none)
> + {
> + SVN_ERR(svn_wc_get_pristine_copy_path(copyfrom_path,
> + ©from_textbase_path,
> + pool));
> + SVN_ERR(svn_io_check_path(copyfrom_textbase_path,
> + ©from_textbase_kind, pool));
> +
> + /* When the text-base is missing we really can't help. */
> + if (copyfrom_textbase_kind == svn_node_none)
> + return svn_error_create(SVN_ERR_WC_COPYFROM_PATH_NOT_FOUND,
> + NULL, NULL);
> + }
> +
> + if (! patch_b->dry_run)
> + {
> + if (copyfrom_kind == svn_node_none)
> + {
> + char *copyfrom_url;
> + const char *copyfrom_src; /* copy of copyfrom's text-base */
> + svn_revnum_t copyfrom_rev;
> + svn_wc_adm_access_t *copyfrom_access;
> +
> + /* Since @c svn_wc_add_repos_file2() *moves* text-base path to
> + * target-path, operate on a copy of it instead. */
> + SVN_ERR(create_empty_file(NULL, ©from_src, adm_access,
> + svn_io_file_del_none, pool));
> + SVN_ERR(svn_io_copy_file(copyfrom_textbase_path, copyfrom_src,
> + FALSE, pool));
> +
> + /* The file we're about to add needs a copyfrom_url along with
> + * a copyfrom_rev, which we both retrieve through the working
> + * copy administrative area of the source file. */
> + SVN_ERR(svn_wc_adm_probe_open3(©from_access, NULL,
> + copyfrom_path, FALSE, -1,
> + patch_b->ctx->cancel_func,
> + patch_b->ctx->cancel_baton, pool));
> + SVN_ERR(svn_wc_get_ancestry(©from_url, ©from_rev,
> + copyfrom_path, copyfrom_access, pool));
> + SVN_ERR(svn_wc_add_repos_file2(path, adm_access,
> + copyfrom_src, NULL,
> + apr_hash_make(pool), NULL,
Hmm, looks like you're throwing away all the props there... that can't
be right.
> + copyfrom_url, copyfrom_rev,
> + pool));
> + }
> + else
> + SVN_ERR(svn_wc_copy2(copyfrom_path, adm_access, path_basename,
> + patch_b->ctx->cancel_func,
> + patch_b->ctx->cancel_baton,
> + NULL, NULL, /* no notification */
> + pool));
> + }
> +
> + return SVN_NO_ERROR;
> +}
> +
> /* A svn_wc_diff_callbacks3_t function. */
> static svn_error_t *
> merge_file_added(svn_wc_adm_access_t *adm_access,
> @@ -303,7 +390,6 @@
> {
> struct patch_cmd_baton *patch_b = baton;
> apr_pool_t *subpool = svn_pool_create(patch_b->pool);
> - const char *mine_basename = svn_path_basename(mine, subpool);
> svn_node_kind_t kind;
> int i;
> apr_hash_t *new_props;
> @@ -361,52 +447,45 @@
> return SVN_NO_ERROR;
> }
>
> - if (! patch_b->dry_run)
> + if (copyfrom_path) /* schedule-add-with-history */
> {
> - if (copyfrom_path) /* schedule-add-with-history */
> - {
> - /* Check whether the source we want to copy from exists. */
> - svn_node_kind_t copyfrom_kind;
> - SVN_ERR(svn_io_check_path(copyfrom_path, ©from_kind,
> - subpool));
> -
> - if (copyfrom_kind == svn_node_none)
> - {
> - if (content_state)
> - *content_state = svn_wc_notify_state_source_missing;
> - svn_pool_destroy(subpool);
> - return SVN_NO_ERROR;
> - }
> -
> - SVN_ERR(svn_wc_copy2(copyfrom_path, adm_access, mine_basename,
> - patch_b->ctx->cancel_func,
> - patch_b->ctx->cancel_baton,
> - NULL, NULL, /* no notification */
> - subpool));
> - }
> - else /* schedule-add */
> + svn_error_t *err;
> + err = add_file_with_history(mine, adm_access, copyfrom_path,
> + patch_b, subpool);
> +
> + if (err && err->apr_err == SVN_ERR_WC_COPYFROM_PATH_NOT_FOUND)
> {
> - /* Copy the cached empty file and schedule-add it. The
> - * contents will come in either via apply-textdelta
> - * following calls if this is a binary file or with
> - * unidiff for text files. */
> - SVN_ERR(svn_io_copy_file(yours, mine, TRUE, subpool));
> - SVN_ERR(svn_wc_add2(mine, adm_access, NULL, SVN_IGNORED_REVNUM,
> - patch_b->ctx->cancel_func,
> - patch_b->ctx->cancel_baton,
> - NULL, NULL, /* no notification */
> - subpool));
> + if (content_state)
> + *content_state = svn_wc_notify_state_source_missing;
> + svn_error_clear(err);
> + svn_pool_destroy(subpool);
> + return SVN_NO_ERROR;
> }
> -
> - /* Now regardless of the schedule-add nature, merge properties. */
> - if (prop_changes->nelts > 0)
> - SVN_ERR(merge_props_changed(adm_access, prop_state,
> - mine, prop_changes,
> - original_props, baton));
> - else
> - if (prop_state)
> - *prop_state = svn_wc_notify_state_unchanged;
> + else if (err)
> + return err;
> }
> + else if (! patch_b->dry_run) /* schedule-add */
> + {
> + /* Copy the cached empty file and schedule-add it. The
> + * contents will come in either via apply-textdelta
> + * following calls if this is a binary file or with
> + * unidiff for text files. */
> + SVN_ERR(svn_io_copy_file(yours, mine, TRUE, subpool));
> + SVN_ERR(svn_wc_add2(mine, adm_access, NULL, SVN_IGNORED_REVNUM,
> + patch_b->ctx->cancel_func,
> + patch_b->ctx->cancel_baton,
> + NULL, NULL, /* no notification */
> + subpool));
> + }
> +
> + /* Now regardless of the schedule-add nature, merge properties. */
> + if (prop_changes->nelts > 0)
> + SVN_ERR(merge_props_changed(adm_access, prop_state,
> + mine, prop_changes,
> + original_props, baton));
> + else
> + if (prop_state)
> + *prop_state = svn_wc_notify_state_unchanged;
>
> if (content_state)
> *content_state = svn_wc_notify_state_changed;
> @@ -491,6 +570,7 @@
> svn_wc_adm_access_t *parent_access;
> const char *parent_path;
> svn_error_t *err;
> + svn_boolean_t has_local_mods;
>
> /* Easy out: if we have no adm_access for the parent directory,
> then this portion of the tree-delta "patch" must be inapplicable.
> @@ -511,10 +591,15 @@
> svn_path_split(mine, &parent_path, NULL, subpool);
> SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parent_path,
> subpool));
> +
> + SVN_ERR(svn_wc_text_modified_p(&has_local_mods, mine, TRUE,
> + adm_access, subpool));
> /* Passing NULL for the notify_func and notify_baton because
> delete_entry() will do it for us. */
> err = svn_client__wc_delete(mine, parent_access, patch_b->force,
> - patch_b->dry_run, FALSE, NULL, NULL,
> + patch_b->dry_run,
> + has_local_mods ? TRUE : FALSE,
> + NULL, NULL,
Hmm, so a delete (whether or not in a move) coming in against a file
with local-mods won't be any sort of conflict, it'll just leave it
unversioned? I guess that's reasonable?
> patch_b->ctx, subpool);
> if (err && state)
> {
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: svn-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: svn-help@subversion.tigris.org
>
>
--dave
--
David Glasser | glasser_at_davidglasser.net | http://www.davidglasser.net/
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Wed Oct 17 00:07:35 2007