Skip to content

Commit 7f346e9

Browse files
committed
Merge branch 'ta/config-set-1'
Use the new caching config-set API in git_config() calls. * ta/config-set-1: add tests for `git_config_get_string_const()` add a test for semantic errors in config files rewrite git_config() to use the config-set API config: add `git_die_config()` to the config-set API change `git_config()` return value to void add line number and file name info to `config_set` config.c: fix accuracy of line number in errors config.c: mark error and warnings strings for translation
2 parents 0c72b98 + 8a7b034 commit 7f346e9

File tree

7 files changed

+207
-30
lines changed

7 files changed

+207
-30
lines changed

Documentation/technical/api-config.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,19 @@ as well as retrieval for the queried variable, including:
155155
Similar to `git_config_get_string`, but expands `~` or `~user` into
156156
the user's home directory when found at the beginning of the path.
157157

158+
`git_die_config(const char *key, const char *err, ...)`::
159+
160+
First prints the error message specified by the caller in `err` and then
161+
dies printing the line number and the file name of the highest priority
162+
value for the configuration variable `key`.
163+
164+
`void git_die_config_linenr(const char *key, const char *filename, int linenr)`::
165+
166+
Helper function which formats the die error message according to the
167+
parameters entered. Used by `git_die_config()`. It can be used by callers
168+
handling `git_config_get_value_multi()` to print the correct error message
169+
for the desired value.
170+
158171
See test-config.c for usage examples.
159172

160173
Value Parsing Helpers

branch.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
161161
strbuf_addf(&name, "branch.%s.description", branch_name);
162162
cb.config_name = name.buf;
163163
cb.value = NULL;
164-
if (git_config(read_branch_desc_cb, &cb) < 0) {
165-
strbuf_release(&name);
166-
return -1;
167-
}
164+
git_config(read_branch_desc_cb, &cb);
168165
if (cb.value)
169166
strbuf_addstr(buf, cb.value);
170167
strbuf_release(&name);

cache.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "gettext.h"
99
#include "convert.h"
1010
#include "trace.h"
11+
#include "string-list.h"
1112

1213
#include SHA1_HEADER
1314
#ifndef git_SHA_CTX
@@ -1296,7 +1297,7 @@ extern int git_config_from_buf(config_fn_t fn, const char *name,
12961297
const char *buf, size_t len, void *data);
12971298
extern void git_config_push_parameter(const char *text);
12981299
extern int git_config_from_parameters(config_fn_t fn, void *data);
1299-
extern int git_config(config_fn_t fn, void *);
1300+
extern void git_config(config_fn_t fn, void *);
13001301
extern int git_config_with_options(config_fn_t fn, void *,
13011302
struct git_config_source *config_source,
13021303
int respect_includes);
@@ -1353,9 +1354,32 @@ extern int parse_config_key(const char *var,
13531354
const char **subsection, int *subsection_len,
13541355
const char **key);
13551356

1357+
struct config_set_element {
1358+
struct hashmap_entry ent;
1359+
char *key;
1360+
struct string_list value_list;
1361+
};
1362+
1363+
struct configset_list_item {
1364+
struct config_set_element *e;
1365+
int value_index;
1366+
};
1367+
1368+
/*
1369+
* the contents of the list are ordered according to their
1370+
* position in the config files and order of parsing the files.
1371+
* (i.e. key-value pair at the last position of .git/config will
1372+
* be at the last item of the list)
1373+
*/
1374+
struct configset_list {
1375+
struct configset_list_item *items;
1376+
unsigned int nr, alloc;
1377+
};
1378+
13561379
struct config_set {
13571380
struct hashmap config_hash;
13581381
int hash_initialized;
1382+
struct configset_list list;
13591383
};
13601384

13611385
extern void git_configset_init(struct config_set *cs);
@@ -1385,6 +1409,14 @@ extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
13851409
extern int git_config_get_maybe_bool(const char *key, int *dest);
13861410
extern int git_config_get_pathname(const char *key, const char **dest);
13871411

