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
28 struct 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
39 struct dir_baton
40 {
41 void *edit_baton;
42 void *wrapped_dir_baton;
43 };
44
45 struct file_baton
46 {
47 void *edit_baton;
48 void *wrapped_file_baton;
49 };
50
51 static svn_error_t *
write_indent(struct edit_baton * eb,apr_pool_t * pool)52 write_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
63 static svn_error_t *
set_target_revision(void * edit_baton,svn_revnum_t target_revision,apr_pool_t * pool)64 set_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
79 static svn_error_t *
open_root(void * edit_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** root_baton)80 open_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
105 static svn_error_t *
delete_entry(const char * path,svn_revnum_t base_revision,void * parent_baton,apr_pool_t * pool)106 delete_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
124 static svn_error_t *
add_directory(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * pool,void ** child_baton)125 add_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
155 static svn_error_t *
open_directory(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** child_baton)156 open_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
183 static svn_error_t *
add_file(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * pool,void ** file_baton)184 add_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
215 static svn_error_t *
open_file(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** file_baton)216 open_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
244 static svn_error_t *
apply_textdelta(void * file_baton,const char * base_checksum,apr_pool_t * pool,svn_txdelta_window_handler_t * handler,void ** handler_baton)245 apply_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
267 static svn_error_t *
close_file(void * file_baton,const char * text_checksum,apr_pool_t * pool)268 close_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
287 static svn_error_t *
absent_file(const char * path,void * file_baton,apr_pool_t * pool)288 absent_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
304 static svn_error_t *
close_directory(void * dir_baton,apr_pool_t * pool)305 close_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
321 static svn_error_t *
absent_directory(const char * path,void * dir_baton,apr_pool_t * pool)322 absent_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
339 static svn_error_t *
change_file_prop(void * file_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)340 change_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 -> %s\n",
350 name, value ? value->data : "<deleted>"));
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
360 static svn_error_t *
change_dir_prop(void * dir_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)361 change_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 -> %s\n",
371 name, value ? value->data : "<deleted>"));
372
373 SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
374 name,
375 value,
376 pool));
377
378 return SVN_NO_ERROR;
379 }
380
381 static svn_error_t *
close_edit(void * edit_baton,apr_pool_t * pool)382 close_edit(void *edit_baton,
383 apr_pool_t *pool)
384 {
385 struct edit_baton *eb = edit_baton;
386
387 SVN_ERR(write_indent(eb, pool));
388 SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
389
390 SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
391
392 return SVN_NO_ERROR;
393 }
394
395 static svn_error_t *
abort_edit(void * edit_baton,apr_pool_t * pool)396 abort_edit(void *edit_baton,
397 apr_pool_t *pool)
398 {
399 struct edit_baton *eb = edit_baton;
400
401 SVN_ERR(write_indent(eb, pool));
402 SVN_ERR(svn_stream_printf(eb->out, pool, "abort_edit\n"));
403
404 SVN_ERR(eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool));
405
406 return SVN_NO_ERROR;
407 }
408
409 svn_error_t *
svn_delta__get_debug_editor(const svn_delta_editor_t ** editor,void ** edit_baton,const svn_delta_editor_t * wrapped_editor,void * wrapped_edit_baton,const char * prefix,apr_pool_t * pool)410 svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
411 void **edit_baton,
412 const svn_delta_editor_t *wrapped_editor,
413 void *wrapped_edit_baton,
414 const char *prefix,
415 apr_pool_t *pool)
416 {
417 svn_delta_editor_t *tree_editor = apr_palloc(pool, sizeof(*tree_editor));
418 struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
419 apr_file_t *errfp;
420 svn_stream_t *out;
421
422 apr_status_t apr_err = apr_file_open_stdout(&errfp, pool);
423 if (apr_err)
424 return svn_error_wrap_apr(apr_err, "Problem opening stderr");
425
426 out = svn_stream_from_aprfile2(errfp, TRUE, pool);
427
428 tree_editor->set_target_revision = set_target_revision;
429 tree_editor->open_root = open_root;
430 tree_editor->delete_entry = delete_entry;
431 tree_editor->add_directory = add_directory;
432 tree_editor->open_directory = open_directory;
433 tree_editor->change_dir_prop = change_dir_prop;
434 tree_editor->close_directory = close_directory;
435 tree_editor->absent_directory = absent_directory;
436 tree_editor->add_file = add_file;
437 tree_editor->open_file = open_file;
438 tree_editor->apply_textdelta = apply_textdelta;
439 tree_editor->change_file_prop = change_file_prop;
440 tree_editor->close_file = close_file;
441 tree_editor->absent_file = absent_file;
442 tree_editor->close_edit = close_edit;
443 tree_editor->abort_edit = abort_edit;
444
445 eb->wrapped_editor = wrapped_editor;
446 eb->wrapped_edit_baton = wrapped_edit_baton;
447 eb->out = out;
448 eb->indent_level = 0;
449 /* This is DBG_FLAG from ../libsvn_subr/debug.c */
450 eb->prefix = apr_pstrcat(pool, "DBG: ", prefix, SVN_VA_NULL);
451
452 *editor = tree_editor;
453 *edit_baton = eb;
454
455 return SVN_NO_ERROR;
456 }
457