mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 00:43:41 +00:00
commit
48bcf81dd2
@ -33,7 +33,7 @@ struct git_config_file {
|
||||
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 (*foreach)(struct git_config_file *, int (*fn)(const char *, const char *, void *), void *data);
|
||||
int (*foreach)(struct git_config_file *, const char *, int (*fn)(const char *, const char *, void *), void *data);
|
||||
void (*free)(struct git_config_file *);
|
||||
};
|
||||
|
||||
@ -314,6 +314,24 @@ GIT_EXTERN(int) git_config_foreach(
|
||||
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Perform an operation on each config variable matching a regular expression.
|
||||
*
|
||||
* This behaviors like `git_config_foreach` with an additional filter of a
|
||||
* regular expression that filters which config keys are passed to the
|
||||
* callback.
|
||||
*
|
||||
* @param cfg where to get the variables from
|
||||
* @param regexp regular expression to match against config names
|
||||
* @param callback the function to call on each variable
|
||||
* @param payload the data to pass to the callback
|
||||
* @return 0 or the return value of the callback which didn't return 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_foreach_match(
|
||||
git_config *cfg,
|
||||
const char *regexp,
|
||||
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Query the value of a config variable and return it mapped to
|
||||
|
@ -194,9 +194,12 @@ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo);
|
||||
*
|
||||
* @param repo A repository object
|
||||
* @param workdir The path to a working directory
|
||||
* @param update_gitlink Create/update gitlink in workdir and set config
|
||||
* "core.worktree" (if workdir is not the parent of the .git directory)
|
||||
* @return 0, or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_repository_set_workdir(git_repository *repo, const char *workdir);
|
||||
GIT_EXTERN(int) git_repository_set_workdir(
|
||||
git_repository *repo, const char *workdir, int update_gitlink);
|
||||
|
||||
/**
|
||||
* Check if a repository is bare
|
||||
|
36
src/buffer.c
36
src/buffer.c
@ -141,6 +141,42 @@ int git_buf_puts(git_buf *buf, const char *string)
|
||||
return git_buf_put(buf, string, strlen(string));
|
||||
}
|
||||
|
||||
int git_buf_puts_escaped(
|
||||
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with)
|
||||
{
|
||||
const char *scan = string;
|
||||
size_t total = 0, esc_with_len = strlen(esc_with);
|
||||
|
||||
while (*scan) {
|
||||
size_t count = strcspn(scan, esc_chars);
|
||||
total += count + 1 + esc_with_len;
|
||||
scan += count + 1;
|
||||
}
|
||||
|
||||
ENSURE_SIZE(buf, buf->size + total + 1);
|
||||
|
||||
for (scan = string; *scan; ) {
|
||||
size_t count = strcspn(scan, esc_chars);
|
||||
|
||||
memmove(buf->ptr + buf->size, scan, count);
|
||||
scan += count;
|
||||
buf->size += count;
|
||||
|
||||
if (*scan) {
|
||||
memmove(buf->ptr + buf->size, esc_with, esc_with_len);
|
||||
buf->size += esc_with_len;
|
||||
|
||||
memmove(buf->ptr + buf->size, scan, 1);
|
||||
scan += 1;
|
||||
buf->size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
buf->ptr[buf->size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
|
||||
{
|
||||
int len;
|
||||
|
19
src/buffer.h
19
src/buffer.h
@ -90,6 +90,18 @@ void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
||||
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
||||
|
||||
/**
|
||||
* Copy string into buf prefixing every character that is contained in the
|
||||
* esc_chars string with the esc_with string.
|
||||
*/
|
||||
int git_buf_puts_escaped(
|
||||
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with);
|
||||
|
||||
GIT_INLINE(int) git_buf_puts_escape_regex(git_buf *buf, const char *string)
|
||||
{
|
||||
return git_buf_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\");
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two strings as paths, inserting a slash between as needed.
|
||||
* @return 0 on success, -1 on failure
|
||||
@ -121,6 +133,13 @@ GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch)
|
||||
return idx;
|
||||
}
|
||||
|
||||
GIT_INLINE(ssize_t) git_buf_rfind(git_buf *buf, char ch)
|
||||
{
|
||||
ssize_t idx = (ssize_t)buf->size - 1;
|
||||
while (idx >= 0 && buf->ptr[idx] != ch) idx--;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* Remove whitespace from the end of the buffer */
|
||||
void git_buf_rtrim(git_buf *buf);
|
||||
|
||||
|
16
src/config.c
16
src/config.c
@ -136,17 +136,27 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority)
|
||||
* Loop over all the variables
|
||||
*/
|
||||
|
||||
int git_config_foreach(git_config *cfg, int (*fn)(const char *, const char *, void *), void *data)
|
||||
int git_config_foreach(
|
||||
git_config *cfg, int (*fn)(const char *, const char *, void *), void *data)
|
||||
{
|
||||
return git_config_foreach_match(cfg, NULL, fn, data);
|
||||
}
|
||||
|
||||
int git_config_foreach_match(
|
||||
git_config *cfg,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *, const char *, void *),
|
||||
void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
file_internal *internal;
|
||||
git_config_file *file;
|
||||
|
||||
for(i = 0; i < cfg->files.length && ret == 0; ++i) {
|
||||
for (i = 0; i < cfg->files.length && ret == 0; ++i) {
|
||||
internal = git_vector_get(&cfg->files, i);
|
||||
file = internal->file;
|
||||
ret = file->foreach(file, fn, data);
|
||||
ret = file->foreach(file, regexp, fn, data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -188,25 +188,46 @@ static void backend_free(git_config_file *_backend)
|
||||
git__free(backend);
|
||||
}
|
||||
|
||||
static int file_foreach(git_config_file *backend, int (*fn)(const char *, const char *, void *), void *data)
|
||||
static int file_foreach(
|
||||
git_config_file *backend,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *, const char *, void *),
|
||||
void *data)
|
||||
{
|
||||
diskfile_backend *b = (diskfile_backend *)backend;
|
||||
cvar_t *var;
|
||||
const char *key;
|
||||
regex_t regex;
|
||||
int result = 0;
|
||||
|
||||
if (!b->values)
|
||||
return 0;
|
||||
|
||||
git_strmap_foreach(b->values, key, var,
|
||||
do {
|
||||
if (fn(key, var->value, data) < 0)
|
||||
break;
|
||||
if (regexp != NULL) {
|
||||
if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) {
|
||||
giterr_set_regex(®ex, result);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
var = CVAR_LIST_NEXT(var);
|
||||
} while (var != NULL);
|
||||
git_strmap_foreach(b->values, key, var,
|
||||
for (; var != NULL; var = CVAR_LIST_NEXT(var)) {
|
||||
/* skip non-matching keys if regexp was provided */
|
||||
if (regexp && regexec(®ex, key, 0, NULL, 0) != 0)
|
||||
continue;
|
||||
|
||||
/* abort iterator on non-zero return value */
|
||||
if ((result = fn(key, var->value, data)) != 0)
|
||||
goto cleanup;
|
||||
}
|
||||
);
|
||||
|
||||
return 0;
|
||||
cleanup:
|
||||
if (regexp != NULL)
|
||||
regfree(®ex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int config_set(git_config_file *cfg, const char *name, const char *value)
|
||||
@ -337,6 +358,7 @@ static int config_get_multivar(
|
||||
result = regcomp(®ex, regex_str, REG_EXTENDED);
|
||||
if (result < 0) {
|
||||
giterr_set_regex(®ex, result);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -396,6 +418,7 @@ static int config_set_multivar(
|
||||
if (result < 0) {
|
||||
git__free(key);
|
||||
giterr_set_regex(&preg, result);
|
||||
regfree(&preg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,27 @@ GIT_INLINE(void) git_config_file_free(git_config_file *cfg)
|
||||
cfg->free(cfg);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_config_file_set_string(
|
||||
git_config_file *cfg, const char *name, const char *value)
|
||||
{
|
||||
return cfg->set(cfg, name, value);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_config_file_foreach(
|
||||
git_config_file *cfg,
|
||||
int (*fn)(const char *key, const char *value, void *data),
|
||||
void *data)
|
||||
{
|
||||
return cfg->foreach(cfg, fn, data);
|
||||
return cfg->foreach(cfg, NULL, fn, data);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_config_file_foreach_match(
|
||||
git_config_file *cfg,
|
||||
const char *regexp,
|
||||
int (*fn)(const char *key, const char *value, void *data),
|
||||
void *data)
|
||||
{
|
||||
return cfg->foreach(cfg, regexp, fn, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
69
src/path.c
69
src/path.c
@ -17,9 +17,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
#define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':')
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Based on the Android implementation, BSD licensed.
|
||||
@ -172,11 +170,11 @@ int git_path_root(const char *path)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
/* Does the root of the path look like a windows drive ? */
|
||||
if (LOOKS_LIKE_DRIVE_PREFIX(path))
|
||||
offset += 2;
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
/* Are we dealing with a windows network path? */
|
||||
else if ((path[0] == '/' && path[1] == '/') ||
|
||||
(path[0] == '\\' && path[1] == '\\'))
|
||||
@ -464,6 +462,71 @@ int git_path_find_dir(git_buf *dir, const char *path, const char *base)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_path_resolve_relative(git_buf *path, size_t ceiling)
|
||||
{
|
||||
char *base, *to, *from, *next;
|
||||
size_t len;
|
||||
|
||||
if (!path || git_buf_oom(path))
|
||||
return -1;
|
||||
|
||||
if (ceiling > path->size)
|
||||
ceiling = path->size;
|
||||
|
||||
/* recognize drive prefixes, etc. that should not be backed over */
|
||||
if (ceiling == 0)
|
||||
ceiling = git_path_root(path->ptr) + 1;
|
||||
|
||||
/* recognize URL prefixes that should not be backed over */
|
||||
if (ceiling == 0) {
|
||||
for (next = path->ptr; *next && git__isalpha(*next); ++next);
|
||||
if (next[0] == ':' && next[1] == '/' && next[2] == '/')
|
||||
ceiling = (next + 3) - path->ptr;
|
||||
}
|
||||
|
||||
base = to = from = path->ptr + ceiling;
|
||||
|
||||
while (*from) {
|
||||
for (next = from; *next && *next != '/'; ++next);
|
||||
|
||||
len = next - from;
|
||||
|
||||
if (len == 1 && from[0] == '.')
|
||||
/* do nothing with singleton dot */;
|
||||
|
||||
else if (len == 2 && from[0] == '.' && from[1] == '.') {
|
||||
while (to > base && to[-1] == '/') to--;
|
||||
while (to > base && to[-1] != '/') to--;
|
||||
}
|
||||
|
||||
else {
|
||||
if (*next == '/')
|
||||
len++;
|
||||
|
||||
if (to != from)
|
||||
memmove(to, from, len);
|
||||
|
||||
to += len;
|
||||
}
|
||||
|
||||
from += len;
|
||||
|
||||
while (*from == '/') from++;
|
||||
}
|
||||
|
||||
*to = '\0';
|
||||
|
||||
path->size = to - path->ptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_path_apply_relative(git_buf *target, const char *relpath)
|
||||
{
|
||||
git_buf_joinpath(target, git_buf_cstr(target), relpath);
|
||||
return git_path_resolve_relative(target, 0);
|
||||
}
|
||||
|
||||
int git_path_cmp(
|
||||
const char *name1, size_t len1, int isdir1,
|
||||
const char *name2, size_t len2, int isdir2)
|
||||
|
23
src/path.h
23
src/path.h
@ -185,6 +185,29 @@ extern int git_path_prettify_dir(git_buf *path_out, const char *path, const char
|
||||
*/
|
||||
extern int git_path_find_dir(git_buf *dir, const char *path, const char *base);
|
||||
|
||||
/**
|
||||
* Resolve relative references within a path.
|
||||
*
|
||||
* This eliminates "./" and "../" relative references inside a path,
|
||||
* as well as condensing multiple slashes into single ones. It will
|
||||
* not touch the path before the "ceiling" length.
|
||||
*
|
||||
* Additionally, this will recognize an "c:/" drive prefix or a "xyz://" URL
|
||||
* prefix and not touch that part of the path.
|
||||
*/
|
||||
extern int git_path_resolve_relative(git_buf *path, size_t ceiling);
|
||||
|
||||
/**
|
||||
* Apply a relative path to base path.
|
||||
*
|
||||
* Note that the base path could be a filename or a URL and this
|
||||
* should still work. The relative path is walked segment by segment
|
||||
* with three rules: series of slashes will be condensed to a single
|
||||
* slash, "." will be eaten with no change, and ".." will remove a
|
||||
* segment from the base path.
|
||||
*/
|
||||
extern int git_path_apply_relative(git_buf *target, const char *relpath);
|
||||
|
||||
/**
|
||||
* Walk each directory entry, except '.' and '..', calling fn(state).
|
||||
*
|
||||
|
@ -741,15 +741,24 @@ static int repo_init_config(const char *git_dir, bool is_bare, bool is_reinit)
|
||||
#define GIT_DESC_CONTENT "Unnamed repository; edit this file 'description' to name the repository.\n"
|
||||
|
||||
static int repo_write_template(
|
||||
const char *git_dir, const char *file, mode_t mode, const char *content)
|
||||
const char *git_dir,
|
||||
bool allow_overwrite,
|
||||
const char *file,
|
||||
mode_t mode,
|
||||
const char *content)
|
||||
{
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
int fd, error = 0;
|
||||
int fd, error = 0, flags;
|
||||
|
||||
if (git_buf_joinpath(&path, git_dir, file) < 0)
|
||||
return -1;
|
||||
|
||||
fd = p_open(git_buf_cstr(&path), O_WRONLY | O_CREAT | O_EXCL, mode);
|
||||
if (allow_overwrite)
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
else
|
||||
flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||
|
||||
fd = p_open(git_buf_cstr(&path), flags, mode);
|
||||
|
||||
if (fd >= 0) {
|
||||
error = p_write(fd, content, strlen(content));
|
||||
@ -811,7 +820,7 @@ static int repo_init_structure(const char *git_dir, int is_bare)
|
||||
/* Make template files as needed */
|
||||
for (i = 0; tmpl[i].file != NULL; ++i) {
|
||||
if (repo_write_template(
|
||||
git_dir, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
|
||||
git_dir, false, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -943,8 +952,47 @@ const char *git_repository_workdir(git_repository *repo)
|
||||
return repo->workdir;
|
||||
}
|
||||
|
||||
int git_repository_set_workdir(git_repository *repo, const char *workdir)
|
||||
static int write_gitlink(
|
||||
const char *in_dir, const char *to_repo)
|
||||
{
|
||||
int error;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
struct stat st;
|
||||
|
||||
if (git_path_dirname_r(&buf, to_repo) < 0 ||
|
||||
git_path_to_dir(&buf) < 0)
|
||||
return -1;
|
||||
|
||||
/* don't write gitlink to natural workdir */
|
||||
if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 &&
|
||||
strcmp(in_dir, buf.ptr) == 0)
|
||||
return GIT_PASSTHROUGH;
|
||||
|
||||
if (git_buf_joinpath(&buf, in_dir, DOT_GIT) < 0)
|
||||
return -1;
|
||||
|
||||
if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) {
|
||||
giterr_set(GITERR_REPOSITORY,
|
||||
"Cannot overwrite gitlink file into path '%s'", in_dir);
|
||||
return GIT_EEXISTS;
|
||||
}
|
||||
|
||||
git_buf_clear(&buf);
|
||||
|
||||
if (git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo) < 0)
|
||||
return -1;
|
||||
|
||||
error = repo_write_template(in_dir, true, DOT_GIT, 0644, buf.ptr);
|
||||
|
||||
git_buf_free(&buf);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_repository_set_workdir(
|
||||
git_repository *repo, const char *workdir, int update_gitlink)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
|
||||
assert(repo && workdir);
|
||||
@ -952,11 +1000,37 @@ int git_repository_set_workdir(git_repository *repo, const char *workdir)
|
||||
if (git_path_prettify_dir(&path, workdir, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
git__free(repo->workdir);
|
||||
if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0)
|
||||
return 0;
|
||||
|
||||
repo->workdir = git_buf_detach(&path);
|
||||
repo->is_bare = 0;
|
||||
return 0;
|
||||
if (update_gitlink) {
|
||||
git_config *config;
|
||||
|
||||
if (git_repository_config__weakptr(&config, repo) < 0)
|
||||
return -1;
|
||||
|
||||
error = write_gitlink(path.ptr, git_repository_path(repo));
|
||||
|
||||
/* passthrough error means gitlink is unnecessary */
|
||||
if (error == GIT_PASSTHROUGH)
|
||||
error = git_config_delete(config, "core.worktree");
|
||||
else if (!error)
|
||||
error = git_config_set_string(config, "core.worktree", path.ptr);
|
||||
|
||||
if (!error)
|
||||
error = git_config_set_bool(config, "core.bare", false);
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
char *old_workdir = repo->workdir;
|
||||
|
||||
repo->workdir = git_buf_detach(&path);
|
||||
repo->is_bare = 0;
|
||||
|
||||
git__free(old_workdir);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_repository_is_bare(git_repository *repo)
|
||||
|
@ -211,7 +211,7 @@ GIT_INLINE(bool) git__isdigit(int c)
|
||||
|
||||
GIT_INLINE(bool) git__isspace(int c)
|
||||
{
|
||||
return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v');
|
||||
return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v' || c == 0x85 /* Unicode CR+LF */);
|
||||
}
|
||||
|
||||
GIT_INLINE(bool) git__iswildcard(int c)
|
||||
|
@ -191,6 +191,81 @@ void test_config_read__escaping_quotes(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int count_cfg_entries(
|
||||
const char *var_name, const char *value, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
GIT_UNUSED(var_name);
|
||||
GIT_UNUSED(value);
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cfg_callback_countdown(
|
||||
const char *var_name, const char *value, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
GIT_UNUSED(var_name);
|
||||
GIT_UNUSED(value);
|
||||
(*count)--;
|
||||
if (*count == 0)
|
||||
return -100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_config_read__foreach(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int count, ret;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(git_config_foreach(cfg, count_cfg_entries, &count));
|
||||
cl_assert_equal_i(5, count);
|
||||
|
||||
count = 3;
|
||||
cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count));
|
||||
cl_assert_equal_i(-100, ret);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_read__foreach_match(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
int count;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(
|
||||
git_config_foreach_match(cfg, "core.*", count_cfg_entries, &count));
|
||||
cl_assert_equal_i(3, count);
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(
|
||||
git_config_foreach_match(cfg, "remote\\.ab.*", count_cfg_entries, &count));
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(
|
||||
git_config_foreach_match(cfg, ".*url$", count_cfg_entries, &count));
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(
|
||||
git_config_foreach_match(cfg, ".*dummy.*", count_cfg_entries, &count));
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(
|
||||
git_config_foreach_match(cfg, ".*nomatch.*", count_cfg_entries, &count));
|
||||
cl_assert_equal_i(0, count);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
BEGIN_TEST(config10, "a repo's config overrides the global config")
|
||||
|
@ -611,3 +611,50 @@ void test_core_buffer__11(void)
|
||||
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
||||
void test_core_buffer__rfind_variants(void)
|
||||
{
|
||||
git_buf a = GIT_BUF_INIT;
|
||||
ssize_t len;
|
||||
|
||||
cl_git_pass(git_buf_sets(&a, "/this/is/it/"));
|
||||
|
||||
len = (ssize_t)git_buf_len(&a);
|
||||
|
||||
cl_assert(git_buf_rfind(&a, '/') == len - 1);
|
||||
cl_assert(git_buf_rfind_next(&a, '/') == len - 4);
|
||||
|
||||
cl_assert(git_buf_rfind(&a, 'i') == len - 3);
|
||||
cl_assert(git_buf_rfind_next(&a, 'i') == len - 3);
|
||||
|
||||
cl_assert(git_buf_rfind(&a, 'h') == 2);
|
||||
cl_assert(git_buf_rfind_next(&a, 'h') == 2);
|
||||
|
||||
cl_assert(git_buf_rfind(&a, 'q') == -1);
|
||||
cl_assert(git_buf_rfind_next(&a, 'q') == -1);
|
||||
|
||||
git_buf_clear(&a);
|
||||
}
|
||||
|
||||
void test_core_buffer__puts_escaped(void)
|
||||
{
|
||||
git_buf a = GIT_BUF_INIT;
|
||||
|
||||
git_buf_clear(&a);
|
||||
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "", ""));
|
||||
cl_assert_equal_s("this is a test", a.ptr);
|
||||
|
||||
git_buf_clear(&a);
|
||||
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "t", "\\"));
|
||||
cl_assert_equal_s("\\this is a \\tes\\t", a.ptr);
|
||||
|
||||
git_buf_clear(&a);
|
||||
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "i ", "__"));
|
||||
cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr);
|
||||
|
||||
git_buf_clear(&a);
|
||||
cl_git_pass(git_buf_puts_escape_regex(&a, "^match\\s*[A-Z]+.*"));
|
||||
cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr);
|
||||
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
@ -418,3 +418,54 @@ void test_core_path__13_cannot_prettify_a_non_existing_file(void)
|
||||
|
||||
git_buf_free(&p);
|
||||
}
|
||||
|
||||
void test_core_path__14_apply_relative(void)
|
||||
{
|
||||
git_buf p = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_buf_sets(&p, "/this/is/a/base"));
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../test"));
|
||||
cl_assert_equal_s("/this/is/a/test", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../the/./end"));
|
||||
cl_assert_equal_s("/this/is/the/end", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "./of/this/../the/string"));
|
||||
cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../../../../.."));
|
||||
cl_assert_equal_s("/this/", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../../../../"));
|
||||
cl_assert_equal_s("/", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../../../.."));
|
||||
cl_assert_equal_s("/", p.ptr);
|
||||
|
||||
|
||||
cl_git_pass(git_buf_sets(&p, "d:/another/test"));
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../../../.."));
|
||||
cl_assert_equal_s("d:/", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "from/here/to/../and/./back/."));
|
||||
cl_assert_equal_s("d:/from/here/and/back/", p.ptr);
|
||||
|
||||
|
||||
cl_git_pass(git_buf_sets(&p, "https://my.url.com/test.git"));
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../another.git"));
|
||||
cl_assert_equal_s("https://my.url.com/another.git", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../full/path/url.patch"));
|
||||
cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, ".."));
|
||||
cl_assert_equal_s("https://my.url.com/full/path/", p.ptr);
|
||||
|
||||
cl_git_pass(git_path_apply_relative(&p, "../../../../../"));
|
||||
cl_assert_equal_s("https://", p.ptr);
|
||||
|
||||
git_buf_free(&p);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "buffer.h"
|
||||
#include "posix.h"
|
||||
#include "util.h"
|
||||
#include "path.h"
|
||||
#include "fileops.h"
|
||||
|
||||
static git_repository *repo;
|
||||
|
||||
@ -16,7 +18,7 @@ void test_repo_setters__cleanup(void)
|
||||
{
|
||||
git_repository_free(repo);
|
||||
cl_fixture_cleanup("testrepo.git");
|
||||
cl_must_pass(p_rmdir("new_workdir"));
|
||||
cl_fixture_cleanup("new_workdir");
|
||||
}
|
||||
|
||||
void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standard_one(void)
|
||||
@ -24,7 +26,7 @@ void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standar
|
||||
cl_assert(git_repository_is_bare(repo) == 1);
|
||||
|
||||
cl_assert(git_repository_workdir(repo) == NULL);
|
||||
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir"));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false));
|
||||
|
||||
cl_assert(git_repository_workdir(repo) != NULL);
|
||||
cl_assert(git_repository_is_bare(repo) == 0);
|
||||
@ -32,9 +34,30 @@ void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standar
|
||||
|
||||
void test_repo_setters__setting_a_workdir_prettifies_its_path(void)
|
||||
{
|
||||
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir"));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false));
|
||||
|
||||
cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0);
|
||||
cl_assert(git__suffixcmp(git_repository_workdir(repo), "new_workdir/") == 0);
|
||||
}
|
||||
|
||||
void test_repo_setters__setting_a_workdir_creates_a_gitlink(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *val;
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", true));
|
||||
|
||||
cl_assert(git_path_isfile("./new_workdir/.git"));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&content, "./new_workdir/.git"));
|
||||
cl_assert(git__prefixcmp(git_buf_cstr(&content), "gitdir: ") == 0);
|
||||
cl_assert(git__suffixcmp(git_buf_cstr(&content), "testrepo.git/") == 0);
|
||||
git_buf_free(&content);
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_get_string(&val, cfg, "core.worktree"));
|
||||
cl_assert(git__suffixcmp(val, "new_workdir/") == 0);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_one_properly_honors_the_refcount(void)
|
||||
|
@ -459,7 +459,7 @@ void test_status_worktree__status_file_without_index_or_workdir(void)
|
||||
cl_git_pass(p_mkdir("wd", 0777));
|
||||
|
||||
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "wd"));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "wd", false));
|
||||
|
||||
cl_git_pass(git_index_open(&index, "empty-index"));
|
||||
cl_assert_equal_i(0, git_index_entrycount(index));
|
||||
@ -500,7 +500,7 @@ void test_status_worktree__status_file_with_clean_index_and_empty_workdir(void)
|
||||
cl_git_pass(p_mkdir("wd", 0777));
|
||||
|
||||
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "wd"));
|
||||
cl_git_pass(git_repository_set_workdir(repo, "wd", false));
|
||||
|
||||
cl_git_pass(git_index_open(&index, "my-index"));
|
||||
fill_index_wth_head_entries(repo, index);
|
||||
|
Loading…
Reference in New Issue
Block a user