Merge branch 'tr/config-multivalue-lift-max'
* tr/config-multivalue-lift-max: config: arbitrary number of matches for --unset and --replace-all
This commit is contained in:
19
config.c
19
config.c
@ -1210,15 +1210,14 @@ int git_config(config_fn_t fn, void *data)
|
|||||||
* Find all the stuff for git_config_set() below.
|
* Find all the stuff for git_config_set() below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MAX_MATCHES 512
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
int baselen;
|
int baselen;
|
||||||
char *key;
|
char *key;
|
||||||
int do_not_match;
|
int do_not_match;
|
||||||
regex_t *value_regex;
|
regex_t *value_regex;
|
||||||
int multi_replace;
|
int multi_replace;
|
||||||
size_t offset[MAX_MATCHES];
|
size_t *offset;
|
||||||
|
unsigned int offset_alloc;
|
||||||
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
|
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
|
||||||
int seen;
|
int seen;
|
||||||
} store;
|
} store;
|
||||||
@ -1241,11 +1240,11 @@ static int store_aux(const char *key, const char *value, void *cb)
|
|||||||
if (matches(key, value)) {
|
if (matches(key, value)) {
|
||||||
if (store.seen == 1 && store.multi_replace == 0) {
|
if (store.seen == 1 && store.multi_replace == 0) {
|
||||||
warning("%s has multiple values", key);
|
warning("%s has multiple values", key);
|
||||||
} else if (store.seen >= MAX_MATCHES) {
|
|
||||||
error("too many matches for %s", key);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALLOC_GROW(store.offset, store.seen + 1,
|
||||||
|
store.offset_alloc);
|
||||||
|
|
||||||
store.offset[store.seen] = cf->do_ftell(cf);
|
store.offset[store.seen] = cf->do_ftell(cf);
|
||||||
store.seen++;
|
store.seen++;
|
||||||
}
|
}
|
||||||
@ -1273,11 +1272,15 @@ static int store_aux(const char *key, const char *value, void *cb)
|
|||||||
* Do not increment matches: this is no match, but we
|
* Do not increment matches: this is no match, but we
|
||||||
* just made sure we are in the desired section.
|
* just made sure we are in the desired section.
|
||||||
*/
|
*/
|
||||||
|
ALLOC_GROW(store.offset, store.seen + 1,
|
||||||
|
store.offset_alloc);
|
||||||
store.offset[store.seen] = cf->do_ftell(cf);
|
store.offset[store.seen] = cf->do_ftell(cf);
|
||||||
/* fallthru */
|
/* fallthru */
|
||||||
case SECTION_END_SEEN:
|
case SECTION_END_SEEN:
|
||||||
case START:
|
case START:
|
||||||
if (matches(key, value)) {
|
if (matches(key, value)) {
|
||||||
|
ALLOC_GROW(store.offset, store.seen + 1,
|
||||||
|
store.offset_alloc);
|
||||||
store.offset[store.seen] = cf->do_ftell(cf);
|
store.offset[store.seen] = cf->do_ftell(cf);
|
||||||
store.state = KEY_SEEN;
|
store.state = KEY_SEEN;
|
||||||
store.seen++;
|
store.seen++;
|
||||||
@ -1285,6 +1288,9 @@ static int store_aux(const char *key, const char *value, void *cb)
|
|||||||
if (strrchr(key, '.') - key == store.baselen &&
|
if (strrchr(key, '.') - key == store.baselen &&
|
||||||
!strncmp(key, store.key, store.baselen)) {
|
!strncmp(key, store.key, store.baselen)) {
|
||||||
store.state = SECTION_SEEN;
|
store.state = SECTION_SEEN;
|
||||||
|
ALLOC_GROW(store.offset,
|
||||||
|
store.seen + 1,
|
||||||
|
store.offset_alloc);
|
||||||
store.offset[store.seen] = cf->do_ftell(cf);
|
store.offset[store.seen] = cf->do_ftell(cf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1583,6 +1589,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALLOC_GROW(store.offset, 1, store.offset_alloc);
|
||||||
store.offset[0] = 0;
|
store.offset[0] = 0;
|
||||||
store.state = START;
|
store.state = START;
|
||||||
store.seen = 0;
|
store.seen = 0;
|
||||||
|
@ -3,17 +3,28 @@
|
|||||||
test_description='Test wacky input to git config'
|
test_description='Test wacky input to git config'
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
# Leaving off the newline is intentional!
|
||||||
setup() {
|
setup() {
|
||||||
(printf "[section]\n" &&
|
(printf "[section]\n" &&
|
||||||
printf " key = foo") >.git/config
|
printf " key = foo") >.git/config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 'check section.key value' verifies that the entry for section.key is
|
||||||
|
# 'value'
|
||||||
check() {
|
check() {
|
||||||
echo "$2" >expected
|
echo "$2" >expected
|
||||||
git config --get "$1" >actual 2>&1
|
git config --get "$1" >actual 2>&1
|
||||||
test_cmp actual expected
|
test_cmp actual expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 'check section.key regex value' verifies that the entry for
|
||||||
|
# section.key *that matches 'regex'* is 'value'
|
||||||
|
check_regex() {
|
||||||
|
echo "$3" >expected
|
||||||
|
git config --get "$1" "$2" >actual 2>&1
|
||||||
|
test_cmp actual expected
|
||||||
|
}
|
||||||
|
|
||||||
test_expect_success 'modify same key' '
|
test_expect_success 'modify same key' '
|
||||||
setup &&
|
setup &&
|
||||||
git config section.key bar &&
|
git config section.key bar &&
|
||||||
@ -47,4 +58,57 @@ test_expect_success 'do not crash on special long config line' '
|
|||||||
check section.key "$LONG_VALUE"
|
check section.key "$LONG_VALUE"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
setup_many() {
|
||||||
|
setup &&
|
||||||
|
# This time we want the newline so that we can tack on more
|
||||||
|
# entries.
|
||||||
|
echo >>.git/config &&
|
||||||
|
# Semi-efficient way of concatenating 5^5 = 3125 lines. Note
|
||||||
|
# that because 'setup' already put one line, this means 3126
|
||||||
|
# entries for section.key in the config file.
|
||||||
|
cat >5to1 <<-\EOF &&
|
||||||
|
key = foo
|
||||||
|
key = foo
|
||||||
|
key = foo
|
||||||
|
key = foo
|
||||||
|
key = foo
|
||||||
|
EOF
|
||||||
|
cat 5to1 5to1 5to1 5to1 5to1 >5to2 && # 25
|
||||||
|
cat 5to2 5to2 5to2 5to2 5to2 >5to3 && # 125
|
||||||
|
cat 5to3 5to3 5to3 5to3 5to3 >5to4 && # 635
|
||||||
|
cat 5to4 5to4 5to4 5to4 5to4 >>.git/config # 3125
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'get many entries' '
|
||||||
|
setup_many &&
|
||||||
|
git config --get-all section.key >actual &&
|
||||||
|
test_line_count = 3126 actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'get many entries by regex' '
|
||||||
|
setup_many &&
|
||||||
|
git config --get-regexp "sec.*ke." >actual &&
|
||||||
|
test_line_count = 3126 actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'add and replace one of many entries' '
|
||||||
|
setup_many &&
|
||||||
|
git config --add section.key bar &&
|
||||||
|
check_regex section.key "b.*r" bar &&
|
||||||
|
git config section.key beer "b.*r" &&
|
||||||
|
check_regex section.key "b.*r" beer
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'replace many entries' '
|
||||||
|
setup_many &&
|
||||||
|
git config --replace-all section.key bar &&
|
||||||
|
check section.key bar
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'unset many entries' '
|
||||||
|
setup_many &&
|
||||||
|
git config --unset-all section.key &&
|
||||||
|
test_must_fail git config section.key
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Reference in New Issue
Block a user