diff options
| author | Peter Wemm <peter@FreeBSD.org> | 2015-10-12 08:54:49 +0000 | 
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 2015-10-12 08:54:49 +0000 | 
| commit | dc5d469d6574e9fb03bdd793658bb371315b306a (patch) | |
| tree | 013c2e6845398e5a9ca4901dcc077769c7520e1d /subversion/libsvn_client/commit.c | |
| parent | 58218291fa73a17020ef0447398e9e8a78f9e8c7 (diff) | |
Diffstat (limited to 'subversion/libsvn_client/commit.c')
| -rw-r--r-- | subversion/libsvn_client/commit.c | 266 | 
1 files changed, 104 insertions, 162 deletions
| diff --git a/subversion/libsvn_client/commit.c b/subversion/libsvn_client/commit.c index 07fdce19cdd0..4a945c887aa9 100644 --- a/subversion/libsvn_client/commit.c +++ b/subversion/libsvn_client/commit.c @@ -45,6 +45,7 @@  #include "client.h"  #include "private/svn_wc_private.h"  #include "private/svn_ra_private.h" +#include "private/svn_sorts_private.h"  #include "svn_private_config.h" @@ -110,7 +111,8 @@ get_ra_editor(const svn_delta_editor_t **editor,              continue;            svn_pool_clear(iterpool); -          SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, NULL, +          SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, +                                          NULL, NULL,                                            ctx->wc_ctx, item->path, FALSE, pool,                                            iterpool));            if (relpath) @@ -203,8 +205,8 @@ collect_lock_tokens(apr_hash_t **result,    for (hi = apr_hash_first(pool, all_tokens); hi; hi = apr_hash_next(hi))      { -      const char *url = svn__apr_hash_index_key(hi); -      const char *token = svn__apr_hash_index_val(hi); +      const char *url = apr_hash_this_key(hi); +      const char *token = apr_hash_this_val(hi);        const char *relpath = svn_uri_skip_ancestor(base_url, url, pool);        if (relpath) @@ -238,91 +240,30 @@ post_process_commit_item(svn_wc_committed_queue_t *queue,      loop_recurse = TRUE;    remove_lock = (! keep_locks && (item->state_flags -                                       & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)); +                                       & (SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN +                                          | SVN_CLIENT_COMMIT_ITEM_ADD +                                          | SVN_CLIENT_COMMIT_ITEM_DELETE))); -  /* When the node was deleted (or replaced), we need to always remove the  -     locks, as they're invalidated on the server. We cannot honor the  +  /* When the node was deleted (or replaced), we need to always remove the +     locks, as they're invalidated on the server. We cannot honor the       SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN flag here because it does not tell       us whether we have locked children. */    if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)      remove_lock = TRUE; -  return svn_wc_queue_committed3(queue, wc_ctx, item->path, -                                 loop_recurse, item->incoming_prop_changes, +  return svn_error_trace( +         svn_wc_queue_committed4(queue, wc_ctx, item->path, +                                 loop_recurse, +                                 0 != (item->state_flags & +                                       (SVN_CLIENT_COMMIT_ITEM_ADD +                                        | SVN_CLIENT_COMMIT_ITEM_DELETE +                                        | SVN_CLIENT_COMMIT_ITEM_TEXT_MODS +                                        | SVN_CLIENT_COMMIT_ITEM_PROP_MODS)), +                                 item->incoming_prop_changes,                                   remove_lock, !keep_changelists, -                                 sha1_checksum, scratch_pool); -} - - -static svn_error_t * -check_nonrecursive_dir_delete(svn_wc_context_t *wc_ctx, -                              const char *target_abspath, -                              svn_depth_t depth, -                              apr_pool_t *scratch_pool) -{ -  svn_node_kind_t kind; - -  SVN_ERR_ASSERT(depth != svn_depth_infinity); - -  SVN_ERR(svn_wc_read_kind2(&kind, wc_ctx, target_abspath, -                            TRUE, FALSE, scratch_pool)); - - -  /* ### TODO(sd): This check is slightly too strict.  It should be -     ### possible to: -     ### -     ###   * delete a directory containing only files when -     ###     depth==svn_depth_files; -     ### -     ###   * delete a directory containing only files and empty -     ###     subdirs when depth==svn_depth_immediates. -     ### -     ### But for now, we insist on svn_depth_infinity if you're -     ### going to delete a directory, because we're lazy and -     ### trying to get depthy commits working in the first place. -     ### -     ### This would be fairly easy to fix, though: just, well, -     ### check the above conditions! -     ### -     ### GJS: I think there may be some confusion here. there is -     ###      the depth of the commit, and the depth of a checked-out -     ###      directory in the working copy. Delete, by its nature, will -     ###      always delete all of its children, so it seems a bit -     ###      strange to worry about what is in the working copy. -  */ -  if (kind == svn_node_dir) -    { -      svn_wc_schedule_t schedule; - -      /* ### Looking at schedule is probably enough, no need for -         pristine compare etc. */ -      SVN_ERR(svn_wc__node_get_schedule(&schedule, NULL, -                                        wc_ctx, target_abspath, -                                        scratch_pool)); - -      if (schedule == svn_wc_schedule_delete -          || schedule == svn_wc_schedule_replace) -        { -          const apr_array_header_t *children; - -          SVN_ERR(svn_wc__node_get_children(&children, wc_ctx, -                                            target_abspath, TRUE, -                                            scratch_pool, scratch_pool)); - -          if (children->nelts > 0) -            return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, -                                     _("Cannot delete the directory '%s' " -                                       "in a non-recursive commit " -                                       "because it has children"), -                                     svn_dirent_local_style(target_abspath, -                                                            scratch_pool)); -        } -    } - -  return SVN_NO_ERROR; +                                 sha1_checksum, scratch_pool));  } -  /* Given a list of committables described by their common base abspath     BASE_ABSPATH and a list of relative dirents TARGET_RELPATHS determine     which absolute paths must be locked to commit all these targets and @@ -393,8 +334,8 @@ determine_lock_targets(apr_array_header_t **lock_targets,         hi = apr_hash_next(hi))      {        const char *common; -      const char *wcroot_abspath = svn__apr_hash_index_key(hi); -      apr_array_header_t *wc_targets = svn__apr_hash_index_val(hi); +      const char *wcroot_abspath = apr_hash_this_key(hi); +      apr_array_header_t *wc_targets = apr_hash_this_val(hi);        svn_pool_clear(iterpool); @@ -420,8 +361,7 @@ determine_lock_targets(apr_array_header_t **lock_targets,            SVN_ERR(svn_dirent_condense_targets(&common, &wc_targets, wc_targets,                                                FALSE, iterpool, iterpool)); -          qsort(wc_targets->elts, wc_targets->nelts, wc_targets->elt_size, -                svn_sort_compare_paths); +          svn_sort__array(wc_targets, svn_sort_compare_paths);            if (wc_targets->nelts == 0                || !svn_path_is_empty(APR_ARRAY_IDX(wc_targets, 0, const char*)) @@ -599,6 +539,7 @@ svn_client_commit6(const apr_array_header_t *targets,    const char *current_abspath;    const char *notify_prefix;    int depth_empty_after = -1; +  apr_hash_t *move_youngest = NULL;    int i;    SVN_ERR_ASSERT(depth != svn_depth_unknown && depth != svn_depth_exclude); @@ -673,26 +614,6 @@ svn_client_commit6(const apr_array_header_t *targets,                                                    base_abspath,                                                    pool); -  /* If a non-recursive commit is desired, do not allow a deleted directory -     as one of the targets. */ -  if (depth != svn_depth_infinity && ! commit_as_operations) -    for (i = 0; i < rel_targets->nelts; i++) -      { -        const char *relpath = APR_ARRAY_IDX(rel_targets, i, const char *); -        const char *target_abspath; - -        svn_pool_clear(iterpool); - -        target_abspath = svn_dirent_join(base_abspath, relpath, iterpool); - -        cmt_err = svn_error_trace( -          check_nonrecursive_dir_delete(ctx->wc_ctx, target_abspath, -                                        depth, iterpool)); - -        if (cmt_err) -          goto cleanup; -      } -    /* Crawl the working copy for commit items. */    {      struct check_url_kind_baton cukb; @@ -741,7 +662,7 @@ svn_client_commit6(const apr_array_header_t *targets,      apr_hash_index_t *hi = apr_hash_first(iterpool,                                            committables->by_repository); -    commit_items = svn__apr_hash_index_val(hi); +    commit_items = apr_hash_this_val(hi);    }    /* If our array of targets contains only locks (and no actual file @@ -789,62 +710,12 @@ svn_client_commit6(const apr_array_header_t *targets,            if (cmt_err)              goto cleanup; -          if (moved_from_abspath && delete_op_root_abspath && -              strcmp(moved_from_abspath, delete_op_root_abspath) == 0) - +          if (moved_from_abspath && delete_op_root_abspath)              { -              svn_boolean_t found_delete_half = -                (svn_hash_gets(committables->by_path, delete_op_root_abspath) -                 != NULL); - -              if (!found_delete_half) -                { -                  const char *delete_half_parent_abspath; - -                  /* The delete-half isn't in the commit target list. -                   * However, it might itself be the child of a deleted node, -                   * either because of another move or a deletion. -                   * -                   * For example, consider: mv A/B B; mv B/C C; commit; -                   * C's moved-from A/B/C is a child of the deleted A/B. -                   * A/B/C does not appear in the commit target list, but -                   * A/B does appear. -                   * (Note that moved-from information is always stored -                   * relative to the BASE tree, so we have 'C moved-from -                   * A/B/C', not 'C moved-from B/C'.) -                   * -                   * An example involving a move and a delete would be: -                   * mv A/B C; rm A; commit; -                   * Now C is moved-from A/B which does not appear in the -                   * commit target list, but A does appear. -                   */ - -                  /* Scan upwards for a deletion op-root from the -                   * delete-half's parent directory. */ -                  delete_half_parent_abspath = -                    svn_dirent_dirname(delete_op_root_abspath, iterpool); -                  if (strcmp(delete_op_root_abspath, -                             delete_half_parent_abspath) != 0) -                    { -                      const char *parent_delete_op_root_abspath; - -                      cmt_err = svn_error_trace( -                                  svn_wc__node_get_deleted_ancestor( -                                    &parent_delete_op_root_abspath, -                                    ctx->wc_ctx, delete_half_parent_abspath, -                                    iterpool, iterpool)); -                      if (cmt_err) -                        goto cleanup; - -                      if (parent_delete_op_root_abspath) -                        found_delete_half = -                          (svn_hash_gets(committables->by_path, -                                         parent_delete_op_root_abspath) -                           != NULL); -                    } -                } +              svn_client_commit_item3_t *delete_half = +                svn_hash_gets(committables->by_path, delete_op_root_abspath); -              if (!found_delete_half) +              if (!delete_half)                  {                    cmt_err = svn_error_createf(                                SVN_ERR_ILLEGAL_TARGET, NULL, @@ -854,8 +725,32 @@ svn_client_commit6(const apr_array_header_t *targets,                                svn_dirent_local_style(item->path, iterpool),                                svn_dirent_local_style(delete_op_root_abspath,                                                       iterpool)); + +                  if (ctx->notify_func2) +                    { +                      svn_wc_notify_t *notify; +                      notify = svn_wc_create_notify( +                                    delete_op_root_abspath, +                                    svn_wc_notify_failed_requires_target, +                                    iterpool); +                      notify->err = cmt_err; + +                      ctx->notify_func2(ctx->notify_baton2, notify, iterpool); +                    } +                    goto cleanup;                  } +              else if (delete_half->revision == item->copyfrom_rev) +                { +                  /* Ok, now we know that we perform an out-of-date check +                     on the copyfrom location. Remember this for a fixup +                     round right before committing. */ + +                  if (!move_youngest) +                    move_youngest = apr_hash_make(pool); + +                  svn_hash_sets(move_youngest, item->path, item); +                }              }          } @@ -885,6 +780,19 @@ svn_client_commit6(const apr_array_header_t *targets,                           svn_dirent_local_style(item->path, iterpool),                           svn_dirent_local_style(copy_op_root_abspath,                                                  iterpool)); + +              if (ctx->notify_func2) +                { +                    svn_wc_notify_t *notify; +                    notify = svn_wc_create_notify( +                                copy_op_root_abspath, +                                svn_wc_notify_failed_requires_target, +                                iterpool); +                    notify->err = cmt_err; + +                    ctx->notify_func2(ctx->notify_baton2, notify, iterpool); +                } +                goto cleanup;              }          } @@ -941,6 +849,37 @@ svn_client_commit6(const apr_array_header_t *targets,    if (cmt_err)      goto cleanup; +  if (move_youngest != NULL) +    { +      apr_hash_index_t *hi; +      svn_revnum_t youngest; + +      SVN_ERR(svn_ra_get_latest_revnum(ra_session, &youngest, pool)); + +      for (hi = apr_hash_first(iterpool, move_youngest); +           hi; +           hi = apr_hash_next(hi)) +        { +          svn_client_commit_item3_t *item = apr_hash_this_val(hi); + +          /* We delete the original side with its original revision and will +             receive an out-of-date error if that node changed since that +             revision. + +             The copy is of that same revision and we know that this revision +             didn't change between this revision and youngest. So we can just +             as well commit a copy from youngest. + +            Note that it is still possible to see gaps between the delete and +            copy revisions as the repository might handle multiple commits +            at the same time (or when an out of date proxy is involved), but +            in general it should decrease the number of gaps. */ + +          if (item->copyfrom_rev < youngest) +            item->copyfrom_rev = youngest; +        } +    } +    cmt_err = svn_error_trace(                get_ra_editor(&editor, &edit_baton, ra_session, ctx,                              log_msg, commit_items, revprop_table, @@ -996,6 +935,9 @@ svn_client_commit6(const apr_array_header_t *targets,                     commit_info->author,                     ctx->cancel_func, ctx->cancel_baton,                     iterpool); + +      if (bump_err) +        goto cleanup;      }   cleanup: @@ -1004,16 +946,16 @@ svn_client_commit6(const apr_array_header_t *targets,       working copies. */    if (timestamp_sleep)      { -      const char *wcroot_abspath; -      svn_error_t *err = svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx, +      const char *sleep_abspath; +      svn_error_t *err = svn_wc__get_wcroot(&sleep_abspath, ctx->wc_ctx,                                              base_abspath, pool, pool);        if (err)          {            svn_error_clear(err); -          wcroot_abspath = NULL; +          sleep_abspath = base_abspath;          } -      svn_io_sleep_for_timestamps(wcroot_abspath, pool); +      svn_io_sleep_for_timestamps(sleep_abspath, pool);      }    /* Abort the commit if it is still in progress. */ | 
