From: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, johannes.schindelin@gmx.de, peff@peff.net,
ps@pks.im, me@ttaylorr.com, johncai86@gmail.com,
newren@gmail.com, Derrick Stolee <stolee@gmail.com>,
Derrick Stolee <stolee@gmail.com>
Subject: [PATCH 12/30] survey: start pretty printing data in table form
Date: Tue, 10 Sep 2024 02:28:37 +0000 [thread overview]
Message-ID: <44417cceddcaeec9e90acd0b058edd8c80627479.1725935335.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1786.git.1725935335.gitgitgadget@gmail.com>
From: Derrick Stolee <stolee@gmail.com>
When 'git survey' provides information to the user, this will be presented
in one of two formats: plaintext and JSON. The JSON implementation will be
delayed until the functionality is complete for the plaintext format.
The most important parts of the plaintext format are headers specifying the
different sections of the report and tables providing concreted data.
Create a custom table data structure that allows specifying a list of
strings for the row values. When printing the table, check each column for
the maximum width so we can create a table of the correct size from the
start.
The table structure is designed to be flexible to the different kinds of
output that will be implemented in future changes.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/survey.c | 175 ++++++++++++++++++++++++++++++++++++++++++
t/t8100-git-survey.sh | 17 +++-
2 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/builtin/survey.c b/builtin/survey.c
index 1b4fe591e59..b2104e84d61 100644
--- a/builtin/survey.c
+++ b/builtin/survey.c
@@ -5,6 +5,7 @@
#include "parse-options.h"
#include "progress.h"
#include "ref-filter.h"
+#include "strbuf.h"
#include "strvec.h"
#include "trace2.h"
@@ -27,10 +28,16 @@ static struct survey_refs_wanted default_ref_options = {
.want_all_refs = 1,
};
+enum survey_format {
+ SURVEY_PLAINTEXT = 0,
+ SURVEY_JSON = 1,
+};
+
struct survey_opts {
int verbose;
int show_progress;
struct survey_refs_wanted refs;
+ enum survey_format format;
};
struct survey_report_ref_summary {
@@ -78,6 +85,161 @@ static void clear_survey_context(struct survey_context *ctx)
strvec_clear(&ctx->refs);
}
+struct survey_table {
+ const char *table_name;
+ struct strvec header;
+ struct strvec *rows;
+ size_t rows_nr;
+ size_t rows_alloc;
+};
+
+#define SURVEY_TABLE_INIT { \
+ .header = STRVEC_INIT, \
+}
+
+static void clear_table(struct survey_table *table)
+{
+ strvec_clear(&table->header);
+ for (size_t i = 0; i < table->rows_nr; i++)
+ strvec_clear(&table->rows[i]);
+ free(table->rows);
+}
+
+static void insert_table_rowv(struct survey_table *table, ...)
+{
+ va_list ap;
+ char *arg;
+ ALLOC_GROW(table->rows, table->rows_nr + 1, table->rows_alloc);
+
+ memset(&table->rows[table->rows_nr], 0, sizeof(struct strvec));
+
+ va_start(ap, table);
+ while ((arg = va_arg(ap, char *)))
+ strvec_push(&table->rows[table->rows_nr], arg);
+ va_end(ap);
+
+ table->rows_nr++;
+}
+
+static void print_table_title(const char *name, size_t *widths, size_t nr)
+{
+ static struct strbuf lines = STRBUF_INIT;
+ size_t width = 0;
+ strbuf_setlen(&lines, 0);
+
+ strbuf_addch(&lines, ' ');
+ strbuf_addstr(&lines, name);
+ strbuf_addch(&lines, '\n');
+
+ for (size_t i = 0; i < nr; i++) {
+ if (i)
+ width += 3;
+ width += widths[i];
+ }
+ strbuf_addchars(&lines, '=', width);
+ printf("%s\n", lines.buf);
+}
+
+static void print_row_plaintext(struct strvec *row, size_t *widths)
+{
+ static struct strbuf line = STRBUF_INIT;
+ strbuf_setlen(&line, 0);
+
+ for (size_t i = 0; i < row->nr; i++) {
+ const char *str = row->v[i];
+ size_t len = strlen(str);
+ if (i)
+ strbuf_add(&line, " | ", 3);
+ strbuf_addchars(&line, ' ', widths[i] - len);
+ strbuf_add(&line, str, len);
+ }
+ printf("%s\n", line.buf);
+}
+
+static void print_divider_plaintext(size_t *widths, size_t nr)
+{
+ static struct strbuf line = STRBUF_INIT;
+ strbuf_setlen(&line, 0);
+
+ for (size_t i = 0; i < nr; i++) {
+ if (i)
+ strbuf_add(&line, "-+-", 3);
+ strbuf_addchars(&line, '-', widths[i]);
+ }
+ printf("%s\n", line.buf);
+}
+
+static void print_table_plaintext(struct survey_table *table)
+{
+ size_t *column_widths;
+ size_t columns_nr = table->header.nr;
+ CALLOC_ARRAY(column_widths, columns_nr);
+
+ for (size_t i = 0; i < columns_nr; i++) {
+ column_widths[i] = strlen(table->header.v[i]);
+
+ for (size_t j = 0; j < table->rows_nr; j++) {
+ size_t rowlen = strlen(table->rows[j].v[i]);
+ if (column_widths[i] < rowlen)
+ column_widths[i] = rowlen;
+ }
+ }
+
+ print_table_title(table->table_name, column_widths, columns_nr);
+ print_row_plaintext(&table->header, column_widths);
+ print_divider_plaintext(column_widths, columns_nr);
+
+ for (size_t j = 0; j < table->rows_nr; j++)
+ print_row_plaintext(&table->rows[j], column_widths);
+}
+
+static void survey_report_plaintext_refs(struct survey_context *ctx)
+{
+ struct survey_report_ref_summary *refs = &ctx->report.refs;
+ struct survey_table table = SURVEY_TABLE_INIT;
+
+ table.table_name = _("REFERENCES SUMMARY");
+
+ strvec_push(&table.header, _("Ref Type"));
+ strvec_push(&table.header, _("Count"));
+
+ if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_branches) {
+ char *fmt = xstrfmt("%"PRIuMAX"", refs->branches_nr);
+ insert_table_rowv(&table, _("Branches"), fmt, NULL);
+ free(fmt);
+ }
+
+ if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_remotes) {
+ char *fmt = xstrfmt("%"PRIuMAX"", refs->remote_refs_nr);
+ insert_table_rowv(&table, _("Remote refs"), fmt, NULL);
+ free(fmt);
+ }
+
+ if (ctx->opts.refs.want_all_refs || ctx->opts.refs.want_tags) {
+ char *fmt = xstrfmt("%"PRIuMAX"", refs->tags_nr);
+ insert_table_rowv(&table, _("Tags (all)"), fmt, NULL);
+ free(fmt);
+ fmt = xstrfmt("%"PRIuMAX"", refs->tags_annotated_nr);
+ insert_table_rowv(&table, _("Tags (annotated)"), fmt, NULL);
+ free(fmt);
+ }
+
+ print_table_plaintext(&table);
+ clear_table(&table);
+}
+
+static void survey_report_plaintext(struct survey_context *ctx)
+{
+ printf("GIT SURVEY for \"%s\"\n", ctx->repo->worktree);
+ printf("-----------------------------------------------------\n");
+ survey_report_plaintext_refs(ctx);
+}
+
+static void survey_report_json(struct survey_context *ctx)
+{
+ /* TODO. */
+}
+
/*
* After parsing the command line arguments, figure out which refs we
* should scan.
@@ -312,6 +474,19 @@ int cmd_survey(int argc, const char **argv, const char *prefix)
survey_phase_refs(&ctx);
+ switch (ctx.opts.format) {
+ case SURVEY_PLAINTEXT:
+ survey_report_plaintext(&ctx);
+ break;
+
+ case SURVEY_JSON:
+ survey_report_json(&ctx);
+ break;
+
+ default:
+ BUG("Undefined format");
+ }
+
clear_survey_context(&ctx);
return 0;
}
diff --git a/t/t8100-git-survey.sh b/t/t8100-git-survey.sh
index 5903c90cb57..a57f6ca7a59 100755
--- a/t/t8100-git-survey.sh
+++ b/t/t8100-git-survey.sh
@@ -21,7 +21,22 @@ test_expect_success 'creat a semi-interesting repo' '
test_expect_success 'git survey (default)' '
git survey >out 2>err &&
- test_line_count = 0 err
+ test_line_count = 0 err &&
+
+ cat >expect <<-EOF &&
+ GIT SURVEY for "$(pwd)"
+ -----------------------------------------------------
+ REFERENCES SUMMARY
+ ========================
+ Ref Type | Count
+ -----------------+------
+ Branches | 1
+ Remote refs | 0
+ Tags (all) | 0
+ Tags (annotated) | 0
+ EOF
+
+ test_cmp expect out
'
test_done
--
gitgitgadget
next prev parent reply other threads:[~2024-09-10 2:29 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-10 2:28 [PATCH 00/30] [RFC] Path-walk API and applications Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 01/30] path-walk: introduce an object walk by path Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 02/30] backfill: add builtin boilerplate Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 03/30] backfill: basic functionality and tests Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 04/30] backfill: add --batch-size=<n> option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 05/30] backfill: add --sparse option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 06/30] backfill: assume --sparse when sparse-checkout is enabled Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 07/30] path-walk: allow consumer to specify object types Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 08/30] path-walk: allow visiting tags Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 09/30] survey: stub in new experimental `git-survey` command Jeff Hostetler via GitGitGadget
2024-09-10 2:28 ` [PATCH 10/30] survey: add command line opts to select references Jeff Hostetler via GitGitGadget
2024-09-10 2:28 ` [PATCH 11/30] survey: collect the set of requested refs Jeff Hostetler via GitGitGadget
2024-09-10 2:28 ` Derrick Stolee via GitGitGadget [this message]
2024-09-10 2:28 ` [PATCH 13/30] survey: add object count summary Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 14/30] survey: summarize total sizes by object type Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 15/30] survey: show progress during object walk Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 16/30] survey: add ability to track prioritized lists Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 17/30] survey: add report of "largest" paths Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 18/30] revision: create mark_trees_uninteresting_dense() Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 19/30] path-walk: add prune_all_uninteresting option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 20/30] pack-objects: add --path-walk option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 21/30] pack-objects: extract should_attempt_deltas() Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 22/30] pack-objects: introduce GIT_TEST_PACK_PATH_WALK Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 23/30] p5313: add size comparison test Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 24/30] repack: add --path-walk option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 25/30] pack-objects: enable --path-walk via config Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 26/30] scalar: enable path-walk during push " Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 27/30] pack-objects: add --full-name-hash option Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 28/30] test-name-hash: add helper to compute name-hash functions Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 29/30] p5314: add a size test for name-hash collisions Derrick Stolee via GitGitGadget
2024-09-10 2:28 ` [PATCH 30/30] pack-objects: output debug info about deltas Derrick Stolee via GitGitGadget
2024-09-11 21:32 ` [PATCH 00/30] [RFC] Path-walk API and applications Junio C Hamano
2024-09-17 10:41 ` Christian Couder
2024-09-18 23:18 ` Derrick Stolee
2024-09-22 18:37 ` Junio C Hamano
2024-09-23 1:22 ` Derrick Stolee
2024-09-23 16:56 ` Junio C Hamano
2024-09-22 21:08 ` Kristoffer Haugsbakk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44417cceddcaeec9e90acd0b058edd8c80627479.1725935335.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=johannes.schindelin@gmx.de \
--cc=johncai86@gmail.com \
--cc=me@ttaylorr.com \
--cc=newren@gmail.com \
--cc=peff@peff.net \
--cc=ps@pks.im \
--cc=stolee@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).