Author: rhuijben
Date: Sat Dec 14 17:09:14 2013
New Revision: 1550940
URL: http://svn.apache.org/r1550940
Log:
Following up on r1550848 and r1550938, automatically anchor the mtcc handling
on an ancestor when that is needed for certain operations.
* subversion/include/svn_client.h
(svn_client_mtcc_get_relpath): Remove function.
(svn_client_mtcc_check_path): Add argument.
* subversion/libsvn_client/mtcc.c
(svn_client_mtcc_get_relpath): Rename to ...
(mtcc_reparent): ... this function. Make static and make the new url
an argument instead of calculating it.
(mtcc_verify_create): Allow creating the "" path if there is no operation
recorded yet. Update caller.
(svn_client_mtcc_add_add_file,
svn_client_mtcc_add_delete,
svn_client_mtcc_add_mkdir,
svn_client_mtcc_add_propset,
svn_client_mtcc_add_update_file): Support adding "" when no operation is
recorded yet.
(svn_client_mtcc_check_path): Allow verifying the recorded node kind with
the repository kind.
* subversion/libsvn_client/mtcc.h
(svn_client_mtcc_op_t): Add boolean.
(MTCC_UNMODIFIED): New macro.
* subversion/tests/libsvn_client/mtcc-test.c
(cstr_stream): New helper function.
(make_greek_tree,
test_update_files): Update caller.
(test_anchoring): New test.
(test_funcs): Add test_anchoring.
Modified:
subversion/trunk/subversion/include/svn_client.h
subversion/trunk/subversion/libsvn_client/mtcc.c
subversion/trunk/subversion/libsvn_client/mtcc.h
subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c
Modified: subversion/trunk/subversion/include/svn_client.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1550940&r1=1550939&r2=1550940&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Sat Dec 14 17:09:14 2013
@@ -6686,18 +6686,6 @@ svn_client_mtcc_create(svn_client_mtcc_t
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/** Calculates a relative path @a *relpath for @a url, reparenting the
- * @a mtcc to a higher anchor url if necessary.
- *
- * @since New in 1.9.
- */
-svn_error_t *
-svn_client_mtcc_get_relpath(const char **relpath,
- const char *url,
- svn_client_mtcc_t *mtcc,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
/** Adds a file add operation of @a relpath to @a mtcc. If @a src_checksum
* is not null it will be provided to the repository to verify if the file
* was transfered succesfull.
@@ -6817,6 +6805,9 @@ svn_client_mtcc_add_update_file(const ch
* This value might be from the cache (in case of modifications, copies)
* or fetched from the repository.
*
+ * If @a check_repository is TRUE, verify the node type with the repository at
+ * least once and cache the result for further checks.
+ *
* When a node does not exist this functions sets @a *kind to @c svn_node_node.
*
* @since New in 1.9.
@@ -6824,6 +6815,7 @@ svn_client_mtcc_add_update_file(const ch
svn_error_t *
svn_client_mtcc_check_path(svn_node_kind_t *kind,
const char *relpath,
+ svn_boolean_t check_repository,
svn_client_mtcc_t *mtcc,
apr_pool_t *scratch_pool);
Modified: subversion/trunk/subversion/libsvn_client/mtcc.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mtcc.c?rev=1550940&r1=1550939&r2=1550940&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mtcc.c (original)
+++ subversion/trunk/subversion/libsvn_client/mtcc.c Sat Dec 14 17:09:14 2013
@@ -287,44 +287,34 @@ update_copy_src(svn_client_mtcc_op_t *op
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_client_mtcc_get_relpath(const char **relpath,
- const char *url,
- svn_client_mtcc_t *mtcc,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+static svn_error_t *
+mtcc_reparent(const char *new_anchor_url,
+ svn_client_mtcc_t *mtcc,
+ apr_pool_t *scratch_pool)
{
- svn_error_t *err;
- const char *new_anchor;
const char *session_url;
const char *up;
- err = svn_ra_get_path_relative_to_session(mtcc->ra_session, relpath, url,
- result_pool);
-
- if (! err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
- return svn_error_trace(err);
-
- svn_error_clear(err);
-
SVN_ERR(svn_ra_get_session_url(mtcc->ra_session, &session_url,
scratch_pool));
- new_anchor = svn_uri_get_longest_ancestor(url, session_url, scratch_pool);
+ up = svn_uri_skip_ancestor(new_anchor_url, session_url, scratch_pool);
- if (svn_path_is_empty(new_anchor))
+ if (! up)
{
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("'%s' is not in the same repository as '%s'"),
- url, session_url);
+ _("'%s' is not an ancestor of '%s'"),
+ new_anchor_url, session_url);
+ }
+ else if (!*up)
+ {
+ return SVN_NO_ERROR; /* Same url */
}
-
- up = svn_uri_skip_ancestor(new_anchor, session_url, scratch_pool);
/* Update copy origins recursively...:( */
SVN_ERR(update_copy_src(mtcc->root_op, up, mtcc->pool));
- SVN_ERR(svn_ra_reparent(mtcc->ra_session, new_anchor, scratch_pool));
+ SVN_ERR(svn_ra_reparent(mtcc->ra_session, new_anchor_url, scratch_pool));
/* Create directory open operations for new ancestors */
while (*up)
@@ -342,9 +332,7 @@ svn_client_mtcc_get_relpath(const char *
mtcc->root_op = root_op;
}
- return svn_error_trace(
- svn_ra_get_path_relative_to_session(mtcc->ra_session, relpath, url,
- result_pool));
+ return SVN_NO_ERROR;
}
/* Check if it is safe to create a new node at NEW_RELPATH. Return a proper
@@ -354,26 +342,32 @@ mtcc_verify_create(svn_client_mtcc_t *mt
const char *new_relpath,
apr_pool_t *scratch_pool)
{
- svn_client_mtcc_op_t *op;
svn_node_kind_t kind;
- SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, FALSE,
- FALSE, mtcc->pool, scratch_pool));
+ if (*new_relpath || !MTCC_UNMODIFIED(mtcc))
+ {
+ svn_client_mtcc_op_t *op;
- if (op)
- return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
- _("Can't copy to '%s': target already operated
on"),
- new_relpath);
+ SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, FALSE,
+ FALSE, mtcc->pool, scratch_pool));
- SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, TRUE,
- FALSE, mtcc->pool, scratch_pool));
+ if (op)
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+ _("Can't create '%s': target already "
+ "operated on"),
+ new_relpath);
- if (op)
- return SVN_NO_ERROR; /* Node is explicitly deleted. We can replace */
+ SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, TRUE,
+ FALSE, mtcc->pool, scratch_pool));
+
+ if (op)
+ return SVN_NO_ERROR; /* Node is explicitly deleted. We can replace */
+ }
/* mod_dav_svn allows overwriting existing directories. Let's hide that
for users of this api */
- SVN_ERR(svn_client_mtcc_check_path(&kind, new_relpath, mtcc, scratch_pool));
+ SVN_ERR(svn_client_mtcc_check_path(&kind, new_relpath, FALSE,
+ mtcc, scratch_pool));
if (kind != svn_node_none)
return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
@@ -397,14 +391,22 @@ svn_client_mtcc_add_add_file(const char
SVN_ERR(mtcc_verify_create(mtcc, relpath, scratch_pool));
- SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, FALSE,
- TRUE, mtcc->pool, scratch_pool));
-
- if (!op || !created)
+ if (!*relpath && MTCC_UNMODIFIED(mtcc))
{
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Can't add file at '%s'"),
- relpath);
+ /* Turn the root operation into a file addition */
+ op = mtcc->root_op;
+ }
+ else
+ {
+ SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, FALSE,
+ TRUE, mtcc->pool, scratch_pool));
+
+ if (!op || !created)
+ {
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Can't add file at '%s'"),
+ relpath);
+ }
}
op->kind = OP_ADD_FILE;
@@ -472,7 +474,8 @@ svn_client_mtcc_add_delete(const char *r
SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
- SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, mtcc, scratch_pool));
+ SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, FALSE,
+ mtcc, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
@@ -480,17 +483,27 @@ svn_client_mtcc_add_delete(const char *r
"does not exist"),
relpath);
- SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, TRUE,
- TRUE, mtcc->pool, scratch_pool));
-
- if (!op || !created)
+ if (! *relpath || MTCC_UNMODIFIED(mtcc))
{
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Can't delete node at '%s'"),
- relpath);
+ /* Turn root operation into delete */
+ op = mtcc->root_op;
+ }
+ else
+ {
+ SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, TRUE,
+ TRUE, mtcc->pool, scratch_pool));
+
+ if (!op || !created)
+ {
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Can't delete node at '%s'"),
+ relpath);
+ }
}
op->kind = OP_DELETE;
+ op->children = NULL;
+ op->prop_mods = NULL;
return SVN_NO_ERROR;
}
@@ -506,6 +519,14 @@ svn_client_mtcc_add_mkdir(const char *re
SVN_ERR(mtcc_verify_create(mtcc, relpath, scratch_pool));
+ if (! *relpath && MTCC_UNMODIFIED(mtcc))
+ {
+ /* Turn the root of the operation in an MKDIR */
+ mtcc->root_op->kind = OP_ADD_DIR;
+
+ return SVN_NO_ERROR;
+ }
+
SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, FALSE,
FALSE, mtcc->pool, scratch_pool));
@@ -581,29 +602,50 @@ svn_client_mtcc_add_propset(const char *
/* ### TODO: Call svn_wc_canonicalize_svn_prop() */
}
- SVN_ERR(mtcc_op_find(&op, NULL, relpath, mtcc->root_op, TRUE, FALSE,
- FALSE, mtcc->pool, scratch_pool));
-
- if (!op)
+ if (!*relpath && MTCC_UNMODIFIED(mtcc))
{
svn_node_kind_t kind;
- svn_boolean_t created;
- /* ### TODO: Check if this node is within a newly copied directory,
- and update origin values accordingly */
+ /* Probing the node for an unmodified root will fix the node type to
+ a file if necessary */
- SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, mtcc, scratch_pool));
+ SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, FALSE,
+ mtcc, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("Can't set properties at not existing
'%s'"),
- relpath);
+ relpath);
+
+ op = mtcc->root_op;
+ }
+ else
+ {
+ SVN_ERR(mtcc_op_find(&op, NULL, relpath, mtcc->root_op, TRUE, FALSE,
+ FALSE, mtcc->pool, scratch_pool));
- SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, TRUE, FALSE,
- (kind != svn_node_dir),
- mtcc->pool, scratch_pool));
+ if (!op)
+ {
+ svn_node_kind_t kind;
+ svn_boolean_t created;
+
+ /* ### TODO: Check if this node is within a newly copied directory,
+ and update origin values accordingly */
+
+ SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, FALSE,
+ mtcc, scratch_pool));
- SVN_ERR_ASSERT(op != NULL);
+ if (kind == svn_node_none)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Can't set properties at not existing
'%s'"),
+ relpath);
+
+ SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, TRUE,
FALSE,
+ (kind != svn_node_dir),
+ mtcc->pool, scratch_pool));
+
+ SVN_ERR_ASSERT(op != NULL);
+ }
}
if (!op->prop_mods)
@@ -638,7 +680,8 @@ svn_client_mtcc_add_update_file(const ch
svn_node_kind_t kind;
SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath) && src_stream);
- SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, mtcc, scratch_pool));
+ SVN_ERR(svn_client_mtcc_check_path(&kind, relpath, FALSE,
+ mtcc, scratch_pool));
if (kind != svn_node_file)
return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
@@ -671,6 +714,7 @@ svn_client_mtcc_add_update_file(const ch
svn_error_t *
svn_client_mtcc_check_path(svn_node_kind_t *kind,
const char *relpath,
+ svn_boolean_t check_repository,
svn_client_mtcc_t *mtcc,
apr_pool_t *scratch_pool)
{
@@ -680,32 +724,77 @@ svn_client_mtcc_check_path(svn_node_kind
SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ if (!*relpath
+ && !mtcc->root_op->performed_stat
+ && MTCC_UNMODIFIED(mtcc))
+ {
+ /* We know nothing about the root. Perhaps it is a file? */
+ SVN_ERR(svn_ra_check_path(mtcc->ra_session, "", mtcc->base_revision,
+ kind, scratch_pool));
+
+ mtcc->root_op->performed_stat = TRUE;
+ if (*kind == svn_node_file)
+ {
+ mtcc->root_op->kind = OP_OPEN_FILE;
+ mtcc->root_op->children = NULL;
+ }
+ return SVN_NO_ERROR;
+ }
+
SVN_ERR(mtcc_op_find(&op, NULL, relpath, mtcc->root_op, TRUE, FALSE,
FALSE, mtcc->pool, scratch_pool));
- if (op)
+ if (!op || (check_repository && !op->performed_stat))
{
- if (op->kind == OP_OPEN_DIR || op->kind == OP_ADD_DIR)
+ SVN_ERR(svn_client_mtcc_get_origin(&origin_relpath, &origin_rev,
+ relpath, mtcc,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_ra_check_path(mtcc->ra_session, origin_relpath,
+ origin_rev, kind, scratch_pool));
+
+ if (op && *kind == svn_node_dir)
{
- *kind = svn_node_dir;
- return SVN_NO_ERROR;
+ if (op->kind == OP_OPEN_DIR || op->kind == OP_ADD_DIR)
+ op->performed_stat = TRUE;
+ else if (op->kind == OP_OPEN_FILE || op->kind == OP_ADD_FILE)
+ return svn_error_createf(SVN_ERR_FS_NOT_DIRECTORY, NULL,
+ _("Can't perform directory operation "
+ "on '%s' as it is not a directory"),
+ relpath);
}
- else if (op->kind == OP_OPEN_FILE || op->kind == OP_ADD_FILE)
+ else if (op && *kind == svn_node_dir)
{
- *kind = svn_node_file;
- return SVN_NO_ERROR;
+ if (op->kind == OP_OPEN_FILE || op->kind == OP_ADD_FILE)
+ op->performed_stat = TRUE;
+ else if (op->kind == OP_OPEN_DIR || op->kind == OP_ADD_DIR)
+ return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
+ _("Can't perform file operation "
+ "on '%s' as it is not a file"),
+ relpath);
+ }
+ else if (op && (op->kind == OP_OPEN_DIR || op->kind == OP_OPEN_FILE))
+ {
+ return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+ _("Can't open '%s' as it does not exist"),
+ relpath);
}
- SVN_ERR_MALFUNCTION(); /* No other kinds defined as delete is filtered */
- }
-
- SVN_ERR(svn_client_mtcc_get_origin(&origin_relpath, &origin_rev,
- relpath, mtcc,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_ra_check_path(mtcc->ra_session, origin_relpath,
- origin_rev, kind, scratch_pool));
+ return SVN_NO_ERROR;
+ }
- return SVN_NO_ERROR;
+ /* op != NULL */
+ if (op->kind == OP_OPEN_DIR || op->kind == OP_ADD_DIR)
+ {
+ *kind = svn_node_dir;
+ return SVN_NO_ERROR;
+ }
+ else if (op->kind == OP_OPEN_FILE || op->kind == OP_ADD_FILE)
+ {
+ *kind = svn_node_file;
+ return SVN_NO_ERROR;
+ }
+ SVN_ERR_MALFUNCTION(); /* No other kinds defined as delete is filtered */
}
static svn_error_t *
@@ -981,6 +1070,20 @@ svn_client_mtcc_commit(apr_hash_t *revpr
SVN_ERR(svn_ra_get_session_url(mtcc->ra_session, &session_url,
scratch_pool));
+ if (mtcc->root_op->kind != OP_OPEN_DIR)
+ {
+ const char *name;
+
+ svn_uri_split(&session_url, &name, session_url, scratch_pool);
+
+ if (*name)
+ {
+ SVN_ERR(mtcc_reparent(session_url, mtcc, scratch_pool));
+
+ SVN_ERR(svn_ra_reparent(mtcc->ra_session, session_url,
scratch_pool));
+ }
+ }
+
/* Create new commit items and add them to the array. */
if (SVN_CLIENT__HAS_LOG_MSG_FUNC(mtcc->ctx))
{
@@ -1004,6 +1107,40 @@ svn_client_mtcc_commit(apr_hash_t *revpr
SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
log_msg, mtcc->ctx, scratch_pool));
+ /* Ugly corner case: The ra session might have died while we were waiting
+ for the callback */
+ {
+ svn_node_kind_t kind;
+ svn_error_t *err = svn_ra_check_path(mtcc->ra_session, "",
+ mtcc->base_revision, &kind,
+ scratch_pool);
+
+ if (err)
+ {
+ svn_error_t *err2 = svn_client_open_ra_session2(&mtcc->ra_session,
+ session_url,
+ NULL, mtcc->ctx,
+ mtcc->pool,
+ scratch_pool);
+
+ if (err2)
+ {
+ svn_pool_destroy(mtcc->pool);
+ return svn_error_trace(svn_error_compose_create(err, err2));
+ }
+ svn_error_clear(err);
+
+ SVN_ERR(svn_ra_check_path(mtcc->ra_session, "",
+ mtcc->base_revision, &kind, scratch_pool));
+ }
+
+ if (kind != svn_node_dir)
+ return svn_error_createf(SVN_ERR_FS_NOT_DIRECTORY, NULL,
+ _("Can't commit to '%s' because it "
+ "is not a directory"),
+ session_url);
+ }
+
SVN_ERR(svn_ra_get_commit_editor3(mtcc->ra_session, &editor, &edit_baton,
commit_revprops,
commit_callback, commit_baton,
Modified: subversion/trunk/subversion/libsvn_client/mtcc.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mtcc.h?rev=1550940&r1=1550939&r2=1550940&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mtcc.h (original)
+++ subversion/trunk/subversion/libsvn_client/mtcc.h Sat Dec 14 17:09:14 2013
@@ -50,8 +50,15 @@ typedef struct svn_client_mtcc_op_t
apr_array_header_t *prop_mods; /* For all except DELETE
List of svn_prop_t */
+
+ svn_boolean_t performed_stat; /* Verified type with repository */
} svn_client_mtcc_op_t;
+/* Check if the mtcc doesn't contain any modifications yet */
+#define MTCC_UNMODIFIED(mtcc)
\
+ ((mtcc->root_op->kind == OP_OPEN_DIR)
\
+ && (mtcc->root_op->prop_mods == NULL || !mtcc->root_op->prop_mods->nelts)
\
+ && (mtcc->root_op->children == NULL || !mtcc->root_op->children->nelts))
struct svn_client_mtcc_t
{
Modified: subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c?rev=1550940&r1=1550939&r2=1550940&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c Sat Dec 14
17:09:14 2013
@@ -52,6 +52,13 @@ verify_commit_callback(const svn_commit_
return SVN_NO_ERROR;
}
+/* Create a stream from a c string */
+static svn_stream_t *
+cstr_stream(const char *data, apr_pool_t *result_pool)
+{
+ return svn_stream_from_string(svn_string_create(data, result_pool),
+ result_pool);
+}
static svn_error_t *
verify_mtcc_commit(svn_client_mtcc_t *mtcc,
@@ -92,11 +99,9 @@ make_greek_tree(const char *repos_url,
{
SVN_ERR(svn_client_mtcc_add_add_file(
svn_test__greek_tree_nodes[i].path,
- svn_stream_from_string(
- svn_string_create(
+ cstr_stream(
svn_test__greek_tree_nodes[i].contents,
subpool),
- subpool),
NULL /* src_checksum */,
mtcc, subpool));
}
@@ -261,25 +266,17 @@ test_update_files(const svn_test_opts_t
/* Update iota with knowledge of the old data */
SVN_ERR(svn_client_mtcc_add_update_file(svn_test__greek_tree_nodes[0].path,
- svn_stream_from_string(
- svn_string_create(
- "new-iota", pool),
+ cstr_stream("new-iota", pool),
+ NULL,
+ cstr_stream(
+ svn_test__greek_tree_nodes[0]
+ .contents,
pool),
- NULL,
- svn_stream_from_string(
- svn_string_create(
- svn_test__greek_tree_nodes[0]
- .contents,
- pool),
- pool),
- NULL,
- mtcc, pool));
+ NULL,
+ mtcc, pool));
SVN_ERR(svn_client_mtcc_add_update_file("A/mu",
- svn_stream_from_string(
- svn_string_create(
- "new-MU", pool),
- pool),
+ cstr_stream("new-MU", pool),
NULL,
NULL, NULL,
mtcc, pool));
@@ -331,6 +328,94 @@ test_overwrite(const svn_test_opts_t *op
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_anchoring(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_client_mtcc_t *mtcc;
+ svn_client_ctx_t *ctx;
+ const char *repos_abspath;
+ const char *repos_url;
+ svn_repos_t* repos;
+
+ repos_abspath = svn_test_data_path("mtcc-anchoring", pool);
+ SVN_ERR(svn_dirent_get_absolute(&repos_abspath, repos_abspath, pool));
+ SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_abspath, pool));
+ SVN_ERR(svn_test__create_repos(&repos, repos_abspath, opts, pool));
+
+ SVN_ERR(make_greek_tree(repos_url, pool));
+
+ SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
+
+ /* Update a file as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "iota",
+ pool),
+ 1, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_update_file("",
+ cstr_stream("new-iota", pool),
+ NULL, NULL, NULL,
+ mtcc, pool));
+ SVN_ERR(svn_client_mtcc_add_propset("", "key",
+ svn_string_create("value", pool),
+ FALSE, mtcc, pool));
+
+ SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
+
+ /* Add a directory as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "BB",
+ pool),
+ 2, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_mkdir("", mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 3, pool));
+
+ /* Add a file as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "new",
+ pool),
+ 3, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_add_file("", cstr_stream("new", pool), NULL,
+ mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 4, pool));
+
+ /* Delete as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "new",
+ pool),
+ 4, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_delete("", mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 5, pool));
+
+ /* Propset file as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "A/mu",
+ pool),
+ 5, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_propset("", "key",
+ svn_string_create("val", pool),
+ FALSE, mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 6, pool));
+
+ /* Propset dir as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc,
+ svn_path_url_add_component2(repos_url, "A",
+ pool),
+ 6, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_propset("", "key",
+ svn_string_create("val", pool),
+ FALSE, mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 7, pool));
+
+ /* Propset reposroot as root operation */
+ SVN_ERR(svn_client_mtcc_create(&mtcc, repos_url, 7, ctx, pool, pool));
+ SVN_ERR(svn_client_mtcc_add_propset("", "key",
+ svn_string_create("val", pool),
+ FALSE, mtcc, pool));
+ SVN_ERR(verify_mtcc_commit(mtcc, 8, pool));
+
+ return SVN_NO_ERROR;
+}
/* ==========================================================================
*/
@@ -352,6 +437,8 @@ struct svn_test_descriptor_t test_funcs[
"test update files"),
SVN_TEST_OPTS_PASS(test_overwrite,
"test overwrite"),
+ SVN_TEST_OPTS_PASS(test_anchoring,
+ "test mtcc anchoring for root operations"),
SVN_TEST_NULL
};