You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/02/12 21:38:02 UTC
svn commit: r1659395 [2/2] - in /subversion/trunk: ./
contrib/client-side/svncopy/ notes/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/org/apache/subversion/javahl/
subversion/bindings/javahl/tests/org/apache/subversion/javahl/ sub...
Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Thu Feb 12 20:38:01 2015
@@ -68,6 +68,7 @@
* the revision if the revision is found. Set REV_IDX to the index in
* LINE_PARTS where the revision specification starts. Remove from
* LINE_PARTS the element(s) that specify the revision.
+ * Set REV_STR to the element that specifies the revision.
* PARENT_DIRECTORY_DISPLAY and LINE are given to return a nice error
* string.
*
@@ -76,6 +77,7 @@
*/
static svn_error_t *
find_and_remove_externals_revision(int *rev_idx,
+ const char **rev_str,
const char **line_parts,
int num_line_parts,
svn_wc_external_item2_t *item,
@@ -137,6 +139,8 @@ find_and_remove_externals_revision(int *
line_parts[j] = line_parts[j+shift_count];
line_parts[num_line_parts-shift_count] = NULL;
+ *rev_str = apr_psprintf(pool, "-r%s", digits_ptr);
+
/* Found the revision, so leave the function immediately, do
* not continue looking for additional revisions. */
return SVN_NO_ERROR;
@@ -158,7 +162,8 @@ find_and_remove_externals_revision(int *
}
svn_error_t *
-svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
+svn_wc__parse_externals_description(apr_array_header_t **externals_p,
+ apr_array_header_t **parser_infos_p,
const char *defining_directory,
const char *desc,
svn_boolean_t canonicalize_url,
@@ -166,6 +171,7 @@ svn_wc_parse_externals_description3(apr_
{
int i;
apr_array_header_t *externals = NULL;
+ apr_array_header_t *parser_infos = NULL;
apr_array_header_t *lines = svn_cstring_split(desc, "\n\r", TRUE, pool);
const char *defining_directory_display = svn_path_is_url(defining_directory) ?
defining_directory : svn_dirent_local_style(defining_directory, pool);
@@ -175,6 +181,10 @@ svn_wc_parse_externals_description3(apr_
if (externals_p)
externals = apr_array_make(pool, 1, sizeof(svn_wc_external_item2_t *));
+ if (parser_infos_p)
+ parser_infos =
+ apr_array_make(pool, 1, sizeof(svn_wc__externals_parser_info_t *));
+
for (i = 0; i < lines->nelts; i++)
{
const char *line = APR_ARRAY_IDX(lines, i, const char *);
@@ -186,10 +196,12 @@ svn_wc_parse_externals_description3(apr_
const char *token1;
svn_boolean_t token0_is_url;
svn_boolean_t token1_is_url;
+ svn_wc__externals_parser_info_t *info = NULL;
/* Index into line_parts where the revision specification
started. */
int rev_idx = -1;
+ const char *rev_str = NULL;
if ((! line) || (line[0] == '#'))
continue;
@@ -209,6 +221,9 @@ svn_wc_parse_externals_description3(apr_
item->revision.kind = svn_opt_revision_unspecified;
item->peg_revision.kind = svn_opt_revision_unspecified;
+ if (parser_infos)
+ info = apr_pcalloc(pool, sizeof(*info));
+
/*
* There are six different formats of externals:
*
@@ -240,6 +255,7 @@ svn_wc_parse_externals_description3(apr_
set item->revision to the parsed revision. */
/* ### ugh. stupid cast. */
SVN_ERR(find_and_remove_externals_revision(&rev_idx,
+ &rev_str,
(const char **)line_parts,
num_line_parts, item,
defining_directory_display,
@@ -290,12 +306,34 @@ svn_wc_parse_externals_description3(apr_
SVN_ERR(svn_opt_parse_path(&item->peg_revision, &item->url,
token0, pool));
item->target_dir = token1;
+
+ if (info)
+ {
+ info->format = svn_wc__external_description_format_2;
+
+ if (rev_str)
+ info->rev_str = apr_pstrdup(pool, rev_str);
+
+ if (item->peg_revision.kind != svn_opt_revision_unspecified)
+ info->peg_rev_str = strrchr(token0, '@');
+ }
}
else
{
item->target_dir = token0;
item->url = token1;
item->peg_revision = item->revision;
+
+ if (info)
+ {
+ info->format = svn_wc__external_description_format_1;
+
+ if (rev_str)
+ {
+ info->rev_str = apr_pstrdup(pool, rev_str);
+ info->peg_rev_str = info->rev_str;
+ }
+ }
}
SVN_ERR(svn_opt_resolve_revisions(&item->peg_revision,
@@ -333,15 +371,34 @@ svn_wc_parse_externals_description3(apr_
if (externals)
APR_ARRAY_PUSH(externals, svn_wc_external_item2_t *) = item;
+ if (parser_infos)
+ APR_ARRAY_PUSH(parser_infos, svn_wc__externals_parser_info_t *) = info;
}
if (externals_p)
*externals_p = externals;
+ if (parser_infos_p)
+ *parser_infos_p = parser_infos;
return SVN_NO_ERROR;
}
svn_error_t *
+svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
+ const char *defining_directory,
+ const char *desc,
+ svn_boolean_t canonicalize_url,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_wc__parse_externals_description(externals_p,
+ NULL,
+ defining_directory,
+ desc,
+ canonicalize_url,
+ pool));
+}
+
+svn_error_t *
svn_wc__externals_find_target_dups(apr_array_header_t **duplicate_targets,
apr_array_header_t *externals,
apr_pool_t *pool,
Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Thu Feb 12 20:38:01 2015
@@ -248,6 +248,7 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t remove_ignored; /* remove ignored items */
svn_boolean_t no_newline; /* do not output the trailing newline */
svn_boolean_t show_passwords; /* show cached passwords */
+ svn_boolean_t pin_externals; /* pin externals to last-changed revisions */
} svn_cl__opt_state_t;
Modified: subversion/trunk/subversion/svn/copy-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/copy-cmd.c?rev=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/copy-cmd.c (original)
+++ subversion/trunk/subversion/svn/copy-cmd.c Thu Feb 12 20:38:01 2015
@@ -167,8 +167,10 @@ svn_cl__copy(apr_getopt_t *os,
SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state,
NULL, ctx->config, pool));
- err = svn_client_copy6(sources, dst_path, TRUE,
+ err = svn_client_copy7(sources, dst_path, TRUE,
opt_state->parents, opt_state->ignore_externals,
+ opt_state->pin_externals,
+ NULL, /* pin all externals */
opt_state->revprop_table,
(opt_state->quiet ? NULL : svn_cl__print_commit_info),
NULL,
Modified: subversion/trunk/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/svn.c?rev=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/svn.c (original)
+++ subversion/trunk/subversion/svn/svn.c Thu Feb 12 20:38:01 2015
@@ -144,7 +144,8 @@ typedef enum svn_cl__longopt_t {
opt_remove_unversioned,
opt_remove_ignored,
opt_no_newline,
- opt_show_passwords
+ opt_show_passwords,
+ opt_pin_externals,
} svn_cl__longopt_t;
@@ -418,6 +419,10 @@ const apr_getopt_option_t svn_cl__option
{"remove-ignored", opt_remove_ignored, 0, N_("remove ignored items")},
{"no-newline", opt_no_newline, 0, N_("do not output the trailing newline")},
{"show-passwords", opt_show_passwords, 0, N_("show cached passwords")},
+ {"pin-externals", opt_pin_externals, 0,
+ N_("pin externals with no explicit revision to their\n"
+ " "
+ "current revision (recommended when tagging)")},
/* Long-opt Aliases
*
@@ -608,7 +613,8 @@ const svn_opt_subcommand_desc2_t svn_cl_
" contact the repository. As such, they may not, by default, be able\n"
" to propagate merge tracking information from the source of the copy\n"
" to the destination.\n"),
- {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS} },
+ {'r', 'q', opt_ignore_externals, opt_parents, SVN_CL__LOG_MSG_OPTIONS,
+ opt_pin_externals} },
{ "delete", svn_cl__delete, {"del", "remove", "rm"}, N_
("Remove files and directories from version control.\n"
@@ -2390,6 +2396,9 @@ sub_main(int *exit_code, int argc, const
case opt_show_passwords:
opt_state.show_passwords = TRUE;
break;
+ case opt_pin_externals:
+ opt_state.pin_externals = TRUE;
+ break;
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
Modified: subversion/trunk/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/externals_tests.py?rev=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/externals_tests.py Thu Feb 12 20:38:01 2015
@@ -3541,6 +3541,339 @@ def replace_tree_with_foreign_external(s
None, None, None, None, None, 1,
'-r', '2', wc_dir)
+
+def verify_pinned_externals(sbox, external_url_for, base_path_or_url,
+ external_youngest_rev, other_external_youngest_rev):
+ "helper for pin-externals tests"
+
+ expected_output = [
+ '%s@%d gamma\n' % (external_url_for["A/B/gamma"],
+ external_youngest_rev),
+ '\n',
+ ]
+ if svntest.sandbox.is_url(base_path_or_url):
+ target = base_path_or_url + '/A_copy/B'
+ else:
+ target = sbox.ospath('A_copy/B')
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'propget', 'svn:externals',
+ target)
+ expected_output = [
+ 'exdir_G -r%d %s\n' % (other_external_youngest_rev,
+ external_url_for["A/C/exdir_G"]),
+ '%s exdir_H\n' % external_url_for["A/C/exdir_H"],
+ '\n',
+ ]
+ if svntest.sandbox.is_url(base_path_or_url):
+ target = base_path_or_url + '/A_copy/C'
+ else:
+ target = sbox.ospath('A_copy/C')
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'propget', 'svn:externals',
+ target)
+ expected_output = [
+ '%s@%d exdir_A\n' % (external_url_for["A/D/exdir_A"],
+ other_external_youngest_rev),
+ '%s@%d exdir_A/G\n' % (external_url_for["A/D/exdir_A/G/"],
+ other_external_youngest_rev),
+ 'exdir_A/H -r1 %s\n' % external_url_for["A/D/exdir_A/H"],
+ '%s@%d x/y/z/blah\n' % (external_url_for["A/D/x/y/z/blah"],
+ other_external_youngest_rev),
+ '\n',
+ ]
+ if svntest.sandbox.is_url(base_path_or_url):
+ target = base_path_or_url + '/A_copy/D'
+ else:
+ target = sbox.ospath('A_copy/D')
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'propget', 'svn:externals',
+ target)
+
+
+def copy_pin_externals_repos_repos(sbox):
+ "svn copy --pin-externals repos->repos"
+
+ external_url_for = externals_test_setup(sbox)
+
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_dir = repo_dir + ".other"
+
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+
+ # Perform a repos->repos copy, pinning externals
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ repo_url + '/A',
+ repo_url + '/A_copy',
+ '-m', 'copy',
+ '--pin-externals')
+ verify_pinned_externals(sbox, external_url_for, repo_url,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_repos_wc(sbox):
+ "svn copy --pin-externals repos->wc"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_dir = repo_dir + ".other"
+
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ # Perform a repos->wc copy, pinning externals
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ repo_url + '/A',
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+ verify_pinned_externals(sbox, external_url_for, wc_dir,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_wc_repos(sbox):
+ "svn copy --pin-externals wc->repos"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_dir = repo_dir + ".other"
+
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ # Perform a wc->repos copy, pinning externals
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ repo_url + '/A_copy',
+ '-m', 'copy',
+ '--pin-externals')
+ verify_pinned_externals(sbox, external_url_for, repo_url,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_wc_wc(sbox):
+ "svn copy --pin-externals wc->wc"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_dir = repo_dir + ".other"
+
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ # Perform a wc->wc copy, pinning externals
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+ verify_pinned_externals(sbox, external_url_for, wc_dir,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_moved_external(sbox):
+ "pin externals which were moved since last changed"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_dir = repo_dir + ".other"
+
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ # Test behaviour for external URLs which were moved since
+ # their last-changed revision.
+ sbox.simple_move('A/D/gamma', 'A/D/gamma-moved')
+ sbox.simple_commit()
+ change_external(sbox.ospath('A/B'), '^/A/D/gamma-moved gamma', commit=True)
+ sbox.simple_update()
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+ external_url_for["A/B/gamma"] = '^/A/D/gamma-moved'
+ verify_pinned_externals(sbox, external_url_for, wc_dir,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_removed_in_head(sbox):
+ "already pinned external which was removed in HEAD"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_url = repo_url + ".other"
+ other_repo_dir = repo_dir + ".other"
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ # Test an already pinned external which was removed in HEAD.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'rm',
+ other_repo_url + '/A/D/H',
+ '-m', 'remove A/D/H')
+ sbox.simple_update()
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+ verify_pinned_externals(sbox, external_url_for, wc_dir,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_from_old_rev(sbox):
+ "copy from an old revision with pinning"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+ repo_dir = sbox.repo_dir
+ other_repo_url = repo_url + ".other"
+ other_repo_dir = repo_dir + ".other"
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+ # Create a couple of revisions affecting 'A'.
+ for i in range(5):
+ svntest.main.file_append(sbox.ospath('A/mu'), 'a new line')
+ sbox.simple_commit()
+ sbox.simple_update()
+
+ # Test a copy from an old revision with pinning.
+ external_youngest_rev = svntest.main.youngest(repo_dir)
+ other_external_youngest_rev = svntest.main.youngest(other_repo_dir)
+ svntest.actions.run_and_verify_svn(None, [],
+ 'copy',
+ os.path.join(wc_dir, 'A@6'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+ external_url_for["A/B/gamma"] = '^/A/D/gamma'
+ verify_pinned_externals(sbox, external_url_for, wc_dir,
+ external_youngest_rev, other_external_youngest_rev)
+
+
+def copy_pin_externals_wc_local_mods(sbox):
+ "cannot pin WC externals with local mods"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ svntest.main.file_append(sbox.ospath('A/C/exdir_G/pi'), 'this file changed')
+ expected_stderr = verify.RegexOutput(".*Cannot pin.*local modifications.*",
+ match_all=False)
+ svntest.actions.run_and_verify_svn(None, expected_stderr,
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+
+
+def copy_pin_externals_wc_switched_subtrees(sbox):
+ "cannot pin WC externals with switched subtrees"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'switch', '--ignore-ancestry', '^/A/B',
+ sbox.ospath('A/D/exdir_A/C'))
+ expected_stderr = verify.RegexOutput(".*Cannot pin.*switched subtree.*",
+ match_all=False)
+ svntest.actions.run_and_verify_svn(None, expected_stderr,
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+
+
+def copy_pin_externals_wc_mixed_revisions(sbox):
+ "cannot pin WC externals with mixed revisions"
+
+ external_url_for = externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+
+ # Create a working copy.
+ svntest.actions.run_and_verify_svn(None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'update', '-r1',
+ sbox.ospath('A/D/exdir_A/mu'))
+ expected_stderr = verify.RegexOutput(".*Cannot pin.*mixed-revision.*",
+ match_all=False)
+ svntest.actions.run_and_verify_svn(None, expected_stderr,
+ 'copy',
+ os.path.join(wc_dir, 'A'),
+ os.path.join(wc_dir, 'A_copy'),
+ '--pin-externals')
+
+
def nested_notification(sbox):
"notification for nested externals"
@@ -3638,6 +3971,16 @@ test_list = [ None,
switch_relative_externals,
copy_file_external_to_repo,
replace_tree_with_foreign_external,
+ copy_pin_externals_repos_repos,
+ copy_pin_externals_repos_wc,
+ copy_pin_externals_wc_repos,
+ copy_pin_externals_wc_wc,
+ copy_pin_externals_moved_external,
+ copy_pin_externals_removed_in_head,
+ copy_pin_externals_from_old_rev,
+ copy_pin_externals_wc_local_mods,
+ copy_pin_externals_wc_switched_subtrees,
+ copy_pin_externals_wc_mixed_revisions,
nested_notification,
]
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=1659395&r1=1659394&r2=1659395&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/client-test.c Thu Feb 12 20:38:01 2015
@@ -35,6 +35,8 @@
#include "svn_repos.h"
#include "svn_subst.h"
#include "private/svn_wc_private.h"
+#include "svn_props.h"
+#include "svn_hash.h"
#include "../svn_test.h"
#include "../svn_test_fs.h"
@@ -1055,6 +1057,236 @@ test_remote_only_status(const svn_test_o
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_copy_pin_externals(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_opt_revision_t rev;
+ svn_opt_revision_t peg_rev;
+ const char *repos_url;
+ const char *A_url;
+ const char *A_copy_url;
+ const char *wc_path;
+ svn_client_ctx_t *ctx;
+ const svn_string_t *propval;
+ apr_hash_t *externals_to_pin;
+ apr_array_header_t *external_items;
+ apr_array_header_t *copy_sources;
+ svn_wc_external_item2_t items[6];
+ svn_client_copy_source_t copy_source;
+ apr_hash_t *props;
+ apr_array_header_t *pinned_externals_descs;
+ apr_array_header_t *pinned_externals;
+ int i;
+ int num_tested_externals;
+ svn_stringbuf_t *externals_test_prop;
+ struct pin_externals_test_data {
+ const char *src_external_desc;
+ const char *expected_dst_external_desc;
+ } pin_externals_test_data[] = {
+ { "^/A/D/gamma B/gamma", "^/A/D/gamma@2 B/gamma" },
+ { "-r1 ^/A/D/G C/exdir_G", "-r1 ^/A/D/G C/exdir_G" },
+ { "^/A/D/H@1 C/exdir_H", "^/A/D/H@1 C/exdir_H" },
+ { "^/A/D/H C/exdir_H2", "^/A/D/H@2 C/exdir_H2" },
+ { "-r1 ^/A/B D/z/y/z/blah", "-r1 ^/A/B@2 D/z/y/z/blah" } ,
+ { "-r1 ^/A/D@2 exdir_D", "-r1 ^/A/D@2 exdir_D" },
+ /* Dated revision should retain their date string exactly. */
+ { "-r{1970-01-01T00:00} ^/A/C 70s", "-r{1970-01-01T00:00} ^/A/C@2 70s"},
+ { "-r{2004-02-23} ^/svn 1.0", "-r{2004-02-23} ^/svn 1.0"},
+ { NULL },
+ };
+
+ /* Create a filesytem and repository containing the Greek tree. */
+ SVN_ERR(create_greek_repos(&repos_url, "pin-externals", opts, pool));
+
+ wc_path = svn_test_data_path("pin-externals-working-copy", pool);
+
+ /* Remove old test data from the previous run */
+ SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
+
+ SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
+ svn_test_add_dir_cleanup(wc_path);
+
+ rev.kind = svn_opt_revision_head;
+ peg_rev.kind = svn_opt_revision_unspecified;
+ SVN_ERR(svn_client_create_context(&ctx, pool));
+
+ /* Configure some externals on ^/A */
+ i = 0;
+ externals_test_prop = svn_stringbuf_create_empty(pool);
+ while (pin_externals_test_data[i].src_external_desc)
+ {
+ svn_stringbuf_appendcstr(externals_test_prop,
+ pin_externals_test_data[i].src_external_desc);
+ svn_stringbuf_appendbyte(externals_test_prop, '\n');
+ i++;
+ }
+ propval = svn_string_create_from_buf(externals_test_prop, pool);
+ A_url = apr_pstrcat(pool, repos_url, "/A", SVN_VA_NULL);
+ SVN_ERR(svn_client_propset_remote(SVN_PROP_EXTERNALS, propval,
+ A_url, TRUE, 1, NULL,
+ NULL, NULL, ctx, pool));
+
+ /* Set up parameters for pinning some externals. */
+ externals_to_pin = apr_hash_make(pool);
+
+ items[0].url = "^/A/D/gamma";
+ items[0].target_dir = "B/gamma";
+ items[1].url = "^/A/B";
+ items[1].target_dir = "D/z/y/z/blah";
+ items[2].url = "^/A/D/H";
+ items[2].target_dir = "C/exdir_H2";
+ items[3].url= "^/A/D";
+ items[3].target_dir= "exdir_D";
+ items[4].url = "^/A/C";
+ items[4].target_dir = "70s";
+ /* Also add an entry which doesn't match any actual definition. */
+ items[5].url = "^/this/does/not/exist";
+ items[5].target_dir = "in/test/data";
+
+ external_items = apr_array_make(pool, 2, sizeof(svn_wc_external_item2_t *));
+ for (i = 0; i < sizeof(items) / sizeof(items[0]); i++)
+ APR_ARRAY_PUSH(external_items, svn_wc_external_item2_t *) = &items[i];
+ svn_hash_sets(externals_to_pin, A_url, external_items);
+
+ /* Copy ^/A to ^/A_copy, pinning two non-pinned externals. */
+ copy_source.path = A_url;
+ copy_source.revision = &rev;
+ copy_source.peg_revision = &peg_rev;
+ copy_sources = apr_array_make(pool, 1, sizeof(svn_client_copy_source_t *));
+ APR_ARRAY_PUSH(copy_sources, svn_client_copy_source_t *) = ©_source;
+ A_copy_url = apr_pstrcat(pool, repos_url, "/A_copy", SVN_VA_NULL);
+ SVN_ERR(svn_client_copy7(copy_sources, A_copy_url, FALSE, FALSE,
+ FALSE, TRUE, externals_to_pin,
+ NULL, NULL, NULL, ctx, pool));
+
+ /* Verify that externals were pinned as expected. */
+ SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_EXTERNALS,
+ A_copy_url, &peg_rev, &rev, NULL,
+ svn_depth_empty, NULL, ctx, pool, pool));
+ propval = svn_hash_gets(props, A_copy_url);
+ SVN_TEST_ASSERT(propval);
+
+ /* Test the unparsed representation of copied externals descriptions. */
+ pinned_externals_descs = svn_cstring_split(propval->data, "\n", FALSE, pool);
+ for (i = 0; i < pinned_externals_descs->nelts; i++)
+ {
+ const char *externals_desc;
+ const char *expected_desc;
+
+ externals_desc = APR_ARRAY_IDX(pinned_externals_descs, i, const char *);
+ expected_desc = pin_externals_test_data[i].expected_dst_external_desc;
+ SVN_TEST_STRING_ASSERT(externals_desc, expected_desc);
+ }
+ /* Ensure all test cases were tested. */
+ SVN_TEST_ASSERT(i == (sizeof(pin_externals_test_data) /
+ sizeof(pin_externals_test_data[0]) - 1));
+
+ SVN_ERR(svn_wc_parse_externals_description3(&pinned_externals, A_copy_url,
+ propval->data, TRUE, pool));
+
+ /* For completeness, test the parsed representation, too */
+ num_tested_externals = 0;
+ for (i = 0; i < pinned_externals->nelts; i++)
+ {
+ svn_wc_external_item2_t *item;
+
+ item = APR_ARRAY_IDX(pinned_externals, i, svn_wc_external_item2_t *);
+ if (strcmp(item->url, "^/A/D/gamma") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "B/gamma");
+ /* Pinned to r2. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 2);
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->url, "^/A/D/G") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "C/exdir_G");
+ /* Not pinned. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 1);
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_head);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->url, "^/A/D/H") == 0)
+ {
+ if (strcmp(item->target_dir, "C/exdir_H") == 0)
+ {
+ /* Was already pinned to r1. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 1);
+ SVN_TEST_ASSERT(item->peg_revision.kind ==
+ svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 1);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->target_dir, "C/exdir_H2") == 0)
+ {
+ /* Pinned to r2. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 2);
+ SVN_TEST_ASSERT(item->peg_revision.kind ==
+ svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+ num_tested_externals++;
+ }
+ else
+ SVN_TEST_ASSERT(FALSE); /* unknown external */
+ }
+ else if (strcmp(item->url, "^/A/B") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "D/z/y/z/blah");
+ /* Pinned to r2. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 1);
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->url, "^/A/D") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "exdir_D");
+ /* Pinned to r2. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->revision.value.number == 1);
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->url, "^/A/C") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "70s");
+ /* Pinned to r2. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_date);
+ /* Don't bother testing the exact date value here. */
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+ SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+ num_tested_externals++;
+ }
+ else if (strcmp(item->url, "^/svn") == 0)
+ {
+ SVN_TEST_STRING_ASSERT(item->target_dir, "1.0");
+ /* Was and not in externals_to_pin, operative revision was a date. */
+ SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_date);
+ /* Don't bother testing the exact date value here. */
+ SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_head);
+ num_tested_externals++;
+ }
+ else
+ SVN_TEST_ASSERT(FALSE); /* unknown URL */
+ }
+
+ /* Ensure all test cases were tested. */
+ SVN_TEST_ASSERT(num_tested_externals == (sizeof(pin_externals_test_data) /
+ sizeof(pin_externals_test_data[0])
+ - 1));
+
+ return SVN_NO_ERROR;
+}
+
/* ========================================================================== */
@@ -1079,6 +1311,8 @@ static struct svn_test_descriptor_t test
"test svn_client_suggest_merge_sources"),
SVN_TEST_OPTS_PASS(test_remote_only_status,
"test svn_client_status6 with ignore_local_mods"),
+ SVN_TEST_OPTS_PASS(test_copy_pin_externals,
+ "test svn_client_copy7 with externals_to_pin"),
SVN_TEST_NULL
};
Propchange: subversion/trunk/subversion/tests/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Feb 12 20:38:01 2015
@@ -56,6 +56,7 @@
/subversion/branches/nfc-nfd-aware-client/subversion/tests/libsvn_fs_x:870276,870376
/subversion/branches/node_pool/subversion/tests/libsvn_fs_x:1304828-1305388
/subversion/branches/performance/subversion/tests/libsvn_fs_x:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-10293
36,1029339-1029340,1029342,1029344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/pin-externals/subversion/tests/libsvn_fs_x:1643757-1659392
/subversion/branches/py-tests-as-modules/subversion/tests/libsvn_fs_x:956579-1033052
/subversion/branches/ra_serf-digest-authn/subversion/tests/libsvn_fs_x:875693-876404
/subversion/branches/reintegrate-improvements/subversion/tests/libsvn_fs_x:873853-874164