Merge branch 'jc/url-match'
authorJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2013 21:50:32 +0000 (14:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2013 21:50:36 +0000 (14:50 -0700)
Allow section.<urlpattern>.var configuration variables to be
treated as a "virtual" section.var given a URL, and use the
mechanism to enhance http.* configuration variables.

This is a reroll of Kyle J. McKay's work.

* jc/url-match:
builtin/config.c: compilation fix
config: "git config --get-urlmatch" parses section.<url>.key
builtin/config: refactor collect_config()
config: parse http.<url>.<variable> using urlmatch
config: add generic callback wrapper to parse section.<url>.key
config: add helper to normalize and match URLs
http.c: fix parsing of http.sslCertPasswordProtected variable

1  2 
.gitignore
Documentation/config.txt
Documentation/git-config.txt
Makefile
builtin/config.c
http.c
diff --cc .gitignore
Simple merge
Simple merge
index 2dbe486eb16d8edde01ece856fa1e0ad75053042,b48e2ecc1ca146c0496902327b3f2a54a58e9a5a..e9917b89a91b36c87892ea1c08522f17be3c0d89
@@@ -95,14 -96,21 +96,22 @@@ OPTION
        in which section and variable names are lowercased, but subsection
        names are not.
  
+ --get-urlmatch name URL::
+       When given a two-part name section.key, the value for
+       section.<url>.key whose <url> part matches the best to the
+       given URL is returned (if no such key exists, the value for
+       section.key is used as a fallback).  When given just the
+       section as name, do so for all the keys in the section and
+       list them.
  --global::
 -      For writing options: write to global ~/.gitconfig file rather than
 -      the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
 -      if this file exists and the ~/.gitconfig file doesn't.
 +      For writing options: write to global `~/.gitconfig` file
 +      rather than the repository `.git/config`, write to
 +      `$XDG_CONFIG_HOME/git/config` file if this file exists and the
 +      `~/.gitconfig` file doesn't.
  +
 -For reading options: read only from global ~/.gitconfig and from
 -$XDG_CONFIG_HOME/git/config rather than from all available files.
 +For reading options: read only from global `~/.gitconfig` and from
 +`$XDG_CONFIG_HOME/git/config` rather than from all available files.
  +
  See also <<FILES>>.
  
diff --cc Makefile
Simple merge
index 4ab9e9a550ddf06f3822cea78689a60fd802f8d2,ae199e9f75eb1d52057cdc63da30418723049f4a..fc8d8820cbd2c0fcddb69aeb3fa258cf87e96814
@@@ -358,12 -351,97 +361,103 @@@ static int get_colorbool(int print
                return get_colorbool_found ? 0 : 1;
  }
  
 -                              given_config_file, respect_includes);
 +static void check_blob_write(void)
 +{
 +      if (given_config_blob)
 +              die("writing config blobs is not supported");
 +}
 +
+ struct urlmatch_current_candidate_value {
+       char value_is_null;
+       struct strbuf value;
+ };
+ static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
+ {
+       struct string_list *values = cb;
+       struct string_list_item *item = string_list_insert(values, var);
+       struct urlmatch_current_candidate_value *matched = item->util;
+       if (!matched) {
+               matched = xmalloc(sizeof(*matched));
+               strbuf_init(&matched->value, 0);
+               item->util = matched;
+       } else {
+               strbuf_reset(&matched->value);
+       }
+       if (value) {
+               strbuf_addstr(&matched->value, value);
+               matched->value_is_null = 0;
+       } else {
+               matched->value_is_null = 1;
+       }
+       return 0;
+ }
+ static char *dup_downcase(const char *string)
+ {
+       char *result;
+       size_t len, i;
+       len = strlen(string);
+       result = xmalloc(len + 1);
+       for (i = 0; i < len; i++)
+               result[i] = tolower(string[i]);
+       result[i] = '\0';
+       return result;
+ }
+ static int get_urlmatch(const char *var, const char *url)
+ {
+       char *section_tail;
+       struct string_list_item *item;
+       struct urlmatch_config config = { STRING_LIST_INIT_DUP };
+       struct string_list values = STRING_LIST_INIT_DUP;
+       config.collect_fn = urlmatch_collect_fn;
+       config.cascade_fn = NULL;
+       config.cb = &values;
+       if (!url_normalize(url, &config.url))
+               die("%s", config.url.err);
+       config.section = dup_downcase(var);
+       section_tail = strchr(config.section, '.');
+       if (section_tail) {
+               *section_tail = '\0';
+               config.key = section_tail + 1;
+               show_keys = 0;
+       } else {
+               config.key = NULL;
+               show_keys = 1;
+       }
+       git_config_with_options(urlmatch_config_entry, &config,
++                              given_config_file, NULL, respect_includes);
+       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,
+                             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);
+       }
+       string_list_clear(&config.vars, 1);
+       string_list_clear(&values, 1);
+       free(config.url.url);
+       free((void *)config.section);
+       return 0;
+ }
  int cmd_config(int argc, const char **argv, const char *prefix)
  {
        int nongit = !startup_info->have_repository;
                check_argc(argc, 1, 2);
                return get_value(argv[0], argv[1]);
        }
+       else if (actions == ACTION_GET_URLMATCH) {
+               check_argc(argc, 2, 2);
+               return get_urlmatch(argv[0], argv[1]);
+       }
        else if (actions == ACTION_UNSET) {
 +              check_blob_write();
                check_argc(argc, 1, 2);
                if (argc == 2)
                        return git_config_set_multivar_in_file(given_config_file,
diff --cc http.c
Simple merge