4
#include "environment.h"
5
#include "parse-options.h"
6
#include "quote.h"
7
+#include "ref-filter.h"
8
#include "refs.h"
9
#include "strbuf.h"
10
+#include "string-list.h"
11
#include "shallow.h"
12
+#include "utf8.h"
13
14
static const char *const repo_usage[] = {
15
"git repo info [--format=(keyvalue|nul)] [-z] [<key>...]",
16
+ "git repo structure",
17
NULL
18
};
19
160
return print_fields(argc, argv, repo, format);
161
}
162
163
+struct ref_stats {
164
+ size_t branches;
165
+ size_t remotes;
166
+ size_t tags;
167
+ size_t others;
168
+};
169
+
170
+struct stats_table {
171
+ struct string_list rows;
172
+
173
+ int name_col_width;
174
+ int value_col_width;
175
+};
176
+
177
+/*
178
+ * Holds column data that gets stored for each row.
179
+ */
180
+struct stats_table_entry {
181
+ char *value;
182
+};
183
+
184
+static void stats_table_vaddf(struct stats_table *table,
185
+ struct stats_table_entry *entry,
186
+ const char *format, va_list ap)
187
+{
188
+ struct strbuf buf = STRBUF_INIT;
189
+ struct string_list_item *item;
190
+ char *formatted_name;
191
+ int name_width;
192
+
193
+ strbuf_vaddf(&buf, format, ap);
194
+ formatted_name = strbuf_detach(&buf, NULL);
195
+ name_width = utf8_strwidth(formatted_name);
196
+
197
+ item = string_list_append_nodup(&table->rows, formatted_name);
198
+ item->util = entry;
199
+
200
+ if (name_width > table->name_col_width)
201
+ table->name_col_width = name_width;
202
+ if (entry) {
203
+ int value_width = utf8_strwidth(entry->value);
204
+ if (value_width > table->value_col_width)
205
+ table->value_col_width = value_width;
206
+ }
207
+}
208
+
209
+static void stats_table_addf(struct stats_table *table, const char *format, ...)
210
+{
211
+ va_list ap;
212
+
213
+ va_start(ap, format);
214
+ stats_table_vaddf(table, NULL, format, ap);
215
+ va_end(ap);
216
+}
217
+
218
+static void stats_table_count_addf(struct stats_table *table, size_t value,
219
+ const char *format, ...)
220
+{
221
+ struct stats_table_entry *entry;
222
+ va_list ap;
223
+
224
+ CALLOC_ARRAY(entry, 1);
225
+ entry->value = xstrfmt("%" PRIuMAX, (uintmax_t)value);
226
+
227
+ va_start(ap, format);
228
+ stats_table_vaddf(table, entry, format, ap);
229
+ va_end(ap);
230
+}
231
+
232
+static inline size_t get_total_reference_count(struct ref_stats *stats)
233
+{
234
+ return stats->branches + stats->remotes + stats->tags + stats->others;
235
+}
236
+
237
+static void stats_table_setup_structure(struct stats_table *table,
238
+ struct ref_stats *refs)
239
+{
240
+ size_t ref_total;
241
+
242
+ ref_total = get_total_reference_count(refs);
243
+ stats_table_addf(table, "* %s", _("References"));
244
+ stats_table_count_addf(table, ref_total, " * %s", _("Count"));
245
+ stats_table_count_addf(table, refs->branches, " * %s", _("Branches"));
246
+ stats_table_count_addf(table, refs->tags, " * %s", _("Tags"));
247
+ stats_table_count_addf(table, refs->remotes, " * %s", _("Remotes"));
248
+ stats_table_count_addf(table, refs->others, " * %s", _("Others"));
249
+}
250
+
251
+static void stats_table_print_structure(const struct stats_table *table)
252
+{
253
+ const char *name_col_title = _("Repository structure");
254
+ const char *value_col_title = _("Value");
255
+ int name_col_width = utf8_strwidth(name_col_title);
256
+ int value_col_width = utf8_strwidth(value_col_title);
257
+ struct string_list_item *item;
258
+
259
+ if (table->name_col_width > name_col_width)
260
+ name_col_width = table->name_col_width;
261
+ if (table->value_col_width > value_col_width)
262
+ value_col_width = table->value_col_width;
263
+
264
+ printf("| %-*s | %-*s |\n", name_col_width, name_col_title,
265
+ value_col_width, value_col_title);
266
+ printf("| ");
267
+ for (int i = 0; i < name_col_width; i++)
268
+ putchar('-');
269
+ printf(" | ");
270
+ for (int i = 0; i < value_col_width; i++)
271
+ putchar('-');
272
+ printf(" |\n");
273
+
274
+ for_each_string_list_item(item, &table->rows) {
275
+ struct stats_table_entry *entry = item->util;
276
+ const char *value = "";
277
+
278
+ if (entry) {
279
+ struct stats_table_entry *entry = item->util;
280
+ value = entry->value;
281
+ }
282
+
283
+ printf("| %-*s | %*s |\n", name_col_width, item->string,
284
+ value_col_width, value);
285
+ }
286
+}
287
+
288
+static void stats_table_clear(struct stats_table *table)
289
+{
290
+ struct stats_table_entry *entry;
291
+ struct string_list_item *item;
292
+
293
+ for_each_string_list_item(item, &table->rows) {
294
+ entry = item->util;
295
+ if (entry)
296
+ free(entry->value);
297
+ }
298
+
299
+ string_list_clear(&table->rows, 1);
300
+}
301
+
302
+static int count_references(const char *refname,
303
+ const char *referent UNUSED,
304
+ const struct object_id *oid UNUSED,
305
+ int flags UNUSED, void *cb_data)
306
+{
307
+ struct ref_stats *stats = cb_data;
308
+
309
+ switch (ref_kind_from_refname(refname)) {
310
+ case FILTER_REFS_BRANCHES:
311
+ stats->branches++;
312
+ break;
313
+ case FILTER_REFS_REMOTES:
314
+ stats->remotes++;
315
+ break;
316
+ case FILTER_REFS_TAGS:
317
+ stats->tags++;
318
+ break;
319
+ case FILTER_REFS_OTHERS:
320
+ stats->others++;
321
+ break;
322
+ default:
323
+ BUG("unexpected reference type");
324
+ }
325
+
326
+ return 0;
327
+}
328
+
329
+static void structure_count_references(struct ref_stats *stats,
330
+ struct repository *repo)
331
+{
332
+ refs_for_each_ref(get_main_ref_store(repo), count_references, &stats);
333
+}
334
+
335
+static int cmd_repo_structure(int argc, const char **argv, const char *prefix,
336
+ struct repository *repo)
337
+{
338
+ struct stats_table table = {
339
+ .rows = STRING_LIST_INIT_DUP,
340
+ };
341
+ struct ref_stats stats = { 0 };
342
+ struct option options[] = { 0 };
343
+
344
+ argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
345
+ if (argc)
346
+ usage(_("too many arguments"));
347
+
348
+ structure_count_references(&stats, repo);
349
+
350
+ stats_table_setup_structure(&table, &stats);
351
+ stats_table_print_structure(&table);
352
+
353
+ stats_table_clear(&table);
354
+
355
+ return 0;
356
+}
357
+
358
int cmd_repo(int argc, const char **argv, const char *prefix,
359
struct repository *repo)
360
{
361
parse_opt_subcommand_fn *fn = NULL;
362
struct option options[] = {
363
OPT_SUBCOMMAND("info", &fn, cmd_repo_info),
364
+ OPT_SUBCOMMAND("structure", &fn, cmd_repo_structure),
365
OPT_END()
366
};
367