aboutsummaryrefslogtreecommitdiffstats
path: root/subversion/include/private/svn_diff_tree.h
blob: 713644d08c4e8b8c4cec13cb848ab6cc995fa5c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/**
 * @copyright
 * ====================================================================
 *    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.
 * ====================================================================
 * @endcopyright
 *
 * @file svn_diff_tree.h
 * @brief Generic diff handler. Replacing the old svn_wc_diff_callbacks4_t
 * infrastructure
 */

#ifndef SVN_DIFF_TREE_H
#define SVN_DIFF_TREE_H

#include "svn_types.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/*
 *                   About the diff tree processor.
 *
 * Subversion uses two kinds of editors to describe changes. One to
 * describe changes on how to *exactly* transform one tree to another tree,
 * as efficiently as possible and one to describe the difference between trees
 * in order to review the changes, or to allow applying them on a third tree
 * which is similar to those other trees.
 *
 * The first case was originally handled by svn_delta_editor_t and might be
 * replaced by svn_editor_t in a future version. This diff processor handles
 * the other case and as such forms the layer below our diff and merge
 * handling.
 *
 * The major difference between this and the other editors is that this diff
 * always provides access to the full text and/or properties in the left and
 * right tree when applicable to allow processor implementers to decide how
 * to interpret changes.
 *
 * Originally this diff processor was not formalized explicitly, but
 * informally handled by the working copy diff callbacks. These callbacks just
 * provided the information to drive a unified diff and a textual merge. To go
 * one step further and allow full tree conflict detection we needed a better
 * defined diff handling. Instead of adding yet a few more functions and
 * arguments to the already overloaded diff callbacks the api was completely
 * redesigned with a few points in mind.
 *
 *   * It must be able to drive the old callbacks interface without users
 *     noticing the difference (100% compatible).
 *     (Implemented as svn_wc__wrap_diff_callbacks())
 *
 *   * It should provide the information that was missing in the old interface,
 *     but required to close existing issues.
 *
 *     E.g. - properties and children on deleted directories.
 *          - revision numbers and copyfrom information on directories.
 *
 * To cleanup the implementation and make it easier on diff processors to
 * handle the results I also added the following constraints.
 *
 *   * Diffs should be fully reversable: anything that is deleted should be
 *     available, just like something that is added.
 *     (Proven via svn_diff__tree_processor_reverse_create)
 *     ### Still in doubt if *_deleted() needs a copy_to argument, for the
 *     ### 99% -> 100%.
 *
 *   * Diff processors should have an easy way to communicate that they are
 *     not interrested in certain expensive to obtain results.
 *
 *   * Directories should have clear open and close events to allow adding them
 *     before their children, but still allowing property changes to have
 *     defined behavior.
 *
 *   * Files and directories should be handled as similar as possible as in
 *     many cases they are just nodes in a tree.
 *
 *   * It should be easy to create diff wrappers to apply certain transforms.
 *
 * During the creation an additional requirement of knowing about 'some
 * absent' nodes was added, to allow the merge to work on just this processor
 * api.
 *
 * The api describes a clean open-close walk through a tree, depending on the
 * driver multiple siblings can be described at the same time, but when a
 * directory is closed all descendants are done.
 *
 * Note that it is possible for nodes to be described as a delete followed by
 * an add at the same place within one parent. (Iff the diff is reversed you
 * can see an add followed by a delete!)
 *   ### "An add followed by a delete" sounds wrong.
 *
 * The directory batons live between the open and close events of a directory
 * and are thereby guaranteed to outlive the batons of their descendants.
 */

/* Describes the source of a merge */
/* ### You mean a diff?
 * ### How come many users don't set the 'repos_relpath' field? */
typedef struct svn_diff_source_t
{
  /* Always available
     In case of copyfrom: the revision copied from
   */
  svn_revnum_t revision;

  /* In case of copyfrom: the repository relative path copied from.

     NULL if the node wasn't copied or moved, or when the driver doesn't
     have this information */
  const char *repos_relpath;

  /* In case of copyfrom: the relative path of source location before the
     move. This path is relative WITHIN THE DIFF. The repository path is
     typically in repos_relpath

     NULL if the node wasn't moved or if the driver doesn't have this
     information. */
  const char *moved_from_relpath;
} svn_diff_source_t;

