diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-07-22 15:29:46 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2021-07-22 16:22:28 -0400 |
commit | 0bd547a8bee02bf984ea5c7acdc8172044fcb3a4 (patch) | |
tree | 4dc86b3fbc275413fccd28405016bbae472adf05 | |
parent | 093d579f7be5636c52290a517eee1eebb7471e31 (diff) | |
download | libgit2-0bd547a8bee02bf984ea5c7acdc8172044fcb3a4.tar.gz |
attr: introduce GIT_ATTR_CHECK_INCLUDE_COMMIT
Introduce `GIT_ATTR_CHECK_INCLUDE_COMMIT`, which like 4fd5748 allows
attribute information to be read from files in the repository. 4fd5748
always reads the information from HEAD, while
`GIT_ATTR_CHECK_INCLUDE_COMMIT` allows users to provide the commit to
read the attributes from.
-rw-r--r-- | include/git2/attr.h | 10 | ||||
-rw-r--r-- | src/attr.c | 29 | ||||
-rw-r--r-- | src/attr_file.c | 34 | ||||
-rw-r--r-- | src/attr_file.h | 8 | ||||
-rw-r--r-- | src/attrcache.c | 7 |
5 files changed, 71 insertions, 17 deletions
diff --git a/include/git2/attr.h b/include/git2/attr.h index 306893c67..62c2ed6e7 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -130,9 +130,13 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); * * Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes * from a `.gitattributes` file in the repository at the HEAD revision. + * + * Passing the `GIT_ATTR_CHECK_INCLUDE_COMMIT` flag will use attributes + * from a `.gitattributes` file in a specific commit. */ #define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) #define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3) +#define GIT_ATTR_CHECK_INCLUDE_COMMIT (1 << 4) /** * An options structure for querying attributes. @@ -142,6 +146,12 @@ typedef struct { /** A combination of GIT_ATTR_CHECK flags */ unsigned int flags; + + /** + * The commit to load attributes from, when + * `GIT_ATTR_CHECK_INCLUDE_COMMIT` is specified. + */ + git_oid *commit_id; } git_attr_options; #define GIT_ATTR_OPTIONS_VERSION 1 diff --git a/src/attr.c b/src/attr.c index a2d78e68b..03b720c5a 100644 --- a/src/attr.c +++ b/src/attr.c @@ -381,8 +381,9 @@ static int attr_setup( git_attr_options *opts) { 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 }; - git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE }; + 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; @@ -430,6 +431,13 @@ static int attr_setup( (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; @@ -480,7 +488,7 @@ 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; @@ -513,7 +521,8 @@ static int attr_decide_sources( break; } - if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) + if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 || + (flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0) srcs[count++] = GIT_ATTR_FILE_SOURCE_COMMIT; return count; @@ -563,13 +572,19 @@ static int push_one_attr(void *ref, const char *path) 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) { 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); } @@ -631,7 +646,7 @@ static int collect_attr_files( info.repo = repo; info.attr_session = attr_session; - info.flags = opts ? opts->flags : 0; + 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 */ diff --git a/src/attr_file.c b/src/attr_file.c index 3b8965a10..f8627381c 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -113,6 +113,7 @@ int git_attr_file__load( bool allow_macros) { int error = 0; + git_commit *commit = NULL; git_tree *tree = NULL; git_tree_entry *tree_entry = NULL; git_blob *blob = NULL; @@ -163,8 +164,14 @@ int git_attr_file__load( break; } case GIT_ATTR_FILE_SOURCE_COMMIT: { - if ((error = git_repository_head_tree(&tree, repo)) < 0) - goto cleanup; + if (source->commit_id) { + if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0 || + (error = git_commit_tree(&tree, commit)) < 0) + goto cleanup; + } else { + if ((error = git_repository_head_tree(&tree, repo)) < 0) + goto cleanup; + } if ((error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0) { /* @@ -239,6 +246,7 @@ cleanup: git_blob_free(blob); git_tree_entry_free(tree_entry); git_tree_free(tree); + git_commit_free(commit); git_buf_dispose(&content); return error; @@ -247,7 +255,8 @@ cleanup: int git_attr_file__out_of_date( git_repository *repo, git_attr_session *attr_session, - git_attr_file *file) + git_attr_file *file, + git_attr_file_source *source) { if (!file) return 1; @@ -280,13 +289,26 @@ int git_attr_file__out_of_date( } case GIT_ATTR_FILE_SOURCE_COMMIT: { - git_tree *tree; + git_tree *tree = NULL; int error; - if ((error = git_repository_head_tree(&tree, repo)) < 0) + if (source->commit_id) { + git_commit *commit = NULL; + + if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0) + return error; + + error = git_commit_tree(&tree, commit); + + git_commit_free(commit); + } else { + error = git_repository_head_tree(&tree, repo); + } + + if (error < 0) return error; - error = git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)); + error = (git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)) != 0); git_tree_free(tree); return error; diff --git a/src/attr_file.h b/src/attr_file.h index 5c8a41291..16e33caf1 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -55,6 +55,12 @@ typedef struct { */ const char *base; const char *filename; + + /* + * The commit ID when the given source type is a commit (or NULL + * for the repository's HEAD commit.) + */ + git_oid *commit_id; } git_attr_file_source; extern const char *git_attr__true; @@ -171,7 +177,7 @@ int git_attr_file__load_standalone( git_attr_file **out, const char *path); int git_attr_file__out_of_date( - git_repository *repo, git_attr_session *session, git_attr_file *file); + git_repository *repo, git_attr_session *session, git_attr_file *file, git_attr_file_source *source); int git_attr_file__parse_buffer( git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros); diff --git a/src/attrcache.c b/src/attrcache.c index f07712735..7fe2bfbdb 100644 --- a/src/attrcache.c +++ b/src/attrcache.c @@ -224,16 +224,17 @@ int git_attr_cache__get( return error; /* 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, attr_session, file)) > 0) + if (!file || + (error = git_attr_file__out_of_date(repo, attr_session, file, source)) > 0) error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser, allow_macros); /* if we loaded the file, insert into and/or update cache */ if (updated) { - if ((error = attr_cache_upsert(cache, updated)) < 0) + if ((error = attr_cache_upsert(cache, updated)) < 0) { git_attr_file__free(updated); - else { + } else { git_attr_file__free(file); /* offset incref from lookup */ file = updated; } |