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

Re: [PATCH] add --xml to proplist command

From: señior ¿tyrtle? <machtyrtle_at_gmail.com>
Date: 2005-07-25 03:38:11 CEST

On 7/24/05 8:05 PM, "Julian Foad" <julianfoad@btopenworld.com> sneezed:

> numbers beginning with a "minus" sign will not be recognised as numbers.
> You'll say that's "just a bug" but that's far from the only problem,
What the hell is that? An ad hominem?
This really soured me on the rest of the message, some of which is just as
bad. From my first mail on this subject (second rev of the patch) I've been
completely open that parsing this data is somewhat nefarious, and that it is
grounds for rejection. You stated your reasons why you thought it was a bad
idea, which honestly, I already knew. When I state my reasons why I think
it isn't -so- bad, I'm labeled some sort of obstinate bastard?

For my purposes I -need- this type information, so it will be the first code
I write. There's no -need- for me to submit this patch, I'd like to.
I think I've been more than amiable; writing a DTD for a spec I thought
would be rejected, fixing formatting mistakes, patching to trunk, compiling
with gcc (for this rev) to catch these stupid errors my compiler is missing,
and even changing my beloved font...changing my font man!

I'm perfectly fine with writing a tool to do this separate from Subversion,
I just think it's beneficial to discuss options/scenarios, and to present,
what is as of now, the only real-world needs of this code...at least once.

I undertsand that you deal with a lot of people thinking/wanting certain
things that you feel are uneccessary or even wrong, but honestly, everyone
does. I've never been in one of those damn internet diatribes, or flame
wars...and don't want to start now...it's just that sentence really soured
me.

> Are you the same person who has been calling himself/herself
> something like "senior tyrtle"?
It would be señior as in Mr., not senior as in old.

Oh yeah, and that thing about not recognizing non-negative numbers, don't
worry, it's just a bug, I'll fix it good.

Fixed group_props_xml_rev to properly return an error code.
Not even begrudgingly removed type guessing code.

Index: subversion/subversion/clients/cmdline/props.c
===================================================================
--- subversion/subversion/clients/cmdline/props.c (revision 15400)
+++ subversion/subversion/clients/cmdline/props.c (working copy)
@@ -42,41 +42,3 @@
      _("Must specify revision explicitly when operating on a "
        "revision property"));
 }
-
-
-svn_error_t *
-svn_cl__print_prop_hash (apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first (pool, prop_hash); hi; hi = apr_hash_next (hi))
- {
- const void *key;
- void *val;
- const char *pname;
- svn_string_t *propval;
- const char *pname_stdout;
-
- apr_hash_this (hi, &key, NULL, &val);
- pname = key;
- propval = val;
-
- if (svn_prop_needs_translation (pname))
- SVN_ERR (svn_subst_detranslate_string (&propval, propval,
- TRUE, pool));
-
- SVN_ERR (svn_cmdline_cstring_from_utf8 (&pname_stdout, pname, pool));
-
- /* ### We leave these printfs for now, since if propval wasn't translated
- * above, we don't know anything about its encoding. In fact, it
- * might be binary data... */
- if (names_only)
- printf (" %s\n", pname_stdout);
- else
- printf (" %s : %s\n", pname_stdout, propval->data);
- }
-
- return SVN_NO_ERROR;
-}
Index: subversion/subversion/clients/cmdline/cl.h
===================================================================
--- subversion/subversion/clients/cmdline/cl.h (revision 15400)
+++ subversion/subversion/clients/cmdline/cl.h (working copy)
@@ -249,7 +249,6 @@
                                    svn_boolean_t repos_locks,
                                    apr_pool_t *pool);
 
-
 /* Print STATUS for PATH in XML to stdout. Use POOL for temporary
    allocations. */
 svn_error_t *
@@ -257,19 +256,6 @@
                           svn_wc_status2_t *status,
                           apr_pool_t *pool);
 
-
-/* Print a hash that maps property names (char *) to property values
- (svn_string_t *). The names are assumed to be in UTF-8 format;
- the values are either in UTF-8 (the special Subversion props) or
- plain binary values.
-
- If NAMES_ONLY is true, print just names, else print names and
- values. */
-svn_error_t *
-svn_cl__print_prop_hash (apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- apr_pool_t *pool);
-
 /* Return a SVN_ERR_CL_ARG_PARSING_ERROR error, with a message stating
    that one must give an explicit revision when operating on a
    revision property. */