/**
 * A callback vtable invoked by our diff-editors, as they receive diffs
 * from the server. 'svn diff' and 'svn merge' implement their own versions
 * of this vtable.
 *
 * All callbacks receive the processor and at least a parent baton. Forwarding
 * the processor allows future extensions to call into the old functions without
 * revving the entire API.
 *
 * Users must call svn_diff__tree_processor_create() to allow adding new
 * callbacks later. (E.g. when we decide how to add move support) These
 * extensions can then just call into other callbacks.
 *
 * @since New in 1.8.
 */
typedef struct svn_diff_tree_processor_t
{
  /** The value passed to svn_diff__tree_processor_create() as BATON.
   */
  void *baton; /* To avoid an additional in some places
                * ### What? */

  /* Called before a directory's children are processed.
   *
   * Set *SKIP_CHILDREN to TRUE, to skip calling callbacks for all
   * children.
   *
   * Set *SKIP to TRUE to skip calling the added, deleted, changed
   * or closed callback for this node only.
   */
  svn_error_t *
  (*dir_opened)(void **new_dir_baton,
                svn_boolean_t *skip,
                svn_boolean_t *skip_children,
                const char *relpath,
                const svn_diff_source_t *left_source,
                const svn_diff_source_t *right_source,
                const svn_diff_source_t *copyfrom_source,
                void *parent_dir_baton,
                const struct svn_diff_tree_processor_t *processor,
                apr_pool_t *result_pool,
                apr_pool_t *scratch_pool);

  /* Called after a directory and all its children are added
   */
  svn_error_t *
  (*dir_added)(const char *relpath,
               const svn_diff_source_t *copyfrom_source,
               const svn_diff_source_t *right_source,
               /*const*/ apr_hash_t *copyfrom_props,
               /*const*/ apr_hash_t *right_props,
               void *dir_baton,
               const struct svn_diff_tree_processor_t *processor,
               apr_pool_t *scratch_pool);

  /* Called after all children of this node are reported as deleted.
   *
   * The default implementation calls dir_closed().
   */
  svn_error_t *
  (*dir_deleted)(const char *relpath,
                 const svn_diff_source_t *left_source,
                 /*const*/ apr_hash_t *left_props,
                 void *dir_baton,
                 const struct svn_diff_tree_processor_t *processor,
                 apr_pool_t *scratch_pool);

  /* Called instead of dir_closed() if the properties on the directory
   *  were modified.
   *
   * The default implementation calls dir_closed().
   */
  svn_error_t *
  (*dir_changed)(const char *relpath,
                 const svn_diff_source_t *left_source,
                 const svn_diff_source_t *right_source,
                 /*const*/ apr_hash_t *left_props,
                 /*const*/ apr_hash_t *right_props,
                 const apr_array_header_t *prop_changes,
                 void *dir_baton,
                 const struct svn_diff_tree_processor_t *processor,
                 apr_pool_t *scratch_pool);

  /* Called when a directory is closed without applying changes to
   * the directory itself.
   *
   * When dir_changed or dir_deleted are handled by the default implementation
   * they call dir_closed()
   */
  svn_error_t *
  (*dir_closed)(const char *relpath,
                const svn_diff_source_t *left_source,
                const svn_diff_source_t *right_source,
                void *dir_baton,
                const struct svn_diff_tree_processor_t *processor,
                apr_pool_t *scratch_pool);

  /* Called before file_added(), file_deleted(), file_changed() and
     file_closed()
   */
  svn_error_t *
  (*file_opened)(void **new_file_baton,
                 svn_boolean_t *skip,
                 const char *relpath,
                 const svn_diff_source_t *left_source,
                 const svn_diff_source_t *right_source,
                 const svn_diff_source_t *copyfrom_source,
                 void *dir_baton,
                 const struct svn_diff_tree_processor_t *processor,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool);

  /* Called after file_opened() for newly added and copied files */
  svn_error_t *
  (*file_added)(const char *relpath,
                const svn_diff_source_t *copyfrom_source,
                const svn_diff_source_t *right_source,
                const char *copyfrom_file,
                const char *right_file,
                /*const*/ apr_hash_t *copyfrom_props,
                /*const*/ apr_hash_t *right_props,
                void *file_baton,
                const struct svn_diff_tree_processor_t *processor,
                apr_pool_t *scratch_pool);

  /* Called after file_opened() for deleted or moved away files */
  svn_error_t *
  (*file_deleted)(const char *relpath,
                  const svn_diff_source_t *left_source,
                  const char *left_file,
                  /*const*/ apr_hash_t *left_props,
                  void *file_baton,
                  const struct svn_diff_tree_processor_t *processor,
                  apr_pool_t *scratch_pool);

  /* Called after file_opened() for changed files */
  svn_error_t *
  (*file_changed)(const char *relpath,
                  const svn_diff_source_t *left_source,
                  const svn_diff_source_t *right_source,
                  const char *left_file,
                  const char *right_file,
                  /*const*/ apr_hash_t *left_props,
                  /*const*/ apr_hash_t *right_props,
                  svn_boolean_t file_modified,
                  const apr_array_header_t *prop_changes,
                  void *file_baton,
                  const struct svn_diff_tree_processor_t *processor,
                  apr_pool_t *scratch_pool);

  /* Called after file_opened() for unmodified files */
  svn_error_t *
  (*file_closed)(const char *relpath,
                 const svn_diff_source_t *left_source,
                 const svn_diff_source_t *right_source,
                 void *file_baton,
                 const struct svn_diff_tree_processor_t *processor,
                 apr_pool_t *scratch_pool);

  /* Called when encountering a marker for an absent file or directory */
  svn_error_t *
  (*node_absent)(const char *relpath,
                 void *dir_baton,
                 const struct svn_diff_tree_processor_t *processor,
                 apr_pool_t *scratch_pool);
} svn_diff_tree_processor_t;

/**
 * Create a new svn_diff_tree_processor_t instance with all functions
 * set to a callback doing nothing but copying the parent baton to
 * the new baton.
 *
 * @since New in 1.8.
 */
svn_diff_tree_processor_t *
svn_diff__tree_processor_create(void *baton,
                                apr_pool_t *result_pool);

/**
 * Create a new svn_diff_tree_processor_t instance with all functions setup
 * to call into another svn_diff_tree_processor_t processor, but with all
 * adds and deletes inverted.
 *
 * @since New in 1.8.
 */ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
                                        const char *prefix_relpath,
                                        apr_pool_t *result_pool);

/**
 * Create a new svn_diff_tree_processor_t instance with all functions setup
 * to call into processor for all paths equal to and below prefix_relpath.
 *
 * @since New in 1.8.
 */ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t *processor,
                                       const char *prefix_relpath,
                                       apr_pool_t *result_pool);

/**
 * Create a new svn_diff_tree_processor_t instance with all function setup
 * to call into processor with all adds with copyfrom information transformed
 * to simple node changes.
 *
 * @since New in 1.8.
 */ /* Used by libsvn_wc diff editor */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_copy_as_changed_create(
                                const svn_diff_tree_processor_t *processor,
                                apr_pool_t *result_pool);


/**
 * Create a new svn_diff_tree_processor_t instance with all functions setup
 * to first call into processor1 and then processor2.
 *
 * This function is mostly a debug and migration helper.
 *
 * @since New in 1.8.
 */ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1,
                                    const svn_diff_tree_processor_t *processor2,
                                    apr_pool_t *result_pool);


svn_diff_source_t *
svn_diff__source_create(svn_revnum_t revision,
                        apr_pool_t *result_pool);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif  /* SVN_DIFF_TREE_H */