1412+
struct key_value_info {
1413+
const char *filename;
1414+
int linenr;
1415+
};
1416+
1417+
extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
1418+
extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
1419+
13881420
extern int committer_ident_sufficiently_given(void);
13891421
extern int author_ident_sufficiently_given(void);
13901422

config.c

Lines changed: 128 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ struct config_source {
3535
long (*do_ftell)(struct config_source *c);
3636
};
3737

38-
struct config_set_element {
39-
struct hashmap_entry ent;
40-
char *key;
41-
struct string_list value_list;
42-
};
43-
4438
static struct config_source *cf;
4539

4640
static int zlib_compression_seen;
@@ -252,6 +246,7 @@ static int get_next_char(void)
252246
cf->linenr++;
253247
if (c == EOF) {
254248
cf->eof = 1;
249+
cf->linenr++;
255250
c = '\n';
256251
}
257252
return c;
@@ -327,6 +322,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
327322
{
328323
int c;
329324
char *value;
325+
int ret;
330326

331327
/* Get the full name */
332328
for (;;) {
@@ -349,7 +345,15 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
349345
if (!value)
350346
return -1;
351347
}
352-
return fn(name->buf, value, data);
348+
/*
349+
* We already consumed the \n, but we need linenr to point to
350+
* the line we just parsed during the call to fn to get
351+
* accurate line number in error messages.
352+
*/
353+
cf->linenr--;
354+
ret = fn(name->buf, value, data);
355+
cf->linenr++;
356+
return ret;
353357
}
354358

355359
static int get_extended_base_var(struct strbuf *name, int c)
@@ -465,9 +469,9 @@ static int git_parse_source(config_fn_t fn, void *data)
465469
break;
466470
}
467471
if (cf->die_on_error)
468-
die("bad config file line %d in %s", cf->linenr, cf->name);
472+
die(_("bad config file line %d in %s"), cf->linenr, cf->name);
469473
else
470-
return error("bad config file line %d in %s", cf->linenr, cf->name);
474+
return error(_("bad config file line %d in %s"), cf->linenr, cf->name);
471475
}
472476

473477
static int parse_unit_factor(const char *end, uintmax_t *val)
@@ -583,9 +587,9 @@ static void die_bad_number(const char *name, const char *value)
583587
value = "";
584588

585589
if (cf && cf->name)
586-
die("bad numeric config value '%s' for '%s' in %s: %s",
590+
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
587591
value, name, cf->name, reason);
588-
die("bad numeric config value '%s' for '%s': %s", value, name, reason);
592+
die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
589593
}
590594

591595
int git_config_int(const char *name, const char *value)
@@ -670,7 +674,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
670674
return config_error_nonbool(var);
671675
*dest = expand_user_path(value);
672676
if (!*dest)
673-
die("Failed to expand user dir in: '%s'", value);
677+
die(_("failed to expand user dir in: '%s'"), value);
674678
return 0;
675679
}
676680

@@ -748,7 +752,7 @@ static int git_default_core_config(const char *var, const char *value)
748752
if (level == -1)
749753
level = Z_DEFAULT_COMPRESSION;
750754
else if (level < 0 || level > Z_BEST_COMPRESSION)
751-
die("bad zlib compression level %d", level);
755+
die(_("bad zlib compression level %d"), level);
752756
zlib_compression_level = level;
753757
zlib_compression_seen = 1;
754758
return 0;
@@ -759,7 +763,7 @@ static int git_default_core_config(const char *var, const char *value)
759763
if (level == -1)
760764
level = Z_DEFAULT_COMPRESSION;
761765
else if (level < 0 || level > Z_BEST_COMPRESSION)
762-
die("bad zlib compression level %d", level);
766+
die(_("bad zlib compression level %d"), level);
763767
core_compression_level = level;
764768
core_compression_seen = 1;
765769
if (!zlib_compression_seen)
@@ -881,7 +885,7 @@ static int git_default_core_config(const char *var, const char *value)
881885
else if (!strcmp(value, "link"))
882886
object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
883887
else
884-
die("Invalid mode for object creation: %s", value);
888+
die(_("invalid mode for object creation: %s"), value);
885889
return 0;
886890
}
887891

