Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 74DF592FC for ; Wed, 16 May 2012 20:33:37 +0000 (UTC) Received: (qmail 24273 invoked by uid 500); 16 May 2012 20:33:37 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 24243 invoked by uid 500); 16 May 2012 20:33:37 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 24232 invoked by uid 99); 16 May 2012 20:33:37 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 20:33:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 20:33:34 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 71AD22388C1C; Wed, 16 May 2012 20:33:14 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1339349 [5/37] - in /subversion/branches/fix-rdump-editor: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/ notes/ notes/api-errata... Date: Wed, 16 May 2012 20:32:54 -0000 To: commits@subversion.apache.org From: hwright@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120516203314.71AD22388C1C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_client/commit.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_client/commit.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_client/commit.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_client/commit.c Wed May 16 20:32:43 2012 @@ -49,6 +49,7 @@ #include "client.h" #include "private/svn_wc_private.h" +#include "private/svn_subr_private.h" #include "private/svn_ra_private.h" #include "private/svn_magic.h" @@ -77,7 +78,7 @@ typedef struct import_ctx_t } import_ctx_t; -/* Apply PATH's contents (as a delta against the empty string) to +/* Apply LOCAL_ABSPATH's contents (as a delta against the empty string) to FILE_BATON in EDITOR. Use POOL for any temporary allocation. PROPERTIES is the set of node properties set on this file. @@ -87,7 +88,7 @@ typedef struct import_ctx_t /* ### how does this compare against svn_wc_transmit_text_deltas2() ??? */ static svn_error_t * -send_file_contents(const char *path, +send_file_contents(const char *local_abspath, void *file_baton, const svn_delta_editor_t *editor, apr_hash_t *properties, @@ -135,12 +136,13 @@ send_file_contents(const char *path, if (special) { - SVN_ERR(svn_subst_read_specialfile(&contents, path, pool, pool)); + SVN_ERR(svn_subst_read_specialfile(&contents, local_abspath, + pool, pool)); } else { /* Open the working copy file. */ - SVN_ERR(svn_stream_open_readonly(&contents, path, pool, pool)); + SVN_ERR(svn_stream_open_readonly(&contents, local_abspath, pool, pool)); /* If we have EOL styles or keywords, then detranslate the file. */ if (svn_subst_translation_required(eol_style, eol, keywords, @@ -150,7 +152,9 @@ send_file_contents(const char *path, return svn_error_createf(SVN_ERR_IO_UNKNOWN_EOL, NULL, _("%s property on '%s' contains " "unrecognized EOL-style '%s'"), - SVN_PROP_EOL_STYLE, path, + SVN_PROP_EOL_STYLE, + svn_dirent_local_style(local_abspath, + pool), eol_style_val->data); /* We're importing, so translate files with 'native' eol-style to @@ -189,8 +193,9 @@ send_file_contents(const char *path, static svn_error_t * import_file(const svn_delta_editor_t *editor, void *dir_baton, - const char *path, + const char *local_abspath, const char *edit_path, + const svn_io_dirent2_t *dirent, import_ctx_t *import_ctx, svn_client_ctx_t *ctx, apr_pool_t *pool) @@ -201,12 +206,8 @@ import_file(const svn_delta_editor_t *ed const char *text_checksum; apr_hash_t* properties; apr_hash_index_t *hi; - svn_node_kind_t kind; - svn_boolean_t is_special; - - SVN_ERR(svn_path_check_valid(path, pool)); - SVN_ERR(svn_io_check_special_path(path, &kind, &is_special, pool)); + SVN_ERR(svn_path_check_valid(local_abspath, pool)); /* Add the file, using the pool from the FILES hash. */ SVN_ERR(editor->add_file(edit_path, dir_baton, NULL, SVN_INVALID_REVNUM, @@ -215,10 +216,10 @@ import_file(const svn_delta_editor_t *ed /* Remember that the repository was modified */ import_ctx->repos_changed = TRUE; - if (! is_special) + if (! dirent->special) { /* add automatic properties */ - SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path, + SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, local_abspath, import_ctx->magic_cookie, ctx, pool)); } @@ -239,7 +240,8 @@ import_file(const svn_delta_editor_t *ed if (ctx->notify_func2) { svn_wc_notify_t *notify - = svn_wc_create_notify(path, svn_wc_notify_commit_added, pool); + = svn_wc_create_notify(local_abspath, svn_wc_notify_commit_added, + pool); notify->kind = svn_node_file; notify->mime_type = mimetype; notify->content_state = notify->prop_state @@ -251,7 +253,7 @@ import_file(const svn_delta_editor_t *ed /* If this is a special file, we need to set the svn:special property and create a temporary detranslated version in order to send to the server. */ - if (is_special) + if (dirent->special) { apr_hash_set(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING, svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool)); @@ -263,75 +265,53 @@ import_file(const svn_delta_editor_t *ed } /* Now, transmit the file contents. */ - SVN_ERR(send_file_contents(path, file_baton, editor, + SVN_ERR(send_file_contents(local_abspath, file_baton, editor, properties, digest, pool)); /* Finally, close the file. */ text_checksum = - svn_checksum_to_cstring(svn_checksum__from_digest(digest, svn_checksum_md5, - pool), pool); + svn_checksum_to_cstring(svn_checksum__from_digest_md5(digest, pool), pool); return editor->close_file(file_baton, text_checksum, pool); } -/* Import directory PATH into the repository directory indicated by - * DIR_BATON in EDITOR. EDIT_PATH is the path imported as the root - * directory, so all edits are relative to that. - * - * DEPTH is the depth at this point in the descent (it may be changed - * for recursive calls). - * - * Accumulate file paths and their batons in FILES, which must be - * non-null. (These are used to send postfix textdeltas later). - * - * EXCLUDES is a hash whose keys are absolute paths to exclude from - * the import (values are unused). +/* Return in CHILDREN a mapping of basenames to dirents for the importable + * children of DIR_ABSPATH. EXCLUDES is a hash of absolute paths to filter + * out. IGNORES, if non-NULL, is a list of basenames to filter out. + * FILTER_CALLBACK and FILTER_BATON will be called for each absolute path, + * allowing users to further filter the list of returned entries. * - * If NO_IGNORE is FALSE, don't import files or directories that match - * ignore patterns. - * - * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each - * directory. - * - * Use POOL for any temporary allocation. */ + * Results are returned in RESULT_POOL; use SCRATCH_POOL for temporary data.*/ static svn_error_t * -import_dir(const svn_delta_editor_t *editor, - void *dir_baton, - const char *path, - const char *edit_path, - svn_depth_t depth, - apr_hash_t *excludes, - svn_boolean_t no_ignore, - svn_boolean_t ignore_unknown_node_types, - import_ctx_t *import_ctx, - svn_client_ctx_t *ctx, - apr_pool_t *pool) +get_filtered_children(apr_hash_t **children, + const char *dir_abspath, + apr_hash_t *excludes, + apr_array_header_t *ignores, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - apr_pool_t *subpool = svn_pool_create(pool); /* iteration pool */ apr_hash_t *dirents; apr_hash_index_t *hi; - apr_array_header_t *ignores; - - SVN_ERR(svn_path_check_valid(path, pool)); - - if (!no_ignore) - SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); + apr_pool_t *iterpool = svn_pool_create(scratch_pool); - SVN_ERR(svn_io_get_dirents3(&dirents, path, TRUE, pool, pool)); + SVN_ERR(svn_io_get_dirents3(&dirents, dir_abspath, TRUE, result_pool, + scratch_pool)); - for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi)) + for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi)) { - const char *this_path, *this_edit_path, *abs_path; - const char *filename = svn__apr_hash_index_key(hi); - const svn_io_dirent_t *dirent = svn__apr_hash_index_val(hi); + const char *base_name = svn__apr_hash_index_key(hi); + const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi); + const char *local_abspath; - svn_pool_clear(subpool); + svn_pool_clear(iterpool); - if (ctx->cancel_func) - SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + local_abspath = svn_dirent_join(dir_abspath, base_name, iterpool); - if (svn_wc_is_adm_dir(filename, subpool)) + if (svn_wc_is_adm_dir(base_name, iterpool)) { /* If someone's trying to import a directory named the same as our administrative directories, that's probably not @@ -342,82 +322,125 @@ import_dir(const svn_delta_editor_t *edi if (ctx->notify_func2) { svn_wc_notify_t *notify - = svn_wc_create_notify(svn_dirent_join(path, filename, - subpool), - svn_wc_notify_skip, subpool); + = svn_wc_create_notify(svn_dirent_join(local_abspath, base_name, + iterpool), + svn_wc_notify_skip, iterpool); notify->kind = svn_node_dir; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; - (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool); + (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool); } + + apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL); + continue; + } + /* If this is an excluded path, exclude it. */ + if (apr_hash_get(excludes, local_abspath, APR_HASH_KEY_STRING)) + { + apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL); continue; } - /* Typically, we started importing from ".", in which case - edit_path is "". So below, this_path might become "./blah", - and this_edit_path might become "blah", for example. */ - this_path = svn_dirent_join(path, filename, subpool); - this_edit_path = svn_relpath_join(edit_path, filename, subpool); - - /* If this is an excluded path, exclude it. */ - SVN_ERR(svn_dirent_get_absolute(&abs_path, this_path, subpool)); - if (apr_hash_get(excludes, abs_path, APR_HASH_KEY_STRING)) - continue; - - if ((!no_ignore) && svn_wc_match_ignore_list(filename, ignores, - subpool)) - continue; - - if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates) + if (ignores && svn_wc_match_ignore_list(base_name, ignores, iterpool)) { - void *this_dir_baton; + apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL); + continue; + } - /* Add the new subdirectory, getting a descent baton from - the editor. */ - SVN_ERR(editor->add_directory(this_edit_path, dir_baton, - NULL, SVN_INVALID_REVNUM, subpool, - &this_dir_baton)); + if (filter_callback) + { + svn_boolean_t filter = FALSE; - /* Remember that the repository was modified */ - import_ctx->repos_changed = TRUE; + SVN_ERR(filter_callback(filter_baton, &filter, local_abspath, + dirent, iterpool)); - /* By notifying before the recursive call below, we display - a directory add before displaying adds underneath the - directory. To do it the other way around, just move this - after the recursive call. */ - if (ctx->notify_func2) + if (filter) { - svn_wc_notify_t *notify - = svn_wc_create_notify(this_path, svn_wc_notify_commit_added, - subpool); - notify->kind = svn_node_dir; - notify->content_state = notify->prop_state - = svn_wc_notify_state_inapplicable; - notify->lock_state = svn_wc_notify_lock_state_inapplicable; - (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool); + apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL); + continue; } + } + } + svn_pool_destroy(iterpool); + + *children = dirents; + return SVN_NO_ERROR; +} + +static svn_error_t * +import_dir(const svn_delta_editor_t *editor, + void *dir_baton, + const char *local_abspath, + const char *edit_path, + svn_depth_t depth, + apr_hash_t *excludes, + svn_boolean_t no_ignore, + svn_boolean_t ignore_unknown_node_types, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, + import_ctx_t *import_ctx, + svn_client_ctx_t *ctx, + apr_pool_t *pool); - /* Recurse. */ - { - svn_depth_t depth_below_here = depth; - if (depth == svn_depth_immediates) - depth_below_here = svn_depth_empty; - - SVN_ERR(import_dir(editor, this_dir_baton, this_path, - this_edit_path, depth_below_here, excludes, - no_ignore, ignore_unknown_node_types, - import_ctx, ctx, - subpool)); - } - /* Finally, close the sub-directory. */ - SVN_ERR(editor->close_directory(this_dir_baton, subpool)); +/* Import the children of DIR_ABSPATH, with other arguments similar to + * import_dir(). */ +static svn_error_t * +import_children(const char *dir_abspath, + const char *edit_path, + apr_hash_t *dirents, + const svn_delta_editor_t *editor, + void *dir_baton, + svn_depth_t depth, + apr_hash_t *excludes, + svn_boolean_t no_ignore, + svn_boolean_t ignore_unknown_node_types, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, + import_ctx_t *import_ctx, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + apr_hash_index_t *hi; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi)) + { + const char *this_abspath, *this_edit_path; + const char *filename = svn__apr_hash_index_key(hi); + const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi); + + svn_pool_clear(iterpool); + + if (ctx->cancel_func) + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + + /* Typically, we started importing from ".", in which case + edit_path is "". So below, this_path might become "./blah", + and this_edit_path might become "blah", for example. */ + this_abspath = svn_dirent_join(dir_abspath, filename, iterpool); + this_edit_path = svn_relpath_join(edit_path, filename, iterpool); + + if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates) + { + /* Recurse. */ + svn_depth_t depth_below_here = depth; + if (depth == svn_depth_immediates) + depth_below_here = svn_depth_empty; + + SVN_ERR(import_dir(editor, dir_baton, this_abspath, + this_edit_path, depth_below_here, excludes, + no_ignore, ignore_unknown_node_types, + filter_callback, filter_baton, + import_ctx, ctx, + iterpool)); } else if (dirent->kind == svn_node_file && depth >= svn_depth_files) { - SVN_ERR(import_file(editor, dir_baton, this_path, - this_edit_path, import_ctx, ctx, subpool)); + SVN_ERR(import_file(editor, dir_baton, this_abspath, + this_edit_path, dirent, + import_ctx, ctx, iterpool)); } else if (dirent->kind != svn_node_dir && dirent->kind != svn_node_file) { @@ -427,24 +450,115 @@ import_dir(const svn_delta_editor_t *edi if (ctx->notify_func2) { svn_wc_notify_t *notify - = svn_wc_create_notify(this_path, - svn_wc_notify_skip, subpool); + = svn_wc_create_notify(this_abspath, + svn_wc_notify_skip, iterpool); notify->kind = svn_node_dir; notify->content_state = notify->prop_state = svn_wc_notify_state_inapplicable; notify->lock_state = svn_wc_notify_lock_state_inapplicable; - (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool); + (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool); } } else return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown or unversionable type for '%s'"), - svn_dirent_local_style(this_path, subpool)); + svn_dirent_local_style(this_abspath, iterpool)); } } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); + return SVN_NO_ERROR; +} + + +/* Import directory LOCAL_ABSPATH into the repository directory indicated by + * DIR_BATON in EDITOR. EDIT_PATH is the path imported as the root + * directory, so all edits are relative to that. + * + * DEPTH is the depth at this point in the descent (it may be changed + * for recursive calls). + * + * Accumulate file paths and their batons in FILES, which must be + * non-null. (These are used to send postfix textdeltas later). + * + * EXCLUDES is a hash whose keys are absolute paths to exclude from + * the import (values are unused). + * + * If NO_IGNORE is FALSE, don't import files or directories that match + * ignore patterns. + * + * If FILTER_CALLBACK is not NULL, call it with FILTER_BATON on each to be + * imported node below LOCAL_ABSPATH to allow filtering nodes. + * + * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each + * directory. + * + * Use POOL for any temporary allocation. */ +static svn_error_t * +import_dir(const svn_delta_editor_t *editor, + void *dir_baton, + const char *local_abspath, + const char *edit_path, + svn_depth_t depth, + apr_hash_t *excludes, + svn_boolean_t no_ignore, + svn_boolean_t ignore_unknown_node_types, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, + import_ctx_t *import_ctx, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + apr_hash_t *dirents; + apr_array_header_t *ignores = NULL; + void *this_dir_baton; + + SVN_ERR(svn_path_check_valid(local_abspath, pool)); + + if (!no_ignore) + SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); + + SVN_ERR(get_filtered_children(&dirents, local_abspath, excludes, ignores, + filter_callback, filter_baton, ctx, + pool, pool)); + + /* Import this directory, but not yet its children. */ + { + /* Add the new subdirectory, getting a descent baton from the editor. */ + SVN_ERR(editor->add_directory(edit_path, dir_baton, NULL, + SVN_INVALID_REVNUM, pool, &this_dir_baton)); + + /* Remember that the repository was modified */ + import_ctx->repos_changed = TRUE; + + /* By notifying before the recursive call below, we display + a directory add before displaying adds underneath the + directory. To do it the other way around, just move this + after the recursive call. */ + if (ctx->notify_func2) + { + svn_wc_notify_t *notify + = svn_wc_create_notify(local_abspath, svn_wc_notify_commit_added, + pool); + notify->kind = svn_node_dir; + notify->content_state = notify->prop_state + = svn_wc_notify_state_inapplicable; + notify->lock_state = svn_wc_notify_lock_state_inapplicable; + (*ctx->notify_func2)(ctx->notify_baton2, notify, pool); + } + } + + /* Now import the children recursively. */ + SVN_ERR(import_children(local_abspath, edit_path, dirents, editor, + this_dir_baton, depth, excludes, no_ignore, + ignore_unknown_node_types, + filter_callback, filter_baton, + import_ctx, ctx, pool)); + + /* Finally, close the sub-directory. */ + SVN_ERR(editor->close_directory(this_dir_baton, pool)); + return SVN_NO_ERROR; } @@ -485,7 +599,7 @@ import_dir(const svn_delta_editor_t *edi * not necessarily the root.) */ static svn_error_t * -import(const char *path, +import(const char *local_abspath, const apr_array_header_t *new_entries, const svn_delta_editor_t *editor, void *edit_baton, @@ -493,15 +607,17 @@ import(const char *path, apr_hash_t *excludes, svn_boolean_t no_ignore, svn_boolean_t ignore_unknown_node_types, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, svn_client_ctx_t *ctx, apr_pool_t *pool) { void *root_baton; - svn_node_kind_t kind; - apr_array_header_t *ignores; + apr_array_header_t *ignores = NULL; apr_array_header_t *batons = NULL; const char *edit_path = ""; import_ctx_t *import_ctx = apr_pcalloc(pool, sizeof(*import_ctx)); + const svn_io_dirent2_t *dirent; svn_magic__init(&import_ctx->magic_cookie, pool); @@ -512,7 +628,7 @@ import(const char *path, pool, &root_baton)); /* Import a file or a directory tree. */ - SVN_ERR(svn_io_check_path(path, &kind, pool)); + SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, FALSE, pool, pool)); /* Make the intermediate directory components necessary for properly rooting our import source tree. */ @@ -529,7 +645,7 @@ import(const char *path, /* If this is the last path component, and we're importing a file, then this component is the name of the file, not an intermediate directory. */ - if ((i == new_entries->nelts - 1) && (kind == svn_node_file)) + if ((i == new_entries->nelts - 1) && (dirent->kind == svn_node_file)) break; APR_ARRAY_PUSH(batons, void *) = root_baton; @@ -542,7 +658,7 @@ import(const char *path, import_ctx->repos_changed = TRUE; } } - else if (kind == svn_node_file) + else if (dirent->kind == svn_node_file) { return svn_error_create (SVN_ERR_NODE_UNKNOWN_KIND, NULL, @@ -557,32 +673,46 @@ import(const char *path, if something underneath it also has our reserved name, then we'll error. */ - if (kind == svn_node_file) + if (dirent->kind == svn_node_file) { + /* This code path ignores EXCLUDES and FILTER, but they don't make + much sense for a single file import anyway. */ svn_boolean_t ignores_match = FALSE; if (!no_ignore) { SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); - ignores_match = svn_wc_match_ignore_list(path, ignores, pool); + ignores_match = svn_wc_match_ignore_list(local_abspath, + ignores, pool); } if (!ignores_match) - SVN_ERR(import_file(editor, root_baton, path, edit_path, - import_ctx, ctx, pool)); + SVN_ERR(import_file(editor, root_baton, local_abspath, edit_path, + dirent, import_ctx, ctx, pool)); } - else if (kind == svn_node_dir) + else if (dirent->kind == svn_node_dir) { - SVN_ERR(import_dir(editor, root_baton, path, edit_path, - depth, excludes, no_ignore, - ignore_unknown_node_types, import_ctx, ctx, pool)); + apr_hash_t *dirents; + + if (!no_ignore) + SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool)); + + SVN_ERR(get_filtered_children(&dirents, local_abspath, excludes, ignores, + filter_callback, filter_baton, ctx, + pool, pool)); + + SVN_ERR(import_children(local_abspath, edit_path, dirents, editor, + root_baton, depth, excludes, no_ignore, + ignore_unknown_node_types, + filter_callback, filter_baton, + import_ctx, ctx, pool)); } - else if (kind == svn_node_none - || kind == svn_node_unknown) + else if (dirent->kind == svn_node_none + || dirent->kind == svn_node_unknown) { return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("'%s' does not exist"), - svn_dirent_local_style(path, pool)); + svn_dirent_local_style(local_abspath, pool)); } /* Close up shop; it's time to go home. */ @@ -629,16 +759,13 @@ capture_commit_info(const svn_commit_inf static svn_error_t * -get_ra_editor(svn_ra_session_t **ra_session, - const svn_delta_editor_t **editor, +get_ra_editor(const svn_delta_editor_t **editor, void **edit_baton, + svn_ra_session_t *ra_session, svn_client_ctx_t *ctx, - const char *base_url, - const char *base_dir_abspath, const char *log_msg, const apr_array_header_t *commit_items, const apr_hash_t *revprop_table, - svn_boolean_t is_commit, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, svn_commit_callback2_t commit_callback, @@ -646,54 +773,43 @@ get_ra_editor(svn_ra_session_t **ra_sess apr_pool_t *pool) { apr_hash_t *commit_revprops; - const char *anchor_abspath; - - /* Open an RA session to URL. */ - SVN_ERR(svn_client__open_ra_session_internal(ra_session, NULL, base_url, - base_dir_abspath, commit_items, - is_commit, !is_commit, - ctx, pool)); - - /* If this is an import (aka, not a commit), we need to verify that - our repository URL exists. */ - if (! is_commit) - { - svn_node_kind_t kind; - - SVN_ERR(svn_ra_check_path(*ra_session, "", SVN_INVALID_REVNUM, - &kind, pool)); - if (kind == svn_node_none) - return svn_error_createf(SVN_ERR_FS_NO_SUCH_ENTRY, NULL, - _("Path '%s' does not exist"), - base_url); - } + apr_hash_t *relpath_map = NULL; SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, log_msg, ctx, pool)); -#ifdef ENABLE_EDITOR_SHIMS - /* We need this for the shims. */ - if (base_dir_abspath) +#ifdef ENABLE_EV2_SHIMS + if (commit_items) { - const char *relpath; - const char *wcroot_abspath; + int i; + apr_pool_t *iterpool = svn_pool_create(pool); - SVN_ERR(svn_wc__get_wc_root(&wcroot_abspath, ctx->wc_ctx, - base_dir_abspath, pool, pool)); + relpath_map = apr_hash_make(pool); + for (i = 0; i < commit_items->nelts; i++) + { + svn_client_commit_item3_t *item = APR_ARRAY_IDX(commit_items, i, + svn_client_commit_item3_t *); + const char *relpath; + + if (!item->path) + continue; - SVN_ERR(svn_ra_get_path_relative_to_root(*ra_session, &relpath, base_url, - pool)); - anchor_abspath = svn_dirent_join(wcroot_abspath, relpath, pool); + svn_pool_clear(iterpool); + SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, NULL, + ctx->wc_ctx, item->path, FALSE, pool, + iterpool)); + if (relpath) + apr_hash_set(relpath_map, relpath, APR_HASH_KEY_STRING, item->path); + } + svn_pool_destroy(iterpool); } - else #endif - anchor_abspath = NULL; /* Fetch RA commit editor. */ - SVN_ERR(svn_ra__register_editor_shim_callbacks(*ra_session, + SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session, svn_client__get_shim_callbacks(ctx->wc_ctx, - anchor_abspath, pool))); - SVN_ERR(svn_ra_get_commit_editor3(*ra_session, editor, edit_baton, + relpath_map, pool))); + SVN_ERR(svn_ra_get_commit_editor3(ra_session, editor, edit_baton, commit_revprops, commit_callback, commit_baton, lock_tokens, keep_locks, pool)); @@ -705,36 +821,39 @@ get_ra_editor(svn_ra_session_t **ra_sess /*** Public Interfaces. ***/ svn_error_t * -svn_client_import4(const char *path, +svn_client_import5(const char *path, const char *url, svn_depth_t depth, svn_boolean_t no_ignore, svn_boolean_t ignore_unknown_node_types, const apr_hash_t *revprop_table, + svn_client_import_filter_func_t filter_callback, + void *filter_baton, svn_commit_callback2_t commit_callback, void *commit_baton, svn_client_ctx_t *ctx, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { svn_error_t *err = SVN_NO_ERROR; const char *log_msg = ""; const svn_delta_editor_t *editor; void *edit_baton; svn_ra_session_t *ra_session; - apr_hash_t *excludes = apr_hash_make(pool); + apr_hash_t *excludes = apr_hash_make(scratch_pool); svn_node_kind_t kind; const char *local_abspath; - apr_array_header_t *new_entries = apr_array_make(pool, 4, + apr_array_header_t *new_entries = apr_array_make(scratch_pool, 4, sizeof(const char *)); const char *temp; const char *dir; - apr_pool_t *subpool; + apr_hash_t *commit_revprops; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); if (svn_path_is_url(path)) return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, _("'%s' is not a local path"), path); - SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); /* Create a new commit item and add it to the array. */ if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) @@ -745,58 +864,55 @@ svn_client_import4(const char *path, svn_client_commit_item3_t *item; const char *tmp_file; apr_array_header_t *commit_items - = apr_array_make(pool, 1, sizeof(item)); + = apr_array_make(scratch_pool, 1, sizeof(item)); - item = svn_client_commit_item3_create(pool); - item->path = apr_pstrdup(pool, path); + item = svn_client_commit_item3_create(scratch_pool); + item->path = apr_pstrdup(scratch_pool, path); item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items, - ctx, pool)); + ctx, scratch_pool)); if (! log_msg) return SVN_NO_ERROR; if (tmp_file) { const char *abs_path; - SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, pool)); + SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, scratch_pool)); apr_hash_set(excludes, abs_path, APR_HASH_KEY_STRING, (void *)1); } } - SVN_ERR(svn_io_check_path(local_abspath, &kind, pool)); + SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool)); + + SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url, NULL, + NULL, FALSE, TRUE, ctx, + scratch_pool)); /* Figure out all the path components we need to create just to have a place to stick our imported tree. */ - subpool = svn_pool_create(pool); - do - { - svn_pool_clear(subpool); + SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind, + iterpool)); - /* See if the user is interested in cancelling this operation. */ - if (ctx->cancel_func) - SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); + /* We can import into directories, but if a file already exists, that's + an error. */ + if (kind == svn_node_file) + return svn_error_createf + (SVN_ERR_ENTRY_EXISTS, NULL, + _("Path '%s' already exists"), url); - if (err) - { - /* If get_ra_editor below failed we either tried to open - an invalid url, or else some other kind of error. In case - the url was bad we back up a directory and try again. */ + while (kind == svn_node_none) + { + svn_pool_clear(iterpool); - if (err->apr_err != SVN_ERR_FS_NO_SUCH_ENTRY) - return err; - else - svn_error_clear(err); + svn_uri_split(&temp, &dir, url, scratch_pool); + APR_ARRAY_PUSH(new_entries, const char *) = dir; + url = temp; + SVN_ERR(svn_ra_reparent(ra_session, url, iterpool)); - svn_uri_split(&temp, &dir, url, pool); - APR_ARRAY_PUSH(new_entries, const char *) = dir; - url = temp; - } + SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind, + iterpool)); } - while ((err = get_ra_editor(&ra_session, - &editor, &edit_baton, ctx, url, NULL, - log_msg, NULL, revprop_table, FALSE, NULL, TRUE, - commit_callback, commit_baton, subpool))); /* Reverse the order of the components we added to our NEW_ENTRIES array. */ if (new_entries->nelts) @@ -815,14 +931,6 @@ svn_client_import4(const char *path, } } - /* An empty NEW_ENTRIES list the first call to get_ra_editor() above - succeeded. That means that URL corresponds to an already - existing filesystem entity. */ - if (kind == svn_node_file && (! new_entries->nelts)) - return svn_error_createf - (SVN_ERR_ENTRY_EXISTS, NULL, - _("Path '%s' already exists"), url); - /* The repository doesn't know about the reserved administrative directory. */ if (new_entries->nelts @@ -833,25 +941,37 @@ svn_client_import4(const char *path, && svn_wc_is_adm_dir(temp = APR_ARRAY_IDX(new_entries, new_entries->nelts - 1, const char *), - pool)) + scratch_pool)) return svn_error_createf (SVN_ERR_CL_ADM_DIR_RESERVED, NULL, _("'%s' is a reserved name and cannot be imported"), - /* ### Is svn_path_local_style() really necessary for this? */ - svn_dirent_local_style(temp, pool)); + svn_dirent_local_style(temp, scratch_pool)); + + SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, + log_msg, ctx, scratch_pool)); + /* Fetch RA commit editor. */ + SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session, + svn_client__get_shim_callbacks(ctx->wc_ctx, + NULL, scratch_pool))); + SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton, + commit_revprops, commit_callback, + commit_baton, NULL, TRUE, + scratch_pool)); /* If an error occurred during the commit, abort the edit and return the error. We don't even care if the abort itself fails. */ - if ((err = import(path, new_entries, editor, edit_baton, + if ((err = import(local_abspath, new_entries, editor, edit_baton, depth, excludes, no_ignore, - ignore_unknown_node_types, ctx, subpool))) + ignore_unknown_node_types, + filter_callback, filter_baton, + ctx, iterpool))) { - svn_error_clear(editor->abort_edit(edit_baton, subpool)); + svn_error_clear(editor->abort_edit(edit_baton, iterpool)); return svn_error_trace(err); } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); return SVN_NO_ERROR; } @@ -1644,11 +1764,18 @@ svn_client_commit6(const apr_array_heade cb.pool = pool; cmt_err = svn_error_trace( - get_ra_editor(&ra_session, &editor, &edit_baton, ctx, - base_url, base_abspath, log_msg, - commit_items, revprop_table, TRUE, lock_tokens, - keep_locks, capture_commit_info, - &cb, pool)); + svn_client__open_ra_session_internal(&ra_session, NULL, base_url, + base_abspath, commit_items, + TRUE, FALSE, ctx, pool)); + + if (cmt_err) + goto cleanup; + + cmt_err = svn_error_trace( + get_ra_editor(&editor, &edit_baton, ra_session, ctx, + log_msg, commit_items, revprop_table, + lock_tokens, keep_locks, capture_commit_info, + &cb, pool)); if (cmt_err) goto cleanup; @@ -1658,9 +1785,9 @@ svn_client_commit6(const apr_array_heade /* Perform the commit. */ cmt_err = svn_error_trace( - svn_client__do_commit(base_url, commit_items, editor, edit_baton, - notify_prefix, NULL, - &sha1_checksums, ctx, pool, iterpool)); + svn_client__do_commit(base_url, commit_items, editor, edit_baton, + notify_prefix, &sha1_checksums, ctx, pool, + iterpool)); /* Handle a successful commit. */ if ((! cmt_err)