Index: subversion/subversion/clients/cmdline/proplist-cmd.c
===================================================================
--- subversion/subversion/clients/cmdline/proplist-cmd.c (revision 15400)
+++ subversion/subversion/clients/cmdline/proplist-cmd.c (working copy)
@@ -26,7 +26,11 @@
 #include "svn_pools.h"
 #include "svn_client.h"
 #include "svn_error.h"
+#include "svn_subst.h"
 #include "svn_path.h"
+#include "svn_xml.h"
+#include "svn_time.h"
+#include "svn_base64.h"
 #include "cl.h"
 
 #include "svn_private_config.h"
@@ -34,6 +38,267 @@
 
 /*** Code. ***/
 
+/* A function that operates on a single property. The property name is in
+ PNAME, it's value in PROPVAL. A function of this type should be passed to
+ iterate_prop_hash. */
+typedef svn_error_t* (*prop_iter_function_t) (const char* pname,
+ const svn_string_t *propval,
+ void *refcon,
+ apr_pool_t *pool);
+
+/* A function that will arbitrarily group a set of properties if we're
+ iterating properties for more than one file/directory. The properties
+ are contained in PROP_HASH, and are the properties for the item in PATH.
+ PROP_HASH should probably be passed to iterate_prop_hash along with a
+ prop_iter_function_t. */
+typedef svn_error_t* (*prop_group_function_t) (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool);
+
+/* Tell iterate_prop_array how to compute the path it will send for printing.
+ The first two values also double as a boolean for whether the path is url.
+*/
+typedef enum {
+ print_path_local,
+ print_path_url,
+ print_path_absolute,
+} print_path_style_t;
+
+/* Iterate a hash that maps property names (char *) to property values
+ (svn_string_t *). The names are assumed to be in UTF-8 format;
+ the values are either in UTF-8 (the special Subversion props) or
+ plain binary values.
+
+ Pass the property name and a (possibly de-translated) value
+ to the print function in PRINT_FUNC. */
+static svn_error_t *
+iterate_prop_hash (apr_hash_t *prop_hash,
+ prop_iter_function_t print_func,
+ void *baton,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first (pool, prop_hash); hi; hi = apr_hash_next (hi))
+ {
+ const char *pname;
+ svn_string_t *propval;
+
+ apr_hash_this (hi, (const void **)&pname, NULL, (void**)&propval);
+
+ if (svn_prop_needs_translation (pname))
+ SVN_ERR (svn_subst_detranslate_string (&propval, propval,
+ TRUE, pool));
+
+ SVN_ERR (print_func (pname, propval, baton, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Iterate an array of props, where each element is a hash that maps
+ property names (char *) to property values (svn_string_t *).
+
+ Pass one hash and the current property's path to the print-function given
+ in GROUP_FUNC. The path is computed as either local, url, or absolute
+ depending on PATH_STYLE. */
+static svn_error_t*
+iterate_prop_array (apr_array_header_t *props,
+ print_path_style_t path_style,
+ prop_group_function_t group_func,
+ void *baton,
+ apr_pool_t *pool)
+{
+ int j;
+ for (j = 0; j < props->nelts; ++j)
+ {
+ svn_client_proplist_item_t *item
+ = ((svn_client_proplist_item_t **)props->elts)[j];
+ const char *name_local;
+
+ switch (path_style)
+ {
+ case print_path_absolute:
+ SVN_ERR (svn_path_get_absolute (&name_local,
+ item->node_name->data, pool));
+ break;
+
+ case print_path_local:
+ name_local = svn_path_local_style (item->node_name->data,
+ pool);
+ break;
+
+ case print_path_url:
+ default:
+ name_local = item->node_name->data;
+ break;
+ }
+
+ SVN_ERR (group_func (item->prop_hash, name_local, baton, pool));
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Print a property in xml, appending the svn_stringbuf_t
+ passed in baton. The property will be catagorized as one of 7 types
+ by attribute "type":
+ base64 base-64 encoded binary data.
+ date an ISO-8601 date
+ boolean a boolean value
+ integer an integer number
+ real a real/floating-point number
+ string a string
+
+ PNAME is the property name, PROPVAL it's value.
+ BATON is an svn_stringbuf_t.
+
+ This function is an prop_iter_function_t*/
+static svn_error_t *
+print_prop_xml (const char *pname,
+ const svn_string_t *propval,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *esc_name = NULL;
+ svn_stringbuf_t *sb = (svn_stringbuf_t*) baton;
+
+ svn_xml_escape_attr_cstring (&esc_name, pname, pool);
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "entry",
+ "name", esc_name->data, NULL);
+
+ svn_stringbuf_appendcstr (sb, "\n");
+ if (!svn_xml_is_xml_safe (propval->data, propval->len))
+ {
+ propval = svn_base64_encode_string (propval, pool);
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "value", "xml:encoding", "base64", NULL);
+ }
+ else
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata,
+ "value", NULL);
+
+ svn_xml_escape_cdata_string (&sb, propval, pool);
+ svn_xml_make_close_tag (&sb, pool, "value");
+
+ svn_xml_make_close_tag (&sb, pool, "entry");
+ return SVN_NO_ERROR;
+}
+
+/* Print the property name and, if NAMES_ONLY is non-null, it's value.
+
+ PNAME is the property name, PROPVAL it's value.
+
+ This function is an prop_iter_function_t*/
+static svn_error_t *
+print_prop_cl (const char *pname,
+ const svn_string_t *propval,
+ void *names_only,
+ apr_pool_t *pool)
+{
+ const char *pname_stdout;
+ SVN_ERR (svn_cmdline_cstring_from_utf8 (&pname_stdout, pname, pool));
+ /* ### We leave these printfs for now, since if propval wasn't translated
+ * above, we don't know anything about its encoding. In fact, it
+ * might be binary data... */
+ if (names_only)
+ printf (" %s\n", pname_stdout);
+ else
+ printf (" %s : %s\n", pname_stdout, propval->data);
+
+ return SVN_NO_ERROR;
+}
+
+/* Groups the properties given in PROP_HASH within tag-pair.
+ Appends the svn_stringbuf_t passed in SB.
+ If REV is SVN_INVALID_REVNUM, it is not output as an attribute.
+ <target path="PATH" revision="REV?">
+ call iterate_prop_hash
+ </target>
+*/
+static svn_error_t*
+group_props_xml_rev (apr_hash_t *prop_hash,
+ const char *path,
+ svn_stringbuf_t *sb,
+ apr_pool_t *pool,
+ svn_revnum_t rev)
+{
+ svn_stringbuf_t *escpath = NULL;
+
+ /* <target path=" _path_ "> */
+ svn_xml_escape_attr_cstring (&escpath, path, pool);
+ if (rev==SVN_INVALID_REVNUM)
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "target",
+ "path", escpath->data, NULL);
+ else
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "target",
+ "path", escpath->data,
+ "revision", apr_psprintf (pool, "%ld", rev),
+ NULL);
+
+ svn_stringbuf_appendcstr (sb, "\n");
+ SVN_ERR (iterate_prop_hash (prop_hash, print_prop_xml, sb, pool));
+
+ /* </target> */
+ svn_xml_make_close_tag (&sb, pool, "target");
+ return SVN_NO_ERROR;
+}
+
+/* Call through to the real grouping function (group_props_xml_rev) when the
+ the proper revsision number is not known.
+ Currently used for printing normal (not revision) properties.
+
+ This function is a prop_group_function_t. */
+static svn_error_t*
+group_props_xml (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool)
+{
+ return ( group_props_xml_rev (prop_hash, path, (svn_stringbuf_t*)baton,
+ pool, SVN_INVALID_REVNUM) );
+}
+
+
+/* Prints the filepath/url for the properties in PROP_HASH.
+ Then calls iterate_prop_hash to print the properties themselves.
+
+ This function is a prop_group_function_t. */
+static svn_error_t*
+group_props_cl (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool)
+ {
+ SVN_ERR (svn_cmdline_printf (pool, "Properties on '%s':\n", path));
+ SVN_ERR (iterate_prop_hash (prop_hash, print_prop_cl, baton, pool));
+ return SVN_NO_ERROR;
+}
+
+/* Create an svn_stringbuf_t, writes an xml header, and opens the first tag
+ (<propertylist>). */
+static svn_error_t *
+begin_xml_proplist (svn_stringbuf_t **sb,
+ apr_pool_t *pool)
+{
+ *sb = svn_stringbuf_create ("", pool);
+ svn_xml_make_header (sb, pool);
+ svn_xml_make_open_tag (sb, pool, svn_xml_normal, "propertylist", NULL);
+ return SVN_NO_ERROR;
+}
+
+/* Closes the xml tags started by begin_xml_proplist (</propertylist>),
+ and writes SB to stdout. */
+static svn_error_t *
+end_xml_proplist (svn_stringbuf_t *sb,
+ apr_pool_t *pool)
+{
+ svn_xml_make_close_tag (&sb, pool, "propertylist");
+ SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+ return SVN_NO_ERROR;
+}
+
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__proplist (apr_getopt_t *os,
@@ -43,6 +308,7 @@
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
+ svn_stringbuf_t *sb;
   int i;
 
   /* Suck up all remaining args in the target array. */
@@ -81,14 +347,22 @@
       SVN_ERR (svn_client_revprop_list (&proplist,
                                         URL, &(opt_state->start_revision),
                                         &rev, ctx, pool));
-
- SVN_ERR
- (svn_cmdline_printf (pool,
+
+ if (opt_state->xml)
+ {
+ begin_xml_proplist (&sb, pool);
+ SVN_ERR (group_props_xml_rev (proplist, URL, sb, pool, rev));
+ SVN_ERR (end_xml_proplist (sb, pool));
+ }
+ else
+ {
+ SVN_ERR (svn_cmdline_printf (pool,
                              _("Unversioned properties on revision %ld:\n"),
                              rev));
 
- SVN_ERR (svn_cl__print_prop_hash
- (proplist, (! opt_state->verbose), pool));
+ SVN_ERR (iterate_prop_hash (proplist, print_prop_cl,
+ (void*)(! opt_state->verbose), pool));
+ }
     }
   else /* operate on normal, versioned properties (not revprops) */
     {
@@ -98,7 +372,6 @@
         {
           const char *target = ((const char **) (targets->elts))[i];
           apr_array_header_t *props;
- int j;
           svn_boolean_t is_url = svn_path_is_url (target);
           const char *truepath;
           svn_opt_revision_t peg_revision;
@@ -120,23 +393,18 @@
                     SVN_ERR_ENTRY_NOT_FOUND,
                     SVN_NO_ERROR));
 
- for (j = 0; j < props->nelts; ++j)
+ if (opt_state->xml)
             {
- svn_client_proplist_item_t *item
- = ((svn_client_proplist_item_t **)props->elts)[j];
- const char *name_local;
+ begin_xml_proplist (&sb, pool);
+ SVN_ERR (iterate_prop_array (props, (print_path_style_t)is_url,
+ group_props_xml, sb, pool));
+ SVN_ERR (end_xml_proplist (sb, pool));
+ }
+ else
+ SVN_ERR (iterate_prop_array (props, (print_path_style_t)is_url,
+ group_props_cl,
+ (void*)opt_state->verbose, pool));
 
- if (! is_url)
- name_local = svn_path_local_style (item->node_name->data,
- subpool);
- else
- name_local = item->node_name->data;
-
- SVN_ERR (svn_cmdline_printf(subpool, "Properties on '%s':\n",
- name_local));
- SVN_ERR (svn_cl__print_prop_hash
- (item->prop_hash, (! opt_state->verbose), subpool));
- }
         }
       svn_pool_destroy (subpool);
     }
