Author: julianfoad Date: Thu Dec 17 14:50:51 2015 New Revision: 1720560 URL: http://svn.apache.org/viewvc?rev=1720560&view=rev Log: Add skeleton code for a merge-by-elements feature.
See dev@ email thread "[RFC] An element-based 'svn merge'" started by me on 2015-12-17, archived at e.g. http://svn.haxx.se/dev/archive-2015-12/0061.shtml or http://mail-archives.apache.org/mod_mbox/subversion-dev/201512.mbox/%3CCAEcU=1aurg2sy96ff5b0hbccolxkb1f67cdcms6nfz2d9cg...@mail.gmail.com%3E This is conditional on an environment variable 'SVN_ELEMENT_MERGE' being set. * subversion/libsvn_client/client.h (merge_source_t, merge_target_t): Move these definitions to here from merge.c. (svn_client__merge_elements): New. * subversion/libsvn_client/merge.c (merge_peg_locked): Call the merge-by-elements code under certain conditions. * subversion/libsvn_client/merge_elements.c New file. Added: subversion/trunk/subversion/libsvn_client/merge_elements.c (with props) Modified: subversion/trunk/subversion/libsvn_client/client.h subversion/trunk/subversion/libsvn_client/merge.c Modified: subversion/trunk/subversion/libsvn_client/client.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1720560&r1=1720559&r2=1720560&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/client.h (original) +++ subversion/trunk/subversion/libsvn_client/client.h Thu Dec 17 14:50:51 2015 @@ -1185,6 +1185,48 @@ svn_client__remote_propget(apr_hash_t *p apr_pool_t *result_pool, apr_pool_t *scratch_pool); +/* */ +typedef struct merge_source_t +{ + /* "left" side URL and revision (inclusive iff youngest) */ + const svn_client__pathrev_t *loc1; + + /* "right" side URL and revision (inclusive iff youngest) */ + const svn_client__pathrev_t *loc2; + + /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */ + svn_boolean_t ancestral; +} merge_source_t; + +/* Description of the merge target root node (a WC working node) */ +typedef struct merge_target_t +{ + /* Absolute path to the WC node */ + const char *abspath; + + /* The repository location of the base node of the target WC. If the node + * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM. + * REPOS_ROOT_URL and REPOS_UUID are always valid. */ + svn_client__pathrev_t loc; + +} merge_target_t; + +/* + * Similar API to svn_client_merge_peg5(). + */ +svn_error_t * +svn_client__merge_elements(svn_boolean_t *use_sleep, + apr_array_header_t *merge_sources, + merge_target_t *target, + svn_ra_session_t *ra_session, + svn_boolean_t diff_ignore_ancestry, + svn_boolean_t force_delete, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Modified: subversion/trunk/subversion/libsvn_client/merge.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1720560&r1=1720559&r2=1720560&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/merge.c (original) +++ subversion/trunk/subversion/libsvn_client/merge.c Thu Dec 17 14:50:51 2015 @@ -215,32 +215,6 @@ /*** Repos-Diff Editor Callbacks ***/ -/* */ -typedef struct merge_source_t -{ - /* "left" side URL and revision (inclusive iff youngest) */ - const svn_client__pathrev_t *loc1; - - /* "right" side URL and revision (inclusive iff youngest) */ - const svn_client__pathrev_t *loc2; - - /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */ - svn_boolean_t ancestral; -} merge_source_t; - -/* Description of the merge target root node (a WC working node) */ -typedef struct merge_target_t -{ - /* Absolute path to the WC node */ - const char *abspath; - - /* The repository location of the base node of the target WC. If the node - * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM. - * REPOS_ROOT_URL and REPOS_UUID are always valid. */ - svn_client__pathrev_t loc; - -} merge_target_t; - typedef struct merge_cmd_baton_t { svn_boolean_t force_delete; /* Delete a file/dir even if modified */ svn_boolean_t dry_run; @@ -11853,6 +11827,21 @@ merge_peg_locked(conflict_report_t **con /* Do the real merge! (We say with confidence that our merge sources are both ancestral and related.) */ + if (getenv("SVN_ELEMENT_MERGE") + && same_repos + && (depth == svn_depth_infinity || depth == svn_depth_unknown) + && ignore_mergeinfo + && !record_only) + { + err = svn_client__merge_elements(&use_sleep, + merge_sources, target, ra_session, + diff_ignore_ancestry, force_delete, + dry_run, merge_options, + ctx, result_pool, scratch_pool); + /* ### Currently this merge just errors out on any conflicts */ + *conflict_report = NULL; + } + else err = do_merge(NULL, NULL, conflict_report, &use_sleep, merge_sources, target, ra_session, TRUE /*sources_related*/, same_repos, ignore_mergeinfo, Added: subversion/trunk/subversion/libsvn_client/merge_elements.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge_elements.c?rev=1720560&view=auto ============================================================================== --- subversion/trunk/subversion/libsvn_client/merge_elements.c (added) +++ subversion/trunk/subversion/libsvn_client/merge_elements.c Thu Dec 17 14:50:51 2015 @@ -0,0 +1,248 @@ +/* + * merge_elements.c: element-based merging + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <assert.h> +#include <apr_strings.h> +#include <apr_tables.h> +#include <apr_hash.h> +#include "svn_types.h" +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_hash.h" +#include "svn_wc.h" +#include "svn_client.h" +#include "svn_dirent_uri.h" + +#include "client.h" +#include "private/svn_element.h" + +#include "svn_private_config.h" + + +/* Print a notification. + * ### TODO: Send notifications through ctx->notify_func2(). + * ### TODO: Only when 'verbose' output is requested. + */ +static +__attribute__((format(printf, 1, 2))) +void +verbose_notify(const char *fmt, + ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + if (fmt[strlen(fmt) - 1] != '\n') + printf("\n"); + va_end(ap); +} + +/* Return a string representation of PATHREV. */ +static const char * +pathrev_str(const svn_client__pathrev_t *pathrev, + apr_pool_t *pool) +{ + const char *rrpath + = svn_uri_skip_ancestor(pathrev->repos_root_url, pathrev->url, pool); + + return apr_psprintf(pool, "^/%s@%ld", rrpath, pathrev->rev); +} + +/* Element matching info. + */ +typedef struct element_matching_info_t +{ + void *info; +} element_matching_info_t; + +/* Return a string representation of INFO. */ +static const char * +element_matching_info_str(const element_matching_info_t *info, + apr_pool_t *result_pool) +{ + /* ### */ + const char *str = "{...}"; + + return str; +} + +/* Assign EIDs (in memory) to the source-left, source-right and target + * trees. + */ +static svn_error_t * +assign_eids_to_trees(svn_element__tree_t **tree_left_p, + svn_element__tree_t **tree_right_p, + svn_element__tree_t **tree_target_p, + const svn_client__pathrev_t *src_left, + const svn_client__pathrev_t *src_right, + merge_target_t *target, + svn_ra_session_t *ra_session, + element_matching_info_t *element_matching_info, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + verbose_notify("--- Assigning EIDs to trees"); + + /* ### */ + return SVN_NO_ERROR; +} + +/* Perform a three-way tree merge. Write the result to *MERGE_RESULT_P. + * + * Set *CONFLICTS_P to describe any conflicts, or set *CONFLICTS_P to + * null if there are none. + */ +static svn_error_t * +merge_trees(svn_element__tree_t **merge_result_p, + void **conflicts_p, + svn_element__tree_t *tree_left, + svn_element__tree_t *tree_right, + svn_element__tree_t *tree_target, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + verbose_notify("--- Merging trees"); + + /* ### */ + *merge_result_p = NULL; + *conflicts_p = NULL; + return SVN_NO_ERROR; +} + +/* Convert the MERGE_RESULT to a series of WC edits and apply those to + * the WC described in TARGET. + */ +static svn_error_t * +apply_merge_result_to_wc(merge_target_t *target, + svn_element__tree_t *merge_result, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + verbose_notify("--- Writing merge result to WC"); + + return SVN_NO_ERROR; +} + +/* Do a three-way element-based merge for one merge source range, + * SRC_LEFT:SRC_RIGHT. If there are no conflicts, write the result to the + * WC described in TARGET. + */ +static svn_error_t * +merge_elements_one_source(svn_boolean_t *use_sleep, + const svn_client__pathrev_t *src_left, + const svn_client__pathrev_t *src_right, + merge_target_t *target, + svn_ra_session_t *ra_session, + element_matching_info_t *element_matching_info, + svn_boolean_t diff_ignore_ancestry, + svn_boolean_t force_delete, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_element__tree_t *tree_left, *tree_right, *tree_target; + svn_element__tree_t *merge_result; + void *conflicts; + + verbose_notify("--- Merging by elements: " + "left=%s, right=%s, matching=%s", + pathrev_str(src_left, scratch_pool), + pathrev_str(src_right, scratch_pool), + element_matching_info_str(element_matching_info, + scratch_pool)); + + /* assign EIDs (in memory) to the source-left, source-right and target + trees */ + SVN_ERR(assign_eids_to_trees(&tree_left, &tree_right, &tree_target, + src_left, src_right, target, ra_session, + element_matching_info, + ctx, scratch_pool, scratch_pool)); + + /* perform a tree merge, creating a temporary result (in memory) */ + SVN_ERR(merge_trees(&merge_result, &conflicts, + tree_left, tree_right, tree_target, + scratch_pool, scratch_pool)); + + /* check for (new style) conflicts in the result; if any, bail out */ + if (conflicts) + { + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Merge had conflicts; " + "this is not yet supported")); + } + + /* convert the result to a series of WC edits and apply those to the WC */ + if (dry_run) + { + verbose_notify("--- Dry run; not writing merge result to WC"); + } + else + { + SVN_ERR(apply_merge_result_to_wc(target, merge_result, + ctx, scratch_pool)); + *use_sleep = TRUE; + } + + /* forget all the EID metadata */ + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client__merge_elements(svn_boolean_t *use_sleep, + apr_array_header_t *merge_sources, + merge_target_t *target, + svn_ra_session_t *ra_session, + svn_boolean_t diff_ignore_ancestry, + svn_boolean_t force_delete, + svn_boolean_t dry_run, + const apr_array_header_t *merge_options, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + int i; + + /* Merge each source range in turn */ + for (i = 0; i < merge_sources->nelts; i++) + { + merge_source_t *source + = APR_ARRAY_IDX(merge_sources, i, void *); + element_matching_info_t *element_matching_info; + + /* ### TODO: get element matching info from the user */ + element_matching_info = NULL; + + SVN_ERR(merge_elements_one_source(use_sleep, + source->loc1, source->loc2, + target, ra_session, + element_matching_info, + diff_ignore_ancestry, + force_delete, dry_run, merge_options, + ctx, scratch_pool)); + } + + return SVN_NO_ERROR; +} Propchange: subversion/trunk/subversion/libsvn_client/merge_elements.c ------------------------------------------------------------------------------ svn:eol-style = native
