Merge branch 'jk/config-blob-sans-repo'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:27 +0000 (21:51 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:27 +0000 (21:51 +0900)
Error codepath fix.

* jk/config-blob-sans-repo:
config: die when --blob is used outside a repository

1  2 
builtin/config.c
diff --combined builtin/config.c
index 1e31aa9f8d98ffa6790ba2c6023634841b1abf74,d00439769ea7a6e9b62f0e1e61c370ff064c9baf..b29d26dede79b9a5c46bdc4f951b22e7b88310b3
@@@ -25,8 -25,7 +25,8 @@@ static char term = '\n'
  
  static int use_global_config, use_system_config, use_local_config;
  static struct git_config_source given_config_source;
 -static int actions, types;
 +static int actions, type;
 +static char *default_value;
  static int end_null;
  static int respect_includes_opt = -1;
  static struct config_options config_options;
@@@ -56,68 -55,11 +56,68 @@@ static int show_origin
  #define PAGING_ACTIONS (ACTION_LIST | ACTION_GET_ALL | \
                        ACTION_GET_REGEXP | ACTION_GET_URLMATCH)
  
 -#define TYPE_BOOL (1<<0)
 -#define TYPE_INT (1<<1)
 -#define TYPE_BOOL_OR_INT (1<<2)
 -#define TYPE_PATH (1<<3)
 -#define TYPE_EXPIRY_DATE (1<<4)
 +#define TYPE_BOOL             1
 +#define TYPE_INT              2
 +#define TYPE_BOOL_OR_INT      3
 +#define TYPE_PATH             4
 +#define TYPE_EXPIRY_DATE      5
 +#define TYPE_COLOR            6
 +
 +#define OPT_CALLBACK_VALUE(s, l, v, h, i) \
 +      { OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
 +      PARSE_OPT_NONEG, option_parse_type, (i) }
 +
 +static struct option builtin_config_options[];
 +
 +static int option_parse_type(const struct option *opt, const char *arg,
 +                           int unset)
 +{
 +      int new_type, *to_type;
 +
 +      if (unset) {
 +              *((int *) opt->value) = 0;
 +              return 0;
 +      }
 +
 +      /*
 +       * To support '--<type>' style flags, begin with new_type equal to
 +       * opt->defval.
 +       */
 +      new_type = opt->defval;
 +      if (!new_type) {
 +              if (!strcmp(arg, "bool"))
 +                      new_type = TYPE_BOOL;
 +              else if (!strcmp(arg, "int"))
 +                      new_type = TYPE_INT;
 +              else if (!strcmp(arg, "bool-or-int"))
 +                      new_type = TYPE_BOOL_OR_INT;
 +              else if (!strcmp(arg, "path"))
 +                      new_type = TYPE_PATH;
 +              else if (!strcmp(arg, "expiry-date"))
 +                      new_type = TYPE_EXPIRY_DATE;
 +              else if (!strcmp(arg, "color"))
 +                      new_type = TYPE_COLOR;
 +              else
 +                      die(_("unrecognized --type argument, %s"), arg);
 +      }
 +
 +      to_type = opt->value;
 +      if (*to_type && *to_type != new_type) {
 +              /*
 +               * Complain when there is a new type not equal to the old type.
 +               * This allows for combinations like '--int --type=int' and
 +               * '--type=int --type=int', but disallows ones like '--type=bool
 +               * --int' and '--type=bool
 +               * --type=int'.
 +               */
 +              error("only one type at a time.");
 +              usage_with_options(builtin_config_usage,
 +                      builtin_config_options);
 +      }
 +      *to_type = new_type;
 +
 +      return 0;
 +}
  
  static struct option builtin_config_options[] = {
        OPT_GROUP(N_("Config file location")),
        OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
        OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
        OPT_GROUP(N_("Type")),
 -      OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
 -      OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
 -      OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
 -      OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
 -      OPT_BIT(0, "expiry-date", &types, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
 +      OPT_CALLBACK('t', "type", &type, "", N_("value is given this type"), option_parse_type),
 +      OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
 +      OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
 +      OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
 +      OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
 +      OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
        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_opt, 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_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
        OPT_END(),
  };
  
@@@ -209,35 -149,30 +209,35 @@@ static int format_config(struct strbuf 
                if (show_keys)
                        strbuf_addch(buf, key_delim);
  
 -              if (types == TYPE_INT)
 +              if (type == TYPE_INT)
                        strbuf_addf(buf, "%"PRId64,
                                    git_config_int64(key_, value_ ? value_ : ""));
 -              else if (types == TYPE_BOOL)
 +              else if (type == TYPE_BOOL)
                        strbuf_addstr(buf, git_config_bool(key_, value_) ?
                                      "true" : "false");
 -              else if (types == TYPE_BOOL_OR_INT) {
 +              else if (type == 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) {
 +              } else if (type == TYPE_PATH) {
                        const char *v;
                        if (git_config_pathname(&v, key_, value_) < 0)
                                return -1;
                        strbuf_addstr(buf, v);
                        free((char *)v);
 -              } else if (types == TYPE_EXPIRY_DATE) {
 +              } else if (type == TYPE_EXPIRY_DATE) {
                        timestamp_t t;
                        if (git_config_expiry_date(&t, key_, value_) < 0)
                                return -1;
                        strbuf_addf(buf, "%"PRItime, t);
 +              } else if (type == TYPE_COLOR) {
 +                      char v[COLOR_MAXLEN];
 +                      if (git_config_color(v, key_, value_) < 0)
 +                              return -1;
 +                      strbuf_addstr(buf, v);
                } else if (value_) {
                        strbuf_addstr(buf, value_);
                } else {
@@@ -323,16 -258,6 +323,16 @@@ static int get_value(const char *key_, 
        config_with_options(collect_config, &values,
                            &given_config_source, &config_options);
  
 +      if (!values.nr && default_value) {
 +              struct strbuf *item;
 +              ALLOC_GROW(values.items, values.nr + 1, values.alloc);
 +              item = &values.items[values.nr++];
 +              strbuf_init(item, 0);
 +              if (format_config(item, key_, default_value) < 0)
 +                      die(_("failed to format default config value: %s"),
 +                              default_value);
 +      }
 +
        ret = !values.nr;
  
        for (i = 0; i < values.nr; i++) {
@@@ -362,7 -287,7 +362,7 @@@ static char *normalize_value(const cha
        if (!value)
                return NULL;
  
 -      if (types == 0 || types == TYPE_PATH || types == TYPE_EXPIRY_DATE)
 +      if (type == 0 || type == TYPE_PATH || type == TYPE_EXPIRY_DATE)
                /*
                 * We don't do normalization for TYPE_PATH here: If
                 * the path is like ~/foobar/, we prefer to store
                 * Also don't do normalization for expiry dates.
                 */
                return xstrdup(value);
 -      if (types == TYPE_INT)
 +      if (type == TYPE_INT)
                return xstrfmt("%"PRId64, git_config_int64(key, value));
 -      if (types == TYPE_BOOL)
 +      if (type == TYPE_BOOL)
                return xstrdup(git_config_bool(key, value) ?  "true" : "false");
 -      if (types == TYPE_BOOL_OR_INT) {
 +      if (type == TYPE_BOOL_OR_INT) {
                int is_bool, v;
                v = git_config_bool_or_int(key, value, &is_bool);
                if (!is_bool)
                else
                        return xstrdup(v ? "true" : "false");
        }
 +      if (type == TYPE_COLOR) {
 +              char v[COLOR_MAXLEN];
 +              if (git_config_color(v, key, value))
 +                      die("cannot parse color '%s'", value);
 +
 +              /*
 +               * The contents of `v` now contain an ANSI escape
 +               * sequence, not suitable for including within a
 +               * configuration file. Treat the above as a
 +               * "sanity-check", and return the given value, which we
 +               * know is representable as valid color code.
 +               */
 +              return xstrdup(value);
 +      }
  
 -      die("BUG: cannot normalize type %d", types);
 +      BUG("cannot normalize type %d", type);
  }
  
  static int get_color_found;
@@@ -602,6 -513,9 +602,9 @@@ int cmd_config(int argc, const char **a
        if (use_local_config && nongit)
                die(_("--local can only be used inside a git repository"));
  
+       if (given_config_source.blob && nongit)
+               die(_("--blob can only be used inside a git repository"));
        if (given_config_source.file &&
                        !strcmp(given_config_source.file, "-")) {
                given_config_source.file = NULL;
                key_delim = '\n';
        }
  
 -      if (HAS_MULTI_BITS(types)) {
 -              error("only one type at a time.");
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 -      }
 -
 -      if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && types) {
 +      if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
                error("--get-color and variable type are incoherent");
                usage_with_options(builtin_config_usage, builtin_config_options);
        }
                usage_with_options(builtin_config_usage, builtin_config_options);
        }
  
 +      if (default_value && !(actions & ACTION_GET)) {
 +              error("--default is only applicable to --get");
 +              usage_with_options(builtin_config_usage,
 +                      builtin_config_options);
 +      }
 +
        if (actions & PAGING_ACTIONS)
                setup_auto_pager("config", 1);