Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 15532)
+++ subversion/clients/cmdline/cl.h (working copy)
@@ -451,6 +451,8 @@
svn_error_t *svn_cl__error_checked_fputs (const char *string,
FILE* stream);
+/* Return string representation of KIND. */
+const char *svn_cl__node_kind_str (svn_node_kind_t kind);
#ifdef __cplusplus
}
Index: subversion/clients/cmdline/util.c
===================================================================
--- subversion/clients/cmdline/util.c (revision 15532)
+++ subversion/clients/cmdline/util.c (working copy)
@@ -712,3 +712,18 @@
return err;
}
+
+
+const char *
+svn_cl__node_kind_str (svn_node_kind_t kind)
+{
+ switch (kind)
+ {
+ case svn_node_dir:
+ return "directory";
+ case svn_node_file:
+ return "file";
+ default:
+ return "";
+ }
+}
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 15532)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -371,8 +371,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/info-cmd.c
===================================================================
--- subversion/clients/cmdline/info-cmd.c (revision 15532)
+++ 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,247 @@
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 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);
+}
+
+
+/* Return string representation of SCHEDULE */
+static const char *
+schedule_str (svn_wc_schedule_t schedule)
+{
+ switch (schedule)
+ {
+ case svn_wc_schedule_normal:
+ return "normal";
+ case svn_wc_schedule_add:
+ return "add";
+ case svn_wc_schedule_delete:
+ return "delete";
+ case svn_wc_schedule_replace:
+ return "replace";
+ default:
+ return "none";
+ }
+}
+
+
+/* If the string DATA is non-null, format it in a simple XML CDATA element
+ * named TAGNAME and append the result to the string SB.
+ * Use POOL for temporary allocations. */
+static void
+make_tagged_cdata (svn_stringbuf_t **sb,
+ apr_pool_t *pool,
+ const char *tagname,
+ const char *data)
+{
+ if (data)
+ {
+ svn_xml_make_open_tag (sb, pool, svn_xml_protect_pcdata,
+ tagname, NULL);
+ svn_xml_escape_cdata_cstring (sb, data, pool);
+ svn_xml_make_close_tag (sb, pool, tagname);
+ }
+}
+
+
+/* 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)
+{
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+ const char *rev_str;
+
+ /* If revision is invalid, assume WC is corrupt. */
+ if (SVN_IS_VALID_REVNUM(info->rev))
+ rev_str = apr_psprintf (pool, "%" APR_OFF_T_FMT, info->rev);
+ else
+ return svn_error_createf (SVN_ERR_WC_CORRUPT, NULL,
+ _("'%s' has invalid revision"),
+ svn_path_local_style (target, pool));
+
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "entry",
+ "path", svn_path_local_style (target, pool),
+ "kind", svn_cl__node_kind_str (info->kind),
+ "revision", rev_str,
+ NULL);
+
+ make_tagged_cdata (&sb, pool, "url", info->URL);
+
+ if (info->repos_root_URL || info->repos_UUID)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "repository", NULL);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "root",
+ info->repos_root_URL);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "uuid",
+ info->repos_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);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "schedule",
+ schedule_str (info->schedule));
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "copy-from-url",
+ info->copyfrom_url);
+
+ if (SVN_IS_VALID_REVNUM (info->copyfrom_rev))
+ {
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "copied-from-rev",
+ apr_psprintf (pool, "%" APR_OFF_T_FMT,
+ info->copyfrom_rev));
+ }
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "checksum", info->checksum);
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "wc-info");
+ }
+
+ if (info->last_changed_author ||
+ SVN_IS_VALID_REVNUM (info->last_changed_rev) ||
+ info->last_changed_date)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "last-changed", NULL);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "author", info->last_changed_author);
+
+ if (SVN_IS_VALID_REVNUM (info->last_changed_rev))
+ {
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "revision",
+ apr_psprintf (pool, "%" APR_OFF_T_FMT,
+ info->last_changed_rev));
+ }
+
+ if (info->last_changed_date)
+ {
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "date",
+ svn_time_to_cstring (info->last_changed_date,
+ pool));
+ }
+
+ if (info->has_wc_info)
+ {
+ if (info->text_time)
+ {
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "text-updated",
+ svn_time_to_cstring (info->text_time, pool));
+ }
+
+ if (info->prop_time)
+ {
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "prop-updated",
+ svn_time_to_cstring (info->prop_time, pool));
+ }
+ }
+
+ /* "" */
+ 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);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "prev-base-file", info->conflict_old);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "prev-wc-file", info->conflict_wrk);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "cur-base-file", info->conflict_new);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "prop-file", info->prejfile);
+
+ /* "" */
+ svn_xml_make_close_tag (&sb, pool, "conflict");
+ }
+
+ if (info->lock)
+ {
+ /* "" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "lock", NULL);
+
+ make_tagged_cdata (&sb, pool, "token", info->lock->token);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "owner", info->lock->owner);
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "created",
+ svn_time_to_cstring (info->lock->creation_date,
+ pool));
+
+ /* " xx " */
+ make_tagged_cdata (&sb, pool, "expires",
+ svn_time_to_cstring (info->lock->expiration_date,
+ pool));
+
+ /* " xxxx " */
+ make_tagged_cdata (&sb, pool, "comment",
+ info->lock->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)
@@ -76,26 +316,9 @@
if (SVN_IS_VALID_REVNUM (info->rev))
SVN_ERR (svn_cmdline_printf (pool, _("Revision: %ld\n"), info->rev));
- switch (info->kind)
- {
- case svn_node_file:
- SVN_ERR (svn_cmdline_printf (pool, _("Node Kind: file\n")));
- break;
-
- case svn_node_dir:
- SVN_ERR (svn_cmdline_printf (pool, _("Node Kind: directory\n")));
- break;
-
- case svn_node_none:
- SVN_ERR (svn_cmdline_printf (pool, _("Node Kind: none\n")));
- break;
-
- case svn_node_unknown:
- default:
- SVN_ERR (svn_cmdline_printf (pool, _("Node Kind: unknown\n")));
- break;
- }
-
+
+ SVN_ERR (svn_cmdline_printf (pool, _("Node Kind: %s\n"),
+ svn_cl__node_kind_str (info->kind)));
if (info->has_wc_info)
{
switch (info->schedule)
@@ -217,7 +440,6 @@
}
-
/* A callback of type svn_info_receiver_t. */
static svn_error_t *
info_receiver (void *baton,
@@ -225,11 +447,13 @@
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);
}
-
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__info (apr_getopt_t *os,
@@ -249,6 +473,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++)
{
@@ -268,7 +509,7 @@
err = svn_client_info (truepath,
&peg_revision, &(opt_state->start_revision),
- info_receiver, NULL,
+ info_receiver, baton,
opt_state->recursive, ctx, subpool);
/* If one of the targets is a non-existent URL or wc-entry,
@@ -297,5 +538,8 @@
}
svn_pool_destroy (subpool);
+ if (opt_state->xml && (! opt_state->incremental))
+ SVN_ERR (print_footer_xml (pool));
+
return SVN_NO_ERROR;
}
Index: tools/client-side/bash_completion
===================================================================
--- tools/client-side/bash_completion (revision 15532)
+++ tools/client-side/bash_completion (working copy)
@@ -99,7 +99,8 @@
--editor-cmd $pOpts"
;;
info)
- cmdOpts="$pOpts $rOpts --targets -R --recursive"
+ cmdOpts="$pOpts $rOpts --targets -R --recursive \
+ --incremental --xml"
;;
list|ls)
cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \