mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 17:20:22 +00:00
Merge pull request #2866 from ethomson/checkout_perf2
Checkout performance
This commit is contained in:
commit
d24a5312d8
129
src/attr.c
129
src/attr.c
@ -29,6 +29,7 @@ git_attr_t git_attr_value(const char *attr)
|
|||||||
|
|
||||||
static int collect_attr_files(
|
static int collect_attr_files(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
const char *path,
|
const char *path,
|
||||||
git_vector *files);
|
git_vector *files);
|
||||||
@ -57,7 +58,7 @@ int git_attr_get(
|
|||||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
|
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
@ -90,9 +91,10 @@ typedef struct {
|
|||||||
git_attr_assignment *found;
|
git_attr_assignment *found;
|
||||||
} attr_get_many_info;
|
} attr_get_many_info;
|
||||||
|
|
||||||
int git_attr_get_many(
|
int git_attr_get_many_with_session(
|
||||||
const char **values,
|
const char **values,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
const char *pathname,
|
const char *pathname,
|
||||||
size_t num_attr,
|
size_t num_attr,
|
||||||
@ -115,7 +117,7 @@ int git_attr_get_many(
|
|||||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
|
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
info = git__calloc(num_attr, sizeof(attr_get_many_info));
|
info = git__calloc(num_attr, sizeof(attr_get_many_info));
|
||||||
@ -161,6 +163,17 @@ cleanup:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_attr_get_many(
|
||||||
|
const char **values,
|
||||||
|
git_repository *repo,
|
||||||
|
uint32_t flags,
|
||||||
|
const char *pathname,
|
||||||
|
size_t num_attr,
|
||||||
|
const char **names)
|
||||||
|
{
|
||||||
|
return git_attr_get_many_with_session(
|
||||||
|
values, repo, NULL, flags, pathname, num_attr, names);
|
||||||
|
}
|
||||||
|
|
||||||
int git_attr_foreach(
|
int git_attr_foreach(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
@ -183,7 +196,7 @@ int git_attr_foreach(
|
|||||||
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0 ||
|
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
|
||||||
(error = git_strmap_alloc(&seen)) < 0)
|
(error = git_strmap_alloc(&seen)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -219,6 +232,7 @@ cleanup:
|
|||||||
|
|
||||||
static int preload_attr_file(
|
static int preload_attr_file(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
const char *base,
|
const char *base,
|
||||||
const char *file)
|
const char *file)
|
||||||
@ -229,19 +243,61 @@ static int preload_attr_file(
|
|||||||
if (!file)
|
if (!file)
|
||||||
return 0;
|
return 0;
|
||||||
if (!(error = git_attr_cache__get(
|
if (!(error = git_attr_cache__get(
|
||||||
&preload, repo, source, base, file, git_attr_file__parse_buffer)))
|
&preload, repo, attr_session, source, base, file, git_attr_file__parse_buffer)))
|
||||||
git_attr_file__free(preload);
|
git_attr_file__free(preload);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int attr_setup(git_repository *repo)
|
static int system_attr_file(
|
||||||
|
git_buf *out,
|
||||||
|
git_attr_session *attr_session)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!attr_session) {
|
||||||
|
error = git_sysdir_find_system_file(out, GIT_ATTR_FILE_SYSTEM);
|
||||||
|
|
||||||
|
if (error == GIT_ENOTFOUND)
|
||||||
|
giterr_clear();
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attr_session->init_sysdir) {
|
||||||
|
error = git_sysdir_find_system_file(&attr_session->sysdir, GIT_ATTR_FILE_SYSTEM);
|
||||||
|
|
||||||
|
if (error == GIT_ENOTFOUND)
|
||||||
|
giterr_clear();
|
||||||
|
else if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
attr_session->init_sysdir = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr_session->sysdir.size == 0)
|
||||||
|
return GIT_ENOTFOUND;
|
||||||
|
|
||||||
|
/* We can safely provide a git_buf with no allocation (asize == 0) to
|
||||||
|
* a consumer. This allows them to treat this as a regular `git_buf`,
|
||||||
|
* but their call to `git_buf_free` will not attempt to free it.
|
||||||
|
*/
|
||||||
|
out->ptr = attr_session->sysdir.ptr;
|
||||||
|
out->size = attr_session->sysdir.size;
|
||||||
|
out->asize = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int attr_setup(git_repository *repo, git_attr_session *attr_session)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
const char *workdir = git_repository_workdir(repo);
|
const char *workdir = git_repository_workdir(repo);
|
||||||
git_index *idx = NULL;
|
git_index *idx = NULL;
|
||||||
git_buf sys = GIT_BUF_INIT;
|
git_buf sys = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
if (attr_session && attr_session->init_setup)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if ((error = git_attr_cache__init(repo)) < 0)
|
if ((error = git_attr_cache__init(repo)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -249,39 +305,39 @@ static int attr_setup(git_repository *repo)
|
|||||||
* definitions will be available for later file parsing
|
* definitions will be available for later file parsing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!(error = git_sysdir_find_system_file(&sys, GIT_ATTR_FILE_SYSTEM))) {
|
error = system_attr_file(&sys, attr_session);
|
||||||
|
|
||||||
|
if (error == 0)
|
||||||
error = preload_attr_file(
|
error = preload_attr_file(
|
||||||
repo, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
|
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
|
||||||
git_buf_free(&sys);
|
else if (error != GIT_ENOTFOUND)
|
||||||
}
|
return error;
|
||||||
if (error < 0) {
|
|
||||||
if (error == GIT_ENOTFOUND) {
|
git_buf_free(&sys);
|
||||||
giterr_clear();
|
|
||||||
error = 0;
|
|
||||||
} else
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((error = preload_attr_file(
|
if ((error = preload_attr_file(
|
||||||
repo, GIT_ATTR_FILE__FROM_FILE,
|
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
|
||||||
NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
|
NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if ((error = preload_attr_file(
|
if ((error = preload_attr_file(
|
||||||
repo, GIT_ATTR_FILE__FROM_FILE,
|
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
|
||||||
git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
|
git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (workdir != NULL &&
|
if (workdir != NULL &&
|
||||||
(error = preload_attr_file(
|
(error = preload_attr_file(
|
||||||
repo, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
|
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
|
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
|
||||||
(error = preload_attr_file(
|
(error = preload_attr_file(
|
||||||
repo, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
|
repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
if (attr_session)
|
||||||
|
attr_session->init_setup = 1;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,6 +377,7 @@ int git_attr_add_macro(
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
|
git_attr_session *attr_session;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
const char *workdir;
|
const char *workdir;
|
||||||
git_index *index;
|
git_index *index;
|
||||||
@ -356,6 +413,7 @@ static int attr_decide_sources(
|
|||||||
|
|
||||||
static int push_attr_file(
|
static int push_attr_file(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_vector *list,
|
git_vector *list,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
const char *base,
|
const char *base,
|
||||||
@ -364,8 +422,9 @@ static int push_attr_file(
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
git_attr_file *file = NULL;
|
git_attr_file *file = NULL;
|
||||||
|
|
||||||
error = git_attr_cache__get(
|
error = git_attr_cache__get(&file, repo, attr_session,
|
||||||
&file, repo, source, base, filename, git_attr_file__parse_buffer);
|
source, base, filename, git_attr_file__parse_buffer);
|
||||||
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -387,8 +446,8 @@ static int push_one_attr(void *ref, const char *path)
|
|||||||
info->flags, info->workdir != NULL, info->index != NULL, src);
|
info->flags, info->workdir != NULL, info->index != NULL, src);
|
||||||
|
|
||||||
for (i = 0; !error && i < n_src; ++i)
|
for (i = 0; !error && i < n_src; ++i)
|
||||||
error = push_attr_file(
|
error = push_attr_file(info->repo, info->attr_session,
|
||||||
info->repo, info->files, src[i], path, GIT_ATTR_FILE);
|
info->files, src[i], path, GIT_ATTR_FILE);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -407,6 +466,7 @@ static void release_attr_files(git_vector *files)
|
|||||||
|
|
||||||
static int collect_attr_files(
|
static int collect_attr_files(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
const char *path,
|
const char *path,
|
||||||
git_vector *files)
|
git_vector *files)
|
||||||
@ -416,7 +476,7 @@ static int collect_attr_files(
|
|||||||
const char *workdir = git_repository_workdir(repo);
|
const char *workdir = git_repository_workdir(repo);
|
||||||
attr_walk_up_info info = { NULL };
|
attr_walk_up_info info = { NULL };
|
||||||
|
|
||||||
if ((error = attr_setup(repo)) < 0)
|
if ((error = attr_setup(repo, attr_session)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
/* Resolve path in a non-bare repo */
|
/* Resolve path in a non-bare repo */
|
||||||
@ -435,12 +495,13 @@ static int collect_attr_files(
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
error = push_attr_file(
|
error = push_attr_file(
|
||||||
repo, files, GIT_ATTR_FILE__FROM_FILE,
|
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
|
||||||
git_repository_path(repo), GIT_ATTR_FILE_INREPO);
|
git_repository_path(repo), GIT_ATTR_FILE_INREPO);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
info.repo = repo;
|
info.repo = repo;
|
||||||
|
info.attr_session = attr_session;
|
||||||
info.flags = flags;
|
info.flags = flags;
|
||||||
info.workdir = workdir;
|
info.workdir = workdir;
|
||||||
if (git_repository_index__weakptr(&info.index, repo) < 0)
|
if (git_repository_index__weakptr(&info.index, repo) < 0)
|
||||||
@ -457,21 +518,21 @@ static int collect_attr_files(
|
|||||||
|
|
||||||
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
|
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
|
||||||
error = push_attr_file(
|
error = push_attr_file(
|
||||||
repo, files, GIT_ATTR_FILE__FROM_FILE,
|
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
|
||||||
NULL, git_repository_attr_cache(repo)->cfg_attr_file);
|
NULL, git_repository_attr_cache(repo)->cfg_attr_file);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
|
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
|
||||||
error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
|
error = system_attr_file(&dir, attr_session);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
error = push_attr_file(
|
error = push_attr_file(
|
||||||
repo, files, GIT_ATTR_FILE__FROM_FILE, NULL, dir.ptr);
|
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
|
||||||
else if (error == GIT_ENOTFOUND) {
|
NULL, dir.ptr);
|
||||||
giterr_clear();
|
else if (error == GIT_ENOTFOUND)
|
||||||
error = 0;
|
error = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -96,6 +96,7 @@ static int attr_file_oid_from_index(
|
|||||||
int git_attr_file__load(
|
int git_attr_file__load(
|
||||||
git_attr_file **out,
|
git_attr_file **out,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_entry *entry,
|
git_attr_file_entry *entry,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
git_attr_file_parser parser)
|
git_attr_file_parser parser)
|
||||||
@ -105,6 +106,7 @@ int git_attr_file__load(
|
|||||||
git_buf content = GIT_BUF_INIT;
|
git_buf content = GIT_BUF_INIT;
|
||||||
git_attr_file *file;
|
git_attr_file *file;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
bool nonexistent = false;
|
||||||
|
|
||||||
*out = NULL;
|
*out = NULL;
|
||||||
|
|
||||||
@ -127,22 +129,16 @@ int git_attr_file__load(
|
|||||||
case GIT_ATTR_FILE__FROM_FILE: {
|
case GIT_ATTR_FILE__FROM_FILE: {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (p_stat(entry->fullpath, &st) < 0)
|
/* For open or read errors, pretend that we got ENOTFOUND. */
|
||||||
return git_path_set_error(errno, entry->fullpath, "stat");
|
|
||||||
if (S_ISDIR(st.st_mode))
|
|
||||||
return GIT_ENOTFOUND;
|
|
||||||
|
|
||||||
/* For open or read errors, return ENOTFOUND to skip item */
|
|
||||||
/* TODO: issue warning when warning API is available */
|
/* TODO: issue warning when warning API is available */
|
||||||
|
|
||||||
if ((fd = git_futils_open_ro(entry->fullpath)) < 0)
|
if (p_stat(entry->fullpath, &st) < 0 ||
|
||||||
return GIT_ENOTFOUND;
|
S_ISDIR(st.st_mode) ||
|
||||||
|
(fd = git_futils_open_ro(entry->fullpath)) < 0 ||
|
||||||
error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size);
|
(error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0)
|
||||||
p_close(fd);
|
nonexistent = true;
|
||||||
|
else
|
||||||
if (error < 0)
|
p_close(fd);
|
||||||
return GIT_ENOTFOUND;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -154,13 +150,21 @@ int git_attr_file__load(
|
|||||||
if ((error = git_attr_file__new(&file, entry, source)) < 0)
|
if ((error = git_attr_file__new(&file, entry, source)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
/* store the key of the attr_reader; don't bother with cache
|
||||||
|
* invalidation during the same attr reader session.
|
||||||
|
*/
|
||||||
|
if (attr_session)
|
||||||
|
file->session_key = attr_session->key;
|
||||||
|
|
||||||
if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) {
|
if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) {
|
||||||
git_attr_file__free(file);
|
git_attr_file__free(file);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write cache breaker */
|
/* write cache breakers */
|
||||||
if (source == GIT_ATTR_FILE__FROM_INDEX)
|
if (nonexistent)
|
||||||
|
file->nonexistent = 1;
|
||||||
|
else if (source == GIT_ATTR_FILE__FROM_INDEX)
|
||||||
git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
|
git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
|
||||||
else if (source == GIT_ATTR_FILE__FROM_FILE)
|
else if (source == GIT_ATTR_FILE__FROM_FILE)
|
||||||
git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
|
git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
|
||||||
@ -175,11 +179,22 @@ cleanup:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_attr_file__out_of_date(git_repository *repo, git_attr_file *file)
|
int git_attr_file__out_of_date(
|
||||||
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
|
git_attr_file *file)
|
||||||
{
|
{
|
||||||
if (!file)
|
if (!file)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* we are never out of date if we just created this data in the same
|
||||||
|
* attr_session; otherwise, nonexistent files must be invalidated
|
||||||
|
*/
|
||||||
|
if (attr_session && attr_session->key == file->session_key)
|
||||||
|
return 0;
|
||||||
|
else if (file->nonexistent)
|
||||||
|
return 1;
|
||||||
|
|
||||||
switch (file->source) {
|
switch (file->source) {
|
||||||
case GIT_ATTR_FILE__IN_MEMORY:
|
case GIT_ATTR_FILE__IN_MEMORY:
|
||||||
return 0;
|
return 0;
|
||||||
@ -831,3 +846,22 @@ void git_attr_rule__free(git_attr_rule *rule)
|
|||||||
git__free(rule);
|
git__free(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_attr_session__init(git_attr_session *session, git_repository *repo)
|
||||||
|
{
|
||||||
|
assert(repo);
|
||||||
|
|
||||||
|
session->key = git_atomic_inc(&repo->attr_session_key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_attr_session__free(git_attr_session *session)
|
||||||
|
{
|
||||||
|
if (!session)
|
||||||
|
return;
|
||||||
|
|
||||||
|
git_buf_free(&session->sysdir);
|
||||||
|
git_buf_free(&session->tmp);
|
||||||
|
|
||||||
|
memset(session, 0, sizeof(git_attr_session));
|
||||||
|
}
|
||||||
|
@ -38,11 +38,11 @@
|
|||||||
GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
|
GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GIT_ATTR_FILE__IN_MEMORY = 0,
|
GIT_ATTR_FILE__IN_MEMORY = 0,
|
||||||
GIT_ATTR_FILE__FROM_FILE = 1,
|
GIT_ATTR_FILE__FROM_FILE = 1,
|
||||||
GIT_ATTR_FILE__FROM_INDEX = 2,
|
GIT_ATTR_FILE__FROM_INDEX = 2,
|
||||||
|
|
||||||
GIT_ATTR_FILE_NUM_SOURCES = 3
|
GIT_ATTR_FILE_NUM_SOURCES = 3
|
||||||
} git_attr_file_source;
|
} git_attr_file_source;
|
||||||
|
|
||||||
extern const char *git_attr__true;
|
extern const char *git_attr__true;
|
||||||
@ -84,6 +84,8 @@ typedef struct {
|
|||||||
git_attr_file_source source;
|
git_attr_file_source source;
|
||||||
git_vector rules; /* vector of <rule*> or <fnmatch*> */
|
git_vector rules; /* vector of <rule*> or <fnmatch*> */
|
||||||
git_pool pool;
|
git_pool pool;
|
||||||
|
unsigned int nonexistent:1;
|
||||||
|
int session_key;
|
||||||
union {
|
union {
|
||||||
git_oid oid;
|
git_oid oid;
|
||||||
git_futils_filestamp stamp;
|
git_futils_filestamp stamp;
|
||||||
@ -96,11 +98,6 @@ struct git_attr_file_entry {
|
|||||||
char fullpath[GIT_FLEX_ARRAY];
|
char fullpath[GIT_FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*git_attr_file_parser)(
|
|
||||||
git_repository *repo,
|
|
||||||
git_attr_file *file,
|
|
||||||
const char *data);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
git_buf full;
|
git_buf full;
|
||||||
char *path;
|
char *path;
|
||||||
@ -108,6 +105,35 @@ typedef struct {
|
|||||||
int is_dir;
|
int is_dir;
|
||||||
} git_attr_path;
|
} git_attr_path;
|
||||||
|
|
||||||
|
/* A git_attr_session can provide an "instance" of reading, to prevent cache
|
||||||
|
* invalidation during a single operation instance (like checkout).
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int key;
|
||||||
|
unsigned int init_setup:1,
|
||||||
|
init_sysdir:1;
|
||||||
|
git_buf sysdir;
|
||||||
|
git_buf tmp;
|
||||||
|
} git_attr_session;
|
||||||
|
|
||||||
|
extern int git_attr_session__init(git_attr_session *attr_session, git_repository *repo);
|
||||||
|
extern void git_attr_session__free(git_attr_session *session);
|
||||||
|
|
||||||
|
extern int git_attr_get_many_with_session(
|
||||||
|
const char **values_out,
|
||||||
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
|
uint32_t flags,
|
||||||
|
const char *path,
|
||||||
|
size_t num_attr,
|
||||||
|
const char **names);
|
||||||
|
|
||||||
|
typedef int (*git_attr_file_parser)(
|
||||||
|
git_repository *repo,
|
||||||
|
git_attr_file *file,
|
||||||
|
const char *data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* git_attr_file API
|
* git_attr_file API
|
||||||
*/
|
*/
|
||||||
@ -122,6 +148,7 @@ void git_attr_file__free(git_attr_file *file);
|
|||||||
int git_attr_file__load(
|
int git_attr_file__load(
|
||||||
git_attr_file **out,
|
git_attr_file **out,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_entry *ce,
|
git_attr_file_entry *ce,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
git_attr_file_parser parser);
|
git_attr_file_parser parser);
|
||||||
@ -130,7 +157,7 @@ int git_attr_file__load_standalone(
|
|||||||
git_attr_file **out, const char *path);
|
git_attr_file **out, const char *path);
|
||||||
|
|
||||||
int git_attr_file__out_of_date(
|
int git_attr_file__out_of_date(
|
||||||
git_repository *repo, git_attr_file *file);
|
git_repository *repo, git_attr_session *session, git_attr_file *file);
|
||||||
|
|
||||||
int git_attr_file__parse_buffer(
|
int git_attr_file__parse_buffer(
|
||||||
git_repository *repo, git_attr_file *attrs, const char *data);
|
git_repository *repo, git_attr_file *attrs, const char *data);
|
||||||
|
@ -149,6 +149,7 @@ static int attr_cache_lookup(
|
|||||||
git_attr_file **out_file,
|
git_attr_file **out_file,
|
||||||
git_attr_file_entry **out_entry,
|
git_attr_file_entry **out_entry,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
const char *base,
|
const char *base,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
@ -162,9 +163,12 @@ static int attr_cache_lookup(
|
|||||||
|
|
||||||
/* join base and path as needed */
|
/* join base and path as needed */
|
||||||
if (base != NULL && git_path_root(filename) < 0) {
|
if (base != NULL && git_path_root(filename) < 0) {
|
||||||
if (git_buf_joinpath(&path, base, filename) < 0)
|
git_buf *p = attr_session ? &attr_session->tmp : &path;
|
||||||
|
|
||||||
|
if (git_buf_joinpath(p, base, filename) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
filename = path.ptr;
|
|
||||||
|
filename = p->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
relfile = filename;
|
relfile = filename;
|
||||||
@ -196,6 +200,7 @@ cleanup:
|
|||||||
int git_attr_cache__get(
|
int git_attr_cache__get(
|
||||||
git_attr_file **out,
|
git_attr_file **out,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
const char *base,
|
const char *base,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
@ -207,12 +212,12 @@ int git_attr_cache__get(
|
|||||||
git_attr_file *file = NULL, *updated = NULL;
|
git_attr_file *file = NULL, *updated = NULL;
|
||||||
|
|
||||||
if ((error = attr_cache_lookup(
|
if ((error = attr_cache_lookup(
|
||||||
&file, &entry, repo, source, base, filename)) < 0)
|
&file, &entry, repo, attr_session, source, base, filename)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
/* load file if we don't have one or if existing one is out of date */
|
/* load file if we don't have one or if existing one is out of date */
|
||||||
if (!file || (error = git_attr_file__out_of_date(repo, file)) > 0)
|
if (!file || (error = git_attr_file__out_of_date(repo, attr_session, file)) > 0)
|
||||||
error = git_attr_file__load(&updated, repo, entry, source, parser);
|
error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser);
|
||||||
|
|
||||||
/* if we loaded the file, insert into and/or update cache */
|
/* if we loaded the file, insert into and/or update cache */
|
||||||
if (updated) {
|
if (updated) {
|
||||||
|
@ -31,6 +31,7 @@ extern int git_attr_cache__do_init(git_repository *repo);
|
|||||||
extern int git_attr_cache__get(
|
extern int git_attr_cache__get(
|
||||||
git_attr_file **file,
|
git_attr_file **file,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_attr_file_source source,
|
git_attr_file_source source,
|
||||||
const char *base,
|
const char *base,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -28,6 +28,11 @@
|
|||||||
#include "buf_text.h"
|
#include "buf_text.h"
|
||||||
#include "merge_file.h"
|
#include "merge_file.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "attr.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "strmap.h"
|
||||||
|
|
||||||
|
GIT__USE_STRMAP;
|
||||||
|
|
||||||
/* See docs/checkout-internals.md for more information */
|
/* See docs/checkout-internals.md for more information */
|
||||||
|
|
||||||
@ -68,7 +73,8 @@ typedef struct {
|
|||||||
size_t total_steps;
|
size_t total_steps;
|
||||||
size_t completed_steps;
|
size_t completed_steps;
|
||||||
git_checkout_perfdata perfdata;
|
git_checkout_perfdata perfdata;
|
||||||
git_buf last_mkdir;
|
git_strmap *mkdir_map;
|
||||||
|
git_attr_session attr_session;
|
||||||
} checkout_data;
|
} checkout_data;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -1291,25 +1297,6 @@ fail:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkout_mkdir(
|
|
||||||
checkout_data *data,
|
|
||||||
const char *path,
|
|
||||||
const char *base,
|
|
||||||
mode_t mode,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
struct git_futils_mkdir_perfdata mkdir_perfdata = {0};
|
|
||||||
|
|
||||||
int error = git_futils_mkdir_withperf(
|
|
||||||
path, base, mode, flags, &mkdir_perfdata);
|
|
||||||
|
|
||||||
data->perfdata.mkdir_calls += mkdir_perfdata.mkdir_calls;
|
|
||||||
data->perfdata.stat_calls += mkdir_perfdata.stat_calls;
|
|
||||||
data->perfdata.chmod_calls += mkdir_perfdata.chmod_calls;
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool should_remove_existing(checkout_data *data)
|
static bool should_remove_existing(checkout_data *data)
|
||||||
{
|
{
|
||||||
int ignorecase = 0;
|
int ignorecase = 0;
|
||||||
@ -1325,31 +1312,43 @@ static bool should_remove_existing(checkout_data *data)
|
|||||||
#define MKDIR_REMOVE_EXISTING \
|
#define MKDIR_REMOVE_EXISTING \
|
||||||
MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
|
MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
|
||||||
|
|
||||||
|
static int checkout_mkdir(
|
||||||
|
checkout_data *data,
|
||||||
|
const char *path,
|
||||||
|
const char *base,
|
||||||
|
mode_t mode,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
struct git_futils_mkdir_options mkdir_opts = {0};
|
||||||
|
int error;
|
||||||
|
|
||||||
|
mkdir_opts.dir_map = data->mkdir_map;
|
||||||
|
mkdir_opts.pool = &data->pool;
|
||||||
|
|
||||||
|
error = git_futils_mkdir_ext(
|
||||||
|
path, base, mode, flags, &mkdir_opts);
|
||||||
|
|
||||||
|
data->perfdata.mkdir_calls += mkdir_opts.perfdata.mkdir_calls;
|
||||||
|
data->perfdata.stat_calls += mkdir_opts.perfdata.stat_calls;
|
||||||
|
data->perfdata.chmod_calls += mkdir_opts.perfdata.chmod_calls;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
static int mkpath2file(
|
static int mkpath2file(
|
||||||
checkout_data *data, const char *path, unsigned int mode)
|
checkout_data *data, const char *path, unsigned int mode)
|
||||||
{
|
{
|
||||||
git_buf *mkdir_path = &data->tmp;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
bool remove_existing = should_remove_existing(data);
|
bool remove_existing = should_remove_existing(data);
|
||||||
|
unsigned int flags =
|
||||||
|
(remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL) |
|
||||||
|
GIT_MKDIR_SKIP_LAST;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if ((error = git_buf_sets(mkdir_path, path)) < 0)
|
if ((error = checkout_mkdir(
|
||||||
|
data, path, data->opts.target_directory, mode, flags)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
git_buf_rtruncate_at_char(mkdir_path, '/');
|
|
||||||
|
|
||||||
if (!data->last_mkdir.size ||
|
|
||||||
data->last_mkdir.size != mkdir_path->size ||
|
|
||||||
memcmp(mkdir_path->ptr, data->last_mkdir.ptr, mkdir_path->size) != 0) {
|
|
||||||
|
|
||||||
if ((error = checkout_mkdir(
|
|
||||||
data, mkdir_path->ptr, data->opts.target_directory, mode,
|
|
||||||
remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL)) < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
git_buf_swap(&data->last_mkdir, mkdir_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remove_existing) {
|
if (remove_existing) {
|
||||||
data->perfdata.stat_calls++;
|
data->perfdata.stat_calls++;
|
||||||
|
|
||||||
@ -1425,8 +1424,8 @@ static int blob_content_to_file(
|
|||||||
hint_path = path;
|
hint_path = path;
|
||||||
|
|
||||||
if (!data->opts.disable_filters)
|
if (!data->opts.disable_filters)
|
||||||
error = git_filter_list_load(
|
error = git_filter_list__load_with_attr_session(
|
||||||
&fl, git_blob_owner(blob), blob, hint_path,
|
&fl, data->repo, &data->attr_session, blob, hint_path,
|
||||||
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
|
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
@ -2008,7 +2007,8 @@ static int checkout_write_merge(
|
|||||||
in_data.ptr = (char *)result.ptr;
|
in_data.ptr = (char *)result.ptr;
|
||||||
in_data.size = result.len;
|
in_data.size = result.len;
|
||||||
|
|
||||||
if ((error = git_filter_list_load(&fl, data->repo, NULL, git_buf_cstr(&path_workdir),
|
if ((error = git_filter_list__load_with_attr_session(
|
||||||
|
&fl, data->repo, &data->attr_session, NULL, git_buf_cstr(&path_workdir),
|
||||||
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT)) < 0 ||
|
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT)) < 0 ||
|
||||||
(error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
|
(error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
@ -2212,12 +2212,17 @@ static void checkout_data_clear(checkout_data *data)
|
|||||||
git__free(data->pfx);
|
git__free(data->pfx);
|
||||||
data->pfx = NULL;
|
data->pfx = NULL;
|
||||||
|
|
||||||
git_buf_free(&data->last_mkdir);
|
git_strmap_free(data->mkdir_map);
|
||||||
|
|
||||||
git_buf_free(&data->path);
|
git_buf_free(&data->path);
|
||||||
git_buf_free(&data->tmp);
|
git_buf_free(&data->tmp);
|
||||||
|
|
||||||
git_index_free(data->index);
|
git_index_free(data->index);
|
||||||
data->index = NULL;
|
data->index = NULL;
|
||||||
|
|
||||||
|
git_strmap_free(data->mkdir_map);
|
||||||
|
|
||||||
|
git_attr_session__free(&data->attr_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkout_data_init(
|
static int checkout_data_init(
|
||||||
@ -2355,11 +2360,14 @@ static int checkout_data_init(
|
|||||||
(error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
|
(error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
|
||||||
(error = git_pool_init(&data->pool, 1, 0)) < 0 ||
|
(error = git_pool_init(&data->pool, 1, 0)) < 0 ||
|
||||||
(error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
|
(error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
|
||||||
(error = git_path_to_dir(&data->path)) < 0)
|
(error = git_path_to_dir(&data->path)) < 0 ||
|
||||||
|
(error = git_strmap_alloc(&data->mkdir_map)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
data->workdir_len = git_buf_len(&data->path);
|
data->workdir_len = git_buf_len(&data->path);
|
||||||
|
|
||||||
|
git_attr_session__init(&data->attr_session, data->repo);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
checkout_data_clear(data);
|
checkout_data_clear(data);
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "strmap.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#if GIT_WIN32
|
#if GIT_WIN32
|
||||||
#include "win32/findfile.h"
|
#include "win32/findfile.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GIT__USE_STRMAP;
|
||||||
|
|
||||||
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
|
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
|
||||||
{
|
{
|
||||||
return git_futils_mkdir(
|
return git_futils_mkdir(
|
||||||
@ -321,12 +324,12 @@ GIT_INLINE(int) validate_existing(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_futils_mkdir_withperf(
|
int git_futils_mkdir_ext(
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *base,
|
const char *base,
|
||||||
mode_t mode,
|
mode_t mode,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
struct git_futils_mkdir_perfdata *perfdata)
|
struct git_futils_mkdir_options *opts)
|
||||||
{
|
{
|
||||||
int error = -1;
|
int error = -1;
|
||||||
git_buf make_path = GIT_BUF_INIT;
|
git_buf make_path = GIT_BUF_INIT;
|
||||||
@ -401,11 +404,14 @@ int git_futils_mkdir_withperf(
|
|||||||
*tail = '\0';
|
*tail = '\0';
|
||||||
st.st_mode = 0;
|
st.st_mode = 0;
|
||||||
|
|
||||||
|
if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* See what's going on with this path component */
|
/* See what's going on with this path component */
|
||||||
perfdata->stat_calls++;
|
opts->perfdata.stat_calls++;
|
||||||
|
|
||||||
if (p_lstat(make_path.ptr, &st) < 0) {
|
if (p_lstat(make_path.ptr, &st) < 0) {
|
||||||
perfdata->mkdir_calls++;
|
opts->perfdata.mkdir_calls++;
|
||||||
|
|
||||||
if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) {
|
if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) {
|
||||||
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
|
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
|
||||||
@ -423,7 +429,7 @@ int git_futils_mkdir_withperf(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((error = validate_existing(
|
if ((error = validate_existing(
|
||||||
make_path.ptr, &st, mode, flags, perfdata)) < 0)
|
make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +438,7 @@ int git_futils_mkdir_withperf(
|
|||||||
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
|
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
|
||||||
st.st_mode != mode) {
|
st.st_mode != mode) {
|
||||||
|
|
||||||
perfdata->chmod_calls++;
|
opts->perfdata.chmod_calls++;
|
||||||
|
|
||||||
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
|
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
|
||||||
lastch == '\0') {
|
lastch == '\0') {
|
||||||
@ -441,6 +447,17 @@ int git_futils_mkdir_withperf(
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts->dir_map && opts->pool) {
|
||||||
|
char *cache_path = git_pool_malloc(opts->pool, make_path.size + 1);
|
||||||
|
GITERR_CHECK_ALLOC(cache_path);
|
||||||
|
|
||||||
|
memcpy(cache_path, make_path.ptr, make_path.size + 1);
|
||||||
|
|
||||||
|
git_strmap_insert(opts->dir_map, cache_path, cache_path, error);
|
||||||
|
if (error < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
@ -448,7 +465,7 @@ int git_futils_mkdir_withperf(
|
|||||||
/* check that full path really is a directory if requested & needed */
|
/* check that full path really is a directory if requested & needed */
|
||||||
if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
|
if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
|
||||||
lastch != '\0') {
|
lastch != '\0') {
|
||||||
perfdata->stat_calls++;
|
opts->perfdata.stat_calls++;
|
||||||
|
|
||||||
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||||
giterr_set(GITERR_OS, "Path is not a directory '%s'",
|
giterr_set(GITERR_OS, "Path is not a directory '%s'",
|
||||||
@ -468,8 +485,8 @@ int git_futils_mkdir(
|
|||||||
mode_t mode,
|
mode_t mode,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
struct git_futils_mkdir_perfdata perfdata = {0};
|
struct git_futils_mkdir_options options = {0};
|
||||||
return git_futils_mkdir_withperf(path, base, mode, flags, &perfdata);
|
return git_futils_mkdir_ext(path, base, mode, flags, &options);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "strmap.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filebuffer methods
|
* Filebuffer methods
|
||||||
@ -95,6 +97,13 @@ struct git_futils_mkdir_perfdata
|
|||||||
size_t chmod_calls;
|
size_t chmod_calls;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct git_futils_mkdir_options
|
||||||
|
{
|
||||||
|
git_strmap *dir_map;
|
||||||
|
git_pool *pool;
|
||||||
|
struct git_futils_mkdir_perfdata perfdata;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a directory or entire path.
|
* Create a directory or entire path.
|
||||||
*
|
*
|
||||||
@ -106,10 +115,10 @@ struct git_futils_mkdir_perfdata
|
|||||||
* @param base Root for relative path. These directories will never be made.
|
* @param base Root for relative path. These directories will never be made.
|
||||||
* @param mode The mode to use for created directories.
|
* @param mode The mode to use for created directories.
|
||||||
* @param flags Combination of the mkdir flags above.
|
* @param flags Combination of the mkdir flags above.
|
||||||
* @param perfdata Performance data, use `git_futils_mkdir` if you don't want this data.
|
* @param opts Extended options, use `git_futils_mkdir` if you are not interested.
|
||||||
* @return 0 on success, else error code
|
* @return 0 on success, else error code
|
||||||
*/
|
*/
|
||||||
extern int git_futils_mkdir_withperf(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata);
|
extern int git_futils_mkdir_ext(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
|
* Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
|
||||||
|
29
src/filter.c
29
src/filter.c
@ -394,15 +394,19 @@ static int filter_list_new(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int filter_list_check_attributes(
|
static int filter_list_check_attributes(
|
||||||
const char ***out, git_filter_def *fdef, const git_filter_source *src)
|
const char ***out,
|
||||||
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
|
git_filter_def *fdef,
|
||||||
|
const git_filter_source *src)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
size_t i;
|
size_t i;
|
||||||
const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
|
const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
|
||||||
GITERR_CHECK_ALLOC(strs);
|
GITERR_CHECK_ALLOC(strs);
|
||||||
|
|
||||||
error = git_attr_get_many(
|
error = git_attr_get_many_with_session(
|
||||||
strs, src->repo, 0, src->path, fdef->nattrs, fdef->attrs);
|
strs, repo, attr_session, 0, src->path, fdef->nattrs, fdef->attrs);
|
||||||
|
|
||||||
/* if no values were found but no matches are needed, it's okay! */
|
/* if no values were found but no matches are needed, it's okay! */
|
||||||
if (error == GIT_ENOTFOUND && !fdef->nmatches) {
|
if (error == GIT_ENOTFOUND && !fdef->nmatches) {
|
||||||
@ -448,9 +452,10 @@ int git_filter_list_new(
|
|||||||
return filter_list_new(out, &src);
|
return filter_list_new(out, &src);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_filter_list_load(
|
int git_filter_list__load_with_attr_session(
|
||||||
git_filter_list **filters,
|
git_filter_list **filters,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
git_blob *blob, /* can be NULL */
|
git_blob *blob, /* can be NULL */
|
||||||
const char *path,
|
const char *path,
|
||||||
git_filter_mode_t mode,
|
git_filter_mode_t mode,
|
||||||
@ -481,7 +486,9 @@ int git_filter_list_load(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fdef->nattrs > 0) {
|
if (fdef->nattrs > 0) {
|
||||||
error = filter_list_check_attributes(&values, fdef, &src);
|
error = filter_list_check_attributes(
|
||||||
|
&values, repo, attr_session, fdef, &src);
|
||||||
|
|
||||||
if (error == GIT_ENOTFOUND) {
|
if (error == GIT_ENOTFOUND) {
|
||||||
error = 0;
|
error = 0;
|
||||||
continue;
|
continue;
|
||||||
@ -523,6 +530,18 @@ int git_filter_list_load(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_filter_list_load(
|
||||||
|
git_filter_list **filters,
|
||||||
|
git_repository *repo,
|
||||||
|
git_blob *blob, /* can be NULL */
|
||||||
|
const char *path,
|
||||||
|
git_filter_mode_t mode,
|
||||||
|
uint32_t options)
|
||||||
|
{
|
||||||
|
return git_filter_list__load_with_attr_session(
|
||||||
|
filters, repo, NULL, blob, path, mode, options);
|
||||||
|
}
|
||||||
|
|
||||||
void git_filter_list_free(git_filter_list *fl)
|
void git_filter_list_free(git_filter_list *fl)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
10
src/filter.h
10
src/filter.h
@ -8,6 +8,7 @@
|
|||||||
#define INCLUDE_filter_h__
|
#define INCLUDE_filter_h__
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "attr_file.h"
|
||||||
#include "git2/filter.h"
|
#include "git2/filter.h"
|
||||||
|
|
||||||
/* Amount of file to examine for NUL byte when checking binary-ness */
|
/* Amount of file to examine for NUL byte when checking binary-ness */
|
||||||
@ -25,6 +26,15 @@ typedef enum {
|
|||||||
|
|
||||||
extern void git_filter_free(git_filter *filter);
|
extern void git_filter_free(git_filter *filter);
|
||||||
|
|
||||||
|
extern int git_filter_list__load_with_attr_session(
|
||||||
|
git_filter_list **filters,
|
||||||
|
git_repository *repo,
|
||||||
|
git_attr_session *attr_session,
|
||||||
|
git_blob *blob, /* can be NULL */
|
||||||
|
const char *path,
|
||||||
|
git_filter_mode_t mode,
|
||||||
|
uint32_t options);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Available filters
|
* Available filters
|
||||||
*/
|
*/
|
||||||
|
@ -161,7 +161,7 @@ static int push_ignore_file(
|
|||||||
git_attr_file *file = NULL;
|
git_attr_file *file = NULL;
|
||||||
|
|
||||||
error = git_attr_cache__get(
|
error = git_attr_cache__get(
|
||||||
&file, ignores->repo, GIT_ATTR_FILE__FROM_FILE,
|
&file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
|
||||||
base, filename, parse_ignore_file);
|
base, filename, parse_ignore_file);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
@ -189,7 +189,7 @@ static int get_internal_ignores(git_attr_file **out, git_repository *repo)
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = git_attr_cache__get(
|
error = git_attr_cache__get(
|
||||||
out, repo, GIT_ATTR_FILE__IN_MEMORY, NULL, GIT_IGNORE_INTERNAL, NULL);
|
out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL, GIT_IGNORE_INTERNAL, NULL);
|
||||||
|
|
||||||
/* if internal rules list is empty, insert default rules */
|
/* if internal rules list is empty, insert default rules */
|
||||||
if (!error && !(*out)->rules.length)
|
if (!error && !(*out)->rules.length)
|
||||||
|
@ -133,6 +133,8 @@ struct git_repository {
|
|||||||
has_8dot3_default:1;
|
has_8dot3_default:1;
|
||||||
unsigned int lru_counter;
|
unsigned int lru_counter;
|
||||||
|
|
||||||
|
git_atomic attr_session_key;
|
||||||
|
|
||||||
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1130,3 +1130,57 @@ void test_checkout_tree__can_collect_perfdata(void)
|
|||||||
|
|
||||||
git_object_free(obj);
|
git_object_free(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_attr_callback(
|
||||||
|
const char *path,
|
||||||
|
size_t completed_steps,
|
||||||
|
size_t total_steps,
|
||||||
|
void *payload)
|
||||||
|
{
|
||||||
|
GIT_UNUSED(completed_steps);
|
||||||
|
GIT_UNUSED(total_steps);
|
||||||
|
GIT_UNUSED(payload);
|
||||||
|
|
||||||
|
if (path && strcmp(path, "ident1.txt") == 0)
|
||||||
|
cl_git_write2file("testrepo/.gitattributes",
|
||||||
|
"*.txt ident\n", 12, O_RDWR|O_CREAT, 0666);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_checkout_tree__caches_attributes_during_checkout(void)
|
||||||
|
{
|
||||||
|
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||||
|
git_oid oid;
|
||||||
|
git_object *obj = NULL;
|
||||||
|
git_buf ident1 = GIT_BUF_INIT, ident2 = GIT_BUF_INIT;
|
||||||
|
char *ident_paths[] = { "ident1.txt", "ident2.txt" };
|
||||||
|
|
||||||
|
opts.progress_cb = update_attr_callback;
|
||||||
|
|
||||||
|
assert_on_branch(g_repo, "master");
|
||||||
|
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
opts.paths.strings = ident_paths;
|
||||||
|
opts.paths.count = 2;
|
||||||
|
|
||||||
|
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/ident"));
|
||||||
|
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||||
|
|
||||||
|
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&ident1, "testrepo/ident1.txt"));
|
||||||
|
cl_git_pass(git_futils_readbuffer(&ident2, "testrepo/ident2.txt"));
|
||||||
|
|
||||||
|
cl_assert_equal_strn(ident1.ptr, "# $Id$", 6);
|
||||||
|
cl_assert_equal_strn(ident2.ptr, "# $Id$", 6);
|
||||||
|
|
||||||
|
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&ident1, "testrepo/ident1.txt"));
|
||||||
|
cl_git_pass(git_futils_readbuffer(&ident2, "testrepo/ident2.txt"));
|
||||||
|
|
||||||
|
cl_assert_equal_strn(ident1.ptr, "# $Id: ", 7);
|
||||||
|
cl_assert_equal_strn(ident2.ptr, "# $Id: ", 7);
|
||||||
|
|
||||||
|
git_buf_free(&ident1);
|
||||||
|
git_buf_free(&ident2);
|
||||||
|
git_object_free(obj);
|
||||||
|
}
|
||||||
|
@ -36,7 +36,7 @@ void test_refs_list__all(void)
|
|||||||
/* We have exactly 12 refs in total if we include the packed ones:
|
/* We have exactly 12 refs in total if we include the packed ones:
|
||||||
* there is a reference that exists both in the packfile and as
|
* there is a reference that exists both in the packfile and as
|
||||||
* loose, but we only list it once */
|
* loose, but we only list it once */
|
||||||
cl_assert_equal_i((int)ref_list.count, 14);
|
cl_assert_equal_i((int)ref_list.count, 15);
|
||||||
|
|
||||||
git_strarray_free(&ref_list);
|
git_strarray_free(&ref_list);
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
|
|||||||
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
|
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
|
||||||
|
|
||||||
cl_git_pass(git_reference_list(&ref_list, g_repo));
|
cl_git_pass(git_reference_list(&ref_list, g_repo));
|
||||||
cl_assert_equal_i((int)ref_list.count, 14);
|
cl_assert_equal_i((int)ref_list.count, 15);
|
||||||
|
|
||||||
git_strarray_free(&ref_list);
|
git_strarray_free(&ref_list);
|
||||||
}
|
}
|
||||||
|
@ -906,6 +906,7 @@ void test_repo_iterator__fs2(void)
|
|||||||
static const char *expect_base[] = {
|
static const char *expect_base[] = {
|
||||||
"heads/br2",
|
"heads/br2",
|
||||||
"heads/dir",
|
"heads/dir",
|
||||||
|
"heads/ident",
|
||||||
"heads/long-file-name",
|
"heads/long-file-name",
|
||||||
"heads/master",
|
"heads/master",
|
||||||
"heads/packed-test",
|
"heads/packed-test",
|
||||||
@ -923,7 +924,7 @@ void test_repo_iterator__fs2(void)
|
|||||||
|
|
||||||
cl_git_pass(git_iterator_for_filesystem(
|
cl_git_pass(git_iterator_for_filesystem(
|
||||||
&i, "testrepo/.git/refs", 0, NULL, NULL));
|
&i, "testrepo/.git/refs", 0, NULL, NULL));
|
||||||
expect_iterator_items(i, 12, expect_base, 12, expect_base);
|
expect_iterator_items(i, 13, expect_base, 13, expect_base);
|
||||||
git_iterator_free(i);
|
git_iterator_free(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tests/resources/testrepo/.gitted/refs/heads/ident
Normal file
BIN
tests/resources/testrepo/.gitted/refs/heads/ident
Normal file
Binary file not shown.
@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void)
|
|||||||
/* walking */;
|
/* walking */;
|
||||||
|
|
||||||
/* git log --branches --oneline | wc -l => 16 */
|
/* git log --branches --oneline | wc -l => 16 */
|
||||||
cl_assert_equal_i(17, i);
|
cl_assert_equal_i(18, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_revwalk_basic__push_head(void)
|
void test_revwalk_basic__push_head(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user