1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-21 02:16:12 +02:00

config: read config from a repository object

Teach the config machinery to read config information from a repository
object.  This involves storing a 'struct config_set' inside the
repository object and adding a number of functions (repo_config*) to be
able to query a repository's config.

The current config API enables lazy-loading of the config.  This means
that when 'git_config_get_int()' is called, if the_config_set hasn't
been populated yet, then it will be populated and properly initialized by
reading the necessary config files (system wide .gitconfig, user's home
.gitconfig, and the repository's config).  To maintain this paradigm,
the new API to read from a repository object's config will also perform
this lazy-initialization.

Since both APIs (git_config_get* and repo_config_get*) have the same
semantics we can migrate the default config to be stored within
'the_repository' and just have the 'git_config_get*' family of functions
redirect to the 'repo_config_get*' functions.

Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Brandon Williams 2017-06-22 11:43:42 -07:00 committed by Junio C Hamano
parent b42b0c0919
commit 3b256228a6
4 changed files with 184 additions and 75 deletions

218
config.c
View File

@ -7,6 +7,7 @@
*/
#include "cache.h"
#include "config.h"
#include "repository.h"
#include "lockfile.h"
#include "exec_cmd.h"
#include "strbuf.h"
@ -72,13 +73,6 @@ static int core_compression_seen;
static int pack_compression_seen;
static int zlib_compression_seen;
/*
* Default config_set that contains key-value pairs from the usual set of config
* config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
* config file and the global /etc/gitconfig)
*/
static struct config_set the_config_set;
static int config_file_fgetc(struct config_source *conf)
{
return getc_unlocked(conf->u.file);
@ -1605,31 +1599,6 @@ int config_with_options(config_fn_t fn, void *data,
return do_git_config_sequence(opts, fn, data);
}
static void git_config_raw(config_fn_t fn, void *data)
{
struct config_options opts = {0};
opts.respect_includes = 1;
if (have_git_dir()) {
opts.commondir = get_git_common_dir();
opts.git_dir = get_git_dir();
}
if (config_with_options(fn, data, NULL, &opts) < 0)
/*
* config_with_options() normally returns only
* zero, as most errors are fatal, and
* non-fatal potential errors are guarded by "if"
* statements that are entered only when no error is
* possible.
*
* If we ever encounter a non-fatal error, it means
* something went really wrong and we should stop
* immediately.
*/
die(_("unknown error occurred while reading the configuration files"));
}
static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
{
int i, value_index;
@ -1683,14 +1652,6 @@ void read_early_config(config_fn_t cb, void *data)
strbuf_release(&gitdir);
}
static void git_config_check_init(void);
void git_config(config_fn_t fn, void *data)
{
git_config_check_init();
configset_iter(&the_config_set, fn, data);
}
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
{
struct config_set_element k;
@ -1900,87 +1861,194 @@ int git_configset_get_pathname(struct config_set *cs, const char *key, const cha
return 1;
}
static void git_config_check_init(void)
/* Functions use to read configuration from a repository */
static void repo_read_config(struct repository *repo)
{
if (the_config_set.hash_initialized)
struct config_options opts;
opts.respect_includes = 1;
opts.commondir = repo->commondir;
opts.git_dir = repo->gitdir;
if (!repo->config)
repo->config = xcalloc(1, sizeof(struct config_set));
else
git_configset_clear(repo->config);
git_configset_init(repo->config);
if (config_with_options(config_set_callback, repo->config, NULL, &opts) < 0)
/*
* config_with_options() normally returns only
* zero, as most errors are fatal, and
* non-fatal potential errors are guarded by "if"
* statements that are entered only when no error is
* possible.
*
* If we ever encounter a non-fatal error, it means
* something went really wrong and we should stop
* immediately.
*/
die(_("unknown error occurred while reading the configuration files"));
}
static void git_config_check_init(struct repository *repo)
{
if (repo->config && repo->config->hash_initialized)
return;
git_configset_init(&the_config_set);
git_config_raw(config_set_callback, &the_config_set);
repo_read_config(repo);
}
static void repo_config_clear(struct repository *repo)
{
if (!repo->config || !repo->config->hash_initialized)
return;
git_configset_clear(repo->config);
}
void repo_config(struct repository *repo, config_fn_t fn, void *data)
{
git_config_check_init(repo);
configset_iter(repo->config, fn, data);
}
int repo_config_get_value(struct repository *repo,
const char *key, const char **value)
{
git_config_check_init(repo);
return git_configset_get_value(repo->config, key, value);
}
const struct string_list *repo_config_get_value_multi(struct repository *repo,
const char *key)
{
git_config_check_init(repo);
return git_configset_get_value_multi(repo->config, key);
}
int repo_config_get_string_const(struct repository *repo,
const char *key, const char **dest)
{
int ret;
git_config_check_init(repo);
ret = git_configset_get_string_const(repo->config, key, dest);
if (ret < 0)
git_die_config(key, NULL);
return ret;
}
int repo_config_get_string(struct repository *repo,
const char *key, char **dest)
{
git_config_check_init(repo);
return repo_config_get_string_const(repo, key, (const char **)dest);
}
int repo_config_get_int(struct repository *repo,
const char *key, int *dest)
{
git_config_check_init(repo);
return git_configset_get_int(repo->config, key, dest);
}
int repo_config_get_ulong(struct repository *repo,
const char *key, unsigned long *dest)
{
git_config_check_init(repo);
return git_configset_get_ulong(repo->config, key, dest);
}
int repo_config_get_bool(struct repository *repo,
const char *key, int *dest)
{
git_config_check_init(repo);
return git_configset_get_bool(repo->config, key, dest);
}
int repo_config_get_bool_or_int(struct repository *repo,
const char *key, int *is_bool, int *dest)
{
git_config_check_init(repo);
return git_configset_get_bool_or_int(repo->config, key, is_bool, dest);
}
int repo_config_get_maybe_bool(struct repository *repo,
const char *key, int *dest)
{
git_config_check_init(repo);
return git_configset_get_maybe_bool(repo->config, key, dest);
}
int repo_config_get_pathname(struct repository *repo,
const char *key, const char **dest)
{
int ret;
git_config_check_init(repo);
ret = git_configset_get_pathname(repo->config, key, dest);
if (ret < 0)
git_die_config(key, NULL);
return ret;
}
/* Functions used historically to read configuration from 'the_repository' */
void git_config(config_fn_t fn, void *data)
{
repo_config(the_repository, fn, data);
}
void git_config_clear(void)
{
if (!the_config_set.hash_initialized)
return;
git_configset_clear(&the_config_set);
repo_config_clear(the_repository);
}
int git_config_get_value(const char *key, const char **value)
{
git_config_check_init();
return git_configset_get_value(&the_config_set, key, value);
return repo_config_get_value(the_repository, key, value);
}
const struct string_list *git_config_get_value_multi(const char *key)
{
git_config_check_init();
return git_configset_get_value_multi(&the_config_set, key);
return repo_config_get_value_multi(the_repository, key);
}
int git_config_get_string_const(const char *key, const char **dest)
{
int ret;
git_config_check_init();
ret = git_configset_get_string_const(&the_config_set, key, dest);
if (ret < 0)
git_die_config(key, NULL);
return ret;
return repo_config_get_string_const(the_repository, key, dest);
}
int git_config_get_string(const char *key, char **dest)
{
git_config_check_init();
return git_config_get_string_const(key, (const char **)dest);
return repo_config_get_string(the_repository, key, dest);
}
int git_config_get_int(const char *key, int *dest)
{
git_config_check_init();
return git_configset_get_int(&the_config_set, key, dest);
return repo_config_get_int(the_repository, key, dest);
}
int git_config_get_ulong(const char *key, unsigned long *dest)
{
git_config_check_init();
return git_configset_get_ulong(&the_config_set, key, dest);
return repo_config_get_ulong(the_repository, key, dest);
}
int git_config_get_bool(const char *key, int *dest)
{
git_config_check_init();
return git_configset_get_bool(&the_config_set, key, dest);
return repo_config_get_bool(the_repository, key, dest);
}
int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
{
git_config_check_init();
return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);
return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
}
int git_config_get_maybe_bool(const char *key, int *dest)
{
git_config_check_init();
return git_configset_get_maybe_bool(&the_config_set, key, dest);
return repo_config_get_maybe_bool(the_repository, key, dest);
}
int git_config_get_pathname(const char *key, const char **dest)
{
int ret;
git_config_check_init();
ret = git_configset_get_pathname(&the_config_set, key, dest);
if (ret < 0)
git_die_config(key, NULL);
return ret;
return repo_config_get_pathname(the_repository, key, dest);
}
int git_config_get_expiry(const char *key, const char **output)

View File

@ -163,6 +163,30 @@ extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
/* Functions for reading a repository's config */
struct repository;
extern void repo_config(struct repository *repo, config_fn_t fn, void *data);
extern int repo_config_get_value(struct repository *repo,
const char *key, const char **value);
extern const struct string_list *repo_config_get_value_multi(struct repository *repo,
const char *key);
extern int repo_config_get_string_const(struct repository *repo,
const char *key, const char **dest);
extern int repo_config_get_string(struct repository *repo,
const char *key, char **dest);
extern int repo_config_get_int(struct repository *repo,
const char *key, int *dest);
extern int repo_config_get_ulong(struct repository *repo,
const char *key, unsigned long *dest);
extern int repo_config_get_bool(struct repository *repo,
const char *key, int *dest);
extern int repo_config_get_bool_or_int(struct repository *repo,
const char *key, int *is_bool, int *dest);
extern int repo_config_get_maybe_bool(struct repository *repo,
const char *key, int *dest);
extern int repo_config_get_pathname(struct repository *repo,
const char *key, const char **dest);
extern int git_config_get_value(const char *key, const char **value);
extern const struct string_list *git_config_get_value_multi(const char *key);
extern void git_config_clear(void);

View File

@ -1,5 +1,6 @@
#include "cache.h"
#include "repository.h"
#include "config.h"
/* The main repository */
static struct repository the_repo;
@ -156,4 +157,10 @@ void repo_clear(struct repository *repo)
repo->index_file = NULL;
free(repo->worktree);
repo->worktree = NULL;
if (repo->config) {
git_configset_clear(repo->config);
free(repo->config);
repo->config = NULL;
}
}

View File

@ -1,6 +1,8 @@
#ifndef REPOSITORY_H
#define REPOSITORY_H
struct config_set;
struct repository {
/* Environment */
/*
@ -39,6 +41,14 @@ struct repository {
*/
char *worktree;
/* Subsystems */
/*
* Repository's config which contains key-value pairs from the usual
* set of config files (i.e. repo specific .git/config, user wide
* ~/.gitconfig, XDG config file and the global /etc/gitconfig)
*/
struct config_set *config;
/* Configurations */
/*
* Bit used during initialization to indicate if repository state (like