subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From br...@apache.org
Subject svn commit: r1661901 - in /subversion/branches/svn-info-detail: BRANCH-README subversion/svn/cl.h subversion/svn/info-cmd.c subversion/svn/svn.c
Date Tue, 24 Feb 2015 11:59:24 GMT
Author: brane
Date: Tue Feb 24 11:59:24 2015
New Revision: 1661901

URL: http://svn.apache.org/r1661901
Log:
On the svn-info-detail branch: Implement 'svn info --show-item [--no-newline]'.

* BRANCH-README: Update the branch description and status.

* subversion/svn/cl.h
  (svn_cl__opt_state_t): New option show_item.
* subversion/svn/svn.c
  (svn_cl__longopt_t): New option opt_show_item.
  (svn_cl__options): Describe it.
  (svn_cl__cmd_table): Add opt_show_item and opt_no_newline to the
   list of available options for 'svn info', and add a detailed description
   of the 'svn info --show-item' invocation.
  (sub_main): Parse the --show-item option argument.

* subversion/svn/info-cmd.c
  (info_item_t): New enumeration.
  (info_item_map_t): New struct.
  (info_item_map): Static array of known keywords for --show-item.
  (info_item_map_len): New.
  (print_info_baton_t): New; baton for the various print_info functions.
   Replaces the former use of just the path_prefix string as the baton.
  (find_print_what): New; converts the --show-item argument to its
   equivalent info_item_t enumeration value.
  (print_info_xml, print_info): Adjust to match the new baton type.
  (print_info_item): New handler for 'svn info --show-item'.
  (svn_cl__info): Initialize the receiver baton and handle the
   --show-item option, including checking valid option combinatinos.

Modified:
    subversion/branches/svn-info-detail/BRANCH-README
    subversion/branches/svn-info-detail/subversion/svn/cl.h
    subversion/branches/svn-info-detail/subversion/svn/info-cmd.c
    subversion/branches/svn-info-detail/subversion/svn/svn.c

Modified: subversion/branches/svn-info-detail/BRANCH-README
URL: http://svn.apache.org/viewvc/subversion/branches/svn-info-detail/BRANCH-README?rev=1661901&r1=1661900&r2=1661901&view=diff
==============================================================================
--- subversion/branches/svn-info-detail/BRANCH-README (original)
+++ subversion/branches/svn-info-detail/BRANCH-README Tue Feb 24 11:59:24 2015
@@ -4,20 +4,47 @@ the problem described in issue #4299 in
 Instead of 'svn youngest', we'll implement an extension to 'svn info',
 as described in option 1. of issue #4556, as follows:
 
-  - Add a --detail=FIELD option to 'svn info' that will cause it to
+  - The 'svn youngest' command will be removed.
+
+  - Add a --show-item=FIELD option to 'svn info' that will cause it to
     display only the value of FIELD and nothing else; for example:
 
-        $ svn info ^/subversion/trunk --detail=revision
+        $ svn info ^/subversion/trunk --show-item=revision
         1660035
-        $ svn info ^/subversion/trunk --detail=last-changed-rev
+        $ svn info ^/subversion/trunk --show-item=last-changed-rev
         1660014
 
     and so on.
 
-  - The --detail option is incompatible with the --xml option
+    When the 'svn info' command is invoked on multiple targets or
+    in recursive mode, the output will be modified to print the
+    requested item and the path or URL of the target:
+
+        $ svn info ^/subversion/trunk -R --show-item=last-changed-rev
+        1660014 http://svn.apache.org/repos/asf/subversion/trunk
+        915036 https://svn.apache.org/repos/asf/subversion/trunk/BUGS
+        ...
+
+  - The --show-item option is incompatible with the --xml option
+
+  - As was the case with the now defunct 'svn youngest' subcommand,
+    it's possible to use --no-newline with --show-item.
 
   - Initially, only a few field values will be supported with
-    --detail; revision, last-changed-rev, url, relative-url,
+    --show-item; revision, last-changed-rev, url, relative-url,
       repository-root; maybe a few more.
 
-  - The 'svn youngest' command will be removed.
+
+Branch Status
+=============
+
+TODO:
+  - Add tests for 'svn info --show-item'.
+  - Modify --show-item output with multiple targets and/or recursive
+    mode to display both the requested item and the (relative) path
+    and/or URL it applies to.
+
+DONE:
+  - Removed 'svn youngest' (already merged to trunk before 1.9.x branch).
+  - Implemented 'svn info --show-item [--no-newline]' with output suitable
+    for single targets.

