From: Phillip Wood Date: Mon, 11 Aug 2025 14:41:30 GMT Subject: Re: [GSoC PATCH v9 2/5] repo: add the field references.format Message-ID: In-Reply-To: <20250807150239.6987-3-lucasseikioshiro@gmail.com> Hi Lucas On 07/08/2025 16:02, Lucas Seiki Oshiro wrote: > ++ > +The returned data is lexicographically sorted by the keys. What's the reason for this? If I query three keys from a script then it is much easier to parse the output if I know the keys are going to appear in the same order that they were on the command line. If the command re-orders them my script now has to check the value of each key which results in a bunch of unnecessary string comparisons because it cannot determine the key from the position in the output. While we were producing json output there was a need to de-duplicate the keys when that output format was selected. However, we no-longer produce json and in any case de-duplication could have been achieved without sorting the input keys by using a hash table, or, as there is a small fixed number of keys, an array that records the keys we've already seen. Thanks Phillip > ++ > +The output format consists of key-value pairs one per line using the `=` > +character as the delimiter between the key and the value. Values containing > +"unusual" characters are quoted as explained for the configuration variable > +`core.quotePath` (see linkgit:git-config[1]). This is the default. > + > +INFO KEYS > +--------- > + > +In order to obtain a set of values from `git repo info`, you should provide > +the keys that identify them. Here's a list of the available keys and the > +values that they return: > + > +`references.format`:: > +The reference storage format. The valid values are: > ++ > +include::ref-storage-format.adoc[] > > SEE ALSO > -------- > diff --git a/builtin/repo.c b/builtin/repo.c > index fd2a9b4216..2b7ab5875e 100644 > --- a/builtin/repo.c > +++ b/builtin/repo.c > @@ -1,17 +1,102 @@ > #include "builtin.h" > #include "parse-options.h" > +#include "quote.h" > +#include "refs.h" > +#include "strbuf.h" > > static const char *const repo_usage[] = { > "git repo info [...]", > NULL > }; > > -static int repo_info(int argc UNUSED, const char **argv UNUSED, > - const char *prefix UNUSED, struct repository *repo UNUSED) > +typedef int get_value_fn(struct repository *repo, struct strbuf *buf); > + > +struct field { > + const char *key; > + get_value_fn *get_value; > +}; > + > +static int get_references_format(struct repository *repo, struct strbuf *buf) > { > + strbuf_addstr(buf, > + ref_storage_format_to_name(repo->ref_storage_format)); > return 0; > } > > +/* repo_info_fields keys should be in lexicographical order */ > +static const struct field repo_info_fields[] = { > + { "references.format", get_references_format }, > +}; > + > +static int repo_info_fields_cmp(const void *va, const void *vb) > +{ > + const struct field *a = va; > + const struct field *b = vb; > + > + return strcmp(a->key, b->key); > +} > + > +static get_value_fn *get_value_fn_for_key(const char *key) > +{ > + const struct field search_key = { key, NULL }; > + const struct field *found = bsearch(&search_key, repo_info_fields, > + ARRAY_SIZE(repo_info_fields), > + sizeof(*found), > + repo_info_fields_cmp); > + return found ? found->get_value : NULL; > +} > + > +static int qsort_strcmp(const void *va, const void *vb) > +{ > + const char *a = *(const char **)va; > + const char *b = *(const char **)vb; > + > + return strcmp(a, b); > +} > + > +static int print_fields(int argc, const char **argv, struct repository *repo) > +{ > + int ret = 0; > + const char *last = ""; > + struct strbuf valbuf = STRBUF_INIT; > + struct strbuf quotbuf = STRBUF_INIT; > + > + QSORT(argv, argc, qsort_strcmp); > + > + for (int i = 0; i < argc; i++) { > + get_value_fn *get_value; > + const char *key = argv[i]; > + > + strbuf_reset(&valbuf); > + strbuf_reset("buf); > + > + if (!strcmp(key, last)) > + continue; > + > + last = key; > + get_value = get_value_fn_for_key(key); > + > + if (!get_value) { > + ret = error(_("key '%s' not found"), key); > + continue; > + } > + > + get_value(repo, &valbuf); > + quote_c_style(valbuf.buf, "buf, NULL, 0); > + printf("%s=%s\n", key, quotbuf.buf); > + } > + > + strbuf_release(&valbuf); > + strbuf_release("buf); > + return ret; > +} > + > +static int repo_info(int argc, const char **argv, const char *prefix UNUSED, > + struct repository *repo) > +{ > + return print_fields(argc - 1, argv + 1, repo); > +} > + > int cmd_repo(int argc, const char **argv, const char *prefix, > struct repository *repo) > { > diff --git a/t/meson.build b/t/meson.build > index bbeba1a8d5..252dbbc031 100644 > --- a/t/meson.build > +++ b/t/meson.build > @@ -230,6 +230,7 @@ integration_tests = [ > 't1700-split-index.sh', > 't1701-racy-split-index.sh', > 't1800-hook.sh', > + 't1900-repo.sh', > 't2000-conflict-when-checking-files-out.sh', > 't2002-checkout-cache-u.sh', > 't2003-checkout-cache-mkdir.sh', > diff --git a/t/t1900-repo.sh b/t/t1900-repo.sh > new file mode 100755 > index 0000000000..2b2516dbae > --- /dev/null > +++ b/t/t1900-repo.sh > @@ -0,0 +1,57 @@ > +#!/bin/sh > + > +test_description='test git repo-info' > + > +. ./test-lib.sh > + > +# Test whether a key-value pair is correctly returned > +# > +# Usage: test_repo_info