@@ -1181,7 +1185,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
11811185

11821186
switch (git_config_from_parameters(fn, data)) {
11831187
case -1: /* error */
1184-
die("unable to parse command-line config");
1188+
die(_("unable to parse command-line config"));
11851189
break;
11861190
case 0: /* found nothing */
11871191
break;
@@ -1228,9 +1232,48 @@ int git_config_with_options(config_fn_t fn, void *data,
12281232
return ret;
12291233
}
12301234

1231-
int git_config(config_fn_t fn, void *data)
1235+
static void git_config_raw(config_fn_t fn, void *data)
1236+
{
1237+
if (git_config_with_options(fn, data, NULL, 1) < 0)
1238+
/*
1239+
* git_config_with_options() normally returns only
1240+
* positive values, as most errors are fatal, and
1241+
* non-fatal potential errors are guarded by "if"
1242+
* statements that are entered only when no error is
1243+
* possible.
1244+
*
1245+
* If we ever encounter a non-fatal error, it means
1246+
* something went really wrong and we should stop
1247+
* immediately.
1248+
*/
1249+
die(_("unknown error occured while reading the configuration files"));
1250+
}
1251+
1252+
static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
12321253
{
1233-
return git_config_with_options(fn, data, NULL, 1);
1254+
int i, value_index;
1255+
struct string_list *values;
1256+
struct config_set_element *entry;
1257+
struct configset_list *list = &cs->list;
1258+
struct key_value_info *kv_info;
1259+
1260+
for (i = 0; i < list->nr; i++) {
1261+
entry = list->items[i].e;
1262+
value_index = list->items[i].value_index;
1263+
values = &entry->value_list;
1264+
if (fn(entry->key, values->items[value_index].string, data) < 0) {
1265+
kv_info = values->items[value_index].util;
1266+
git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
1267+
}
1268+
}
1269+
}
1270+
1271+
static void git_config_check_init(void);
1272+
1273+
void git_config(config_fn_t fn, void *data)
1274+
{
1275+
git_config_check_init();
1276+
configset_iter(&the_config_set, fn, data);
12341277
}
12351278

12361279
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
@@ -1258,6 +1301,10 @@ static struct config_set_element *configset_find_element(struct config_set *cs,
12581301
static int configset_add_value(struct config_set *cs, const char *key, const char *value)
12591302
{
12601303
struct config_set_element *e;
1304+
struct string_list_item *si;
1305+
struct configset_list_item *l_item;
1306+
struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
1307+
12611308
e = configset_find_element(cs, key);
12621309
/*
12631310
* Since the keys are being fed by git_config*() callback mechanism, they
@@ -1270,7 +1317,22 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
12701317
string_list_init(&e->value_list, 1);
12711318
hashmap_add(&cs->config_hash, e);
12721319
}
1273-
string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
1320+
si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
1321+
1322+
ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
1323+
l_item = &cs->list.items[cs->list.nr++];
1324+
l_item->e = e;
1325+
l_item->value_index = e->value_list.nr - 1;
1326+
1327+
if (cf) {
1328+
kv_info->filename = strintern(cf->name);
1329+
kv_info->linenr = cf->linenr;
1330+
} else {
1331+
/* for values read from `git_config_from_parameters()` */
1332+
kv_info->filename = NULL;
1333+
kv_info->linenr = -1;
1334+
}
1335+
si->util = kv_info;
12741336

12751337
return 0;
12761338
}
@@ -1285,6 +1347,9 @@ void git_configset_init(struct config_set *cs)
12851347
{
12861348
hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
12871349
cs->hash_initialized = 1;
1350+
cs->list.nr = 0;
1351+
cs->list.alloc = 0;
1352+
cs->list.items = NULL;
12881353
}
12891354

12901355
void git_configset_clear(struct config_set *cs)
@@ -1297,10 +1362,14 @@ void git_configset_clear(struct config_set *cs)
12971362
hashmap_iter_init(&cs->config_hash, &iter);
12981363
while ((entry = hashmap_iter_next(&iter))) {
12991364
free(entry->key);
1300-
string_list_clear(&entry->value_list, 0);
1365+
string_list_clear(&entry->value_list, 1);
13011366
}
13021367
hashmap_free(&cs->config_hash, 1);
13031368
cs->hash_initialized = 0;
1369+
free(cs->list.items);
1370+
cs->list.nr = 0;
1371+
cs->list.alloc = 0;
1372+
cs->list.items = NULL;
13041373
}
13051374