Modified: subversion/branches/svn-info-detail/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-info-detail/subversion/svn/cl.h?rev=1661901&r1=1661900&r2=1661901&view=diff
==============================================================================
--- subversion/branches/svn-info-detail/subversion/svn/cl.h (original)
+++ subversion/branches/svn-info-detail/subversion/svn/cl.h Tue Feb 24 11:59:24 2015
@@ -249,6 +249,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t no_newline;        /* do not output the trailing newline */
   svn_boolean_t show_passwords;    /* show cached passwords */
   svn_boolean_t pin_externals;     /* pin externals to last-changed revisions */
+  const char *show_item;           /* print only the given item */
 } svn_cl__opt_state_t;
 
 

Modified: subversion/branches/svn-info-detail/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-info-detail/subversion/svn/info-cmd.c?rev=1661901&r1=1661900&r2=1661901&view=diff
==============================================================================
--- subversion/branches/svn-info-detail/subversion/svn/info-cmd.c (original)
+++ subversion/branches/svn-info-detail/subversion/svn/info-cmd.c Tue Feb 24 11:59:24 2015
@@ -89,6 +89,150 @@ relative_url(const svn_client_info2_t *i
 }
 
 
+/* The kinds of items for print_info_item(). */
+typedef enum
+{
+  /* Entry kind */
+  info_item_kind,
+
+  /* Repository location. */
+  info_item_url,
+  info_item_relative_url,
+  info_item_repos_root_url,
+  info_item_repos_uuid,
+
+  /* Working copy revision or repository HEAD revision */
+  info_item_revision,
+
+  /* Commit details. */
+  info_item_last_changed_rev,
+  info_item_last_changed_date,
+  info_item_last_changed_author,
+
+  /* Working copy information */
+  info_item_wc_root
+} info_item_t;
+
+/* Mapping between option keywords and info_item_t. */
+typedef struct info_item_map_t
+{
+  const svn_string_t keyword;
+  const info_item_t print_what;
+} info_item_map_t;
+
+#define MAKE_STRING(x) { x, sizeof(x) - 1 }
+static const info_item_map_t info_item_map[] =
+  {
+    { MAKE_STRING("kind"),                info_item_kind },
+    { MAKE_STRING("url"),                 info_item_url },
+    { MAKE_STRING("relative-url"),        info_item_relative_url },
+    { MAKE_STRING("repos-root-url"),      info_item_repos_root_url },
+    { MAKE_STRING("repos-uuid"),          info_item_repos_uuid },
+    { MAKE_STRING("revision"),            info_item_revision },
+    { MAKE_STRING("last-changed-rev"),    info_item_last_changed_rev },
+    { MAKE_STRING("last-changed-date"),   info_item_last_changed_date },
+    { MAKE_STRING("last-changed-author"), info_item_last_changed_author },
+    { MAKE_STRING("wc-root"),             info_item_wc_root }
+  };
+#undef MAKE_STRING
+
+static const apr_size_t info_item_map_len =
+  (sizeof(info_item_map) / sizeof(info_item_map[0]));
+
+
+/* The baton type used by the info receiver functions. */
+typedef struct print_info_baton_t
+{
+  /* The path prefix that output paths should be normalized to. */
+  const char *path_prefix;
+
+  /*
+   * The following fields are used by print_info_item().
+   */
+
+  /* Which item to print. */
+  info_item_t print_what;
+
+  /* Do we print the trailing newline? */
+  svn_boolean_t print_newline;
+
+} print_info_baton_t;
+
+
+/* Find the appropriate info_item_t for KEYWORD and initialize
+ * RECEIVER_BATON for print_info_item(). Use SCRATCH_POOL for
+ * temporary allocation.
+ */
+static svn_error_t *
+find_print_what(const char *keyword,
+                print_info_baton_t *receiver_baton,
+                apr_pool_t *scratch_pool)
+{
+  svn_cl__simcheck_t **keywords = apr_palloc(
+      scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t*));
+  svn_cl__simcheck_t *kwbuf = apr_palloc(
+      scratch_pool, info_item_map_len * sizeof(svn_cl__simcheck_t));
+  apr_size_t i;
+
+  for (i = 0; i < info_item_map_len; ++i)
+    {
+      keywords[i] = &kwbuf[i];
+      kwbuf[i].token.data = info_item_map[i].keyword.data;
+      kwbuf[i].token.len = info_item_map[i].keyword.len;
+      kwbuf[i].data = &info_item_map[i];
+    }
+
+  switch (svn_cl__similarity_check(keyword, keywords,
+                                   info_item_map_len, scratch_pool))
+    {
+      const info_item_map_t *kw0;
+      const info_item_map_t *kw1;
+      const info_item_map_t *kw2;
+
+    case 0:                     /* Exact match. */
+      kw0 = keywords[0]->data;
+      receiver_baton->print_what = kw0->print_what;
+      return SVN_NO_ERROR;
+
+    case 1:
+      /* The best alternative isn't good enough */
+      return svn_error_createf(
+          SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+          _("'%s' is not a valid value for the 'show-item' option."),
+          keyword);
+
+    case 2:
+      /* There is only one good candidate */
+      kw0 = keywords[0]->data;
+      return svn_error_createf(
+          SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+          _("'%s' is not a valid value for the 'show-item' option;"
+            " did you mean '%s'?"),
+          keyword, kw0->keyword.data);
+
+    case 3:
+      /* Suggest a list of the most likely candidates */
+      kw0 = keywords[0]->data;
+      kw1 = keywords[1]->data;
+      return svn_error_createf(
+          SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+          _("'%s' is not a valid value for the 'show-item' option;"
+            " did you mean '%s' or '%s'?"),
+          keyword, kw0->keyword.data, kw1->keyword.data);
+
+    default:
+      /* Never suggest more than three candidates */
+      kw0 = keywords[0]->data;
+      kw1 = keywords[1]->data;
+      kw2 = keywords[2]->data;
+      return svn_error_createf(
+          SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+          _("'%s' is not a valid value for the 'show-item' option;"
+            " did you mean '%s', '%s' or '%s'?"),
+          keyword, kw0->keyword.data, kw1->keyword.data, kw2->keyword.data);
+    }
+}
+
 /* A callback of type svn_client_info_receiver2_t.
    Prints svn info in xml mode to standard out */
 static svn_error_t *
