Author: rinrab Date: Thu May 8 14:19:32 2025 New Revision: 1925463 URL: http://svn.apache.org/viewvc?rev=1925463&view=rev Log: Add svn_client_patch2 function that accesses the patch file from an APR file instead of using a local path.
* subversion/include/svn_client.h (svn_client_patch2): New function. (svn_client_patch): Deprecate. * subversion/libsvn_client/deprecated.c (svn_client_patch): Add and implement through svn_client_patch2(). * subversion/libsvn_client/patch.c (apply_patches): Accept a file instead of a path and create a svn_diff_patch_parser_t instead of opening a svn_patch_file_t. (svn_client_patch): Update implementation to svn_client_patch2. * subversion/svn/patch-cmd.c (svn_cl__patch): Check and open the patch file manually, pass to the new function, and close it then. * subversion/tests/libsvn_client/client-test.c (test_patch): Update patch api used. See also a related discussion with myself on dev@ where this was initiated: https://lists.apache.org/thread/p260hdrt5wx0tv6xs9l5nt3pvbzvnrv4 Modified: subversion/trunk/subversion/include/svn_client.h subversion/trunk/subversion/libsvn_client/deprecated.c subversion/trunk/subversion/libsvn_client/patch.c subversion/trunk/subversion/svn/patch-cmd.c subversion/trunk/subversion/tests/libsvn_client/client-test.c Modified: subversion/trunk/subversion/include/svn_client.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1925463&r1=1925462&r2=1925463&view=diff ============================================================================== --- subversion/trunk/subversion/include/svn_client.h (original) +++ subversion/trunk/subversion/include/svn_client.h Thu May 8 14:19:32 2025 @@ -7718,8 +7718,9 @@ typedef svn_error_t *(*svn_client_patch_ apr_pool_t *scratch_pool); /** - * Apply a unidiff patch that's located at absolute path - * @a patch_abspath to the working copy directory at @a wc_dir_abspath. + * Apply a unidiff patch, described in @a apr_file which should have + * @c APR_READ and @c APR_BUFFERED capabilities to the working copy + * directory at @a wc_dir_abspath. * * This function makes a best-effort attempt at applying the patch. * It might skip patch targets which cannot be patched (e.g. targets @@ -7756,7 +7757,26 @@ typedef svn_error_t *(*svn_client_patch_ * * Use @a scratch_pool for temporary allocations. * - * @since New in 1.7. + * @since New in 1.15. + */ +svn_error_t * +svn_client_patch2(apr_file_t *apr_file, + const char *wc_dir_abspath, + svn_boolean_t dry_run, + int strip_count, + svn_boolean_t reverse, + svn_boolean_t ignore_whitespace, + svn_boolean_t remove_tempfiles, + svn_client_patch_func_t patch_func, + void *patch_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + +/** + * Similar to svn_client_patch2(), but accessing the patch by an absolute + * path. + * + * @deprecated Provided for backward compatibility with the 1.7 API. */ svn_error_t * svn_client_patch(const char *patch_abspath, Modified: subversion/trunk/subversion/libsvn_client/deprecated.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/deprecated.c?rev=1925463&r1=1925462&r2=1925463&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/deprecated.c (original) +++ subversion/trunk/subversion/libsvn_client/deprecated.c Thu May 8 14:19:32 2025 @@ -3290,3 +3290,46 @@ svn_client_upgrade(const char *path, return svn_error_trace(svn_client_upgrade2(NULL, path, NULL, ctx, NULL, scratch_pool)); } + +svn_error_t * +svn_client_patch(const char *patch_abspath, + const char *wc_dir_abspath, + svn_boolean_t dry_run, + int strip_count, + svn_boolean_t reverse, + svn_boolean_t ignore_whitespace, + svn_boolean_t remove_tempfiles, + svn_client_patch_func_t patch_func, + void *patch_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_node_kind_t kind; + apr_file_t *apr_file; + + SVN_ERR(svn_io_check_path(patch_abspath, &kind, scratch_pool)); + if (kind == svn_node_none) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' does not exist"), + svn_dirent_local_style(patch_abspath, + scratch_pool)); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' is not a file"), + svn_dirent_local_style(patch_abspath, + scratch_pool)); + + SVN_ERR(svn_io_file_open(&apr_file, patch_abspath, + APR_READ | APR_BUFFERED, APR_OS_DEFAULT, + scratch_pool)); + + SVN_ERR(svn_client_patch2(apr_file, wc_dir_abspath, + dry_run, strip_count, reverse, + ignore_whitespace, remove_tempfiles, + patch_func, patch_baton, + ctx, scratch_pool)); + + SVN_ERR(svn_io_file_close(apr_file, scratch_pool)); + + return SVN_NO_ERROR; +} Modified: subversion/trunk/subversion/libsvn_client/patch.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/patch.c?rev=1925463&r1=1925462&r2=1925463&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/patch.c (original) +++ subversion/trunk/subversion/libsvn_client/patch.c Thu May 8 14:19:32 2025 @@ -3613,8 +3613,8 @@ check_ancestor_delete(const char *delete /* This function is the main entry point into the patch code. */ static svn_error_t * -apply_patches(/* The path to the patch file. */ - const char *patch_abspath, +apply_patches(/* The patch file. */ + apr_file_t *apr_file, /* The abspath to the working copy the patch should be applied to. */ const char *root_abspath, /* Indicates whether we're doing a dry run. */ @@ -3636,11 +3636,10 @@ apply_patches(/* The path to the patch f { svn_patch_t *patch; apr_pool_t *iterpool; - svn_patch_file_t *patch_file; + svn_diff_patch_parser_t *patch_parser; apr_array_header_t *targets_info; - /* Try to open the patch file. */ - SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, scratch_pool)); + patch_parser = svn_diff_patch_parser_create(apr_file, scratch_pool); /* Apply patches. */ targets_info = apr_array_make(scratch_pool, 0, @@ -3653,9 +3652,9 @@ apply_patches(/* The path to the patch f if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); - SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file, - reverse, ignore_whitespace, - iterpool, iterpool)); + SVN_ERR(svn_diff_patch_parser_next(&patch, patch_parser, + reverse, ignore_whitespace, + iterpool, iterpool)); if (patch) { patch_target_t *target; @@ -3720,24 +3719,23 @@ apply_patches(/* The path to the patch f } while (patch); - SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; } svn_error_t * -svn_client_patch(const char *patch_abspath, - const char *wc_dir_abspath, - svn_boolean_t dry_run, - int strip_count, - svn_boolean_t reverse, - svn_boolean_t ignore_whitespace, - svn_boolean_t remove_tempfiles, - svn_client_patch_func_t patch_func, - void *patch_baton, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool) +svn_client_patch2(apr_file_t *apr_file, + const char *wc_dir_abspath, + svn_boolean_t dry_run, + int strip_count, + svn_boolean_t reverse, + svn_boolean_t ignore_whitespace, + svn_boolean_t remove_tempfiles, + svn_client_patch_func_t patch_func, + void *patch_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) { svn_node_kind_t kind; @@ -3751,18 +3749,6 @@ svn_client_patch(const char *patch_abspa svn_dirent_local_style(wc_dir_abspath, scratch_pool)); - SVN_ERR(svn_io_check_path(patch_abspath, &kind, scratch_pool)); - if (kind == svn_node_none) - return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, - _("'%s' does not exist"), - svn_dirent_local_style(patch_abspath, - scratch_pool)); - if (kind != svn_node_file) - return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, - _("'%s' is not a file"), - svn_dirent_local_style(patch_abspath, - scratch_pool)); - SVN_ERR(svn_io_check_path(wc_dir_abspath, &kind, scratch_pool)); if (kind == svn_node_none) return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, @@ -3776,7 +3762,7 @@ svn_client_patch(const char *patch_abspa scratch_pool)); SVN_WC__CALL_WITH_WRITE_LOCK( - apply_patches(patch_abspath, wc_dir_abspath, dry_run, strip_count, + apply_patches(apr_file, wc_dir_abspath, dry_run, strip_count, reverse, ignore_whitespace, remove_tempfiles, patch_func, patch_baton, ctx, scratch_pool), ctx->wc_ctx, wc_dir_abspath, FALSE /* lock_anchor */, scratch_pool); Modified: subversion/trunk/subversion/svn/patch-cmd.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/patch-cmd.c?rev=1925463&r1=1925462&r2=1925463&view=diff ============================================================================== --- subversion/trunk/subversion/svn/patch-cmd.c (original) +++ subversion/trunk/subversion/svn/patch-cmd.c Thu May 8 14:19:32 2025 @@ -51,8 +51,10 @@ svn_cl__patch(apr_getopt_t *os, apr_array_header_t *targets; const char *abs_patch_path; const char *patch_path; + apr_file_t *patch_file; const char *abs_target_path; const char *target_path; + svn_node_kind_t kind; opt_state = ((svn_cl__cmd_baton_t *)baton)->opt_state; ctx = ((svn_cl__cmd_baton_t *)baton)->ctx; @@ -74,6 +76,19 @@ svn_cl__patch(apr_getopt_t *os, SVN_ERR(svn_dirent_get_absolute(&abs_patch_path, patch_path, pool)); + SVN_ERR(svn_io_check_path(abs_patch_path, &kind, pool)); + if (kind == svn_node_none) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' does not exist"), + svn_dirent_local_style(abs_patch_path, pool)); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' is not a file"), + svn_dirent_local_style(abs_patch_path, pool)); + + SVN_ERR(svn_io_file_open(&patch_file, abs_patch_path, + APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool)); + if (targets->nelts == 1) target_path = ""; /* "" is the canonical form of "." */ else @@ -84,12 +99,13 @@ svn_cl__patch(apr_getopt_t *os, } SVN_ERR(svn_dirent_get_absolute(&abs_target_path, target_path, pool)); - SVN_ERR(svn_client_patch(abs_patch_path, abs_target_path, - opt_state->dry_run, opt_state->strip, - opt_state->reverse_diff, - opt_state->ignore_whitespace, - TRUE, NULL, NULL, ctx, pool)); + SVN_ERR(svn_client_patch2(patch_file, abs_target_path, + opt_state->dry_run, opt_state->strip, + opt_state->reverse_diff, + opt_state->ignore_whitespace, + TRUE, NULL, NULL, ctx, pool)); + SVN_ERR(svn_io_file_close(patch_file, pool)); if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_print_conflict_stats(ctx->notify_baton2, pool)); Modified: subversion/trunk/subversion/tests/libsvn_client/client-test.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/client-test.c?rev=1925463&r1=1925462&r2=1925463&view=diff ============================================================================== --- subversion/trunk/subversion/tests/libsvn_client/client-test.c (original) +++ subversion/trunk/subversion/tests/libsvn_client/client-test.c Thu May 8 14:19:32 2025 @@ -348,6 +348,8 @@ test_patch(const svn_test_opts_t *opts, const char *reject_tempfile_path; const char *key; int i; + apr_off_t off; + #define NL APR_EOL_STR #define UNIDIFF_LINES 7 const char *unidiff_patch[UNIDIFF_LINES] = { @@ -401,8 +403,8 @@ test_patch(const svn_test_opts_t *opts, pool, svn_test_data_path("test-patch", pool), "test-patch.diff", SVN_VA_NULL); SVN_ERR(svn_io_file_open(&patch_file, patch_file_path, - (APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE), - APR_OS_DEFAULT, pool)); + (APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE + | APR_BUFFERED), APR_OS_DEFAULT, pool)); for (i = 0; i < UNIDIFF_LINES; i++) { apr_size_t len = strlen(unidiff_patch[i]); @@ -415,9 +417,12 @@ test_patch(const svn_test_opts_t *opts, pcb.patched_tempfiles = apr_hash_make(pool); pcb.reject_tempfiles = apr_hash_make(pool); pcb.state_pool = pool; - SVN_ERR(svn_client_patch(patch_file_path, wc_path, FALSE, 0, FALSE, - FALSE, FALSE, patch_collection_func, &pcb, - ctx, pool)); + + off = 0; + SVN_ERR(svn_io_file_seek(patch_file, APR_SET, &off, pool)); + SVN_ERR(svn_client_patch2(patch_file, wc_path, FALSE, 0, FALSE, + FALSE, FALSE, patch_collection_func, &pcb, + ctx, pool)); SVN_ERR(svn_io_file_close(patch_file, pool)); SVN_TEST_ASSERT(apr_hash_count(pcb.patched_tempfiles) == 1);