mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 03:15:46 +00:00
Implement setting multivars
This commit is contained in:
parent
5e0dc4af01
commit
3005855f7e
@ -31,6 +31,7 @@ struct git_config_file {
|
|||||||
int (*get)(struct git_config_file *, const char *key, const char **value);
|
int (*get)(struct git_config_file *, const char *key, const char **value);
|
||||||
int (*get_multivar)(struct git_config_file *, const char *key, const char *regexp, int (*fn)(const char *, void *), void *data);
|
int (*get_multivar)(struct git_config_file *, const char *key, const char *regexp, int (*fn)(const char *, void *), void *data);
|
||||||
int (*set)(struct git_config_file *, const char *key, const char *value);
|
int (*set)(struct git_config_file *, const char *key, const char *value);
|
||||||
|
int (*set_multivar)(git_config_file *cfg, const char *name, const char *regexp, const char *value);
|
||||||
int (*del)(struct git_config_file *, const char *key);
|
int (*del)(struct git_config_file *, const char *key);
|
||||||
int (*foreach)(struct git_config_file *, int (*fn)(const char *, const char *, void *), void *data);
|
int (*foreach)(struct git_config_file *, int (*fn)(const char *, const char *, void *), void *data);
|
||||||
void (*free)(struct git_config_file *);
|
void (*free)(struct git_config_file *);
|
||||||
@ -255,6 +256,12 @@ GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value);
|
GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a multivar
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a config variable
|
* Delete a config variable
|
||||||
*
|
*
|
||||||
|
18
src/config.c
18
src/config.c
@ -364,6 +364,24 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex
|
|||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
|
||||||
|
{
|
||||||
|
file_internal *internal;
|
||||||
|
git_config_file *file;
|
||||||
|
int error = GIT_ENOTFOUND;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = cfg->files.length; i > 0; --i) {
|
||||||
|
internal = git_vector_get(&cfg->files, i - 1);
|
||||||
|
file = internal->file;
|
||||||
|
error = file->set_multivar(file, name, regexp, value);
|
||||||
|
if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
|
||||||
|
git__rethrow(error, "Failed to replace multivar");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int git_config_find_global_r(git_buf *path)
|
int git_config_find_global_r(git_buf *path)
|
||||||
{
|
{
|
||||||
return git_futils_find_global_file(path, GIT_CONFIG_FILENAME);
|
return git_futils_find_global_file(path, GIT_CONFIG_FILENAME);
|
||||||
|
@ -84,7 +84,7 @@ typedef struct {
|
|||||||
|
|
||||||
static int config_parse(diskfile_backend *cfg_file);
|
static int config_parse(diskfile_backend *cfg_file);
|
||||||
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
||||||
static int config_write(diskfile_backend *cfg, const char *key, const char *value);
|
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
|
||||||
|
|
||||||
static void cvar_free(cvar_t *var)
|
static void cvar_free(cvar_t *var)
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
|||||||
git__free(existing->value);
|
git__free(existing->value);
|
||||||
existing->value = tmp;
|
existing->value = tmp;
|
||||||
|
|
||||||
return config_write(b, existing->key, value);
|
return config_write(b, existing->key, NULL, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var = git__malloc(sizeof(cvar_t));
|
var = git__malloc(sizeof(cvar_t));
|
||||||
@ -263,7 +263,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
|
|||||||
|
|
||||||
cvar_free(old_value);
|
cvar_free(old_value);
|
||||||
|
|
||||||
error = config_write(b, key, value);
|
error = config_write(b, key, NULL, value);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
@ -314,7 +314,7 @@ static int config_get_multivar(git_config_file *cfg, const char *name, const cha
|
|||||||
return git__throw(GIT_ENOTFOUND, "Variable '%s' not found", name);
|
return git__throw(GIT_ENOTFOUND, "Variable '%s' not found", name);
|
||||||
|
|
||||||
if (regexp != NULL) {
|
if (regexp != NULL) {
|
||||||
error = regcomp(&preg, regexp, 0);
|
error = regcomp(&preg, regexp, REG_EXTENDED);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return git__throw(GIT_EINVALIDARGS, "Failed to compile regex");
|
return git__throw(GIT_EINVALIDARGS, "Failed to compile regex");
|
||||||
}
|
}
|
||||||
@ -335,6 +335,88 @@ static int config_get_multivar(git_config_file *cfg, const char *name, const cha
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int config_set_multivar(git_config_file *cfg, const char *name, const char *regexp, const char *value)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
cvar_t *var;
|
||||||
|
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||||
|
char *key;
|
||||||
|
regex_t preg;
|
||||||
|
|
||||||
|
if (regexp == NULL)
|
||||||
|
return git__throw(GIT_EINVALIDARGS, "No regex supplied");
|
||||||
|
|
||||||
|
if ((error = normalize_name(name, &key)) < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
var = git_hashtable_lookup(b->values, key);
|
||||||
|
free(key);
|
||||||
|
|
||||||
|
if (var == NULL)
|
||||||
|
return git__throw(GIT_ENOTFOUND, "Variable '%s' not found", name);
|
||||||
|
|
||||||
|
error = regcomp(&preg, regexp, REG_EXTENDED);
|
||||||
|
if (error < 0)
|
||||||
|
return git__throw(GIT_EINVALIDARGS, "Failed to compile regex");
|
||||||
|
|
||||||
|
|
||||||
|
/* "^$" means we need to addd */
|
||||||
|
if (!regexec(&preg, "", 0, NULL, 0)) {
|
||||||
|
cvar_t *newvar = git__malloc(sizeof(cvar_t));
|
||||||
|
if (newvar == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(newvar, 0x0, sizeof(cvar_t));
|
||||||
|
newvar->key = git__strdup(var->key);
|
||||||
|
if (newvar->key == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
newvar->value = git__strdup(value);
|
||||||
|
if (newvar->value == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (var->next != NULL) {
|
||||||
|
var = var->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->next = newvar;
|
||||||
|
error = config_write(b, var->key, &preg, value);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
error = git__rethrow(error, "Failed to update value in file");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!regexec(&preg, var->value, 0, NULL, 0)) {
|
||||||
|
char *tmp = git__strdup(value);
|
||||||
|
if (tmp == NULL) {
|
||||||
|
error = GIT_ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(var->value);
|
||||||
|
var->value = tmp;
|
||||||
|
error = config_write(b, var->key, &preg, var->value);
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
error = git__rethrow(error, "Failed to update value in file");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var = var->next;
|
||||||
|
} while (var != NULL);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
regfree(&preg);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
static int config_delete(git_config_file *cfg, const char *name)
|
static int config_delete(git_config_file *cfg, const char *name)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@ -359,7 +441,7 @@ static int config_delete(git_config_file *cfg, const char *name)
|
|||||||
if ((error = git_hashtable_remove2(b->values, var->key, (void **)&old_value)) < GIT_SUCCESS)
|
if ((error = git_hashtable_remove2(b->values, var->key, (void **)&old_value)) < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to remove %s from hashtable", key);
|
return git__rethrow(error, "Failed to remove %s from hashtable", key);
|
||||||
|
|
||||||
error = config_write(b, var->key, NULL);
|
error = config_write(b, var->key, NULL, NULL);
|
||||||
cvar_free(old_value);
|
cvar_free(old_value);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -385,6 +467,7 @@ int git_config_file__ondisk(git_config_file **out, const char *path)
|
|||||||
backend->parent.get = config_get;
|
backend->parent.get = config_get;
|
||||||
backend->parent.get_multivar = config_get_multivar;
|
backend->parent.get_multivar = config_get_multivar;
|
||||||
backend->parent.set = config_set;
|
backend->parent.set = config_set;
|
||||||
|
backend->parent.set_multivar = config_set_multivar;
|
||||||
backend->parent.del = config_delete;
|
backend->parent.del = config_delete;
|
||||||
backend->parent.foreach = file_foreach;
|
backend->parent.foreach = file_foreach;
|
||||||
backend->parent.free = backend_free;
|
backend->parent.free = backend_free;
|
||||||
@ -874,7 +957,7 @@ static int write_section(git_filebuf *file, const char *key)
|
|||||||
/*
|
/*
|
||||||
* This is pretty much the parsing, except we write out anything we don't have
|
* This is pretty much the parsing, except we write out anything we don't have
|
||||||
*/
|
*/
|
||||||
static int config_write(diskfile_backend *cfg, const char *key, const char* value)
|
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char* value)
|
||||||
{
|
{
|
||||||
int error = GIT_SUCCESS, c;
|
int error = GIT_SUCCESS, c;
|
||||||
int section_matches = 0, last_section_matched = 0;
|
int section_matches = 0, last_section_matched = 0;
|
||||||
@ -960,6 +1043,10 @@ static int config_write(diskfile_backend *cfg, const char *key, const char* valu
|
|||||||
if (!last_section_matched) {
|
if (!last_section_matched) {
|
||||||
cfg_consume_line(cfg);
|
cfg_consume_line(cfg);
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
/* As a last attempt, if we were given "^$", we should add it */
|
||||||
|
if (preg != NULL && regexec(preg, "", 0, NULL, 0))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int cmp = -1;
|
int cmp = -1;
|
||||||
@ -968,6 +1055,9 @@ static int config_write(diskfile_backend *cfg, const char *key, const char* valu
|
|||||||
if ((error = parse_variable(cfg, &var_name, &var_value)) == GIT_SUCCESS)
|
if ((error = parse_variable(cfg, &var_name, &var_value)) == GIT_SUCCESS)
|
||||||
cmp = strcasecmp(name, var_name);
|
cmp = strcasecmp(name, var_name);
|
||||||
|
|
||||||
|
if (preg != NULL)
|
||||||
|
cmp = regexec(preg, var_value, 0, NULL, 0);
|
||||||
|
|
||||||
git__free(var_name);
|
git__free(var_name);
|
||||||
git__free(var_value);
|
git__free(var_value);
|
||||||
|
|
||||||
@ -1034,8 +1124,10 @@ static int config_write(diskfile_backend *cfg, const char *key, const char* valu
|
|||||||
|
|
||||||
/* And now if we just need to add a variable */
|
/* And now if we just need to add a variable */
|
||||||
if (section_matches) {
|
if (section_matches) {
|
||||||
error = git_filebuf_printf(&file, "\t%s = %s\n", name, value);
|
if (preg == NULL || !regexec(preg, "", 0, NULL, 0)) {
|
||||||
goto cleanup;
|
error = git_filebuf_printf(&file, "\t%s = %s\n", name, value);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Or maybe we need to write out a whole section */
|
/* Or maybe we need to write out a whole section */
|
||||||
@ -1043,7 +1135,8 @@ static int config_write(diskfile_backend *cfg, const char *key, const char* valu
|
|||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
git__rethrow(error, "Failed to write new section");
|
git__rethrow(error, "Failed to write new section");
|
||||||
|
|
||||||
error = git_filebuf_printf(&file, "\t%s = %s\n", name, value);
|
if (preg == NULL || !regexec(preg, "", 0, NULL, 0))
|
||||||
|
error = git_filebuf_printf(&file, "\t%s = %s\n", name, value);
|
||||||
cleanup:
|
cleanup:
|
||||||
git__free(section);
|
git__free(section);
|
||||||
git__free(current_section);
|
git__free(current_section);
|
||||||
|
@ -4,7 +4,7 @@ static int mv_read_cb(const char *name, const char *GIT_UNUSED(value), void *dat
|
|||||||
{
|
{
|
||||||
int *n = (int *) data;
|
int *n = (int *) data;
|
||||||
|
|
||||||
if (!strcmp(name, "remote.fancy.fetch"))
|
if (!strcmp(name, "remote.fancy.url"))
|
||||||
(*n)++;
|
(*n)++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -35,7 +35,7 @@ static int cb(const char *GIT_UNUSED(val), void *data)
|
|||||||
void test_config_multivar__get(void)
|
void test_config_multivar__get(void)
|
||||||
{
|
{
|
||||||
git_config *cfg;
|
git_config *cfg;
|
||||||
const char *name = "remote.fancy.fetch";
|
const char *name = "remote.fancy.url";
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config11")));
|
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config11")));
|
||||||
@ -50,3 +50,39 @@ void test_config_multivar__get(void)
|
|||||||
|
|
||||||
git_config_free(cfg);
|
git_config_free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_config_multivar__add(void)
|
||||||
|
{
|
||||||
|
git_config *cfg;
|
||||||
|
const char *name = "remote.fancy.url";
|
||||||
|
int n;
|
||||||
|
|
||||||
|
cl_fixture_sandbox("config");
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||||
|
cl_git_pass(git_config_set_multivar(cfg, name, "^$", "git://git.otherplace.org/libgit2"));
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
cl_git_pass(git_config_get_multivar(cfg, name, NULL, cb, &n));
|
||||||
|
cl_assert(n == 3);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
cl_git_pass(git_config_get_multivar(cfg, name, "otherplace", cb, &n));
|
||||||
|
cl_assert(n == 1);
|
||||||
|
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
/* We know it works in memory, let's see if the file is written correctly */
|
||||||
|
|
||||||
|
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
cl_git_pass(git_config_get_multivar(cfg, name, NULL, cb, &n));
|
||||||
|
cl_assert(n == 3);
|
||||||
|
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
cl_git_pass(git_config_get_multivar(cfg, name, "otherplace", cb, &n));
|
||||||
|
cl_assert(n == 1);
|
||||||
|
|
||||||
|
git_config_free(cfg);
|
||||||
|
}
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user