]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/config.c
Merge branch 'js/commit-slab-decl-fix'
[thirdparty/git.git] / builtin / config.c
index e4d96313d79d8ca8dede8f89becaa2b94f909d24..6cbf73369b2f6cf41430d78e0a5e8ffa18de6d15 100644 (file)
@@ -3,6 +3,7 @@
 #include "color.h"
 #include "parse-options.h"
 #include "urlmatch.h"
+#include "quote.h"
 
 static const char *const builtin_config_usage[] = {
        N_("git config [<options>]"),
@@ -13,6 +14,7 @@ static char *key;
 static regex_t *key_regexp;
 static regex_t *regexp;
 static int show_keys;
+static int omit_values;
 static int use_key_regexp;
 static int do_all;
 static int do_not_match;
@@ -25,6 +27,7 @@ static struct git_config_source given_config_source;
 static int actions, types;
 static int end_null;
 static int respect_includes = -1;
+static int show_origin;
 
 #define ACTION_GET (1<<0)
 #define ACTION_GET_ALL (1<<1)
@@ -77,7 +80,9 @@ static struct option builtin_config_options[] = {
        OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
        OPT_GROUP(N_("Other")),
        OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+       OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
        OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
+       OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
        OPT_END(),
 };
 
@@ -88,9 +93,29 @@ static void check_argc(int argc, int min, int max) {
        usage_with_options(builtin_config_usage, builtin_config_options);
 }
 
+static void show_config_origin(struct strbuf *buf)
+{
+       const char term = end_null ? '\0' : '\t';
+
+       strbuf_addstr(buf, current_config_origin_type());
+       strbuf_addch(buf, ':');
+       if (end_null)
+               strbuf_addstr(buf, current_config_name());
+       else
+               quote_c_style(current_config_name(), buf, NULL, 0);
+       strbuf_addch(buf, term);
+}
+
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-       if (value_)
+       if (show_origin) {
+               struct strbuf buf = STRBUF_INIT;
+               show_config_origin(&buf);
+               /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
+               fwrite(buf.buf, 1, buf.len, stdout);
+               strbuf_release(&buf);
+       }
+       if (!omit_values && value_)
                printf("%s%c%s%c", key_, delim, value_, term);
        else
                printf("%s%c", key_, term);
@@ -105,48 +130,42 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
-       int must_free_vptr = 0;
-       int must_print_delim = 0;
-       char value[256];
-       const char *vptr = value;
-
-       strbuf_init(buf, 0);
-
-       if (show_keys) {
+       if (show_origin)
+               show_config_origin(buf);
+       if (show_keys)
                strbuf_addstr(buf, key_);
-               must_print_delim = 1;
-       }
-       if (types == TYPE_INT)
-               sprintf(value, "%"PRId64,
-                       git_config_int64(key_, value_ ? value_ : ""));
-       else if (types == TYPE_BOOL)
-               vptr = git_config_bool(key_, value_) ? "true" : "false";
-       else if (types == TYPE_BOOL_OR_INT) {
-               int is_bool, v;
-               v = git_config_bool_or_int(key_, value_, &is_bool);
-               if (is_bool)
-                       vptr = v ? "true" : "false";
-               else
-                       sprintf(value, "%d", v);
-       } else if (types == TYPE_PATH) {
-               if (git_config_pathname(&vptr, key_, value_) < 0)
-                       return -1;
-               must_free_vptr = 1;
-       } else if (value_) {
-               vptr = value_;
-       } else {
-               /* Just show the key name */
-               vptr = "";
-               must_print_delim = 0;
-       }
+       if (!omit_values) {
+               if (show_keys)
+                       strbuf_addch(buf, key_delim);
 
-       if (must_print_delim)
-               strbuf_addch(buf, key_delim);
-       strbuf_addstr(buf, vptr);
+               if (types == TYPE_INT)
+                       strbuf_addf(buf, "%"PRId64,
+                                   git_config_int64(key_, value_ ? value_ : ""));
+               else if (types == TYPE_BOOL)
+                       strbuf_addstr(buf, git_config_bool(key_, value_) ?
+                                     "true" : "false");
+               else if (types == TYPE_BOOL_OR_INT) {
+                       int is_bool, v;
+                       v = git_config_bool_or_int(key_, value_, &is_bool);
+                       if (is_bool)
+                               strbuf_addstr(buf, v ? "true" : "false");
+                       else
+                               strbuf_addf(buf, "%d", v);
+               } else if (types == TYPE_PATH) {
+                       const char *v;
+                       if (git_config_pathname(&v, key_, value_) < 0)
+                               return -1;
+                       strbuf_addstr(buf, v);
+                       free((char *)v);
+               } else if (value_) {
+                       strbuf_addstr(buf, value_);
+               } else {
+                       /* Just show the key name; back out delimiter */
+                       if (show_keys)
+                               strbuf_setlen(buf, buf->len - 1);
+               }
+       }
        strbuf_addch(buf, term);
-
-       if (must_free_vptr)
-               free((char *)vptr);
        return 0;
 }
 
