1/* 2 * merge_elements.c: element-based merging 3 * 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 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 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 20 * under the License. 21 * ==================================================================== 22 */ 23 24#include <assert.h> 25#include <apr_strings.h> 26#include <apr_tables.h> 27#include <apr_hash.h> 28#include "svn_types.h" 29#include "svn_error.h" 30#include "svn_pools.h" 31#include "svn_hash.h" 32#include "svn_wc.h" 33#include "svn_client.h" 34#include "svn_dirent_uri.h" 35 36#include "client.h" 37#include "private/svn_element.h" 38 39#include "svn_private_config.h" 40 41 42/* Print a notification. 43 * ### TODO: Send notifications through ctx->notify_func2(). 44 * ### TODO: Only when 'verbose' output is requested. 45 */ 46static 47__attribute__((format(printf, 1, 2))) 48void 49verbose_notify(const char *fmt, 50 ...) 51{ 52 va_list ap; 53 54 va_start(ap, fmt); 55 vprintf(fmt, ap); 56 if (fmt[strlen(fmt) - 1] != '\n') 57 printf("\n"); 58 va_end(ap); 59} 60 61/* Return a string representation of PATHREV. */ 62static const char * 63pathrev_str(const svn_client__pathrev_t *pathrev, 64 apr_pool_t *pool) 65{ 66 const char *rrpath 67 = svn_uri_skip_ancestor(pathrev->repos_root_url, pathrev->url, pool); 68 69 return apr_psprintf(pool, "^/%s@%ld", rrpath, pathrev->rev); 70} 71 72/* Element matching info. 73 */ 74typedef struct element_matching_info_t 75{ 76 void *info; 77} element_matching_info_t; 78 79/* Return a string representation of INFO. */ 80static const char * 81element_matching_info_str(const element_matching_info_t *info, 82 apr_pool_t *result_pool) 83{ 84 /* ### */ 85 const char *str = "{...}"; 86 87 return str; 88} 89 90/* Assign EIDs (in memory) to the source-left, source-right and target 91 * trees. 92 */ 93static svn_error_t * 94assign_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) 105{ 106 verbose_notify("--- Assigning EIDs to trees"); 107 108 /* ### */ 109 return SVN_NO_ERROR; 110} 111 112/* Perform a three-way tree merge. Write the result to *MERGE_RESULT_P. 113 * 114 * Set *CONFLICTS_P to describe any conflicts, or set *CONFLICTS_P to 115 * null if there are none. 116 */ 117static svn_error_t * 118merge_trees(svn_element__tree_t **merge_result_p, 119 void **conflicts_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) 125{ 126 verbose_notify("--- Merging trees"); 127 128 /* ### */ 129 *merge_result_p = NULL; 130 *conflicts_p = NULL; 131 return SVN_NO_ERROR; 132} 133 134/* Convert the MERGE_RESULT to a series of WC edits and apply those to 135 * the WC described in TARGET. 136 */ 137static svn_error_t * 138apply_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) 142{ 143 verbose_notify("--- Writing merge result to WC"); 144 145 return SVN_NO_ERROR; 146} 147 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. 151 */ 152static svn_error_t * 153merge_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) 165{ 166 svn_element__tree_t *tree_left, *tree_right, *tree_target; 167 svn_element__tree_t *merge_result; 168 void *conflicts; 169 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, 175 scratch_pool)); 176 177 /* assign EIDs (in memory) to the source-left, source-right and target 178 trees */ 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)); 183 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)); 188 189 /* check for (new style) conflicts in the result; if any, bail out */ 190 if (conflicts) 191 { 192 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 193 _("Merge had conflicts; " 194 "this is not yet supported")); 195 } 196 197 /* convert the result to a series of WC edits and apply those to the WC */ 198 if (dry_run) 199 { 200 verbose_notify("--- Dry run; not writing merge result to WC"); 201 } 202 else 203 { 204 SVN_ERR(apply_merge_result_to_wc(target, merge_result, 205 ctx, scratch_pool)); 206 *use_sleep = TRUE; 207 } 208 209 /* forget all the EID metadata */ 210 return SVN_NO_ERROR; 211} 212 213svn_error_t * 214svn_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) 225{ 226 int i; 227 228 /* Merge each source range in turn */ 229 for (i = 0; i < merge_sources->nelts; i++) 230 { 231 merge_source_t *source 232 = APR_ARRAY_IDX(merge_sources, i, void *); 233 element_matching_info_t *element_matching_info; 234 235 /* ### TODO: get element matching info from the user */ 236 element_matching_info = NULL; 237 238 SVN_ERR(merge_elements_one_source(use_sleep, 239 source->loc1, source->loc2, 240 target, ra_session, 241 element_matching_info, 242 diff_ignore_ancestry, 243 force_delete, dry_run, merge_options, 244 ctx, scratch_pool)); 245 } 246 247 return SVN_NO_ERROR; 248} 249