debug_editor.c revision 362181
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 "private/svn_delta_private.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  const char *prefix;
37};
38
39struct dir_baton
40{
41  void *edit_baton;
42  void *wrapped_dir_baton;
43};
44
45struct file_baton
46{
47  void *edit_baton;
48  void *wrapped_file_baton;
49};
50
51static svn_error_t *
52write_indent(struct edit_baton *eb, apr_pool_t *pool)
53{
54  int i;
55
56  SVN_ERR(svn_stream_puts(eb->out, eb->prefix));
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  if (eb->wrapped_editor)
75    SVN_ERR(eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
76                                                    target_revision,
77                                                    pool));
78  return SVN_NO_ERROR;
79}
80
81static svn_error_t *
82open_root(void *edit_baton,
83          svn_revnum_t base_revision,
84          apr_pool_t *pool,
85          void **root_baton)
86{
87  struct edit_baton *eb = edit_baton;
88  struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));
89
90  SVN_ERR(write_indent(eb, pool));
91  SVN_ERR(svn_stream_printf(eb->out, pool, "open_root : %ld\n",
92                            base_revision));
93  eb->indent_level++;
94
95  if (eb->wrapped_editor)
96    SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
97                                          base_revision,
98                                          pool,
99                                          &dir_baton->wrapped_dir_baton));
100
101  dir_baton->edit_baton = edit_baton;
102
103  *root_baton = dir_baton;
104
105  return SVN_NO_ERROR;
106}
107
108static svn_error_t *
109delete_entry(const char *path,
110             svn_revnum_t base_revision,
111             void *parent_baton,
112             apr_pool_t *pool)
113{
114  struct dir_baton *pb = parent_baton;
115  struct edit_baton *eb = pb->edit_baton;
116
117  SVN_ERR(write_indent(eb, pool));
118  SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
119                            path, base_revision));
120
121  if (eb->wrapped_editor)
122    SVN_ERR(eb->wrapped_editor->delete_entry(path,
123                                             base_revision,
124                                             pb->wrapped_dir_baton,
125                                             pool));
126  return SVN_NO_ERROR;
127}
128
129static svn_error_t *
130add_directory(const char *path,
131              void *parent_baton,
132              const char *copyfrom_path,
133              svn_revnum_t copyfrom_revision,
134              apr_pool_t *pool,
135              void **child_baton)
136{
137  struct dir_baton *pb = parent_baton;
138  struct edit_baton *eb = pb->edit_baton;
139  struct dir_baton *b = apr_palloc(pool, sizeof(*b));
140
141  SVN_ERR(write_indent(eb, pool));
142  SVN_ERR(svn_stream_printf(eb->out, pool,
143                            "add_directory : '%s' [from '%s':%ld]\n",
144                            path, copyfrom_path, copyfrom_revision));
145  eb->indent_level++;
146
147  if (eb->wrapped_editor)
148    SVN_ERR(eb->wrapped_editor->add_directory(path,
149                                              pb->wrapped_dir_baton,
150                                              copyfrom_path,
151                                              copyfrom_revision,
152                                              pool,
153                                              &b->wrapped_dir_baton));
154
155  b->edit_baton = eb;
156  *child_baton = b;
157
158  return SVN_NO_ERROR;
159}
160
161static svn_error_t *
162open_directory(const char *path,
163               void *parent_baton,
164               svn_revnum_t base_revision,
165               apr_pool_t *pool,
166               void **child_baton)
167{
168  struct dir_baton *pb = parent_baton;
169  struct edit_baton *eb = pb->edit_baton;
170  struct dir_baton *db = apr_palloc(pool, sizeof(*db));
171
172  SVN_ERR(write_indent(eb, pool));
173  SVN_ERR(svn_stream_printf(eb->out, pool, "open_directory : '%s':%ld\n",
174                            path, base_revision));
175  eb->indent_level++;
176
177  if (eb->wrapped_editor)
178    SVN_ERR(eb->wrapped_editor->open_directory(path,
179                                               pb->wrapped_dir_baton,
180                                               base_revision,
181                                               pool,
182                                               &db->wrapped_dir_baton));
183
184  db->edit_baton = eb;
185  *child_baton = db;
186
187  return SVN_NO_ERROR;
188}
189
190static svn_error_t *
191add_file(const char *path,
192         void *parent_baton,
193         const char *copyfrom_path,
194         svn_revnum_t copyfrom_revision,
195         apr_pool_t *pool,
196         void **file_baton)
197{
198  struct dir_baton *pb = parent_baton;
199  struct edit_baton *eb = pb->edit_baton;
200  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
201
202  SVN_ERR(write_indent(eb, pool));
203  SVN_ERR(svn_stream_printf(eb->out, pool,
204                            "add_file : '%s' [from '%s':%ld]\n",
205                            path, copyfrom_path, copyfrom_revision));
206
207  eb->indent_level++;
208
209  if (eb->wrapped_editor)
210    SVN_ERR(eb->wrapped_editor->add_file(path,
211                                         pb->wrapped_dir_baton,
212                                         copyfrom_path,
213                                         copyfrom_revision,
214                                         pool,
215                                         &fb->wrapped_file_baton));
216
217  fb->edit_baton = eb;
218  *file_baton = fb;
219
220  return SVN_NO_ERROR;
221}
222
223static svn_error_t *
224open_file(const char *path,
225          void *parent_baton,
226          svn_revnum_t base_revision,
227          apr_pool_t *pool,
228          void **file_baton)
229{
230  struct dir_baton *pb = parent_baton;
231  struct edit_baton *eb = pb->edit_baton;
232  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
233
234  SVN_ERR(write_indent(eb, pool));
235  SVN_ERR(svn_stream_printf(eb->out, pool, "open_file : '%s':%ld\n",
236                            path, base_revision));
237
238  eb->indent_level++;
239
240  if (eb->wrapped_editor)
241    SVN_ERR(eb->wrapped_editor->open_file(path,
242                                          pb->wrapped_dir_baton,
243                                          base_revision,
244                                          pool,
245                                          &fb->wrapped_file_baton));
246
247  fb->edit_baton = eb;
248  *file_baton = fb;
249
250  return SVN_NO_ERROR;
251}
252
253static svn_error_t *
254apply_textdelta(void *file_baton,
255                const char *base_checksum,
256                apr_pool_t *pool,
257                svn_txdelta_window_handler_t *handler,
258                void **handler_baton)
259{
260  struct file_baton *fb = file_baton;
261  struct edit_baton *eb = fb->edit_baton;
262
263  SVN_ERR(write_indent(eb, pool));
264  SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
265                            base_checksum));
266
267  if (eb->wrapped_editor)
268    SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
269                                                base_checksum,
270                                                pool,
271                                                handler,
272                                                handler_baton));
273
274  return SVN_NO_ERROR;
275}
276
277static svn_error_t *
278apply_textdelta_stream(const struct svn_delta_editor_t *editor,
279                       void *file_baton,
280                       const char *base_checksum,
281                       svn_txdelta_stream_open_func_t open_func,
282                       void *open_baton,
283                       apr_pool_t *scratch_pool)
284{
285  struct file_baton *fb = file_baton;
286  struct edit_baton *eb = fb->edit_baton;
287
288  SVN_ERR(write_indent(eb, scratch_pool));
289  SVN_ERR(svn_stream_printf(eb->out, scratch_pool,
290                            "apply_textdelta_stream : %s\n",
291                            base_checksum));
292
293  if (eb->wrapped_editor)
294    SVN_ERR(eb->wrapped_editor->apply_textdelta_stream(eb->wrapped_editor,
295                                                       fb->wrapped_file_baton,
296                                                       base_checksum,
297                                                       open_func, open_baton,
298                                                       scratch_pool));
299
300  return SVN_NO_ERROR;
301}
302
303static svn_error_t *
304close_file(void *file_baton,
305           const char *text_checksum,
306           apr_pool_t *pool)
307{
308  struct file_baton *fb = file_baton;
309  struct edit_baton *eb = fb->edit_baton;
310
311  eb->indent_level--;
312
313  SVN_ERR(write_indent(eb, pool));
314  SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
315                            text_checksum));
316
317  if (eb->wrapped_editor)
318    SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
319                                           text_checksum, pool));
320
321  return SVN_NO_ERROR;
322}
323
324static svn_error_t *
325absent_file(const char *path,
326            void *file_baton,
327            apr_pool_t *pool)
328{
329  struct file_baton *fb = file_baton;
330  struct edit_baton *eb = fb->edit_baton;
331
332  SVN_ERR(write_indent(eb, pool));
333  SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
334
335  if (eb->wrapped_editor)
336    SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
337                                            pool));
338
339  return SVN_NO_ERROR;
340}
341
342static svn_error_t *
343close_directory(void *dir_baton,
344                apr_pool_t *pool)
345{
346  struct dir_baton *db = dir_baton;
347  struct edit_baton *eb = db->edit_baton;
348
349  eb->indent_level--;
350  SVN_ERR(write_indent(eb, pool));
351  SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
352
353  if (eb->wrapped_editor)
354    SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
355                                                pool));
356
357  return SVN_NO_ERROR;
358}
359
360static svn_error_t *
361absent_directory(const char *path,
362                 void *dir_baton,
363                 apr_pool_t *pool)
364{
365  struct dir_baton *db = dir_baton;
366  struct edit_baton *eb = db->edit_baton;
367
368  SVN_ERR(write_indent(eb, pool));
369  SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
370                            path));
371
372  if (eb->wrapped_editor)
373    SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
374                                                 pool));
375
376  return SVN_NO_ERROR;
377}
378
379static svn_error_t *
380change_file_prop(void *file_baton,
381                 const char *name,
382                 const svn_string_t *value,
383                 apr_pool_t *pool)
384{
385  struct file_baton *fb = file_baton;
386  struct edit_baton *eb = fb->edit_baton;
387
388  SVN_ERR(write_indent(eb, pool));
389  SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s -> %s\n",
390                            name, value ? value->data : "<deleted>"));
391
392  if (eb->wrapped_editor)
393    SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
394                                                 name,
395                                                 value,
396                                                 pool));
397
398  return SVN_NO_ERROR;
399}
400
401static svn_error_t *
402change_dir_prop(void *dir_baton,
403                const char *name,
404                const svn_string_t *value,
405                apr_pool_t *pool)
406{
407  struct dir_baton *db = dir_baton;
408  struct edit_baton *eb = db->edit_baton;
409
410  SVN_ERR(write_indent(eb, pool));
411  SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s -> %s\n",
412                            name, value ? value->data : "<deleted>"));
413
414  if (eb->wrapped_editor)
415    SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
416                                                name,
417                                                value,
418                                                pool));
419
420  return SVN_NO_ERROR;
421}
422
423static svn_error_t *
424close_edit(void *edit_baton,
425           apr_pool_t *pool)
426{
427  struct edit_baton *eb = edit_baton;
428
429  SVN_ERR(write_indent(eb, pool));
430  SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
431
432  if (eb->wrapped_editor)
433    SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
434
435  return SVN_NO_ERROR;
436}
437
438static svn_error_t *
439abort_edit(void *edit_baton,
440           apr_pool_t *pool)
441{
442  struct edit_baton *eb = edit_baton;
443
444  SVN_ERR(write_indent(eb, pool));
445  SVN_ERR(svn_stream_printf(eb->out, pool, "abort_edit\n"));
446
447  if (eb->wrapped_editor)
448    SVN_ERR(eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool));
449
450  return SVN_NO_ERROR;
451}
452
453svn_error_t *
454svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
455                            void **edit_baton,
456                            const svn_delta_editor_t *wrapped_editor,
457                            void *wrapped_edit_baton,
458                            const char *prefix,
459                            apr_pool_t *pool)
460{
461  svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
462  struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
463  apr_file_t *errfp;
464  svn_stream_t *out;
465
466  apr_status_t apr_err = apr_file_open_stdout(&errfp, pool);
467  if (apr_err)
468    return svn_error_wrap_apr(apr_err, "Problem opening stderr");
469
470  out = svn_stream_from_aprfile2(errfp, TRUE, pool);
471
472  tree_editor->set_target_revision = set_target_revision;
473  tree_editor->open_root = open_root;
474  tree_editor->delete_entry = delete_entry;
475  tree_editor->add_directory = add_directory;
476  tree_editor->open_directory = open_directory;
477  tree_editor->change_dir_prop = change_dir_prop;
478  tree_editor->close_directory = close_directory;
479  tree_editor->absent_directory = absent_directory;
480  tree_editor->add_file = add_file;
481  tree_editor->open_file = open_file;
482  tree_editor->apply_textdelta = apply_textdelta;
483  tree_editor->apply_textdelta_stream = apply_textdelta_stream;
484  tree_editor->change_file_prop = change_file_prop;
485  tree_editor->close_file = close_file;
486  tree_editor->absent_file = absent_file;
487  tree_editor->close_edit = close_edit;
488  tree_editor->abort_edit = abort_edit;
489
490  eb->wrapped_editor = wrapped_editor;
491  eb->wrapped_edit_baton = wrapped_edit_baton;
492  eb->out = out;
493  eb->indent_level = 0;
494  /* This is DBG_FLAG from ../libsvn_subr/debug.c */
495  eb->prefix = apr_pstrcat(pool, "DBG: ", prefix, SVN_VA_NULL);
496
497  *editor = tree_editor;
498  *edit_baton = eb;
499
500  return SVN_NO_ERROR;
501}
502