@@ -99,7 +243,7 @@ print_info_xml(void *baton,
 {
   svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
   const char *rev_str;
-  const char *path_prefix = baton;
+  print_info_baton_t *const receiver_baton = baton;
 
   if (SVN_IS_VALID_REVNUM(info->rev))
     rev_str = apr_psprintf(pool, "%ld", info->rev);
@@ -109,7 +253,7 @@ print_info_xml(void *baton,
   /* "<entry ...>" */
   svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
                         "path", svn_cl__local_style_skip_ancestor(
-                                  path_prefix, target, pool),
+                                  receiver_baton->path_prefix, target, pool),
                         "kind", svn_cl__node_kind_str_xml(info->kind),
                         "revision", rev_str,
                         SVN_VA_NULL);
@@ -269,11 +413,11 @@ print_info(void *baton,
            const svn_client_info2_t *info,
            apr_pool_t *pool)
 {
-  const char *path_prefix = baton;
+  print_info_baton_t *const receiver_baton = baton;
 
   SVN_ERR(svn_cmdline_printf(pool, _("Path: %s\n"),
                              svn_cl__local_style_skip_ancestor(
-                               path_prefix, target, pool)));
+                               receiver_baton->path_prefix, target, pool)));
 
   /* ### remove this someday:  it's only here for cmdline output
      compatibility with svn 1.1 and older.  */
@@ -394,14 +538,14 @@ print_info(void *baton,
       if (info->wc_info->moved_from_abspath)
         SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"),
                                    svn_cl__local_style_skip_ancestor(
-                                      path_prefix,
+                                      receiver_baton->path_prefix,
                                       info->wc_info->moved_from_abspath,
                                       pool)));
 
       if (info->wc_info->moved_to_abspath)
         SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"),
                                    svn_cl__local_style_skip_ancestor(
-                                      path_prefix,
+                                      receiver_baton->path_prefix,
                                       info->wc_info->moved_to_abspath,
                                       pool)));
     }
