~ubuntu-branches/ubuntu/trusty/subversion/trusty-proposed

« back to all changes in this revision

Viewing changes to subversion/libsvn_wc/conflicts.c

  • Committer: Package Import Robot
  • Author(s): Andy Whitcroft
  • Date: 2012-06-21 15:36:36 UTC
  • mfrom: (0.4.13 sid)
  • Revision ID: package-import@ubuntu.com-20120621153636-amqqmuidgwgxz1ly
Tags: 1.7.5-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Create pot file on build.
  - Build a python-subversion-dbg package.
  - Build-depend on python-dbg.
  - Build-depend on default-jre-headless/-jdk.
  - Do not apply java-build patch.
  - debian/rules: Manually create the doxygen output directory, otherwise
    we get weird build failures when running parallel builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * conflicts.c: routines for managing conflict data.
 
3
 *            NOTE: this code doesn't know where the conflict is
 
4
 *            actually stored.
 
5
 *
 
6
 * ====================================================================
 
7
 *    Licensed to the Apache Software Foundation (ASF) under one
 
8
 *    or more contributor license agreements.  See the NOTICE file
 
9
 *    distributed with this work for additional information
 
10
 *    regarding copyright ownership.  The ASF licenses this file
 
11
 *    to you under the Apache License, Version 2.0 (the
 
12
 *    "License"); you may not use this file except in compliance
 
13
 *    with the License.  You may obtain a copy of the License at
 
14
 *
 
15
 *      http://www.apache.org/licenses/LICENSE-2.0
 
16
 *
 
17
 *    Unless required by applicable law or agreed to in writing,
 
18
 *    software distributed under the License is distributed on an
 
19
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
20
 *    KIND, either express or implied.  See the License for the
 
21
 *    specific language governing permissions and limitations
 
22
 *    under the License.
 
23
 * ====================================================================
 
24
 */
 
25
 
 
26
 
 
27
 
 
28
#include <string.h>
 
29
 
 
30
#include <apr_pools.h>
 
31
#include <apr_tables.h>
 
32
#include <apr_hash.h>
 
33
#include <apr_errno.h>
 
34
 
 
35
#include "svn_types.h"
 
36
#include "svn_pools.h"
 
37
#include "svn_string.h"
 
38
#include "svn_error.h"
 
39
#include "svn_dirent_uri.h"
 
40
#include "svn_wc.h"
 
41
#include "svn_io.h"
 
42
#include "svn_diff.h"
 
43
 
 
44
#include "wc.h"
 
45
#include "wc_db.h"
 
46
#include "conflicts.h"
 
47
 
 
48
#include "private/svn_wc_private.h"
 
49
#include "private/svn_skel.h"
 
50
 
 
51
#include "svn_private_config.h"
 
52
 
 
53
svn_skel_t *
 
54
svn_wc__conflict_skel_new(apr_pool_t *result_pool)
 
55
{
 
56
  svn_skel_t *operation = svn_skel__make_empty_list(result_pool);
 
57
  svn_skel_t *result = svn_skel__make_empty_list(result_pool);
 
58
 
 
59
  svn_skel__prepend(operation, result);
 
60
  return result;
 
61
}
 
62
 
 
63
 
 
64
static void
 
65
prepend_prop_value(const svn_string_t *value,
 
66
                   svn_skel_t *skel,
 
67
                   apr_pool_t *result_pool)
 
68
{
 
69
  svn_skel_t *value_skel = svn_skel__make_empty_list(result_pool);
 
70
 
 
71
  if (value != NULL)
 
72
    {
 
73
      const void *dup = apr_pmemdup(result_pool, value->data, value->len);
 
74
 
 
75
      svn_skel__prepend(svn_skel__mem_atom(dup, value->len, result_pool),
 
76
                        value_skel);
 
77
    }
 
78
 
 
79
  svn_skel__prepend(value_skel, skel);
 
80
}
 
