config: plumb --fixed-value into config API

The git_config_set_multivar_in_file_gently() and related methods now take a 'flags' bitfield, so add a new bit representing the --fixed-value option from 'git config'. This alters the purpose of the value_pattern parameter to be an exact string match. This requires some initialization changes in git_config_set_multivar_in_file_gently() and a new strcmp() call in the matches() method. The new CONFIG_FLAGS_FIXED_VALUE flag is initialized in builtin/config.c based on the --fixed-value option, and that needs to be updated in several callers. This patch only affects some of the modes of 'git config', and the rest will be completed in the next change. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Nov 25, 2020 at 22:12 UTC c90702a1f6f7473a959994a2dff0f0dd450b8029
4 files changed +73 -5
builtin/config.c
+11 -5
@@ -633,6 +633,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
633 {
634 int nongit = !startup_info->have_repository;
635 char *value;
636 + int flags = 0;
637
638 given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
639
@@ -800,6 +801,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
801 error(_("--fixed-value only applies with 'value-pattern'"));
802 usage_builtin_config();
803 }
804 +
805 + flags |= CONFIG_FLAGS_FIXED_VALUE;
806 }
807
808 if (actions & PAGING_ACTIONS)
@@ -863,7 +866,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
866 value = normalize_value(argv[0], argv[1]);
867 UNLEAK(value);
868 return git_config_set_multivar_in_file_gently(given_config_source.file,
866 - argv[0], value, argv[2], 0);
869 + argv[0], value, argv[2],
870 + flags);
871 }
872 else if (actions == ACTION_ADD) {
873 check_write();
@@ -872,7 +876,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
876 UNLEAK(value);
877 return git_config_set_multivar_in_file_gently(given_config_source.file,
878 argv[0], value,
875 - CONFIG_REGEX_NONE, 0);
879 + CONFIG_REGEX_NONE,
880 + flags);
881 }
882 else if (actions == ACTION_REPLACE_ALL) {
883 check_write();
@@ -881,7 +886,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
886 UNLEAK(value);
887 return git_config_set_multivar_in_file_gently(given_config_source.file,
888 argv[0], value, argv[2],
884 - CONFIG_FLAGS_MULTI_REPLACE);
889 + flags | CONFIG_FLAGS_MULTI_REPLACE);
890 }
891 else if (actions == ACTION_GET) {
892 check_argc(argc, 1, 2);
@@ -908,7 +913,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
913 check_argc(argc, 1, 2);
914 if (argc == 2)
915 return git_config_set_multivar_in_file_gently(given_config_source.file,
911 - argv[0], NULL, argv[1], 0);
916 + argv[0], NULL, argv[1],
917 + flags);
918 else
919 return git_config_set_in_file_gently(given_config_source.file,
920 argv[0], NULL);
@@ -918,7 +924,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
924 check_argc(argc, 1, 2);
925 return git_config_set_multivar_in_file_gently(given_config_source.file,
926 argv[0], NULL, argv[1],
921 - CONFIG_FLAGS_MULTI_REPLACE);
927 + flags | CONFIG_FLAGS_MULTI_REPLACE);
928 }
929 else if (actions == ACTION_RENAME_SECTION) {
930 int ret;
config.c
+5
@@ -2415,6 +2415,7 @@ struct config_store_data {
2415 size_t baselen;
2416 char *key;
2417 int do_not_match;
2418 + const char *fixed_value;
2419 regex_t *value_pattern;
2420 int multi_replace;
2421 struct {
@@ -2444,6 +2445,8 @@ static int matches(const char *key, const char *value,
2445 {
2446 if (strcmp(key, store->key))
2447 return 0; /* not ours */
2448 + if (store->fixed_value)
2449 + return !strcmp(store->fixed_value, value);
2450 if (!store->value_pattern)
2451 return 1; /* always matches */
2452 if (store->value_pattern == CONFIG_REGEX_NONE)
@@ -2816,6 +2819,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
2819 store.value_pattern = NULL;
2820 else if (value_pattern == CONFIG_REGEX_NONE)
2821 store.value_pattern = CONFIG_REGEX_NONE;
2822 + else if (flags & CONFIG_FLAGS_FIXED_VALUE)
2823 + store.fixed_value = value_pattern;
2824 else {
2825 if (value_pattern[0] == '!') {
2826 store.do_not_match = 1;
config.h
+7
@@ -269,6 +269,13 @@ int git_config_key_is_valid(const char *key);
269 */
270 #define CONFIG_FLAGS_MULTI_REPLACE (1 << 0)
271
272 +/*
273 + * When CONFIG_FLAGS_FIXED_VALUE is specified, match key/value pairs
274 + * by string comparison (not regex match) to the provided value_pattern
275 + * parameter.
276 + */
277 +#define CONFIG_FLAGS_FIXED_VALUE (1 << 1)
278 +
279 int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
280 void git_config_set_multivar(const char *, const char *, const char *, unsigned);
281 int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, unsigned);
t/t1300-config.sh
+50
@@ -1994,4 +1994,54 @@ test_expect_success 'refuse --fixed-value for incompatible actions' '
1994 test_must_fail git config --file=config --fixed-value --unset-all dev.null
1995 '
1996
1997 +test_expect_success '--fixed-value uses exact string matching' '
1998 + test_when_finished rm -f config initial &&
1999 + META="a+b*c?d[e]f.g" &&
2000 + git config --file=initial fixed.test "$META" &&
2001 +
2002 + cp initial config &&
2003 + git config --file=config fixed.test bogus "$META" &&
2004 + git config --file=config --list >actual &&
2005 + cat >expect <<-EOF &&
2006 + fixed.test=$META
2007 + fixed.test=bogus
2008 + EOF
2009 + test_cmp expect actual &&
2010 +
2011 + cp initial config &&
2012 + git config --file=config --fixed-value fixed.test bogus "$META" &&
2013 + git config --file=config --list >actual &&
2014 + cat >expect <<-\EOF &&
2015 + fixed.test=bogus
2016 + EOF
2017 + test_cmp expect actual &&
2018 +
2019 + cp initial config &&
2020 + test_must_fail git config --file=config --unset fixed.test "$META" &&
2021 + git config --file=config --fixed-value --unset fixed.test "$META" &&
2022 + test_must_fail git config --file=config fixed.test &&
2023 +
2024 + cp initial config &&
2025 + test_must_fail git config --file=config --unset-all fixed.test "$META" &&
2026 + git config --file=config --fixed-value --unset-all fixed.test "$META" &&
2027 + test_must_fail git config --file=config fixed.test &&
2028 +
2029 + cp initial config &&
2030 + git config --file=config --replace-all fixed.test bogus "$META" &&
2031 + git config --file=config --list >actual &&
2032 + cat >expect <<-EOF &&
2033 + fixed.test=$META
2034 + fixed.test=bogus
2035 + EOF
2036 + test_cmp expect actual &&
2037 +
2038 + git config --file=config --fixed-value --replace-all fixed.test bogus "$META" &&
2039 + git config --file=config --list >actual &&
2040 + cat >expect <<-EOF &&
2041 + fixed.test=bogus
2042 + fixed.test=bogus
2043 + EOF
2044 + test_cmp expect actual
2045 +'
2046 +
2047 test_done