Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C6CC918183 for ; Tue, 19 Apr 2016 11:08:43 +0000 (UTC) Received: (qmail 74493 invoked by uid 500); 19 Apr 2016 11:08:43 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 74452 invoked by uid 500); 19 Apr 2016 11:08:43 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 74442 invoked by uid 99); 19 Apr 2016 11:08:43 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 19 Apr 2016 11:08:43 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id DB99518028D for ; Tue, 19 Apr 2016 11:08:42 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.799 X-Spam-Level: * X-Spam-Status: No, score=1.799 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RP_MATCHES_RCVD=-0.001] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id hgnoUdiNIb8p for ; Tue, 19 Apr 2016 11:08:40 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with ESMTP id CF3795F23C for ; Tue, 19 Apr 2016 11:08:39 +0000 (UTC) Received: from svn01-us-west.apache.org (svn.apache.org [10.41.0.6]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 042EDE00B6 for ; Tue, 19 Apr 2016 11:08:38 +0000 (UTC) Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 1FA1A3A022C for ; Tue, 19 Apr 2016 11:08:38 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1739897 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/conflicts.c svn/conflict-callbacks.c Date: Tue, 19 Apr 2016 11:08:37 -0000 To: commits@subversion.apache.org From: stsp@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20160419110838.1FA1A3A022C@svn01-us-west.apache.org> Author: stsp Date: Tue Apr 19 11:08:37 2016 New Revision: 1739897 URL: http://svn.apache.org/viewvc?rev=1739897&view=rev Log: Add another resolution option for file/file tree conflict "incoming add vs. local obstruction upon merge". This new option replaces the local file with the incoming fileand then merges content. Again, the implementation is rather crude since modifications made to the working copy are not atomic. This will be addressed later. * subversion/include/svn_client.h (svn_client_conflict_option_merge_incoming_added_file_replace_and_merge): New conflict option ID. * subversion/libsvn_client/conflicts.c (resolve_merge_incoming_added_file_replace_and_merge, configure_option_merge_incoming_added_file_replace_and_merge): New. (svn_client_conflict_tree_get_resolution_options): Handle the new option. * subversion/svn/conflict-callbacks.c (builtin_resolver_options): Bind a menu key code to the new option and provide a short description. Modified: subversion/trunk/subversion/include/svn_client.h subversion/trunk/subversion/libsvn_client/conflicts.c subversion/trunk/subversion/svn/conflict-callbacks.c Modified: subversion/trunk/subversion/include/svn_client.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1739897&r1=1739896&r2=1739897&view=diff ============================================================================== --- subversion/trunk/subversion/include/svn_client.h (original) +++ subversion/trunk/subversion/include/svn_client.h Tue Apr 19 11:08:37 2016 @@ -4408,6 +4408,7 @@ typedef enum svn_client_conflict_option_ /* Options for incoming file add vs local file 'obstruction' on merge. */ svn_client_conflict_option_merge_incoming_added_file_text_merge, + svn_client_conflict_option_merge_incoming_added_file_replace_and_merge, } svn_client_conflict_option_id_t; Modified: subversion/trunk/subversion/libsvn_client/conflicts.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1739897&r1=1739896&r2=1739897&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/conflicts.c (original) +++ subversion/trunk/subversion/libsvn_client/conflicts.c Tue Apr 19 11:08:37 2016 @@ -3724,6 +3724,195 @@ resolve_merge_incoming_added_file_text_m return SVN_NO_ERROR; } +/* Implements conflict_option_resolve_func_t. */ +static svn_error_t * +resolve_merge_incoming_added_file_replace_and_merge( + svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + apr_pool_t *scratch_pool) +{ + svn_ra_session_t *ra_session; + const char *url; + const char *corrected_url; + const char *repos_root_url; + const char *repos_uuid; + const char *incoming_new_repos_relpath; + svn_revnum_t incoming_new_pegrev; + apr_file_t *incoming_new_file; + svn_stream_t *incoming_new_stream; + apr_hash_t *incoming_new_props; + const char *local_abspath; + const char *lock_abspath; + svn_client_ctx_t *ctx = conflict->ctx; + svn_wc_merge_outcome_t merge_content_outcome; + svn_wc_notify_state_t merge_props_outcome; + const char *wc_tmpdir; + apr_file_t *working_file_tmp; + svn_stream_t *working_file_tmp_stream; + const char *working_file_tmp_abspath; + svn_stream_t *working_file_stream; + apr_hash_t *working_props; + apr_file_t *empty_file; + const char *empty_file_abspath; + apr_array_header_t *propdiffs; + svn_error_t *err; + + local_abspath = svn_client_conflict_get_local_abspath(conflict); + + /* Set up tempory storage for the working version of file. */ + SVN_ERR(svn_wc__get_tmpdir(&wc_tmpdir, ctx->wc_ctx, local_abspath, + scratch_pool, scratch_pool)); + SVN_ERR(svn_io_open_unique_file3(&working_file_tmp, + &working_file_tmp_abspath, wc_tmpdir, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + working_file_tmp_stream = svn_stream_from_aprfile2(working_file_tmp, + FALSE, scratch_pool); + + /* Copy the working file to temporary storage. */ + SVN_ERR(svn_stream_open_readonly(&working_file_stream, local_abspath, + scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_copy3(working_file_stream, working_file_tmp_stream, + ctx->cancel_baton, ctx->cancel_baton, + scratch_pool)); + SVN_ERR(svn_io_file_flush(working_file_tmp, scratch_pool)); + + /* Get a copy of the working file's properties. */ + SVN_ERR(svn_wc_prop_list2(&working_props, ctx->wc_ctx, local_abspath, + scratch_pool, scratch_pool)); + + /* Create a property diff against an empty base. */ + SVN_ERR(svn_prop_diffs(&propdiffs, apr_hash_make(scratch_pool), + working_props, scratch_pool)); + + /* Fetch the incoming added file from the repository. */ + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location( + &incoming_new_repos_relpath, &incoming_new_pegrev, + NULL, conflict, scratch_pool, + scratch_pool)); + SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, &repos_uuid, + conflict, scratch_pool, + scratch_pool)); + url = svn_path_url_add_component2(repos_root_url, incoming_new_repos_relpath, + scratch_pool); + SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url, + url, NULL, NULL, FALSE, FALSE, + conflict->ctx, scratch_pool, + scratch_pool)); + if (corrected_url) + url = corrected_url; + SVN_ERR(svn_io_open_unique_file3(&incoming_new_file, NULL, wc_tmpdir, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + incoming_new_stream = svn_stream_from_aprfile2(incoming_new_file, TRUE, + scratch_pool); + SVN_ERR(svn_ra_get_file(ra_session, "", incoming_new_pegrev, + incoming_new_stream, NULL, /* fetched_rev */ + &incoming_new_props, scratch_pool)); + /* Flush file to disk. */ + SVN_ERR(svn_io_file_flush(incoming_new_file, scratch_pool)); + + /* Reset the stream in preparation for adding its content to WC. */ + SVN_ERR(svn_stream_reset(incoming_new_stream)); + + /* Create an empty file as fake "merge-base" for the two added files. + * The files are not ancestrally related so this is the best we can do. */ + SVN_ERR(svn_io_open_unique_file3(&empty_file, &empty_file_abspath, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx, + local_abspath, + scratch_pool, scratch_pool)); + + /* ### The following WC modifications should be atomic. */ + + /* Replace the working file with the file from the repository. */ + err = svn_wc_delete4(ctx->wc_ctx, local_abspath, FALSE, FALSE, + ctx->cancel_func, ctx->cancel_baton, + ctx->notify_func2, ctx->notify_baton2, + scratch_pool); + if (err) + goto unlock_wc; + err = svn_wc_add_repos_file4(ctx->wc_ctx, local_abspath, + incoming_new_stream, + NULL, /* ### could we merge first, then set + ### the merged content here? */ + incoming_new_props, + NULL, /* ### merge props first, set here? */ + url, incoming_new_pegrev, + ctx->cancel_func, ctx->cancel_baton, + scratch_pool); + if (err) + goto unlock_wc; + + if (ctx->notify_func2) + { + svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath, + svn_wc_notify_add, + scratch_pool); + notify->kind = svn_node_file; + ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool); + } + + /* Resolve to current working copy state. svn_wc_merge5() requires this. */ + err = svn_wc__del_tree_conflict(ctx->wc_ctx, local_abspath, scratch_pool); + if (err) + goto unlock_wc; + + /* Perform the file merge. */ + err = svn_wc_merge5(&merge_content_outcome, &merge_props_outcome, + ctx->wc_ctx, empty_file_abspath, + working_file_tmp_abspath, local_abspath, + NULL, NULL, NULL, /* labels */ + NULL, NULL, /* conflict versions */ + FALSE, /* dry run */ + NULL, NULL, /* diff3_cmd, merge_options */ + NULL, propdiffs, + NULL, NULL, /* conflict func/baton */ + ctx->cancel_func, ctx->cancel_baton, + scratch_pool); + + if (ctx->notify_func2) + { + svn_wc_notify_t *notify = svn_wc_create_notify( + local_abspath, + svn_wc_notify_update_update, + scratch_pool); + + if (merge_content_outcome == svn_wc_merge_conflict) + notify->content_state = svn_wc_notify_state_conflicted; + else + notify->content_state = svn_wc_notify_state_merged; + notify->prop_state = merge_props_outcome; + notify->kind = svn_node_file; + ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool); + } + + +unlock_wc: + err = svn_error_compose_create(err, svn_wc__release_write_lock(ctx->wc_ctx, + lock_abspath, + scratch_pool)); + svn_io_sleep_for_timestamps(local_abspath, scratch_pool); + SVN_ERR(err); + + SVN_ERR(svn_stream_close(incoming_new_stream)); + + if (ctx->notify_func2) + { + svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved, + scratch_pool); + + ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool); + } + + conflict->resolution_tree = svn_client_conflict_option_get_id(option); + + return SVN_NO_ERROR; +} + /* Resolver options for a text conflict */ static const svn_client_conflict_option_t text_conflict_options[] = { @@ -4147,6 +4336,63 @@ configure_option_merge_incoming_added_fi return SVN_NO_ERROR; } +/* Configure 'incoming added file replace and merge' resolution option for a + * tree conflict. */ +static svn_error_t * +configure_option_merge_incoming_added_file_replace_and_merge( + svn_client_conflict_t *conflict, + apr_array_header_t *options, + apr_pool_t *scratch_pool) +{ + svn_wc_operation_t operation; + svn_wc_conflict_action_t incoming_change; + svn_wc_conflict_reason_t local_change; + svn_node_kind_t victim_node_kind; + const char *incoming_new_repos_relpath; + svn_revnum_t incoming_new_pegrev; + svn_node_kind_t incoming_new_kind; + + operation = svn_client_conflict_get_operation(conflict); + incoming_change = svn_client_conflict_get_incoming_change(conflict); + local_change = svn_client_conflict_get_local_change(conflict); + victim_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict); + SVN_ERR(svn_client_conflict_get_incoming_new_repos_location( + &incoming_new_repos_relpath, &incoming_new_pegrev, + &incoming_new_kind, conflict, scratch_pool, + scratch_pool)); + + if (operation == svn_wc_operation_merge && + victim_node_kind == svn_node_file && + incoming_new_kind == svn_node_file && + incoming_change == svn_wc_conflict_action_add && + local_change == svn_wc_conflict_reason_obstructed) + { + svn_client_conflict_option_t *option; + const char *wcroot_abspath; + + option = apr_pcalloc(options->pool, sizeof(*option)); + option->id = + svn_client_conflict_option_merge_incoming_added_file_replace_and_merge; + SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, conflict->ctx->wc_ctx, + conflict->local_abspath, scratch_pool, + scratch_pool)); + option->description = + apr_psprintf(options->pool, + _("delete '%s', copy '^/%s@%ld' here, and merge the files"), + svn_dirent_local_style( + svn_dirent_skip_ancestor(wcroot_abspath, + conflict->local_abspath), + scratch_pool), + incoming_new_repos_relpath, incoming_new_pegrev); + option->conflict = conflict; + option->do_resolve_func = + resolve_merge_incoming_added_file_replace_and_merge; + APR_ARRAY_PUSH(options, const svn_client_conflict_option_t *) = option; + } + + return SVN_NO_ERROR; +} + svn_error_t * svn_client_conflict_tree_get_resolution_options(apr_array_header_t **options, svn_client_conflict_t *conflict, @@ -4178,6 +4424,8 @@ svn_client_conflict_tree_get_resolution_ SVN_ERR(configure_option_merge_incoming_added_file_text_merge(conflict, *options, scratch_pool)); + SVN_ERR(configure_option_merge_incoming_added_file_replace_and_merge( + conflict, *options, scratch_pool)); return SVN_NO_ERROR; } Modified: subversion/trunk/subversion/svn/conflict-callbacks.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1739897&r1=1739896&r2=1739897&view=diff ============================================================================== --- subversion/trunk/subversion/svn/conflict-callbacks.c (original) +++ subversion/trunk/subversion/svn/conflict-callbacks.c Tue Apr 19 11:08:37 2016 @@ -417,6 +417,8 @@ static const resolver_option_t builtin_r /* Options for incoming file add vs local file add upon merge. */ { "m", N_("merge the files"), NULL, svn_client_conflict_option_merge_incoming_added_file_text_merge }, + { "M", N_("replace my file with incoming file and merge the files"), NULL, + svn_client_conflict_option_merge_incoming_added_file_replace_and_merge }, { NULL } };