Hi,
This patch implements '--include-externals' option to 'svn list' [Issue
#4225] [1].
All tests pass with 'make check' & 'make davautocheck'.
Attached the patch and log message.
Please review this patch and share your thoughts.
Thanks in advance for your time.
Thanks & Regards,
Vijayaguru
[1] http://subversion.tigris.org/issues/show_bug.cgi?id=4225
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 1405691)
+++ subversion/include/svn_client.h (working copy)
@@ -5280,7 +5280,7 @@
* @{
*/
-/** The type of function invoked by svn_client_list2() to report the details
+/** The type of function invoked by svn_client_list3() to report the details
* of each directory entry being listed.
*
* @a baton is the baton that was passed to the caller. @a path is the
@@ -5290,11 +5290,41 @@
* the entry's lock, if it is locked and if lock information is being
* reported by the caller; otherwise @a lock is NULL. @a abs_path is the
* repository path of the top node of the list operation; it is relative to
- * the repository root and begins with "/". @a pool may be used for
- * temporary allocations.
+ * the repository root and begins with "/".
*
- * @since New in 1.4.
+ * If svn_client_list3() was called with @a include_externals set to TRUE,
+ * @a notify_external_start, @a notify_external_end, @a external_parent_url
+ * and @a external_target will be set. @a notify_external_start and
+ * @a notify_external_end is used to control the list output of externals.
+ * @a external_parent_url is url of the directory which has the externals
+ * definitions. @a external_target is the target subdirectory of externals
+ * definitions.
+
+ * @a pool may be used for temporary allocations.
+ *
+ * @since New in 1.8.
*/
+typedef svn_error_t *(*svn_client_list_func2_t)(
+ void *baton,
+ const char *path,
+ const svn_dirent_t *dirent,
+ const svn_lock_t *lock,
+ const char *abs_path,
+ svn_boolean_t notify_external_start,
+ svn_boolean_t notify_external_end,
+ const char *external_parent_url,
+ const char *external_target,
+ apr_pool_t *pool);
+
+/**
+ * Similar to #svn_client_list_func2_t, but without any information about
+ * externals definitions.
+ *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
+ *
+ * @since New in 1.4
+ *
+ * */
typedef svn_error_t *(*svn_client_list_func_t)(void *baton,
const char *path,
const svn_dirent_t *dirent,
@@ -5318,6 +5348,10 @@
*
* If @a fetch_locks is TRUE, include locks when reporting directory entries.
*
+ * If @a include_externals is TRUE, also list all external items
+ * reached by recursion. @a depth value passed to the original list target
+ * applies for the externals also.
+ *
* Use @a pool for temporary allocations.
*
* Use authentication baton cached in @a ctx to authenticate against the
@@ -5334,8 +5368,30 @@
* otherwise simply bitwise OR together the combination of @c SVN_DIRENT_
* fields you care about.
*
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_client_list3(const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
+ svn_depth_t depth,
+ apr_uint32_t dirent_fields,
+ svn_boolean_t fetch_locks,
+ svn_boolean_t include_externals,
+ svn_client_list_func2_t list_func,
+ void *baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+
+/** Similar to svn_client_list3(), but with @a include_externals set to FALSE,
+ * and using a #svn_client_list_func2_t as callback.
+ *
+ * @deprecated Provided for backwards compatibility with the 1.7 API.
+ *
* @since New in 1.5.
*/
+SVN_DEPRECATED
svn_error_t *
svn_client_list2(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h (revision 1405691)
+++ subversion/libsvn_client/client.h (working copy)
@@ -1009,7 +1009,6 @@
svn_client_ctx_t *ctx,
apr_pool_t *pool);
-
/* Perform status operations on each external in EXTERNAL_MAP, a const char *
local_abspath of all externals mapping to the const char* defining_abspath.
All other options are the same as those passed to svn_client_status(). */
@@ -1024,6 +1023,21 @@
void *status_baton,
apr_pool_t *pool);
+/* List external items defined on each external in EXTERNALS, a const char *
+ externals_parent_url(url of the directory which has the externals
+ definitions) of all externals mapping to the const char * externals_desc
+ (externals description text). All other options are the same as those
+ passed to svn_client_list(). */
+svn_error_t *
+svn_client__list_externals(apr_hash_t *externals,
+ svn_depth_t depth,
+ apr_uint32_t dirent_fields,
+ svn_boolean_t fetch_locks,
+ svn_client_list_func2_t list_func,
+ void *baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
/* Baton for svn_client__dirent_fetcher */
struct svn_client__dirent_fetcher_baton_t
{
Index: subversion/libsvn_client/deprecated.c
===================================================================
--- subversion/libsvn_client/deprecated.c (revision 1405691)
+++ subversion/libsvn_client/deprecated.c (working copy)
@@ -1269,7 +1269,75 @@
}
/*** From list.c ***/
+
+/* Baton for use with wrap_list_func */
+struct list_func_wrapper_baton {
+ void *baton;
+ svn_client_list_func_t list_func;
+};
+
+/* This implements svn_client_list_func2_t */
+static svn_error_t *
+list_func_wrapper(void *baton,
+ const char *path,
+ const svn_dirent_t *dirent,
+ const svn_lock_t *lock,
+ const char *abs_path,
+ svn_boolean_t notify_external_start,
+ svn_boolean_t notify_external_end,
+ const char *external_parent_url,
+ const char *external_target,
+ apr_pool_t *pool)
+{
+ struct list_func_wrapper_baton *lfwb = baton;
+
+ if (lfwb->list_func)
+ return lfwb->list_func(lfwb->baton, path, dirent, lock, abs_path, pool);
+
+ return SVN_NO_ERROR;
+}
+
+static void
+wrap_list_func(svn_client_list_func2_t *list_func2,
+ void **list_func2_baton,
+ svn_client_list_func_t list_func,
+ void *baton,
+ apr_pool_t *pool)
+{
+ struct list_func_wrapper_baton *lfwb = apr_palloc(pool, sizeof(*lfwb));
+
+ /* Set the user provided old format callback in the baton. */
+ lfwb->baton = baton;
+ lfwb->list_func = list_func;
+
+ *list_func2_baton = lfwb;
+ *list_func2 = list_func_wrapper;
+}
+
svn_error_t *
+svn_client_list2(const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *revision,
+ svn_depth_t depth,
+ apr_uint32_t dirent_fields,
+ svn_boolean_t fetch_locks,
+ svn_client_list_func_t list_func,
+ void *baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_client_list_func2_t list_func2;
+ void *list_func2_baton;
+
+ wrap_list_func(&list_func2, &list_func2_baton, list_func, baton, pool);
+
+ return svn_client_list3(path_or_url, peg_revision, revision, depth,
+ dirent_fields, fetch_locks,
+ FALSE /* include externals */,
+ list_func2, list_func2_baton, ctx, pool);
+}
+
+svn_error_t *
svn_client_list(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
Index: subversion/libsvn_client/externals.c
===================================================================
--- subversion/libsvn_client/externals.c (revision 1405691)
+++ subversion/libsvn_client/externals.c (working copy)
@@ -1180,3 +1180,95 @@
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_client__list_externals(apr_hash_t *externals,
+ svn_depth_t depth,
+ apr_uint32_t dirent_fields,
+ svn_boolean_t fetch_locks,
+ svn_client_list_func2_t list_func,
+ void *baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *sub_iterpool = svn_pool_create(pool);
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, externals);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *externals_parent_url = svn__apr_hash_index_key(hi);
+ svn_string_t *externals_desc = svn__apr_hash_index_val(hi);
+ const char *externals_parent_repos_root_url;
+ apr_array_header_t *items;
+ int i;
+
+ svn_pool_clear(iterpool);
+
+ items = apr_array_make(iterpool, 1, sizeof(svn_wc_external_item2_t*));
+
+ SVN_ERR(svn_client_get_repos_root(&externals_parent_repos_root_url,
+ NULL /* uuid */,
+ externals_parent_url, ctx,
+ iterpool, iterpool));
+
+ SVN_ERR(svn_wc_parse_externals_description3(&items,
+ externals_parent_url,
+ externals_desc->data,
+ FALSE, iterpool));
+
+ if (! items->nelts)
+ continue;
+
+ for (i = 0; i < items->nelts; i++)
+ {
+ const char *resolved_url;
+
+ svn_wc_external_item2_t *item =
+ APR_ARRAY_IDX(items, i, svn_wc_external_item2_t *);
+
+ svn_pool_clear(sub_iterpool);
+
+ SVN_ERR(svn_wc__resolve_relative_external_url(
+ &resolved_url,
+ item,
+ externals_parent_repos_root_url,
+ externals_parent_url,
+ sub_iterpool, sub_iterpool));
+
+ /* Notify that we're about to handle an external. */
+ SVN_ERR(list_func(baton, NULL, NULL, NULL, NULL,
+ TRUE /*notify_external_start */,
+ FALSE /*notify_external_end */,
+ externals_parent_url,
+ item->target_dir, iterpool));
+
+ /* List the external */
+ SVN_ERR(wrap_external_error(
+ ctx, item->target_dir,
+ svn_client_list3(resolved_url,
+ &item->peg_revision,
+ &item->revision,
+ depth, dirent_fields,
+ fetch_locks,
+ TRUE,
+ list_func, baton, ctx,
+ sub_iterpool),
+ sub_iterpool));
+
+ /* Notify that we are done with external handling. It is helpful
+ when list is run in xml mode. */
+ SVN_ERR(list_func(baton, NULL, NULL, NULL, NULL,
+ FALSE /*notify_external_start */,
+ TRUE /*notify_external_end */,
+ NULL, NULL, iterpool));
+ }
+ }
+ svn_pool_destroy(sub_iterpool);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
Index: subversion/libsvn_client/list.c
===================================================================
--- subversion/libsvn_client/list.c (revision 1405691)
+++ subversion/libsvn_client/list.c (working copy)
@@ -47,7 +47,12 @@
LOCKS, if non-NULL, is a hash mapping const char * paths to svn_lock_t
objects and FS_PATH is the absolute filesystem path of the RA session.
- Use POOL for temporary allocations.
+ Use SCRATCH_POOL for temporary allocations.
+
+ If INCLUDE_EXTERNALS is true, set *EXTERNALS to a hash table whose keys
+ are URLs of the directory which has external definitions, and whose values
+ are the externals description text. Allocate the hash's keys and
+ values in RESULT_POOL.
*/
static svn_error_t *
get_dir_contents(apr_uint32_t dirent_fields,
@@ -58,23 +63,30 @@
const char *fs_path,
svn_depth_t depth,
svn_client_ctx_t *ctx,
- svn_client_list_func_t list_func,
+ svn_boolean_t include_externals,
+ apr_hash_t **externals,
+ svn_client_list_func2_t list_func,
void *baton,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_hash_t *tmpdirents;
- apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_array_header_t *array;
svn_error_t *err;
+ apr_hash_t *prop_hash = NULL;
+ const svn_string_t *prop_val;
int i;
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
-
- /* Get the directory's entries, but not its props. Ignore any
- not-authorized errors. */
- err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
- dir, rev, dirent_fields, pool);
+
+ /* Get the directory's entries. If include_externals is set, get its
+ properties also. Ignore any not-authorized errors. */
+ err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL,
+ include_externals ? &prop_hash : NULL,
+ dir, rev, dirent_fields, scratch_pool);
+
if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
(err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
{
@@ -82,12 +94,27 @@
return SVN_NO_ERROR;
}
SVN_ERR(err);
+
+ if (prop_hash
+ && (prop_val = apr_hash_get(prop_hash, SVN_PROP_EXTERNALS,
+ APR_HASH_KEY_STRING)))
+ {
+ const char *url;
+ SVN_ERR(svn_ra_get_session_url(ra_session, &url, scratch_pool));
+
+ apr_hash_set(*externals, svn_path_url_add_component2(url, dir,
+ result_pool),
+ APR_HASH_KEY_STRING, svn_string_dup(prop_val,
+ result_pool));
+ }
+
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
/* Sort the hash, so we can call the callback in a "deterministic" order. */
- array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically, pool);
+ array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically,
+ scratch_pool);
for (i = 0; i < array->nelts; ++i)
{
svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
@@ -110,12 +137,17 @@
if (the_ent->kind == svn_node_file
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity)
- SVN_ERR(list_func(baton, path, the_ent, lock, fs_path, iterpool));
-
+ SVN_ERR(list_func(baton, path, the_ent, lock, fs_path, FALSE, FALSE,
+ NULL, NULL, iterpool));
+
+ /* If include_externals is set, populate the *externals hash table
+ recursively for all directory entries. */
if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
SVN_ERR(get_dir_contents(dirent_fields, path, rev,
- ra_session, locks, fs_path, depth, ctx,
- list_func, baton, iterpool));
+ ra_session, locks, fs_path, depth, ctx,
+ include_externals,
+ include_externals ? externals : NULL,
+ list_func, baton, result_pool, iterpool));
}
svn_pool_destroy(iterpool);
@@ -224,14 +256,16 @@
return SVN_NO_ERROR;
}
+
svn_error_t *
-svn_client_list2(const char *path_or_url,
+svn_client_list3(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_depth_t depth,
apr_uint32_t dirent_fields,
svn_boolean_t fetch_locks,
- svn_client_list_func_t list_func,
+ svn_boolean_t include_externals,
+ svn_client_list_func2_t list_func,
void *baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -242,6 +276,7 @@
const char *fs_path;
svn_error_t *err;
apr_hash_t *locks;
+ apr_hash_t *externals = apr_hash_make(pool);
/* We use the kind field to determine if we should recurse, so we
always need it. */
@@ -284,14 +319,29 @@
SVN_ERR(list_func(baton, "", dirent, locks
? (apr_hash_get(locks, fs_path,
APR_HASH_KEY_STRING))
- : NULL, fs_path, pool));
+ : NULL, fs_path, FALSE, FALSE, NULL, NULL, pool));
if (dirent->kind == svn_node_dir
&& (depth == svn_depth_files
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity))
SVN_ERR(get_dir_contents(dirent_fields, "", loc->rev, ra_session, locks,
- fs_path, depth, ctx, list_func, baton, pool));
-
+ fs_path, depth, ctx, include_externals,
+ include_externals ? &externals : NULL,
+ list_func, baton,
+ pool, pool));
+
+ /* We handle externals after listing entries under path_or_url, so that
+ handling external items (and any errors therefrom) doesn't delay
+ the primary operation. */
+ if (include_externals && externals && apr_hash_count(externals))
+ {
+ /* The 'externals' hash populated by get_dir_contents() is processed
+ here. */
+ SVN_ERR(svn_client__list_externals(externals, depth, dirent_fields,
+ fetch_locks, list_func, baton,
+ ctx, pool));
+ }
+
return SVN_NO_ERROR;
}
Index: subversion/svn/list-cmd.c
===================================================================
--- subversion/svn/list-cmd.c (revision 1405691)
+++ subversion/svn/list-cmd.c (working copy)
@@ -44,7 +44,7 @@
svn_client_ctx_t *ctx;
};
-/* This implements the svn_client_list_func_t API, printing a single
+/* This implements the svn_client_list_func2_t API, printing a single
directory entry in text format. */
static svn_error_t *
print_dirent(void *baton,
@@ -52,6 +52,10 @@
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
+ svn_boolean_t notify_external_start,
+ svn_boolean_t notify_external_end,
+ const char *external_parent_url,
+ const char *external_target,
apr_pool_t *pool)
{
struct print_baton *pb = baton;
@@ -59,6 +63,16 @@
static const char *time_format_long = NULL;
static const char *time_format_short = NULL;
+ if (notify_external_start)
+ {
+ return svn_cmdline_printf(pool, "Externals on '%s - %s':\n",
+ external_parent_url,
+ external_target);
+ }
+
+ if (notify_external_end)
+ return SVN_NO_ERROR;
+
if (time_format_long == NULL)
time_format_long = _("%b %d %H:%M");
if (time_format_short == NULL)
@@ -133,7 +147,7 @@
}
-/* This implements the svn_client_list_func_t API, printing a single dirent
+/* This implements the svn_client_list_func2_t API, printing a single dirent
in XML format. */
static svn_error_t *
print_dirent_xml(void *baton,
@@ -141,12 +155,33 @@
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
+ svn_boolean_t notify_external_start,
+ svn_boolean_t notify_external_end,
+ const char *external_parent_url,
+ const char *external_target,
apr_pool_t *pool)
{
struct print_baton *pb = baton;
const char *entryname;
- svn_stringbuf_t *sb;
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
+ if (notify_external_start)
+ {
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "external",
+ "parent_url", external_parent_url,
+ "target", external_target,
+ NULL);
+
+ return svn_cl__error_checked_fputs(sb->data, stdout);
+ }
+
+ if (notify_external_end)
+ {
+ svn_xml_make_close_tag(&sb, pool, "external");
+
+ return svn_cl__error_checked_fputs(sb->data, stdout);
+ }
+
if (strcmp(path, "") == 0)
{
if (dirent->kind == svn_node_file)
@@ -163,8 +198,6 @@
if (pb->ctx->cancel_func)
SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
- sb = svn_stringbuf_create_empty(pool);
-
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"kind", svn_cl__node_kind_str_xml(dirent->kind),
NULL);
@@ -225,6 +258,8 @@
struct print_baton pb;
svn_boolean_t seen_nonexistent_target = FALSE;
svn_error_t *err;
+ svn_error_t *externals_err = SVN_NO_ERROR;
+ struct svn_cl__check_externals_failed_notify_baton nwb;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -266,6 +301,15 @@
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_immediates;
+ if (opt_state->include_externals)
+ {
+ nwb.wrapped_func = ctx->notify_func2;
+ nwb.wrapped_baton = ctx->notify_baton2;
+ nwb.had_externals_error = FALSE;
+ ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
+ ctx->notify_baton2 = &nwb;
+ }
+
/* For each target, try to list it. */
for (i = 0; i < targets->nelts; i++)
{
@@ -290,11 +334,12 @@
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
- err = svn_client_list2(truepath, &peg_revision,
+ err = svn_client_list3(truepath, &peg_revision,
&(opt_state->start_revision),
opt_state->depth,
dirent_fields,
(opt_state->xml || opt_state->verbose),
+ opt_state->include_externals,
opt_state->xml ? print_dirent_xml : print_dirent,
&pb, ctx, subpool);
@@ -322,14 +367,24 @@
}
svn_pool_destroy(subpool);
+
+ if (opt_state->include_externals && nwb.had_externals_error)
+ {
+ externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS,
+ NULL,
+ _("Failure occurred processing one or "
+ "more externals definitions"));
+ }
if (opt_state->xml && ! opt_state->incremental)
SVN_ERR(svn_cl__xml_print_footer("lists", pool));
if (seen_nonexistent_target)
- return svn_error_create(
- SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not list all targets because some targets don't exist"));
+ {
+ err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Could not list all targets because some targets don't exist"));
+ return svn_error_compose_create(externals_err, err);
+ }
else
- return SVN_NO_ERROR;
+ return svn_error_compose_create(externals_err, err);
}
Index: subversion/svn/main.c
===================================================================
--- subversion/svn/main.c (revision 1405691)
+++ subversion/svn/main.c (working copy)
@@ -356,11 +356,7 @@
" "
"Please run 'svn update' instead.")},
{"include-externals", opt_include_externals, 0,
- N_("Also commit file and dir externals reached by\n"
- " "
- "recursion. This does not include externals with a\n"
- " "
- "fixed revision. (See the svn:externals property)")},
+ N_("include externals definitions")},
{"show-inherited-props", opt_show_inherited_props, 0,
N_("retrieve target's inherited properties")},
{"search", opt_search, 1,
@@ -622,7 +618,8 @@
" If locked, the letter 'O'. (Use 'svn info URL' to see details)\n"
" Size (in bytes)\n"
" Date and time of the last commit\n"),
- {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml} },
+ {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml,
+ opt_include_externals} },
{ "lock", svn_cl__lock, {0}, N_
("Lock working copy paths or URLs in the repository, so that\n"
Index: subversion/tests/cmdline/externals_tests.py
===================================================================
--- subversion/tests/cmdline/externals_tests.py (revision 1405691)
+++ subversion/tests/cmdline/externals_tests.py (working copy)
@@ -2131,7 +2131,7 @@
actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
expected_status, None, None, None, None, None, True, wc_dir)
-def include_externals(sbox):
+def commit_include_externals(sbox):
"commit --include-externals"
# svntest.factory.make(sbox, """
# mkdir Z
@@ -2866,6 +2866,55 @@
"OUTPUT", expected_stdout, [], 0, 'copy', repo_url + '/A/C',
sbox.ospath('External-WC-to-URL-Copy'))
+@Issue(4225)
+def list_include_externals(sbox):
+ "list with --include-externals"
+
+ externals_test_setup(sbox)
+
+ wc_dir = sbox.wc_dir
+ repo_url = sbox.repo_url
+
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'checkout',
+ repo_url, wc_dir)
+
+ B_path = sbox.ospath("A/B")
+ C_path = sbox.ospath("A/C")
+
+ B_url = repo_url + "/A/B"
+ C_url = repo_url + "/A/C"
+
+ expected_stdout = verify.UnorderedOutput([
+ "E/" + "\n",
+ "F/" + "\n",
+ "lambda" + "\n",
+ "Externals on " + "'" + B_url + " - " + "gamma" + "'" + ":" + "\n",
+ "gamma" + "\n"])
+
+ exit_code, stdout, stderr = svntest.actions.run_and_verify_svn2(
+ "OUTPUT", expected_stdout, [], 0, 'ls', '--include-externals', B_path)
+
+ exit_code, stdout, stderr = svntest.actions.run_and_verify_svn2(
+ "OUTPUT", expected_stdout, [], 0, 'ls', '--include-externals', B_url)
+
+ expected_stdout = verify.UnorderedOutput([
+ "Externals on " + "'" + C_url + " - " + "exdir_G" + "'" + ":" + "\n",
+ "pi" + "\n",
+ "rho" + "\n",
+ "tau" + "\n",
+ "Externals on " + "'" + C_url + " - " + "exdir_H" + "'" + ":" + "\n",
+ "chi" + "\n",
+ "omega" + "\n",
+ "psi" + "\n"])
+
+ exit_code, stdout, stderr = svntest.actions.run_and_verify_svn2(
+ "OUTPUT", expected_stdout, [], 0, 'ls', '--include-externals', C_path)
+
+ exit_code, stdout, stderr = svntest.actions.run_and_verify_svn2(
+ "OUTPUT", expected_stdout, [], 0, 'ls', '--include-externals', C_url)
+
+
########################################################################
# Run the tests
@@ -2907,12 +2956,13 @@
file_externals_different_url,
file_external_in_unversioned,
copy_file_externals,
- include_externals,
+ commit_include_externals,
include_immediate_dir_externals,
shadowing,
remap_file_external_with_prop_del,
dir_external_with_dash_r_only,
url_to_wc_copy_of_externals,
+ list_include_externals,
]
if __name__ == '__main__':
Fix issue #4225, "Add '--include-externals' option to svn list".
* subversion/include/svn_client.h
(svn_client_list_func2_t): New type used to notify externals information.
(svn_client_list_func_t): Deprecate type.
(svn_client_list3): New function, which has a new argument
include_externals.
(svn_client_list2): Deprecate it.
* subversion/libsvn_client/deprecated.c
(list_func_wrapper_baton): New struct to deprecate svn_client_list2().
(list_func_wrapper, wrap_list_func): Helper functions to deprecate
svn_client_list2().
(svn_client_list2): Call svn_client_list3 with include_externals set to
FALSE, and use svn_client_list_func2_t as callback implemented by
list_func_wrapper().
* subversion/libsvn_client/externals.c
(svn_client__list_externals): New function. Walk through all the externals
under list target recursively and call svn_client_list3() for each
external item.
* subversion/libsvn_client/list.c
(get_dir_contents): Populate the hash table 'externals'. Use
svn_client_list_func2_t instead of svn_client_list_func_t to report file
and directory entries.
(svn_client_list3): New function. If include_externals is set, process all
the
externals which are populated by get_dir_contents() using
svn_client__list_externals().
* subversion/svn/list-cmd.c
(print_dirent): Implement svn_client_list_func2_t to control the output when
used with externals.
(print_dirent_xml): Implement svn_client_list_func2_t. Enclose the external
items in the element <external parent_url=.. target= ..><..></external>
(svn_cl__list): Call svn_client_list3(). Handle if there are any errors
during externals processing.
* subversion/svn/main.c
(svn_cl__options): Short description about include_externals.
(svn_cl__cmd_table): Enable include_externals for 'list'.
* subversion/tests/cmdline/externals_tests.py
(include_externals): Rename it to 'commit_include_externals'.
(list_include_externals): New test.
(test_list): Add a reference to the new test. Rename 'include_externals' to
'commit_include_externals'.
Patch by: Vijayaguru G <vijay{_AT_}collab.net>