13061375
static int config_set_callback(const char *key, const char *value, void *cb)
@@ -1419,7 +1488,7 @@ static void git_config_check_init(void)
14191488
if (the_config_set.hash_initialized)
14201489
return;
14211490
git_configset_init(&the_config_set);
1422-
git_config(config_set_callback, &the_config_set);
1491+
git_config_raw(config_set_callback, &the_config_set);
14231492
}
14241493

14251494
void git_config_clear(void)
@@ -1443,8 +1512,12 @@ const struct string_list *git_config_get_value_multi(const char *key)
14431512

14441513
int git_config_get_string_const(const char *key, const char **dest)
14451514
{
1515+
int ret;
14461516
git_config_check_init();
1447-
return git_configset_get_string_const(&the_config_set, key, dest);
1517+
ret = git_configset_get_string_const(&the_config_set, key, dest);
1518+
if (ret < 0)
1519+
git_die_config(key, NULL);
1520+
return ret;
14481521
}
14491522

14501523
int git_config_get_string(const char *key, char **dest)
@@ -1485,8 +1558,39 @@ int git_config_get_maybe_bool(const char *key, int *dest)
14851558

14861559
int git_config_get_pathname(const char *key, const char **dest)
14871560
{
1561+
int ret;
14881562
git_config_check_init();
1489-
return git_configset_get_pathname(&the_config_set, key, dest);
1563+
ret = git_configset_get_pathname(&the_config_set, key, dest);
1564+
if (ret < 0)
1565+
git_die_config(key, NULL);
1566+
return ret;
1567+
}
1568+
1569+
NORETURN
1570+
void git_die_config_linenr(const char *key, const char *filename, int linenr)
1571+
{
1572+
if (!filename)
1573+
die(_("unable to parse '%s' from command-line config"), key);
1574+
else
1575+
die(_("bad config variable '%s' in file '%s' at line %d"),
1576+
key, filename, linenr);
1577+
}
1578+
1579+
NORETURN __attribute__((format(printf, 2, 3)))
1580+
void git_die_config(const char *key, const char *err, ...)
1581+
{
1582+
const struct string_list *values;
1583+
struct key_value_info *kv_info;
1584+
1585+
if (err) {
1586+
va_list params;
1587+
va_start(params, err);
1588+
vreportf("error: ", err, params);
1589+
va_end(params);
1590+
}
1591+
values = git_config_get_value_multi(key);
1592+
kv_info = values->items[values->nr - 1].util;
1593+
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
14901594
}
14911595

14921596
/*
@@ -1522,7 +1626,7 @@ static int store_aux(const char *key, const char *value, void *cb)
15221626
case KEY_SEEN:
15231627
if (matches(key, value)) {
15241628
if (store.seen == 1 && store.multi_replace == 0) {
1525-
warning("%s has multiple values", key);
1629+
warning(_("%s has multiple values"), key);
15261630
}
15271631

15281632
ALLOC_GROW(store.offset, store.seen + 1,

0 commit comments

Comments
 (0)