diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2019-07-21 14:11:03 +0100 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2019-08-11 20:47:59 +0100 |
commit | 4fd5748c4bbc0fba3db9fb2fb20e01261339b9d9 (patch) | |
tree | 77da3e9a547b5b9bad7c6bbd4e2f6a05f12f560c | |
parent | a5392eae3d40dc7789de581406e35a1ce7487e1e (diff) | |
download | libgit2-4fd5748c4bbc0fba3db9fb2fb20e01261339b9d9.tar.gz |
attr: optionally read attributes from repository
When `GIT_ATTR_CHECK_INCLUDE_HEAD` is specified, read `gitattribute`
files that are checked into the repository at the HEAD revision.
-rw-r--r-- | include/git2/attr.h | 11 | ||||
-rw-r--r-- | src/attr.c | 17 | ||||
-rw-r--r-- | src/attr_file.c | 43 | ||||
-rw-r--r-- | src/attr_file.h | 3 |
4 files changed, 65 insertions, 9 deletions
diff --git a/include/git2/attr.h b/include/git2/attr.h index cab9758a0..72e43806c 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -119,13 +119,20 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); #define GIT_ATTR_CHECK_INDEX_ONLY 2 /** - * Check attribute flags: Using the system attributes file. + * Check attribute flags: controlling extended attribute behavior. * * Normally, attribute checks include looking in the /etc (or system * equivalent) directory for a `gitattributes` file. Passing this * flag will cause attribute checks to ignore that file. + * equivalent) directory for a `gitattributes` file. Passing the + * `GIT_ATTR_CHECK_NO_SYSTEM` flag will cause attribute checks to + * ignore that file. + * + * Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes + * from a `.gitattributes` file in the repository at the HEAD revision. */ -#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) +#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) +#define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3) /** * Look up the value of one git attribute for path. diff --git a/src/attr.c b/src/attr.c index 02a7148e8..bd517cde3 100644 --- a/src/attr.c +++ b/src/attr.c @@ -305,7 +305,10 @@ static int system_attr_file( return 0; } -static int attr_setup(git_repository *repo, git_attr_session *attr_session) +static int attr_setup( + git_repository *repo, + git_attr_session *attr_session, + uint32_t flags) { git_buf path = GIT_BUF_INIT; git_index *idx = NULL; @@ -352,6 +355,11 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session) NULL, GIT_ATTR_FILE, true)) < 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) + goto out; + if (attr_session) attr_session->init_setup = 1; @@ -428,6 +436,9 @@ static int attr_decide_sources( break; } + if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) + srcs[count++] = GIT_ATTR_FILE__FROM_HEAD; + return count; } @@ -460,7 +471,7 @@ static int push_attr_file( 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[2]; + git_attr_file_source src[GIT_ATTR_FILE_NUM_SOURCES]; int error = 0, n_src, i; bool allow_macros; @@ -499,7 +510,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)) < 0) + if ((error = attr_setup(repo, attr_session, flags)) < 0) return error; /* Resolve path in a non-bare repo */ diff --git a/src/attr_file.c b/src/attr_file.c index f8769c6e7..a1b4c7324 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -109,6 +109,8 @@ int git_attr_file__load( bool allow_macros) { int error = 0; + git_tree *tree = NULL; + git_tree_entry *tree_entry = NULL; git_blob *blob = NULL; git_buf content = GIT_BUF_INIT; const char *content_str; @@ -117,6 +119,8 @@ int git_attr_file__load( bool nonexistent = false; int bom_offset; git_bom_t bom; + git_oid id; + git_off_t blobsize; *out = NULL; @@ -125,9 +129,6 @@ int git_attr_file__load( /* in-memory attribute file doesn't need data */ break; case GIT_ATTR_FILE__FROM_INDEX: { - git_oid id; - git_off_t blobsize; - if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 || (error = git_blob_lookup(&blob, repo, &id)) < 0) return error; @@ -157,6 +158,25 @@ int git_attr_file__load( break; } + case GIT_ATTR_FILE__FROM_HEAD: { + if ((error = git_repository_head_tree(&tree, repo)) < 0 || + (error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0 || + (error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0) + goto cleanup; + + /* + * Do not assume that data straight from the ODB is NULL-terminated; + * copy the contents of a file to a buffer to work on. + */ + blobsize = git_blob_rawsize(blob); + + GIT_ERROR_CHECK_BLOBSIZE(blobsize); + if ((error = git_buf_put(&content, + git_blob_rawcontent(blob), (size_t)blobsize)) < 0) + goto cleanup; + + break; + } default: git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source); return -1; @@ -188,6 +208,8 @@ int git_attr_file__load( file->nonexistent = 1; else if (source == GIT_ATTR_FILE__FROM_INDEX) git_oid_cpy(&file->cache_data.oid, git_blob_id(blob)); + else if (source == GIT_ATTR_FILE__FROM_HEAD) + git_oid_cpy(&file->cache_data.oid, git_tree_id(tree)); else if (source == GIT_ATTR_FILE__FROM_FILE) git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st); /* else always cacheable */ @@ -196,6 +218,8 @@ int git_attr_file__load( cleanup: git_blob_free(blob); + git_tree_entry_free(tree_entry); + git_tree_free(tree); git_buf_dispose(&content); return error; @@ -236,6 +260,19 @@ int git_attr_file__out_of_date( return (git_oid__cmp(&file->cache_data.oid, &id) != 0); } + case GIT_ATTR_FILE__FROM_HEAD: { + git_tree *tree; + int error; + + if ((error = git_repository_head_tree(&tree, repo)) < 0) + return error; + + error = git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)); + + git_tree_free(tree); + return error; + } + default: git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source); return -1; diff --git a/src/attr_file.h b/src/attr_file.h index f4f9a097a..2b6b1d623 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -40,8 +40,9 @@ typedef enum { GIT_ATTR_FILE__IN_MEMORY = 0, GIT_ATTR_FILE__FROM_FILE = 1, GIT_ATTR_FILE__FROM_INDEX = 2, + GIT_ATTR_FILE__FROM_HEAD = 3, - GIT_ATTR_FILE_NUM_SOURCES = 3 + GIT_ATTR_FILE_NUM_SOURCES = 4 } git_attr_file_source; extern const char *git_attr__true; |