81
 
 
82
 
 
83
svn_error_t *
 
84
svn_wc__conflict_skel_add_prop_conflict(
 
85
  svn_skel_t *skel,
 
86
  const char *prop_name,
 
87
  const svn_string_t *original_value,
 
88
  const svn_string_t *mine_value,
 
89
  const svn_string_t *incoming_value,
 
90
  const svn_string_t *incoming_base_value,
 
91
  apr_pool_t *result_pool,
 
92
  apr_pool_t *scratch_pool)
 
93
{
 
94
  svn_skel_t *prop_skel = svn_skel__make_empty_list(result_pool);
 
95
 
 
96
  /* ### check that OPERATION has been filled in.  */
 
97
 
 
98
  /* See notes/wc-ng/conflict-storage  */
 
99
  prepend_prop_value(incoming_base_value, prop_skel, result_pool);
 
100
  prepend_prop_value(incoming_value, prop_skel, result_pool);
 
101
  prepend_prop_value(mine_value, prop_skel, result_pool);
 
102
  prepend_prop_value(original_value, prop_skel, result_pool);
 
103
  svn_skel__prepend_str(apr_pstrdup(result_pool, prop_name), prop_skel,
 
104
                        result_pool);
 
105
  svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_PROP, prop_skel, result_pool);
 
106
 
 
107
  /* Now we append PROP_SKEL to the end of the provided conflict SKEL.  */
 
108
  svn_skel__append(skel, prop_skel);
 
109
 
 
110
  return SVN_NO_ERROR;
 
111
}
 
112
 
 
113
 
 
114
 
 
115
 
 
116
/*** Resolving a conflict automatically ***/
 
117
 
 
118
 
 
119
/* Helper for resolve_conflict_on_entry.  Delete the file FILE_ABSPATH
 
120
   in if it exists.  Set WAS_PRESENT to TRUE if the file existed, and
 
121
   leave it UNTOUCHED otherwise. */
 
122
static svn_error_t *
 
123
attempt_deletion(const char *file_abspath,
 
124
                 svn_boolean_t *was_present,
 
125
                 apr_pool_t *scratch_pool)
 
126
{
 
127
  svn_error_t *err;
 
128
 
 
129
  if (file_abspath == NULL)
 
130
    return SVN_NO_ERROR;
 
131
 
 
132
  err = svn_io_remove_file2(file_abspath, FALSE, scratch_pool);
 
133
 
 
134
  if (err == NULL || !APR_STATUS_IS_ENOENT(err->apr_err))
 
135
    {
 
136
      *was_present = TRUE;
 
137
      return svn_error_trace(err);
 
138
    }
 
139
 
 
140
  svn_error_clear(err);
 
141
  return SVN_NO_ERROR;
 
142
}
 
143
 
 
144
 
 
145
/* Conflict resolution involves removing the conflict files, if they exist,
 
146
   and clearing the conflict filenames from the entry.  The latter needs to
 
147
   be done whether or not the conflict files exist.
 
148
 
 
149
   Tree conflicts are not resolved here, because the data stored in one
 
150
   entry does not refer to that entry but to children of it.
 
151
 
 
152
   PATH is the path to the item to be resolved, BASE_NAME is the basename
 
153
   of PATH, and CONFLICT_DIR is the access baton for PATH.  ORIG_ENTRY is
 
154
   the entry prior to resolution. RESOLVE_TEXT and RESOLVE_PROPS are TRUE
 
155
   if text and property conflicts respectively are to be resolved.
 
156
 
 
157
   If this call marks any conflict as resolved, set *DID_RESOLVE to true,
 
158
   else do not change *DID_RESOLVE.
 
159
 
 
160
   See svn_wc_resolved_conflict5() for how CONFLICT_CHOICE behaves.
 
161
 
 
162
   ### FIXME: This function should be loggy, otherwise an interruption can
 
163
   ### leave, for example, one of the conflict artifact files deleted but
 
164
   ### the entry still referring to it and trying to use it for the next
 
165
   ### attempt at resolving.
 
166
 
 
167
   ### Does this still apply in the world of WC-NG?  -hkw
 
168
*/
 
