[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] "--xml" option for "svn list"

From: Julian Foad <julianfoad_at_btopenworld.com>
Date: 2005-01-17 19:28:49 CET

It's time to submit this for review.

Log message:
[[[
Implement an XML output option for "svn list", similar to that for "svn log".

* doc/book/book/ch09.xml
   Document the new options for "svn list".

* subversion/clients/cmdline/ls-cmd.c
   (kind_str): New helper function.
   (print_dirents_xml): New.
   (svn_cl__ls): Output XML if requested.

* subversion/clients/cmdline/main.c
   (svn_cl__cmd_table):
     Add "--incremental" and "--xml" options to "list" command.

* tools/client-side/bash_completion
   (_svn): Add "--incremental" and "--xml" options to "list" command.
]]]

An XML DTD gives a concise description of the output format. I have just
written this, to cover "svn log" and "svn list". Should I include this in the
book and/or in a separate .dtd file?

[[[
<!-- XML DTD for Subversion command-line client output. -->

<!-- Common attributes and elements -->
<!-- revision number: integer -->
<!ENTITY % revision-attr "revision CDATA #REQUIRED">
<!ELEMENT author (#PCDATA)> <!-- user name -->
<!ELEMENT date (#PCDATA)> <!-- date as "yyyy-mm-ddThh:mm:ss.ssssssZ" -->

<!-- For "svn log" -->
<!ELEMENT log (logentry*)>
<!ELEMENT logentry (author, date, paths?, msg?)>
<!ATTLIST logentry %revision-attr;>
<!ELEMENT paths (path*)>
<!ELEMENT path (#PCDATA)> <!-- path within repository -->
<!ATTLIST path action CDATA #REQUIRED> <!-- action code: one character -->
<!ELEMENT msg (#PCDATA)> <!-- log message -->

<!-- For "svn list" -->
<!ELEMENT lists (list+)>
<!ELEMENT list (entry*)>
<!ATTLIST list path CDATA #REQUIRED> <!-- local path or URL -->
<!ELEMENT entry (name, size?, commit)>
<!ATTLIST entry kind (dir | file) #REQUIRED>
<!ELEMENT name (#PCDATA)> <!-- name of file or directory -->
<!ELEMENT size (#PCDATA)> <!-- file size in bytes: integer -->
<!ELEMENT commit (author, date)>
<!ATTLIST commit %revision-attr;>
]]]

- Julian

Implement an XML output option for "svn list", similar to that for "svn log".

* doc/book/book/ch09.xml
  Document the new options for "svn list".

* subversion/clients/cmdline/ls-cmd.c
  (kind_str): New helper function.
  (print_dirents_xml): New.
  (svn_cl__ls): Output XML if requested.

* subversion/clients/cmdline/main.c
  (svn_cl__cmd_table):
    Add "--incremental" and "--xml" options to "list" command.

* tools/client-side/bash_completion
  (_svn): Add "--incremental" and "--xml" options to "list" command.

Index: tools/client-side/bash_completion
===================================================================
--- tools/client-side/bash_completion (revision 12757)
+++ tools/client-side/bash_completion (working copy)
@@ -100,7 +100,8 @@ _svn()
                 cmdOpts="--targets -R --recursive"
                 ;;
         list|ls)
- cmdOpts="$rOpts -v --verbose -R --recursive $pOpts"
+ cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \
+ --incremental --xml"
                 ;;
         log)
                 cmdOpts="$rOpts -v --verbose --targets $pOpts --stop-on-copy \
Index: doc/book/book/ch09.xml
===================================================================
--- doc/book/book/ch09.xml (revision 12757)
+++ doc/book/book/ch09.xml (working copy)
@@ -1951,6 +1951,12 @@ Last Changed Date: 2003-01-16 23:21:19 -
             bytes)</para></listitem> <listitem><para>Date and time of
             the last commit</para></listitem>
           </itemizedlist>
+
+ <para>With <option>--xml</option>, output is in XML format (with
+ a header and an enclosing document element unless
+ <option>--incremental</option> is also specified). All of the
+ information is present; the <option>--verbose</option> option
+ is not accepted.</para>
         </refsect1>
 
         <refsect1>
@@ -1975,6 +1981,8 @@ Last Changed Date: 2003-01-16 23:21:19 -
 --revision (-r) REV
 --verbose (-v)
 --recursive (-R)
+--incremental
+--xml
 --username USER
 --password PASS
 --no-auth-cache
Index: subversion/clients/cmdline/ls-cmd.c
===================================================================
--- subversion/clients/cmdline/ls-cmd.c (revision 12757)
+++ subversion/clients/cmdline/ls-cmd.c (working copy)
@@ -28,8 +28,10 @@
 #include "svn_sorts.h"
 #include "svn_pools.h"
 #include "svn_time.h"
+#include "svn_xml.h"
 #include "cl.h"
 
+#include "svn_private_config.h"
 
 /*** Code. ***/
 
@@ -114,6 +116,109 @@
 }
 
 
+static const char *
+kind_str (svn_node_kind_t kind)
+{
+ switch (kind)
+ {
+ case svn_node_dir:
+ return "dir";
+ case svn_node_file:
+ return "file";
+ default:
+ return "";
+ }
+}
+
+
+static svn_error_t *
+print_dirents_xml (apr_hash_t *dirents,
+ const char *path,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ /* Collate whole list into sb before printing. */
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ apr_array_header_t *array;
+ int i;
+
+ array = svn_sort__hash (dirents, svn_sort_compare_items_as_paths, pool);
+
+ /* "<list path=...>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "list",
+ "path", path,
+ NULL);
+
+ for (i = 0; i < array->nelts; ++i)
+ {
+ const char *utf8_entryname;
+ svn_dirent_t *dirent;
+ svn_sort__item_t *item;
+
+ if (ctx->cancel_func)
+ SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
+
+ item = &APR_ARRAY_IDX (array, i, svn_sort__item_t);
+
+ utf8_entryname = item->key;
+
+ dirent = apr_hash_get (dirents, utf8_entryname, item->klen);
+
+ /* "<entry ...>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "entry",
+ "kind", kind_str (dirent->kind),
+ NULL);
+
+ /* "<name>xxx</name> */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "name", NULL);
+ svn_xml_escape_cdata_cstring (&sb, utf8_entryname, pool);
+ svn_xml_make_close_tag (&sb, pool, "name");
+
+ /* "<size>xxx</size>" */
+ if (dirent->kind == svn_node_file)
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "size",
+ NULL);
+ svn_xml_escape_cdata_cstring
+ (&sb, apr_psprintf (pool, "%" SVN_FILESIZE_T_FMT, dirent->size),
+ pool);
+ svn_xml_make_close_tag (&sb, pool, "size");
+ }
+
+ /* "<commit revision=...>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "commit",
+ "revision",
+ apr_psprintf (pool, "%" SVN_REVNUM_T_FMT,
+ dirent->created_rev),
+ NULL);
+ if (dirent->last_author)
+ {
+ /* "<author>xxx</author>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "author",
+ NULL);
+ svn_xml_escape_cdata_cstring (&sb, dirent->last_author, pool);
+ svn_xml_make_close_tag (&sb, pool, "author");
+ }
+ /* "<date>xxx</date>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "date", NULL);
+ svn_xml_escape_cdata_cstring
+ (&sb, svn_time_to_cstring (dirent->time, pool), pool);
+ svn_xml_make_close_tag (&sb, pool, "date");
+ /* "</commit>" */
+ svn_xml_make_close_tag (&sb, pool, "commit");
+
+ /* "</entry>" */
+ svn_xml_make_close_tag (&sb, pool, "entry");
+ }
+
+ /* "</list>" */
+ svn_xml_make_close_tag (&sb, pool, "list");
+
+ return svn_cmdline_printf (pool, "%s", sb->data);
+}
+
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__ls (apr_getopt_t *os,
@@ -132,6 +237,38 @@
   /* Add "." if user passed 0 arguments */
   svn_opt_push_implicit_dot_target (targets, pool);
 
+ if (opt_state->xml)
+ {
+ /* The XML output contains all the information, so "--verbose"
+ does not apply. */
+ if (opt_state->verbose)
+ return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'verbose' option invalid in XML mode"));
+
+ /* 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_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+
+ /* <?xml version="1.0" encoding="utf-8"?> */
+ svn_xml_make_header (&sb, pool);
+
+ /* "<lists>" */
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "lists", NULL);
+
+ SVN_ERR (svn_cmdline_printf (pool, "%s", sb->data));
+ }
+ }
+ else
+ {
+ if (opt_state->incremental)
+ return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("'incremental' option only valid in XML "
+ "mode"));
+ }
+
   /* For each target, try to list it. */
   for (i = 0; i < targets->nelts; i++)
     {
@@ -149,9 +286,24 @@
                                &(opt_state->start_revision),
                                opt_state->recursive, ctx, subpool));
 
- SVN_ERR (print_dirents (dirents, opt_state->verbose, ctx, subpool));
+ if (opt_state->xml)
+ SVN_ERR (print_dirents_xml (dirents, truepath, ctx, subpool));
+ else
+ SVN_ERR (print_dirents (dirents, opt_state->verbose, ctx, subpool));
+
       svn_pool_clear (subpool);
     }
 
+ if (opt_state->xml)
+ {
+ if (! opt_state->incremental)
+ {
+ svn_stringbuf_t *sb = svn_stringbuf_create ("", pool);
+ /* "</lists>" */
+ svn_xml_make_close_tag (&sb, pool, "lists");
+ SVN_ERR (svn_cmdline_printf (pool, "%s", sb->data));
+ }
+ }
+
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 12757)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -369,7 +369,8 @@
        " Author of the last commit\n"
        " Size (in bytes)\n"
        " Date and time of the last commit\n"),
- {'r', 'v', 'R', SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
+ {'r', 'v', 'R', svn_cl__incremental_opt, svn_cl__xml_opt,
+ SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
   
   { "log", svn_cl__log, {0},
     N_("Show the log messages for a set of revision(s) and/or file(s).\n"

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Mon Jan 17 19:32:48 2005

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.