Skip to content

Commit

Permalink
config: read config from a repository object
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bmwill authored and gitster committed Jun 24, 2017
1 parent b42b0c0 commit 3b25622
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 74 deletions.
216 changes: 142 additions & 74 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
#include "cache.h"
#include "config.h"
#include "repository.h"
#include "lockfile.h"
#include "exec_cmd.h"
#include "strbuf.h"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

void git_config_clear(void)
static void repo_config_clear(struct repository *repo)
{
if (!the_config_set.hash_initialized)
if (!repo->config || !repo->config->hash_initialized)
return;
git_configset_clear(&the_config_set);
git_configset_clear(repo->config);
}

int git_config_get_value(const char *key, const char **value)
void repo_config(struct repository *repo, config_fn_t fn, void *data)
{
git_config_check_init();
return git_configset_get_value(&the_config_set, key, value);
git_config_check_init(repo);
configset_iter(repo->config, fn, data);
}

const struct string_list *git_config_get_value_multi(const char *key)
int repo_config_get_value(struct repository *repo,
const char *key, const char **value)
{
git_config_check_init();
return git_configset_get_value_multi(&the_config_set, key);
git_config_check_init(repo);
return git_configset_get_value(repo->config, key, value);
}

int git_config_get_string_const(const char *key, const char **dest)
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();
ret = git_configset_get_string_const(&the_config_set, key, dest);
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)
{
repo_config_clear(the_repository);
}

int git_config_get_value(const char *key, const char **value)
{
return repo_config_get_value(the_repository, key, value);
}

const struct string_list *git_config_get_value_multi(const char *key)
{
return repo_config_get_value_multi(the_repository, key);
}

int git_config_get_string_const(const char *key, const char **dest)
{
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)
Expand Down
24 changes: 24 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions repository.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "cache.h"
#include "repository.h"
#include "config.h"

/* The main repository */
static struct repository the_repo;
Expand Down Expand Up @@ -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;
}
}
10 changes: 10 additions & 0 deletions repository.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef REPOSITORY_H
#define REPOSITORY_H

struct config_set;

struct repository {
/* Environment */
/*
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3b25622

Please sign in to comment.