aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Tobler <jltobler@gmail.com>2025-12-17 11:54:00 -0600
committerJunio C Hamano <gitster@pobox.com>2025-12-18 09:02:31 +0900
commit54731320cc3db337f9a3e3920f707e9de3596c60 (patch)
tree56e999bbf02332ec73d67f47b387ff68425ca7c8
parentce849b1851102d974653701564573798034492d5 (diff)
downloadgit-54731320cc3db337f9a3e3920f707e9de3596c60.tar.xz
builtin/repo: humanise count values in structure output
The table output format for the git-repo(1) structure subcommand is used by default and intended to provide output to users in a human-friendly manner. When the reference/object count values in a repository are large, it becomes more cumbersome for users to read the values. For larger values, update the table output format to instead produce more human-friendly count values that are scaled down with the appropriate unit prefix. Output for the keyvalue and nul formats remains unchanged. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--builtin/repo.c38
-rw-r--r--strbuf.c26
-rw-r--r--strbuf.h6
-rwxr-xr-xt/t1901-repo-structure.sh62
4 files changed, 91 insertions, 41 deletions
diff --git a/builtin/repo.c b/builtin/repo.c
index a69699857a..9c61bc3e17 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -223,6 +223,7 @@ struct stats_table {
int name_col_width;
int value_col_width;
+ int unit_col_width;
};
/*
@@ -230,6 +231,7 @@ struct stats_table {
*/
struct stats_table_entry {
char *value;
+ const char *unit;
};
static void stats_table_vaddf(struct stats_table *table,
@@ -250,11 +252,18 @@ static void stats_table_vaddf(struct stats_table *table,
if (name_width > table->name_col_width)
table->name_col_width = name_width;
- if (entry) {
+ if (!entry)
+ return;
+ if (entry->value) {
int value_width = utf8_strwidth(entry->value);
if (value_width > table->value_col_width)
table->value_col_width = value_width;
}
+ if (entry->unit) {
+ int unit_width = utf8_strwidth(entry->unit);
+ if (unit_width > table->unit_col_width)
+ table->unit_col_width = unit_width;
+ }
}
static void stats_table_addf(struct stats_table *table, const char *format, ...)
@@ -273,7 +282,7 @@ static void stats_table_count_addf(struct stats_table *table, size_t value,
va_list ap;
CALLOC_ARRAY(entry, 1);
- entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value);
+ humanise_count(value, &entry->value, &entry->unit);
va_start(ap, format);
stats_table_vaddf(table, entry, format, ap);
@@ -324,20 +333,24 @@ static void stats_table_print_structure(const struct stats_table *table)
{
const char *name_col_title = _("Repository structure");
const char *value_col_title = _("Value");
- int name_col_width = utf8_strwidth(name_col_title);
- int value_col_width = utf8_strwidth(value_col_title);
+ int title_name_width = utf8_strwidth(name_col_title);
+ int title_value_width = utf8_strwidth(value_col_title);
+ int name_col_width = table->name_col_width;
+ int value_col_width = table->value_col_width;
+ int unit_col_width = table->unit_col_width;
struct string_list_item *item;
struct strbuf buf = STRBUF_INIT;
- if (table->name_col_width > name_col_width)
- name_col_width = table->name_col_width;
- if (table->value_col_width > value_col_width)
- value_col_width = table->value_col_width;
+ if (title_name_width > name_col_width)
+ name_col_width = title_name_width;
+ if (title_value_width > value_col_width + unit_col_width + 1)
+ value_col_width = title_value_width - unit_col_width;
strbuf_addstr(&buf, "| ");
strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, name_col_title);
strbuf_addstr(&buf, " | ");
- strbuf_utf8_align(&buf, ALIGN_LEFT, value_col_width, value_col_title);
+ strbuf_utf8_align(&buf, ALIGN_LEFT,
+ value_col_width + unit_col_width + 1, value_col_title);
strbuf_addstr(&buf, " |");
printf("%s\n", buf.buf);
@@ -345,17 +358,20 @@ static void stats_table_print_structure(const struct stats_table *table)
for (int i = 0; i < name_col_width; i++)
putchar('-');
printf(" | ");
- for (int i = 0; i < value_col_width; i++)
+ for (int i = 0; i < value_col_width + unit_col_width + 1; i++)
putchar('-');
printf(" |\n");
for_each_string_list_item(item, &table->rows) {
struct stats_table_entry *entry = item->util;
const char *value = "";
+ const char *unit = "";
if (entry) {
struct stats_table_entry *entry = item->util;
value = entry->value;
+ if (entry->unit)
+ unit = entry->unit;
}
strbuf_reset(&buf);
@@ -363,6 +379,8 @@ static void stats_table_print_structure(const struct stats_table *table)
strbuf_utf8_align(&buf, ALIGN_LEFT, name_col_width, item->string);
strbuf_addstr(&buf, " | ");
strbuf_utf8_align(&buf, ALIGN_RIGHT, value_col_width, value);
+ strbuf_addch(&buf, ' ');
+ strbuf_utf8_align(&buf, ALIGN_LEFT, unit_col_width, unit);
strbuf_addstr(&buf, " |");
printf("%s\n", buf.buf);
}
diff --git a/strbuf.c b/strbuf.c
index 349ee9727a..995ff15169 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -836,6 +836,32 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn);
}
+void humanise_count(size_t count, char **value, const char **unit)
+{
+ if (count >= 1000000000) {
+ size_t x = count + 5000000; /* for rounding */
+ *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000000),
+ (unsigned)(x % 1000000000 / 10000000));
+ /* TRANSLATORS: SI decimal prefix symbol for 10^9 */
+ *unit = _("G");
+ } else if (count >= 1000000) {
+ size_t x = count + 5000; /* for rounding */
+ *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000),
+ (unsigned)(x % 1000000 / 10000));
+ /* TRANSLATORS: SI decimal prefix symbol for 10^6 */
+ *unit = _("M");
+ } else if (count >= 1000) {
+ size_t x = count + 5; /* for rounding */
+ *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000),
+ (unsigned)(x % 1000 / 10));
+ /* TRANSLATORS: SI decimal prefix symbol for 10^3 */
+ *unit = _("k");
+ } else {
+ *value = xstrfmt("%u", (unsigned)count);
+ *unit = NULL;
+ }
+}
+
void humanise_bytes(off_t bytes, char **value, const char **unit,
unsigned flags)
{
diff --git a/strbuf.h b/strbuf.h
index 698b3cc4a5..52feef4c1b 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -382,6 +382,12 @@ void humanise_bytes(off_t bytes, char **value, const char **unit,
unsigned flags);
/**
+ * Converts the given count into a downscaled human-readable value and
+ * corresponding unit as two separate strings.
+ */
+void humanise_count(size_t count, char **value, const char **unit);
+
+/**
* Append the given byte size as a human-readable string (i.e. 12.23 KiB,
* 3.50 MiB).
*/
diff --git a/t/t1901-repo-structure.sh b/t/t1901-repo-structure.sh
index 36a71a144e..55fd13ad1b 100755
--- a/t/t1901-repo-structure.sh
+++ b/t/t1901-repo-structure.sh
@@ -10,21 +10,21 @@ test_expect_success 'empty repository' '
(
cd repo &&
cat >expect <<-\EOF &&
- | Repository structure | Value |
- | -------------------- | ----- |
- | * References | |
- | * Count | 0 |
- | * Branches | 0 |
- | * Tags | 0 |
- | * Remotes | 0 |
- | * Others | 0 |
- | | |
- | * Reachable objects | |
- | * Count | 0 |
- | * Commits | 0 |
- | * Trees | 0 |
- | * Blobs | 0 |
- | * Tags | 0 |
+ | Repository structure | Value |
+ | -------------------- | ------ |
+ | * References | |
+ | * Count | 0 |
+ | * Branches | 0 |
+ | * Tags | 0 |
+ | * Remotes | 0 |
+ | * Others | 0 |
+ | | |
+ | * Reachable objects | |
+ | * Count | 0 |
+ | * Commits | 0 |
+ | * Trees | 0 |
+ | * Blobs | 0 |
+ | * Tags | 0 |
EOF
git repo structure >out 2>err &&
@@ -39,7 +39,7 @@ test_expect_success 'repository with references and objects' '
git init repo &&
(
cd repo &&
- test_commit_bulk 42 &&
+ test_commit_bulk 1005 &&
git tag -a foo -m bar &&
oid="$(git rev-parse HEAD)" &&
@@ -49,21 +49,21 @@ test_expect_success 'repository with references and objects' '
git notes add -m foo &&
cat >expect <<-\EOF &&
- | Repository structure | Value |
- | -------------------- | ----- |
- | * References | |
- | * Count | 4 |
- | * Branches | 1 |
- | * Tags | 1 |
- | * Remotes | 1 |
- | * Others | 1 |
- | | |
- | * Reachable objects | |
- | * Count | 130 |
- | * Commits | 43 |
- | * Trees | 43 |
- | * Blobs | 43 |
- | * Tags | 1 |
+ | Repository structure | Value |
+ | -------------------- | ------ |
+ | * References | |
+ | * Count | 4 |
+ | * Branches | 1 |
+ | * Tags | 1 |
+ | * Remotes | 1 |
+ | * Others | 1 |
+ | | |
+ | * Reachable objects | |
+ | * Count | 3.02 k |
+ | * Commits | 1.01 k |
+ | * Trees | 1.01 k |
+ | * Blobs | 1.01 k |
+ | * Tags | 1 |
EOF
git repo structure >out 2>err &&