static svn_error_t * invoke_commit_cb(svn_commit_callback2_t commit_cb, void *commit_baton, svn_fs_t *fs, svn_revnum_t revision, const char *post_commit_errstr, apr_pool_t *scratch_pool) { /* FS interface returns non-const values. */ /* const */ svn_string_t *date; /* const */ svn_string_t *author; svn_commit_info_t *commit_info; if (commit_cb == NULL) return SVN_NO_ERROR; SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE, scratch_pool)); SVN_ERR(svn_fs_revision_prop(&author, fs, revision, SVN_PROP_REVISION_AUTHOR, scratch_pool)); commit_info = svn_create_commit_info(scratch_pool); /* fill up the svn_commit_info structure */ commit_info->revision = revision; commit_info->date = date ? date->data : NULL; commit_info->author = author ? author->data : NULL; commit_info->post_commit_err = post_commit_errstr; /* commit_info->repos_root is not set by the repos layer, only by RA layers */ return svn_error_trace(commit_cb(commit_info, commit_baton, scratch_pool)); }
svn_error_t * svn_ra_serf__run_merge(const svn_commit_info_t **commit_info, svn_ra_serf__session_t *session, const char *merge_resource_url, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { merge_context_t *merge_ctx; svn_ra_serf__handler_t *handler; svn_ra_serf__xml_context_t *xmlctx; merge_ctx = apr_pcalloc(scratch_pool, sizeof(*merge_ctx)); merge_ctx->pool = result_pool; merge_ctx->session = session; merge_ctx->merge_resource_url = merge_resource_url; merge_ctx->lock_tokens = lock_tokens; merge_ctx->keep_locks = keep_locks; /* We don't need the full merge response when working over HTTPv2. * Over HTTPv1, this response is only required with a non-null * svn_ra_push_wc_prop_func_t callback. */ merge_ctx->disable_merge_response = SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session) || session->wc_callbacks->push_wc_prop == NULL; merge_ctx->commit_info = svn_create_commit_info(result_pool); merge_ctx->merge_url = session->session_url.path; xmlctx = svn_ra_serf__xml_context_create(merge_ttable, NULL, merge_closed, NULL, merge_ctx, scratch_pool); handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL, scratch_pool); handler->method = "MERGE"; handler->path = merge_ctx->merge_url; handler->body_delegate = create_merge_body; handler->body_delegate_baton = merge_ctx; handler->body_type = "text/xml"; handler->header_delegate = setup_merge_headers; handler->header_delegate_baton = merge_ctx; merge_ctx->handler = handler; SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool)); if (handler->sline.code != 200) return svn_error_trace(svn_ra_serf__unexpected_status(handler)); *commit_info = merge_ctx->commit_info; /* Sanity check (Reported to be triggered by CodePlex's svnbridge) */ if (! SVN_IS_VALID_REVNUM(merge_ctx->commit_info->revision)) { return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL, _("The MERGE response did not include " "a new revision")); } merge_ctx->commit_info->repos_root = apr_pstrdup(result_pool, session->repos_root_str); return SVN_NO_ERROR; }
static svn_error_t * close_edit(void *edit_baton, apr_pool_t *pool) { struct edit_baton *eb = edit_baton; svn_revnum_t new_revision = SVN_INVALID_REVNUM; svn_error_t *err; const char *conflict; const char *post_commit_err = NULL; /* If no transaction has been created (ie. if open_root wasn't called before close_edit), abort the operation here with an error. */ if (! eb->txn) return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL, "No valid transaction supplied to close_edit"); /* Commit. */ err = svn_repos_fs_commit_txn(&conflict, eb->repos, &new_revision, eb->txn, pool); if (SVN_IS_VALID_REVNUM(new_revision)) { if (err) { /* If the error was in post-commit, then the commit itself succeeded. In which case, save the post-commit warning (to be reported back to the client, who will probably display it as a warning) and clear the error. */ post_commit_err = svn_repos__post_commit_error_str(err, pool); svn_error_clear(err); err = SVN_NO_ERROR; } } else { /* ### todo: we should check whether it really was a conflict, and return the conflict info if so? */ /* If the commit failed, it's *probably* due to a conflict -- that is, the txn being out-of-date. The filesystem gives us the ability to continue diddling the transaction and try again; but let's face it: that's not how the cvs or svn works from a user interface standpoint. Thus we don't make use of this fs feature (for now, at least.) So, in a nutshell: svn commits are an all-or-nothing deal. Each commit creates a new fs txn which either succeeds or is aborted completely. No second chances; the user simply needs to update and commit again :) */ eb->txn_aborted = TRUE; return svn_error_trace( svn_error_compose_create(err, svn_fs_abort_txn(eb->txn, pool))); } /* Pass new revision information to the caller's callback. */ { svn_string_t *date, *author; svn_commit_info_t *commit_info; /* Even if there was a post-commit hook failure, it's more serious if one of the calls here fails, so we explicitly check for errors here, while saving the possible post-commit error for later. */ err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos), new_revision, SVN_PROP_REVISION_DATE, pool); if (! err) { err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos), new_revision, SVN_PROP_REVISION_AUTHOR, pool); } if ((! err) && eb->commit_callback) { commit_info = svn_create_commit_info(pool); /* fill up the svn_commit_info structure */ commit_info->revision = new_revision; commit_info->date = date ? date->data : NULL; commit_info->author = author ? author->data : NULL; commit_info->post_commit_err = post_commit_err; err = (*eb->commit_callback)(commit_info, eb->commit_callback_baton, pool); } } return svn_error_trace(err); }
svn_error_t * svn_ra_serf__run_merge(const svn_commit_info_t **commit_info, svn_ra_serf__session_t *session, const char *merge_resource_url, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { merge_context_t *merge_ctx; svn_ra_serf__handler_t *handler; svn_ra_serf__xml_context_t *xmlctx; merge_ctx = apr_pcalloc(scratch_pool, sizeof(*merge_ctx)); merge_ctx->pool = result_pool; merge_ctx->session = session; merge_ctx->merge_resource_url = merge_resource_url; merge_ctx->lock_tokens = lock_tokens; merge_ctx->keep_locks = keep_locks; merge_ctx->commit_info = svn_create_commit_info(result_pool); merge_ctx->merge_url = session->session_url.path; xmlctx = svn_ra_serf__xml_context_create(merge_ttable, NULL, merge_closed, NULL, merge_ctx, scratch_pool); handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL, scratch_pool); handler->method = "MERGE"; handler->path = merge_ctx->merge_url; handler->body_delegate = create_merge_body; handler->body_delegate_baton = merge_ctx; handler->header_delegate = setup_merge_headers; handler->header_delegate_baton = merge_ctx; merge_ctx->handler = handler; SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool)); if (handler->sline.code != 200) return svn_error_trace(svn_ra_serf__unexpected_status(handler)); *commit_info = merge_ctx->commit_info; /* Sanity check (Reported to be triggered by CodePlex's svnbridge) */ if (! SVN_IS_VALID_REVNUM(merge_ctx->commit_info->revision)) { return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL, _("The MERGE response did not include " "a new revision")); } merge_ctx->commit_info->repos_root = apr_pstrdup(result_pool, session->repos_root_str); return SVN_NO_ERROR; }