static svn_error_t * 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 *log_msg, const apr_array_header_t *commit_items, const apr_hash_t *revprop_table, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, svn_commit_callback2_t commit_callback, void *commit_baton, apr_pool_t *pool) { apr_hash_t *commit_revprops; apr_hash_t *relpath_map = NULL; SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, log_msg, ctx, pool)); #ifdef ENABLE_EV2_SHIMS if (commit_items) { int i; apr_pool_t *iterpool = svn_pool_create(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_pool_clear(iterpool); SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, NULL, NULL, ctx->wc_ctx, item->path, FALSE, pool, iterpool)); if (relpath) svn_hash_sets(relpath_map, relpath, item->path); } svn_pool_destroy(iterpool); } #endif /* Fetch RA commit editor. */ SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session, svn_client__get_shim_callbacks(ctx->wc_ctx, 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)); return SVN_NO_ERROR; }
static svn_error_t * commit_tree(svn_ra_session_t *session, apr_pool_t *pool) { apr_hash_t *revprop_table = apr_hash_make(pool); const svn_delta_editor_t *editor; void *edit_baton; const char *repos_root_url; void *root_baton, *A_baton, *B_baton, *file_baton; SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, revprop_table, NULL, NULL, NULL, TRUE, pool)); SVN_ERR(svn_ra_get_repos_root(session, &repos_root_url, pool)); SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, pool, &root_baton)); SVN_ERR(editor->add_directory("A", root_baton, NULL, SVN_INVALID_REVNUM, pool, &A_baton)); SVN_ERR(editor->add_directory("A/B", A_baton, NULL, SVN_INVALID_REVNUM, pool, &B_baton)); SVN_ERR(editor->add_file("A/B/f", B_baton, NULL, SVN_INVALID_REVNUM, pool, &file_baton)); SVN_ERR(editor->close_file(file_baton, NULL, pool)); SVN_ERR(editor->add_file("A/B/g", B_baton, NULL, SVN_INVALID_REVNUM, pool, &file_baton)); SVN_ERR(editor->close_file(file_baton, NULL, pool)); SVN_ERR(editor->close_directory(B_baton, pool)); SVN_ERR(editor->add_directory("A/BB", A_baton, NULL, SVN_INVALID_REVNUM, pool, &B_baton)); SVN_ERR(editor->add_file("A/BB/f", B_baton, NULL, SVN_INVALID_REVNUM, pool, &file_baton)); SVN_ERR(editor->close_file(file_baton, NULL, pool)); SVN_ERR(editor->add_file("A/BB/g", B_baton, NULL, SVN_INVALID_REVNUM, pool, &file_baton)); SVN_ERR(editor->close_file(file_baton, NULL, pool)); SVN_ERR(editor->close_directory(B_baton, pool)); SVN_ERR(editor->close_directory(A_baton, pool)); SVN_ERR(editor->close_edit(edit_baton, pool)); return SVN_NO_ERROR; }
/* Commit some simple changes */ static svn_error_t * commit_changes(svn_ra_session_t *session, apr_pool_t *pool) { apr_hash_t *revprop_table = apr_hash_make(pool); const svn_delta_editor_t *editor; void *edit_baton; const char *repos_root_url; void *root_baton, *dir_baton; SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, revprop_table, NULL, NULL, NULL, TRUE, pool)); SVN_ERR(svn_ra_get_repos_root(session, &repos_root_url, pool)); SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, pool, &root_baton)); /* copy root-dir@0 to A@1 */ SVN_ERR(editor->add_directory("A", root_baton, repos_root_url, 0, pool, &dir_baton)); SVN_ERR(editor->close_edit(edit_baton, pool)); return SVN_NO_ERROR; }
static svn_error_t * new_node_record(void **node_baton, apr_hash_t *headers, void *revision_baton, apr_pool_t *pool) { struct revision_baton *rb = revision_baton; const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor; void *commit_edit_baton = rb->pb->commit_edit_baton; struct node_baton *nb; apr_hash_index_t *hi; void *child_baton; const char *nb_dirname; nb = apr_pcalloc(rb->pool, sizeof(*nb)); nb->rb = rb; nb->is_added = FALSE; nb->copyfrom_path = NULL; nb->copyfrom_url = NULL; nb->copyfrom_rev = SVN_INVALID_REVNUM; nb->prop_changes = apr_hash_make(rb->pool); /* If the creation of commit_editor is pending, create it now and open_root on it; also create a top-level directory baton. */ if (!commit_editor) { /* The revprop_table should have been filled in with important information like svn:log in set_revision_property. We can now use it all this information to create our commit_editor. But first, clear revprops that we aren't allowed to set with the commit_editor. We'll set them separately using the RA API after closing the editor (see close_revision). */ svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_AUTHOR, NULL); svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_DATE, NULL); SVN_ERR(svn_ra__register_editor_shim_callbacks(rb->pb->session, get_shim_callbacks(rb, rb->pool))); SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor, &commit_edit_baton, rb->revprop_table, commit_callback, revision_baton, NULL, FALSE, rb->pool)); rb->pb->commit_editor = commit_editor; rb->pb->commit_edit_baton = commit_edit_baton; SVN_ERR(commit_editor->open_root(commit_edit_baton, rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); LDR_DBG(("Opened root %p\n", child_baton)); /* child_baton corresponds to the root directory baton here */ push_directory(rb, child_baton, "", TRUE /*is_added*/, NULL, SVN_INVALID_REVNUM); } for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi)) { const char *hname = svn__apr_hash_index_key(hi); const char *hval = svn__apr_hash_index_val(hi); /* Parse the different kinds of headers we can encounter and stuff them into the node_baton for writing later */ if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_PATH) == 0) nb->path = apr_pstrdup(rb->pool, hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_KIND) == 0) nb->kind = strcmp(hval, "file") == 0 ? svn_node_file : svn_node_dir; if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_ACTION) == 0) { if (strcmp(hval, "add") == 0) nb->action = svn_node_action_add; if (strcmp(hval, "change") == 0) nb->action = svn_node_action_change; if (strcmp(hval, "delete") == 0) nb->action = svn_node_action_delete; if (strcmp(hval, "replace") == 0) nb->action = svn_node_action_replace; } if (strcmp(hname, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5) == 0) nb->base_checksum = apr_pstrdup(rb->pool, hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV) == 0) nb->copyfrom_rev = atoi(hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH) == 0) nb->copyfrom_path = apr_pstrdup(rb->pool, hval); } nb_dirname = svn_relpath_dirname(nb->path, pool); if (svn_path_compare_paths(nb_dirname, rb->db->relpath) != 0) { char *ancestor_path; apr_size_t residual_close_count; apr_array_header_t *residual_open_path; int i; apr_size_t n; /* Before attempting to handle the action, call open_directory for all the path components and set the directory baton accordingly */ ancestor_path = svn_relpath_get_longest_ancestor(nb_dirname, rb->db->relpath, pool); residual_close_count = svn_path_component_count(svn_relpath_skip_ancestor(ancestor_path, rb->db->relpath)); residual_open_path = svn_path_decompose(svn_relpath_skip_ancestor(ancestor_path, nb_dirname), pool); /* First close all as many directories as there are after skip_ancestor, and then open fresh directories */ for (n = 0; n < residual_close_count; n ++) { /* Don't worry about destroying the actual rb->db object, since the pool we're using has the lifetime of one revision anyway */ LDR_DBG(("Closing dir %p\n", rb->db->baton)); SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool)); rb->db = rb->db->parent; } for (i = 0; i < residual_open_path->nelts; i ++) { char *relpath_compose = svn_relpath_join(rb->db->relpath, APR_ARRAY_IDX(residual_open_path, i, const char *), rb->pool); SVN_ERR(commit_editor->open_directory(relpath_compose, rb->db->baton, rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); LDR_DBG(("Opened dir %p\n", child_baton)); push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/, NULL, SVN_INVALID_REVNUM); } }
} SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items, ctx, pool)); if (! log_msg) return SVN_NO_ERROR; } else log_msg = ""; SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, log_msg, ctx, pool)); /* Fetch RA commit editor */ SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton, commit_revprops, 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, relpaths, path_driver_cb_func, (void *)editor, pool); if (err) { return svn_error_trace( svn_error_compose_create(err, editor->abort_edit(edit_baton, pool))); }
static svn_error_t * propset_on_url(const char *propname, const svn_string_t *propval, const char *target, svn_boolean_t skip_checks, svn_revnum_t base_revision_for_url, const apr_hash_t *revprop_table, svn_commit_callback2_t commit_callback, void *commit_baton, svn_client_ctx_t *ctx, apr_pool_t *pool) { enum svn_prop_kind prop_kind = svn_property_kind(NULL, propname); svn_ra_session_t *ra_session; svn_node_kind_t node_kind; const char *message; const svn_delta_editor_t *editor; void *edit_baton; apr_hash_t *commit_revprops; svn_error_t *err; if (prop_kind != svn_prop_regular_kind) return svn_error_createf (SVN_ERR_BAD_PROP_KIND, NULL, _("Property '%s' is not a regular property"), propname); /* Open an RA session for the URL. Note that we don't have a local directory, nor a place to put temp files. */ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, target, NULL, NULL, FALSE, TRUE, ctx, pool)); SVN_ERR(svn_ra_check_path(ra_session, "", base_revision_for_url, &node_kind, pool)); if (node_kind == svn_node_none) return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL, _("Path '%s' does not exist in revision %ld"), target, base_revision_for_url); /* Setting an inappropriate property is not allowed (unless overridden by 'skip_checks', in some circumstances). Deleting an inappropriate property is allowed, however, since older clients allowed (and other clients possibly still allow) setting it in the first place. */ if (propval && svn_prop_is_svn_prop(propname)) { const svn_string_t *new_value; struct getter_baton gb; gb.ra_session = ra_session; gb.base_revision_for_url = base_revision_for_url; SVN_ERR(svn_wc_canonicalize_svn_prop(&new_value, propname, propval, target, node_kind, skip_checks, get_file_for_validation, &gb, pool)); propval = new_value; } /* Create a new commit item and add it to the array. */ if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx)) { svn_client_commit_item3_t *item; const char *tmp_file; apr_array_header_t *commit_items = apr_array_make(pool, 1, sizeof(item)); item = svn_client_commit_item3_create(pool); item->url = target; item->state_flags = SVN_CLIENT_COMMIT_ITEM_PROP_MODS; APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item; SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items, ctx, pool)); if (! message) return SVN_NO_ERROR; } else message = ""; SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table, message, ctx, pool)); /* Fetch RA commit editor. */ SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton, commit_revprops, commit_callback, commit_baton, NULL, TRUE, /* No lock tokens */ pool)); err = do_url_propset(propname, propval, node_kind, base_revision_for_url, editor, edit_baton, pool); if (err) { /* At least try to abort the edit (and fs txn) before throwing err. */ svn_error_clear(editor->abort_edit(edit_baton, pool)); return svn_error_trace(err); } /* Close the edit. */ return editor->close_edit(edit_baton, pool); }