You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2018/11/25 04:57:09 UTC

svn commit: r1847384 - in /subversion/trunk/subversion/svn: cl.h list-cmd.c svn.c

Author: brane
Date: Sun Nov 25 04:57:09 2018
New Revision: 1847384

URL: http://svn.apache.org/viewvc?rev=1847384&view=rev
Log:
Make the 'svn list -v' output more human-friendly.

This change introduces two new mini-features:
  - The -H, --human-readable option, which makes 'svn list -v' display
    file sizes in base-2 units;
  - Automatic adjustment of the width of the 'author' field in the
    verbose output, within a set of limits, so that long author names
    are truncated less often.

In --human-readable form, the 'size' field is narrower, so the initial
and maximum widths of the 'author' field are adjusted to maintain
the same overall width of the 'svn list -v' output.

* subversion/svn/cl.h (svn_cl__opt_state_t): Add flag 'human_readable'.
* subversion/svn/svn.c
  (svn_cl__options): New option; -H, --human-readable.
  (svn_cl__cmd_table): Add the -H option to the 'list' command description.
  (sub_main): Handle the -H option.

* subversion/svn/list-cmd.c
  (struct print_baton): Add fields 'human_readable', 'author_width'
   and 'max_author_width; and moved 'ctx' to the start of the struct.
  (initial_author_width, initial_human_readable_author_width,
   maximum_author_width, maximum_human_readable_author_width,
   normal_size_width, human_readable_size_width): New static constants.
  (get_human_readable_size): New.
  (print_dirent): Auto-adjust the width of the author field and select
   plain or human-friendly display for the size field.
  (svn_cl__list): Initialize the new fields in the print_baton structure.

Modified:
    subversion/trunk/subversion/svn/cl.h
    subversion/trunk/subversion/svn/list-cmd.c
    subversion/trunk/subversion/svn/svn.c

Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1847384&r1=1847383&r2=1847384&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Sun Nov 25 04:57:09 2018
@@ -257,6 +257,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t adds_as_modification; /* update 'add vs add' no tree conflict */
   svn_boolean_t vacuum_pristines; /* remove unreferenced pristines */
   svn_boolean_t drop;             /* drop shelf after successful unshelve */
