1 /** 2 * @copyright 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 * @endcopyright 22 * 23 * @file svn_diff_tree.h 24 * @brief Generic diff handler. Replacing the old svn_wc_diff_callbacks4_t 25 * infrastructure 26 */ 27 28 #ifndef SVN_DIFF_TREE_H 29 #define SVN_DIFF_TREE_H 30 31 #include "svn_types.h" 32 33 #ifdef __cplusplus 34 extern "C" { 35 #endif /* __cplusplus */ 36 37 /* 38 * About the diff tree processor. 39 * 40 * Subversion uses two kinds of editors to describe changes. One to 41 * describe changes on how to *exactly* transform one tree to another tree, 42 * as efficiently as possible and one to describe the difference between trees 43 * in order to review the changes, or to allow applying them on a third tree 44 * which is similar to those other trees. 45 * 46 * The first case was originally handled by svn_delta_editor_t and might be 47 * replaced by svn_editor_t in a future version. This diff processor handles 48 * the other case and as such forms the layer below our diff and merge 49 * handling. 50 * 51 * The major difference between this and the other editors is that this diff 52 * always provides access to the full text and/or properties in the left and 53 * right tree when applicable to allow processor implementers to decide how 54 * to interpret changes. 55 * 56 * Originally this diff processor was not formalized explicitly, but 57 * informally handled by the working copy diff callbacks. These callbacks just 58 * provided the information to drive a unified diff and a textual merge. To go 59 * one step further and allow full tree conflict detection we needed a better 60 * defined diff handling. Instead of adding yet a few more functions and 61 * arguments to the already overloaded diff callbacks the api was completely 62 * redesigned with a few points in mind. 63 * 64 * * It must be able to drive the old callbacks interface without users 65 * noticing the difference (100% compatible). 66 * (Implemented as svn_wc__wrap_diff_callbacks()) 67 * 68 * * It should provide the information that was missing in the old interface, 69 * but required to close existing issues. 70 * 71 * E.g. - properties and children on deleted directories. 72 * - revision numbers and copyfrom information on directories. 73 * 74 * To cleanup the implementation and make it easier on diff processors to 75 * handle the results I also added the following constraints. 76 * 77 * * Diffs should be fully reversable: anything that is deleted should be 78 * available, just like something that is added. 79 * (Proven via svn_diff__tree_processor_reverse_create) 80 * ### Still in doubt if *_deleted() needs a copy_to argument, for the 81 * ### 99% -> 100%. 82 * 83 * * Diff processors should have an easy way to communicate that they are 84 * not interrested in certain expensive to obtain results. 85 * 86 * * Directories should have clear open and close events to allow adding them 87 * before their children, but still allowing property changes to have 88 * defined behavior. 89 * 90 * * Files and directories should be handled as similar as possible as in 91 * many cases they are just nodes in a tree. 92 * 93 * * It should be easy to create diff wrappers to apply certain transforms. 94 * 95 * During the creation an additional requirement of knowing about 'some 96 * absent' nodes was added, to allow the merge to work on just this processor 97 * api. 98 * 99 * The api describes a clean open-close walk through a tree, depending on the 100 * driver multiple siblings can be described at the same time, but when a 101 * directory is closed all descendants are done. 102 * 103 * Note that it is possible for nodes to be described as a delete followed by 104 * an add at the same place within one parent. (Iff the diff is reversed you 105 * can see an add followed by a delete!) 106 * ### "An add followed by a delete" sounds wrong. 107 * 108 * The directory batons live between the open and close events of a directory 109 * and are thereby guaranteed to outlive the batons of their descendants. 110 */ 111 112 /* Describes the source of a merge */ 113 /* ### You mean a diff? 114 * ### How come many users don't set the 'repos_relpath' field? */ 115 typedef struct svn_diff_source_t 116 { 117 /* Always available 118 In case of copyfrom: the revision copied from 119 */ 120 svn_revnum_t revision; 121 122 /* In case of copyfrom: the repository relative path copied from. 123 124 NULL if the node wasn't copied or moved, or when the driver doesn't 125 have this information */ 126 const char *repos_relpath; 127 128 /* In case of copyfrom: the relative path of source location before the 129 move. This path is relative WITHIN THE DIFF. The repository path is 130 typically in repos_relpath 131 132 NULL if the node wasn't moved or if the driver doesn't have this 133 information. */ 134 const char *moved_from_relpath; 135 } svn_diff_source_t; 136 137 /** 138 * A callback vtable invoked by our diff-editors, as they receive diffs 139 * from the server. 'svn diff' and 'svn merge' implement their own versions 140 * of this vtable. 141 * 142 * All callbacks receive the processor and at least a parent baton. Forwarding 143 * the processor allows future extensions to call into the old functions without 144 * revving the entire API. 145 * 146 * Users must call svn_diff__tree_processor_create() to allow adding new 147 * callbacks later. (E.g. when we decide how to add move support) These 148 * extensions can then just call into other callbacks. 149 * 150 * @since New in 1.8. 151 */ 152 typedef struct svn_diff_tree_processor_t 153 { 154 /** The value passed to svn_diff__tree_processor_create() as BATON. 155 */ 156 void *baton; /* To avoid an additional in some places 157 * ### What? */ 158 159 /* Called before a directory's children are processed. 160 * 161 * Set *SKIP_CHILDREN to TRUE, to skip calling callbacks for all 162 * children. 163 * 164 * Set *SKIP to TRUE to skip calling the added, deleted, changed 165 * or closed callback for this node only. 166 */ 167 svn_error_t * 168 (*dir_opened)(void **new_dir_baton, 169 svn_boolean_t *skip, 170 svn_boolean_t *skip_children, 171 const char *relpath, 172 const svn_diff_source_t *left_source, 173 const svn_diff_source_t *right_source, 174 const svn_diff_source_t *copyfrom_source, 175 void *parent_dir_baton, 176 const struct svn_diff_tree_processor_t *processor, 177 apr_pool_t *result_pool, 178 apr_pool_t *scratch_pool); 179 180 /* Called after a directory and all its children are added 181 */ 182 svn_error_t * 183 (*dir_added)(const char *relpath, 184 const svn_diff_source_t *copyfrom_source, 185 const svn_diff_source_t *right_source, 186 /*const*/ apr_hash_t *copyfrom_props, 187 /*const*/ apr_hash_t *right_props, 188 void *dir_baton, 189 const struct svn_diff_tree_processor_t *processor, 190 apr_pool_t *scratch_pool); 191 192 /* Called after all children of this node are reported as deleted. 193 * 194 * The default implementation calls dir_closed(). 195 */ 196 svn_error_t * 197 (*dir_deleted)(const char *relpath, 198 const svn_diff_source_t *left_source, 199 /*const*/ apr_hash_t *left_props, 200 void *dir_baton, 201 const struct svn_diff_tree_processor_t *processor, 202 apr_pool_t *scratch_pool); 203 204 /* Called instead of dir_closed() if the properties on the directory 205 * were modified. 206 * 207 * The default implementation calls dir_closed(). 208 */ 209 svn_error_t * 210 (*dir_changed)(const char *relpath, 211 const svn_diff_source_t *left_source, 212 const svn_diff_source_t *right_source, 213 /*const*/ apr_hash_t *left_props, 214 /*const*/ apr_hash_t *right_props, 215 const apr_array_header_t *prop_changes, 216 void *dir_baton, 217 const struct svn_diff_tree_processor_t *processor, 218 apr_pool_t *scratch_pool); 219 220 /* Called when a directory is closed without applying changes to 221 * the directory itself. 222 * 223 * When dir_changed or dir_deleted are handled by the default implementation 224 * they call dir_closed() 225 */ 226 svn_error_t * 227 (*dir_closed)(const char *relpath, 228 const svn_diff_source_t *left_source, 229 const svn_diff_source_t *right_source, 230 void *dir_baton, 231 const struct svn_diff_tree_processor_t *processor, 232 apr_pool_t *scratch_pool); 233 234 /* Called before file_added(), file_deleted(), file_changed() and 235 file_closed() 236 */ 237 svn_error_t * 238 (*file_opened)(void **new_file_baton, 239 svn_boolean_t *skip, 240 const char *relpath, 241 const svn_diff_source_t *left_source, 242 const svn_diff_source_t *right_source, 243 const svn_diff_source_t *copyfrom_source, 244 void *dir_baton, 245 const struct svn_diff_tree_processor_t *processor, 246 apr_pool_t *result_pool, 247 apr_pool_t *scratch_pool); 248 249 /* Called after file_opened() for newly added and copied files */ 250 svn_error_t * 251 (*file_added)(const char *relpath, 252 const svn_diff_source_t *copyfrom_source, 253 const svn_diff_source_t *right_source, 254 const char *copyfrom_file, 255 const char *right_file, 256 /*const*/ apr_hash_t *copyfrom_props, 257 /*const*/ apr_hash_t *right_props, 258 void *file_baton, 259 const struct svn_diff_tree_processor_t *processor, 260 apr_pool_t *scratch_pool); 261 262 /* Called after file_opened() for deleted or moved away files */ 263 svn_error_t * 264 (*file_deleted)(const char *relpath, 265 const svn_diff_source_t *left_source, 266 const char *left_file, 267 /*const*/ apr_hash_t *left_props, 268 void *file_baton, 269 const struct svn_diff_tree_processor_t *processor, 270 apr_pool_t *scratch_pool); 271 272 /* Called after file_opened() for changed files */ 273 svn_error_t * 274 (*file_changed)(const char *relpath, 275 const svn_diff_source_t *left_source, 276 const svn_diff_source_t *right_source, 277 const char *left_file, 278 const char *right_file, 279 /*const*/ apr_hash_t *left_props, 280 /*const*/ apr_hash_t *right_props, 281 svn_boolean_t file_modified, 282 const apr_array_header_t *prop_changes, 283 void *file_baton, 284 const struct svn_diff_tree_processor_t *processor, 285 apr_pool_t *scratch_pool); 286 287 /* Called after file_opened() for unmodified files */ 288 svn_error_t * 289 (*file_closed)(const char *relpath, 290 const svn_diff_source_t *left_source, 291 const svn_diff_source_t *right_source, 292 void *file_baton, 293 const struct svn_diff_tree_processor_t *processor, 294 apr_pool_t *scratch_pool); 295 296 /* Called when encountering a marker for an absent file or directory */ 297 svn_error_t * 298 (*node_absent)(const char *relpath, 299 void *dir_baton, 300 const struct svn_diff_tree_processor_t *processor, 301 apr_pool_t *scratch_pool); 302 } svn_diff_tree_processor_t; 303 304 /** 305 * Create a new svn_diff_tree_processor_t instance with all functions 306 * set to a callback doing nothing but copying the parent baton to 307 * the new baton. 308 * 309 * @since New in 1.8. 310 */ 311 svn_diff_tree_processor_t * 312 svn_diff__tree_processor_create(void *baton, 313 apr_pool_t *result_pool); 314 315 /** 316 * Create a new svn_diff_tree_processor_t instance with all functions setup 317 * to call into another svn_diff_tree_processor_t processor, but with all 318 * adds and deletes inverted. 319 * 320 * @since New in 1.8. 321 */ /* Used by libsvn clients repository diff */ 322 const svn_diff_tree_processor_t * 323 svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor, 324 apr_pool_t *result_pool); 325 326 /** 327 * Create a new svn_diff_tree_processor_t instance with all functions setup 328 * to call into processor for all paths equal to and below prefix_relpath. 329 * 330 * @since New in 1.8. 331 */ /* Used by libsvn clients repository diff */ 332 const svn_diff_tree_processor_t * 333 svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t *processor, 334 const char *prefix_relpath, 335 apr_pool_t *result_pool); 336 337 /** 338 * Create a new svn_diff_tree_processor_t instance with all function setup 339 * to call into processor with all adds with copyfrom information transformed 340 * to simple node changes. 341 * 342 * @since New in 1.8. 343 */ /* Used by libsvn_wc diff editor */ 344 const svn_diff_tree_processor_t * 345 svn_diff__tree_processor_copy_as_changed_create( 346 const svn_diff_tree_processor_t *processor, 347 apr_pool_t *result_pool); 348 349 350 /** 351 * Create a new svn_diff_tree_processor_t instance with all functions setup 352 * to first call into processor1 and then processor2. 353 * 354 * This function is mostly a debug and migration helper. 355 * 356 * @since New in 1.8. 357 */ /* Used by libsvn clients repository diff */ 358 const svn_diff_tree_processor_t * 359 svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1, 360 const svn_diff_tree_processor_t *processor2, 361 apr_pool_t *result_pool); 362 363 364 svn_diff_source_t * 365 svn_diff__source_create(svn_revnum_t revision, 366 apr_pool_t *result_pool); 367 368 #ifdef __cplusplus 369 } 370 #endif /* __cplusplus */ 371 372 #endif /* SVN_DIFF_TREE_H */ 373 374