169
static svn_error_t *
 
170
resolve_conflict_on_node(svn_wc__db_t *db,
 
171
                         const char *local_abspath,
 
172
                         svn_boolean_t resolve_text,
 
173
                         svn_boolean_t resolve_props,
 
174
                         svn_wc_conflict_choice_t conflict_choice,
 
175
                         svn_boolean_t *did_resolve,
 
176
                         apr_pool_t *pool)
 
177
{
 
178
  svn_boolean_t found_file;
 
179
  const char *conflict_old = NULL;
 
180
  const char *conflict_new = NULL;
 
181
  const char *conflict_working = NULL;
 
182
  const char *prop_reject_file = NULL;
 
183
  svn_wc__db_kind_t kind;
 
184
  int i;
 
185
  const apr_array_header_t *conflicts;
 
186
  const char *conflict_dir_abspath;
 
187
 
 
188
  *did_resolve = FALSE;
 
189
 
 
190
  SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, TRUE, pool));
 
191
  SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
 
192
                                    pool, pool));
 
193
 
 
194
  for (i = 0; i < conflicts->nelts; i++)
 
195
    {
 
196
      const svn_wc_conflict_description2_t *desc;
 
197
 
 
198
      desc = APR_ARRAY_IDX(conflicts, i,
 
199
                           const svn_wc_conflict_description2_t*);
 
200
 
 
201
      if (desc->kind == svn_wc_conflict_kind_text)
 
202
        {
 
203
          conflict_old = desc->base_abspath;
 
204
          conflict_new = desc->their_abspath;
 
205
          conflict_working = desc->my_abspath;
 
206
        }
 
207
      else if (desc->kind == svn_wc_conflict_kind_property)
 
208
        prop_reject_file = desc->their_abspath;
 
209
    }
 
210
 
 
211
  if (kind == svn_wc__db_kind_dir)
 
212
    conflict_dir_abspath = local_abspath;
 
213
  else
 
214
    conflict_dir_abspath = svn_dirent_dirname(local_abspath, pool);
 
215
 
 
216
  if (resolve_text)
 
217
    {
 
218
      const char *auto_resolve_src;
 
219
 
 
220
      /* Handle automatic conflict resolution before the temporary files are
 
221
       * deleted, if necessary. */
 
222
      switch (conflict_choice)
 
223
        {
 
224
        case svn_wc_conflict_choose_base:
 
225
          auto_resolve_src = conflict_old;
 
226
          break;
 
227
        case svn_wc_conflict_choose_mine_full:
 
228
          auto_resolve_src = conflict_working;
 
229
          break;
 
230
        case svn_wc_conflict_choose_theirs_full:
 
231
          auto_resolve_src = conflict_new;
 
232
          break;
 
233
        case svn_wc_conflict_choose_merged:
 
234
          auto_resolve_src = NULL;
 
235
          break;
 
236
        case svn_wc_conflict_choose_theirs_conflict:
 
237
        case svn_wc_conflict_choose_mine_conflict:
 
238
          {
 
239
            if (conflict_old && conflict_working && conflict_new)
 
240
              {
 
241
                const char *temp_dir;
 
242
                svn_stream_t *tmp_stream = NULL;
 
243
                svn_diff_t *diff;
 
244
                svn_diff_conflict_display_style_t style =
 
245
                  conflict_choice == svn_wc_conflict_choose_theirs_conflict
 
246
                  ? svn_diff_conflict_display_latest
 
247
                  : svn_diff_conflict_display_modified;
 
248
 
 
249
                SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
 
250
                                                       conflict_dir_abspath,
 
251
                                                       pool, pool));
 
252
                SVN_ERR(svn_stream_open_unique(&tmp_stream,
 
253
                                               &auto_resolve_src,
 
254
                                               temp_dir,
 
255
                                               svn_io_file_del_on_pool_cleanup,
 
256
                                               pool, pool));
 
257
 
 
258
                SVN_ERR(svn_diff_file_diff3_2(&diff,
 
259
                                              conflict_old,
 
260
                                              conflict_working,
 
261
                                              conflict_new,
 
262
                                              svn_diff_file_options_create(pool),
 
263
                                              pool));
 
264
                SVN_ERR(svn_diff_file_output_merge2(tmp_stream, diff,
 
265
                                                    conflict_old,
 
266
                                                    conflict_working,
 
267
                                                    conflict_new,
 
268
                                                    /* markers ignored */
 
269
                                                    NULL, NULL, NULL, NULL,
 
270
                                                    style,
 
271
                                                    pool));
 
272
                SVN_ERR(svn_stream_close(tmp_stream));
 
273
              }
 
274
            else
 
275
              auto_resolve_src = NULL;
 
276
            break;
 
277
          }
 
