Commit d9012202 by Edward Thomson

config: provide origin in git_config_entry

A git_config_entry now knows the type of the origin for the entry
("file", "memory", etc) and the path details (for files, the path on
disk). This is propagated through snapshots.
parent a8cac7ff
......@@ -62,10 +62,26 @@ typedef enum {
* An entry in a configuration file
*/
typedef struct git_config_entry {
const char *name; /**< Name of the entry (normalised) */
const char *value; /**< String value of the entry */
unsigned int include_depth; /**< Depth of includes where this variable was found */
git_config_level_t level; /**< Which config file this was found in */
/** Name of the configuration entry (normalized) */
const char *name;
/** Literal (string) value of the entry */
const char *value;
/** The type of backend that this entry exists in (eg, "file") */
const char *backend_type;
/**
* The path to the origin of this entry. For config files, this is
* the path to the file.
*/
const char *origin_path;
/** Depth of includes where this variable was found */
unsigned int include_depth;
/** Configuration level for the file this was found in */
git_config_level_t level;
/**
* Free function for this entry; for internal purposes. Callers
......
......@@ -24,6 +24,8 @@
/* Max depth for [include] directives */
#define MAX_INCLUDE_DEPTH 10
#define CONFIG_FILE_TYPE "file"
typedef struct config_file {
git_futils_filestamp stamp;
unsigned char checksum[GIT_HASH_SHA256_SIZE];
......@@ -801,7 +803,11 @@ static int read_on_variable(
GIT_ERROR_CHECK_ALLOC(entry->base.value);
}
entry->base.origin_path = git_config_list_add_path(parse_data->config_list, parse_data->file->path);
GIT_ERROR_CHECK_ALLOC(entry->base.origin_path);
entry->base.level = parse_data->level;
entry->base.backend_type = CONFIG_FILE_TYPE;
entry->base.include_depth = parse_data->depth;
entry->base.free = git_config_list_entry_free;
entry->config_list = parse_data->config_list;
......
......@@ -26,6 +26,11 @@ typedef struct config_list_iterator {
struct git_config_list {
git_refcount rc;
/* Paths to config files that contribute to these entries */
git_strmap *paths;
/* Config entries */
git_strmap *map;
config_entry_list *entries;
};
......@@ -33,18 +38,22 @@ struct git_config_list {
int git_config_list_new(git_config_list **out)
{
git_config_list *config_list;
int error;
config_list = git__calloc(1, sizeof(git_config_list));
GIT_ERROR_CHECK_ALLOC(config_list);
GIT_REFCOUNT_INC(config_list);
if ((error = git_strmap_new(&config_list->map)) < 0)
if (git_strmap_new(&config_list->paths) < 0 ||
git_strmap_new(&config_list->map) < 0) {
git_strmap_free(config_list->paths);
git_strmap_free(config_list->map);
git__free(config_list);
else
*out = config_list;
return error;
return -1;
}
*out = config_list;
return 0;
}
int git_config_list_dup_entry(git_config_list *config_list, const git_config_entry *entry)
......@@ -63,6 +72,12 @@ int git_config_list_dup_entry(git_config_list *config_list, const git_config_ent
GIT_ERROR_CHECK_ALLOC(duplicated->base.value);
}
if (entry->origin_path) {
duplicated->base.origin_path = git_config_list_add_path(config_list, entry->origin_path);
GIT_ERROR_CHECK_ALLOC(duplicated->base.origin_path);
}
duplicated->base.backend_type = entry->backend_type;
duplicated->base.level = entry->level;
duplicated->base.include_depth = entry->include_depth;
duplicated->base.free = git_config_list_entry_free;
......@@ -110,6 +125,12 @@ static void config_list_free(git_config_list *config_list)
{
config_entry_list *entry_list = NULL, *next;
config_entry_map_head *head;
char *path;
git_strmap_foreach_value(config_list->paths, path, {
git__free(path);
});
git_strmap_free(config_list->paths);
git_strmap_foreach_value(config_list->map, head, {
git__free((char *) head->entry->base.name);
......@@ -247,3 +268,19 @@ void git_config_list_entry_free(git_config_entry *e)
git_config_list_entry *entry = (git_config_list_entry *)e;
git_config_list_free(entry->config_list);
}
const char *git_config_list_add_path(
git_config_list *config_list,
const char *path)
{
const char *p;
if ((p = git_strmap_get(config_list->paths, path)) != NULL)
return p;
if ((p = git__strdup(path)) == NULL ||
git_strmap_set(config_list->paths, p, (void *)p) < 0)
return NULL;
return p;
}
......@@ -27,5 +27,6 @@ int git_config_list_append(git_config_list *list, git_config_list_entry *entry);
int git_config_list_get(git_config_list_entry **out, git_config_list *list, const char *key);
int git_config_list_get_unique(git_config_list_entry **out, git_config_list *list, const char *key);
int git_config_list_iterator_new(git_config_iterator **out, git_config_list *list);
const char *git_config_list_add_path(git_config_list *list, const char *path);
void git_config_list_entry_free(git_config_entry *entry);
......@@ -68,6 +68,7 @@ static int read_variable_cb(
entry->base.value = var_value ? git__strdup(var_value) : NULL;
entry->base.level = parse_data->level;
entry->base.include_depth = 0;
entry->base.backend_type = "memory";
entry->base.free = git_config_list_entry_free;
entry->config_list = parse_data->config_list;
......
......@@ -495,6 +495,8 @@ void test_config_read__read_git_config_entry(void)
cl_assert_equal_s("core.dummy2", entry->name);
cl_assert_equal_s("42", entry->value);
cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level);
cl_assert_equal_s("file", entry->backend_type);
cl_assert_equal_s(cl_fixture("config/config9"), entry->origin_path);
git_config_entry_free(entry);
git_config_free(cfg);
......
......@@ -79,6 +79,7 @@ void test_config_snapshot__multivar(void)
void test_config_snapshot__includes(void)
{
git_config_entry *entry;
int i;
cl_git_mkfile("including", "[include]\npath = included");
......@@ -99,6 +100,16 @@ void test_config_snapshot__includes(void)
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
/* Ensure that the config entry is populated with origin */
cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key"));
cl_assert_equal_s("section.key", entry->name);
cl_assert_equal_s("1", entry->value);
cl_assert_equal_s("file", entry->backend_type);
cl_assert_equal_s("./included", entry->origin_path);
git_config_entry_free(entry);
cl_git_pass(p_unlink("including"));
cl_git_pass(p_unlink("included"));
}
......@@ -106,6 +117,7 @@ void test_config_snapshot__includes(void)
void test_config_snapshot__snapshot(void)
{
git_config *snapshot_snapshot;
git_config_entry *entry;
int i;
cl_git_mkfile("configfile", "[section]\nkey = 1\n");
......@@ -118,15 +130,26 @@ void test_config_snapshot__snapshot(void)
cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key"));
cl_assert_equal_i(i, 1);
/* Ensure that the config entry is populated with origin */
cl_git_pass(git_config_get_entry(&entry, snapshot_snapshot, "section.key"));
cl_assert_equal_s("section.key", entry->name);
cl_assert_equal_s("1", entry->value);
cl_assert_equal_s("file", entry->backend_type);
cl_assert_equal_s("configfile", entry->origin_path);
git_config_entry_free(entry);
git_config_free(snapshot_snapshot);
cl_git_pass(p_unlink("configfile"));
}
void test_config_snapshot__snapshot_from_in_memony(void)
void test_config_snapshot__snapshot_from_in_memory(void)
{
const char *configuration = "[section]\nkey = 1\n";
git_config_backend *backend;
git_config_entry *entry;
int i;
cl_git_pass(git_config_new(&cfg));
......@@ -136,4 +159,14 @@ void test_config_snapshot__snapshot_from_in_memony(void)
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
/* Ensure that the config entry is populated with origin */
cl_git_pass(git_config_get_entry(&entry, snapshot, "section.key"));
cl_assert_equal_s("section.key", entry->name);
cl_assert_equal_s("1", entry->value);
cl_assert_equal_s("memory", entry->backend_type);
cl_assert_equal_p(NULL, entry->origin_path);
git_config_entry_free(entry);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment