Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 14784)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -359,8 +359,8 @@
"\n"
" Print information about each TARGET (default: '.')\n"
" TARGET may be either a working-copy path or URL.\n"),
- {'r', 'R', svn_cl__targets_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt} },
+ {'r', 'R', svn_cl__targets_opt, svn_cl__incremental_opt, svn_cl__xml_opt,
+ SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
{ "list", svn_cl__ls, {"ls"},
N_("List directory entries in the repository.\n"
Index: subversion/clients/cmdline/dtd/info.dtd
===================================================================
--- subversion/clients/cmdline/dtd/info.dtd (revision 0)
+++ subversion/clients/cmdline/dtd/info.dtd (revision 0)
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: subversion/clients/cmdline/info-cmd.c
===================================================================
--- subversion/clients/cmdline/info-cmd.c (revision 14784)
+++ subversion/clients/cmdline/info-cmd.c (working copy)
@@ -28,6 +28,7 @@
#include "svn_error.h"
#include "svn_path.h"
#include "svn_time.h"
+#include "svn_xml.h"
#include "cl.h"
#include "svn_private_config.h"
@@ -47,8 +48,372 @@
return SVN_NO_ERROR;
}
+/* Prints XML header */
+static svn_error_t *
+print_header_xml (apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+ /* */
+ svn_xml_make_header (&sb, pool);
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "info", NULL);
+
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+/* Prints XML target */
static svn_error_t *
+print_target_xml (apr_pool_t *pool, const char *target,
+ svn_boolean_t to_open)
+{
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ if (to_open)
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "target",
+ "path", target, NULL);
+ else
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "target");
+
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+/* Prints XML footer */
+static svn_error_t *
+print_footer_xml (apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "info");
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+/* prints svn info in xml mode to standard out */
+static svn_error_t *
+print_info_xml (const char *target,
+ const svn_info_t *info,
+ apr_pool_t *pool)
+{
+ const char *str_kind;
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ switch (info->kind)
+ {
+ case svn_node_file:
+ str_kind = "file";
+ break;
+
+ case svn_node_dir:
+ str_kind = "directory";
+ break;
+
+ case svn_node_none:
+ str_kind = "none";
+ break;
+
+ case svn_node_unknown:
+ default:
+ str_kind = "unknown";
+ break;
+ }
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "entry",
+ "path", svn_path_local_style (target, pool),
+ "type", str_kind,
+ NULL);
+
+ if (info->URL)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "url", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->URL, pool);
+ svn_xml_make_close_tag (&sb, pool, "url");
+ }
+
+ if (SVN_IS_VALID_REVNUM (info->rev))
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "revision", NULL);
+ svn_xml_escape_cdata_cstring (&sb, apr_psprintf (pool,
+ "%" APR_OFF_T_FMT, info->rev), pool);
+ svn_xml_make_close_tag (&sb, pool, "revision");
+ }
+
+ if (info->repos_root_URL || info->repos_UUID)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "repository", NULL);
+
+ if (info->repos_root_URL)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "root", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->repos_root_URL, pool);
+ svn_xml_make_close_tag (&sb, pool, "root");
+ }
+
+ if (info->repos_UUID)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "uuid", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->repos_UUID, pool);
+ svn_xml_make_close_tag (&sb, pool, "uuid");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "repository");
+ }
+
+ if (info->has_wc_info)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "wc-info", NULL);
+
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "schedule", NULL);
+ switch (info->schedule)
+ {
+ case svn_wc_schedule_normal:
+ svn_xml_escape_cdata_cstring (&sb, "normal", pool);
+ break;
+
+ case svn_wc_schedule_add:
+ svn_xml_escape_cdata_cstring (&sb, "add", pool);
+ break;
+
+ case svn_wc_schedule_delete:
+ svn_xml_escape_cdata_cstring (&sb, "delete", pool);
+ break;
+
+ case svn_wc_schedule_replace:
+ svn_xml_escape_cdata_cstring (&sb, "replace", pool);
+ break;
+
+ default:
+ break;
+ }
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "schedule");
+
+ if (info->copyfrom_url)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "copy-from-url", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->copyfrom_url, pool);
+ svn_xml_make_close_tag (&sb, pool, "copy-from-url");
+ }
+
+ if (SVN_IS_VALID_REVNUM (info->copyfrom_rev))
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "copied-from-rev", NULL);
+ svn_xml_escape_cdata_cstring (&sb, apr_psprintf (pool,
+ "%" APR_OFF_T_FMT,
+ info->copyfrom_rev), pool);
+ svn_xml_make_close_tag (&sb, pool, "copied-from-rev");
+ }
+
+ if (info->checksum)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "checksum", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->checksum, pool);
+ svn_xml_make_close_tag (&sb, pool, "checksum");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "wc-info");
+ }
+
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "last-changed", NULL);
+
+ if (info->last_changed_author)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "author", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->last_changed_author, pool);
+ svn_xml_make_close_tag (&sb, pool, "author");
+ }
+
+ if (SVN_IS_VALID_REVNUM (info->last_changed_rev))
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "last-rev", NULL);
+ svn_xml_escape_cdata_cstring (&sb, apr_psprintf (pool,
+ "%" APR_OFF_T_FMT,
+ info->last_changed_rev), pool);
+ svn_xml_make_close_tag (&sb, pool, "last-rev");
+ }
+
+ if (info->last_changed_date)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "date", NULL);
+ svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring
+ (info->last_changed_date, pool), pool);
+ svn_xml_make_close_tag (&sb, pool, "date");
+ }
+
+ if (info->has_wc_info)
+ {
+ if (info->text_time)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "text-updated", NULL);
+ svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring
+ (info->text_time, pool), pool);
+ svn_xml_make_close_tag (&sb, pool, "text-updated");
+ }
+
+ if (info->prop_time)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "prop-updated", NULL);
+ svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring
+ (info->prop_time, pool), pool);
+ svn_xml_make_close_tag (&sb, pool, "prop-updated");
+ }
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "last-changed");
+
+
+ if (info->conflict_old || info->conflict_wrk
+ || info->conflict_new || info->prejfile )
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "conflict", NULL);
+
+ if (info->conflict_old)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "prev-basefile", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->conflict_old, pool);
+ svn_xml_make_close_tag (&sb, pool, "prev-basefile");
+ }
+
+ if (info->conflict_wrk)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "prev-wrkfile", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->conflict_wrk, pool);
+ svn_xml_make_close_tag (&sb, pool, "prev-wrkfile");
+ }
+
+ if (info->conflict_new)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "cur-basefile", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->conflict_new, pool);
+ svn_xml_make_close_tag (&sb, pool, "cur-basefile");
+ }
+
+ if (info->prejfile)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "prop-file", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->prejfile, pool);
+ svn_xml_make_close_tag (&sb, pool, "prop-file");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "conflict");
+ }
+
+ if (info->lock)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "lock", NULL);
+
+ if (info->lock->token)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "token", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->lock->token, pool);
+ svn_xml_make_close_tag (&sb, pool, "token");
+ }
+
+ if (info->lock->owner)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "owner", NULL);
+ svn_xml_escape_cdata_cstring (&sb, info->lock->owner, pool);
+ svn_xml_make_close_tag (&sb, pool, "owner");
+ }
+
+ if (info->lock->creation_date)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "created", NULL);
+ svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring
+ (info->lock->creation_date, pool),
+ pool);
+ svn_xml_make_close_tag (&sb, pool, "created");
+ }
+
+ if (info->lock->expiration_date)
+ {
+ /* " xx " */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "expires", NULL);
+ svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring
+ (info->lock->expiration_date, pool),
+ pool);
+ svn_xml_make_close_tag (&sb, pool, "expires");
+ }
+
+ if (info->lock->comment)
+ {
+ /* " xxxx " */
+ int comment_lines;
+ /* NOTE: The stdio will handle newline translation. */
+ comment_lines = svn_cstring_count_newlines (info->lock->comment) + 1;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "comment",
+ "lines", apr_psprintf (pool, "%d",
+ comment_lines), NULL);
+
+ svn_xml_escape_cdata_cstring (&sb, info->lock->comment, pool);
+ svn_xml_make_close_tag (&sb, pool, "comment");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "lock");
+ }
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "entry");
+
+ return svn_cl__error_checked_fputs (sb->data, stdout);
+}
+
+
+static svn_error_t *
print_info (const char *target,
const svn_info_t *info,
apr_pool_t *pool)
@@ -225,7 +590,10 @@
const svn_info_t *info,
apr_pool_t *pool)
{
- return print_info (path, info, pool);
+ if ((((svn_cl__cmd_baton_t *) baton)->opt_state)->xml)
+ return print_info_xml (path, info, pool);
+ else
+ return print_info (path, info, pool);
}
@@ -249,6 +617,23 @@
/* Add "." if user passed 0 arguments. */
svn_opt_push_implicit_dot_target (targets, pool);
+
+ if (opt_state->xml)
+ {
+ /* If output is not incremental, output the XML header and wrap
+ everything in a top-level element. This makes the output in
+ its entirety a well-formed XML document. */
+ if (! opt_state->incremental)
+ SVN_ERR (print_header_xml (pool));
+
+ }
+ else
+ {
+ if (opt_state->incremental)
+ return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'incremental' option only valid in XML "
+ "mode"));
+ }
for (i = 0; i < targets->nelts; i++)
{
@@ -266,26 +651,34 @@
&& (peg_revision.kind == svn_opt_revision_unspecified))
peg_revision.kind = svn_opt_revision_head;
+ if (opt_state->xml)
+ print_target_xml (pool, target, TRUE);
+
err = svn_client_info (truepath,
&peg_revision, &(opt_state->start_revision),
- info_receiver, NULL,
+ info_receiver, baton,
opt_state->recursive, ctx, subpool);
+ if (opt_state->xml)
+ print_target_xml (pool, target, FALSE);
+
/* If one of the targets is a non-existent URL or wc-entry,
don't bail out. Just warn and move on to the next target. */
if (err && err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE)
{
svn_error_clear (err);
- SVN_ERR (svn_cmdline_printf
- (subpool, _("%s: (Not a versioned resource)\n\n"),
+ SVN_ERR (svn_cmdline_fprintf
+ (stderr, subpool,
+ _("%s: (Not a versioned resource)\n\n"),
svn_path_local_style (target, pool)));
continue;
}
else if (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
{
svn_error_clear (err);
- SVN_ERR (svn_cmdline_printf
- (subpool, _("%s: (Not a valid URL)\n\n"),
+ SVN_ERR (svn_cmdline_fprintf
+ (stderr, subpool,
+ _("%s: (Not a valid URL)\n\n"),
svn_path_local_style (target, pool)));
continue;
}
@@ -295,5 +688,8 @@
}
svn_pool_destroy (subpool);
+ if (opt_state->xml && (! opt_state->incremental))
+ err = print_footer_xml (pool);
+
return SVN_NO_ERROR;
}
Index: tools/client-side/bash_completion
===================================================================
--- tools/client-side/bash_completion (revision 14784)
+++ tools/client-side/bash_completion (working copy)
@@ -99,7 +99,8 @@
--editor-cmd $pOpts"
;;
info)
- cmdOpts="$rOpts --targets -R --recursive"
+ cmdOpts="$rOpts --targets -R --recursive \
+ --incremental --xml"
;;
list|ls)
cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \