Skip to content

Commit 0530d7d

Browse files
authored
Merge pull request libgit2#4767 from pks-t/pks/config-mem
In-memory configuration
2 parents ba1cd49 + 2be39ce commit 0530d7d

File tree

14 files changed

+983
-545
lines changed

14 files changed

+983
-545
lines changed

src/config.c

Lines changed: 128 additions & 105 deletions
Large diffs are not rendered by default.

src/config.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
struct git_config {
2626
git_refcount rc;
27-
git_vector files;
27+
git_vector backends;
2828
};
2929

3030
extern int git_config__global_location(git_buf *buf);
@@ -34,19 +34,6 @@ extern int git_config_rename_section(
3434
const char *old_section_name, /* eg "branch.dummy" */
3535
const char *new_section_name); /* NULL to drop the old section */
3636

37-
/**
38-
* Create a configuration file backend for ondisk files
39-
*
40-
* These are the normal `.gitconfig` files that Core Git
41-
* processes. Note that you first have to add this file to a
42-
* configuration object before you can query it for configuration
43-
* variables.
44-
*
45-
* @param out the new backend
46-
* @param path where the config file is located
47-
*/
48-
extern int git_config_file__ondisk(git_config_backend **out, const char *path);
49-
5037
extern int git_config__normalize_name(const char *in, char **out);
5138

5239
/* internal only: does not normalize key and sets out to NULL if not found */

src/config_backend.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_config_file_h__
8+
#define INCLUDE_config_file_h__
9+
10+
#include "common.h"
11+
12+
#include "git2/sys/config.h"
13+
#include "git2/config.h"
14+
15+
/**
16+
* Create a configuration file backend for ondisk files
17+
*
18+
* These are the normal `.gitconfig` files that Core Git
19+
* processes. Note that you first have to add this file to a
20+
* configuration object before you can query it for configuration
21+
* variables.
22+
*
23+
* @param out the new backend
24+
* @param path where the config file is located
25+
*/
26+
extern int git_config_backend_from_file(git_config_backend **out, const char *path);
27+
28+
/**
29+
* Create an in-memory configuration file backend
30+
*
31+
* @param out the new backend
32+
* @param cfg the configuration that is to be parsed
33+
*/
34+
extern int git_config_backend_from_string(git_config_backend **out, const char *cfg);
35+
36+
GIT_INLINE(int) git_config_backend_open(git_config_backend *cfg, unsigned int level, const git_repository *repo)
37+
{
38+
return cfg->open(cfg, level, repo);
39+
}
40+
41+
GIT_INLINE(void) git_config_backend_free(git_config_backend *cfg)
42+
{
43+
if (cfg)
44+
cfg->free(cfg);
45+
}
46+
47+
GIT_INLINE(int) git_config_backend_get_string(
48+
git_config_entry **out, git_config_backend *cfg, const char *name)
49+
{
50+
return cfg->get(cfg, name, out);
51+
}
52+
53+
GIT_INLINE(int) git_config_backend_set_string(
54+
git_config_backend *cfg, const char *name, const char *value)
55+
{
56+
return cfg->set(cfg, name, value);
57+
}
58+
59+
GIT_INLINE(int) git_config_backend_delete(
60+
git_config_backend *cfg, const char *name)
61+
{
62+
return cfg->del(cfg, name);
63+
}
64+
65+
GIT_INLINE(int) git_config_backend_foreach(
66+
git_config_backend *cfg,
67+
int (*fn)(const git_config_entry *entry, void *data),
68+
void *data)
69+
{
70+
return git_config_backend_foreach_match(cfg, NULL, fn, data);
71+
}
72+
73+
GIT_INLINE(int) git_config_backend_lock(git_config_backend *cfg)
74+
{
75+
return cfg->lock(cfg);
76+
}
77+
78+
GIT_INLINE(int) git_config_backend_unlock(git_config_backend *cfg, int success)
79+
{
80+
return cfg->unlock(cfg, success);
81+
}
82+
83+
#endif