278
        default:
 
279
          return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
 
280
                                  _("Invalid 'conflict_result' argument"));
 
281
        }
 
282
 
 
283
      if (auto_resolve_src)
 
284
        SVN_ERR(svn_io_copy_file(
 
285
          svn_dirent_join(conflict_dir_abspath, auto_resolve_src, pool),
 
286
          local_abspath, TRUE, pool));
 
287
    }
 
288
 
 
289
  /* Records whether we found any of the conflict files.  */
 
290
  found_file = FALSE;
 
291
 
 
292
  if (resolve_text)
 
293
    {
 
294
      SVN_ERR(attempt_deletion(conflict_old, &found_file, pool));
 
295
      SVN_ERR(attempt_deletion(conflict_new, &found_file, pool));
 
296
      SVN_ERR(attempt_deletion(conflict_working, &found_file, pool));
 
297
      resolve_text = conflict_old || conflict_new || conflict_working;
 
298
    }
 
299
  if (resolve_props)
 
300
    {
 
301
      if (prop_reject_file != NULL)
 
302
        SVN_ERR(attempt_deletion(prop_reject_file, &found_file, pool));
 
303
      else
 
304
        resolve_props = FALSE;
 
305
    }
 
306
 
 
307
  if (resolve_text || resolve_props)
 
308
    {
 
309
      SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
 
310
                                          resolve_text, resolve_props,
 
311
                                          FALSE, pool));
 
312
 
 
313
      /* No feedback if no files were deleted and all we did was change the
 
314
         entry, such a file did not appear as a conflict */
 
315
      if (found_file)
 
316
        *did_resolve = TRUE;
 
317
    }
 
318
 
 
319
  return SVN_NO_ERROR;
 
320
}
 
321
 
 
322
 
 
323
svn_error_t *
 
324
svn_wc__resolve_text_conflict(svn_wc__db_t *db,
 
325
                              const char *local_abspath,
 
326
                              apr_pool_t *scratch_pool)
 
327
{
 
328
  svn_boolean_t ignored_result;
 
329
 
 
330
  return svn_error_trace(resolve_conflict_on_node(
 
331
                           db, local_abspath,
 
332
                           TRUE /* resolve_text */,
 
333
                           FALSE /* resolve_props */,
 
334
                           svn_wc_conflict_choose_merged,
 
335
                           &ignored_result,
 
336
                           scratch_pool));
 
337
}
 
338
 
 
339
 
 
340
/* */
 
341
static svn_error_t *
 
342
resolve_one_conflict(svn_wc__db_t *db,
 
343
                     const char *local_abspath,
 
344
                     svn_boolean_t resolve_text,
 
345
                     const char *resolve_prop,
 
346
                     svn_boolean_t resolve_tree,
 
347
                     svn_wc_conflict_choice_t conflict_choice,
 
348
                     svn_wc_notify_func2_t notify_func,
 
349
                     void *notify_baton,
 
350
                     apr_pool_t *scratch_pool)
 
