1/*
2 * debug_editor.c :  An editor that writes the operations it does to stderr.
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 "svn_io.h"
25
26#include "debug_editor.h"
27
28struct edit_baton
29{
30  const svn_delta_editor_t *wrapped_editor;
31  void *wrapped_edit_baton;
32
33  int indent_level;
34
35  svn_stream_t *out;
36};
37
38struct dir_baton
39{
40  void *edit_baton;
41  void *wrapped_dir_baton;
42};
43
44struct file_baton
45{
46  void *edit_baton;
47  void *wrapped_file_baton;
48};
49
50static svn_error_t *
51write_indent(struct edit_baton *eb, apr_pool_t *pool)
52{
53  int i;
54
55  /* This is DBG_FLAG from ../libsvn_subr/debug.c */
56  SVN_ERR(svn_stream_puts(eb->out, "DBG:"));
57  for (i = 0; i < eb->indent_level; ++i)
58    SVN_ERR(svn_stream_puts(eb->out, " "));
59
60  return SVN_NO_ERROR;
61}
62
63static svn_error_t *
64set_target_revision(void *edit_baton,
65                    svn_revnum_t target_revision,
66                    apr_pool_t *pool)
67{
68  struct edit_baton *eb = edit_baton;
69
70  SVN_ERR(write_indent(eb, pool));
71  SVN_ERR(svn_stream_printf(eb->out, pool, "set_target_revision : %ld\n",
72                            target_revision));
73
74  return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
75                                                 target_revision,
76                                                 pool);
77}
78
79static svn_error_t *
80open_root(void *edit_baton,
81          svn_revnum_t base_revision,
82          apr_pool_t *pool,
83          void **root_baton)
84{
85  struct edit_baton *eb = edit_baton;
86  struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));
87
88  SVN_ERR(write_indent(eb, pool));
89  SVN_ERR(svn_stream_printf(eb->out, pool, "open_root : %ld\n",
90                            base_revision));
91  eb->indent_level++;
92
93  SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
94                                        base_revision,
95                                        pool,
96                                        &dir_baton->wrapped_dir_baton));
97
98  dir_baton->edit_baton = edit_baton;
99
100  *root_baton = dir_baton;
101
102  return SVN_NO_ERROR;
103}
104
105static svn_error_t *
106delete_entry(const char *path,
107             svn_revnum_t base_revision,
108             void *parent_baton,
109             apr_pool_t *pool)
110{
111  struct dir_baton *pb = parent_baton;
112  struct edit_baton *eb = pb->edit_baton;
113
114  SVN_ERR(write_indent(eb, pool));
115  SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
116                            path, base_revision));
117
118  return eb->wrapped_editor->delete_entry(path,
119                                          base_revision,
120                                          pb->wrapped_dir_baton,
121                                          pool);
122}
123
124static svn_error_t *
125add_directory(const char *path,
126              void *parent_baton,
127              const char *copyfrom_path,
128              svn_revnum_t copyfrom_revision,
129              apr_pool_t *pool,
130              void **child_baton)
131{
132  struct dir_baton *pb = parent_baton;
133  struct edit_baton *eb = pb->edit_baton;
134  struct dir_baton *b = apr_palloc(pool, sizeof(*b));
135
136  SVN_ERR(write_indent(eb, pool));
137  SVN_ERR(svn_stream_printf(eb->out, pool,
138                            "add_directory : '%s' [from '%s':%ld]\n",
139                            path, copyfrom_path, copyfrom_revision));
140  eb->indent_level++;
141
142  SVN_ERR(eb->wrapped_editor->add_directory(path,
143                                            pb->wrapped_dir_baton,
144                                            copyfrom_path,
145                                            copyfrom_revision,
146                                            pool,
147                                            &b->wrapped_dir_baton));
148
149  b->edit_baton = eb;
150  *child_baton = b;
151
152  return SVN_NO_ERROR;
153}
154
155static svn_error_t *
156open_directory(const char *path,
157               void *parent_baton,
158               svn_revnum_t base_revision,
159               apr_pool_t *pool,
160               void **child_baton)
161{
162  struct dir_baton *pb = parent_baton;
163  struct edit_baton *eb = pb->edit_baton;
164  struct dir_baton *db = apr_palloc(pool, sizeof(*db));
165
166  SVN_ERR(write_indent(eb, pool));
167  SVN_ERR(svn_stream_printf(eb->out, pool, "open_directory : '%s':%ld\n",
168                            path, base_revision));
169  eb->indent_level++;
170
171  SVN_ERR(eb->wrapped_editor->open_directory(path,
172                                             pb->wrapped_dir_baton,
173                                             base_revision,
174                                             pool,
175                                             &db->wrapped_dir_baton));
176
177  db->edit_baton = eb;
178  *child_baton = db;
179
180  return SVN_NO_ERROR;
181}
182
183static svn_error_t *
184add_file(const char *path,
185         void *parent_baton,
186         const char *copyfrom_path,
187         svn_revnum_t copyfrom_revision,
188         apr_pool_t *pool,
189         void **file_baton)
190{
191  struct dir_baton *pb = parent_baton;
192  struct edit_baton *eb = pb->edit_baton;
193  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
194
195  SVN_ERR(write_indent(eb, pool));
196  SVN_ERR(svn_stream_printf(eb->out, pool,
197                            "add_file : '%s' [from '%s':%ld]\n",
198                            path, copyfrom_path, copyfrom_revision));
199
200  eb->indent_level++;
201
202  SVN_ERR(eb->wrapped_editor->add_file(path,
203                                       pb->wrapped_dir_baton,
204                                       copyfrom_path,
205                                       copyfrom_revision,
206                                       pool,
207                                       &fb->wrapped_file_baton));
208
209  fb->edit_baton = eb;
210  *file_baton = fb;
211
212  return SVN_NO_ERROR;
213}
214
215static svn_error_t *
216open_file(const char *path,
217          void *parent_baton,
218          svn_revnum_t base_revision,
219          apr_pool_t *pool,
220          void **file_baton)
221{
222  struct dir_baton *pb = parent_baton;
223  struct edit_baton *eb = pb->edit_baton;
224  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
225
226  SVN_ERR(write_indent(eb, pool));
227  SVN_ERR(svn_stream_printf(eb->out, pool, "open_file : '%s':%ld\n",
228                            path, base_revision));
229
230  eb->indent_level++;
231
232  SVN_ERR(eb->wrapped_editor->open_file(path,
233                                        pb->wrapped_dir_baton,
234                                        base_revision,
235                                        pool,
236                                        &fb->wrapped_file_baton));
237
238  fb->edit_baton = eb;
239  *file_baton = fb;
240
241  return SVN_NO_ERROR;
242}
243
244static svn_error_t *
245apply_textdelta(void *file_baton,
246                const char *base_checksum,
247                apr_pool_t *pool,
248                svn_txdelta_window_handler_t *handler,
249                void **handler_baton)
250{
251  struct file_baton *fb = file_baton;
252  struct edit_baton *eb = fb->edit_baton;
253
254  SVN_ERR(write_indent(eb, pool));
255  SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
256                            base_checksum));
257
258  SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
259                                              base_checksum,
260                                              pool,
261                                              handler,
262                                              handler_baton));
263
264  return SVN_NO_ERROR;
265}
266
267static svn_error_t *
268close_file(void *file_baton,
269           const char *text_checksum,
270           apr_pool_t *pool)
271{
272  struct file_baton *fb = file_baton;
273  struct edit_baton *eb = fb->edit_baton;
274
275  eb->indent_level--;
276
277  SVN_ERR(write_indent(eb, pool));
278  SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
279                            text_checksum));
280
281  SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
282                                         text_checksum, pool));
283
284  return SVN_NO_ERROR;
285}
286
287static svn_error_t *
288absent_file(const char *path,
289            void *file_baton,
290            apr_pool_t *pool)
291{
292  struct file_baton *fb = file_baton;
293  struct edit_baton *eb = fb->edit_baton;
294
295  SVN_ERR(write_indent(eb, pool));
296  SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
297
298  SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
299                                          pool));
300
301  return SVN_NO_ERROR;
302}
303
304static svn_error_t *
305close_directory(void *dir_baton,
306                apr_pool_t *pool)
307{
308  struct dir_baton *db = dir_baton;
309  struct edit_baton *eb = db->edit_baton;
310
311  eb->indent_level--;
312  SVN_ERR(write_indent(eb, pool));
313  SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
314
315  SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
316                                              pool));
317
318  return SVN_NO_ERROR;
319}
320
321static svn_error_t *
322absent_directory(const char *path,
323                 void *dir_baton,
324                 apr_pool_t *pool)
325{
326  struct dir_baton *db = dir_baton;
327  struct edit_baton *eb = db->edit_baton;
328
329  SVN_ERR(write_indent(eb, pool));
330  SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
331                            path));
332
333  SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
334                                               pool));
335
336  return SVN_NO_ERROR;
337}
338
339static svn_error_t *
340change_file_prop(void *file_baton,
341                 const char *name,
342                 const svn_string_t *value,
343                 apr_pool_t *pool)
344{
345  struct file_baton *fb = file_baton;
346  struct edit_baton *eb = fb->edit_baton;
347
348  SVN_ERR(write_indent(eb, pool));
349  SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s\n",
350                            name));
351
352  SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
353                                               name,
354                                               value,
355                                               pool));
356
357  return SVN_NO_ERROR;
358}
359
360static svn_error_t *
361change_dir_prop(void *dir_baton,
362                const char *name,
363                const svn_string_t *value,
364                apr_pool_t *pool)
365{
366  struct dir_baton *db = dir_baton;
367  struct edit_baton *eb = db->edit_baton;
368
369  SVN_ERR(write_indent(eb, pool));
370  SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s\n", name));
371
372  SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
373                                              name,
374                                              value,
375                                              pool));
376
377  return SVN_NO_ERROR;
378}
379
380static svn_error_t *
381close_edit(void *edit_baton,
382           apr_pool_t *pool)
383{
384  struct edit_baton *eb = edit_baton;
385
386  SVN_ERR(write_indent(eb, pool));
387  SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
388
389  SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
390
391  return SVN_NO_ERROR;
392}
393
394svn_error_t *
395svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
396                            void **edit_baton,
397                            const svn_delta_editor_t *wrapped_editor,
398                            void *wrapped_edit_baton,
399                            apr_pool_t *pool)
400{
401  svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
402  struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
403  apr_file_t *errfp;
404  svn_stream_t *out;
405
406  apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);
407  if (apr_err)
408    return svn_error_wrap_apr(apr_err, "Problem opening stderr");
409
410  out = svn_stream_from_aprfile2(errfp, TRUE, pool);
411
412  tree_editor->set_target_revision = set_target_revision;
413  tree_editor->open_root = open_root;
414  tree_editor->delete_entry = delete_entry;
415  tree_editor->add_directory = add_directory;
416  tree_editor->open_directory = open_directory;
417  tree_editor->change_dir_prop = change_dir_prop;
418  tree_editor->close_directory = close_directory;
419  tree_editor->absent_directory = absent_directory;
420  tree_editor->add_file = add_file;
421  tree_editor->open_file = open_file;
422  tree_editor->apply_textdelta = apply_textdelta;
423  tree_editor->change_file_prop = change_file_prop;
424  tree_editor->close_file = close_file;
425  tree_editor->absent_file = absent_file;
426  tree_editor->close_edit = close_edit;
427
428  eb->wrapped_editor = wrapped_editor;
429  eb->wrapped_edit_baton = wrapped_edit_baton;
430  eb->out = out;
431  eb->indent_level = 0;
432
433  *editor = tree_editor;
434  *edit_baton = eb;
435
436  return SVN_NO_ERROR;
437}
438