258
272
apr_pool_t *pool)
260
274
return (svn_client_commit_item3_t *)
261
apr_hash_get(committables->by_path, path, APR_HASH_KEY_STRING);
264
/* Helper for harvest_committables().
265
* If ENTRY is a dir, return an SVN_ERR_WC_FOUND_CONFLICT error when
266
* encountering a tree-conflicted immediate child node. However, do
267
* not consider immediate children that are outside the bounds of DEPTH.
269
* TODO ### WC_CTX and LOCAL_ABSPATH ...
270
* ENTRY, DEPTH, CHANGELISTS and POOL are the same ones
271
* originally received by harvest_committables().
273
* Tree-conflicts information is stored in the victim's immediate parent.
274
* In some cases of an absent tree-conflicted victim, the tree-conflict
275
* information in its parent dir is the only indication that the node
276
* is under version control. This function is necessary for this
277
* particular case. In all other cases, this simply bails out a little
280
bail_on_tree_conflicted_children(svn_wc_context_t *wc_ctx,
281
const char *local_abspath,
282
svn_node_kind_t kind,
284
apr_hash_t *changelists,
285
svn_wc_notify_func2_t notify_func,
289
apr_hash_t *conflicts;
290
apr_hash_index_t *hi;
292
if ((depth == svn_depth_empty)
293
|| (kind != svn_node_dir))
294
/* There can't possibly be tree-conflicts information here. */
297
SVN_ERR(svn_wc__get_all_tree_conflicts(&conflicts, wc_ctx, local_abspath,
302
for (hi = apr_hash_first(pool, conflicts); hi; hi = apr_hash_next(hi))
304
const svn_wc_conflict_description2_t *conflict =
305
svn__apr_hash_index_val(hi);
307
if ((conflict->node_kind == svn_node_dir) &&
308
(depth == svn_depth_files))
311
/* So we've encountered a conflict that is included in DEPTH.
312
Bail out. But if there are CHANGELISTS, avoid bailing out
313
on an item that doesn't match the CHANGELISTS. */
314
if (!svn_wc__changelist_match(wc_ctx, local_abspath, changelists, pool))
317
/* At this point, a conflict was found, and either there were no
318
changelists, or the changelists matched. Bail out already! */
320
if (notify_func != NULL)
322
notify_func(notify_baton,
323
svn_wc_create_notify(local_abspath,
324
svn_wc_notify_failed_conflict,
329
return svn_error_createf(
330
SVN_ERR_WC_FOUND_CONFLICT, NULL,
331
_("Aborting commit: '%s' remains in conflict"),
332
svn_dirent_local_style(conflict->local_abspath, pool));
275
svn_hash_gets(committables->by_path, path);
338
278
/* Helper function for svn_client__harvest_committables().
420
366
Any items added to COMMITTABLES are allocated from the COMITTABLES
421
367
hash pool, not POOL. SCRATCH_POOL is used for temporary allocations. */
423
harvest_committables(svn_wc_context_t *wc_ctx,
424
const char *local_abspath,
372
const char *root_abspath;
373
svn_client__committables_t *committables;
374
apr_hash_t *lock_tokens;
375
const char *commit_relpath; /* Valid for the harvest root */
377
svn_boolean_t just_locked;
378
apr_hash_t *changelists;
379
apr_hash_t *danglers;
380
svn_client__check_url_kind_t check_url_func;
381
void *check_url_baton;
382
svn_wc_notify_func2_t notify_func;
384
svn_wc_context_t *wc_ctx;
385
apr_pool_t *result_pool;
387
/* Harvester state */
388
const char *skip_below_abspath; /* If non-NULL, skip everything below */
392
harvest_status_callback(void *status_baton,
393
const char *local_abspath,
394
const svn_wc_status3_t *status,
395
apr_pool_t *scratch_pool);
398
harvest_committables(const char *local_abspath,
425
399
svn_client__committables_t *committables,
426
400
apr_hash_t *lock_tokens,
427
const char *repos_root_url,
428
const char *commit_relpath,
429
svn_boolean_t copy_mode_root,
401
const char *copy_mode_relpath,
430
402
svn_depth_t depth,
431
403
svn_boolean_t just_locked,
432
404
apr_hash_t *changelists,
433
svn_boolean_t skip_files,
434
svn_boolean_t skip_dirs,
435
405
apr_hash_t *danglers,
436
406
svn_client__check_url_kind_t check_url_func,
437
407
void *check_url_baton,
439
409
void *cancel_baton,
440
410
svn_wc_notify_func2_t notify_func,
441
411
void *notify_baton,
412
svn_wc_context_t *wc_ctx,
442
413
apr_pool_t *result_pool,
443
414
apr_pool_t *scratch_pool)
445
svn_boolean_t text_mod = FALSE;
446
svn_boolean_t prop_mod = FALSE;
416
struct harvest_baton baton;
418
SVN_ERR_ASSERT((just_locked && lock_tokens) || !just_locked);
420
baton.root_abspath = local_abspath;
421
baton.committables = committables;
422
baton.lock_tokens = lock_tokens;
423
baton.commit_relpath = copy_mode_relpath;
425
baton.just_locked = just_locked;
426
baton.changelists = changelists;
427
baton.danglers = danglers;
428
baton.check_url_func = check_url_func;
429
baton.check_url_baton = check_url_baton;
430
baton.notify_func = notify_func;
431
baton.notify_baton = notify_baton;
432
baton.wc_ctx = wc_ctx;
433
baton.result_pool = result_pool;
435
baton.skip_below_abspath = NULL;
437
SVN_ERR(svn_wc_walk_status(wc_ctx,
440
(copy_mode_relpath != NULL) /* get_all */,
441
FALSE /* no_ignore */,
442
FALSE /* ignore_text_mods */,
443
NULL /* ignore_patterns */,
444
harvest_status_callback,
446
cancel_func, cancel_baton,
453
harvest_not_present_for_copy(svn_wc_context_t *wc_ctx,
454
const char *local_abspath,
455
svn_client__committables_t *committables,
456
const char *repos_root_url,
457
const char *commit_relpath,
458
svn_client__check_url_kind_t check_url_func,
459
void *check_url_baton,
460
apr_pool_t *result_pool,
461
apr_pool_t *scratch_pool)
463
const apr_array_header_t *children;
464
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
467
/* A function to retrieve not present children would be nice to have */
468
SVN_ERR(svn_wc__node_get_children_of_working_node(
469
&children, wc_ctx, local_abspath, TRUE,
470
scratch_pool, iterpool));
472
for (i = 0; i < children->nelts; i++)
474
const char *this_abspath = APR_ARRAY_IDX(children, i, const char *);
475
const char *name = svn_dirent_basename(this_abspath, NULL);
476
const char *this_commit_relpath;
477
svn_boolean_t not_present;
478
svn_node_kind_t kind;
480
svn_pool_clear(iterpool);
482
SVN_ERR(svn_wc__node_is_not_present(¬_present, NULL, NULL, wc_ctx,
483
this_abspath, FALSE, scratch_pool));
488
if (commit_relpath == NULL)
489
this_commit_relpath = NULL;
491
this_commit_relpath = svn_relpath_join(commit_relpath, name,
494
/* We should check if we should really add a delete operation */
497
svn_revnum_t parent_rev;
498
const char *parent_repos_relpath;
499
const char *parent_repos_root_url;
500
const char *node_url;
502
/* Determine from what parent we would be the deleted child */
503
SVN_ERR(svn_wc__node_get_origin(
504
NULL, &parent_rev, &parent_repos_relpath,
505
&parent_repos_root_url, NULL, NULL,
507
svn_dirent_dirname(this_abspath,
509
FALSE, scratch_pool, scratch_pool));
511
node_url = svn_path_url_add_component2(
512
svn_path_url_add_component2(parent_repos_root_url,
513
parent_repos_relpath,
515
svn_dirent_basename(this_abspath, NULL),
518
SVN_ERR(check_url_func(check_url_baton, &kind,
519
node_url, parent_rev, iterpool));
521
if (kind == svn_node_none)
522
continue; /* This node can't be deleted */
525
SVN_ERR(svn_wc_read_kind2(&kind, wc_ctx, this_abspath,
526
TRUE, TRUE, scratch_pool));
528
SVN_ERR(add_committable(committables, this_abspath, kind,
532
NULL /* copyfrom_relpath */,
533
SVN_INVALID_REVNUM /* copyfrom_rev */,
534
NULL /* moved_from_abspath */,
535
SVN_CLIENT_COMMIT_ITEM_DELETE,
537
result_pool, scratch_pool));
540
svn_pool_destroy(iterpool);
544
/* Implements svn_wc_status_func4_t */
546
harvest_status_callback(void *status_baton,
547
const char *local_abspath,
548
const svn_wc_status3_t *status,
549
apr_pool_t *scratch_pool)
447
551
apr_byte_t state_flags = 0;
448
svn_node_kind_t working_kind;
449
svn_node_kind_t db_kind;
450
const char *node_relpath;
451
const char *node_lock_token;
452
552
svn_revnum_t node_rev;
453
553
const char *cf_relpath = NULL;
454
554
svn_revnum_t cf_rev = SVN_INVALID_REVNUM;
455
555
svn_boolean_t matches_changelists;
456
svn_boolean_t is_special;
457
556
svn_boolean_t is_added;
458
557
svn_boolean_t is_deleted;
459
558
svn_boolean_t is_replaced;
460
svn_boolean_t is_not_present;
461
svn_boolean_t is_excluded;
462
559
svn_boolean_t is_op_root;
463
svn_boolean_t is_symlink;
464
svn_boolean_t conflicted;
465
const char *node_changelist;
466
svn_boolean_t is_update_root;
467
560
svn_revnum_t original_rev;
468
561
const char *original_relpath;
469
svn_boolean_t copy_mode = (commit_relpath != NULL);
471
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
562
svn_boolean_t copy_mode;
564
struct harvest_baton *baton = status_baton;
565
svn_boolean_t is_harvest_root =
566
(strcmp(baton->root_abspath, local_abspath) == 0);
567
svn_client__committables_t *committables = baton->committables;
568
const char *repos_root_url = status->repos_root_url;
569
const char *commit_relpath = NULL;
570
svn_boolean_t copy_mode_root = (baton->commit_relpath && is_harvest_root);
571
svn_boolean_t just_locked = baton->just_locked;
572
apr_hash_t *changelists = baton->changelists;
573
svn_wc_notify_func2_t notify_func = baton->notify_func;
574
void *notify_baton = baton->notify_baton;
575
svn_wc_context_t *wc_ctx = baton->wc_ctx;
576
apr_pool_t *result_pool = baton->result_pool;
577
const char *moved_from_abspath = NULL;
579
if (baton->commit_relpath)
580
commit_relpath = svn_relpath_join(
581
baton->commit_relpath,
582
svn_dirent_skip_ancestor(baton->root_abspath,
586
copy_mode = (commit_relpath != NULL);
588
if (baton->skip_below_abspath
589
&& svn_dirent_is_ancestor(baton->skip_below_abspath, local_abspath))
594
baton->skip_below_abspath = NULL; /* We have left the skip tree */
596
/* Return early for nodes that don't have a committable status */
597
switch (status->node_status)
599
case svn_wc_status_unversioned:
600
case svn_wc_status_ignored:
601
case svn_wc_status_external:
602
case svn_wc_status_none:
603
/* Unversioned nodes aren't committable, but are reported by the status
605
But if the unversioned node is the root of the walk, we have a user
608
return svn_error_createf(
609
SVN_ERR_ILLEGAL_TARGET, NULL,
610
_("'%s' is not under version control"),
611
svn_dirent_local_style(local_abspath, scratch_pool));
613
case svn_wc_status_normal:
614
/* Status normal nodes aren't modified, so we don't have to commit them
615
when we perform a normal commit. But if a node is conflicted we want
616
to stop the commit and if we are collecting lock tokens we want to
619
When in copy mode we need to compare the revision of the node against
620
the parent node to copy mixed-revision base nodes properly */
621
if (!copy_mode && !status->conflicted
622
&& !(just_locked && status->lock))
473
630
/* Early out if the item is already marked as committable. */
474
631
if (look_up_committable(committables, local_abspath, scratch_pool))
477
634
SVN_ERR_ASSERT((copy_mode && commit_relpath)
478
635
|| (! copy_mode && ! commit_relpath));
479
636
SVN_ERR_ASSERT((copy_mode_root && copy_mode) || ! copy_mode_root);
480
SVN_ERR_ASSERT((just_locked && lock_tokens) || !just_locked);
483
SVN_ERR(cancel_func(cancel_baton));
638
/* Save the result for reuse. */
639
matches_changelists = ((changelists == NULL)
640
|| (status->changelist != NULL
641
&& svn_hash_gets(changelists, status->changelist)
645
if (status->kind != svn_node_dir && ! matches_changelists)
650
/* If NODE is in our changelist, then examine it for conflicts. We
651
need to bail out if any conflicts exist.
652
The status walker checked for conflict marker removal. */
653
if (status->conflicted && matches_changelists)
655
if (notify_func != NULL)
657
notify_func(notify_baton,
658
svn_wc_create_notify(local_abspath,
659
svn_wc_notify_failed_conflict,
664
return svn_error_createf(
665
SVN_ERR_WC_FOUND_CONFLICT, NULL,
666
_("Aborting commit: '%s' remains in conflict"),
667
svn_dirent_local_style(local_abspath, scratch_pool));
669
else if (status->node_status == svn_wc_status_obstructed)
671
/* A node's type has changed before attempting to commit.
672
This also catches symlink vs non symlink changes */
674
if (notify_func != NULL)
676
notify_func(notify_baton,
677
svn_wc_create_notify(local_abspath,
678
svn_wc_notify_failed_obstruction,
683
return svn_error_createf(
684
SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
685
_("Node '%s' has unexpectedly changed kind"),
686
svn_dirent_local_style(local_abspath, scratch_pool));
689
if (status->conflicted && status->kind == svn_node_unknown)
690
return SVN_NO_ERROR; /* Ignore delete-delete conflict */
485
692
/* Return error on unknown path kinds. We check both the entry and
486
693
the node itself, since a path might have changed kind since its
487
694
entry was written. */
488
SVN_ERR(svn_wc__node_get_commit_status(&db_kind, &is_added, &is_deleted,
695
SVN_ERR(svn_wc__node_get_commit_status(&is_added, &is_deleted,
490
&is_not_present, &is_excluded,
491
&is_op_root, &is_symlink,
492
&node_rev, &node_relpath,
493
699
&original_rev, &original_relpath,
496
&prop_mod, &is_update_root,
498
700
wc_ctx, local_abspath,
499
701
scratch_pool, scratch_pool));
501
if ((skip_files && db_kind == svn_node_file) || is_excluded)
504
if (!node_relpath && commit_relpath)
505
node_relpath = commit_relpath;
507
SVN_ERR(svn_io_check_special_path(local_abspath, &working_kind, &is_special,
510
/* ### In 1.6 an obstructed dir would fail when locking before we
511
got here. Locking now doesn't fail so perhaps we should do
512
some sort of checking here. */
514
if ((working_kind != svn_node_file)
515
&& (working_kind != svn_node_dir)
516
&& (working_kind != svn_node_none))
518
return svn_error_createf
519
(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
520
_("Unknown entry kind for '%s'"),
521
svn_dirent_local_style(local_abspath, scratch_pool));
524
/* Save the result for reuse. */
525
matches_changelists = ((changelists == NULL)
526
|| (node_changelist != NULL
527
&& apr_hash_get(changelists, node_changelist,
528
APR_HASH_KEY_STRING) != NULL));
531
if (working_kind != svn_node_dir && working_kind != svn_node_none
532
&& ! matches_changelists)
703
/* Hande file externals only when passed as explicit target. Note that
704
* svn_client_commit6() passes all committable externals in as explicit
705
* targets iff they count. */
706
if (status->file_external && !is_harvest_root)
534
708
return SVN_NO_ERROR;
537
/* Verify that the node's type has not changed before attempting to
539
if ((((!is_symlink) && (is_special))
541
|| (is_symlink && (! is_special))
542
#endif /* HAVE_SYMLINK */
543
) && (working_kind != svn_node_none))
545
return svn_error_createf
546
(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
547
_("Entry '%s' has unexpectedly changed special status"),
548
svn_dirent_local_style(local_abspath, scratch_pool));
553
&& db_kind == svn_node_file)
559
/* If NODE is in our changelist, then examine it for conflicts. We
560
need to bail out if any conflicts exist. */
561
if (conflicted && matches_changelists)
563
svn_boolean_t tc, pc, treec;
565
SVN_ERR(svn_wc_conflicted_p3(&tc, &pc, &treec, wc_ctx,
566
local_abspath, scratch_pool));
567
if (tc || pc || treec)
711
if (status->node_status == svn_wc_status_missing && matches_changelists)
713
/* Added files and directories must exist. See issue #3198. */
714
if (is_added && is_op_root)
569
716
if (notify_func != NULL)
571
718
notify_func(notify_baton,
572
719
svn_wc_create_notify(local_abspath,
573
svn_wc_notify_failed_conflict,
720
svn_wc_notify_failed_missing,
578
724
return svn_error_createf(
579
SVN_ERR_WC_FOUND_CONFLICT, NULL,
580
_("Aborting commit: '%s' remains in conflict"),
581
svn_dirent_local_style(local_abspath, scratch_pool));
725
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
726
_("'%s' is scheduled for addition, but is missing"),
727
svn_dirent_local_style(local_abspath, scratch_pool));
585
733
if (is_deleted && !is_op_root /* && !is_added */)
586
734
return SVN_NO_ERROR; /* Not an operational delete and not an add. */
588
if (node_relpath == NULL)
589
SVN_ERR(svn_wc__node_get_repos_relpath(&node_relpath,
590
wc_ctx, local_abspath,
591
scratch_pool, scratch_pool));
592
736
/* Check for the deletion case.
593
737
* We delete explicitly deleted nodes (duh!)
594
738
* We delete not-present children of copies
646
754
state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
647
755
cf_relpath = original_relpath;
648
756
cf_rev = original_rev;
758
if (status->moved_from_abspath && !copy_mode)
760
state_flags |= SVN_CLIENT_COMMIT_ITEM_MOVED_HERE;
761
moved_from_abspath = status->moved_from_abspath;
652
/* Further additions occur in copy mode. */
654
&& (!is_added || copy_mode_root)
655
&& !(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
766
/* Further copies may occur in copy mode. */
768
&& !(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
657
svn_revnum_t dir_rev;
660
SVN_ERR(svn_wc__node_get_base_rev(&dir_rev, wc_ctx,
661
svn_dirent_dirname(local_abspath,
665
if (copy_mode_root || node_rev != dir_rev)
667
state_flags |= SVN_CLIENT_COMMIT_ITEM_ADD;
669
SVN_ERR(svn_wc__node_get_origin(NULL, &cf_rev,
672
wc_ctx, local_abspath, FALSE,
770
svn_revnum_t dir_rev = SVN_INVALID_REVNUM;
772
if (!copy_mode_root && !status->switched && !is_added)
773
SVN_ERR(svn_wc__node_get_base(NULL, &dir_rev, NULL, NULL, NULL, NULL,
774
wc_ctx, svn_dirent_dirname(local_abspath,
776
FALSE /* ignore_enoent */,
777
FALSE /* show_hidden */,
673
778
scratch_pool, scratch_pool));
676
state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
680
/* If an add is scheduled to occur, dig around for some more
681
information about it. */
682
if (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
684
/* First of all, the working file or directory must exist.
686
if (working_kind == svn_node_none)
688
if (notify_func != NULL)
690
notify_func(notify_baton,
691
svn_wc_create_notify(local_abspath,
692
svn_wc_notify_failed_missing,
696
return svn_error_createf(
697
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
698
_("'%s' is scheduled for addition, but is missing"),
699
svn_dirent_local_style(local_abspath, scratch_pool));
702
/* Regular adds of files have text mods, but for copies we have
703
to test for textual mods. Directories simply don't have text! */
704
if (db_kind == svn_node_file)
706
/* Check for text mods. */
707
if (state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
708
SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx, local_abspath,
709
FALSE, scratch_pool));
715
/* Else, if we aren't deleting this item, we'll have to look for
716
local text or property mods to determine if the path might be
718
else if (! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
720
/* Check for text mods on files. If EOL_PROP_CHANGED is TRUE,
721
then we need to force a translated byte-for-byte comparison
722
against the text-base so that a timestamp comparison won't
723
bail out early. Depending on how the svn:eol-style prop was
724
changed, we might have to send new text to the server to
725
match the new newline style. */
726
if (db_kind == svn_node_file)
727
SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx, local_abspath,
728
FALSE, scratch_pool));
731
/* Set text/prop modification flags accordingly. */
733
state_flags |= SVN_CLIENT_COMMIT_ITEM_TEXT_MODS;
735
state_flags |= SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
780
if (copy_mode_root || status->switched || node_rev != dir_rev)
782
state_flags |= (SVN_CLIENT_COMMIT_ITEM_ADD
783
| SVN_CLIENT_COMMIT_ITEM_IS_COPY);
787
/* Copy from original location */
788
cf_rev = original_rev;
789
cf_relpath = original_relpath;
793
/* Copy BASE location, to represent a mixed-rev or switch copy */
794
cf_rev = status->revision;
795
cf_relpath = status->repos_relpath;
800
if (!(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
801
|| (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
803
svn_boolean_t text_mod = FALSE;
804
svn_boolean_t prop_mod = FALSE;
806
if (status->kind == svn_node_file)
808
/* Check for text modifications on files */
809
if ((state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
810
&& ! (state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY))
812
text_mod = TRUE; /* Local added files are always modified */
815
text_mod = (status->text_status != svn_wc_status_normal);
818
prop_mod = (status->prop_status != svn_wc_status_normal
819
&& status->prop_status != svn_wc_status_none);
821
/* Set text/prop modification flags accordingly. */
823
state_flags |= SVN_CLIENT_COMMIT_ITEM_TEXT_MODS;
825
state_flags |= SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
737
828
/* If the entry has a lock token and it is already a commit candidate,
738
829
or the caller wants unmodified locked items to be treated as
739
830
such, note this fact. */
740
if (node_lock_token && lock_tokens && (state_flags || just_locked))
831
if (status->lock && baton->lock_tokens && (state_flags || just_locked))
742
833
state_flags |= SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN;
745
836
/* Now, if this is something to commit, add it to our list. */
837
if (matches_changelists
748
if (matches_changelists)
750
/* Finally, add the committable item. */
751
SVN_ERR(add_committable(committables, local_abspath, db_kind,
840
/* Finally, add the committable item. */
841
SVN_ERR(add_committable(committables, local_abspath,
846
: status->repos_relpath,
757
848
? SVN_INVALID_REVNUM
762
result_pool, scratch_pool));
763
if (state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
764
apr_hash_set(lock_tokens,
765
svn_path_url_add_component2(
766
repos_root_url, node_relpath,
767
apr_hash_pool_get(lock_tokens)),
769
apr_pstrdup(apr_hash_pool_get(lock_tokens),
854
baton->lock_tokens, status->lock,
855
result_pool, scratch_pool));
774
/* Fetch lock tokens for descendants of deleted nodes. */
776
&& (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
858
/* Fetch lock tokens for descendants of deleted BASE nodes. */
859
if (matches_changelists
860
&& (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
862
&& SVN_IS_VALID_REVNUM(node_rev) /* && BASE-kind = dir */
863
&& baton->lock_tokens)
778
865
apr_hash_t *local_relpath_tokens;
779
866
apr_hash_index_t *hi;
780
apr_pool_t *token_pool = apr_hash_pool_get(lock_tokens);
782
868
SVN_ERR(svn_wc__node_get_lock_tokens_recursive(
783
869
&local_relpath_tokens, wc_ctx, local_abspath,
784
token_pool, scratch_pool));
870
result_pool, scratch_pool));
786
872
/* Add tokens to existing hash. */
787
873
for (hi = apr_hash_first(scratch_pool, local_relpath_tokens);
827
926
if (parent_is_copy)
828
927
parent_abspath = copy_root_abspath;
830
if (!apr_hash_get(danglers, parent_abspath, APR_HASH_KEY_STRING))
929
if (!svn_hash_gets(danglers, parent_abspath))
832
apr_hash_set(danglers,
833
apr_pstrdup(result_pool, parent_abspath),
835
apr_pstrdup(result_pool, local_abspath));
931
svn_hash_sets(danglers, apr_pstrdup(result_pool, parent_abspath),
932
apr_pstrdup(result_pool, local_abspath));
840
if (db_kind != svn_node_dir || depth <= svn_depth_empty)
843
SVN_ERR(bail_on_tree_conflicted_children(wc_ctx, local_abspath,
844
db_kind, depth, changelists,
845
notify_func, notify_baton,
937
if (is_deleted && !is_added)
939
/* Skip all descendants */
940
if (status->kind == svn_node_dir)
941
baton->skip_below_abspath = apr_pstrdup(baton->result_pool,
848
946
/* Recursively handle each node according to depth, except when the
849
node is only being deleted. */
850
if ((! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
851
|| (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
947
node is only being deleted, or is in an added tree (as added trees
948
use the normal commit handling). */
949
if (copy_mode && !is_added && !is_deleted && status->kind == svn_node_dir)
853
const apr_array_header_t *children;
854
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
856
svn_depth_t depth_below_here = depth;
858
if (depth < svn_depth_infinity)
859
depth_below_here = svn_depth_empty; /* Stop recursing */
861
SVN_ERR(svn_wc__node_get_children_of_working_node(
862
&children, wc_ctx, local_abspath, copy_mode,
863
scratch_pool, iterpool));
864
for (i = 0; i < children->nelts; i++)
866
const char *this_abspath = APR_ARRAY_IDX(children, i, const char *);
867
const char *name = svn_dirent_basename(this_abspath, NULL);
868
const char *this_commit_relpath;
870
svn_pool_clear(iterpool);
872
if (commit_relpath == NULL)
873
this_commit_relpath = NULL;
875
this_commit_relpath = svn_relpath_join(commit_relpath, name,
878
SVN_ERR(harvest_committables(wc_ctx, this_abspath,
879
committables, lock_tokens,
882
FALSE, /* COPY_MODE_ROOT */
886
(depth < svn_depth_files),
887
(depth < svn_depth_immediates),
889
check_url_func, check_url_baton,
890
cancel_func, cancel_baton,
891
notify_func, notify_baton,
896
svn_pool_destroy(iterpool);
951
SVN_ERR(harvest_not_present_for_copy(wc_ctx, local_abspath, committables,
952
repos_root_url, commit_relpath,
953
baton->check_url_func,
954
baton->check_url_baton,
955
result_pool, scratch_pool));
899
958
return SVN_NO_ERROR;
1888
#ifdef SVN_CLIENT_COMMIT_DEBUG
1890
/*** Temporary test editor ***/
1896
const svn_delta_editor_t *real_editor;
1902
struct edit_baton *eb;
1908
static struct item_baton *
1909
make_baton(struct edit_baton *eb,
1914
struct item_baton *new_baton = apr_pcalloc(pool, sizeof(*new_baton));
1916
new_baton->real_baton = real_baton;
1917
new_baton->path = apr_pstrdup(pool, path);
1921
static svn_error_t *
1922
set_target_revision(void *edit_baton,
1923
svn_revnum_t target_revision,
1926
struct edit_baton *eb = edit_baton;
1927
return (*eb->real_editor->set_target_revision)(eb->real_eb,
1932
static svn_error_t *
1933
open_root(void *edit_baton,
1934
svn_revnum_t base_revision,
1935
apr_pool_t *dir_pool,
1938
struct edit_baton *eb = edit_baton;
1939
struct item_baton *new_baton = make_baton(eb, NULL, eb->path, dir_pool);
1940
fprintf(stderr, "TEST EDIT STARTED (base URL=%s)\n", eb->path);
1941
*root_baton = new_baton;
1942
return (*eb->real_editor->open_root)(eb->real_eb,
1945
&new_baton->real_baton);
1948
static svn_error_t *
1949
add_file(const char *path,
1951
const char *copyfrom_path,
1952
svn_revnum_t copyfrom_revision,
1956
struct item_baton *db = parent_baton;
1957
struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
1958
const char *copystuffs = "";
1959
if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
1960
copystuffs = apr_psprintf(pool,
1961
" (copied from %s:%ld)",
1964
fprintf(stderr, " Adding : %s%s\n", path, copystuffs);
1966
return (*db->eb->real_editor->add_file)(path, db->real_baton,
1967
copyfrom_path, copyfrom_revision,
1968
pool, &new_baton->real_baton);
1971
static svn_error_t *
1972
delete_entry(const char *path,
1973
svn_revnum_t revision,
1977
struct item_baton *db = parent_baton;
1978
fprintf(stderr, " Deleting: %s\n", path);
1979
return (*db->eb->real_editor->delete_entry)(path, revision,
1980
db->real_baton, pool);
1983
static svn_error_t *
1984
open_file(const char *path,
1986
svn_revnum_t base_revision,
1990
struct item_baton *db = parent_baton;
1991
struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
1992
fprintf(stderr, " Opening : %s\n", path);
1994
return (*db->eb->real_editor->open_file)(path, db->real_baton,
1995
base_revision, pool,
1996
&new_baton->real_baton);
1999
static svn_error_t *
2000
close_file(void *baton, const char *text_checksum, apr_pool_t *pool)
2002
struct item_baton *fb = baton;
2003
fprintf(stderr, " Closing : %s\n", fb->path);
2004
return (*fb->eb->real_editor->close_file)(fb->real_baton,
2005
text_checksum, pool);
2009
static svn_error_t *
2010
change_file_prop(void *file_baton,
2012
const svn_string_t *value,
2015
struct item_baton *fb = file_baton;
2016
fprintf(stderr, " PropSet (%s=%s)\n", name, value ? value->data : "");
2017
return (*fb->eb->real_editor->change_file_prop)(fb->real_baton,
2021
static svn_error_t *
2022
apply_textdelta(void *file_baton,
2023
const char *base_checksum,
2025
svn_txdelta_window_handler_t *handler,
2026
void **handler_baton)
2028
struct item_baton *fb = file_baton;
2029
fprintf(stderr, " Transmitting text...\n");
2030
return (*fb->eb->real_editor->apply_textdelta)(fb->real_baton,
2031
base_checksum, pool,
2032
handler, handler_baton);
2035
static svn_error_t *
2036
close_edit(void *edit_baton, apr_pool_t *pool)
2038
struct edit_baton *eb = edit_baton;
2039
fprintf(stderr, "TEST EDIT COMPLETED\n");
2040
return (*eb->real_editor->close_edit)(eb->real_eb, pool);
2043
static svn_error_t *
2044
add_directory(const char *path,
2046
const char *copyfrom_path,
2047
svn_revnum_t copyfrom_revision,
2051
struct item_baton *db = parent_baton;
2052
struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
2053
const char *copystuffs = "";
2054
if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
2055
copystuffs = apr_psprintf(pool,
2056
" (copied from %s:%ld)",
2059
fprintf(stderr, " Adding : %s%s\n", path, copystuffs);
2061
return (*db->eb->real_editor->add_directory)(path,
2066
&new_baton->real_baton);
2069
static svn_error_t *
2070
open_directory(const char *path,
2072
svn_revnum_t base_revision,
2076
struct item_baton *db = parent_baton;
2077
struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
2078
fprintf(stderr, " Opening : %s\n", path);
2080
return (*db->eb->real_editor->open_directory)(path, db->real_baton,
2081
base_revision, pool,
2082
&new_baton->real_baton);
2085
static svn_error_t *
2086
change_dir_prop(void *dir_baton,
2088
const svn_string_t *value,
2091
struct item_baton *db = dir_baton;
2092
fprintf(stderr, " PropSet (%s=%s)\n", name, value ? value->data : "");
2093
return (*db->eb->real_editor->change_dir_prop)(db->real_baton,
2097
static svn_error_t *
2098
close_directory(void *baton, apr_pool_t *pool)
2100
struct item_baton *db = baton;
2101
fprintf(stderr, " Closing : %s\n", db->path);
2102
return (*db->eb->real_editor->close_directory)(db->real_baton, pool);
2105
static svn_error_t *
2106
abort_edit(void *edit_baton, apr_pool_t *pool)
2108
struct edit_baton *eb = edit_baton;
2109
fprintf(stderr, "TEST EDIT ABORTED\n");
2110
return (*eb->real_editor->abort_edit)(eb->real_eb, pool);
2113
static svn_error_t *
2114
get_test_editor(const svn_delta_editor_t **editor,
2116
const svn_delta_editor_t *real_editor,
2118
const char *base_url,
2121
svn_delta_editor_t *ed = svn_delta_default_editor(pool);
2122
struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
2124
eb->path = apr_pstrdup(pool, base_url);
2125
eb->real_editor = real_editor;
2126
eb->real_eb = real_eb;
2128
/* We don't implement absent_file() or absent_directory() in this
2129
editor, because presumably commit would never send that. */
2130
ed->set_target_revision = set_target_revision;
2131
ed->open_root = open_root;
2132
ed->add_directory = add_directory;
2133
ed->open_directory = open_directory;
2134
ed->close_directory = close_directory;
2135
ed->add_file = add_file;
2136
ed->open_file = open_file;
2137
ed->close_file = close_file;
2138
ed->delete_entry = delete_entry;
2139
ed->apply_textdelta = apply_textdelta;
2140
ed->change_dir_prop = change_dir_prop;
2141
ed->change_file_prop = change_file_prop;
2142
ed->close_edit = close_edit;
2143
ed->abort_edit = abort_edit;
2147
return SVN_NO_ERROR;
2149
#endif /* SVN_CLIENT_COMMIT_DEBUG */
2152
1872
svn_client__get_log_msg(const char **log_msg,
2153
1873
const char **tmp_file,