Index: subversion/libsvn_ra/ra_loader.c =================================================================== --- subversion/libsvn_ra/ra_loader.c (revision 15181) +++ subversion/libsvn_ra/ra_loader.c (working copy) @@ -230,6 +230,20 @@ return SVN_NO_ERROR; } +char *svn_ra_find_protocol (const char *repos_URL) +{ + const struct ra_lib_defn *defn; + + /* Find which protocol */ + for (defn = ra_libraries; defn->ra_name != NULL; ++defn) + { + if (has_scheme_of (defn, repos_URL)) + return defn->ra_name; + } + + return NULL; +} + svn_error_t *svn_ra_open (svn_ra_session_t **session_p, const char *repos_URL, const svn_ra_callbacks_t *callbacks, @@ -322,6 +336,21 @@ return session->vtable->rev_prop (session, rev, name, value, pool); } +svn_error_t *svn_ra_get_commit_editor2 (svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool) +{ + return session->vtable->get_commit_editor2 (session, editor, edit_baton, + log_msg, callback, callback_baton, + lock_tokens, keep_locks, pool); +} + svn_error_t *svn_ra_get_commit_editor (svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, Index: subversion/libsvn_ra/ra_loader.h =================================================================== --- subversion/libsvn_ra/ra_loader.h (revision 15181) +++ subversion/libsvn_ra/ra_loader.h (working copy) @@ -76,6 +76,9 @@ const char *name, svn_string_t **value, apr_pool_t *pool); + /* This parameter should be removed once ra_dav, ra_local and ra_svn + start using get_commit_editor2. Currently, only ra_dav uses + get_commit_editor2 */ svn_error_t *(*get_commit_editor) (svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, @@ -198,6 +201,16 @@ apr_hash_t **locks, const char *path, apr_pool_t *pool); + + svn_error_t *(*get_commit_editor2) (svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); } svn_ra__vtable_t; /* The RA session object. */ Index: subversion/include/svn_repos.h =================================================================== --- subversion/include/svn_repos.h (revision 15181) +++ subversion/include/svn_repos.h (working copy) @@ -598,8 +598,27 @@ * NULL). Callers who supply their own transactions are responsible * for cleaning them up (either by committing them, or aborting them). * - * @since New in 1.2. + * @since New in 1.3. */ +svn_error_t *svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor, + void **edit_baton, + svn_repos_t *repos, + svn_fs_txn_t *txn, + const char *repos_url, + const char *base_path, + const char *user, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_repos_get_commit_editor3(), but with + * svn_commit_callback2_t as @a callback type + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ svn_error_t *svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, Index: subversion/include/svn_types.h =================================================================== --- subversion/include/svn_types.h (revision 15181) +++ subversion/include/svn_types.h (working copy) @@ -343,9 +343,23 @@ /** Callback function type for commits. * * When a commit succeeds, an instance of this is invoked on the @a - * new_revision, @a date, and @a author of the commit, along with the - * @a baton closure. + * new_revision, @a date, and @a author of the commit, the post-commit + * hooks stderr - if any, along with the @a baton closure. + * + * @since New in 1.3. */ +typedef svn_error_t * (*svn_commit_callback2_t) ( + svn_revnum_t new_revision, + const char *date, + const char *author, + const char *post_commit_err, + void *baton); + +/** Similar to svn_commit_callback2_t, without the @a post_commit_err + * parameter. Currently ra_svn and ra_local use this callback. should + * be deprecated once both these protocols start using + * svn_commit_callback2_t. + */ typedef svn_error_t * (*svn_commit_callback_t) ( svn_revnum_t new_revision, const char *date, Index: subversion/include/svn_client.h =================================================================== --- subversion/include/svn_client.h (revision 15181) +++ subversion/include/svn_client.h (working copy) @@ -264,6 +264,27 @@ /** Information about commits passed back to client from this module. */ +typedef struct svn_client_commit_info2_t +{ + /** just-committed revision. */ + svn_revnum_t revision; + + /** server-side date of the commit. */ + const char *date; + + /** author of the commit. */ + const char *author; + + /** post-commit hook's stderr. */ + const char *post_commit_err; + +} svn_client_commit_info2_t; + +/** Similar to svn_client_commit_info2_t, without the + * post_commit_err parameter. Currently ra_svn and ra_local + * would need this. Should be deprecated once both these + * protocols start using svn_client_commit_info2_t. + */ typedef struct svn_client_commit_info_t { /** just-committed revision. */ @@ -692,7 +713,7 @@ * @a ctx->notify_baton2 and the path of the new directory. Note that this is * only called for items added to the working copy. */ svn_error_t * -svn_client_mkdir (svn_client_commit_info_t **commit_info, +svn_client_mkdir (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_client_ctx_t *ctx, apr_pool_t *pool); @@ -727,7 +748,7 @@ * @a ctx->notify_func2 with @a ctx->notify_baton2 and the path of the deleted * item. */ svn_error_t * -svn_client_delete (svn_client_commit_info_t **commit_info, +svn_client_delete (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_boolean_t force, svn_client_ctx_t *ctx, @@ -825,9 +846,23 @@ * @c SVN_INVALID_REVNUM, then the commit was a no-op; nothing needed to * be committed. * - * @since New in 1.2. + * @since New in 1.3. */ svn_error_t * +svn_client_commit3 (svn_client_commit_info2_t **commit_info, + const apr_array_header_t *targets, + svn_boolean_t recurse, + svn_boolean_t keep_locks, + svn_client_ctx_t *ctx, + apr_pool_t *pool); + +/** + * Similar to svn_client_commit3, except that the @a commit_info + * parameter uses the svn_client_commit_info_t type. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +svn_error_t * svn_client_commit2 (svn_client_commit_info_t **commit_info, const apr_array_header_t *targets, svn_boolean_t recurse, @@ -1378,8 +1413,24 @@ * If @a ctx->notify_func2 is non-null, invoke it with @a ctx->notify_baton2 * for each item added at the new location, passing the new, relative path of * the added item. + * + * @since New in 1.3 */ svn_error_t * +svn_client_copy2 (svn_client_commit_info2_t **commit_info, + const char *src_path, + const svn_opt_revision_t *src_revision, + const char *dst_path, + svn_client_ctx_t *ctx, + apr_pool_t *pool); + +/** + * Similar to svn_client_copy2(), but for the type of @a commit_info + * is svn_client_commit_info_t instead of svn_client_commit_info2_t. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +svn_error_t * svn_client_copy (svn_client_commit_info_t **commit_info, const char *src_path, const svn_opt_revision_t *src_revision, Index: subversion/include/svn_ra.h =================================================================== --- subversion/include/svn_ra.h (revision 15181) +++ subversion/include/svn_ra.h (working copy) @@ -373,6 +373,23 @@ typedef struct svn_ra_session_t svn_ra_session_t; /** + * This is a tempraoary function, should be removed once + * ra_svn and ra_local start become post-commit err aware. + * + * From the given @a reposURL, find out which protocol scheme fits + * and return one of the following strings. + * "dav" + * "svn" + * "local" + * + * NULL is returned if the reposURL doesnt fit into any valid scheme. + * + * @since New in 1.3 + */ +char * +svn_ra_find_protocol (const char *repos_URL); + +/** * Open a repository session to @a repos_URL. Return an opaque object * representing this session in @a *session_p, allocated in @a pool. * @@ -500,8 +517,22 @@ * * Use @a pool for memory allocation. * - * @since New in 1.2. + * @since New in 1.3. */ +svn_error_t *svn_ra_get_commit_editor2 (svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); + +/** + * Similar to svn_ra_get_commit_editor2, but @a callback + * has svn_commit_callback_t for type + */ svn_error_t *svn_ra_get_commit_editor (svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, Index: subversion/libsvn_ra_local/ra_plugin.c =================================================================== --- subversion/libsvn_ra_local/ra_plugin.c (revision 15181) +++ subversion/libsvn_ra_local/ra_plugin.c (working copy) @@ -1255,6 +1255,7 @@ svn_ra_local__unlock, svn_ra_local__get_lock, svn_ra_local__get_locks, + NULL, }; Index: subversion/libsvn_client/delete.c =================================================================== --- subversion/libsvn_client/delete.c (revision 15181) +++ subversion/libsvn_client/delete.c (working copy) @@ -109,7 +109,7 @@ static svn_error_t * -delete_urls (svn_client_commit_info_t **commit_info, +delete_urls (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_client_ctx_t *ctx, apr_pool_t *pool) @@ -183,13 +183,22 @@ } svn_pool_destroy (subpool); + SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); + /* This check is temproary, should be removed once ra_svn and ra_local + * start using svn_ra_get_commit_editor2 */ /* Fetch RA commit editor */ - SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); - SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, - log_msg, svn_client__commit_callback, - commit_baton, - NULL, TRUE, /* No lock tokens */ - pool)); + if ( !strcmp ("dav", svn_ra_find_protocol (common))) + SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, + log_msg, svn_client__commit_callback2, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool)); + else + SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, + log_msg, svn_client__commit_callback, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool)); /* Call the path-based editor driver. */ err = svn_delta_path_driver (editor, edit_baton, SVN_INVALID_REVNUM, @@ -233,7 +242,7 @@ svn_error_t * -svn_client_delete (svn_client_commit_info_t **commit_info, +svn_client_delete (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_boolean_t force, svn_client_ctx_t *ctx, Index: subversion/libsvn_client/client.h =================================================================== --- subversion/libsvn_client/client.h (revision 15181) +++ subversion/libsvn_client/client.h (working copy) @@ -249,13 +249,24 @@ /* Get the commit_baton to be used in couple with commit_callback. */ svn_error_t *svn_client__commit_get_baton (void **baton, - svn_client_commit_info_t **info, + svn_client_commit_info2_t **info, apr_pool_t *pool); /* The commit_callback function for storing svn_client_commit_info_t pointed by commit_baton. If the commit_info supplied by get_baton points to NULL after close_edit, it means the commit is a no-op. */ +svn_error_t *svn_client__commit_callback2 (svn_revnum_t revision, + const char *date, + const char *author, + const char *post_commit_err, + void *baton); + +/* Similar to svn_client__commit_callback2, but doesnt contain + the post_commit_err parameter. + Should be removed once ra_svn and ra_local start using + svn_client__commit_callback2. +*/ svn_error_t *svn_client__commit_callback (svn_revnum_t revision, const char *date, const char *author, Index: subversion/libsvn_client/copy.c =================================================================== --- subversion/libsvn_client/copy.c (revision 15181) +++ subversion/libsvn_client/copy.c (working copy) @@ -271,7 +271,7 @@ static svn_error_t * -repos_to_repos_copy (svn_client_commit_info_t **commit_info, +repos_to_repos_copy (svn_client_commit_info2_t **commit_info, const char *src_url, const svn_opt_revision_t *src_revision, const char *dst_url, @@ -450,11 +450,20 @@ /* Fetch RA commit editor. */ SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); - SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, message, - svn_client__commit_callback, - commit_baton, - NULL, TRUE, /* No lock tokens */ - pool)); + /* This check is temproary, should be removed once ra_svn and ra_local + * start using svn_ra_get_commit_editor2 */ + if ( !strcmp ("dav", svn_ra_find_protocol (top_url))) + SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, message, + svn_client__commit_callback2, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool)); + else + SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, message, + svn_client__commit_callback, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool)); /* Setup our PATHS for the path-based editor drive. */ APR_ARRAY_PUSH (paths, const char *) = dst_rel; @@ -579,7 +588,7 @@ static svn_error_t * -wc_to_repos_copy (svn_client_commit_info_t **commit_info, +wc_to_repos_copy (svn_client_commit_info2_t **commit_info, const char *src_path, const char *dst_url, svn_client_ctx_t *ctx, @@ -706,13 +715,28 @@ /* Fetch RA commit editor. */ SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); - if ((cmt_err = svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, - message, - svn_client__commit_callback, - commit_baton, - NULL, TRUE, /* No lock tokens */ - pool))) - goto cleanup; + /* This check is temproary, should be removed once ra_svn and ra_local + * start using svn_ra_get_commit_editor2 */ + if ( !strcmp ("dav", svn_ra_find_protocol (base_url))) + { + if ((cmt_err = svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, + message, + svn_client__commit_callback2, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool))) + goto cleanup; + } + else + { + if ((cmt_err = svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, + message, + svn_client__commit_callback, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool))) + goto cleanup; + } /* Make a note that we have a commit-in-progress. */ commit_in_progress = TRUE; @@ -1006,7 +1030,7 @@ static svn_error_t * -setup_copy (svn_client_commit_info_t **commit_info, +setup_copy (svn_client_commit_info2_t **commit_info, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, @@ -1118,12 +1142,12 @@ /* Public Interfaces */ svn_error_t * -svn_client_copy (svn_client_commit_info_t **commit_info, - const char *src_path, - const svn_opt_revision_t *src_revision, - const char *dst_path, - svn_client_ctx_t *ctx, - apr_pool_t *pool) +svn_client_copy2 (svn_client_commit_info2_t **commit_info, + const char *src_path, + const svn_opt_revision_t *src_revision, + const char *dst_path, + svn_client_ctx_t *ctx, + apr_pool_t *pool) { return setup_copy (commit_info, src_path, src_revision, dst_path, @@ -1133,9 +1157,25 @@ pool); } +svn_error_t * +svn_client_copy (svn_client_commit_info_t **commit_info, + const char *src_path, + const svn_opt_revision_t *src_revision, + const char *dst_path, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + return svn_client_copy2 ( (svn_client_commit_info2_t **)commit_info, + src_path, + src_revision, + dst_path, + ctx, + pool); +} + svn_error_t * -svn_client_move2 (svn_client_commit_info_t **commit_info, +svn_client_move3 (svn_client_commit_info2_t **commit_info, const char *src_path, const char *dst_path, svn_boolean_t force, @@ -1154,6 +1194,22 @@ } svn_error_t * +svn_client_move2 (svn_client_commit_info_t **commit_info, + const char *src_path, + const char *dst_path, + svn_boolean_t force, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + return svn_client_move3 ( (svn_client_commit_info2_t ** )commit_info, + src_path, + dst_path, + force, + ctx, + pool); +} + +svn_error_t * svn_client_move (svn_client_commit_info_t **commit_info, const char *src_path, const svn_opt_revision_t *src_revision, @@ -1177,7 +1233,7 @@ _("Cannot specify revisions (except HEAD) with move operations")); } - return setup_copy (commit_info, + return setup_copy ( (svn_client_commit_info2_t **)commit_info, src_path, src_revision, dst_path, TRUE /* is_move */, force, Index: subversion/libsvn_client/commit_util.c =================================================================== --- subversion/libsvn_client/commit_util.c (revision 15181) +++ subversion/libsvn_client/commit_util.c (working copy) @@ -1316,12 +1316,12 @@ /* Commit callback baton */ struct commit_baton { - svn_client_commit_info_t **info; + svn_client_commit_info2_t **info; apr_pool_t *pool; }; svn_error_t *svn_client__commit_get_baton (void **baton, - svn_client_commit_info_t **info, + svn_client_commit_info2_t **info, apr_pool_t *pool) { struct commit_baton *cb = apr_pcalloc (pool, sizeof (*cb)); @@ -1332,18 +1332,31 @@ return SVN_NO_ERROR; } + svn_error_t *svn_client__commit_callback (svn_revnum_t revision, const char *date, const char *author, void *baton) { + return svn_client__commit_callback2 (revision, date, author, + NULL, baton); +} + + +svn_error_t *svn_client__commit_callback2 (svn_revnum_t revision, + const char *date, + const char *author, + const char *post_commit_err, + void *baton) +{ struct commit_baton *cb = baton; - svn_client_commit_info_t **info = cb->info; + svn_client_commit_info2_t **info = cb->info; *info = apr_palloc (cb->pool, sizeof (**info)); (*info)->date = date ? apr_pstrdup (cb->pool, date) : NULL; (*info)->author = author ? apr_pstrdup (cb->pool, author) : NULL; (*info)->revision = revision; + (*info)->post_commit_err = post_commit_err ? apr_pstrdup (cb->pool, post_commit_err) : NULL; return SVN_NO_ERROR; } Index: subversion/libsvn_client/add.c =================================================================== --- subversion/libsvn_client/add.c (revision 15181) +++ subversion/libsvn_client/add.c (working copy) @@ -494,7 +494,7 @@ static svn_error_t * -mkdir_urls (svn_client_commit_info_t **commit_info, +mkdir_urls (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_client_ctx_t *ctx, apr_pool_t *pool) @@ -586,11 +586,18 @@ /* Fetch RA commit editor */ SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); - SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, - log_msg, svn_client__commit_callback, - commit_baton, + if ( !strcmp ("dav", svn_ra_find_protocol (common))) + SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, + log_msg, svn_client__commit_callback2, + commit_baton, + NULL, TRUE, /* No lock tokens */ + pool)); + else + SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, + log_msg, svn_client__commit_callback, + commit_baton, NULL, TRUE, /* No lock tokens */ - pool)); + pool)); /* Call the path-based editor driver. */ err = svn_delta_path_driver (editor, edit_baton, SVN_INVALID_REVNUM, @@ -611,7 +618,7 @@ svn_error_t * -svn_client_mkdir (svn_client_commit_info_t **commit_info, +svn_client_mkdir (svn_client_commit_info2_t **commit_info, const apr_array_header_t *paths, svn_client_ctx_t *ctx, apr_pool_t *pool) Index: subversion/libsvn_client/commit.c =================================================================== --- subversion/libsvn_client/commit.c (revision 15181) +++ subversion/libsvn_client/commit.c (working copy) @@ -588,7 +588,7 @@ svn_wc_adm_access_t *base_access, const char *log_msg, apr_array_header_t *commit_items, - svn_client_commit_info_t **commit_info, + svn_client_commit_info2_t **commit_info, svn_boolean_t is_commit, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, @@ -623,12 +623,21 @@ /* Fetch RA commit editor. */ SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool)); - return svn_ra_get_commit_editor (*ra_session, editor, edit_baton, log_msg, - svn_client__commit_callback, - commit_baton, lock_tokens, keep_locks, - pool); + /* This check is temproary, should be removed once ra_svn and ra_local + * start using svn_ra_get_commit_editor2 */ + if ( !strcmp ("dav", svn_ra_find_protocol (base_url))) + return svn_ra_get_commit_editor2 (*ra_session, editor, edit_baton, log_msg, + svn_client__commit_callback2, + commit_baton, lock_tokens, keep_locks, + pool); + else + return svn_ra_get_commit_editor (*ra_session, editor, edit_baton, log_msg, + svn_client__commit_callback, + commit_baton, lock_tokens, keep_locks, + pool); } + /*** Public Interfaces. ***/ @@ -717,7 +726,8 @@ } while ((err = get_ra_editor (&ra_session, NULL, &editor, &edit_baton, ctx, url, base_dir, - NULL, log_msg, NULL, commit_info, + NULL, log_msg, NULL, + (svn_client_commit_info2_t **) commit_info, FALSE, NULL, TRUE, subpool))); /* Reverse the order of the components we added to our NEW_ENTRIES array. */ @@ -1164,7 +1174,7 @@ } svn_error_t * -svn_client_commit2 (svn_client_commit_info_t **commit_info, +svn_client_commit3 (svn_client_commit_info2_t **commit_info, const apr_array_header_t *targets, svn_boolean_t recurse, svn_boolean_t keep_locks, @@ -1623,6 +1633,25 @@ } svn_error_t * +svn_client_commit2 (svn_client_commit_info_t **commit_info, + const apr_array_header_t *targets, + svn_boolean_t recurse, + svn_boolean_t keep_locks, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + svn_client_commit_info2_t *commit_info2 = NULL; + svn_error_t *ret_val = NULL; + ret_val = svn_client_commit3 (&commit_info2, targets, recurse, + keep_locks, ctx, pool); + + /* point commit_info to commit_info2 */ + *commit_info = commit_info2 ; + + return ret_val ; +} + +svn_error_t * svn_client_commit (svn_client_commit_info_t **commit_info, const apr_array_header_t *targets, svn_boolean_t nonrecursive, Index: subversion/mod_dav_svn/merge.c =================================================================== --- subversion/mod_dav_svn/merge.c (revision 15181) +++ subversion/mod_dav_svn/merge.c (working copy) @@ -29,8 +29,10 @@ #include "svn_props.h" #include "dav_svn.h" +#include "svn_xml.h" + /* ################################################################# These functions are currently *VERY* SVN specific. @@ -200,6 +202,7 @@ dav_error * dav_svn__merge_response(ap_filter_t *output, const dav_svn_repos *repos, svn_revnum_t new_rev, + char *post_commit_err, apr_xml_elem *prop_elem, svn_boolean_t disable_merge_response, apr_pool_t *pool) @@ -209,6 +212,7 @@ svn_error_t *serr; const char *vcc; const char *rev; + const char *post_commit_err_elem, *post_commit_header_info; svn_string_t *creationdate, *creator_displayname; serr = svn_fs_revision_root(&root, repos->fs, new_rev, pool); @@ -231,6 +235,24 @@ /* the version-name of the baseline is the revision number */ rev = apr_psprintf(pool, "%ld", new_rev); + /* get the post-commit hook stderr, if any */ + if (post_commit_err) + { + post_commit_header_info = apr_psprintf (pool, + " xmlns:S=\"%s\"", + SVN_XML_NAMESPACE); + post_commit_err_elem = apr_psprintf (pool, + "%s" + "", + post_commit_err); + } + else + { + post_commit_header_info = "" ; + post_commit_err_elem = "" ; + } + + /* get the creationdate and creator-displayname of the new revision, too. */ serr = svn_fs_revision_prop(&creationdate, repos->fs, new_rev, SVN_PROP_REVISION_DATE, pool); @@ -252,7 +274,9 @@ (void) ap_fputstrs(output, bb, DAV_XML_HEADER DEBUG_CR - "" DEBUG_CR + "" DEBUG_CR "" DEBUG_CR /* generate a response for the new baseline */ @@ -264,7 +288,8 @@ /* ### this is wrong. it's a VCC, not a baseline. but ### we need to tell the client to look at *this* ### resource for the version-name. */ - "" DEBUG_CR + "" DEBUG_CR, + post_commit_err_elem, DEBUG_CR "", rev, "" DEBUG_CR, NULL); if (creationdate) Index: subversion/mod_dav_svn/dav_svn.h =================================================================== --- subversion/mod_dav_svn/dav_svn.h (revision 15181) +++ subversion/mod_dav_svn/dav_svn.h (working copy) @@ -501,6 +501,7 @@ dav_error * dav_svn__merge_response(ap_filter_t *output, const dav_svn_repos *repos, svn_revnum_t new_rev, + char *post_commit_err, apr_xml_elem *prop_elem, svn_boolean_t disable_merge_response, apr_pool_t *pool); Index: subversion/mod_dav_svn/version.c =================================================================== --- subversion/mod_dav_svn/version.c (revision 15181) +++ subversion/mod_dav_svn/version.c (working copy) @@ -1614,6 +1614,7 @@ svn_fs_txn_t *txn; const char *conflict; svn_error_t *serr; + char *post_commit_err = NULL ; svn_revnum_t new_rev; apr_hash_t *locks; svn_boolean_t disable_merge_response = FALSE; @@ -1694,8 +1695,13 @@ return dav_svn_convert_err(serr, HTTP_CONFLICT, msg, pool); } else if (serr) - svn_error_clear(serr); + { + if (serr->child->message) + post_commit_err = apr_pstrdup (pool, serr->child->message); + svn_error_clear(serr); + } + /* Commit was successful, so schedule deltification. */ register_deltification_cleanup(source->info->repos->repos, new_rev, source->info->r->connection->pool); @@ -1735,7 +1741,8 @@ /* process the response for the new revision. */ return dav_svn__merge_response(output, source->info->repos, new_rev, - prop_elem, disable_merge_response, pool); + post_commit_err, prop_elem, + disable_merge_response, pool); } const dav_hooks_vsn dav_svn_hooks_vsn = { Index: subversion/clients/cmdline/cl.h =================================================================== --- subversion/clients/cmdline/cl.h (revision 15181) +++ subversion/clients/cmdline/cl.h (working copy) @@ -226,6 +226,10 @@ /* Print out commit information found in COMMIT_INFO to the console. * POOL is used for temporay allocations. */ +svn_error_t *svn_cl__print_commit_info2 (svn_client_commit_info2_t *commit_info, + apr_pool_t *pool); +/* This function should be removed, once all commit related + * commands switch to using svn_cl__print_commit_info2 */ svn_error_t *svn_cl__print_commit_info (svn_client_commit_info_t *commit_info, apr_pool_t *pool); Index: subversion/clients/cmdline/mkdir-cmd.c =================================================================== --- subversion/clients/cmdline/mkdir-cmd.c (revision 15181) +++ subversion/clients/cmdline/mkdir-cmd.c (working copy) @@ -43,7 +43,7 @@ svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; apr_pool_t *subpool = svn_pool_create (pool); - svn_client_commit_info_t *commit_info = NULL; + svn_client_commit_info2_t *commit_info = NULL; svn_error_t *err; SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, @@ -87,7 +87,7 @@ } if (commit_info && ! opt_state->quiet) - SVN_ERR (svn_cl__print_commit_info (commit_info, subpool)); + SVN_ERR (svn_cl__print_commit_info2 (commit_info, subpool)); return SVN_NO_ERROR; } Index: subversion/clients/cmdline/move-cmd.c =================================================================== --- subversion/clients/cmdline/move-cmd.c (revision 15181) +++ subversion/clients/cmdline/move-cmd.c (working copy) @@ -42,7 +42,7 @@ svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; const char *src_path, *dst_path; - svn_client_commit_info_t *commit_info = NULL; + svn_client_commit_info2_t *commit_info = NULL; svn_error_t *err; SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, @@ -77,7 +77,7 @@ SVN_ERR (svn_cl__cleanup_log_msg (ctx->log_msg_baton, err)); if (commit_info && ! opt_state->quiet) - SVN_ERR (svn_cl__print_commit_info (commit_info, pool)); + SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool)); return SVN_NO_ERROR; } Index: subversion/clients/cmdline/copy-cmd.c =================================================================== --- subversion/clients/cmdline/copy-cmd.c (revision 15181) +++ subversion/clients/cmdline/copy-cmd.c (working copy) @@ -43,7 +43,7 @@ apr_array_header_t *targets; const char *src_path, *dst_path; svn_boolean_t src_is_url, dst_is_url; - svn_client_commit_info_t *commit_info = NULL; + svn_client_commit_info2_t *commit_info = NULL; svn_error_t *err; SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, @@ -110,9 +110,9 @@ SVN_ERR (svn_cl__make_log_msg_baton (&(ctx->log_msg_baton), opt_state, NULL, ctx->config, pool)); - err = svn_client_copy (&commit_info, src_path, - &(opt_state->start_revision), - dst_path, ctx, pool); + err = svn_client_copy2 (&commit_info, src_path, + &(opt_state->start_revision), + dst_path, ctx, pool); if (ctx->log_msg_func) SVN_ERR (svn_cl__cleanup_log_msg (ctx->log_msg_baton, err)); @@ -120,7 +120,7 @@ return err; if (commit_info && ! opt_state->quiet) - SVN_ERR (svn_cl__print_commit_info (commit_info, pool)); + SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool)); return SVN_NO_ERROR; } Index: subversion/clients/cmdline/util.c =================================================================== --- subversion/clients/cmdline/util.c (revision 15181) +++ subversion/clients/cmdline/util.c (working copy) @@ -60,7 +60,23 @@ return SVN_NO_ERROR; } +svn_error_t * +svn_cl__print_commit_info2 (svn_client_commit_info2_t *commit_info, + apr_pool_t *pool) +{ + if ((commit_info) + && (SVN_IS_VALID_REVNUM (commit_info->revision))) + SVN_ERR (svn_cmdline_printf (pool, _("\nCommitted revision %ld.\n"), + commit_info->revision)); + if ((commit_info) + && (commit_info->post_commit_err)) + SVN_ERR (svn_cmdline_printf (pool, _("\nWARNING:\n%s\n"), + commit_info->post_commit_err)); + return SVN_NO_ERROR; +} + + svn_error_t * svn_cl__edit_externally (svn_string_t **edited_contents /* UTF-8! */, const char **tmpfile_left /* UTF-8! */, Index: subversion/clients/cmdline/commit-cmd.c =================================================================== --- subversion/clients/cmdline/commit-cmd.c (revision 15181) +++ subversion/clients/cmdline/commit-cmd.c (working copy) @@ -46,7 +46,7 @@ const char *base_dir; svn_config_t *cfg; svn_boolean_t no_unlock = FALSE; - svn_client_commit_info_t *commit_info = NULL; + svn_client_commit_info2_t *commit_info = NULL; SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, opt_state->targets, pool)); @@ -92,7 +92,7 @@ /* Commit. */ SVN_ERR (svn_cl__cleanup_log_msg - (ctx->log_msg_baton, svn_client_commit2 (&commit_info, + (ctx->log_msg_baton, svn_client_commit3 (&commit_info, targets, opt_state->nonrecursive ? FALSE : TRUE, @@ -100,7 +100,7 @@ ctx, pool))); if (commit_info && ! opt_state->quiet) - SVN_ERR (svn_cl__print_commit_info (commit_info, pool)); + SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool)); return SVN_NO_ERROR; } Index: subversion/clients/cmdline/delete-cmd.c =================================================================== --- subversion/clients/cmdline/delete-cmd.c (revision 15181) +++ subversion/clients/cmdline/delete-cmd.c (working copy) @@ -41,7 +41,7 @@ svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; apr_array_header_t *targets; - svn_client_commit_info_t *commit_info = NULL; + svn_client_commit_info2_t *commit_info = NULL; svn_error_t *err; SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, @@ -80,7 +80,7 @@ return err; if (commit_info && ! opt_state->quiet) - SVN_ERR (svn_cl__print_commit_info (commit_info, pool)); + SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool)); return SVN_NO_ERROR; } Index: subversion/libsvn_repos/hooks.c =================================================================== --- subversion/libsvn_repos/hooks.c (revision 15181) +++ subversion/libsvn_repos/hooks.c (working copy) @@ -297,7 +297,7 @@ args[2] = apr_psprintf (pool, "%ld", rev); args[3] = NULL; - SVN_ERR (run_hook_cmd ("post-commit", hook, args, FALSE, NULL, pool)); + SVN_ERR (run_hook_cmd ("post-commit", hook, args, TRUE, NULL, pool)); } return SVN_NO_ERROR; Index: subversion/libsvn_repos/commit.c =================================================================== --- subversion/libsvn_repos/commit.c (revision 15181) +++ subversion/libsvn_repos/commit.c (working copy) @@ -49,7 +49,11 @@ /* Commit message for this commit. */ const char *log_msg; - /* Callback to run when the commit is done. */ + /** Callback to run when the commit is done. + * + * Old callback structure. To be removed later + * Kept now, as ra_svn and ra_local still use this + */ svn_commit_callback_t callback; void *callback_baton; @@ -91,6 +95,9 @@ /* The author (also according to the repository) of this commit. */ const char **committed_author; + + /* Callback to run when the commit is done. */ + svn_commit_callback2_t callback2; }; @@ -556,7 +563,9 @@ svn_revnum_t new_revision = SVN_INVALID_REVNUM; svn_error_t *err; const char *conflict; + char *post_commit_err = NULL ; + /* Commit. */ err = svn_repos_fs_commit_txn (&conflict, eb->repos, &new_revision, eb->txn, pool); @@ -587,12 +596,10 @@ } else if (err) { - /* ### TODO: ra_local is the only RA layer that currently - understands SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED. And as of - at least r12960, svn_repos_fs_commit_txn() would never return - that anyway. If someone who knows ra_svn better can add - handling for this special case, this whole "else if" block - can go away (again). */ + /* retrieve the post-commit hook stderr */ + if (err->child->message) + post_commit_err = apr_pstrdup (pool, err->child->message) ; + svn_error_clear(err); err = SVN_NO_ERROR; } @@ -615,10 +622,17 @@ eb->pool); if (! err2) - err2 = (*eb->callback) (new_revision, - date ? date->data : NULL, - author ? author->data : NULL, - eb->callback_baton); + if( *eb->callback2) + err2 = (*eb->callback2) (new_revision, + date ? date->data : NULL, + author ? author->data : NULL, + post_commit_err ? post_commit_err : NULL, + eb->callback_baton); + else + err2 = (*eb->callback) (new_revision, + date ? date->data : NULL, + author ? author->data : NULL, + eb->callback_baton); if (err2) { svn_error_clear (err); @@ -647,7 +661,7 @@ /*** Public interfaces. ***/ svn_error_t * -svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor, +svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, svn_fs_txn_t *txn, @@ -655,7 +669,7 @@ const char *base_path, const char *user, const char *log_msg, - svn_commit_callback_t callback, + svn_commit_callback2_t callback, void *callback_baton, apr_pool_t *pool) { @@ -681,7 +695,7 @@ eb->pool = subpool; eb->user = user ? apr_pstrdup (subpool, user) : NULL; eb->log_msg = apr_pstrdup (subpool, log_msg); - eb->callback = callback; + eb->callback2 = callback; eb->callback_baton = callback_baton; eb->base_path = apr_pstrdup (subpool, base_path); eb->repos = repos; @@ -698,6 +712,44 @@ svn_error_t * +svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor, + void **edit_baton, + svn_repos_t *repos, + svn_fs_txn_t *txn, + const char *repos_url, + const char *base_path, + const char *user, + const char *log_msg, + svn_commit_callback_t callback, + void *callback_baton, + apr_pool_t *pool) +{ + svn_error_t *ret_val = NULL; + struct edit_baton *eb = NULL; + + /* get commit editor with new call back set to NULL */ + ret_val = svn_repos_get_commit_editor3 (editor, + edit_baton, + repos, + txn, + repos_url, + base_path, + user, + log_msg, + NULL, + callback_baton, + pool); + + /* set the older callback function */ + eb = *edit_baton; + if (eb) + eb->callback = callback; + + return ret_val; +} + + +svn_error_t * svn_repos_get_commit_editor (const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, Index: subversion/libsvn_ra_svn/client.c =================================================================== --- subversion/libsvn_ra_svn/client.c (revision 15181) +++ subversion/libsvn_ra_svn/client.c (working copy) @@ -1608,6 +1608,7 @@ ra_svn_unlock, ra_svn_get_lock, ra_svn_get_locks, + NULL, }; svn_error_t * Index: subversion/libsvn_ra_dav/merge.c =================================================================== --- subversion/libsvn_ra_dav/merge.c (revision 15181) +++ subversion/libsvn_ra_dav/merge.c (working copy) @@ -58,6 +58,8 @@ { "DAV:", "collection", ELEM_collection, 0 }, { "DAV:", "baseline", ELEM_baseline, 0 }, { "DAV:", "version-name", ELEM_version_name, SVN_RA_DAV__XML_CDATA }, + { SVN_XML_NAMESPACE, "post-commit-err", + ELEM_post_commit_err, SVN_RA_DAV__XML_CDATA }, { "DAV:", "creationdate", ELEM_creationdate, SVN_RA_DAV__XML_CDATA }, { "DAV:", "creator-displayname", ELEM_creator_displayname, SVN_RA_DAV__XML_CDATA }, @@ -104,6 +106,8 @@ svn_stringbuf_t *committed_date; /* DAV:creationdate for this resource */ svn_stringbuf_t *last_author; /* DAV:creator-displayname for this resource */ + svn_stringbuf_t *post_commit_err;/* SVN_XML_NAMESPACE:post-commit hook's + stderr */ /* We only invoke set_prop() on targets listed in valid_targets. Some entities (such as directories that have had changes @@ -341,6 +345,7 @@ || child == ELEM_version_name || child == ELEM_creationdate || child == ELEM_creator_displayname + || child == ELEM_post_commit_err /* other props */) return SVN_RA_DAV__XML_VALID; else @@ -524,6 +529,10 @@ svn_stringbuf_set(mc->vsn_name, cdata); break; + case ELEM_post_commit_err: + svn_stringbuf_set(mc->post_commit_err, cdata); + break; + case ELEM_creationdate: svn_stringbuf_set(mc->committed_date, cdata); break; @@ -637,10 +646,11 @@ -svn_error_t * svn_ra_dav__merge_activity( +svn_error_t * svn_ra_dav__merge_activity2 ( svn_revnum_t *new_rev, const char **committed_date, const char **committed_author, + const char **post_commit_err, svn_ra_dav__session_t *ras, const char *repos_url, const char *activity_url, @@ -670,7 +680,10 @@ mc.vsn_url = MAKE_BUFFER(pool); mc.committed_date = MAKE_BUFFER(pool); mc.last_author = MAKE_BUFFER(pool); + if (post_commit_err) + mc.post_commit_err = MAKE_BUFFER(pool); + if (disable_merge_response || (! keep_locks)) { @@ -727,7 +740,39 @@ *committed_author = mc.last_author->len ? apr_pstrdup(pool, mc.last_author->data) : NULL; + if (post_commit_err) + *post_commit_err = mc.post_commit_err->len + ? apr_pstrdup(pool, mc.post_commit_err->data) : NULL; + svn_pool_destroy(mc.scratchpool); return NULL; } + + +svn_error_t * svn_ra_dav__merge_activity ( + svn_revnum_t *new_rev, + const char **committed_date, + const char **committed_author, + svn_ra_dav__session_t *ras, + const char *repos_url, + const char *activity_url, + apr_hash_t *valid_targets, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_boolean_t disable_merge_response, + apr_pool_t *pool) +{ + return svn_ra_dav__merge_activity2 (new_rev, + committed_date, + committed_author, + NULL, + ras, + repos_url, + activity_url, + valid_targets, + lock_tokens, + keep_locks, + disable_merge_response, + pool); +} Index: subversion/libsvn_ra_dav/ra_dav.h =================================================================== --- subversion/libsvn_ra_dav/ra_dav.h (revision 15181) +++ subversion/libsvn_ra_dav/ra_dav.h (working copy) @@ -215,6 +215,20 @@ svn_string_t **value, apr_pool_t *pool); +svn_error_t * svn_ra_dav__get_commit_editor2 ( + svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); + +/** To be removed once ra_local and ra_svn start + * using svn_ra_dav__get_commit_editor2 + */ svn_error_t * svn_ra_dav__get_commit_editor( svn_ra_session_t *session, const svn_delta_editor_t **editor, @@ -657,6 +671,7 @@ ELEM_updated_set, ELEM_vcc, ELEM_version_name, + ELEM_post_commit_err, ELEM_error, /* SVN elements */ @@ -707,6 +722,24 @@ }; /* ### docco */ +svn_error_t * svn_ra_dav__merge_activity2 ( + svn_revnum_t *new_rev, + const char **committed_date, + const char **committed_author, + const char **post_commit_err, + svn_ra_dav__session_t *ras, + const char *repos_url, + const char *activity_url, + apr_hash_t *valid_targets, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + svn_boolean_t disable_merge_response, + apr_pool_t *pool); + +/** Kept for the time being. + * Should be removed once all usages are + * svn_ra_dav__merge_activity2 + */ svn_error_t * svn_ra_dav__merge_activity( svn_revnum_t *new_rev, const char **committed_date, Index: subversion/libsvn_ra_dav/session.c =================================================================== --- subversion/libsvn_ra_dav/session.c (revision 15181) +++ subversion/libsvn_ra_dav/session.c (working copy) @@ -1529,7 +1529,7 @@ svn_ra_dav__change_rev_prop, svn_ra_dav__rev_proplist, svn_ra_dav__rev_prop, - svn_ra_dav__get_commit_editor, + NULL, svn_ra_dav__get_file, svn_ra_dav__get_dir, svn_ra_dav__do_update, @@ -1547,6 +1547,7 @@ svn_ra_dav__unlock, svn_ra_dav__get_lock, svn_ra_dav__get_locks, + svn_ra_dav__get_commit_editor2, }; svn_error_t * Index: subversion/libsvn_ra_dav/commit.c =================================================================== --- subversion/libsvn_ra_dav/commit.c (revision 15181) +++ subversion/libsvn_ra_dav/commit.c (working copy) @@ -126,6 +126,9 @@ /* A context for neon COPY request callbacks. */ struct copy_baton *cb; + /* The commit callback and baton */ + svn_commit_callback2_t callback2; + } commit_ctx_t; typedef struct @@ -1463,24 +1466,30 @@ svn_revnum_t new_rev; const char *committed_date; const char *committed_author; + const char *post_commit_err; - SVN_ERR( svn_ra_dav__merge_activity(&new_rev, - &committed_date, - &committed_author, - cc->ras, - cc->ras->root.path, - cc->activity_url, - cc->valid_targets, - cc->tokens, - cc->keep_locks, - cc->disable_merge_response, - pool) ); + SVN_ERR( svn_ra_dav__merge_activity2 (&new_rev, + &committed_date, + &committed_author, + &post_commit_err, + cc->ras, + cc->ras->root.path, + cc->activity_url, + cc->valid_targets, + cc->tokens, + cc->keep_locks, + cc->disable_merge_response, + pool) ); SVN_ERR( delete_activity(edit_baton, pool) ); SVN_ERR( svn_ra_dav__maybe_store_auth_info(cc->ras) ); if (new_rev != SVN_INVALID_REVNUM) - SVN_ERR( cc->callback (new_rev, committed_date, committed_author, - cc->callback_baton)); + if ( cc->callback2) + SVN_ERR( cc->callback2 (new_rev, committed_date, committed_author, + post_commit_err, cc->callback_baton)); + else + SVN_ERR( cc->callback (new_rev, committed_date, committed_author, + cc->callback_baton)); return SVN_NO_ERROR; } @@ -1569,15 +1578,15 @@ return SVN_NO_ERROR; } -svn_error_t * svn_ra_dav__get_commit_editor(svn_ra_session_t *session, - const svn_delta_editor_t **editor, - void **edit_baton, - const char *log_msg, - svn_commit_callback_t callback, - void *callback_baton, - apr_hash_t *lock_tokens, - svn_boolean_t keep_locks, - apr_pool_t *pool) +svn_error_t * svn_ra_dav__get_commit_editor2 (svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool) { svn_ra_dav__session_t *ras = session->priv; svn_delta_editor_t *commit_editor; @@ -1596,7 +1605,7 @@ cc->push_func = ras->callbacks->push_wc_prop; cc->cb_baton = ras->callback_baton; cc->log_msg = log_msg; - cc->callback = callback; + cc->callback2 = callback; cc->callback_baton = callback_baton; cc->tokens = lock_tokens; cc->keep_locks = keep_locks; @@ -1655,3 +1664,34 @@ *edit_baton = cc; return SVN_NO_ERROR; } + +svn_error_t * svn_ra_dav__get_commit_editor(svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool) +{ + svn_error_t *ret_val = NULL; + commit_ctx_t *cc; + + ret_val = svn_ra_dav__get_commit_editor2 (session, + editor, + edit_baton, + log_msg, + NULL, + callback_baton, + lock_tokens, + keep_locks, + pool); + + /* Also set the old version for callback */ + cc = *edit_baton; + if (cc) + cc->callback = callback ; + + return ret_val; +}