git/t/helper/test-config.c
Glen Choo 8868b1ebfb config: pass kvi to die_bad_number()
Plumb "struct key_value_info" through all code paths that end in
die_bad_number(), which lets us remove the helper functions that read
analogous values from "struct config_reader". As a result, nothing reads
config_reader.config_kvi any more, so remove that too.

In config.c, this requires changing the signature of
git_configset_get_value() to 'return' "kvi" in an out parameter so that
git_configset_get_<type>() can pass it to git_config_<type>(). Only
numeric types will use "kvi", so for non-numeric types (e.g.
git_configset_get_string()), pass NULL to indicate that the out
parameter isn't needed.

Outside of config.c, config callbacks now need to pass "ctx->kvi" to any
of the git_config_<type>() functions that parse a config string into a
number type. Included is a .cocci patch to make that refactor.

The only exceptional case is builtin/config.c, where git_config_<type>()
is called outside of a config callback (namely, on user-provided input),
so config source information has never been available. In this case,
die_bad_number() defaults to a generic, but perfectly descriptive
message. Let's provide a safe, non-NULL for "kvi" anyway, but make sure
not to change the message.

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-06-28 14:06:40 -07:00

237 lines
6.2 KiB
C

#include "test-tool.h"
#include "config.h"
#include "setup.h"
#include "string-list.h"
/*
* This program exposes the C API of the configuration mechanism
* as a set of simple commands in order to facilitate testing.
*
* Reads stdin and prints result of command to stdout:
*
* get_value -> prints the value with highest priority for the entered key
*
* get_value_multi -> prints all values for the entered key in increasing order
* of priority
*
* get -> print return value for the entered key
*
* get_int -> print integer value for the entered key or die
*
* get_bool -> print bool value for the entered key or die
*
* get_string -> print string value for the entered key or die
*
* configset_get_value -> returns value with the highest priority for the entered key
* from a config_set constructed from files entered as arguments.
*
* configset_get_value_multi -> returns value_list for the entered key sorted in
* ascending order of priority from a config_set
* constructed from files entered as arguments.
*
* iterate -> iterate over all values using git_config(), and print some
* data for each
*
* git_config_int -> iterate over all values using git_config() and print the
* integer value for the entered key or die
*
* Examples:
*
* To print the value with highest priority for key "foo.bAr Baz.rock":
* test-tool config get_value "foo.bAr Baz.rock"
*
*/
static int iterate_cb(const char *var, const char *value,
const struct config_context *ctx,
void *data UNUSED)
{
const struct key_value_info *kvi = ctx->kvi;
static int nr;
if (nr++)
putchar('\n');
printf("key=%s\n", var);
printf("value=%s\n", value ? value : "(null)");
printf("origin=%s\n", config_origin_type_name(kvi->origin_type));
printf("name=%s\n", kvi->filename ? kvi->filename : "");
printf("lno=%d\n", kvi->linenr);
printf("scope=%s\n", config_scope_name(kvi->scope));
return 0;
}
static int parse_int_cb(const char *var, const char *value,
const struct config_context *ctx, void *data)
{
const char *key_to_match = data;
if (!strcmp(key_to_match, var)) {
int parsed = git_config_int(value, value, ctx->kvi);
printf("%d\n", parsed);
}
return 0;
}
static int early_config_cb(const char *var, const char *value,
const struct config_context *ctx UNUSED,
void *vdata)
{
const char *key = vdata;
if (!strcmp(key, var))
printf("%s\n", value);
return 0;
}
int cmd__config(int argc, const char **argv)
{
int i, val;
const char *v;
const struct string_list *strptr;
struct config_set cs;
if (argc == 3 && !strcmp(argv[1], "read_early_config")) {
read_early_config(early_config_cb, (void *)argv[2]);
return 0;
}
setup_git_directory();
git_configset_init(&cs);
if (argc < 2) {
fprintf(stderr, "Please, provide a command name on the command-line\n");
goto exit1;
} else if (argc == 3 && !strcmp(argv[1], "get_value")) {
if (!git_config_get_value(argv[2], &v)) {
if (!v)
printf("(NULL)\n");
else
printf("%s\n", v);
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) {
if (!git_config_get_value_multi(argv[2], &strptr)) {
for (i = 0; i < strptr->nr; i++) {
v = strptr->items[i].string;
if (!v)
printf("(NULL)\n");
else
printf("%s\n", v);
}
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get")) {
int ret;
if (!(ret = git_config_get(argv[2])))
goto exit0;
else if (ret == 1)
printf("Value not found for \"%s\"\n", argv[2]);
else if (ret == -CONFIG_INVALID_KEY)
printf("Key \"%s\" is invalid\n", argv[2]);
else if (ret == -CONFIG_NO_SECTION_OR_NAME)
printf("Key \"%s\" has no section\n", argv[2]);
else
/*
* A normal caller should just check "ret <
* 0", but for our own tests let's BUG() if
* our whitelist of git_config_parse_key()
* return values isn't exhaustive.
*/
BUG("Key \"%s\" has unknown return %d", argv[2], ret);
goto exit1;
} else if (argc == 3 && !strcmp(argv[1], "get_int")) {
if (!git_config_get_int(argv[2], &val)) {
printf("%d\n", val);
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_bool")) {
if (!git_config_get_bool(argv[2], &val)) {
printf("%d\n", val);
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_string")) {
if (!git_config_get_string_tmp(argv[2], &v)) {
printf("%s\n", v);
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (!strcmp(argv[1], "configset_get_value")) {
for (i = 3; i < argc; i++) {
int err;
if ((err = git_configset_add_file(&cs, argv[i]))) {
fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]);
goto exit2;
}
}
if (!git_configset_get_value(&cs, argv[2], &v, NULL)) {
if (!v)
printf("(NULL)\n");
else
printf("%s\n", v);
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (!strcmp(argv[1], "configset_get_value_multi")) {
for (i = 3; i < argc; i++) {
int err;
if ((err = git_configset_add_file(&cs, argv[i]))) {
fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]);
goto exit2;
}
}
if (!git_configset_get_value_multi(&cs, argv[2], &strptr)) {
for (i = 0; i < strptr->nr; i++) {
v = strptr->items[i].string;
if (!v)
printf("(NULL)\n");
else
printf("%s\n", v);
}
goto exit0;
} else {
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (!strcmp(argv[1], "iterate")) {
git_config(iterate_cb, NULL);
goto exit0;
} else if (argc == 3 && !strcmp(argv[1], "git_config_int")) {
git_config(parse_int_cb, (void *) argv[2]);
goto exit0;
}
die("%s: Please check the syntax and the function name", argv[0]);
exit0:
git_configset_clear(&cs);
return 0;
exit1:
git_configset_clear(&cs);
return 1;
exit2:
git_configset_clear(&cs);
return 2;
}