Commit 4fd5748c by Edward Thomson

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.
parent a5392eae
...@@ -119,13 +119,20 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); ...@@ -119,13 +119,20 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
#define GIT_ATTR_CHECK_INDEX_ONLY 2 #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 * Normally, attribute checks include looking in the /etc (or system
* equivalent) directory for a `gitattributes` file. Passing this * equivalent) directory for a `gitattributes` file. Passing this
* flag will cause attribute checks to ignore that file. * 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. * Look up the value of one git attribute for path.
......
...@@ -305,7 +305,10 @@ static int system_attr_file( ...@@ -305,7 +305,10 @@ static int system_attr_file(
return 0; 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_buf path = GIT_BUF_INIT;
git_index *idx = NULL; git_index *idx = NULL;
...@@ -352,6 +355,11 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session) ...@@ -352,6 +355,11 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
NULL, GIT_ATTR_FILE, true)) < 0) NULL, GIT_ATTR_FILE, true)) < 0)
goto out; 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) if (attr_session)
attr_session->init_setup = 1; attr_session->init_setup = 1;
...@@ -428,6 +436,9 @@ static int attr_decide_sources( ...@@ -428,6 +436,9 @@ static int attr_decide_sources(
break; break;
} }
if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0)
srcs[count++] = GIT_ATTR_FILE__FROM_HEAD;
return count; return count;
} }
...@@ -460,7 +471,7 @@ static int push_attr_file( ...@@ -460,7 +471,7 @@ static int push_attr_file(
static int push_one_attr(void *ref, const char *path) static int push_one_attr(void *ref, const char *path)
{ {
attr_walk_up_info *info = (attr_walk_up_info *)ref; 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; int error = 0, n_src, i;
bool allow_macros; bool allow_macros;
...@@ -499,7 +510,7 @@ static int collect_attr_files( ...@@ -499,7 +510,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, attr_session)) < 0) if ((error = attr_setup(repo, attr_session, flags)) < 0)
return error; return error;
/* Resolve path in a non-bare repo */ /* Resolve path in a non-bare repo */
......
...@@ -109,6 +109,8 @@ int git_attr_file__load( ...@@ -109,6 +109,8 @@ int git_attr_file__load(
bool allow_macros) bool allow_macros)
{ {
int error = 0; int error = 0;
git_tree *tree = NULL;
git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL; git_blob *blob = NULL;
git_buf content = GIT_BUF_INIT; git_buf content = GIT_BUF_INIT;
const char *content_str; const char *content_str;
...@@ -117,6 +119,8 @@ int git_attr_file__load( ...@@ -117,6 +119,8 @@ int git_attr_file__load(
bool nonexistent = false; bool nonexistent = false;
int bom_offset; int bom_offset;
git_bom_t bom; git_bom_t bom;
git_oid id;
git_off_t blobsize;
*out = NULL; *out = NULL;
...@@ -125,9 +129,6 @@ int git_attr_file__load( ...@@ -125,9 +129,6 @@ int git_attr_file__load(
/* in-memory attribute file doesn't need data */ /* in-memory attribute file doesn't need data */
break; break;
case GIT_ATTR_FILE__FROM_INDEX: { 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 || if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
(error = git_blob_lookup(&blob, repo, &id)) < 0) (error = git_blob_lookup(&blob, repo, &id)) < 0)
return error; return error;
...@@ -157,6 +158,25 @@ int git_attr_file__load( ...@@ -157,6 +158,25 @@ int git_attr_file__load(
break; 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: default:
git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source); git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source);
return -1; return -1;
...@@ -188,6 +208,8 @@ int git_attr_file__load( ...@@ -188,6 +208,8 @@ int git_attr_file__load(
file->nonexistent = 1; file->nonexistent = 1;
else if (source == GIT_ATTR_FILE__FROM_INDEX) 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_HEAD)
git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
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);
/* else always cacheable */ /* else always cacheable */
...@@ -196,6 +218,8 @@ int git_attr_file__load( ...@@ -196,6 +218,8 @@ int git_attr_file__load(
cleanup: cleanup:
git_blob_free(blob); git_blob_free(blob);
git_tree_entry_free(tree_entry);
git_tree_free(tree);
git_buf_dispose(&content); git_buf_dispose(&content);
return error; return error;
...@@ -236,6 +260,19 @@ int git_attr_file__out_of_date( ...@@ -236,6 +260,19 @@ int git_attr_file__out_of_date(
return (git_oid__cmp(&file->cache_data.oid, &id) != 0); 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: default:
git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source); git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source);
return -1; return -1;
......
...@@ -40,8 +40,9 @@ typedef enum { ...@@ -40,8 +40,9 @@ 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__FROM_HEAD = 3,
GIT_ATTR_FILE_NUM_SOURCES = 3 GIT_ATTR_FILE_NUM_SOURCES = 4
} git_attr_file_source; } git_attr_file_source;
extern const char *git_attr__true; extern const char *git_attr__true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment