git-config-set: support selecting values by non-matching regex
Extend the regex syntax of value_regex so that prepending an exclamation mark means non-match: [core] quetzal = "Dodo" for Brainf*ck quetzal = "T. Rex" for Malbolge quetzal = "cat" You can match the third line with git-config-set --get quetzal '! for ' Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
a6322d079b
commit
f98d863d21
@ -22,7 +22,9 @@ actually the section and the key separated by a dot, and the value will be
|
||||
escaped.
|
||||
|
||||
If you want to set/unset an option which can occor on multiple lines, you
|
||||
should provide a POSIX regex for the value.
|
||||
should provide a POSIX regex for the value. If you want to handle the lines
|
||||
*not* matching the regex, just prepend a single exlamation mark in front
|
||||
(see EXAMPLES).
|
||||
|
||||
This command will fail if
|
||||
|
||||
@ -82,6 +84,7 @@ Given a .git/config like this:
|
||||
command="ssh" for "ssh://kernel.org/"
|
||||
command="proxy-command" for kernel.org
|
||||
command="myprotocol-command" for "my://"
|
||||
command=default-proxy ; for all the rest
|
||||
|
||||
you can set the filemode to true with
|
||||
|
||||
@ -139,6 +142,19 @@ new one with
|
||||
% git config-set --replace-all proxy.command ssh
|
||||
------------
|
||||
|
||||
However, if you really only want to replace the line for the default proxy,
|
||||
i.e. the one without a "for ..." postfix, do something like this:
|
||||
|
||||
------------
|
||||
% git config-set proxy.command ssh '! for '
|
||||
------------
|
||||
|
||||
To actually match only values with an exclamation mark, you have to
|
||||
|
||||
------------
|
||||
% git config-set section.key value '[!]'
|
||||
------------
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -8,13 +8,15 @@ static char* key = NULL;
|
||||
static char* value = NULL;
|
||||
static regex_t* regex = NULL;
|
||||
static int do_all = 0;
|
||||
static int do_not_match = 0;
|
||||
static int seen = 0;
|
||||
|
||||
static int show_config(const char* key_, const char* value_)
|
||||
{
|
||||
if (!strcmp(key_, key) &&
|
||||
(regex == NULL ||
|
||||
!regexec(regex, value_, 0, NULL, 0))) {
|
||||
(do_not_match ^
|
||||
!regexec(regex, value_, 0, NULL, 0)))) {
|
||||
if (do_all) {
|
||||
printf("%s\n", value_);
|
||||
return 0;
|
||||
@ -38,6 +40,11 @@ static int get_value(const char* key_, const char* regex_)
|
||||
key[i] = tolower(key_[i]);
|
||||
|
||||
if (regex_) {
|
||||
if (regex_[0] == '!') {
|
||||
do_not_match = 1;
|
||||
regex_++;
|
||||
}
|
||||
|
||||
regex = (regex_t*)malloc(sizeof(regex_t));
|
||||
if (regcomp(regex, regex_, REG_EXTENDED)) {
|
||||
fprintf(stderr, "Invalid pattern: %s\n", regex_);
|
||||
|
23
config.c
23
config.c
@ -269,6 +269,7 @@ int git_config(config_fn_t fn)
|
||||
static struct {
|
||||
int baselen;
|
||||
char* key;
|
||||
int do_not_match;
|
||||
regex_t* value_regex;
|
||||
int multi_replace;
|
||||
off_t offset[MAX_MATCHES];
|
||||
@ -276,13 +277,19 @@ static struct {
|
||||
int seen;
|
||||
} store;
|
||||
|
||||
static int matches(const char* key, const char* value)
|
||||
{
|
||||
return !strcmp(key, store.key) &&
|
||||
(store.value_regex == NULL ||
|
||||
(store.do_not_match ^
|
||||
!regexec(store.value_regex, value, 0, NULL, 0)));
|
||||
}
|
||||
|
||||
static int store_aux(const char* key, const char* value)
|
||||
{
|
||||
switch (store.state) {
|
||||
case KEY_SEEN:
|
||||
if (!strcmp(key, store.key) &&
|
||||
(store.value_regex == NULL ||
|
||||
!regexec(store.value_regex, value, 0, NULL, 0))) {
|
||||
if (matches(key, value)) {
|
||||
if (store.seen == 1 && store.multi_replace == 0) {
|
||||
fprintf(stderr,
|
||||
"Warning: %s has multiple values\n",
|
||||
@ -306,9 +313,7 @@ static int store_aux(const char* key, const char* value)
|
||||
/* fallthru */
|
||||
case SECTION_END_SEEN:
|
||||
case START:
|
||||
if (!strcmp(key, store.key) &&
|
||||
(store.value_regex == NULL ||
|
||||
!regexec(store.value_regex, value, 0, NULL, 0))) {
|
||||
if (matches(key, value)) {
|
||||
store.offset[store.seen] = ftell(config_file);
|
||||
store.state = KEY_SEEN;
|
||||
store.seen++;
|
||||
@ -471,6 +476,12 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
if (value_regex == NULL)
|
||||
store.value_regex = NULL;
|
||||
else {
|
||||
if (value_regex[0] == '!') {
|
||||
store.do_not_match = 1;
|
||||
value_regex++;
|
||||
} else
|
||||
store.do_not_match = 0;
|
||||
|
||||
store.value_regex = (regex_t*)malloc(sizeof(regex_t));
|
||||
if (regcomp(store.value_regex, value_regex,
|
||||
REG_EXTENDED)) {
|
||||
|
@ -69,6 +69,28 @@ EOF
|
||||
|
||||
test_expect_success 'similar section' 'cmp .git/config expect'
|
||||
|
||||
test_expect_success 'replace with non-match' \
|
||||
'git-config-set core.penguin kingpin !blue'
|
||||
|
||||
test_expect_success 'replace with non-match (actually matching)' \
|
||||
'git-config-set core.penguin "very blue" !kingpin'
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = very blue
|
||||
Movie = BadPhysics
|
||||
UPPERCASE = true
|
||||
penguin = kingpin
|
||||
[Cores]
|
||||
WhatEver = Second
|
||||
EOF
|
||||
|
||||
test_expect_success 'non-match result' 'cmp .git/config expect'
|
||||
|
||||
cat > .git/config << EOF
|
||||
[beta] ; silly comment # another comment
|
||||
noIndent= sillyValue ; 'nother silly comment
|
||||
@ -173,6 +195,12 @@ EOF
|
||||
|
||||
test_expect_success 'multivar' 'cmp .git/config expect'
|
||||
|
||||
test_expect_success 'non-match' \
|
||||
'git-config-set --get nextsection.nonewline !for'
|
||||
|
||||
test_expect_success 'non-match value' \
|
||||
'test wow = $(git-config-set --get nextsection.nonewline !for)'
|
||||
|
||||
test_expect_failure 'ambiguous get' \
|
||||
'git-config-set --get nextsection.nonewline'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user