Index: subversion/subversion/clients/cmdline/main.c
===================================================================
--- subversion/subversion/clients/cmdline/main.c (revision 15400)
+++ subversion/subversion/clients/cmdline/main.c (working copy)
@@ -548,7 +548,7 @@
        " 1. Lists versioned props. If specified, REV determines in which\n"
        " revision the target is first looked up.\n"
        " 2. Lists unversioned remote props on repos revision.\n"),
- {'v', 'R', 'r', 'q', svn_cl__revprop_opt, SVN_CL__AUTH_OPTIONS,
+ {'v', 'R', 'r', 'q', svn_cl__revprop_opt, svn_cl__xml_opt, SVN_CL__AUTH_OPTIONS,
      svn_cl__config_dir_opt} },
 
   { "propset", svn_cl__propset, {"pset", "ps"},
Index: subversion/subversion/clients/cmdline/dtd/proplist.dtd
===================================================================
--- subversion/subversion/clients/cmdline/dtd/proplist.dtd (revision 0)
+++ subversion/subversion/clients/cmdline/dtd/proplist.dtd (revision 0)
@@ -0,0 +1,17 @@
+<!-- XML DTD for Subversion command-line client output. -->
+
+<!-- For "svn proplist" -->
+<!ELEMENT propertylist (target*)>
+<!ELEMENT target (entry*)>
+<!-- target is allowed to be empty (no properties) -->
+
+<!-- target must have a local path or URL in "path" attribute-->
+<!-- target can optionally specify the revision number (integer) -->
+<!ATTLIST target path CDATA #REQUIRED
+ revision CDATA #IMPLIED>
+<!ELEMENT entry (value)> <!-- entry must have one and only a value -->
+
+<!ATTLIST entry name CDATA #REQUIRED> <!-- entry must have a name -->
+
+<!ELEMENT value (#PCDATA)>
+<!ATTLIST value xml:encoding CDATA #IMPLIED> <!-- value can be state encoding -->
\ No newline at end of file

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Received on Mon Jul 25 03:40:34 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.