@@ -449,21 +593,24 @@ print_info(void *baton,
                       SVN_ERR(svn_cmdline_printf(pool,
                                 _("Conflict Previous Base File: %s\n"),
                                 svn_cl__local_style_skip_ancestor(
-                                        path_prefix, conflict->base_abspath,
+                                        receiver_baton->path_prefix,
+                                        conflict->base_abspath,
                                         pool)));
 
                     if (conflict->my_abspath)
                       SVN_ERR(svn_cmdline_printf(pool,
                                 _("Conflict Previous Working File: %s\n"),
                                 svn_cl__local_style_skip_ancestor(
-                                        path_prefix, conflict->my_abspath,
+                                        receiver_baton->path_prefix,
+                                        conflict->my_abspath,
                                         pool)));
 
                     if (conflict->their_abspath)
                       SVN_ERR(svn_cmdline_printf(pool,
                                 _("Conflict Current Base File: %s\n"),
                                 svn_cl__local_style_skip_ancestor(
-                                        path_prefix, conflict->their_abspath,
+                                        receiver_baton->path_prefix,
+                                        conflict->their_abspath,
                                         pool)));
                   break;
 
@@ -472,7 +619,7 @@ print_info(void *baton,
                       SVN_ERR(svn_cmdline_printf(pool,
                                 _("Conflict Properties File: %s\n"),
                                 svn_cl__local_style_skip_ancestor(
-                                        path_prefix,
+                                        receiver_baton->path_prefix,
                                         conflict->prop_reject_abspath,
                                         pool)));
                     printed_prop_conflict_file = TRUE;
@@ -580,6 +727,96 @@ print_info(void *baton,
 }
 
 
+/* A callback of type svn_client_info_receiver2_t. */
+static svn_error_t *
+print_info_item(void *baton,
+                  const char *target,
+                  const svn_client_info2_t *info,
+                  apr_pool_t *pool)
+{
+  print_info_baton_t *const receiver_baton = baton;
+
+  switch (receiver_baton->print_what)
+    {
+    case info_item_kind:
+      switch (info->kind)
+        {
+        case svn_node_file:
+          SVN_ERR(svn_cmdline_fputs("file", stdout, pool));
+          break;
+
+        case svn_node_dir:
+          SVN_ERR(svn_cmdline_fputs("directory", stdout, pool));
+          break;
+
+        case svn_node_none:
+          SVN_ERR(svn_cmdline_fputs("none", stdout, pool));
+          break;
+
+        case svn_node_unknown:
+        default:
+          SVN_ERR(svn_cmdline_fputs("unknown", stdout, pool));
+          break;
+        }
+
+    case info_item_url:
+      SVN_ERR(svn_cmdline_fputs(info->URL, stdout, pool));
+      break;
+
+    case info_item_relative_url:
+      SVN_ERR(svn_cmdline_fputs(relative_url(info, pool), stdout, pool));
+      break;
+
+    case info_item_repos_root_url:
+      SVN_ERR(svn_cmdline_fputs(info->repos_root_URL, stdout, pool));
+      break;
+
+    case info_item_repos_uuid:
+      SVN_ERR(svn_cmdline_fputs(info->repos_UUID, stdout, pool));
+      break;
+
+    case info_item_revision:
+      SVN_ERR(svn_cmdline_printf(pool, "%ld", info->rev));
+      break;
+
+    case info_item_last_changed_rev:
+      SVN_ERR(svn_cmdline_printf(pool, "%ld", info->last_changed_rev));
+      break;
+
+    case info_item_last_changed_date:
+      SVN_ERR(svn_cmdline_fputs(
+                  svn_time_to_cstring(info->last_changed_date, pool),
+                  stdout, pool));
+      break;
+
+    case info_item_last_changed_author:
+      SVN_ERR(svn_cmdline_fputs(info->last_changed_author, stdout, pool));
+      break;
+
+    case info_item_wc_root:
+      /* FIXME: Consider just printing nothing if wc-root is not available. */
+      if (info->wc_info && info->wc_info->wcroot_abspath)
+        SVN_ERR(svn_cmdline_fputs(svn_dirent_local_style(
+                                      info->wc_info->wcroot_abspath,
+                                      pool),
+                                  stdout, pool));
+      else
+        return svn_error_create(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+                                _("Can't print the working copy root of"
+                                  " something that is not in a working copy"));
+      break;
+
+    default:
+      SVN_ERR_MALFUNCTION();
+    }
+
+  if (receiver_baton->print_newline)
+    SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__info(apr_getopt_t *os,
@@ -595,7 +832,7 @@ svn_cl__info(apr_getopt_t *os,
   svn_boolean_t seen_nonexistent_target = FALSE;
   svn_opt_revision_t peg_revision;
   svn_client_info_receiver2_t receiver;
-  const char *path_prefix;
+  print_info_baton_t receiver_baton = { 0 };
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -608,26 +845,52 @@ svn_cl__info(apr_getopt_t *os,
     {
       receiver = print_info_xml;
 
+      if (opt_state->show_item)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("the 'show-item' option is not valid"
+                                  " in XML mode"));
+      if (opt_state->no_newline)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("the 'no-newline' option is only valid"
+                                  " with the 'show-item' option"));
+
       /* 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(svn_cl__xml_print_header("info", pool));
     }
+  else if (opt_state->show_item)
+    {
+      receiver = print_info_item;
+
+      if (opt_state->incremental)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("the 'incremental' option is only valid"
+                                  " in XML mode"));
+
+      SVN_ERR(find_print_what(opt_state->show_item,
+                              &receiver_baton, pool));
+      receiver_baton.print_newline = !opt_state->no_newline;
+    }
   else
     {
       receiver = print_info;
 
       if (opt_state->incremental)
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("'incremental' option only valid in XML "
-                                  "mode"));
+                                _("the 'incremental' option is only valid"
+                                  " in XML mode"));
+      if (opt_state->no_newline)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("the 'no-newline' option is only valid"
+                                  " with the 'show-item' option"));
     }
 
   if (opt_state->depth == svn_depth_unknown)
     opt_state->depth = svn_depth_empty;
 
-  SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", pool));
+  SVN_ERR(svn_dirent_get_absolute(&receiver_baton.path_prefix, "", pool));
 
   for (i = 0; i < targets->nelts; i++)
     {
@@ -658,7 +921,7 @@ svn_cl__info(apr_getopt_t *os,
                              TRUE /* fetch_actual_only */,
                              opt_state->include_externals,
                              opt_state->changelists,
-                             receiver, (void *) path_prefix,
+                             receiver, &receiver_baton,
                              ctx, subpool);
 
       if (err)

Modified: subversion/branches/svn-info-detail/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-info-detail/subversion/svn/svn.c?rev=1661901&r1=1661900&r2=1661901&view=diff
==============================================================================
--- subversion/branches/svn-info-detail/subversion/svn/svn.c (original)
+++ subversion/branches/svn-info-detail/subversion/svn/svn.c Tue Feb 24 11:59:24 2015
@@ -146,6 +146,7 @@ typedef enum svn_cl__longopt_t {
   opt_no_newline,
   opt_show_passwords,
   opt_pin_externals,
+  opt_show_item,
 } svn_cl__longopt_t;
 
 
@@ -423,6 +424,8 @@ const apr_getopt_option_t svn_cl__option
                        N_("pin externals with no explicit revision to their\n"
                           "                             "
                           "current revision (recommended when tagging)")},
+  {"show-item", opt_show_item, 1,
+                       N_("print only the item identified by ARG")},
 
   /* Long-opt Aliases
    *
@@ -721,9 +724,25 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "\n"
      "  Print information about each TARGET (default: '.').\n"
      "  TARGET may be either a working-copy path or URL.  If specified, REV\n"
-     "  determines in which revision the target is first looked up.\n"),
+     "  determines in which revision the target is first looked up.\n"
+     "\n"
+     "  With --show-item, print only the value of one item of information\n"
+     "  about TARGET. One of the following items can be selected:\n"
+     "     kind                  the kind of TARGET\n"
+     "     url                   the URL of TARGET in the repository\n"
+     "     relative-url          the repositor-relative URL\n"
+     "     repos-root-url        the repository root URL\n"
+     "     repos-uuid            the repository UUID\n"
+     "     revision              if TARGET is a local path, its working\n"
+     "                           copy revision; otherwise, the HEAD revision\n"
+     "                           of the repository\n"
+     "     last-changed-rev      the most recent revision in which TARGET\n"
+     "                           was changed\n"
+     "     last-changed-date     the date of the last-changed revision\n"
+     "     last-changed-author   the author of the last-changed revision\n"
+     "     wc-root               the root of TARGET's working copy"),
     {'r', 'R', opt_depth, opt_targets, opt_incremental, opt_xml,
-     opt_changelist, opt_include_externals}
+     opt_changelist, opt_include_externals, opt_show_item, opt_no_newline}
   },
 
   { "list", svn_cl__list, {"ls"}, N_
@@ -2391,6 +2410,10 @@ sub_main(int *exit_code, int argc, const
       case opt_pin_externals:
         opt_state.pin_externals = TRUE;
         break;
+      case opt_show_item:
+        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+        opt_state.show_item = utf8_opt_arg;
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */



Mime
View raw message