351
{
 
352
  const apr_array_header_t *conflicts;
 
353
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
354
  int i;
 
355
  svn_boolean_t resolved = FALSE;
 
356
 
 
357
  SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
 
358
                                    scratch_pool, iterpool));
 
359
 
 
360
  for (i = 0; i < conflicts->nelts; i++)
 
361
    {
 
362
      const svn_wc_conflict_description2_t *cd;
 
363
      svn_boolean_t did_resolve;
 
364
 
 
365
      cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
 
366
 
 
367
      svn_pool_clear(iterpool);
 
368
 
 
369
      switch (cd->kind)
 
370
        {
 
371
          case svn_wc_conflict_kind_tree:
 
372
            if (!resolve_tree)
 
373
              break;
 
374
 
 
375
            /* For now, we only clear tree conflict information and resolve
 
376
             * to the working state. There is no way to pick theirs-full
 
377
             * or mine-full, etc. Throw an error if the user expects us
 
378
             * to be smarter than we really are. */
 
379
            if (conflict_choice != svn_wc_conflict_choose_merged)
 
380
              {
 
381
                return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
 
382
                                         NULL,
 
383
                                         _("Tree conflicts can only be "
 
384
                                           "resolved to 'working' state; "
 
385
                                           "'%s' not resolved"),
 
386
                                         svn_dirent_local_style(local_abspath,
 
387
                                                                iterpool));
 
388
              }
 
389
 
 
390
            SVN_ERR(svn_wc__db_op_set_tree_conflict(db, local_abspath, NULL,
 
391
                                                    iterpool));
 
392
 
 
393
            resolved = TRUE;
 
394
            break;
 
395
 
 
396
          case svn_wc_conflict_kind_text:
 
397
            if (!resolve_text)
 
398
              break;
 
399
 
 
400
            SVN_ERR(resolve_conflict_on_node(db,
 
401
                                             local_abspath,
 
402
                                             TRUE /* resolve_text */,
 
403
                                             FALSE /* resolve_props */,
 
404
                                             conflict_choice,
 
405
                                             &did_resolve,
 
406
                                             iterpool));
 
407
 
 
408
            if (did_resolve)
 
409
              resolved = TRUE;
 
410
            break;
 
411
 
 
412
          case svn_wc_conflict_kind_property:
 
413
            if (!resolve_prop)
 
414
              break;
 
415
 
 
416
            /* ### this is bogus. resolve_conflict_on_node() does not handle
 
417
               ### individual property resolution.  */
 
418
            if (*resolve_prop != '\0' &&
 
419
                strcmp(resolve_prop, cd->property_name) != 0)
 
420
              {
 
421
                break; /* Skip this property conflict */
 
422
              }
 
423
 
 
424
 
 
425
            /* We don't have property name handling here yet :( */
 
426
            SVN_ERR(resolve_conflict_on_node(db,
 
427
                                             local_abspath,
 
428
                                             FALSE /* resolve_text */,
 
429
                                             TRUE /* resolve_props */,
 
430
                                             conflict_choice,
 
431
                                             &did_resolve,
 
432
                                             iterpool));
 
433
 
 
434
            if (did_resolve)
 
435
              resolved = TRUE;
 
436
            break;
 
437
 
 
438
          default:
 
439
            /* We can't resolve other conflict types */
 
440
            break;
 
441
        }
 
442
    }
 
443
 
 
444
  /* Notify */
 
445
  if (notify_func && resolved)
 
446
    notify_func(notify_baton,
 
447
                svn_wc_create_notify(local_abspath, svn_wc_notify_resolved,
 
448
                                     iterpool),
 
449
                iterpool);
 
450
 
 
451
  svn_pool_destroy(iterpool);
 
452
 
 
453
  return SVN_NO_ERROR;
 
454
}
 
455
 
 
456
/* */
 
