2 * merge_elements.c: element-based merging
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
25 #include <apr_strings.h>
26 #include <apr_tables.h>
28 #include "svn_types.h"
29 #include "svn_error.h"
30 #include "svn_pools.h"
33 #include "svn_client.h"
34 #include "svn_dirent_uri.h"
37 #include "private/svn_element.h"
39 #include "svn_private_config.h"
42 /* Print a notification.
43 * ### TODO: Send notifications through ctx->notify_func2().
44 * ### TODO: Only when 'verbose' output is requested.
47 __attribute__((format(printf, 1, 2)))
49 verbose_notify(const char *fmt,
56 if (fmt[strlen(fmt) - 1] != '\n')
61 /* Return a string representation of PATHREV. */
63 pathrev_str(const svn_client__pathrev_t *pathrev,
67 = svn_uri_skip_ancestor(pathrev->repos_root_url, pathrev->url, pool);
69 return apr_psprintf(pool, "^/%s@%ld", rrpath, pathrev->rev);
72 /* Element matching info.
74 typedef struct element_matching_info_t
77 } element_matching_info_t;
79 /* Return a string representation of INFO. */
81 element_matching_info_str(const element_matching_info_t *info,
82 apr_pool_t *result_pool)
85 const char *str = "{...}";
90 /* Assign EIDs (in memory) to the source-left, source-right and target
94 assign_eids_to_trees(svn_element__tree_t **tree_left_p,
95 svn_element__tree_t **tree_right_p,
96 svn_element__tree_t **tree_target_p,
97 const svn_client__pathrev_t *src_left,
98 const svn_client__pathrev_t *src_right,
99 merge_target_t *target,
100 svn_ra_session_t *ra_session,
101 element_matching_info_t *element_matching_info,
102 svn_client_ctx_t *ctx,
103 apr_pool_t *result_pool,
104 apr_pool_t *scratch_pool)
106 verbose_notify("--- Assigning EIDs to trees");
112 /* Perform a three-way tree merge. Write the result to *MERGE_RESULT_P.
114 * Set *CONFLICTS_P to describe any conflicts, or set *CONFLICTS_P to
115 * null if there are none.
118 merge_trees(svn_element__tree_t **merge_result_p,
120 svn_element__tree_t *tree_left,
121 svn_element__tree_t *tree_right,
122 svn_element__tree_t *tree_target,
123 apr_pool_t *result_pool,
124 apr_pool_t *scratch_pool)
126 verbose_notify("--- Merging trees");
129 *merge_result_p = NULL;
134 /* Convert the MERGE_RESULT to a series of WC edits and apply those to
135 * the WC described in TARGET.
138 apply_merge_result_to_wc(merge_target_t *target,
139 svn_element__tree_t *merge_result,
140 svn_client_ctx_t *ctx,
141 apr_pool_t *scratch_pool)
143 verbose_notify("--- Writing merge result to WC");
148 /* Do a three-way element-based merge for one merge source range,
149 * SRC_LEFT:SRC_RIGHT. If there are no conflicts, write the result to the
150 * WC described in TARGET.
153 merge_elements_one_source(svn_boolean_t *use_sleep,
154 const svn_client__pathrev_t *src_left,
155 const svn_client__pathrev_t *src_right,
156 merge_target_t *target,
157 svn_ra_session_t *ra_session,
158 element_matching_info_t *element_matching_info,
159 svn_boolean_t diff_ignore_ancestry,
160 svn_boolean_t force_delete,
161 svn_boolean_t dry_run,
162 const apr_array_header_t *merge_options,
163 svn_client_ctx_t *ctx,
164 apr_pool_t *scratch_pool)
166 svn_element__tree_t *tree_left, *tree_right, *tree_target;
167 svn_element__tree_t *merge_result;
170 verbose_notify("--- Merging by elements: "
171 "left=%s, right=%s, matching=%s",
172 pathrev_str(src_left, scratch_pool),
173 pathrev_str(src_right, scratch_pool),
174 element_matching_info_str(element_matching_info,
177 /* assign EIDs (in memory) to the source-left, source-right and target
179 SVN_ERR(assign_eids_to_trees(&tree_left, &tree_right, &tree_target,
180 src_left, src_right, target, ra_session,
181 element_matching_info,
182 ctx, scratch_pool, scratch_pool));
184 /* perform a tree merge, creating a temporary result (in memory) */
185 SVN_ERR(merge_trees(&merge_result, &conflicts,
186 tree_left, tree_right, tree_target,
187 scratch_pool, scratch_pool));
189 /* check for (new style) conflicts in the result; if any, bail out */
192 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
193 _("Merge had conflicts; "
194 "this is not yet supported"));
197 /* convert the result to a series of WC edits and apply those to the WC */
200 verbose_notify("--- Dry run; not writing merge result to WC");
204 SVN_ERR(apply_merge_result_to_wc(target, merge_result,
209 /* forget all the EID metadata */
214 svn_client__merge_elements(svn_boolean_t *use_sleep,
215 apr_array_header_t *merge_sources,
216 merge_target_t *target,
217 svn_ra_session_t *ra_session,
218 svn_boolean_t diff_ignore_ancestry,
219 svn_boolean_t force_delete,
220 svn_boolean_t dry_run,
221 const apr_array_header_t *merge_options,
222 svn_client_ctx_t *ctx,
223 apr_pool_t *result_pool,
224 apr_pool_t *scratch_pool)
228 /* Merge each source range in turn */
229 for (i = 0; i < merge_sources->nelts; i++)
231 merge_source_t *source
232 = APR_ARRAY_IDX(merge_sources, i, void *);
233 element_matching_info_t *element_matching_info;
235 /* ### TODO: get element matching info from the user */
236 element_matching_info = NULL;
238 SVN_ERR(merge_elements_one_source(use_sleep,
239 source->loc1, source->loc2,
241 element_matching_info,
242 diff_ignore_ancestry,
243 force_delete, dry_run, merge_options,