svn_diff_tree.h revision 299742
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
34extern "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? */
115typedef struct svn_diff_source_t
116{
117  /* Always available */
118  svn_revnum_t revision;
119
120  /* Depending on the driver available for copyfrom */
121  /* ### What? */
122  const char *repos_relpath;
123} svn_diff_source_t;
124
125/**
126 * A callback vtable invoked by our diff-editors, as they receive diffs
127 * from the server. 'svn diff' and 'svn merge' implement their own versions
128 * of this vtable.
129 *
130 * All callbacks receive the processor and at least a parent baton. Forwarding
131 * the processor allows future extensions to call into the old functions without
132 * revving the entire API.
133 *
134 * Users must call svn_diff__tree_processor_create() to allow adding new
135 * callbacks later. (E.g. when we decide how to add move support) These
136 * extensions can then just call into other callbacks.
137 *
138 * @since New in 1.8.
139 */
140typedef struct svn_diff_tree_processor_t
141{
142  /** The value passed to svn_diff__tree_processor_create() as BATON.
143   */
144  void *baton; /* To avoid an additional in some places
145                * ### What? */
146
147  /* Called before a directory's children are processed.
148   *
149   * Set *SKIP_CHILDREN to TRUE, to skip calling callbacks for all
150   * children.
151   *
152   * Set *SKIP to TRUE to skip calling the added, deleted, changed
153   * or closed callback for this node only.
154   */
155  svn_error_t *
156  (*dir_opened)(void **new_dir_baton,
157                svn_boolean_t *skip,
158                svn_boolean_t *skip_children,
159                const char *relpath,
160                const svn_diff_source_t *left_source,
161                const svn_diff_source_t *right_source,
162                const svn_diff_source_t *copyfrom_source,
163                void *parent_dir_baton,
164                const struct svn_diff_tree_processor_t *processor,
165                apr_pool_t *result_pool,
166                apr_pool_t *scratch_pool);
167
168  /* Called after a directory and all its children are added
169   */
170  svn_error_t *
171  (*dir_added)(const char *relpath,
172               const svn_diff_source_t *copyfrom_source,
173               const svn_diff_source_t *right_source,
174               /*const*/ apr_hash_t *copyfrom_props,
175               /*const*/ apr_hash_t *right_props,
176               void *dir_baton,
177               const struct svn_diff_tree_processor_t *processor,
178               apr_pool_t *scratch_pool);
179
180  /* Called after all children of this node are reported as deleted.
181   *
182   * The default implementation calls dir_closed().
183   */
184  svn_error_t *
185  (*dir_deleted)(const char *relpath,
186                 const svn_diff_source_t *left_source,
187                 /*const*/ apr_hash_t *left_props,
188                 void *dir_baton,
189                 const struct svn_diff_tree_processor_t *processor,
190                 apr_pool_t *scratch_pool);
191
192  /* Called instead of dir_closed() if the properties on the directory
193   *  were modified.
194   *
195   * The default implementation calls dir_closed().
196   */
197  svn_error_t *
198  (*dir_changed)(const char *relpath,
199                 const svn_diff_source_t *left_source,
200                 const svn_diff_source_t *right_source,
201                 /*const*/ apr_hash_t *left_props,
202                 /*const*/ apr_hash_t *right_props,
203                 const apr_array_header_t *prop_changes,
204                 void *dir_baton,
205                 const struct svn_diff_tree_processor_t *processor,
206                 apr_pool_t *scratch_pool);
207
208  /* Called when a directory is closed without applying changes to
209   * the directory itself.
210   *
211   * When dir_changed or dir_deleted are handled by the default implementation
212   * they call dir_closed()
213   */
214  svn_error_t *
215  (*dir_closed)(const char *relpath,
216                const svn_diff_source_t *left_source,
217                const svn_diff_source_t *right_source,
218                void *dir_baton,
219                const struct svn_diff_tree_processor_t *processor,
220                apr_pool_t *scratch_pool);
221
222  /* Called before file_added(), file_deleted(), file_changed() and
223     file_closed()
224   */
225  svn_error_t *
226  (*file_opened)(void **new_file_baton,
227                 svn_boolean_t *skip,
228                 const char *relpath,
229                 const svn_diff_source_t *left_source,
230                 const svn_diff_source_t *right_source,
231                 const svn_diff_source_t *copyfrom_source,
232                 void *dir_baton,
233                 const struct svn_diff_tree_processor_t *processor,
234                 apr_pool_t *result_pool,
235                 apr_pool_t *scratch_pool);
236
237  /* Called after file_opened() for newly added and copied files */
238  svn_error_t *
239  (*file_added)(const char *relpath,
240                const svn_diff_source_t *copyfrom_source,
241                const svn_diff_source_t *right_source,
242                const char *copyfrom_file,
243                const char *right_file,
244                /*const*/ apr_hash_t *copyfrom_props,
245                /*const*/ apr_hash_t *right_props,
246                void *file_baton,
247                const struct svn_diff_tree_processor_t *processor,
248                apr_pool_t *scratch_pool);
249
250  /* Called after file_opened() for deleted or moved away files */
251  svn_error_t *
252  (*file_deleted)(const char *relpath,
253                  const svn_diff_source_t *left_source,
254                  const char *left_file,
255                  /*const*/ apr_hash_t *left_props,
256                  void *file_baton,
257                  const struct svn_diff_tree_processor_t *processor,
258                  apr_pool_t *scratch_pool);
259
260  /* Called after file_opened() for changed files */
261  svn_error_t *
262  (*file_changed)(const char *relpath,
263                  const svn_diff_source_t *left_source,
264                  const svn_diff_source_t *right_source,
265                  const char *left_file,
266                  const char *right_file,
267                  /*const*/ apr_hash_t *left_props,
268                  /*const*/ apr_hash_t *right_props,
269                  svn_boolean_t file_modified,
270                  const apr_array_header_t *prop_changes,
271                  void *file_baton,
272                  const struct svn_diff_tree_processor_t *processor,
273                  apr_pool_t *scratch_pool);
274
275  /* Called after file_opened() for unmodified files */
276  svn_error_t *
277  (*file_closed)(const char *relpath,
278                 const svn_diff_source_t *left_source,
279                 const svn_diff_source_t *right_source,
280                 void *file_baton,
281                 const struct svn_diff_tree_processor_t *processor,
282                 apr_pool_t *scratch_pool);
283
284  /* Called when encountering a marker for an absent file or directory */
285  svn_error_t *
286  (*node_absent)(const char *relpath,
287                 void *dir_baton,
288                 const struct svn_diff_tree_processor_t *processor,
289                 apr_pool_t *scratch_pool);
290} svn_diff_tree_processor_t;
291
292/**
293 * Create a new svn_diff_tree_processor_t instance with all functions
294 * set to a callback doing nothing but copying the parent baton to
295 * the new baton.
296 *
297 * @since New in 1.8.
298 */
299svn_diff_tree_processor_t *
300svn_diff__tree_processor_create(void *baton,
301                                apr_pool_t *result_pool);
302
303/**
304 * Create a new svn_diff_tree_processor_t instance with all functions setup
305 * to call into another svn_diff_tree_processor_t processor, but with all
306 * adds and deletes inverted.
307 *
308 * @since New in 1.8.
309 */ /* Used by libsvn clients repository diff */
310const svn_diff_tree_processor_t *
311svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
312                                        const char *prefix_relpath,
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 processor for all paths equal to and below prefix_relpath.
318 *
319 * @since New in 1.8.
320 */ /* Used by libsvn clients repository diff */
321const svn_diff_tree_processor_t *
322svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t *processor,
323                                       const char *prefix_relpath,
324                                       apr_pool_t *result_pool);
325
326/**
327 * Create a new svn_diff_tree_processor_t instance with all function setup
328 * to call into processor with all adds with copyfrom information transformed
329 * to simple node changes.
330 *
331 * @since New in 1.8.
332 */ /* Used by libsvn_wc diff editor */
333const svn_diff_tree_processor_t *
334svn_diff__tree_processor_copy_as_changed_create(
335                                const svn_diff_tree_processor_t *processor,
336                                apr_pool_t *result_pool);
337
338
339/**
340 * Create a new svn_diff_tree_processor_t instance with all functions setup
341 * to first call into processor1 and then processor2.
342 *
343 * This function is mostly a debug and migration helper.
344 *
345 * @since New in 1.8.
346 */ /* Used by libsvn clients repository diff */
347const svn_diff_tree_processor_t *
348svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1,
349                                    const svn_diff_tree_processor_t *processor2,
350                                    apr_pool_t *result_pool);
351
352
353svn_diff_source_t *
354svn_diff__source_create(svn_revnum_t revision,
355                        apr_pool_t *result_pool);
356
357#ifdef __cplusplus
358}
359#endif /* __cplusplus */
360
361#endif  /* SVN_DIFF_TREE_H */
362
363