457
static svn_error_t *
 
458
recursive_resolve_conflict(svn_wc__db_t *db,
 
459
                           const char *local_abspath,
 
460
                           svn_boolean_t this_is_conflicted,
 
461
                           svn_depth_t depth,
 
462
                           svn_boolean_t resolve_text,
 
463
                           const char *resolve_prop,
 
464
                           svn_boolean_t resolve_tree,
 
465
                           svn_wc_conflict_choice_t conflict_choice,
 
466
                           svn_cancel_func_t cancel_func,
 
467
                           void *cancel_baton,
 
468
                           svn_wc_notify_func2_t notify_func,
 
469
                           void *notify_baton,
 
470
                           apr_pool_t *scratch_pool)
 
471
{
 
472
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
473
  const apr_array_header_t *children;
 
474
  apr_hash_t *visited = apr_hash_make(scratch_pool);
 
475
  svn_depth_t child_depth;
 
476
  int i;
 
477
 
 
478
  if (cancel_func)
 
479
    SVN_ERR(cancel_func(cancel_baton));
 
480
 
 
481
  if (this_is_conflicted)
 
482
    {
 
483
      SVN_ERR(resolve_one_conflict(db,
 
484
                                   local_abspath,
 
485
                                   resolve_text,
 
486
                                   resolve_prop,
 
487
                                   resolve_tree,
 
488
                                   conflict_choice,
 
489
                                   notify_func, notify_baton,
 
490
                                   iterpool));
 
491
    }
 
492
 
 
493
  if (depth < svn_depth_files)
 
494
    return SVN_NO_ERROR;
 
495
 
 
496
  child_depth = (depth < svn_depth_infinity) ? svn_depth_empty : depth;
 
497
 
 
498
  SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
 
499
                                   scratch_pool, iterpool));
 
500
 
 
501
  for (i = 0; i < children->nelts; i++)
 
502
    {
 
503
      const char *name = APR_ARRAY_IDX(children, i, const char *);
 
504
      const char *child_abspath;
 
505
      svn_wc__db_status_t status;
 
506
      svn_wc__db_kind_t kind;
 
507
      svn_boolean_t conflicted;
 
508
 
 
509
      svn_pool_clear(iterpool);
 
510
 
 
511
      if (cancel_func)
 
512
        SVN_ERR(cancel_func(cancel_baton));
 
513
 
 
514
      child_abspath = svn_dirent_join(local_abspath, name, iterpool);
 
515
 
 
516
      SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
 
517
                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
518
                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
519
                                   &conflicted, NULL, NULL, NULL, NULL, NULL,
 
520
                                   NULL,
 
521
                                   db, child_abspath, iterpool, iterpool));
 
522
 
 
523
      if (status == svn_wc__db_status_not_present
 
524
          || status == svn_wc__db_status_excluded
 
525
          || status == svn_wc__db_status_server_excluded)
 
526
        continue;
 
527
 
 
528
      apr_hash_set(visited, name, APR_HASH_KEY_STRING, name);
 
529
      if (kind == svn_wc__db_kind_dir && depth < svn_depth_immediates)
 
530
        continue;
 
531
 
 
532
      if (kind == svn_wc__db_kind_dir)
 
533
        SVN_ERR(recursive_resolve_conflict(db,
 
534
                                           child_abspath,
 
535
                                           conflicted,
 
536
                                           child_depth,
 
537
                                           resolve_text,
 
538
                                           resolve_prop,
 
539
                                           resolve_tree,
 
540
                                           conflict_choice,
 
541
                                           cancel_func, cancel_baton,
 
542
                                           notify_func, notify_baton,
 
543
                                           iterpool));
 
544
      else if (conflicted)
 
545
        SVN_ERR(resolve_one_conflict(db,
 
546
                                     child_abspath,
 
547
                                     resolve_text,
 
548
                                     resolve_prop,
 
549
                                     resolve_tree,
 
550
                                     conflict_choice,
 
551
                                     notify_func, notify_baton,
 
552
                                     iterpool));
 
