mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 06:20:56 +00:00
config: add support for include directives
Relative, absolute and home-relative paths are supported. The recursion limit it set at 10, just like in git.
This commit is contained in:
parent
d209cc4751
commit
d8d25acb9a
@ -34,6 +34,8 @@ typedef struct git_config_file_iter {
|
||||
cvar_t* next_var;
|
||||
} git_config_file_iter;
|
||||
|
||||
/* Max depth for [include] directives */
|
||||
#define MAX_INCLUDE_DEPTH 10
|
||||
|
||||
#define CVAR_LIST_HEAD(list) ((list)->head)
|
||||
|
||||
@ -74,6 +76,8 @@ typedef struct git_config_file_iter {
|
||||
(iter) = (tmp))
|
||||
|
||||
struct reader {
|
||||
time_t file_mtime;
|
||||
size_t file_size;
|
||||
char *file_path;
|
||||
git_buf buffer;
|
||||
char *read_ptr;
|
||||
@ -89,8 +93,6 @@ typedef struct {
|
||||
struct reader reader;
|
||||
|
||||
char *file_path;
|
||||
time_t file_mtime;
|
||||
size_t file_size;
|
||||
|
||||
git_config_level_t level;
|
||||
} diskfile_backend;
|
||||
@ -169,7 +171,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
|
||||
|
||||
git_buf_init(&b->reader.buffer, 0);
|
||||
res = git_futils_readbuffer_updated(
|
||||
&b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, NULL);
|
||||
&b->reader.buffer, b->file_path, &b->reader.file_mtime, &b->reader.file_size, NULL);
|
||||
|
||||
/* It's fine if the file doesn't exist */
|
||||
if (res == GIT_ENOTFOUND)
|
||||
@ -191,7 +193,7 @@ static int config_refresh(git_config_backend *cfg)
|
||||
git_strmap *old_values;
|
||||
|
||||
res = git_futils_readbuffer_updated(
|
||||
&b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, &updated);
|
||||
&b->reader.buffer, b->file_path, &b->reader.file_mtime, &b->reader.file_size, &updated);
|
||||
if (res < 0 || !updated)
|
||||
return (res == GIT_ENOTFOUND) ? 0 : res;
|
||||
|
||||
@ -899,6 +901,15 @@ static int strip_comments(char *line, int in_quotes)
|
||||
return quote_count;
|
||||
}
|
||||
|
||||
static int included_path(git_buf *out, const char *dir, const char *path)
|
||||
{
|
||||
/* From the user's home */
|
||||
if (path[0] == '~' && path[1] == '/')
|
||||
return git_futils_find_global_file(out, &path[1]);
|
||||
|
||||
return git_path_join_unrooted(out, path, dir, NULL);
|
||||
}
|
||||
|
||||
static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth)
|
||||
{
|
||||
int c;
|
||||
@ -910,6 +921,10 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c
|
||||
int result = 0;
|
||||
khiter_t pos;
|
||||
|
||||
/* FIXME: should we return an error? */
|
||||
if (depth >= MAX_INCLUDE_DEPTH)
|
||||
return 0;
|
||||
|
||||
/* Initialize the reading position */
|
||||
reader->read_ptr = reader->buffer.ptr;
|
||||
reader->eof = 0;
|
||||
@ -979,6 +994,38 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c
|
||||
existing->next = var;
|
||||
}
|
||||
|
||||
if (!git__strcmp(var->entry->name, "include.path")) {
|
||||
struct reader r;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
char *dir;
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
if ((result = git_path_dirname_r(&path, reader->file_path)) < 0)
|
||||
break;
|
||||
|
||||
dir = git_buf_detach(&path);
|
||||
result = included_path(&path, dir, var->entry->value);
|
||||
git__free(dir);
|
||||
|
||||
if (result < 0)
|
||||
break;
|
||||
|
||||
r.file_path = git_buf_detach(&path);
|
||||
git_buf_init(&r.buffer, 0);
|
||||
if ((result = git_futils_readbuffer_updated(&r.buffer, r.file_path, &r.file_mtime,
|
||||
&r.file_size, NULL)) < 0) {
|
||||
git__free(r.file_path);
|
||||
break;
|
||||
}
|
||||
|
||||
result = config_parse(cfg_file, &r, level, depth+1);
|
||||
git__free(r.file_path);
|
||||
git_buf_free(&r.buffer);
|
||||
|
||||
if (result < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1199,7 +1246,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
|
||||
git__free(current_section);
|
||||
|
||||
/* refresh stats - if this errors, then commit will error too */
|
||||
(void)git_filebuf_stats(&cfg->file_mtime, &cfg->file_size, &file);
|
||||
(void)git_filebuf_stats(&cfg->reader.file_mtime, &cfg->reader.file_size, &file);
|
||||
|
||||
result = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE);
|
||||
git_buf_free(&cfg->reader.buffer);
|
||||
|
50
tests-clar/config/include.c
Normal file
50
tests-clar/config/include.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "buffer.h"
|
||||
#include "fileops.h"
|
||||
|
||||
void test_config_include__relative(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-include")));
|
||||
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "foo.bar.baz"));
|
||||
cl_assert_equal_s(str, "huzzah");
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_include__absolute(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_buf_printf(&buf, "[include]\npath = %s/config-included", cl_fixture("config")));
|
||||
|
||||
cl_git_mkfile("config-include-absolute", git_buf_cstr(&buf));
|
||||
git_buf_free(&buf);
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config-include-absolute"));
|
||||
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "foo.bar.baz"));
|
||||
cl_assert_equal_s(str, "huzzah");
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_include__homedir(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
|
||||
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config")));
|
||||
cl_git_mkfile("config-include-homedir", "[include]\npath = ~/config-included");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config-include-homedir"));
|
||||
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "foo.bar.baz"));
|
||||
cl_assert_equal_s(str, "huzzah");
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
2
tests-clar/resources/config/config-include
Normal file
2
tests-clar/resources/config/config-include
Normal file
@ -0,0 +1,2 @@
|
||||
[include]
|
||||
path = config-included
|
2
tests-clar/resources/config/config-included
Normal file
2
tests-clar/resources/config/config-included
Normal file
@ -0,0 +1,2 @@
|
||||
[foo "bar"]
|
||||
baz = huzzah
|
Loading…
Reference in New Issue
Block a user