src/config_entries.c

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "config_entries.h"
9+
10+
typedef struct config_entry_list {
11+
struct config_entry_list *next;
12+
struct config_entry_list *last;
13+
git_config_entry *entry;
14+
} config_entry_list;
15+
16+
typedef struct config_entries_iterator {
17+
git_config_iterator parent;
18+
git_config_entries *entries;
19+
config_entry_list *head;
20+
} config_entries_iterator;
21+
22+
struct git_config_entries {
23+
git_refcount rc;
24+
git_strmap *map;
25+
config_entry_list *list;
26+
};
27+
28+
static void config_entry_list_free(config_entry_list *list)
29+
{
30+
config_entry_list *next;
31+
32+
while (list != NULL) {
33+
next = list->next;
34+
35+
git__free((char*) list->entry->name);
36+
git__free((char *) list->entry->value);
37+
git__free(list->entry);
38+
git__free(list);
39+
40+
list = next;
41+
};
42+
}
43+
44+
static void config_entry_list_append(config_entry_list **list, config_entry_list *entry)
45+
{
46+
if (*list)
47+
(*list)->last->next = entry;
48+
else
49+
*list = entry;
50+
(*list)->last = entry;
51+
}
52+
53+
int git_config_entries_new(git_config_entries **out)
54+
{
55+
git_config_entries *entries;
56+
int error;
57+
58+
entries = git__calloc(1, sizeof(git_config_entries));
59+
GITERR_CHECK_ALLOC(entries);
60+
GIT_REFCOUNT_INC(entries);
61+
62+
if ((error = git_strmap_alloc(&entries->map)) < 0)
63+
git__free(entries);
64+
else
65+
*out = entries;
66+
67+
return error;
68+
}
69+
70+
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
71+
{
72+
git_config_entries *result = NULL;
73+
config_entry_list *head;
74+
int error;
75+
76+
if ((error = git_config_entries_new(&result)) < 0)
77+
goto out;
78+
79+
for (head = entries->list; head; head = head->next) {
80+
git_config_entry *dup;
81+
82+
dup = git__calloc(1, sizeof(git_config_entry));
83+
dup->name = git__strdup(head->entry->name);
84+
GITERR_CHECK_ALLOC(dup->name);
85+
if (head->entry->value) {
86+
dup->value = git__strdup(head->entry->value);
87+
GITERR_CHECK_ALLOC(dup->value);
88+
}
89+
dup->level = head->entry->level;
90+
dup->include_depth = head->entry->include_depth;
91+
92+
if ((error = git_config_entries_append(result, dup)) < 0)
93+
goto out;
94+
}
95+
96+
*out = result;
97+
result = NULL;
98+
99+
out:
100+
git_config_entries_free(result);
101+
return error;
102+
}
103+
104+
void git_config_entries_incref(git_config_entries *entries)
105+
{
106+
GIT_REFCOUNT_INC(entries);
107+
}
108+
109+
static void config_entries_free(git_config_entries *entries)
110+
{
111+
config_entry_list *list = NULL, *next;
112+
113+
git_strmap_foreach_value(entries->map, list, config_entry_list_free(list));
114+
git_strmap_free(entries->map);
115+
116+
list = entries->list;
117+
while (list != NULL) {
118+
next = list->next;
119+
git__free(list);
120+
list = next;
121+
}
122+
123+
git__free(entries);
124+
}
125+
126+
void git_config_entries_free(git_config_entries *entries)
127+
{
128+
if (entries)
129+
GIT_REFCOUNT_DEC(entries, config_entries_free);
130+
}
131+
132+
int git_config_entries_append(git_config_entries *entries, git_config_entry *entry)
133+
{
134+
git_strmap_iter pos;
135+
config_entry_list *existing, *var;
136+
int error = 0;
137+
138+
var = git__calloc(1, sizeof(config_entry_list));
139+
GITERR_CHECK_ALLOC(var);
140+
var->entry = entry;
141+
142+
pos = git_strmap_lookup_index(entries->map, entry->name);
143+
if (!git_strmap_valid_index(entries->map, pos)) {
144+
/*
145+
* We only ever inspect `last` from the first config
146+
* entry in a multivar. In case where this new entry is
147+
* the first one in the entry map, it will also be the
148+
* last one at the time of adding it, which is
149+
* why we set `last` here to itself. Otherwise we
150+
* do not have to set `last` and leave it set to
151+
* `NULL`.
152+
*/
153+
var->last = var;
154+
155+
git_strmap_insert(entries->map, entry->name, var, &error);
156+
157+
if (error > 0)
158+
error = 0;
159+
} else {
160+
existing = git_strmap_value_at(entries->map, pos);
161+
config_entry_list_append(&existing, var);
162+
}
163+
164+
var = git__calloc(1, sizeof(config_entry_list));
165+
GITERR_CHECK_ALLOC(var);
166+
var->entry = entry;
167+
config_entry_list_append(&entries->list, var);
168+
169+
return error;
170+
}
171+
172+
int config_entry_get(config_entry_list **out, git_config_entries *entries, const char *key)
173+
{
174+
khiter_t pos;
175+
176+
pos = git_strmap_lookup_index(entries->map, key);
177+
178+
/* no error message; the config system will write one */
179+
if (!git_strmap_valid_index(entries->map, pos))
180+
return GIT_ENOTFOUND;
181+
182+
*out = git_strmap_value_at(entries->map, pos);
183+
184+
return 0;
185+
}
186+
187+
int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
188+
{
189+
config_entry_list *entry;
190+
int error;
191+
192+
if ((error = config_entry_get(&entry, entries, key)) < 0)
193+
return error;
194+
*out = entry->last->entry;
195+
196+
return 0;
197+
}
198+
199+
int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key)
200+
{
201+
config_entry_list *entry;
202+
int error;
203+
204+
if ((error = config_entry_get(&entry, entries, key)) < 0)
205+
return error;
206+
207+
if (entry->next != NULL) {
208+
giterr_set(GITERR_CONFIG, "entry is not unique due to being a multivar");
209+
return -1;
210+
}
211+
212+
if (entry->entry->include_depth) {
213+
giterr_set(GITERR_CONFIG, "entry is not unique due to being included");
214+
return -1;
215+
}
216+
217+
*out = entry->entry;
218+
219+
return 0;
220+
}
221+
222+
void config_iterator_free(git_config_iterator *iter)
223+
{
224+
config_entries_iterator *it = (config_entries_iterator *) iter;
225+
git_config_entries_free(it->entries);
226+
git__free(it);
227+
}
228+
229+
int config_iterator_next(
230+
git_config_entry **entry,
231+
git_config_iterator *iter)
232+
{
233+
config_entries_iterator *it = (config_entries_iterator *) iter;
234+
235+
if (!it->head)
236+
return GIT_ITEROVER;
237+
238+
*entry = it->head->entry;
239+
it->head = it->head->next;
240+
241+
return 0;
242+
}
243+
244+
int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries)
245+
{
246+
config_entries_iterator *it;
247+
248+
it = git__calloc(1, sizeof(config_entries_iterator));
249+
GITERR_CHECK_ALLOC(it);
250+
it->parent.next = config_iterator_next;
251+
it->parent.free = config_iterator_free;
252+
it->head = entries->list;
253+
it->entries = entries;
254+
255+
git_config_entries_incref(entries);
256+
*out = &it->parent;
257+
258+
return 0;
259+
}

src/config_entries.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "common.h"
9+
10+
#include "git2/sys/config.h"
11+
#include "config.h"
12+
13+
typedef struct git_config_entries git_config_entries;
14+
15+
int git_config_entries_new(git_config_entries **out);
16+
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries);
17+
void git_config_entries_incref(git_config_entries *entries);
18+
void git_config_entries_free(git_config_entries *entries);
19+
/* Add or append the new config option */
20+
int git_config_entries_append(git_config_entries *entries, git_config_entry *entry);
21+
int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key);
22+
int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key);
23+
int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries);

0 commit comments

Comments
 (0)