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