diff options
Diffstat (limited to 'src/attr.c')
-rw-r--r-- | src/attr.c | 224 |
1 files changed, 159 insertions, 65 deletions
diff --git a/src/attr.c b/src/attr.c index cab5e8b97..03b720c5a 100644 --- a/src/attr.c +++ b/src/attr.c @@ -36,16 +36,16 @@ git_attr_value_t git_attr_value(const char *attr) static int collect_attr_files( git_repository *repo, git_attr_session *attr_session, - uint32_t flags, + git_attr_options *opts, const char *path, git_vector *files); static void release_attr_files(git_vector *files); -int git_attr_get( +int git_attr_get_ext( const char **value, git_repository *repo, - uint32_t flags, + git_attr_options *opts, const char *pathname, const char *name) { @@ -61,6 +61,7 @@ int git_attr_get( GIT_ASSERT_ARG(value); GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(name); + GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options"); *value = NULL; @@ -70,7 +71,7 @@ int git_attr_get( if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0) return -1; - if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0) + if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0) goto cleanup; memset(&attr, 0, sizeof(attr)); @@ -97,6 +98,20 @@ cleanup: return error; } +int git_attr_get( + const char **value, + git_repository *repo, + uint32_t flags, + const char *pathname, + const char *name) +{ + git_attr_options opts = GIT_ATTR_OPTIONS_INIT; + + opts.flags = flags; + + return git_attr_get_ext(value, repo, &opts, pathname, name); +} + typedef struct { git_attr_name name; @@ -107,7 +122,7 @@ int git_attr_get_many_with_session( const char **values, git_repository *repo, git_attr_session *attr_session, - uint32_t flags, + git_attr_options *opts, const char *pathname, size_t num_attr, const char **names) @@ -129,6 +144,7 @@ int git_attr_get_many_with_session( GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(pathname); GIT_ASSERT_ARG(names); + GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options"); if (git_repository_is_bare(repo)) dir_flag = GIT_DIR_FLAG_FALSE; @@ -136,7 +152,7 @@ int git_attr_get_many_with_session( if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0) return -1; - if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0) + if ((error = collect_attr_files(repo, attr_session, opts, pathname, &files)) < 0) goto cleanup; info = git__calloc(num_attr, sizeof(attr_get_many_info)); @@ -190,8 +206,24 @@ int git_attr_get_many( size_t num_attr, const char **names) { + git_attr_options opts = GIT_ATTR_OPTIONS_INIT; + + opts.flags = flags; + return git_attr_get_many_with_session( - values, repo, NULL, flags, pathname, num_attr, names); + values, repo, NULL, &opts, pathname, num_attr, names); +} + +int git_attr_get_many_ext( + const char **values, + git_repository *repo, + git_attr_options *opts, + const char *pathname, + size_t num_attr, + const char **names) +{ + return git_attr_get_many_with_session( + values, repo, NULL, opts, pathname, num_attr, names); } int git_attr_foreach( @@ -201,6 +233,20 @@ int git_attr_foreach( int (*callback)(const char *name, const char *value, void *payload), void *payload) { + git_attr_options opts = GIT_ATTR_OPTIONS_INIT; + + opts.flags = flags; + + return git_attr_foreach_ext(repo, &opts, pathname, callback, payload); +} + +int git_attr_foreach_ext( + git_repository *repo, + git_attr_options *opts, + const char *pathname, + int (*callback)(const char *name, const char *value, void *payload), + void *payload) +{ int error; git_attr_path path; git_vector files = GIT_VECTOR_INIT; @@ -213,6 +259,7 @@ int git_attr_foreach( GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(callback); + GIT_ERROR_CHECK_VERSION(opts, GIT_ATTR_OPTIONS_VERSION, "git_attr_options"); if (git_repository_is_bare(repo)) dir_flag = GIT_DIR_FLAG_FALSE; @@ -220,7 +267,7 @@ int git_attr_foreach( if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0) return -1; - if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 || + if ((error = collect_attr_files(repo, NULL, opts, pathname, &files)) < 0 || (error = git_strmap_new(&seen)) < 0) goto cleanup; @@ -253,26 +300,43 @@ cleanup: return error; } -static int preload_attr_file( +static int preload_attr_source( git_repository *repo, git_attr_session *attr_session, - git_attr_file_source source, - const char *base, - const char *file, - bool allow_macros) + git_attr_file_source *source) { int error; git_attr_file *preload = NULL; - if (!file) + if (!source) return 0; - if (!(error = git_attr_cache__get(&preload, repo, attr_session, source, base, file, - git_attr_file__parse_buffer, allow_macros))) + + error = git_attr_cache__get(&preload, repo, attr_session, source, + git_attr_file__parse_buffer, true); + + if (!error) git_attr_file__free(preload); return error; } +GIT_INLINE(int) preload_attr_file( + git_repository *repo, + git_attr_session *attr_session, + const char *base, + const char *filename) +{ + git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE }; + + if (!filename) + return 0; + + source.base = base; + source.filename = filename; + + return preload_attr_source(repo, attr_session, &source); +} + static int system_attr_file( git_buf *out, git_attr_session *attr_session) @@ -314,9 +378,12 @@ static int system_attr_file( static int attr_setup( git_repository *repo, git_attr_session *attr_session, - uint32_t flags) + git_attr_options *opts) { - git_buf path = GIT_BUF_INIT; + git_buf system = GIT_BUF_INIT, info = GIT_BUF_INIT; + git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE, NULL }; + git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL }; + git_attr_file_source commit_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL }; git_index *idx = NULL; const char *workdir; int error = 0; @@ -332,45 +399,51 @@ static int attr_setup( * definitions will be available for later file parsing. */ - if ((error = system_attr_file(&path, attr_session)) < 0 || - (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE, - NULL, path.ptr, true)) < 0) { + if ((error = system_attr_file(&system, attr_session)) < 0 || + (error = preload_attr_file(repo, attr_session, NULL, system.ptr)) < 0) { if (error != GIT_ENOTFOUND) goto out; + + error = 0; } - if ((error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE, - NULL, git_repository_attr_cache(repo)->cfg_attr_file, true)) < 0) + if ((error = preload_attr_file(repo, attr_session, NULL, + git_repository_attr_cache(repo)->cfg_attr_file)) < 0) goto out; - git_buf_clear(&path); /* git_repository_item_path expects an empty buffer, because it uses git_buf_set */ - if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || - (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE, - path.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) { + if ((error = git_repository_item_path(&info, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || + (error = preload_attr_file(repo, attr_session, info.ptr, GIT_ATTR_FILE_INREPO)) < 0) { if (error != GIT_ENOTFOUND) goto out; + + error = 0; } if ((workdir = git_repository_workdir(repo)) != NULL && - (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE, - workdir, GIT_ATTR_FILE, true)) < 0) + (error = preload_attr_file(repo, attr_session, workdir, GIT_ATTR_FILE)) < 0) goto out; if ((error = git_repository_index__weakptr(&idx, repo)) < 0 || - (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, - NULL, GIT_ATTR_FILE, true)) < 0) + (error = preload_attr_source(repo, attr_session, &index_source)) < 0) goto out; - if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 && - (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_HEAD, - NULL, GIT_ATTR_FILE, true)) < 0) + if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) && + (error = preload_attr_source(repo, attr_session, &head_source)) < 0) goto out; + if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0)) { + commit_source.commit_id = opts->commit_id; + + if ((error = preload_attr_source(repo, attr_session, &commit_source)) < 0) + goto out; + } + if (attr_session) attr_session->init_setup = 1; out: - git_buf_dispose(&path); + git_buf_dispose(&system); + git_buf_dispose(&info); return error; } @@ -415,56 +488,60 @@ int git_attr_add_macro( typedef struct { git_repository *repo; git_attr_session *attr_session; - uint32_t flags; + git_attr_options *opts; const char *workdir; git_index *index; git_vector *files; } attr_walk_up_info; static int attr_decide_sources( - uint32_t flags, bool has_wd, bool has_index, git_attr_file_source *srcs) + uint32_t flags, + bool has_wd, + bool has_index, + git_attr_file_source_t *srcs) { int count = 0; switch (flags & 0x03) { case GIT_ATTR_CHECK_FILE_THEN_INDEX: if (has_wd) - srcs[count++] = GIT_ATTR_FILE__FROM_FILE; + srcs[count++] = GIT_ATTR_FILE_SOURCE_FILE; if (has_index) - srcs[count++] = GIT_ATTR_FILE__FROM_INDEX; + srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX; break; case GIT_ATTR_CHECK_INDEX_THEN_FILE: if (has_index) - srcs[count++] = GIT_ATTR_FILE__FROM_INDEX; + srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX; if (has_wd) - srcs[count++] = GIT_ATTR_FILE__FROM_FILE; + srcs[count++] = GIT_ATTR_FILE_SOURCE_FILE; break; case GIT_ATTR_CHECK_INDEX_ONLY: if (has_index) - srcs[count++] = GIT_ATTR_FILE__FROM_INDEX; + srcs[count++] = GIT_ATTR_FILE_SOURCE_INDEX; break; } - if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) - srcs[count++] = GIT_ATTR_FILE__FROM_HEAD; + if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 || + (flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0) + srcs[count++] = GIT_ATTR_FILE_SOURCE_COMMIT; return count; } -static int push_attr_file( +static int push_attr_source( git_repository *repo, git_attr_session *attr_session, git_vector *list, - git_attr_file_source source, - const char *base, - const char *filename, + git_attr_file_source *source, bool allow_macros) { int error = 0; git_attr_file *file = NULL; error = git_attr_cache__get(&file, repo, attr_session, - source, base, filename, git_attr_file__parse_buffer, allow_macros); + source, + git_attr_file__parse_buffer, + allow_macros); if (error < 0) return error; @@ -477,20 +554,40 @@ static int push_attr_file( return error; } +GIT_INLINE(int) push_attr_file( + git_repository *repo, + git_attr_session *attr_session, + git_vector *list, + const char *base, + const char *filename) +{ + git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE, base, filename }; + return push_attr_source(repo, attr_session, list, &source, true); +} + static int push_one_attr(void *ref, const char *path) { attr_walk_up_info *info = (attr_walk_up_info *)ref; - git_attr_file_source src[GIT_ATTR_FILE_NUM_SOURCES]; + git_attr_file_source_t src[GIT_ATTR_FILE_NUM_SOURCES]; int error = 0, n_src, i; bool allow_macros; - n_src = attr_decide_sources( - info->flags, info->workdir != NULL, info->index != NULL, src); + n_src = attr_decide_sources(info->opts ? info->opts->flags : 0, + info->workdir != NULL, + info->index != NULL, + src); + allow_macros = info->workdir ? !strcmp(info->workdir, path) : false; - for (i = 0; !error && i < n_src; ++i) - error = push_attr_file(info->repo, info->attr_session, info->files, - src[i], path, GIT_ATTR_FILE, allow_macros); + for (i = 0; !error && i < n_src; ++i) { + git_attr_file_source source = { src[i], path, GIT_ATTR_FILE }; + + if (src[i] == GIT_ATTR_FILE_SOURCE_COMMIT && info->opts) + source.commit_id = info->opts->commit_id; + + error = push_attr_source(info->repo, info->attr_session, info->files, + &source, allow_macros); + } return error; } @@ -510,7 +607,7 @@ static void release_attr_files(git_vector *files) static int collect_attr_files( git_repository *repo, git_attr_session *attr_session, - uint32_t flags, + git_attr_options *opts, const char *path, git_vector *files) { @@ -519,7 +616,7 @@ static int collect_attr_files( const char *workdir = git_repository_workdir(repo); attr_walk_up_info info = { NULL }; - if ((error = attr_setup(repo, attr_session, flags)) < 0) + if ((error = attr_setup(repo, attr_session, opts)) < 0) return error; /* Resolve path in a non-bare repo */ @@ -542,15 +639,14 @@ static int collect_attr_files( */ if ((error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 || - (error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE, - attrfile.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) { + (error = push_attr_file(repo, attr_session, files, attrfile.ptr, GIT_ATTR_FILE_INREPO)) < 0) { if (error != GIT_ENOTFOUND) goto cleanup; } info.repo = repo; info.attr_session = attr_session; - info.flags = flags; + info.opts = opts; info.workdir = workdir; if (git_repository_index__weakptr(&info.index, repo) < 0) git_error_clear(); /* no error even if there is no index */ @@ -565,18 +661,16 @@ static int collect_attr_files( goto cleanup; if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) { - error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE, - NULL, git_repository_attr_cache(repo)->cfg_attr_file, true); + error = push_attr_file(repo, attr_session, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file); if (error < 0) goto cleanup; } - if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) { + if (!opts || (opts->flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) { error = system_attr_file(&dir, attr_session); if (!error) - error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE, - NULL, dir.ptr, true); + error = push_attr_file(repo, attr_session, files, NULL, dir.ptr); else if (error == GIT_ENOTFOUND) error = 0; } |