+  svn_boolean_t human_readable;   /* show human-readable output */
   enum svn_cl__viewspec_t {
       svn_cl__viewspec_unspecified = 0 /* default */,
       svn_cl__viewspec_classic,

Modified: subversion/trunk/subversion/svn/list-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/list-cmd.c?rev=1847384&r1=1847383&r2=1847384&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/list-cmd.c (original)
+++ subversion/trunk/subversion/svn/list-cmd.c Sun Nov 25 04:57:09 2018
@@ -40,8 +40,13 @@
 
 /* Baton used when printing directory entries. */
 struct print_baton {
-  svn_boolean_t verbose;
   svn_client_ctx_t *ctx;
+  svn_boolean_t verbose;
+  svn_boolean_t human_readable;
+
+  /* Keep track of the width of the author field. */
+  int author_width;
+  int max_author_width;
 
   /* To keep track of last seen external information. */
   const char *last_external_parent_url;
@@ -49,12 +54,73 @@ struct print_baton {
   svn_boolean_t in_external;
 };
 
+/* Starting and maximum width of the author field */
+static const int initial_author_width = 8;
+static const int initial_human_readable_author_width = 14;
+static const int maximum_author_width = 16;
+static const int maximum_human_readable_author_width = 22;
+
+/* Width of the size field */
+static const int normal_size_width = 10;
+static const int human_readable_size_width = 4;
+
 /* Field flags required for this function */
 static const apr_uint32_t print_dirent_fields = SVN_DIRENT_KIND;
 static const apr_uint32_t print_dirent_fields_verbose = (
     SVN_DIRENT_KIND  | SVN_DIRENT_SIZE | SVN_DIRENT_TIME |
     SVN_DIRENT_CREATED_REV | SVN_DIRENT_LAST_AUTHOR);
 
+/* Converts a file size to human-readable form with base-2 unit suffix.
+   File sizes are never negative, so we don't handle that case. */
+static const char *
+get_human_readable_size(svn_filesize_t size, apr_pool_t *scratch_pool)
+{
+  static const struct
+  {
+    svn_filesize_t mask;
+    char suffix;
+  }
+  order[] =
+    {
+      {APR_INT64_C(0x0000000000000000), 'B'}, /* byte */
+      {APR_INT64_C(0x00000000000003FF), 'K'}, /* kibi */
+      {APR_INT64_C(0x00000000000FFFFF), 'M'}, /* mibi */
+      {APR_INT64_C(0x000000003FFFFFFF), 'G'}, /* gibi */
+      {APR_INT64_C(0x000000FFFFFFFFFF), 'T'}, /* tibi */
+      {APR_INT64_C(0x0003FFFFFFFFFFFF), 'E'}, /* exbi */
+      {APR_INT64_C(0x0FFFFFFFFFFFFFFF), 'P'}  /* pibi */
+    };
+
+  const svn_filesize_t abs_size = ((size < 0) ? -size : size);
+  double human_readable_size;
+
+  /* Find the size mask for the (absolute) file size. It would be sexy to
+     do a binary search here, but with only 7 elements in the array ... */
+  apr_size_t index = sizeof(order) / sizeof(order[0]);
+  while (index > 0)
+    {
+      --index;
+      if (abs_size > order[index].mask)
+        break;
+    }
+
+  /* Adjust the size to the given order of magnitude.
+
+     This is division by (order[index].mask + 1), which is the base-2^10
+     magnitude of the size; and that is the same as an arithmetic right
+     shift by (index * 10) bits. But we split it into an integer and a
+     floating-point division, so that we don't overflow the mantissa at
+     very large file sizes. */
+  human_readable_size = (index == 0 ? (double)size
+                         : (size >> 3 * index) / 128.0 / index);
+
+  /* When the absolute adjusted size is < 10, show tenths of a unit, too.
+     NOTE: This will display the locale-specific decimal separator. */
+  return apr_psprintf(scratch_pool, "%.*f%c",
+                      (abs_size >> 10 * index < 10) ? 1 : 0,
+                      human_readable_size, order[index].suffix);
+}
+
 /* This implements the svn_client_list_func2_t API, printing a single
    directory entry in text format. */
 static svn_error_t *
@@ -121,7 +187,10 @@ print_dirent(void *baton,
       apr_status_t apr_err;
       apr_size_t size;
       char timestr[20];
-      const char *sizestr, *utf8_timestr;
+      const int sizewidth = (!pb->human_readable ? normal_size_width
+                             : human_readable_size_width);
+      const char *sizestr = "";
+      const char *utf8_timestr;
 
       /* svn_time_to_human_cstring gives us something *way* too long
          to use for this, so we have to roll our own.  We include
@@ -146,15 +215,36 @@ print_dirent(void *baton,
       /* we need it in UTF-8. */
       SVN_ERR(svn_utf_cstring_to_utf8(&utf8_timestr, timestr, scratch_pool));
 
-      sizestr = apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT,
-                             dirent->size);
+      /* We may have to adjust the width of th 'author' field. */
+      if (dirent->last_author)
+        {
+          const int author_width = (int)strlen(dirent->last_author);
+          if (author_width > pb->author_width)
+            {
+              if (author_width < pb->max_author_width)
+                pb->author_width = author_width;
+              else
+                pb->author_width = pb->max_author_width;
+            }
+        }
+
+      /* The format of the size field depends on the --human-readable flag. */
+      if (dirent->kind == svn_node_file)
+        {
+          if (pb->human_readable)
+            sizestr = get_human_readable_size(dirent->size, scratch_pool);
+          else
+            sizestr = apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT,
+                                   dirent->size);
+        }
 
       return svn_cmdline_printf
-              (scratch_pool, "%7ld %-8.8s %c %10s %12s %s%s\n",
+              (scratch_pool, "%7ld %-*.*s %c %*s %12s %s%s\n",
                dirent->created_rev,
+               pb->author_width, pb->author_width,
                dirent->last_author ? dirent->last_author : " ? ",
                lock ? 'O' : ' ',
-               (dirent->kind == svn_node_file) ? sizestr : "",
+               sizewidth, sizestr,
                utf8_timestr,
                entryname,
                (dirent->kind == svn_node_dir) ? "/" : "");
@@ -332,6 +422,11 @@ svn_cl__list(apr_getopt_t *os,
 
   pb.ctx = ctx;
   pb.verbose = opt_state->verbose;
+  pb.human_readable = opt_state->human_readable;
+  pb.author_width = (!pb.human_readable ? initial_author_width
+                     : initial_human_readable_author_width);
+  pb.max_author_width = (!pb.human_readable ? maximum_author_width
+                         : maximum_human_readable_author_width);
 
   if (opt_state->depth == svn_depth_unknown)
     opt_state->depth = svn_depth_immediates;

Modified: subversion/trunk/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/svn.c?rev=1847384&r1=1847383&r2=1847384&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/svn.c (original)
+++ subversion/trunk/subversion/svn/svn.c Sun Nov 25 04:57:09 2018
@@ -166,6 +166,7 @@ const apr_getopt_option_t svn_cl__option
   {"quiet",         'q', 0, N_("print nothing, or only summary information")},
   {"recursive",     'R', 0, N_("descend recursively, same as --depth=infinity")},
   {"non-recursive", 'N', 0, N_("obsolete")},
+  {"human-readable",'H', 0, N_("show human-readable output")},
   {"change",        'c', 1,
                     N_("the change made by revision ARG (like -r ARG-1:ARG)\n"
                        "                             "
@@ -895,8 +896,15 @@ const svn_opt_subcommand_desc3_t svn_cl_
      "    Size (in bytes)\n"
      "    Date and time of the last commit\n"
     )},
-    {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml,
-     opt_include_externals, opt_search}, },
+    {'r', 'v', 'R', 'H', opt_depth, opt_incremental, opt_xml,
+     opt_include_externals, opt_search},
+    {{'H', N_("with --verbose, show file sizes with base-2\n"
+              "                             "
+              "unit suffixes (Byte, Kilobyte, Megabyte,\n"
+              "                             "
+              "Gigabyte, Terabyte and Petabyte), limiting\n"
+              "                             "
+              "the number of digits to three or less")}} },
 
   { "lock", svn_cl__lock, {0}, {N_(
      "Lock working copy paths or URLs in the repository, so that\n"
@@ -2477,6 +2485,9 @@ sub_main(int *exit_code, int argc, const
       case 'N':
         descend = FALSE;
         break;
+      case 'H':
+        opt_state.human_readable = TRUE;
+        break;
       case opt_depth:
         err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
         if (err)