@@ -163,6 +182,7 @@ static int collect_config(const char *key_, const char *value_, void *cb)
                return 0;
 
        ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+       strbuf_init(&values->items[values->nr], 0);
 
        return format_config(&values->items[values->nr++], key_, value_);
 }
@@ -192,7 +212,7 @@ static int get_value(const char *key_, const char *regex_)
 
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
-                       fprintf(stderr, "Invalid key pattern: %s\n", key_);
+                       error("invalid key pattern: %s", key_);
                        free(key_regexp);
                        key_regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
@@ -213,7 +233,7 @@ static int get_value(const char *key_, const char *regex_)
 
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
-                       fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       error("invalid pattern: %s", regex_);
                        free(regexp);
                        regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
@@ -250,8 +270,6 @@ free_strings:
 
 static char *normalize_value(const char *key, const char *value)
 {
-       char *normalized;
-
        if (!value)
                return NULL;
 
@@ -262,27 +280,21 @@ static char *normalize_value(const char *key, const char *value)
                 * "~/foobar/" in the config file, and to expand the ~
                 * when retrieving the value.
                 */
-               normalized = xstrdup(value);
-       else {
-               normalized = xmalloc(64);
-               if (types == TYPE_INT) {
-                       int64_t v = git_config_int64(key, value);
-                       sprintf(normalized, "%"PRId64, v);
-               }
-               else if (types == TYPE_BOOL)
-                       sprintf(normalized, "%s",
-                               git_config_bool(key, value) ? "true" : "false");
-               else if (types == TYPE_BOOL_OR_INT) {
-                       int is_bool, v;
-                       v = git_config_bool_or_int(key, value, &is_bool);
-                       if (!is_bool)
-                               sprintf(normalized, "%d", v);
-                       else
-                               sprintf(normalized, "%s", v ? "true" : "false");
-               }
+               return xstrdup(value);
+       if (types == TYPE_INT)
+               return xstrfmt("%"PRId64, git_config_int64(key, value));
+       if (types == TYPE_BOOL)
+               return xstrdup(git_config_bool(key, value) ?  "true" : "false");
+       if (types == TYPE_BOOL_OR_INT) {
+               int is_bool, v;
+               v = git_config_bool_or_int(key, value, &is_bool);
+               if (!is_bool)
+                       return xstrfmt("%d", v);
+               else
+                       return xstrdup(v ? "true" : "false");
        }
 
-       return normalized;
+       die("BUG: cannot normalize type %d", types);
 }
 
 static int get_color_found;
@@ -364,6 +376,9 @@ static int get_colorbool(const char *var, int print)
 
 static void check_write(void)
 {
+       if (!given_config_source.file && !startup_info->have_repository)
+               die("not in a git directory");
+
        if (given_config_source.use_stdin)
                die("writing to stdin is not supported");
 
@@ -401,6 +416,7 @@ static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
 
 static int get_urlmatch(const char *var, const char *url)
 {
+       int ret;
        char *section_tail;
        struct string_list_item *item;
        struct urlmatch_config config = { STRING_LIST_INIT_DUP };
@@ -427,16 +443,15 @@ static int get_urlmatch(const char *var, const char *url)
        git_config_with_options(urlmatch_config_entry, &config,
                                &given_config_source, respect_includes);
 
+       ret = !values.nr;
+
        for_each_string_list_item(item, &values) {
                struct urlmatch_current_candidate_value *matched = item->util;
-               struct strbuf key = STRBUF_INIT;
                struct strbuf buf = STRBUF_INIT;
 
-               strbuf_addstr(&key, item->string);
-               format_config(&buf, key.buf,
+               format_config(&buf, item->string,
                              matched->value_is_null ? NULL : matched->value.buf);
                fwrite(buf.buf, 1, buf.len, stdout);
-               strbuf_release(&key);
                strbuf_release(&buf);
 
                strbuf_release(&matched->value);
@@ -446,7 +461,7 @@ static int get_urlmatch(const char *var, const char *url)
        free(config.url.url);
 
        free((void *)config.section);
-       return 0;
+       return ret;
 }
 
 static char *default_user_config(void)
@@ -548,6 +563,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                default:
                        usage_with_options(builtin_config_usage, builtin_config_options);
                }
+       if (omit_values &&
+           !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
+               error("--name-only is only applicable to --list or --get-regexp");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
+
+       if (show_origin && !(actions &
+               (ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
+               error("--show-origin is only applicable to --get, --get-all, "
+                         "--get-regexp, and --list.");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
 
        if (actions == ACTION_LIST) {
                check_argc(argc, 0, 0);
@@ -576,7 +603,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                                      given_config_source.file : git_path("config"));
                if (use_global_config) {
                        int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
-                       if (fd) {
+                       if (fd >= 0) {
                                char *content = default_user_config();
                                write_str_in_full(fd, content);
                                free(content);
@@ -593,7 +620,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               ret = git_config_set_in_file(given_config_source.file, argv[0], value);
+               ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
                if (ret == CONFIG_NOTHING_SET)
                        error("cannot overwrite multiple values with a single value\n"
                        "       Use a regexp, --add or --replace-all to change %s.", argv[0]);
@@ -603,23 +630,23 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 0);
        }
        else if (actions == ACTION_ADD) {
                check_write();
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value,
-                                                      CONFIG_REGEX_NONE, 0);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value,
+                                                             CONFIG_REGEX_NONE, 0);
        }
        else if (actions == ACTION_REPLACE_ALL) {
                check_write();
                check_argc(argc, 2, 3);
                value = normalize_value(argv[0], argv[1]);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, argv[2], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], value, argv[2], 1);
        }
        else if (actions == ACTION_GET) {
                check_argc(argc, 1, 2);
@@ -645,17 +672,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_write();
                check_argc(argc, 1, 2);
                if (argc == 2)
-                       return git_config_set_multivar_in_file(given_config_source.file,
-                                                              argv[0], NULL, argv[1], 0);
+                       return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                                     argv[0], NULL, argv[1], 0);
                else
-                       return git_config_set_in_file(given_config_source.file,
-                                                     argv[0], NULL);
+                       return git_config_set_in_file_gently(given_config_source.file,
+                                                            argv[0], NULL);
        }
        else if (actions == ACTION_UNSET_ALL) {
                check_write();
                check_argc(argc, 1, 2);
-               return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], NULL, argv[1], 1);
+               return git_config_set_multivar_in_file_gently(given_config_source.file,
+                                                             argv[0], NULL, argv[1], 1);
        }
        else if (actions == ACTION_RENAME_SECTION) {
                int ret;