/* * 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 #include #include #include #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; }