553
    }
 
554
 
 
555
    SVN_ERR(svn_wc__db_read_conflict_victims(&children, db, local_abspath,
 
556
                                           scratch_pool, iterpool));
 
557
 
 
558
  for (i = 0; i < children->nelts; i++)
 
559
    {
 
560
      const char *name = APR_ARRAY_IDX(children, i, const char *);
 
561
      const char *child_abspath;
 
562
 
 
563
      svn_pool_clear(iterpool);
 
564
 
 
565
      if (apr_hash_get(visited, name, APR_HASH_KEY_STRING) != NULL)
 
566
        continue; /* Already visited */
 
567
 
 
568
      if (cancel_func)
 
569
        SVN_ERR(cancel_func(cancel_baton));
 
570
 
 
571
      child_abspath = svn_dirent_join(local_abspath, name, iterpool);
 
572
 
 
573
      /* We only have to resolve one level of tree conflicts. All other
 
574
         conflicts are resolved in the other loop */
 
575
      SVN_ERR(resolve_one_conflict(db,
 
576
                                   child_abspath,
 
577
                                   FALSE /*resolve_text*/,
 
578
                                   FALSE /*resolve_prop*/,
 
579
                                   resolve_tree,
 
580
                                   conflict_choice,
 
581
                                   notify_func, notify_baton,
 
582
                                   iterpool));
 
583
    }
 
584
 
 
585
 
 
586
  svn_pool_destroy(iterpool);
 
587
 
 
588
  return SVN_NO_ERROR;
 
589
}
 
590
 
 
591
 
 
592
svn_error_t *
 
593
svn_wc_resolved_conflict5(svn_wc_context_t *wc_ctx,
 
594
                          const char *local_abspath,
 
595
                          svn_depth_t depth,
 
596
                          svn_boolean_t resolve_text,
 
597
                          const char *resolve_prop,
 
598
                          svn_boolean_t resolve_tree,
 
599
                          svn_wc_conflict_choice_t conflict_choice,
 
600
                          svn_cancel_func_t cancel_func,
 
601
                          void *cancel_baton,
 
602
                          svn_wc_notify_func2_t notify_func,
 
603
                          void *notify_baton,
 
604
                          apr_pool_t *scratch_pool)
 
605
{
 
606
  svn_wc__db_kind_t kind;
 
607
  svn_boolean_t conflicted;
 
608
  /* ### the underlying code does NOT support resolving individual
 
609
     ### properties. bail out if the caller tries it.  */
 
610
  if (resolve_prop != NULL && *resolve_prop != '\0')
 
611
    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
 
612
                            U_("Resolving a single property is not (yet) "
 
613
                               "supported."));
 
614
 
 
615
  SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL,
 
616
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
617
                               NULL, NULL, NULL, NULL, NULL, NULL, &conflicted,
 
618
                               NULL, NULL, NULL, NULL, NULL, NULL,
 
619
                               wc_ctx->db, local_abspath,
 
620
                               scratch_pool, scratch_pool));
 
621
 
 
622
  /* When the implementation still used the entry walker, depth
 
623
     unknown was translated to infinity. */
 
624
  if (kind != svn_wc__db_kind_dir)
 
625
    depth = svn_depth_empty;
 
626
  else if (depth == svn_depth_unknown)
 
627
    depth = svn_depth_infinity;
 
628
 
 
629
  return svn_error_trace(recursive_resolve_conflict(
 
630
                           wc_ctx->db,
 
631
                           local_abspath,
 
632
                           conflicted,
 
633
                           depth,
 
634
                           resolve_text,
 
635
                           resolve_prop,
 
636
                           resolve_tree,
 
637
                           conflict_choice,
 
638
                           cancel_func, cancel_baton,
 
639
                           notify_func, notify_baton,
 
640
                           scratch_pool));
 
641
}