{"thread":{"id":"15012","subject":"[PATCH v2 1/3] count-objects: Add total pack size to verbose output","startedAt":"2008-08-14T22:18:25Z","lastAt":"2008-08-15T15:47:39Z","messageCount":18,"participants":["Marcus Griep","Petr Baudis","Junio C Hamano","Shawn O. Pearce"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"87250","messageId":"1218752308-3173-1-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":null,"subject":"[PATCH v2 0/3] count-objects size and strbuf human-readable","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-14T22:18:25Z","receivedAt":"2008-08-14T22:18:25Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"This patch series does three things.  First, it allows count-objects\nto report pack size along side loose object size in verbose output.\n\nSecond, it adds a function to strbuf to assist in formatting values\nusing metric orders of magnitude in both SI and binary units, thus\nproviding a more human-readable display format.\n\nThird, it allows count-objects to utilize that faculty through an\nadditional command line argument which shows sizes in verbose\noutput as human readable values.\n\nMarcus Griep (3):\n  count-objects: Add total pack size to verbose output\n  strbuf: Add method to convert byte-size to human readable form\n  count-objects: add human-readable size option\n\n .gitignore                          |    1 +\n Documentation/git-count-objects.txt |   13 ++++--\n Makefile                            |    2 +-\n builtin-count-objects.c             |   31 +++++++++++-\n strbuf.c                            |   88 +++++++++++++++++++++++++++++++++++\n strbuf.h                            |    9 ++++\n t/t0031-human-readable.sh           |    9 ++++\n test-human-read.c                   |   64 +++++++++++++++++++++++++\n 8 files changed, 209 insertions(+), 8 deletions(-)\n create mode 100755 t/t0031-human-readable.sh\n create mode 100644 test-human-read.c\n"},{"id":"87249","messageId":"1218752308-3173-2-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218752308-3173-1-git-send-email-marcus@griep.us","subject":"[PATCH v2 1/3] count-objects: Add total pack size to verbose output","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-14T22:18:26Z","receivedAt":"2008-08-14T22:18:26Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Adds the total pack size (including indexes) the verbose count-objects\noutput, floored to the nearest kilobyte.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n builtin-count-objects.c |    3 +++\n 1 files changed, 3 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-count-objects.c b/builtin-count-objects.c\nindex 91b5487..249040b 100644\n--- a/builtin-count-objects.c\n+++ b/builtin-count-objects.c\n@@ -104,6 +104,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tif (verbose) {\n \t\tstruct packed_git *p;\n \t\tunsigned long num_pack = 0;\n+\t\tunsigned long size_pack = 0;\n \t\tif (!packed_git)\n \t\t\tprepare_packed_git();\n \t\tfor (p = packed_git; p; p = p->next) {\n@@ -112,12 +113,14 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tif (open_pack_index(p))\n \t\t\t\tcontinue;\n \t\t\tpacked += p->num_objects;\n+\t\t\tsize_pack += p->pack_size + p->index_size;\n \t\t\tnum_pack++;\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n \t\tprintf(\"size: %lu\\n\", loose_size / 2);\n \t\tprintf(\"in-pack: %lu\\n\", packed);\n \t\tprintf(\"packs: %lu\\n\", num_pack);\n+\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n \t}\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87251","messageId":"1218752308-3173-3-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218752308-3173-2-git-send-email-marcus@griep.us","subject":"[PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-14T22:18:27Z","receivedAt":"2008-08-14T22:18:27Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Takes a strbuf as its first argument and appends the human-readable\nform of 'value', the second argument, to that buffer.\n\nArgument 3, 'maxlen', specifies the longest string that should\nbe returned. That will make it easier for any pretty-ish formatting\nlike `ls` and `du` use. A value of 0 is unlimited length.\n\n'scale' specifies a boundary, above which 'value' should be\nreduced, and below which it should be reported. Commonly this is\n1000.  If 0, then it will find a scale that best fits into 'maxlen'.\nIf both 'maxlen' and 'scale' are 0, then scale will default to 1000.\n\n'suffix' is appended onto every formatted string.  This is often\n\"\", \"B\", \"bps\", \"objects\" etc.\n\n'flags' provides the ability to switch between a binary (1024)\nand an si (1000) period (HR_USE_SI).  Also, adding a space between\nnumber and unit (HR_SPACE).\n\nOn success, returns 0.  If maxlen is specified and there is not\nenough space given the scale or an inordinately large value, returns\n-n, where n is the amount of additional length necessary.\n\ne.g. strbuf_append_human_readable(sb, 1012, 0, 0, \"bps\", HR_SPACE)\nproduces \"0.9 Kbps\".\n\nAlso, add in test cases to ensure it produces the expected output\nand to demonstrate what different arguments do.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n .gitignore                |    1 +\n Makefile                  |    2 +-\n strbuf.c                  |   88 +++++++++++++++++++++++++++++++++++++++++++++\n strbuf.h                  |    9 +++++\n t/t0031-human-readable.sh |    9 +++++\n test-human-read.c         |   64 ++++++++++++++++++++++++++++++++\n 6 files changed, 172 insertions(+), 1 deletions(-)\n create mode 100755 t/t0031-human-readable.sh\n create mode 100644 test-human-read.c\n\ndiff --git a/.gitignore b/.gitignore\nindex a213e8e..d65fa75 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -146,6 +146,7 @@ test-date\n test-delta\n test-dump-cache-tree\n test-genrandom\n+test-human-read\n test-match-trees\n test-parse-options\n test-path-utils\ndiff --git a/Makefile b/Makefile\nindex 90c5a13..f17ab76 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1297,7 +1297,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X test-human-read$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/strbuf.c b/strbuf.c\nindex 720737d..78de035 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -308,3 +308,91 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)\n \n \treturn len;\n }\n+\n+int strbuf_append_human_readable(struct strbuf *sb,\n+\t\t\t\tdouble val,\n+\t\t\t\tint maxlen, int scale,\n+\t\t\t\tconst char *suffix,\n+\t\t\t\tint flags)\n+{\n+\tconst int maxscale = 7;\n+\n+        char *hr_prefixes[] = {\n+\t\t\"\", \"K\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n+\t};\n+        char **prefix = &hr_prefixes[0];\n+\tint period = 1024;\n+\tint sign = val < 0 ? -1 : 1;\n+\t/* Baselen is (sign, if needed) (digit) (space, if needed)\n+\t\t\t(prefix) (suffix) */\n+\tint baselen = (val < 0 ? 1 : 0) + 1 + (flags & HR_SPACE ? 1 : 0)\n+\t\t\t+ 1 + strlen(suffix);\n+\n+\tval *= sign;\n+\n+\tif (flags & HR_USE_SI) {\n+\t\tperiod = 1000;\n+\t\thr_prefixes[1] = \"k\";\n+\t}\n+\n+\tif (scale == 0) {\n+\t\tif (maxlen == 0) {\n+\t\t\tscale = 1000;\n+\t\t\tmaxlen = baselen + 3;\n+\t\t}\n+\t\telse {\n+\t\t\tint space = maxlen - baselen;\n+\t\t\tscale = 10;\n+\t\t\twhile (--space > 0) {\n+\t\t\t\tscale *= 10;\n+\t\t\t}\n+\t\t}\n+\t}\n+\telse {\n+\t\tint space = 1;\n+\t\tint check = 10;\n+\t\twhile (check < scale) {\n+\t\t\tcheck *= 10;\n+\t\t\t++space;\n+\t\t}\n+\t\tif (!maxlen)\n+\t\t\tmaxlen = baselen + space;\n+\t\tif (maxlen - baselen - space< 0)\n+\t\t\treturn maxlen - baselen - space;\n+\t}\n+\n+        while (val >= scale && *prefix++)\n+\t\tval /= period;\n+\n+        if (val >= scale) {\n+\t\tint needed = 0;\n+\t\twhile (val >= scale) {\n+\t\t\tval /= period;\n+\t\t\t--needed;\n+\t\t}\n+\t\treturn needed;\n+\t}\n+\n+\tstrbuf_addf(sb, \"%f\", sign * val);\n+\n+\tif (maxlen) {\n+\t\tint signlen = sign == -1 ? 1 : 0;\n+\t\tint len = maxlen - baselen\n+\t\t\t\t- (sb->buf[maxlen-baselen-1+signlen] == '.'\n+\t\t\t\t\t? 1\n+\t\t\t\t\t: 0);\n+\t\tif (len <= 0) {\n+\t\t\tstrbuf_setlen(sb, 0);\n+\t\t\treturn len - 1;\n+\t\t}\n+\t\tstrbuf_setlen(sb, len + signlen);\n+\t}\n+\n+\tstrbuf_addf(sb, \"%s%s%s\",\n+\t\tflags & HR_SPACE ? \" \" : \"\",\n+\t\t*prefix,\n+\t\tsuffix\n+\t\t);\n+\n+\treturn 0;\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex eba7ba4..14ccdf9 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -122,6 +122,15 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);\n \n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+#define HR_USE_SI 0x01\n+#define HR_SPACE  0x02\n+\n+extern int strbuf_append_human_readable(struct strbuf *,\n+\t\t\t\t\tdouble val,\n+\t\t\t\t\tint maxlen, int scale,\n+\t\t\t\t\tconst char *suffix,\n+\t\t\t\t\tint flags);\n+\n extern void stripspace(struct strbuf *buf, int skip_comments);\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n \ndiff --git a/t/t0031-human-readable.sh b/t/t0031-human-readable.sh\nnew file mode 100755\nindex 0000000..ce2fd77\n--- /dev/null\n+++ b/t/t0031-human-readable.sh\n@@ -0,0 +1,9 @@\n+#!/bin/sh\n+\n+test_description=\"Test human-readable formatting\"\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'human-readable formatting tests' 'test-human-read'\n+\n+test_done\ndiff --git a/test-human-read.c b/test-human-read.c\nnew file mode 100644\nindex 0000000..994b20b\n--- /dev/null\n+++ b/test-human-read.c\n@@ -0,0 +1,64 @@\n+#include \"builtin.h\"\n+#include \"strbuf.h\"\n+\n+struct test {\n+\tdouble val;\n+\tint len;\n+\tint scale;\n+\tchar *suffix;\n+\tint flags;\n+\n+\tchar *out;\n+\tint retval;\n+};\n+\n+int main(int argc, char **argv) {\n+\tint failures = 0, i, retval;\n+\tstruct test tests[] = {\n+\t\t{ 1012, 0, 0, \"\", HR_SPACE, \"0.9 K\", 0 },\n+\t\t{ 1012, 0, 0, \"iB\", HR_SPACE, \"0.9 KiB\", 0 },\n+\t\t{ 1012, 0, 0, \"B\", HR_SPACE | HR_USE_SI, \"1.0 kB\", 0 },\n+\t\t{ -1012, 0, 0, \"B\", HR_SPACE | HR_USE_SI, \"-1.0 kB\", 0 },\n+\t\t{ 1012, 6, 0, \"\", 0, \"1012\", 0 },\n+\t\t{ 1012, 6, 0, \"B\", 0, \"0.9KB\", 0 },\n+\t\t{ 1012, 5, 0, \"\", 0, \"0.9K\", 0 },\n+\t\t{ 1012, 4, 0, \"\", 0, \"0K\", 0 },\n+\t\t{ 1012, 3, 0, \"\", 0, \"0K\", 0 },\n+\t\t{ 1012, 2, 0, \"\", 0, \"\", -1 },\n+\t\t{ -1012, 6, 0, \"\", 0, \"-0.9K\", 0 },\n+\t\t{ -1012, 5, 0, \"\", 0, \"-0K\", 0 },\n+\t\t{ -1012, 4, 0, \"\", 0, \"-0K\", 0 },\n+\t\t{ -1012, 3, 0, \"\", 0, \"\", -1 },\n+\t\t{ 1012, 0, 1000, \"\", 0, \"0.9K\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 0, 1000000, \"\", 0, \"518144K\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 0, 1000000, \"iB\", 0, \"518144KiB\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 9, 1000000, \"\", 0, \"518144K\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 8, 1000000, \"\", 0, \"518144K\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 7, 1000000, \"\", 0, \"\", -1 },\n+\t\t{ 506.0 * 1024 * 1024, 6, 1000000, \"\", 0, \"\", -2 },\n+\t\t{ 506.0 * 1024 * 1024 * 1024, 0, 1000000, \"\", 0, \"518144M\", 0 },\n+\t\t{ 506.0 * 1024 * 1024 * 1024, 0, 1000000, \"\", HR_USE_SI, \"543313M\", 0 }\n+\t};\n+\tstruct strbuf sb;\n+\tstrbuf_init(&sb, 0);\n+\n+\tfor (i = 0; i < 23; ++i) {\n+\t\tprintf(\"Test %d: val: %g maxlen: %d scale: %d suffix: '%s' flags: %d\\n\", \n+\t\t\ti+1, tests[i].val, tests[i].len, tests[i].scale,\n+\t\t\ttests[i].suffix, tests[i].flags);\n+\t\tstrbuf_setlen(&sb, 0);\n+\t\tretval = strbuf_append_human_readable(&sb, tests[i].val, tests[i].len,\n+\t\t\t\ttests[i].scale, tests[i].suffix, tests[i].flags);\n+\t\tif(strcmp(sb.buf, tests[i].out)) {\n+\t\t\tprintf(\"\\tFailure: Expected '%s', actual '%s'\\n\",\n+\t\t\t\ttests[i].out, sb.buf);\n+\t\t\t++failures;\n+\t\t} else if (retval != tests[i].retval) {\n+\t\t\tprintf(\"\\tFailure: Expected retval '%d', actual retval '%d'\\n\",\n+\t\t\t\ttests[i].retval, retval);\n+\t\t\t++failures;\n+\t\t}\n+\t}\n+\n+\treturn failures;\n+}\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87252","messageId":"1218752308-3173-4-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218752308-3173-3-git-send-email-marcus@griep.us","subject":"[PATCH v2 3/3] count-objects: add human-readable size option","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-14T22:18:28Z","receivedAt":"2008-08-14T22:18:28Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Adds a human readable size option to the verbose output\nof count-objects for loose and pack object size totals.\n\nUpdates documentation to match.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n Documentation/git-count-objects.txt |   13 +++++++++----\n builtin-count-objects.c             |   30 ++++++++++++++++++++++++++----\n 2 files changed, 35 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt\nindex 75a8da1..291bc5e 100644\n--- a/Documentation/git-count-objects.txt\n+++ b/Documentation/git-count-objects.txt\n@@ -7,7 +7,7 @@ git-count-objects - Count unpacked number of objects and their disk consumption\n \n SYNOPSIS\n --------\n-'git count-objects' [-v]\n+'git count-objects' [-v [-H]]\n \n DESCRIPTION\n -----------\n@@ -21,9 +21,14 @@ OPTIONS\n --verbose::\n \tIn addition to the number of loose objects and disk\n \tspace consumed, it reports the number of in-pack\n-\tobjects, number of packs, and number of objects that can be\n-\tremoved by running `git prune-packed`.\n-\n+\tobjects, number of packs, disk space consumed by those packs\n+\tand number of objects that can be removed by running\n+\t`git prune-packed`.\n+\n+-H::\n+--human-sizes::\n+\tDisplays sizes reported by `--verbose` in a more\n+\thuman-readable format. (e.g. 22M or 1.5G)\n \n Author\n ------\ndiff --git a/builtin-count-objects.c b/builtin-count-objects.c\nindex 249040b..4be9d7e 100644\n--- a/builtin-count-objects.c\n+++ b/builtin-count-objects.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"strbuf.h\"\n \n static void count_objects(DIR *d, char *path, int len, int verbose,\n \t\t\t  unsigned long *loose,\n@@ -67,13 +68,13 @@ static void count_objects(DIR *d, char *path, int len, int verbose,\n }\n \n static char const * const count_objects_usage[] = {\n-\t\"git count-objects [-v]\",\n+\t\"git count-objects [-v [-H]]\",\n \tNULL\n };\n \n int cmd_count_objects(int argc, const char **argv, const char *prefix)\n {\n-\tint i, verbose = 0;\n+\tint i, verbose = 0, human_readable = 0;\n \tconst char *objdir = get_object_directory();\n \tint len = strlen(objdir);\n \tchar *path = xmalloc(len + 50);\n@@ -81,6 +82,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tunsigned long loose_size = 0;\n \tstruct option opts[] = {\n \t\tOPT__VERBOSE(&verbose),\n+\t\tOPT_BOOLEAN('H', \"human-sizes\", &human_readable,\n+\t\t\t\"displays sizes in human readable format\"),\n \t\tOPT_END(),\n \t};\n \n@@ -117,15 +120,34 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tnum_pack++;\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n-\t\tprintf(\"size: %lu\\n\", loose_size / 2);\n+\t\tprintf(\"size: \");\n+\t\tif (human_readable) {\n+\t\t\tstruct strbuf sb;\n+\t\t\tstrbuf_init(&sb, 0);\n+\t\t\tstrbuf_append_human_readable(&sb, loose_size * 512,\n+\t\t\t\t\t\t\t0, 0, \"\", 0);\n+\t\t\tprintf(\"%s\\n\", sb.buf);\n+\t\t}\n+\t\telse\n+\t\t\tprintf(\"%lu\\n\", loose_size / 2);\n \t\tprintf(\"in-pack: %lu\\n\", packed);\n \t\tprintf(\"packs: %lu\\n\", num_pack);\n-\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n+\t\tprintf(\"size-pack: \");\n+\t\tif (human_readable) {\n+\t\t\tstruct strbuf sb;\n+\t\t\tstrbuf_init(&sb, 0);\n+\t\t\tstrbuf_append_human_readable(&sb, size_pack,\n+\t\t\t\t\t\t\t0, 0, \"\", 0);\n+\t\t\tprintf(\"%s\\n\", sb.buf);\n+\t\t}\n+\t\telse\n+\t\t\tprintf(\"%lu\\n\", size_pack / 1024);\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n \t}\n \telse\n \t\tprintf(\"%lu objects, %lu kilobytes\\n\",\n \t\t       loose, loose_size / 2);\n+\n \treturn 0;\n }\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87257","messageId":"20080814223429.GC10544@machine.or.cz","threadId":"15012","inReplyTo":"1218752308-3173-3-git-send-email-marcus@griep.us","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2008-08-14T22:34:29Z","receivedAt":"2008-08-14T22:34:29Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Thu, Aug 14, 2008 at 06:18:27PM -0400, Marcus Griep wrote:\n> Takes a strbuf as its first argument and appends the human-readable\n> form of 'value', the second argument, to that buffer.\n> \n> Argument 3, 'maxlen', specifies the longest string that should\n> be returned. That will make it easier for any pretty-ish formatting\n> like `ls` and `du` use. A value of 0 is unlimited length.\n\nFrankly, I doubt this has too much value, and it complicates the code _a\nlot_. If you can't fit your stuff into pretty column, it's better to\njust print whatever you have to and disrupt the columns instead of\n_failing_, isn't it?\n\n> 'scale' specifies a boundary, above which 'value' should be\n> reduced, and below which it should be reported. Commonly this is\n> 1000.  If 0, then it will find a scale that best fits into 'maxlen'.\n> If both 'maxlen' and 'scale' are 0, then scale will default to 1000.\n> \n> 'suffix' is appended onto every formatted string.  This is often\n> \"\", \"B\", \"bps\", \"objects\" etc.\n> \n> 'flags' provides the ability to switch between a binary (1024)\n> and an si (1000) period (HR_USE_SI).  Also, adding a space between\n> number and unit (HR_SPACE).\n> \n> On success, returns 0.  If maxlen is specified and there is not\n> enough space given the scale or an inordinately large value, returns\n> -n, where n is the amount of additional length necessary.\n> \n> e.g. strbuf_append_human_readable(sb, 1012, 0, 0, \"bps\", HR_SPACE)\n> produces \"0.9 Kbps\".\n\nShouldn't pretty much all of this be documented in the code too?\n\n> Also, add in test cases to ensure it produces the expected output\n> and to demonstrate what different arguments do.\n> \n> Signed-off-by: Marcus Griep <marcus@griep.us>\n\nMy point still stands - in case of binary units, we should always\nconsistently use the i suffix. So having an example in the commit\nmessage that advertises \"bps\" is simply wrong when it should read \"iB/s\"\n(like it does with the current progress.c code).\n\nI may sound boring, but it seems to me that you're still ignoring my\npoint quitly without proper counter-argumentation and I think it's an\nimportant want, and since it's so hard to keep things consistent across\nthe wide Git codebase, we should do all we can to keep it.\n\n> +int strbuf_append_human_readable(struct strbuf *sb,\n> +\t\t\t\tdouble val,\n> +\t\t\t\tint maxlen, int scale,\n> +\t\t\t\tconst char *suffix,\n> +\t\t\t\tint flags)\n> +{\n> +\tconst int maxscale = 7;\n> +\n> +        char *hr_prefixes[] = {\n> +\t\t\"\", \"K\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n> +\t};\n> +        char **prefix = &hr_prefixes[0];\n\nWhitespace damage? Also at a lot of other places in your patch.\n\n> +\tint period = 1024;\n> +\tint sign = val < 0 ? -1 : 1;\n> +\t/* Baselen is (sign, if needed) (digit) (space, if needed)\n> +\t\t\t(prefix) (suffix) */\n> +\tint baselen = (val < 0 ? 1 : 0) + 1 + (flags & HR_SPACE ? 1 : 0)\n> +\t\t\t+ 1 + strlen(suffix);\n> +\n> +\tval *= sign;\n> +\n> +\tif (flags & HR_USE_SI) {\n> +\t\tperiod = 1000;\n> +\t\thr_prefixes[1] = \"k\";\n\nHmmm. We could have\n\n+        char *hr_prefixes[] = {\n+\t\t\"\", \"Ki\", \"Mi\", \"Gi\", \"Ti\", \"Pi\", \"Ei\", \"Zi\", \"Yi\", NULL\n+\t};\n+        char *hr_si_prefixes[] = {\n+\t\t\"\", \"k\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n+\t};\n\n;-)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nThe next generation of interesting software will be done\non the Macintosh, not the IBM PC.  -- Bill Gates\n"},{"id":"87258","messageId":"20080814223740.GD10544@machine.or.cz","threadId":"15012","inReplyTo":"1218752308-3173-4-git-send-email-marcus@griep.us","subject":"Re: [PATCH v2 3/3] count-objects: add human-readable size option","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2008-08-14T22:37:40Z","receivedAt":"2008-08-14T22:37:40Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Thu, Aug 14, 2008 at 06:18:28PM -0400, Marcus Griep wrote:\n> @@ -21,9 +21,14 @@ OPTIONS\n>  --verbose::\n>  \tIn addition to the number of loose objects and disk\n>  \tspace consumed, it reports the number of in-pack\n> -\tobjects, number of packs, and number of objects that can be\n> -\tremoved by running `git prune-packed`.\n> -\n> +\tobjects, number of packs, disk space consumed by those packs\n> +\tand number of objects that can be removed by running\n> +\t`git prune-packed`.\n> +\n> +-H::\n> +--human-sizes::\n> +\tDisplays sizes reported by `--verbose` in a more\n> +\thuman-readable format. (e.g. 22M or 1.5G)\n>  \n>  Author\n>  ------\n\nCan you guess what would I bug you about? ;-)\n\n> -\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n> +\t\tprintf(\"size-pack: \");\n> +\t\tif (human_readable) {\n> +\t\t\tstruct strbuf sb;\n> +\t\t\tstrbuf_init(&sb, 0);\n> +\t\t\tstrbuf_append_human_readable(&sb, size_pack,\n> +\t\t\t\t\t\t\t0, 0, \"\", 0);\n> +\t\t\tprintf(\"%s\\n\", sb.buf);\n> +\t\t}\n> +\t\telse\n> +\t\t\tprintf(\"%lu\\n\", size_pack / 1024);\n\nIf it's non-human-readable anyway, why are you dividing this by 1024? At\nany rate, it is not obvious at all that the size-pack is not actually\nsize-pack but size-pack/1024. You should either add the (fixed) unit\nstring behind or name it size-pack-kb - or just not divide it at all?\n\nThis also applies to PATCH1/3 in case it would get applied but the other\ntwo wouldn't.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nThe next generation of interesting software will be done\non the Macintosh, not the IBM PC.  -- Bill Gates\n"},{"id":"87267","messageId":"7viqu3ci5k.fsf@gitster.siamese.dyndns.org","threadId":"15012","inReplyTo":"20080814223429.GC10544@machine.or.cz","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-14T23:04:55Z","receivedAt":"2008-08-14T23:04:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> My point still stands - in case of binary units, we should always\n> consistently use the i suffix. So having an example in the commit\n> message that advertises \"bps\" is simply wrong when it should read \"iB/s\"\n> (like it does with the current progress.c code).\n>\n> I may sound boring, but it seems to me that you're still ignoring my\n> point quitly without proper counter-argumentation and I think it's an\n> important want, and since it's so hard to keep things consistent across\n> the wide Git codebase, we should do all we can to keep it.\n\nI pretty much agree with everything you said in this thread.  In addition,\nI wonder if we would want to be able to say:\n\n\t960 bps\n        0.9 KiB/s\n\t2.3 MiB/s\n\nIOW, I do not think it is a good idea to have the list of \"prefixes\" in\nthis function and force callers to _append_ unit.  You might be better off\nby making the interface to the function to pass something like this:\n\n\tstruct human_unit {\n\t\tchar *unitname;\n                unsigned long valuescale;\n\t} bps_to_human[] = {\n        \t{ \"bps\", 1 },\n                { \"KiB/s\", 1024 },\n                { \"MiB/s\", 1024 * 1024 },\n                { NULL, 0 },\n\t};\n\nand perhaps give canned set of unit list for sizes and throughputs as\nconvenience.\n\nBy doing so, you could even do this:\n\n\tstruct human_unit bits_to_human[] = {\n        \t{ \"bits\", 1 },\n                { \"bytes\", 8 },\n                { \"Kbytes\", 8 * 1024 },\n                { \"Mbytes\", 8 * 1024 * 1024 },\n                { NULL, 0 },\n\t};\n\nI also am not particularly happy about using \"double\" in this API.  Most\nof the callers that gather stats in the rest of the codebase count in\n(long) integers as far as I can tell, and it may be conceptually cleaner\nto keep the use of double as an internal implementation issue of this\nparticular function.\n"},{"id":"87271","messageId":"20080814232459.GF10360@machine.or.cz","threadId":"15012","inReplyTo":"7viqu3ci5k.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2008-08-14T23:24:59Z","receivedAt":"2008-08-14T23:24:59Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Thu, Aug 14, 2008 at 04:04:55PM -0700, Junio C Hamano wrote:\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> > My point still stands - in case of binary units, we should always\n> > consistently use the i suffix. So having an example in the commit\n> > message that advertises \"bps\" is simply wrong when it should read \"iB/s\"\n> > (like it does with the current progress.c code).\n> >\n> > I may sound boring, but it seems to me that you're still ignoring my\n> > point quitly without proper counter-argumentation and I think it's an\n> > important want, and since it's so hard to keep things consistent across\n> > the wide Git codebase, we should do all we can to keep it.\n> \n> I pretty much agree with everything you said in this thread.  In addition,\n> I wonder if we would want to be able to say:\n> \n> \t960 bps\n>         0.9 KiB/s\n> \t2.3 MiB/s\n\nI dont hink it would be a big deal to say bytes/s or B/s (which is as\nlong as bps).\n\n> IOW, I do not think it is a good idea to have the list of \"prefixes\" in\n> this function and force callers to _append_ unit.  You might be better off\n> by making the interface to the function to pass something like this:\n> \n> \tstruct human_unit {\n> \t\tchar *unitname;\n>                 unsigned long valuescale;\n> \t} bps_to_human[] = {\n>         \t{ \"bps\", 1 },\n>                 { \"KiB/s\", 1024 },\n>                 { \"MiB/s\", 1024 * 1024 },\n>                 { NULL, 0 },\n> \t};\n> \n> and perhaps give canned set of unit list for sizes and throughputs as\n> convenience.\n> \n> By doing so, you could even do this:\n> \n> \tstruct human_unit bits_to_human[] = {\n>         \t{ \"bits\", 1 },\n>                 { \"bytes\", 8 },\n>                 { \"Kbytes\", 8 * 1024 },\n>                 { \"Mbytes\", 8 * 1024 * 1024 },\n>                 { NULL, 0 },\n> \t};\n\nFrankly, my gut feeling here is that we are overengineering the whole\nthing quite a bit, which is the same reason I dislike maxlen.\n\nIf it turns out we really do need to have custom prefixes somewhere, we\nwould have to go with something like this, but on the other hand this\ngoes against the consistency of output, and I have a bit of trouble\nimagining a convincing use-case. So far we have two fairly different\nusers of such a code and just tailoring it to these two seems to make it\ngeneral enough for now.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nThe next generation of interesting software will be done\non the Macintosh, not the IBM PC.  -- Bill Gates\n"},{"id":"87274","messageId":"7vej4rcgi0.fsf@gitster.siamese.dyndns.org","threadId":"15012","inReplyTo":"20080814232459.GF10360@machine.or.cz","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-14T23:40:39Z","receivedAt":"2008-08-14T23:40:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> Frankly, my gut feeling here is that we are overengineering the whole\n> thing quite a bit, which is the same reason I dislike maxlen.\n\nFair enough.\n"},{"id":"87275","messageId":"48A4C521.6090507@griep.us","threadId":"15012","inReplyTo":"20080814223740.GD10544@machine.or.cz","subject":"Re: [PATCH v2 3/3] count-objects: add human-readable size option","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-14T23:52:01Z","receivedAt":"2008-08-14T23:52:01Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Petr Baudis wrote:\n>> +-H::\n> \n> Can you guess what would I bug you about? ;-)\n\nIf we get '-h', I'll submit another patch :-P\n\n> If it's non-human-readable anyway, why are you dividing this by 1024? At\n> any rate, it is not obvious at all that the size-pack is not actually\n> size-pack but size-pack/1024. You should either add the (fixed) unit\n> string behind or name it size-pack-kb - or just not divide it at all?\n\nI divide by 1024 here because the loose object size is reported in KiB.\nThe total that ends up in size_pack is in B, hence to be consistent, I\nreport the pack size in KiB as well.\n\n-- \nMarcus Griep\nGPG Key ID: 0x5E968152\n——\nhttp://www.boohaunt.net\nאת.ψο´\n"},{"id":"87278","messageId":"7vabffcf4e.fsf@gitster.siamese.dyndns.org","threadId":"15012","inReplyTo":"48A4C521.6090507@griep.us","subject":"Re: [PATCH v2 3/3] count-objects: add human-readable size option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-15T00:10:25Z","receivedAt":"2008-08-15T00:10:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Marcus Griep <marcus@griep.us> writes:\n\n> Petr Baudis wrote:\n>>> +-H::\n>> \n>> Can you guess what would I bug you about? ;-)\n>\n> If we get '-h', I'll submit another patch :-P\n\nWasn't the problem about documenting the addition of pack size, which is\nnot about this human-readable option?\n\n>> If it's non-human-readable anyway, why are you dividing this by 1024? At\n>> any rate, it is not obvious at all that the size-pack is not actually\n>> size-pack but size-pack/1024. You should either add the (fixed) unit\n>> string behind or name it size-pack-kb - or just not divide it at all?\n>\n> I divide by 1024 here because the loose object size is reported in KiB.\n> The total that ends up in size_pack is in B, hence to be consistent, I\n> report the pack size in KiB as well.\n\nI thought this part was ok without room for dispute.\n"},{"id":"87284","messageId":"48A4D1DD.9060202@griep.us","threadId":"15012","inReplyTo":"20080814223429.GC10544@machine.or.cz","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T00:46:21Z","receivedAt":"2008-08-15T00:46:21Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Petr Baudis wrote:\n> Frankly, I doubt this has too much value, and it complicates the code _a\n> lot_. If you can't fit your stuff into pretty column, it's better to\n> just print whatever you have to and disrupt the columns instead of\n> _failing_, isn't it?\n\nGenerally, the only reason for such a failure would be requesting\nconflicting scale and maxlen values or requesting a maxlen which would\nbe too small to reasonably display any value, hence an empty string and\na number reporting how much more is necessary to get appropriate output.\n\nIn other words, a failure reports that you probably requested an\nirrational number for maxlen.  It would probably be easier to understand\nif it were in terms of the numeric output rather than the entire string.\nIf I change it that way, then there shouldn't be an \"irrational\" positive\nnumber to request, eliminating the need for these failures.\n\n> Shouldn't pretty much all of this be documented in the code too?\n\nShould I stuff this in comments in the header file, source file, or both?\n\n> My point still stands - in case of binary units, we should always\n> consistently use the i suffix. So having an example in the commit\n> message that advertises \"bps\" is simply wrong when it should read \"iB/s\"\n> (like it does with the current progress.c code).\n> \n> I may sound boring, but it seems to me that you're still ignoring my\n> point quitly without proper counter-argumentation and I think it's an\n> important want, and since it's so hard to keep things consistent across\n> the wide Git codebase, we should do all we can to keep it.\n\nFrom a consistency standpoint, I can certainly agree.  It's not hard to\nimplement.  I wanted to avoid pigeon-holeing, but to keep our reporting\nconsistent, using '*i' for all binaries works for me.\n\n> Whitespace damage? Also at a lot of other places in your patch.\n\nNo damage.  It was indicated to me that 80-ish was the preferred width, so\nI was trying to follow that.  If that's not true in the C sources, I'll\nbundle things up a bit more.\n\n> Hmmm. We could have\n> \n> +        char *hr_prefixes[] = {\n> +\t\t\"\", \"Ki\", \"Mi\", \"Gi\", \"Ti\", \"Pi\", \"Ei\", \"Zi\", \"Yi\", NULL\n> +\t};\n> +        char *hr_si_prefixes[] = {\n> +\t\t\"\", \"k\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n> +\t};\n> \n> ;-)\n\nPer previous, sounds good to me.\n\nOverall, I was looking to create a generic function that could be used\nacross Git without making assumptions of the consumer.  Hence the maxlen,\nscale, SI, and space configurability.\n\nThanks for the input, and I'll work up another draft.\n\n-- \nMarcus Griep\nGPG Key ID: 0x5E968152\n——\nhttp://www.boohaunt.net\nאת.ψο´\n"},{"id":"87285","messageId":"20080815005212.GI3782@spearce.org","threadId":"15012","inReplyTo":"48A4D1DD.9060202@griep.us","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-08-15T00:52:12Z","receivedAt":"2008-08-15T00:52:12Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Marcus Griep <marcus@griep.us> wrote:\n> Petr Baudis wrote:\n> > Whitespace damage? Also at a lot of other places in your patch.\n> \n> No damage.  It was indicated to me that 80-ish was the preferred width, so\n> I was trying to follow that.  If that's not true in the C sources, I'll\n> bundle things up a bit more.\n\nThe sources are roughly:\n\n- 80 columns wide, try not to make it wider;\n\n- ident leading part of line with _TABs_ not spaces;\n\n- tab width in your editor should be 8, so you see when you\n  are too wide;\n\n- one tab per block in C;\n\n- don't align variable names in declarations;\n\n- use {} only around complex statements;\n\n... there's more.  But if you follow the above along with \"dammit,\nmake it match the code above and below where you are inserting\"\nyou get it pretty quick.\n\n-- \nShawn.\n"},{"id":"87286","messageId":"48A4D3A7.6080109@griep.us","threadId":"15012","inReplyTo":"7viqu3ci5k.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T00:53:59Z","receivedAt":"2008-08-15T00:53:59Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> \t960 bps\n>         0.9 KiB/s\n> \t2.3 MiB/s\n\nA pedantic note, but bps is bits per second, whereas Bps or B/s is bytes\nper second.  Requiring the same suffix for each would prevent some easily\noverlooked issues like this.\n\n> I also am not particularly happy about using \"double\" in this API.  Most\n> of the callers that gather stats in the rest of the codebase count in\n> (long) integers as far as I can tell, and it may be conceptually cleaner\n> to keep the use of double as an internal implementation issue of this\n> particular function.\n\nThe function requires the use of a double for fractional parts, so letting \nthe compiler perform an upcast were necessary seems innocuous to me.\n\nAlso, Yibi-/Zibi-, unlikely to be used as they are, won't fit in a long.\n\n-- \nMarcus Griep\nGPG Key ID: 0x5E968152\n——\nhttp://www.boohaunt.net\nאת.ψο´\n"},{"id":"87291","messageId":"1218774022-30198-1-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218752308-3173-1-git-send-email-marcus@griep.us","subject":"[PATCH v3 1/3] count-objects: Add total pack size to verbose output","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T04:20:20Z","receivedAt":"2008-08-15T04:20:20Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Adds the total pack size (including indexes) the verbose count-objects\noutput, floored to the nearest kilobyte.\n\nUpdates documentation to match this addition.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n Documentation/git-count-objects.txt |    5 +++--\n builtin-count-objects.c             |    3 +++\n 2 files changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt\nindex 75a8da1..6bc1c21 100644\n--- a/Documentation/git-count-objects.txt\n+++ b/Documentation/git-count-objects.txt\n@@ -21,8 +21,9 @@ OPTIONS\n --verbose::\n \tIn addition to the number of loose objects and disk\n \tspace consumed, it reports the number of in-pack\n-\tobjects, number of packs, and number of objects that can be\n-\tremoved by running `git prune-packed`.\n+\tobjects, number of packs, disk space consumed by those packs,\n+\tand number of objects that can be removed by running\n+\t`git prune-packed`.\n \n \n Author\ndiff --git a/builtin-count-objects.c b/builtin-count-objects.c\nindex 91b5487..249040b 100644\n--- a/builtin-count-objects.c\n+++ b/builtin-count-objects.c\n@@ -104,6 +104,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tif (verbose) {\n \t\tstruct packed_git *p;\n \t\tunsigned long num_pack = 0;\n+\t\tunsigned long size_pack = 0;\n \t\tif (!packed_git)\n \t\t\tprepare_packed_git();\n \t\tfor (p = packed_git; p; p = p->next) {\n@@ -112,12 +113,14 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tif (open_pack_index(p))\n \t\t\t\tcontinue;\n \t\t\tpacked += p->num_objects;\n+\t\t\tsize_pack += p->pack_size + p->index_size;\n \t\t\tnum_pack++;\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n \t\tprintf(\"size: %lu\\n\", loose_size / 2);\n \t\tprintf(\"in-pack: %lu\\n\", packed);\n \t\tprintf(\"packs: %lu\\n\", num_pack);\n+\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n \t}\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87290","messageId":"1218774022-30198-2-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218774022-30198-1-git-send-email-marcus@griep.us","subject":"[PATCH v3 2/3] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T04:20:21Z","receivedAt":"2008-08-15T04:20:21Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Takes a strbuf as its first argument and appends the human-readable\nform of 'value', the second argument, to that buffer.\n\ne.g. strbuf_append_human_readable(sb, 1012, 0, 0, HR_SPACE)\nproduces \"0.9 Ki\".\n\nDocumented in strbuf.h; units can be directly appended to the strbuf\nto produce \"0.9 KiB/s\", \"0.9 KiB\", or other unit.\n\nSupports SI magnitude prefixes as well:\ne.g. strbuf_append_human_readable(sb, 2024, 0, 0, HR_USE_SI)\nproduces \"2.0k\", to which a unit can be appended, such as \" objects\"\nto produce \"2.0k objects\".\n\nAlso, add in test cases to ensure it produces the expected output\nand to demonstrate what different arguments do.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n .gitignore                |    1 +\n Makefile                  |    2 +-\n strbuf.c                  |   92 +++++++++++++++++++++++++++++++++++++++++++++\n strbuf.h                  |   30 +++++++++++++++\n t/t0031-human-readable.sh |    9 ++++\n test-human-read.c         |   68 +++++++++++++++++++++++++++++++++\n 6 files changed, 201 insertions(+), 1 deletions(-)\n create mode 100755 t/t0031-human-readable.sh\n create mode 100644 test-human-read.c\n\ndiff --git a/.gitignore b/.gitignore\nindex a213e8e..d65fa75 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -146,6 +146,7 @@ test-date\n test-delta\n test-dump-cache-tree\n test-genrandom\n+test-human-read\n test-match-trees\n test-parse-options\n test-path-utils\ndiff --git a/Makefile b/Makefile\nindex 90c5a13..f17ab76 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1297,7 +1297,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X test-human-read$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/strbuf.c b/strbuf.c\nindex 720737d..d9888fb 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -308,3 +308,95 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)\n \n \treturn len;\n }\n+\n+int strbuf_append_human_readable(struct strbuf *sb,\n+\t\t\t\tdouble val,\n+\t\t\t\tint maxlen, int scale,\n+\t\t\t\tint flags)\n+{\n+\tconst int maxscale = 7;\n+\n+\tchar *hr_prefixes[] = {\n+\t\t\"\", \"Ki\", \"Mi\", \"Gi\", \"Ti\", \"Pi\", \"Ei\", \"Zi\", \"Yi\", NULL\n+\t};\n+\tchar *hr_si_prefixes[] = {\n+\t\t\"\", \"k\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n+\t};\n+\tchar **prefix = &hr_prefixes[0];\n+\tint period = 1024;\n+\tint sign = val < 0 ? -1 : 1;\n+\tint retval = 0;\n+\n+\tval *= sign;\n+\n+\tif (flags & HR_PAD_UNIT) {\n+\t\thr_prefixes[0] = \"  \";\n+\t\thr_si_prefixes[0] = \" \";\n+\t}\n+\n+\tif (flags & HR_USE_SI) {\n+\t\tperiod = 1000;\n+\t\tprefix = &hr_si_prefixes[0];\n+\t}\n+\n+\tif (scale == 0) {\n+\t\tif (maxlen == 0) {\n+\t\t\tscale = 1000;\n+\t\t\tmaxlen = 3;\n+\t\t}\n+\t\telse {\n+\t\t\tint space = maxlen;\n+\t\t\tscale = 10;\n+\t\t\twhile (--space > 0) {\n+\t\t\t\tscale *= 10;\n+\t\t\t}\n+\t\t}\n+\t}\n+\telse {\n+\t\tint space = 1;\n+\t\tint check = 10;\n+\t\tint setscale = scale;\n+\t\twhile (check < scale) {\n+\t\t\tcheck *= 10;\n+\t\t\t++space;\n+\t\t\tif (maxlen - space == 0)\n+\t\t\t\tsetscale = check;\n+\t\t}\n+\t\tif (!maxlen)\n+\t\t\tmaxlen = space;\n+\t\tscale = setscale;\n+\t}\n+\n+\twhile (val >= scale && *prefix++)\n+\t\tval /= period;\n+\n+\tif (val >= scale) {\n+\t\tint needed = 0;\n+\t\twhile (val >= scale) {\n+\t\t\tval /= period;\n+\t\t\t--needed;\n+\t\t}\n+\t\tif (needed < retval)\n+\t\t\tretval = needed;\n+\t}\n+\n+\tstrbuf_addf(sb, \"%f\", sign * val);\n+\n+\tif (maxlen) {\n+\t\tint signlen = sign == -1 ? 1 : 0;\n+\t\tmaxlen -= (sb->buf[maxlen-1+signlen] == '.' ? 1 : 0);\n+\t\tif (maxlen <= 0) {\n+\t\t\tstrbuf_setlen(sb, 0);\n+\t\t\tretval = maxlen - 1;\n+\t\t} else {\n+\t\t\tstrbuf_setlen(sb, maxlen + signlen);\n+\t\t}\n+\t}\n+\n+\tstrbuf_addf(sb, \"%s%s\",\n+\t\tflags & HR_SPACE ? \" \" : \"\",\n+\t\t*prefix\n+\t\t);\n+\n+\treturn retval;\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex eba7ba4..305ef55 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -125,4 +125,34 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);\n extern void stripspace(struct strbuf *buf, int skip_comments);\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n \n+/*\n+ * strbuf_append_human_readable\n+ *\n+ * 'val': value to be metrically-reduced to a human-readable number\n+ * 'maxlen': maximum number of characters to be taken up by the reduced 'val'\n+ *           not including the sign or magnitude (i.e. 'Ki') characters;\n+ *           when 'maxlen' is 0 length is controled by 'scale'\n+ * 'scale': when 'val' is greater than 'scale', 'val' is reduced by the\n+ *          period (default 1024, see 'flags') until it is less than 'scale';\n+ *          when 'scale' is 0, 'val' is reduced until it fits in 'maxlen';\n+ *          when 'scale' and 'maxlen' are both zero, 'scale' defaults to 1000\n+ * 'flags': HR_USE_SI: uses a period of 1000 and uses SI magnitude prefixes\n+ *          HR_SPACE: inserts a space between the reduced 'val' and the units\n+ *          HR_PAD_UNIT: instead of an empty string for singles, pads with\n+ *                       spaces to the length of the magnitude prefixes\n+ *\n+ * Returns 0 if 'val' is successfully reduced and fits in 'maxlen', otherwise\n+ * returns -n where n is the number of additional characters necessary to\n+ * fully fit the reduced value.\n+ */\n+\n+#define HR_USE_SI 0x01\n+#define HR_SPACE 0x02\n+#define HR_PAD_UNIT 0x04\n+\n+extern int strbuf_append_human_readable(struct strbuf *,\n+\t\t\t\t\tdouble val,\n+\t\t\t\t\tint maxlen, int scale,\n+\t\t\t\t\tint flags);\n+\n #endif /* STRBUF_H */\ndiff --git a/t/t0031-human-readable.sh b/t/t0031-human-readable.sh\nnew file mode 100755\nindex 0000000..ce2fd77\n--- /dev/null\n+++ b/t/t0031-human-readable.sh\n@@ -0,0 +1,9 @@\n+#!/bin/sh\n+\n+test_description=\"Test human-readable formatting\"\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'human-readable formatting tests' 'test-human-read'\n+\n+test_done\ndiff --git a/test-human-read.c b/test-human-read.c\nnew file mode 100644\nindex 0000000..855296c\n--- /dev/null\n+++ b/test-human-read.c\n@@ -0,0 +1,68 @@\n+#include \"builtin.h\"\n+#include \"strbuf.h\"\n+\n+struct test {\n+\tdouble val;\n+\tint len;\n+\tint scale;\n+\tint flags;\n+\n+\tchar *out;\n+\tint retval;\n+};\n+\n+int main(int argc, char **argv) {\n+\tint failures = 0, i = 0, retval;\n+\tstruct test tests[] = {\n+\t\t{ 1012, 0, 0, HR_SPACE, \"0.9 Ki\", 0 },\n+\t\t{ 1012, 0, 0, HR_SPACE, \"0.9 Ki\", 0 },\n+\t\t{ 1012, 0, 0, HR_SPACE | HR_USE_SI, \"1.0 k\", 0 },\n+\t\t{ -1012, 0, 0, HR_SPACE | HR_USE_SI, \"-1.0 k\", 0 },\n+\t\t{ 1012, 5, 0, HR_SPACE | HR_PAD_UNIT, \"1012   \", 0 },\n+\t\t{ 1012, 5, 0, HR_SPACE, \"1012 \", 0 },\n+\t\t{ 1012, 5, 0, HR_USE_SI | HR_SPACE | HR_PAD_UNIT, \"1012  \", 0 },\n+\t\t{ 1012, 5, 0, HR_USE_SI | HR_SPACE, \"1012 \", 0 },\n+\t\t{ 1012, 4, 0, 0, \"1012\", 0 },\n+\t\t{ 1012, 3, 0, 0, \"0.9Ki\", 0 },\n+\t\t{ 1012, 2, 0, 0, \"0Ki\", 0 },\n+\t\t{ 1012, 1, 0, 0, \"0Ki\", 0 },\n+\t\t{ 1012, 0, 0, 0, \"0.9Ki\", 0 },\n+\t\t{ -1012, 3, 0, 0, \"-0.9Ki\", 0 },\n+\t\t{ -1012, 2, 0, 0, \"-0Ki\", 0 },\n+\t\t{ -1012, 1, 0, 0, \"-0Ki\", 0 },\n+\t\t{ -1012, 0, 0, 0, \"-0.9Ki\", 0 },\n+\t\t{ 2024, 4, 0, 0, \"2024\", 0 },\n+\t\t{ 20240, 4, 0, 0, \"19.7Ki\", 0 },\n+\t\t{ 1012, 0, 1000, 0, \"0.9Ki\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 0, 1000000, 0, \"518144Ki\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 0, 1000000, 0, \"518144Ki\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 7, 1000000, 0, \"518144Ki\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 6, 1000000, 0, \"518144Ki\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 5, 1000000, 0, \"506.0Mi\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 4, 1000000, 0, \"506Mi\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 3, 1000000, 0, \"506Mi\", 0 },\n+\t\t{ 506.0 * 1024 * 1024, 2, 1000000, 0, \"0Gi\", 0 },\n+\t\t{ 506.0 * 1024 * 1024 * 1024, 0, 1000000, 0, \"518144Mi\", 0 },\n+\t\t{ 506.0 * 1024 * 1024 * 1024, 0, 1000000, HR_USE_SI, \"543313M\", 0 },\n+\t\t{ 0, 0, 0, 0, NULL, 0 }\n+\t};\n+\tstruct strbuf sb;\n+\tstruct test *current = &tests[0];\n+\tstrbuf_init(&sb, 0);\n+\n+\twhile(current->out) {\n+\t\tprintf(\"Test %2d - \", ++i);\n+\t\tstrbuf_setlen(&sb, 0);\n+\t\tretval = strbuf_append_human_readable(&sb, current->val, current->len,\n+\t\t\t\tcurrent->scale, current->flags);\n+\t\tif(strcmp(sb.buf, current->out) || retval != current->retval) {\n+\t\t\tprintf(\"Failure: Act '%s' (%d); Exp '%s' (%d)\\n\",\n+\t\t\t\tsb.buf, retval, current->out, current->retval);\n+\t\t\t++failures;\n+\t\t} else\n+\t\t\tprintf(\"Success: '%s' (%d)\\n\", sb.buf, retval);\n+\t\t++current;\n+\t}\n+\n+\treturn failures;\n+}\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87289","messageId":"1218774022-30198-3-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218774022-30198-2-git-send-email-marcus@griep.us","subject":"[PATCH v3 3/3] count-objects: add human-readable size option","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T04:20:22Z","receivedAt":"2008-08-15T04:20:22Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Adds a human readable size option to the verbose output\nof count-objects for loose and pack object size totals.\n\nUpdates documentation to match.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n Documentation/git-count-objects.txt |    6 +++++-\n builtin-count-objects.c             |   29 +++++++++++++++++++++++++----\n 2 files changed, 30 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt\nindex 6bc1c21..dc7b5b1 100644\n--- a/Documentation/git-count-objects.txt\n+++ b/Documentation/git-count-objects.txt\n@@ -7,7 +7,7 @@ git-count-objects - Count unpacked number of objects and their disk consumption\n \n SYNOPSIS\n --------\n-'git count-objects' [-v]\n+'git count-objects' [-v [-H]]\n \n DESCRIPTION\n -----------\n@@ -25,6 +25,10 @@ OPTIONS\n \tand number of objects that can be removed by running\n \t`git prune-packed`.\n \n+-H::\n+--human-sizes::\n+\tDisplays sizes reported by `--verbose` in a more\n+\thuman-readable format. (e.g. 22M or 1.5G)\n \n Author\n ------\ndiff --git a/builtin-count-objects.c b/builtin-count-objects.c\nindex 249040b..6b1cd37 100644\n--- a/builtin-count-objects.c\n+++ b/builtin-count-objects.c\n@@ -7,6 +7,7 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"strbuf.h\"\n \n static void count_objects(DIR *d, char *path, int len, int verbose,\n \t\t\t  unsigned long *loose,\n@@ -67,13 +68,13 @@ static void count_objects(DIR *d, char *path, int len, int verbose,\n }\n \n static char const * const count_objects_usage[] = {\n-\t\"git count-objects [-v]\",\n+\t\"git count-objects [-v [-H]]\",\n \tNULL\n };\n \n int cmd_count_objects(int argc, const char **argv, const char *prefix)\n {\n-\tint i, verbose = 0;\n+\tint i, verbose = 0, human_readable = 0;\n \tconst char *objdir = get_object_directory();\n \tint len = strlen(objdir);\n \tchar *path = xmalloc(len + 50);\n@@ -81,6 +82,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tunsigned long loose_size = 0;\n \tstruct option opts[] = {\n \t\tOPT__VERBOSE(&verbose),\n+\t\tOPT_BOOLEAN('H', \"human-sizes\", &human_readable,\n+\t\t\t\"displays sizes in human readable format\"),\n \t\tOPT_END(),\n \t};\n \n@@ -117,10 +120,28 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tnum_pack++;\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n-\t\tprintf(\"size: %lu\\n\", loose_size / 2);\n+\t\tprintf(\"size: \");\n+\t\tif (human_readable) {\n+\t\t\tstruct strbuf sb;\n+\t\t\tstrbuf_init(&sb, 0);\n+\t\t\tstrbuf_append_human_readable(&sb, loose_size * 512,\n+\t\t\t\t\t\t\t0, 0, 0);\n+\t\t\tprintf(\"%s\\n\", sb.buf);\n+\t\t}\n+\t\telse\n+\t\t\tprintf(\"%lu\\n\", loose_size / 2);\n \t\tprintf(\"in-pack: %lu\\n\", packed);\n \t\tprintf(\"packs: %lu\\n\", num_pack);\n-\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n+\t\tprintf(\"size-pack: \");\n+\t\tif (human_readable) {\n+\t\t\tstruct strbuf sb;\n+\t\t\tstrbuf_init(&sb, 0);\n+\t\t\tstrbuf_append_human_readable(&sb, size_pack,\n+\t\t\t\t\t\t\t0, 0, 0);\n+\t\t\tprintf(\"%s\\n\", sb.buf);\n+\t\t}\n+\t\telse\n+\t\t\tprintf(\"%lu\\n\", size_pack / 1024);\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n \t}\n-- \n1.6.0.rc2.6.g8eda3\n"},{"id":"87321","messageId":"1218815259-31816-1-git-send-email-marcus@griep.us","threadId":"15012","inReplyTo":"1218774022-30198-1-git-send-email-marcus@griep.us","subject":"[PATCH v3.1 1/3] count-objects: Add total pack size to verbose output","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-08-15T15:47:39Z","receivedAt":"2008-08-15T15:47:39Z","isPatch":true,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Adds the total pack size (including indexes) the verbose count-objects\noutput, floored to the nearest kilobyte.\n\nAs well, t5500 is sensitive to changes in the output of git-count-objects\nand is updated for the recent addition of size-pack to that command.\n\nUpdates documentation to match this addition.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n\n I realized that there was a breaking test in there that depended upon the\n output of git-count-objects.  I updated that test case to understand the\n additional output.\n\n Documentation/git-count-objects.txt |    5 +++--\n builtin-count-objects.c             |    3 +++\n t/t5500-fetch-pack.sh               |    3 ++-\n 3 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt\nindex 75a8da1..6bc1c21 100644\n--- a/Documentation/git-count-objects.txt\n+++ b/Documentation/git-count-objects.txt\n@@ -21,8 +21,9 @@ OPTIONS\n --verbose::\n \tIn addition to the number of loose objects and disk\n \tspace consumed, it reports the number of in-pack\n-\tobjects, number of packs, and number of objects that can be\n-\tremoved by running `git prune-packed`.\n+\tobjects, number of packs, disk space consumed by those packs,\n+\tand number of objects that can be removed by running\n+\t`git prune-packed`.\n \n \n Author\ndiff --git a/builtin-count-objects.c b/builtin-count-objects.c\nindex 91b5487..249040b 100644\n--- a/builtin-count-objects.c\n+++ b/builtin-count-objects.c\n@@ -104,6 +104,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \tif (verbose) {\n \t\tstruct packed_git *p;\n \t\tunsigned long num_pack = 0;\n+\t\tunsigned long size_pack = 0;\n \t\tif (!packed_git)\n \t\t\tprepare_packed_git();\n \t\tfor (p = packed_git; p; p = p->next) {\n@@ -112,12 +113,14 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)\n \t\t\tif (open_pack_index(p))\n \t\t\t\tcontinue;\n \t\t\tpacked += p->num_objects;\n+\t\t\tsize_pack += p->pack_size + p->index_size;\n \t\t\tnum_pack++;\n \t\t}\n \t\tprintf(\"count: %lu\\n\", loose);\n \t\tprintf(\"size: %lu\\n\", loose_size / 2);\n \t\tprintf(\"in-pack: %lu\\n\", packed);\n \t\tprintf(\"packs: %lu\\n\", num_pack);\n+\t\tprintf(\"size-pack: %lu\\n\", size_pack / 1024);\n \t\tprintf(\"prune-packable: %lu\\n\", packed_loose);\n \t\tprintf(\"garbage: %lu\\n\", garbage);\n \t}\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 362cf7e..399c8d9 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -137,7 +137,8 @@ test_expect_success \"clone shallow object count\" \\\n \t\"test \\\"in-pack: 18\\\" = \\\"$(grep in-pack count.shallow)\\\"\"\n \n count_output () {\n-\tsed -e '/^in-pack:/d' -e '/^packs:/d' -e '/: 0$/d' \"$1\"\n+\tsed -e '/^in-pack:/d' -e '/^size-pack:/d' \\\n+\t\t-e '/^packs:/d' -e '/: 0$/d' \"$1\"\n }\n \n test_expect_success \"clone shallow object count (part 2)\" '\n-- \n1.6.0.rc2.6.g8eda3\n"}]}