mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 00:30:27 +00:00
Merge pull request #2215 from libgit2/rb/submodule-cache-fixes
Improve submodule cache management
This commit is contained in:
commit
923c84008d
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* This example demonstrates the use of the libgit2 status APIs,
|
||||
@ -44,19 +45,22 @@ enum {
|
||||
#define MAX_PATHSPEC 8
|
||||
|
||||
struct opts {
|
||||
git_status_options statusopt;
|
||||
char *repodir;
|
||||
char *pathspec[MAX_PATHSPEC];
|
||||
int npaths;
|
||||
int format;
|
||||
int zterm;
|
||||
int showbranch;
|
||||
git_status_options statusopt;
|
||||
char *repodir;
|
||||
char *pathspec[MAX_PATHSPEC];
|
||||
int npaths;
|
||||
int format;
|
||||
int zterm;
|
||||
int showbranch;
|
||||
int showsubmod;
|
||||
int repeat;
|
||||
};
|
||||
|
||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||
static void show_branch(git_repository *repo, int format);
|
||||
static void print_long(git_status_list *status);
|
||||
static void print_short(git_repository *repo, git_status_list *status);
|
||||
static int print_submod(git_submodule *sm, const char *name, void *payload);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -84,6 +88,10 @@ int main(int argc, char *argv[])
|
||||
fatal("Cannot report status on bare repository",
|
||||
git_repository_path(repo));
|
||||
|
||||
show_status:
|
||||
if (o.repeat)
|
||||
printf("\033[H\033[2J");
|
||||
|
||||
/**
|
||||
* Run status on the repository
|
||||
*
|
||||
@ -98,17 +106,29 @@ int main(int argc, char *argv[])
|
||||
* about what results are presented.
|
||||
*/
|
||||
check_lg2(git_status_list_new(&status, repo, &o.statusopt),
|
||||
"Could not get status", NULL);
|
||||
"Could not get status", NULL);
|
||||
|
||||
if (o.showbranch)
|
||||
show_branch(repo, o.format);
|
||||
|
||||
if (o.showsubmod) {
|
||||
int submod_count = 0;
|
||||
check_lg2(git_submodule_foreach(repo, print_submod, &submod_count),
|
||||
"Cannot iterate submodules", o.repodir);
|
||||
}
|
||||
|
||||
if (o.format == FORMAT_LONG)
|
||||
print_long(status);
|
||||
else
|
||||
print_short(repo, status);
|
||||
|
||||
git_status_list_free(status);
|
||||
|
||||
if (o.repeat) {
|
||||
sleep(o.repeat);
|
||||
goto show_status;
|
||||
}
|
||||
|
||||
git_repository_free(repo);
|
||||
git_threads_shutdown();
|
||||
|
||||
@ -381,7 +401,7 @@ static void print_short(git_repository *repo, git_status_list *status)
|
||||
}
|
||||
|
||||
/**
|
||||
* Now that we have all the information, it's time to format the output.
|
||||
* Now that we have all the information, format the output.
|
||||
*/
|
||||
|
||||
if (s->head_to_index) {
|
||||
@ -417,6 +437,21 @@ static void print_short(git_repository *repo, git_status_list *status)
|
||||
}
|
||||
}
|
||||
|
||||
static int print_submod(git_submodule *sm, const char *name, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
(void)name;
|
||||
|
||||
if (*count == 0)
|
||||
printf("# Submodules\n");
|
||||
(*count)++;
|
||||
|
||||
printf("# - submodule '%s' at %s\n",
|
||||
git_submodule_name(sm), git_submodule_path(sm));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse options that git's status command supports.
|
||||
*/
|
||||
@ -462,6 +497,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
o->statusopt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
|
||||
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
|
||||
o->repodir = a + strlen("--git-dir=");
|
||||
else if (!strcmp(a, "--repeat"))
|
||||
o->repeat = 10;
|
||||
else if (match_int_arg(&o->repeat, &args, "--repeat", 0))
|
||||
/* okay */;
|
||||
else if (!strcmp(a, "--list-submodules"))
|
||||
o->showsubmod = 1;
|
||||
else
|
||||
check_lg2(-1, "Unsupported option", a);
|
||||
}
|
||||
|
53
src/buffer.c
53
src/buffer.c
@ -467,6 +467,59 @@ int git_buf_join(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_buf_join3(
|
||||
git_buf *buf,
|
||||
char separator,
|
||||
const char *str_a,
|
||||
const char *str_b,
|
||||
const char *str_c)
|
||||
{
|
||||
size_t len_a = strlen(str_a), len_b = strlen(str_b), len_c = strlen(str_c);
|
||||
int sep_a = 0, sep_b = 0;
|
||||
char *tgt;
|
||||
|
||||
/* for this function, disallow pointers into the existing buffer */
|
||||
assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
|
||||
assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
|
||||
assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
|
||||
|
||||
if (separator) {
|
||||
if (len_a > 0) {
|
||||
while (*str_b == separator) { str_b++; len_b--; }
|
||||
sep_a = (str_a[len_a - 1] != separator);
|
||||
}
|
||||
if (len_a > 0 || len_b > 0)
|
||||
while (*str_c == separator) { str_c++; len_c--; }
|
||||
if (len_b > 0)
|
||||
sep_b = (str_b[len_b - 1] != separator);
|
||||
}
|
||||
|
||||
if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0)
|
||||
return -1;
|
||||
|
||||
tgt = buf->ptr;
|
||||
|
||||
if (len_a) {
|
||||
memcpy(tgt, str_a, len_a);
|
||||
tgt += len_a;
|
||||
}
|
||||
if (sep_a)
|
||||
*tgt++ = separator;
|
||||
if (len_b) {
|
||||
memcpy(tgt, str_b, len_b);
|
||||
tgt += len_b;
|
||||
}
|
||||
if (sep_b)
|
||||
*tgt++ = separator;
|
||||
if (len_c)
|
||||
memcpy(tgt, str_c, len_c);
|
||||
|
||||
buf->size = len_a + sep_a + len_b + sep_b + len_c;
|
||||
buf->ptr[buf->size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_buf_rtrim(git_buf *buf)
|
||||
{
|
||||
while (buf->size > 0) {
|
||||
|
@ -98,8 +98,12 @@ void git_buf_truncate(git_buf *buf, size_t len);
|
||||
void git_buf_shorten(git_buf *buf, size_t amount);
|
||||
void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||
|
||||
/** General join with separator */
|
||||
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
||||
/** Fast join of two strings - first may legally point into `buf` data */
|
||||
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
||||
/** Fast join of three strings - cannot reference `buf` data */
|
||||
int git_buf_join3(git_buf *buf, char separator, const char *str_a, const char *str_b, const char *str_c);
|
||||
|
||||
/**
|
||||
* Join two strings as paths, inserting a slash between as needed.
|
||||
|
30
src/config.c
30
src/config.c
@ -615,6 +615,36 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_config__update_entry(
|
||||
git_config *config,
|
||||
const char *key,
|
||||
const char *value,
|
||||
bool overwrite_existing,
|
||||
bool only_if_existing)
|
||||
{
|
||||
int error = 0;
|
||||
const git_config_entry *ce = NULL;
|
||||
|
||||
if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0)
|
||||
return error;
|
||||
|
||||
if (!ce && only_if_existing) /* entry doesn't exist */
|
||||
return 0;
|
||||
if (ce && !overwrite_existing) /* entry would be overwritten */
|
||||
return 0;
|
||||
if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */
|
||||
return 0;
|
||||
if (!value && (!ce || !ce->value)) /* asked to delete absent entry */
|
||||
return 0;
|
||||
|
||||
if (!value)
|
||||
error = git_config_delete_entry(config, key);
|
||||
else
|
||||
error = git_config_set_string(config, key, value);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/***********
|
||||
* Getters
|
||||
***********/
|
||||
|
@ -53,6 +53,14 @@ extern int git_config__lookup_entry(
|
||||
const char *key,
|
||||
bool no_errors);
|
||||
|
||||
/* internal only: update and/or delete entry string with constraints */
|
||||
extern int git_config__update_entry(
|
||||
git_config *cfg,
|
||||
const char *key,
|
||||
const char *value,
|
||||
bool overwrite_existing,
|
||||
bool only_if_existing);
|
||||
|
||||
/*
|
||||
* Lookup functions that cannot fail. These functions look up a config
|
||||
* value and return a fallback value if the value is missing or if any
|
||||
|
@ -16,7 +16,8 @@ GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level
|
||||
|
||||
GIT_INLINE(void) git_config_file_free(git_config_backend *cfg)
|
||||
{
|
||||
cfg->free(cfg);
|
||||
if (cfg)
|
||||
cfg->free(cfg);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) git_config_file_get_string(
|
||||
|
12
src/index.c
12
src/index.c
@ -517,6 +517,18 @@ int git_index_read(git_index *index, int force)
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_index__changed_relative_to(
|
||||
git_index *index, const git_futils_filestamp *fs)
|
||||
{
|
||||
/* attempt to update index (ignoring errors) */
|
||||
if (git_index_read(index, false) < 0)
|
||||
giterr_clear();
|
||||
|
||||
return (index->stamp.mtime != fs->mtime ||
|
||||
index->stamp.size != fs->size ||
|
||||
index->stamp.ino != fs->ino);
|
||||
}
|
||||
|
||||
int git_index_write(git_index *index)
|
||||
{
|
||||
git_filebuf file = GIT_FILEBUF_INIT;
|
||||
|
@ -62,4 +62,11 @@ extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
|
||||
|
||||
extern unsigned int git_index__create_mode(unsigned int mode);
|
||||
|
||||
GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index)
|
||||
{
|
||||
return &index->stamp;
|
||||
}
|
||||
|
||||
extern int git_index__changed_relative_to(git_index *index, const git_futils_filestamp *fs);
|
||||
|
||||
#endif
|
||||
|
@ -119,6 +119,14 @@ GIT_INLINE(void) git_path_mkposix(char *path)
|
||||
# define git_path_mkposix(p) /* blank */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check if string is a relative path (i.e. starts with "./" or "../")
|
||||
*/
|
||||
GIT_INLINE(int) git_path_is_relative(const char *p)
|
||||
{
|
||||
return (p[0] == '.' && (p[1] == '/' || (p[1] == '.' && p[2] == '/')));
|
||||
}
|
||||
|
||||
extern int git__percent_decode(git_buf *decoded_out, const char *input);
|
||||
|
||||
/**
|
||||
|
@ -1432,7 +1432,7 @@ static int create_new_reflog_file(const char *filepath)
|
||||
|
||||
GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
|
||||
{
|
||||
return git_buf_join_n(path, '/', 3, repo->path_repository, GIT_REFLOG_DIR, name);
|
||||
return git_buf_join3(path, '/', repo->path_repository, GIT_REFLOG_DIR, name);
|
||||
}
|
||||
|
||||
static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
|
||||
|
88
src/remote.c
88
src/remote.c
@ -495,9 +495,10 @@ cleanup:
|
||||
int git_remote_save(const git_remote *remote)
|
||||
{
|
||||
int error;
|
||||
git_config *config;
|
||||
git_config *cfg;
|
||||
const char *tagopt = NULL;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
const git_config_entry *existing;
|
||||
|
||||
assert(remote);
|
||||
|
||||
@ -509,43 +510,31 @@ int git_remote_save(const git_remote *remote)
|
||||
if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
|
||||
return error;
|
||||
|
||||
if (git_repository_config__weakptr(&config, remote->repo) < 0)
|
||||
return -1;
|
||||
if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
|
||||
return error;
|
||||
|
||||
if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
|
||||
return -1;
|
||||
if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
|
||||
return error;
|
||||
|
||||
if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
|
||||
git_buf_free(&buf);
|
||||
return -1;
|
||||
}
|
||||
/* after this point, buffer is allocated so end with cleanup */
|
||||
|
||||
if ((error = git_config_set_string(
|
||||
cfg, git_buf_cstr(&buf), remote->url)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_buf_clear(&buf);
|
||||
if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
|
||||
return -1;
|
||||
if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (remote->pushurl) {
|
||||
if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
|
||||
git_buf_free(&buf);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
int error = git_config_delete_entry(config, git_buf_cstr(&buf));
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
error = 0;
|
||||
giterr_clear();
|
||||
}
|
||||
if (error < 0) {
|
||||
git_buf_free(&buf);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if ((error = git_config__update_entry(
|
||||
cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
|
||||
goto on_error;
|
||||
if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
|
||||
goto on_error;
|
||||
if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* What action to take depends on the old and new values. This
|
||||
@ -561,31 +550,26 @@ int git_remote_save(const git_remote *remote)
|
||||
*/
|
||||
|
||||
git_buf_clear(&buf);
|
||||
if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
|
||||
goto on_error;
|
||||
if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
|
||||
if (error < 0 && error != GIT_ENOTFOUND)
|
||||
goto on_error;
|
||||
if ((error = git_config__lookup_entry(
|
||||
&existing, cfg, git_buf_cstr(&buf), false)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
|
||||
if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
|
||||
goto on_error;
|
||||
} else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
|
||||
if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
|
||||
goto on_error;
|
||||
} else if (tagopt) {
|
||||
if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
|
||||
goto on_error;
|
||||
}
|
||||
if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
|
||||
tagopt = "--tags";
|
||||
else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
|
||||
tagopt = "--no-tags";
|
||||
else if (existing != NULL)
|
||||
tagopt = NULL;
|
||||
|
||||
error = git_config__update_entry(
|
||||
cfg, git_buf_cstr(&buf), tagopt, true, false);
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&buf);
|
||||
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
git_buf_free(&buf);
|
||||
return -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
const char *git_remote_name(const git_remote *remote)
|
||||
|
@ -93,6 +93,7 @@ void git_repository__cleanup(git_repository *repo)
|
||||
|
||||
git_cache_clear(&repo->objects);
|
||||
git_attr_cache_flush(repo);
|
||||
git_submodule_cache_free(repo);
|
||||
|
||||
set_config(repo, NULL);
|
||||
set_index(repo, NULL);
|
||||
@ -108,7 +109,6 @@ void git_repository_free(git_repository *repo)
|
||||
git_repository__cleanup(repo);
|
||||
|
||||
git_cache_free(&repo->objects);
|
||||
git_submodule_config_free(repo);
|
||||
|
||||
git_diff_driver_registry_free(repo->diff_drivers);
|
||||
repo->diff_drivers = NULL;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "buffer.h"
|
||||
#include "object.h"
|
||||
#include "attrcache.h"
|
||||
#include "strmap.h"
|
||||
#include "submodule.h"
|
||||
#include "diff_driver.h"
|
||||
|
||||
#define DOT_GIT ".git"
|
||||
@ -105,10 +105,10 @@ struct git_repository {
|
||||
git_refdb *_refdb;
|
||||
git_config *_config;
|
||||
git_index *_index;
|
||||
git_submodule_cache *_submodules;
|
||||
|
||||
git_cache objects;
|
||||
git_attr_cache attrcache;
|
||||
git_strmap *submodules;
|
||||
git_diff_driver_registry *diff_drivers;
|
||||
|
||||
char *path_repository;
|
||||
@ -149,11 +149,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo);
|
||||
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar);
|
||||
void git_repository__cvar_cache_clear(git_repository *repo);
|
||||
|
||||
/*
|
||||
* Submodule cache
|
||||
*/
|
||||
extern void git_submodule_config_free(git_repository *repo);
|
||||
|
||||
GIT_INLINE(int) git_repository__ensure_not_bare(
|
||||
git_repository *repo,
|
||||
const char *operation_name)
|
||||
|
958
src/submodule.c
958
src/submodule.c
File diff suppressed because it is too large
Load Diff
@ -99,6 +99,29 @@ struct git_submodule {
|
||||
git_oid wd_oid;
|
||||
};
|
||||
|
||||
/**
|
||||
* The git_submodule_cache stores known submodules along with timestamps,
|
||||
* etc. about when they were loaded
|
||||
*/
|
||||
typedef struct {
|
||||
git_repository *repo;
|
||||
git_strmap *submodules;
|
||||
git_mutex lock;
|
||||
|
||||
/* cache invalidation data */
|
||||
git_oid head_id;
|
||||
git_futils_filestamp index_stamp;
|
||||
git_buf gitmodules_path;
|
||||
git_futils_filestamp gitmodules_stamp;
|
||||
git_futils_filestamp config_stamp;
|
||||
} git_submodule_cache;
|
||||
|
||||
/* Force revalidation of submodule data cache (alloc as needed) */
|
||||
extern int git_submodule_cache_refresh(git_repository *repo);
|
||||
|
||||
/* Release all submodules */
|
||||
extern void git_submodule_cache_free(git_repository *repo);
|
||||
|
||||
/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
|
||||
enum {
|
||||
GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
|
||||
@ -111,17 +134,16 @@ enum {
|
||||
GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
|
||||
};
|
||||
|
||||
#define GIT_SUBMODULE_STATUS__ALL_WD_FLAGS \
|
||||
(GIT_SUBMODULE_STATUS_IN_WD | \
|
||||
GIT_SUBMODULE_STATUS__WD_OID_VALID | \
|
||||
GIT_SUBMODULE_STATUS__WD_FLAGS)
|
||||
|
||||
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
|
||||
((S) & ~(0xFFFFFFFFu << 20))
|
||||
|
||||
/* Internal submodule check does not attempt to refresh cached data */
|
||||
extern bool git_submodule__is_submodule(git_repository *repo, const char *name);
|
||||
|
||||
/* Internal lookup does not attempt to refresh cached data */
|
||||
extern int git_submodule__lookup(
|
||||
git_submodule **out, git_repository *repo, const char *path);
|
||||
|
||||
/* Internal status fn returns status and optionally the various OIDs */
|
||||
extern int git_submodule__status(
|
||||
unsigned int *out_status,
|
||||
@ -143,5 +165,6 @@ extern int git_submodule_parse_update(
|
||||
|
||||
extern const char *git_submodule_ignore_to_str(git_submodule_ignore_t);
|
||||
extern const char *git_submodule_update_to_str(git_submodule_update_t);
|
||||
extern const char *git_submodule_recurse_to_str(git_submodule_recurse_t);
|
||||
|
||||
#endif
|
||||
|
@ -54,7 +54,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
|
||||
bytes = src->length * sizeof(void *);
|
||||
|
||||
v->_alloc_size = src->length;
|
||||
v->_cmp = cmp;
|
||||
v->_cmp = cmp ? cmp : src->_cmp;
|
||||
v->length = src->length;
|
||||
v->flags = src->flags;
|
||||
if (cmp != src->_cmp)
|
||||
|
@ -599,6 +599,38 @@ void test_core_buffer__10(void)
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
||||
void test_core_buffer__join3(void)
|
||||
{
|
||||
git_buf a = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_buf_join3(&a, '/', "test", "string", "join"));
|
||||
cl_assert_equal_s("test/string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "test/", "string", "join"));
|
||||
cl_assert_equal_s("test/string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string", "join"));
|
||||
cl_assert_equal_s("test/string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "join"));
|
||||
cl_assert_equal_s("test/string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "/join"));
|
||||
cl_assert_equal_s("test/string/join", a.ptr);
|
||||
|
||||
cl_git_pass(git_buf_join3(&a, '/', "", "string", "join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "/join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
|
||||
cl_git_pass(git_buf_join3(&a, '/', "string", "", "join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "/join"));
|
||||
cl_assert_equal_s("string/join", a.ptr);
|
||||
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
||||
void test_core_buffer__11(void)
|
||||
{
|
||||
git_buf a = GIT_BUF_INIT;
|
||||
|
@ -131,8 +131,6 @@ void test_diff_submodules__dirty_submodule_2(void)
|
||||
|
||||
g_repo = setup_fixture_submodules();
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
||||
|
||||
opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
|
||||
GIT_DIFF_SHOW_UNTRACKED_CONTENT |
|
||||
GIT_DIFF_RECURSE_UNTRACKED_DIRS |
|
||||
@ -165,8 +163,6 @@ void test_diff_submodules__dirty_submodule_2(void)
|
||||
|
||||
git_diff_free(diff);
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
check_diff_patches(diff, expected_dirty);
|
||||
git_diff_free(diff);
|
||||
@ -299,7 +295,6 @@ void test_diff_submodules__invalid_cache(void)
|
||||
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
||||
cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
|
117
tests/submodule/add.c
Normal file
117
tests/submodule/add.c
Normal file
@ -0,0 +1,117 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "posix.h"
|
||||
#include "path.h"
|
||||
#include "submodule_helpers.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
void test_submodule_add__cleanup(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
static void assert_submodule_url(const char* name, const char *url)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *s;
|
||||
git_buf key = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
|
||||
cl_git_pass(git_buf_printf(&key, "submodule.%s.url", name));
|
||||
cl_git_pass(git_config_get_string(&s, cfg, git_buf_cstr(&key)));
|
||||
cl_assert_equal_s(s, url);
|
||||
|
||||
git_config_free(cfg);
|
||||
git_buf_free(&key);
|
||||
}
|
||||
|
||||
void test_submodule_add__url_absolute(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
|
||||
g_repo = setup_fixture_submod2();
|
||||
|
||||
/* re-add existing submodule */
|
||||
cl_git_fail_with(
|
||||
GIT_EEXISTS,
|
||||
git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1));
|
||||
|
||||
/* add a submodule using a gitlink */
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_libgit2", 1)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_assert(git_path_isfile("submod2/" "sm_libgit2" "/.git"));
|
||||
|
||||
cl_assert(git_path_isdir("submod2/.git/modules"));
|
||||
cl_assert(git_path_isdir("submod2/.git/modules/" "sm_libgit2"));
|
||||
cl_assert(git_path_isfile("submod2/.git/modules/" "sm_libgit2" "/HEAD"));
|
||||
assert_submodule_url("sm_libgit2", "https://github.com/libgit2/libgit2.git");
|
||||
|
||||
/* add a submodule not using a gitlink */
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_libgit2b", 0)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_assert(git_path_isdir("submod2/" "sm_libgit2b" "/.git"));
|
||||
cl_assert(git_path_isfile("submod2/" "sm_libgit2b" "/.git/HEAD"));
|
||||
cl_assert(!git_path_exists("submod2/.git/modules/" "sm_libgit2b"));
|
||||
assert_submodule_url("sm_libgit2b", "https://github.com/libgit2/libgit2.git");
|
||||
}
|
||||
|
||||
void test_submodule_add__url_relative(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_remote *remote;
|
||||
|
||||
/* default remote url is https://github.com/libgit2/false.git */
|
||||
g_repo = cl_git_sandbox_init("testrepo2");
|
||||
|
||||
/* make sure we don't default to origin - rename origin -> test_remote */
|
||||
cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
|
||||
cl_git_pass(git_remote_rename(remote, "test_remote", NULL, NULL));
|
||||
cl_git_fail(git_remote_load(&remote, g_repo, "origin"));
|
||||
git_remote_free(remote);
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, "../TestGitRepository", "TestGitRepository", 1)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
assert_submodule_url("TestGitRepository", "https://github.com/libgit2/TestGitRepository");
|
||||
}
|
||||
|
||||
void test_submodule_add__url_relative_to_origin(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
|
||||
/* default remote url is https://github.com/libgit2/false.git */
|
||||
g_repo = cl_git_sandbox_init("testrepo2");
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, "../TestGitRepository", "TestGitRepository", 1)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
assert_submodule_url("TestGitRepository", "https://github.com/libgit2/TestGitRepository");
|
||||
}
|
||||
|
||||
void test_submodule_add__url_relative_to_workdir(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
|
||||
/* In this repo, HEAD (master) has no remote tracking branc h*/
|
||||
g_repo = cl_git_sandbox_init("testrepo");
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, "./", "TestGitRepository", 1)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
assert_submodule_url("TestGitRepository", git_repository_workdir(g_repo));
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "submodule_helpers.h"
|
||||
#include "posix.h"
|
||||
#include "git2/sys/repository.h"
|
||||
#include "fileops.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
@ -115,13 +115,7 @@ void test_submodule_lookup__lookup_even_with_unborn_head(void)
|
||||
&head, g_repo, "HEAD", "refs/heads/garbage", 1, NULL, NULL));
|
||||
git_reference_free(head);
|
||||
|
||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
||||
test_submodule_lookup__simple_lookup(); /* baseline should still pass */
|
||||
}
|
||||
|
||||
void test_submodule_lookup__lookup_even_with_missing_index(void)
|
||||
@ -133,44 +127,145 @@ void test_submodule_lookup__lookup_even_with_missing_index(void)
|
||||
git_repository_set_index(g_repo, idx);
|
||||
git_index_free(idx);
|
||||
|
||||
test_submodule_lookup__simple_lookup(); /* baseline should still pass */
|
||||
}
|
||||
|
||||
static void baseline_tests(void)
|
||||
{
|
||||
/* small baseline that should work even if we change the index or make
|
||||
* commits from the index
|
||||
*/
|
||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
||||
}
|
||||
|
||||
static void add_submodule_with_commit(const char *name)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_repository *smrepo;
|
||||
git_index *idx;
|
||||
git_buf p = GIT_BUF_INIT;
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||
"https://github.com/libgit2/libgit2.git", name, 1));
|
||||
|
||||
assert_submodule_exists(g_repo, name);
|
||||
|
||||
cl_git_pass(git_submodule_open(&smrepo, sm));
|
||||
cl_git_pass(git_repository_index(&idx, smrepo));
|
||||
|
||||
cl_git_pass(git_buf_joinpath(&p, git_repository_workdir(smrepo), "file"));
|
||||
cl_git_mkfile(p.ptr, "new file");
|
||||
git_buf_free(&p);
|
||||
|
||||
cl_git_pass(git_index_add_bypath(idx, "file"));
|
||||
cl_git_pass(git_index_write(idx));
|
||||
git_index_free(idx);
|
||||
|
||||
cl_repo_commit_from_index(NULL, smrepo, NULL, 0, "initial commit");
|
||||
git_repository_free(smrepo);
|
||||
|
||||
cl_git_pass(git_submodule_add_finalize(sm));
|
||||
|
||||
git_submodule_free(sm);
|
||||
}
|
||||
|
||||
void test_submodule_lookup__just_added(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_buf snap1 = GIT_BUF_INIT, snap2 = GIT_BUF_INIT;
|
||||
git_reference *original_head = NULL;
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_just_added", 1));
|
||||
refute_submodule_exists(g_repo, "sm_just_added", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "sm_just_added_2", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "sm_just_added_idx", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "sm_just_added_head", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||
baseline_tests();
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&snap1, "submod2/.gitmodules"));
|
||||
cl_git_pass(git_repository_head(&original_head, g_repo));
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||
"https://github.com/libgit2/libgit2.git", "sm_just_added", 1));
|
||||
git_submodule_free(sm);
|
||||
assert_submodule_exists(g_repo, "sm_just_added");
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_just_added_2", 1));
|
||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||
"https://github.com/libgit2/libgit2.git", "sm_just_added_2", 1));
|
||||
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||
cl_git_fail(git_submodule_add_finalize(sm)); /* fails if no HEAD */
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_git_append2file("submod2/.gitmodules", "\n[submodule \"mismatch_name\"]\n\tpath = mismatch_path\n\turl = https://example.com/example.git\n\n");
|
||||
add_submodule_with_commit("sm_just_added_head");
|
||||
cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "commit new sm to head");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
||||
add_submodule_with_commit("sm_just_added_idx");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&snap2, "submod2/.gitmodules"));
|
||||
|
||||
cl_git_append2file(
|
||||
"submod2/.gitmodules",
|
||||
"\n[submodule \"mismatch_name\"]\n"
|
||||
"\tpath = mismatch_path\n"
|
||||
"\turl = https://example.com/example.git\n\n");
|
||||
|
||||
assert_submodule_exists(g_repo, "mismatch_name");
|
||||
assert_submodule_exists(g_repo, "mismatch_path");
|
||||
|
||||
assert_submodule_exists(g_repo, "sm_just_added");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||
baseline_tests();
|
||||
|
||||
/* all the regular ones should still be working right, too */
|
||||
cl_git_rewritefile("submod2/.gitmodules", snap2.ptr);
|
||||
git_buf_free(&snap2);
|
||||
|
||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||
assert_submodule_exists(g_repo, "sm_just_added");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||
baseline_tests();
|
||||
|
||||
cl_git_rewritefile("submod2/.gitmodules", snap1.ptr);
|
||||
git_buf_free(&snap1);
|
||||
|
||||
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||
/* note error code change, because add_setup made a repo in the workdir */
|
||||
refute_submodule_exists(g_repo, "sm_just_added", GIT_EEXISTS);
|
||||
refute_submodule_exists(g_repo, "sm_just_added_2", GIT_EEXISTS);
|
||||
/* these still exist in index and head respectively */
|
||||
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||
baseline_tests();
|
||||
|
||||
{
|
||||
git_index *idx;
|
||||
cl_git_pass(git_repository_index(&idx, g_repo));
|
||||
cl_git_pass(git_index_remove_bypath(idx, "sm_just_added_idx"));
|
||||
cl_git_pass(git_index_remove_bypath(idx, "sm_just_added_head"));
|
||||
cl_git_pass(git_index_write(idx));
|
||||
git_index_free(idx);
|
||||
}
|
||||
|
||||
refute_submodule_exists(g_repo, "sm_just_added_idx", GIT_EEXISTS);
|
||||
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||
|
||||
{
|
||||
git_signature *sig;
|
||||
cl_git_pass(git_signature_now(&sig, "resetter", "resetter@email.com"));
|
||||
cl_git_pass(git_reference_create(NULL, g_repo, "refs/heads/master", git_reference_target(original_head), 1, sig, "move head back"));
|
||||
git_signature_free(sig);
|
||||
git_reference_free(original_head);
|
||||
}
|
||||
|
||||
refute_submodule_exists(g_repo, "sm_just_added_head", GIT_EEXISTS);
|
||||
}
|
||||
|
||||
|
@ -7,61 +7,12 @@ static git_repository *g_repo = NULL;
|
||||
|
||||
#define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git"
|
||||
#define SM_LIBGIT2 "sm_libgit2"
|
||||
#define SM_LIBGIT2B "sm_libgit2b"
|
||||
|
||||
void test_submodule_modify__initialize(void)
|
||||
{
|
||||
g_repo = setup_fixture_submod2();
|
||||
}
|
||||
|
||||
void test_submodule_modify__add(void)
|
||||
{
|
||||
git_submodule *sm;
|
||||
git_config *cfg;
|
||||
const char *s;
|
||||
|
||||
/* re-add existing submodule */
|
||||
cl_assert_equal_i(
|
||||
GIT_EEXISTS,
|
||||
git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1));
|
||||
|
||||
/* add a submodule using a gitlink */
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git"));
|
||||
|
||||
cl_assert(git_path_isdir("submod2/.git/modules"));
|
||||
cl_assert(git_path_isdir("submod2/.git/modules/" SM_LIBGIT2));
|
||||
cl_assert(git_path_isfile("submod2/.git/modules/" SM_LIBGIT2 "/HEAD"));
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(
|
||||
git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2 ".url"));
|
||||
cl_assert_equal_s(s, SM_LIBGIT2_URL);
|
||||
git_config_free(cfg);
|
||||
|
||||
/* add a submodule not using a gitlink */
|
||||
|
||||
cl_git_pass(
|
||||
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0)
|
||||
);
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git"));
|
||||
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD"));
|
||||
cl_assert(!git_path_exists("submod2/.git/modules/" SM_LIBGIT2B));
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(
|
||||
git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2B ".url"));
|
||||
cl_assert_equal_s(s, SM_LIBGIT2_URL);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int delete_one_config(const git_config_entry *entry, void *payload)
|
||||
{
|
||||
git_config *cfg = payload;
|
||||
@ -118,6 +69,26 @@ static int sync_one_submodule(
|
||||
return git_submodule_sync(sm);
|
||||
}
|
||||
|
||||
static void assert_submodule_url_is_synced(
|
||||
git_submodule *sm, const char *parent_key, const char *child_key)
|
||||
{
|
||||
git_config *cfg;
|
||||
const char *str;
|
||||
git_repository *smrepo;
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(git_config_get_string(&str, cfg, parent_key));
|
||||
cl_assert_equal_s(git_submodule_url(sm), str);
|
||||
git_config_free(cfg);
|
||||
|
||||
cl_git_pass(git_submodule_open(&smrepo, sm));
|
||||
cl_git_pass(git_repository_config(&cfg, smrepo));
|
||||
cl_git_pass(git_config_get_string(&str, cfg, child_key));
|
||||
cl_assert_equal_s(git_submodule_url(sm), str);
|
||||
git_config_free(cfg);
|
||||
git_repository_free(smrepo);
|
||||
}
|
||||
|
||||
void test_submodule_modify__sync(void)
|
||||
{
|
||||
git_submodule *sm1, *sm2, *sm3;
|
||||
@ -153,14 +124,12 @@ void test_submodule_modify__sync(void)
|
||||
cl_git_pass(git_submodule_foreach(g_repo, sync_one_submodule, NULL));
|
||||
|
||||
/* check that submodule config is updated */
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url"));
|
||||
cl_assert_equal_s(git_submodule_url(sm1), str);
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url"));
|
||||
cl_assert_equal_s(git_submodule_url(sm2), str);
|
||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url"));
|
||||
cl_assert_equal_s(git_submodule_url(sm3), str);
|
||||
git_config_free(cfg);
|
||||
assert_submodule_url_is_synced(
|
||||
sm1, "submodule."SM1".url", "branch.origin.remote");
|
||||
assert_submodule_url_is_synced(
|
||||
sm2, "submodule."SM2".url", "branch.origin.remote");
|
||||
assert_submodule_url_is_synced(
|
||||
sm3, "submodule."SM3".url", "branch.origin.remote");
|
||||
|
||||
git_submodule_free(sm1);
|
||||
git_submodule_free(sm2);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "clar_libgit2.h"
|
||||
#include "posix.h"
|
||||
#include "fileops.h"
|
||||
|
||||
void test_submodule_nosubs__cleanup(void)
|
||||
{
|
||||
@ -68,7 +69,10 @@ void test_submodule_nosubs__reload_add_reload(void)
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(repo, 0));
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
||||
/* try one add with a reload (to make sure no errors happen) */
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, repo,
|
||||
"https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
||||
|
||||
cl_git_pass(git_submodule_reload_all(repo, 0));
|
||||
|
||||
@ -78,6 +82,17 @@ void test_submodule_nosubs__reload_add_reload(void)
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||
git_submodule_free(sm);
|
||||
|
||||
/* try one add without a reload (to make sure cache inval works, too) */
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(&sm, repo,
|
||||
"https://github.com/libgit2/libgit2.git", "libgit2-again", 1));
|
||||
cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2-again"));
|
||||
cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
|
||||
git_submodule_free(sm);
|
||||
}
|
||||
|
||||
void test_submodule_nosubs__bad_gitmodules(void)
|
||||
@ -93,3 +108,69 @@ void test_submodule_nosubs__bad_gitmodules(void)
|
||||
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));
|
||||
}
|
||||
|
||||
void test_submodule_nosubs__add_and_delete(void)
|
||||
{
|
||||
git_repository *repo = cl_git_sandbox_init("status");
|
||||
git_submodule *sm;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
/* note lack of calls to git_submodule_reload_all - this *should* work */
|
||||
|
||||
cl_git_fail(git_submodule_lookup(NULL, repo, "libgit2"));
|
||||
cl_git_fail(git_submodule_lookup(NULL, repo, "submodules/libgit2"));
|
||||
|
||||
/* create */
|
||||
|
||||
cl_git_pass(git_submodule_add_setup(
|
||||
&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||
git_submodule_free(sm);
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&buf, "status/.gitmodules"));
|
||||
cl_assert(strstr(buf.ptr, "[submodule \"submodules/libgit2\"]") != NULL);
|
||||
cl_assert(strstr(buf.ptr, "path = submodules/libgit2") != NULL);
|
||||
git_buf_free(&buf);
|
||||
|
||||
/* lookup */
|
||||
|
||||
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||
git_submodule_free(sm);
|
||||
|
||||
/* update name */
|
||||
|
||||
cl_git_rewritefile(
|
||||
"status/.gitmodules",
|
||||
"[submodule \"libgit2\"]\n"
|
||||
" path = submodules/libgit2\n"
|
||||
" url = https://github.com/libgit2/libgit2.git\n");
|
||||
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||
cl_assert_equal_s("libgit2", git_submodule_name(sm));
|
||||
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||
git_submodule_free(sm);
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||
git_submodule_free(sm);
|
||||
|
||||
/* revert name update */
|
||||
|
||||
cl_git_rewritefile(
|
||||
"status/.gitmodules",
|
||||
"[submodule \"submodules/libgit2\"]\n"
|
||||
" path = submodules/libgit2\n"
|
||||
" url = https://github.com/libgit2/libgit2.git\n");
|
||||
|
||||
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||
git_submodule_free(sm);
|
||||
|
||||
/* remove completely */
|
||||
|
||||
cl_must_pass(p_unlink("status/.gitmodules"));
|
||||
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||
cl_git_fail(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||
}
|
||||
|
@ -126,20 +126,26 @@ git_repository *setup_fixture_submod2(void)
|
||||
return repo;
|
||||
}
|
||||
|
||||
void assert_submodule_exists(git_repository *repo, const char *name)
|
||||
void assert__submodule_exists(
|
||||
git_repository *repo, const char *name,
|
||||
const char *msg, const char *file, int line)
|
||||
{
|
||||
git_submodule *sm;
|
||||
cl_git_pass(git_submodule_lookup(&sm, repo, name));
|
||||
cl_assert(sm);
|
||||
int error = git_submodule_lookup(&sm, repo, name);
|
||||
if (error)
|
||||
cl_git_report_failure(error, file, line, msg);
|
||||
cl_assert_at_line(sm != NULL, file, line);
|
||||
git_submodule_free(sm);
|
||||
}
|
||||
|
||||
void refute_submodule_exists(
|
||||
git_repository *repo, const char *name, int expected_error)
|
||||
void refute__submodule_exists(
|
||||
git_repository *repo, const char *name, int expected_error,
|
||||
const char *msg, const char *file, int line)
|
||||
{
|
||||
git_submodule *sm;
|
||||
cl_assert_equal_i(
|
||||
expected_error, git_submodule_lookup(&sm, repo, name));
|
||||
clar__assert_equal(
|
||||
file, line, msg, 1, "%i",
|
||||
expected_error, (int)(git_submodule_lookup(&sm, repo, name)));
|
||||
}
|
||||
|
||||
unsigned int get_submodule_status(git_repository *repo, const char *name)
|
||||
@ -154,3 +160,19 @@ unsigned int get_submodule_status(git_repository *repo, const char *name)
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int print_submodules(git_submodule *sm, const char *name, void *p)
|
||||
{
|
||||
unsigned int loc = 0;
|
||||
GIT_UNUSED(p);
|
||||
git_submodule_location(&loc, sm);
|
||||
fprintf(stderr, "# submodule %s (at %s) flags %x\n",
|
||||
name, git_submodule_path(sm), loc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_submodules(git_repository *repo)
|
||||
{
|
||||
git_submodule_foreach(repo, print_submodules, NULL);
|
||||
}
|
||||
|
||||
|
@ -6,5 +6,16 @@ extern git_repository *setup_fixture_submod2(void);
|
||||
|
||||
extern unsigned int get_submodule_status(git_repository *, const char *);
|
||||
|
||||
extern void assert_submodule_exists(git_repository *, const char *);
|
||||
extern void refute_submodule_exists(git_repository *, const char *, int err);
|
||||
extern void assert__submodule_exists(
|
||||
git_repository *, const char *, const char *, const char *, int);
|
||||
|
||||
#define assert_submodule_exists(repo,name) \
|
||||
assert__submodule_exists(repo, name, "git_submodule_lookup(" #name ") failed", __FILE__, __LINE__)
|
||||
|
||||
extern void refute__submodule_exists(
|
||||
git_repository *, const char *, int err, const char *, const char *, int);
|
||||
|
||||
#define refute_submodule_exists(repo,name,code) \
|
||||
refute__submodule_exists(repo, name, code, "expected git_submodule_lookup(" #name ") to fail with error " #code, __FILE__, __LINE__)
|
||||
|
||||
extern void dump_submodules(git_repository *repo);
|
||||
|
Loading…
Reference in New Issue
Block a user