[PATCH 4/4] builtin/repo: add nul format for stats
- From
Justin Tobler <jltobler@gmail.com>
- Date
- Sep 23, 2025, 02:57 UTC
- Message-ID
- <20250923025700.3046260-5-jltobler@gmail.com>
- In-Reply-To
- <20250923025700.3046260-1-jltobler@gmail.com>
Introduce the `nul` mode for the --format option. When enabled, the output is similar to the `keyvalue` mode, but key-values are delimited by a NUL character instead of a newline. This allows stat values to support special characters without having to cquote values.
Signed-off-by: Justin Tobler <jltobler@gmail.com> --- Documentation/git-repo.adoc | 10 ++++--- builtin/repo.c | 52 ++++++++++++++++++++----------------- t/t1901-repo-stats.sh | 27 +++++++++++++++++++ 3 files changed, 62 insertions(+), 27 deletions(-)
diff --git a/Documentation/git-repo.adoc b/Documentation/git-repo.adoc index 7d0341e4f1..57267064ea 100644 --- a/Documentation/git-repo.adoc +++ b/Documentation/git-repo.adoc @@ -9,7 +9,7 @@ SYNOPSIS -------- [synopsis] git repo info [--format=(keyvalue|nul)] [-z] [<key>...] -git repo stats [--format=(table|keyvalue)] +git repo stats [--format=(table|keyvalue|nul)] DESCRIPTION ----------- @@ -44,12 +44,12 @@ supported: + `-z` is an alias for `--format=nul`. -`stats [--format=(table|keyvalue)]`:: +`stats [--format=(table|keyvalue|nul)]`:: Retrieve stats about the current repository. All references and reachable objects in the repository are categorized and counted accordingly. + -The output format can be chosen through the flag `--format`. Two formats are +The output format can be chosen through the flag `--format`. Three formats are supported: + `table`::: @@ -61,6 +61,10 @@ supported: Each line of output contains a key-value pair of a repostiory stat. The '=' character is used to delimit between the key and the value. +`nul`::: + Similar to 'keyvalue', but uses a NUL character to delimit between + key-value pairs instead of a newline. + INFO KEYS --------- In order to obtain a set of values from `git repo info`, you should provide diff --git a/builtin/repo.c b/builtin/repo.c index 4c16a68e4e..37034e6347 100644 --- a/builtin/repo.c +++ b/builtin/repo.c @@ -14,7 +14,7 @@ static const char *const repo_usage[] = { "git repo info [--format=(keyvalue|nul)] [-z] [<key>...]", - "git repo stats [--format=(table|keyvalue)]", + "git repo stats [--format=(table|keyvalue|nul)]", NULL }; @@ -291,27 +291,31 @@ static void stats_table_print(struct stats_table *table) strbuf_release(&buf); } -static void stats_print(struct stats *stats) +static void stats_print(struct stats *stats, int nul_delim) { struct strbuf buf = STRBUF_INIT; - - strbuf_addf(&buf, "references.branches.count=%" PRIuMAX "\n", - (uintmax_t)stats->refs.branches); - strbuf_addf(&buf, "references.tags.count=%" PRIuMAX "\n", - (uintmax_t)stats->refs.tags); - strbuf_addf(&buf, "references.remotes.count=%" PRIuMAX "\n", - (uintmax_t)stats->refs.remotes); - strbuf_addf(&buf, "references.others.count=%" PRIuMAX "\n", - (uintmax_t)stats->refs.others); - - strbuf_addf(&buf, "objects.commits.count=%" PRIuMAX "\n", - (uintmax_t)stats->objects.commits); - strbuf_addf(&buf, "objects.trees.count=%" PRIuMAX "\n", - (uintmax_t)stats->objects.trees); - strbuf_addf(&buf, "objects.blobs.count=%" PRIuMAX "\n", - (uintmax_t)stats->objects.blobs); - strbuf_addf(&buf, "objects.tags.count=%" PRIuMAX "\n", - (uintmax_t)stats->objects.tags); + char delim = '\n'; + + if (nul_delim) + delim = '\0'; + + strbuf_addf(&buf, "references.branches.count=%" PRIuMAX "%c", + (uintmax_t)stats->refs.branches, delim); + strbuf_addf(&buf, "references.tags.count=%" PRIuMAX "%c", + (uintmax_t)stats->refs.tags, delim); + strbuf_addf(&buf, "references.remotes.count=%" PRIuMAX "%c", + (uintmax_t)stats->refs.remotes, delim); + strbuf_addf(&buf, "references.others.count=%" PRIuMAX "%c", + (uintmax_t)stats->refs.others, delim); + + strbuf_addf(&buf, "objects.commits.count=%" PRIuMAX "%c", + (uintmax_t)stats->objects.commits, delim); + strbuf_addf(&buf, "objects.trees.count=%" PRIuMAX "%c", + (uintmax_t)stats->objects.trees, delim); + strbuf_addf(&buf, "objects.blobs.count=%" PRIuMAX "%c", + (uintmax_t)stats->objects.blobs, delim); + strbuf_addf(&buf, "objects.tags.count=%" PRIuMAX "%c", + (uintmax_t)stats->objects.tags, delim); fwrite(buf.buf, sizeof(char), buf.len, stdout); strbuf_release(&buf); @@ -408,9 +412,6 @@ static int repo_stats(int argc, const char **argv, const char *prefix, struct rev_info revs; parse_options(argc, argv, prefix, options, repo_usage, 0); - if (format == FORMAT_NUL_TERMINATED) - die(_("nul format not yet supported")); - repo_init_revisions(repo, &revs, prefix); filter.name_patterns = ref_patterns.v; filter_refs(&refs, &filter, FILTER_REFS_REGULAR); @@ -424,7 +425,10 @@ static int repo_stats(int argc, const char **argv, const char *prefix, stats_table_print(&table); break; case FORMAT_KEYVALUE: - stats_print(&stats); + stats_print(&stats, 0); + break; + case FORMAT_NUL_TERMINATED: + stats_print(&stats, 1); break; default: BUG("not a valid output format: %d", format); diff --git a/t/t1901-repo-stats.sh b/t/t1901-repo-stats.sh index 5bc6d9d5c4..061b2fbbc1 100755 --- a/t/t1901-repo-stats.sh +++ b/t/t1901-repo-stats.sh @@ -127,4 +127,31 @@ test_expect_success 'repository stats with keyvalue format' ' ) ' +test_expect_success 'repository stats with nul format' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit_bulk 42 && + git tag -a foo -m bar && + git repo stats --format=nul >out 2>err && + + cat >expect <<-EOF && + references.branches.count=1 + references.tags.count=1 + references.remotes.count=0 + references.others.count=0 + objects.commits.count=42 + objects.trees.count=42 + objects.blobs.count=42 + objects.tags.count=1 + EOF + + tr "\n" "\0" <expect >expect_null && + + test_cmp expect_null out && + test_line_count = 0 err + ) +' + test_done
-- 2.51.0.193.g4975ec3473b