Unverified Commit 003a1df6 by Edward Thomson Committed by GitHub

Merge pull request #5952 from libgit2/ethomson/attrs_from_commit

Support reading attributes from a specific commit
parents f313b383 1439b9ff
...@@ -130,9 +130,32 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); ...@@ -130,9 +130,32 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
* *
* Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes * Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes
* from a `.gitattributes` file in the repository at the HEAD revision. * 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_NO_SYSTEM (1 << 2)
#define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3) #define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3)
#define GIT_ATTR_CHECK_INCLUDE_COMMIT (1 << 4)
/**
* An options structure for querying attributes.
*/
typedef struct {
unsigned int version;
/** 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
#define GIT_ATTR_OPTIONS_INIT {GIT_ATTR_OPTIONS_VERSION}
/** /**
* Look up the value of one git attribute for path. * Look up the value of one git attribute for path.
...@@ -157,6 +180,28 @@ GIT_EXTERN(int) git_attr_get( ...@@ -157,6 +180,28 @@ GIT_EXTERN(int) git_attr_get(
const char *name); const char *name);
/** /**
* Look up the value of one git attribute for path with extended options.
*
* @param value_out Output of the value of the attribute. Use the GIT_ATTR_...
* macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just
* use the string value for attributes set to a value. You
* should NOT modify or free this value.
* @param repo The repository containing the path.
* @param opts The `git_attr_options` to use when querying these attributes.
* @param path The path to check for attributes. Relative paths are
* interpreted relative to the repo root. The file does
* not have to exist, but if it does not, then it will be
* treated as a plain file (not a directory).
* @param name The name of the attribute to look up.
*/
GIT_EXTERN(int) git_attr_get_ext(
const char **value_out,
git_repository *repo,
git_attr_options *opts,
const char *path,
const char *name);
/**
* Look up a list of git attributes for path. * Look up a list of git attributes for path.
* *
* Use this if you have a known list of attributes that you want to * Use this if you have a known list of attributes that you want to
...@@ -194,6 +239,30 @@ GIT_EXTERN(int) git_attr_get_many( ...@@ -194,6 +239,30 @@ GIT_EXTERN(int) git_attr_get_many(
const char **names); const char **names);
/** /**
* Look up a list of git attributes for path with extended options.
*
* @param values_out An array of num_attr entries that will have string
* pointers written into it for the values of the attributes.
* You should not modify or free the values that are written
* into this array (although of course, you should free the
* array itself if you allocated it).
* @param repo The repository containing the path.
* @param opts The `git_attr_options` to use when querying these attributes.
* @param path The path inside the repo to check attributes. This
* does not have to exist, but if it does not, then
* it will be treated as a plain file (i.e. not a directory).
* @param num_attr The number of attributes being looked up
* @param names An array of num_attr strings containing attribute names.
*/
GIT_EXTERN(int) git_attr_get_many_ext(
const char **values_out,
git_repository *repo,
git_attr_options *opts,
const char *path,
size_t num_attr,
const char **names);
/**
* The callback used with git_attr_foreach. * The callback used with git_attr_foreach.
* *
* This callback will be invoked only once per attribute name, even if there * This callback will be invoked only once per attribute name, even if there
...@@ -232,6 +301,26 @@ GIT_EXTERN(int) git_attr_foreach( ...@@ -232,6 +301,26 @@ GIT_EXTERN(int) git_attr_foreach(
void *payload); void *payload);
/** /**
* Loop over all the git attributes for a path with extended options.
*
* @param repo The repository containing the path.
* @param opts The `git_attr_options` to use when querying these attributes.
* @param path Path inside the repo to check attributes. This does not have
* to exist, but if it does not, then it will be treated as a
* plain file (i.e. not a directory).
* @param callback Function to invoke on each attribute name and value.
* See git_attr_foreach_cb.
* @param payload Passed on as extra parameter to callback function.
* @return 0 on success, non-zero callback return value, or error code
*/
GIT_EXTERN(int) git_attr_foreach_ext(
git_repository *repo,
git_attr_options *opts,
const char *path,
git_attr_foreach_cb callback,
void *payload);
/**
* Flush the gitattributes cache. * Flush the gitattributes cache.
* *
* Call this if you have reason to believe that the attributes files on * Call this if you have reason to believe that the attributes files on
......
...@@ -114,6 +114,12 @@ typedef enum { ...@@ -114,6 +114,12 @@ typedef enum {
* in the HEAD commit. * in the HEAD commit.
*/ */
GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD = (1 << 2), GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD = (1 << 2),
/**
* When set, filters will be loaded from a `.gitattributes` file
* in the specified commit.
*/
GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT = (1 << 3),
} git_blob_filter_flag_t; } git_blob_filter_flag_t;
/** /**
...@@ -128,6 +134,12 @@ typedef struct { ...@@ -128,6 +134,12 @@ typedef struct {
/** Flags to control the filtering process, see `git_blob_filter_flag_t` above */ /** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
uint32_t flags; uint32_t flags;
/**
* The commit to load attributes from, when
* `GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
*/
git_oid *commit_id;
} git_blob_filter_options; } git_blob_filter_options;
#define GIT_BLOB_FILTER_OPTIONS_VERSION 1 #define GIT_BLOB_FILTER_OPTIONS_VERSION 1
......
...@@ -49,9 +49,34 @@ typedef enum { ...@@ -49,9 +49,34 @@ typedef enum {
/** Load attributes from `.gitattributes` in the root of HEAD */ /** Load attributes from `.gitattributes` in the root of HEAD */
GIT_FILTER_ATTRIBUTES_FROM_HEAD = (1u << 2), GIT_FILTER_ATTRIBUTES_FROM_HEAD = (1u << 2),
/**
* Load attributes from `.gitattributes` in a given commit.
* This can only be specified in a `git_filter_options`.
*/
GIT_FILTER_ATTRIBUTES_FROM_COMMIT = (1u << 3),
} git_filter_flag_t; } git_filter_flag_t;
/** /**
* Filtering options
*/
typedef struct {
unsigned int version;
/** See `git_filter_flag_t` above */
uint32_t flags;
/**
* The commit to load attributes from, when
* `GIT_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
*/
git_oid *commit_id;
} git_filter_options;
#define GIT_FILTER_OPTIONS_VERSION 1
#define GIT_FILTER_OPTIONS_INIT {GIT_FILTER_OPTIONS_VERSION}
/**
* A filter that can transform file data * A filter that can transform file data
* *
* This represents a filter that can be used to transform or even replace * This represents a filter that can be used to transform or even replace
...@@ -104,6 +129,29 @@ GIT_EXTERN(int) git_filter_list_load( ...@@ -104,6 +129,29 @@ GIT_EXTERN(int) git_filter_list_load(
uint32_t flags); uint32_t flags);
/** /**
* Load the filter list for a given path.
*
* This will return 0 (success) but set the output git_filter_list to NULL
* if no filters are requested for the given file.
*
* @param filters Output newly created git_filter_list (or NULL)
* @param repo Repository object that contains `path`
* @param blob The blob to which the filter will be applied (if known)
* @param path Relative path of the file to be filtered
* @param mode Filtering direction (WT->ODB or ODB->WT)
* @param opts The `git_filter_options` to use when loading filters
* @return 0 on success (which could still return NULL if no filters are
* needed for the requested file), <0 on error
*/
GIT_EXTERN(int) git_filter_list_load_ext(
git_filter_list **filters,
git_repository *repo,
git_blob *blob,
const char *path,
git_filter_mode_t mode,
git_filter_options *opts);
/**
* Query the filter list to see if a given filter (by name) will run. * Query the filter list to see if a given filter (by name) will run.
* The built-in filters "crlf" and "ident" can be queried, otherwise this * The built-in filters "crlf" and "ident" can be queried, otherwise this
* is the name of the filter specified by the filter attribute. * is the name of the filter specified by the filter attribute.
......
...@@ -33,7 +33,7 @@ static void attr_file_free(git_attr_file *file) ...@@ -33,7 +33,7 @@ static void attr_file_free(git_attr_file *file)
int git_attr_file__new( int git_attr_file__new(
git_attr_file **out, git_attr_file **out,
git_attr_file_entry *entry, git_attr_file_entry *entry,
git_attr_file_source source) git_attr_file_source *source)
{ {
git_attr_file *attrs = git__calloc(1, sizeof(git_attr_file)); git_attr_file *attrs = git__calloc(1, sizeof(git_attr_file));
GIT_ERROR_CHECK_ALLOC(attrs); GIT_ERROR_CHECK_ALLOC(attrs);
...@@ -47,8 +47,8 @@ int git_attr_file__new( ...@@ -47,8 +47,8 @@ int git_attr_file__new(
goto on_error; goto on_error;
GIT_REFCOUNT_INC(attrs); GIT_REFCOUNT_INC(attrs);
attrs->entry = entry; attrs->entry = entry;
attrs->source = source; memcpy(&attrs->source, source, sizeof(git_attr_file_source));
*out = attrs; *out = attrs;
return 0; return 0;
...@@ -108,11 +108,12 @@ int git_attr_file__load( ...@@ -108,11 +108,12 @@ int git_attr_file__load(
git_repository *repo, git_repository *repo,
git_attr_session *attr_session, 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,
bool allow_macros) bool allow_macros)
{ {
int error = 0; int error = 0;
git_commit *commit = NULL;
git_tree *tree = NULL; git_tree *tree = NULL;
git_tree_entry *tree_entry = NULL; git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL; git_blob *blob = NULL;
...@@ -128,11 +129,11 @@ int git_attr_file__load( ...@@ -128,11 +129,11 @@ int git_attr_file__load(
*out = NULL; *out = NULL;
switch (source) { switch (source->type) {
case GIT_ATTR_FILE__IN_MEMORY: case GIT_ATTR_FILE_SOURCE_MEMORY:
/* 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_SOURCE_INDEX: {
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;
...@@ -145,7 +146,7 @@ int git_attr_file__load( ...@@ -145,7 +146,7 @@ int git_attr_file__load(
git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize); git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize);
break; break;
} }
case GIT_ATTR_FILE__FROM_FILE: { case GIT_ATTR_FILE_SOURCE_FILE: {
int fd = -1; int fd = -1;
/* For open or read errors, pretend that we got ENOTFOUND. */ /* For open or read errors, pretend that we got ENOTFOUND. */
...@@ -162,10 +163,31 @@ int git_attr_file__load( ...@@ -162,10 +163,31 @@ int git_attr_file__load(
break; break;
} }
case GIT_ATTR_FILE__FROM_HEAD: { case GIT_ATTR_FILE_SOURCE_COMMIT: {
if ((error = git_repository_head_tree(&tree, repo)) < 0 || if (source->commit_id) {
(error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0 || if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0 ||
(error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 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) {
/*
* If the attributes file does not exist, we can
* cache an empty file for this commit to prevent
* needless future lookups.
*/
if (error == GIT_ENOTFOUND) {
error = 0;
break;
}
goto cleanup;
}
if ((error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0)
goto cleanup; goto cleanup;
/* /*
...@@ -182,7 +204,7 @@ int git_attr_file__load( ...@@ -182,7 +204,7 @@ int git_attr_file__load(
break; 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->type);
return -1; return -1;
} }
...@@ -210,11 +232,11 @@ int git_attr_file__load( ...@@ -210,11 +232,11 @@ int git_attr_file__load(
/* write cache breakers */ /* write cache breakers */
if (nonexistent) if (nonexistent)
file->nonexistent = 1; file->nonexistent = 1;
else if (source == GIT_ATTR_FILE__FROM_INDEX) else if (source->type == GIT_ATTR_FILE_SOURCE_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) else if (source->type == GIT_ATTR_FILE_SOURCE_COMMIT)
git_oid_cpy(&file->cache_data.oid, git_tree_id(tree)); git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
else if (source == GIT_ATTR_FILE__FROM_FILE) else if (source->type == GIT_ATTR_FILE_SOURCE_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 */
...@@ -224,6 +246,7 @@ cleanup: ...@@ -224,6 +246,7 @@ cleanup:
git_blob_free(blob); git_blob_free(blob);
git_tree_entry_free(tree_entry); git_tree_entry_free(tree_entry);
git_tree_free(tree); git_tree_free(tree);
git_commit_free(commit);
git_buf_dispose(&content); git_buf_dispose(&content);
return error; return error;
...@@ -232,7 +255,8 @@ cleanup: ...@@ -232,7 +255,8 @@ cleanup:
int git_attr_file__out_of_date( int git_attr_file__out_of_date(
git_repository *repo, git_repository *repo,
git_attr_session *attr_session, git_attr_session *attr_session,
git_attr_file *file) git_attr_file *file,
git_attr_file_source *source)
{ {
if (!file) if (!file)
return 1; return 1;
...@@ -245,15 +269,15 @@ int git_attr_file__out_of_date( ...@@ -245,15 +269,15 @@ int git_attr_file__out_of_date(
else if (file->nonexistent) else if (file->nonexistent)
return 1; return 1;
switch (file->source) { switch (file->source.type) {
case GIT_ATTR_FILE__IN_MEMORY: case GIT_ATTR_FILE_SOURCE_MEMORY:
return 0; return 0;
case GIT_ATTR_FILE__FROM_FILE: case GIT_ATTR_FILE_SOURCE_FILE:
return git_futils_filestamp_check( return git_futils_filestamp_check(
&file->cache_data.stamp, file->entry->fullpath); &file->cache_data.stamp, file->entry->fullpath);
case GIT_ATTR_FILE__FROM_INDEX: { case GIT_ATTR_FILE_SOURCE_INDEX: {
int error; int error;
git_oid id; git_oid id;
...@@ -264,21 +288,34 @@ int git_attr_file__out_of_date( ...@@ -264,21 +288,34 @@ 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: { case GIT_ATTR_FILE_SOURCE_COMMIT: {
git_tree *tree; git_tree *tree = NULL;
int error; 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; 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); git_tree_free(tree);
return error; 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.type);
return -1; return -1;
} }
} }
...@@ -389,6 +426,7 @@ int git_attr_file__lookup_one( ...@@ -389,6 +426,7 @@ int git_attr_file__lookup_one(
int git_attr_file__load_standalone(git_attr_file **out, const char *path) int git_attr_file__load_standalone(git_attr_file **out, const char *path)
{ {
git_buf content = GIT_BUF_INIT; git_buf content = GIT_BUF_INIT;
git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE };
git_attr_file *file = NULL; git_attr_file *file = NULL;
int error; int error;
...@@ -400,7 +438,7 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path) ...@@ -400,7 +438,7 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path)
* don't have to free it - freeing file+pool will free cache entry, too. * don't have to free it - freeing file+pool will free cache entry, too.
*/ */
if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 || if ((error = git_attr_file__new(&file, NULL, &source)) < 0 ||
(error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 || (error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 ||
(error = git_attr_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0) (error = git_attr_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0)
goto out; goto out;
......
...@@ -37,12 +37,30 @@ ...@@ -37,12 +37,30 @@
(GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO) (GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
typedef enum { typedef enum {
GIT_ATTR_FILE__IN_MEMORY = 0, GIT_ATTR_FILE_SOURCE_MEMORY = 0,
GIT_ATTR_FILE__FROM_FILE = 1, GIT_ATTR_FILE_SOURCE_FILE = 1,
GIT_ATTR_FILE__FROM_INDEX = 2, GIT_ATTR_FILE_SOURCE_INDEX = 2,
GIT_ATTR_FILE__FROM_HEAD = 3, GIT_ATTR_FILE_SOURCE_COMMIT = 3,
GIT_ATTR_FILE_NUM_SOURCES = 4 GIT_ATTR_FILE_NUM_SOURCES = 4
} git_attr_file_source_t;
typedef struct {
/* The source location for the attribute file. */
git_attr_file_source_t type;
/*
* The filename of the attribute file to read (relative to the
* given base path).
*/
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; } git_attr_file_source;
extern const char *git_attr__true; extern const char *git_attr__true;
...@@ -124,7 +142,7 @@ extern int git_attr_get_many_with_session( ...@@ -124,7 +142,7 @@ extern int git_attr_get_many_with_session(
const char **values_out, const char **values_out,
git_repository *repo, git_repository *repo,
git_attr_session *attr_session, git_attr_session *attr_session,
uint32_t flags, git_attr_options *opts,
const char *path, const char *path,
size_t num_attr, size_t num_attr,
const char **names); const char **names);
...@@ -142,7 +160,7 @@ typedef int (*git_attr_file_parser)( ...@@ -142,7 +160,7 @@ typedef int (*git_attr_file_parser)(
int git_attr_file__new( int git_attr_file__new(
git_attr_file **out, git_attr_file **out,
git_attr_file_entry *entry, git_attr_file_entry *entry,
git_attr_file_source source); git_attr_file_source *source);
void git_attr_file__free(git_attr_file *file); void git_attr_file__free(git_attr_file *file);
...@@ -151,7 +169,7 @@ int git_attr_file__load( ...@@ -151,7 +169,7 @@ int git_attr_file__load(
git_repository *repo, git_repository *repo,
git_attr_session *attr_session, 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,
bool allow_macros); bool allow_macros);
...@@ -159,7 +177,7 @@ int git_attr_file__load_standalone( ...@@ -159,7 +177,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_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( int git_attr_file__parse_buffer(
git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros); git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros);
......
...@@ -112,7 +112,7 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file) ...@@ -112,7 +112,7 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
* Replace the existing value if another thread has * Replace the existing value if another thread has
* created it in the meantime. * created it in the meantime.
*/ */
old = git_atomic_swap(entry->file[file->source], file); old = git_atomic_swap(entry->file[file->source.type], file);
if (old) { if (old) {
GIT_REFCOUNT_OWN(old, NULL); GIT_REFCOUNT_OWN(old, NULL);
...@@ -136,7 +136,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file) ...@@ -136,7 +136,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
return error; return error;
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL) if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
old = git_atomic_compare_and_swap(&entry->file[file->source], file, NULL); old = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
attr_cache_unlock(cache); attr_cache_unlock(cache);
...@@ -158,41 +158,42 @@ static int attr_cache_lookup( ...@@ -158,41 +158,42 @@ static int attr_cache_lookup(
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_session *attr_session,
git_attr_file_source source, git_attr_file_source *source)
const char *base,
const char *filename)
{ {
int error = 0; int error = 0;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
const char *wd = git_repository_workdir(repo), *relfile; const char *wd = git_repository_workdir(repo);
const char *filename;
git_attr_cache *cache = git_repository_attr_cache(repo); git_attr_cache *cache = git_repository_attr_cache(repo);
git_attr_file_entry *entry = NULL; git_attr_file_entry *entry = NULL;
git_attr_file *file = NULL; git_attr_file *file = NULL;
/* join base and path as needed */ /* join base and path as needed */
if (base != NULL && git_path_root(filename) < 0) { if (source->base != NULL && git_path_root(source->filename) < 0) {
git_buf *p = attr_session ? &attr_session->tmp : &path; git_buf *p = attr_session ? &attr_session->tmp : &path;
if (git_buf_joinpath(p, base, filename) < 0 || if (git_buf_joinpath(p, source->base, source->filename) < 0 ||
git_path_validate_workdir_buf(repo, p) < 0) git_path_validate_workdir_buf(repo, p) < 0)
return -1; return -1;
filename = p->ptr; filename = p->ptr;
} else {
filename = source->filename;
} }
relfile = filename; if (wd && !git__prefixcmp(filename, wd))
if (wd && !git__prefixcmp(relfile, wd)) filename += strlen(wd);
relfile += strlen(wd);
/* check cache for existing entry */ /* check cache for existing entry */
if ((error = attr_cache_lock(cache)) < 0) if ((error = attr_cache_lock(cache)) < 0)
goto cleanup; goto cleanup;
entry = attr_cache_lookup_entry(cache, relfile); entry = attr_cache_lookup_entry(cache, filename);
if (!entry)
error = attr_cache_make_entry(&entry, repo, relfile); if (!entry) {
else if (entry->file[source] != NULL) { error = attr_cache_make_entry(&entry, repo, filename);
file = entry->file[source]; } else if (entry->file[source->type] != NULL) {
file = entry->file[source->type];
GIT_REFCOUNT_INC(file); GIT_REFCOUNT_INC(file);
} }
...@@ -210,9 +211,7 @@ int git_attr_cache__get( ...@@ -210,9 +211,7 @@ 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_session *attr_session,
git_attr_file_source source, git_attr_file_source *source,
const char *base,
const char *filename,
git_attr_file_parser parser, git_attr_file_parser parser,
bool allow_macros) bool allow_macros)
{ {
...@@ -221,19 +220,21 @@ int git_attr_cache__get( ...@@ -221,19 +220,21 @@ int git_attr_cache__get(
git_attr_file_entry *entry = NULL; git_attr_file_entry *entry = NULL;
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, attr_session, source)) < 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, attr_session, file)) > 0) if (!file ||
error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser, allow_macros); (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 we loaded the file, insert into and/or update cache */
if (updated) { if (updated) {
if ((error = attr_cache_upsert(cache, updated)) < 0) if ((error = attr_cache_upsert(cache, updated)) < 0) {
git_attr_file__free(updated); git_attr_file__free(updated);
else { } else {
git_attr_file__free(file); /* offset incref from lookup */ git_attr_file__free(file); /* offset incref from lookup */
file = updated; file = updated;
} }
...@@ -260,7 +261,7 @@ int git_attr_cache__get( ...@@ -260,7 +261,7 @@ int git_attr_cache__get(
bool git_attr_cache__is_cached( bool git_attr_cache__is_cached(
git_repository *repo, git_repository *repo,
git_attr_file_source source, git_attr_file_source_t source_type,
const char *filename) const char *filename)
{ {
git_attr_cache *cache = git_repository_attr_cache(repo); git_attr_cache *cache = git_repository_attr_cache(repo);
...@@ -273,7 +274,7 @@ bool git_attr_cache__is_cached( ...@@ -273,7 +274,7 @@ bool git_attr_cache__is_cached(
if ((entry = git_strmap_get(files, filename)) == NULL) if ((entry = git_strmap_get(files, filename)) == NULL)
return false; return false;
return entry && (entry->file[source] != NULL); return entry && (entry->file[source_type] != NULL);
} }
......
...@@ -31,16 +31,14 @@ extern int git_attr_cache__get( ...@@ -31,16 +31,14 @@ 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_session *attr_session,
git_attr_file_source source, git_attr_file_source *source,
const char *base,
const char *filename,
git_attr_file_parser parser, git_attr_file_parser parser,
bool allow_macros); bool allow_macros);
extern bool git_attr_cache__is_cached( extern bool git_attr_cache__is_cached(
git_repository *repo, git_repository *repo,
git_attr_file_source source, git_attr_file_source_t source_type,
const char *path); const char *filename);
extern int git_attr_cache__alloc_file_entry( extern int git_attr_cache__alloc_file_entry(
git_attr_file_entry **out, git_attr_file_entry **out,
......
...@@ -421,7 +421,7 @@ int git_blob_filter( ...@@ -421,7 +421,7 @@ int git_blob_filter(
int error = 0; int error = 0;
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT; git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
git_filter_flag_t flags = GIT_FILTER_DEFAULT; git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
GIT_ASSERT_ARG(blob); GIT_ASSERT_ARG(blob);
GIT_ASSERT_ARG(path); GIT_ASSERT_ARG(path);
...@@ -441,14 +441,19 @@ int git_blob_filter( ...@@ -441,14 +441,19 @@ int git_blob_filter(
return 0; return 0;
if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES; filter_opts.flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0) if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD; filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
if (!(error = git_filter_list_load( if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_COMMIT;
filter_opts.commit_id = opts.commit_id;
}
if (!(error = git_filter_list_load_ext(
&fl, git_blob_owner(blob), blob, path, &fl, git_blob_owner(blob), blob, path,
GIT_FILTER_TO_WORKTREE, flags))) { GIT_FILTER_TO_WORKTREE, &filter_opts))) {
error = git_filter_list_apply_to_blob(out, fl, blob); error = git_filter_list_apply_to_blob(out, fl, blob);
......
...@@ -1513,7 +1513,7 @@ static int blob_content_to_file( ...@@ -1513,7 +1513,7 @@ static int blob_content_to_file(
int flags = data->opts.file_open_flags; int flags = data->opts.file_open_flags;
mode_t file_mode = data->opts.file_mode ? mode_t file_mode = data->opts.file_mode ?
data->opts.file_mode : entry_filemode; data->opts.file_mode : entry_filemode;
git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
struct checkout_stream writer; struct checkout_stream writer;
mode_t mode; mode_t mode;
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
...@@ -1536,13 +1536,13 @@ static int blob_content_to_file( ...@@ -1536,13 +1536,13 @@ static int blob_content_to_file(
return fd; return fd;
} }
filter_opts.attr_session = &data->attr_session; filter_session.attr_session = &data->attr_session;
filter_opts.temp_buf = &data->tmp; filter_session.temp_buf = &data->tmp;
if (!data->opts.disable_filters && if (!data->opts.disable_filters &&
(error = git_filter_list__load_ext( (error = git_filter_list__load(
&fl, data->repo, blob, hint_path, &fl, data->repo, blob, hint_path,
GIT_FILTER_TO_WORKTREE, &filter_opts))) { GIT_FILTER_TO_WORKTREE, &filter_session))) {
p_close(fd); p_close(fd);
return error; return error;
} }
...@@ -2064,7 +2064,7 @@ static int checkout_write_merge( ...@@ -2064,7 +2064,7 @@ static int checkout_write_merge(
git_merge_file_result result = {0}; git_merge_file_result result = {0};
git_filebuf output = GIT_FILEBUF_INIT; git_filebuf output = GIT_FILEBUF_INIT;
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
int error = 0; int error = 0;
if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3) if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
...@@ -2114,12 +2114,12 @@ static int checkout_write_merge( ...@@ -2114,12 +2114,12 @@ 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;
filter_opts.attr_session = &data->attr_session; filter_session.attr_session = &data->attr_session;
filter_opts.temp_buf = &data->tmp; filter_session.temp_buf = &data->tmp;
if ((error = git_filter_list__load_ext( if ((error = git_filter_list__load(
&fl, data->repo, NULL, git_buf_cstr(&path_workdir), &fl, data->repo, NULL, git_buf_cstr(&path_workdir),
GIT_FILTER_TO_WORKTREE, &filter_opts)) < 0 || GIT_FILTER_TO_WORKTREE, &filter_session)) < 0 ||
(error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0) (error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0)
goto done; goto done;
} else { } else {
......
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
#include "array.h" #include "array.h"
struct git_filter_source { struct git_filter_source {
git_repository *repo; git_repository *repo;
const char *path; const char *path;
git_oid oid; /* zero if unknown (which is likely) */ git_oid oid; /* zero if unknown (which is likely) */
uint16_t filemode; /* zero if unknown */ uint16_t filemode; /* zero if unknown */
git_filter_mode_t mode; git_filter_mode_t mode;
uint32_t flags; git_filter_options options;
}; };
typedef struct { typedef struct {
...@@ -396,7 +396,7 @@ git_filter_mode_t git_filter_source_mode(const git_filter_source *src) ...@@ -396,7 +396,7 @@ git_filter_mode_t git_filter_source_mode(const git_filter_source *src)
uint32_t git_filter_source_flags(const git_filter_source *src) uint32_t git_filter_source_flags(const git_filter_source *src)
{ {
return src->flags; return src->options.flags;
} }
static int filter_list_new( static int filter_list_new(
...@@ -416,7 +416,8 @@ static int filter_list_new( ...@@ -416,7 +416,8 @@ static int filter_list_new(
fl->source.repo = src->repo; fl->source.repo = src->repo;
fl->source.path = fl->path; fl->source.path = fl->path;
fl->source.mode = src->mode; fl->source.mode = src->mode;
fl->source.flags = src->flags;
memcpy(&fl->source.options, &src->options, sizeof(git_filter_options));
*out = fl; *out = fl;
return 0; return 0;
...@@ -425,25 +426,30 @@ static int filter_list_new( ...@@ -425,25 +426,30 @@ static int filter_list_new(
static int filter_list_check_attributes( static int filter_list_check_attributes(
const char ***out, const char ***out,
git_repository *repo, git_repository *repo,
git_attr_session *attr_session, git_filter_session *filter_session,
git_filter_def *fdef, git_filter_def *fdef,
const git_filter_source *src) const git_filter_source *src)
{ {
const char **strs = git__calloc(fdef->nattrs, sizeof(const char *)); const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
uint32_t flags = 0; git_attr_options attr_opts = GIT_ATTR_OPTIONS_INIT;
size_t i; size_t i;
int error; int error;
GIT_ERROR_CHECK_ALLOC(strs); GIT_ERROR_CHECK_ALLOC(strs);
if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) if ((src->options.flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
flags |= GIT_ATTR_CHECK_NO_SYSTEM; attr_opts.flags |= GIT_ATTR_CHECK_NO_SYSTEM;
if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0) if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
flags |= GIT_ATTR_CHECK_INCLUDE_HEAD; attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_COMMIT;
attr_opts.commit_id = src->options.commit_id;
}
error = git_attr_get_many_with_session( error = git_attr_get_many_with_session(
strs, repo, attr_session, flags, src->path, fdef->nattrs, fdef->attrs); strs, repo, filter_session->attr_session, &attr_opts, 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) {
...@@ -488,17 +494,17 @@ int git_filter_list_new( ...@@ -488,17 +494,17 @@ int git_filter_list_new(
src.repo = repo; src.repo = repo;
src.path = NULL; src.path = NULL;
src.mode = mode; src.mode = mode;
src.flags = flags; src.options.flags = flags;
return filter_list_new(out, &src); return filter_list_new(out, &src);
} }
int git_filter_list__load_ext( int git_filter_list__load(
git_filter_list **filters, git_filter_list **filters,
git_repository *repo, git_repository *repo,
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,
git_filter_options *filter_opts) git_filter_session *filter_session)
{ {
int error = 0; int error = 0;
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
...@@ -515,7 +521,8 @@ int git_filter_list__load_ext( ...@@ -515,7 +521,8 @@ int git_filter_list__load_ext(
src.repo = repo; src.repo = repo;
src.path = path; src.path = path;
src.mode = mode; src.mode = mode;
src.flags = filter_opts->flags;
memcpy(&src.options, &filter_session->options, sizeof(git_filter_options));
if (blob) if (blob)
git_oid_cpy(&src.oid, git_blob_id(blob)); git_oid_cpy(&src.oid, git_blob_id(blob));
...@@ -529,7 +536,8 @@ int git_filter_list__load_ext( ...@@ -529,7 +536,8 @@ int git_filter_list__load_ext(
if (fdef->nattrs > 0) { if (fdef->nattrs > 0) {
error = filter_list_check_attributes( error = filter_list_check_attributes(
&values, repo, filter_opts->attr_session, fdef, &src); &values, repo,
filter_session, fdef, &src);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND) {
error = 0; error = 0;
...@@ -556,7 +564,7 @@ int git_filter_list__load_ext( ...@@ -556,7 +564,7 @@ int git_filter_list__load_ext(
if ((error = filter_list_new(&fl, &src)) < 0) if ((error = filter_list_new(&fl, &src)) < 0)
break; break;
fl->temp_buf = filter_opts->temp_buf; fl->temp_buf = filter_session->temp_buf;
} }
fe = git_array_alloc(fl->filters); fe = git_array_alloc(fl->filters);
...@@ -580,6 +588,23 @@ int git_filter_list__load_ext( ...@@ -580,6 +588,23 @@ int git_filter_list__load_ext(
return error; return error;
} }
int git_filter_list_load_ext(
git_filter_list **filters,
git_repository *repo,
git_blob *blob, /* can be NULL */
const char *path,
git_filter_mode_t mode,
git_filter_options *opts)
{
git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
if (opts)
memcpy(&filter_session.options, opts, sizeof(git_filter_options));
return git_filter_list__load(
filters, repo, blob, path, mode, &filter_session);
}
int git_filter_list_load( int git_filter_list_load(
git_filter_list **filters, git_filter_list **filters,
git_repository *repo, git_repository *repo,
...@@ -588,12 +613,12 @@ int git_filter_list_load( ...@@ -588,12 +613,12 @@ int git_filter_list_load(
git_filter_mode_t mode, git_filter_mode_t mode,
uint32_t flags) uint32_t flags)
{ {
git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
filter_opts.flags = flags; filter_session.options.flags = flags;
return git_filter_list__load_ext( return git_filter_list__load(
filters, repo, blob, path, mode, &filter_opts); filters, repo, blob, path, mode, &filter_session);
} }
void git_filter_list_free(git_filter_list *fl) void git_filter_list_free(git_filter_list *fl)
......
...@@ -16,24 +16,24 @@ ...@@ -16,24 +16,24 @@
#define GIT_FILTER_BYTES_TO_CHECK_NUL 8000 #define GIT_FILTER_BYTES_TO_CHECK_NUL 8000
typedef struct { typedef struct {
git_filter_options options;
git_attr_session *attr_session; git_attr_session *attr_session;
git_buf *temp_buf; git_buf *temp_buf;
uint32_t flags; } git_filter_session;
} git_filter_options;
#define GIT_FILTER_OPTIONS_INIT {0} #define GIT_FILTER_SESSION_INIT {GIT_FILTER_OPTIONS_INIT, 0}
extern int git_filter_global_init(void); extern int git_filter_global_init(void);
extern void git_filter_free(git_filter *filter); extern void git_filter_free(git_filter *filter);
extern int git_filter_list__load_ext( extern int git_filter_list__load(
git_filter_list **filters, git_filter_list **filters,
git_repository *repo, git_repository *repo,
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,
git_filter_options *filter_opts); git_filter_session *filter_session);
/* /*
* The given input buffer will be converted to the given output buffer. * The given input buffer will be converted to the given output buffer.
......
...@@ -247,11 +247,12 @@ static int push_ignore_file( ...@@ -247,11 +247,12 @@ static int push_ignore_file(
const char *base, const char *base,
const char *filename) const char *filename)
{ {
int error = 0; git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE, base, filename };
git_attr_file *file = NULL; git_attr_file *file = NULL;
int error = 0;
error = git_attr_cache__get(&file, ignores->repo, NULL, &source, parse_ignore_file, false);
error = git_attr_cache__get(&file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
base, filename, parse_ignore_file, false);
if (error < 0) if (error < 0)
return error; return error;
...@@ -272,13 +273,13 @@ static int push_one_ignore(void *payload, const char *path) ...@@ -272,13 +273,13 @@ static int push_one_ignore(void *payload, const char *path)
static int get_internal_ignores(git_attr_file **out, git_repository *repo) static int get_internal_ignores(git_attr_file **out, git_repository *repo)
{ {
git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_MEMORY, NULL, GIT_IGNORE_INTERNAL };
int error; int error;
if ((error = git_attr_cache__init(repo)) < 0) if ((error = git_attr_cache__init(repo)) < 0)
return error; return error;
error = git_attr_cache__get(out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL, error = git_attr_cache__get(out, repo, NULL, &source, NULL, false);
GIT_IGNORE_INTERNAL, NULL, false);
/* 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)
......
...@@ -236,6 +236,7 @@ void test_attr_lookup__check_attr_examples(void) ...@@ -236,6 +236,7 @@ void test_attr_lookup__check_attr_examples(void)
void test_attr_lookup__from_buffer(void) void test_attr_lookup__from_buffer(void)
{ {
git_attr_file *file; git_attr_file *file;
git_attr_file_source source = {0};
struct attr_expected cases[] = { struct attr_expected cases[] = {
{ "abc", "foo", EXPECT_TRUE, NULL }, { "abc", "foo", EXPECT_TRUE, NULL },
...@@ -250,7 +251,7 @@ void test_attr_lookup__from_buffer(void) ...@@ -250,7 +251,7 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
cl_git_pass(git_attr_file__new(&file, NULL, 0)); cl_git_pass(git_attr_file__new(&file, NULL, &source));
cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz", true)); cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz", true));
......
...@@ -71,11 +71,11 @@ void test_attr_repo__get_one(void) ...@@ -71,11 +71,11 @@ void test_attr_repo__get_one(void)
} }
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
} }
void test_attr_repo__get_one_start_deep(void) void test_attr_repo__get_one_start_deep(void)
...@@ -92,11 +92,11 @@ void test_attr_repo__get_one_start_deep(void) ...@@ -92,11 +92,11 @@ void test_attr_repo__get_one_start_deep(void)
} }
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
} }
void test_attr_repo__get_many(void) void test_attr_repo__get_many(void)
...@@ -341,7 +341,7 @@ void test_attr_repo__sysdir_with_session(void) ...@@ -341,7 +341,7 @@ void test_attr_repo__sysdir_with_session(void)
g_repo = cl_git_sandbox_reopen(); g_repo = cl_git_sandbox_reopen();
cl_git_pass(git_attr_session__init(&session, g_repo)); cl_git_pass(git_attr_session__init(&session, g_repo));
cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, 0, "file", ARRAY_SIZE(attrs), attrs)); cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, NULL, "file", ARRAY_SIZE(attrs), attrs));
cl_assert_equal_s(values[0], "1"); cl_assert_equal_s(values[0], "1");
cl_assert_equal_s(values[1], "2"); cl_assert_equal_s(values[1], "2");
......
...@@ -132,3 +132,63 @@ void test_filter_bare__sanitizes(void) ...@@ -132,3 +132,63 @@ void test_filter_bare__sanitizes(void)
git_blob_free(blob); git_blob_free(blob);
} }
void test_filter_bare__from_specific_commit_one(void)
{
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
git_blob *blob;
git_buf buf = { 0 };
git_oid commit_id;
cl_git_pass(git_oid_fromstr(&commit_id, "b8986fec0f7bde90f78ac72706e782d82f24f2f0"));
opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
opts.commit_id = &commit_id;
cl_git_pass(git_revparse_single(
(git_object **)&blob, g_repo, "055c872")); /* ident */
cl_assert_equal_s("$Id$\n", git_blob_rawcontent(blob));
cl_git_pass(git_blob_filter(&buf, blob, "ident.bin", &opts));
cl_assert_equal_s("$Id$\n", buf.ptr);
cl_git_pass(git_blob_filter(&buf, blob, "ident.identlf", &opts));
cl_assert_equal_s("$Id: 055c8729cdcc372500a08db659c045e16c4409fb $\n", buf.ptr);
git_buf_dispose(&buf);
git_blob_free(blob);
}
void test_filter_bare__from_specific_commit_with_no_attributes_file(void)
{
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
git_blob *blob;
git_buf buf = { 0 };
git_oid commit_id;
cl_git_pass(git_oid_fromstr(&commit_id, "5afb6a14a864e30787857dd92af837e8cdd2cb1b"));
opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
opts.commit_id = &commit_id;
cl_git_pass(git_revparse_single(
(git_object **)&blob, g_repo, "799770d")); /* all-lf */
cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &opts));
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
/* we never convert CRLF -> LF on platforms that have LF */
cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &opts));
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
/* we never convert CRLF -> LF on platforms that have LF */
cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &opts));
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
git_buf_dispose(&buf);
git_blob_free(blob);
}
...@@ -70,9 +70,9 @@ void test_ignore_status__0(void) ...@@ -70,9 +70,9 @@ void test_ignore_status__0(void)
/* confirm that ignore files were cached */ /* confirm that ignore files were cached */
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/exclude"));
cl_assert(git_attr_cache__is_cached( cl_assert(git_attr_cache__is_cached(
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore")); g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitignore"));
} }
......
b8986fec0f7bde90f78ac72706e782d82f24f2f0
1ec507638b806aba45d6142082885f2a9e88322d
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