mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
Merge pull request #5952 from libgit2/ethomson/attrs_from_commit
Support reading attributes from a specific commit
This commit is contained in:
@@ -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
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
@@ -156,6 +179,28 @@ GIT_EXTERN(int) git_attr_get(
|
||||
const char *path,
|
||||
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.
|
||||
*
|
||||
@@ -193,6 +238,30 @@ GIT_EXTERN(int) git_attr_get_many(
|
||||
size_t num_attr,
|
||||
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.
|
||||
*
|
||||
@@ -231,6 +300,26 @@ GIT_EXTERN(int) git_attr_foreach(
|
||||
git_attr_foreach_cb callback,
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -114,6 +114,12 @@ typedef enum {
|
||||
* in the HEAD commit.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -128,6 +134,12 @@ typedef struct {
|
||||
|
||||
/** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
|
||||
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;
|
||||
|
||||
#define GIT_BLOB_FILTER_OPTIONS_VERSION 1
|
||||
|
||||
@@ -49,8 +49,33 @@ typedef enum {
|
||||
|
||||
/** Load attributes from `.gitattributes` in the root of HEAD */
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@@ -103,6 +128,29 @@ GIT_EXTERN(int) git_filter_list_load(
|
||||
git_filter_mode_t mode,
|
||||
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.
|
||||
* The built-in filters "crlf" and "ident" can be queried, otherwise this
|
||||
|
||||
224
src/attr.c
224
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(
|
||||
@@ -200,6 +232,20 @@ int git_attr_foreach(
|
||||
const char *pathname,
|
||||
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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ static void attr_file_free(git_attr_file *file)
|
||||
int git_attr_file__new(
|
||||
git_attr_file **out,
|
||||
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_ERROR_CHECK_ALLOC(attrs);
|
||||
@@ -47,8 +47,8 @@ int git_attr_file__new(
|
||||
goto on_error;
|
||||
|
||||
GIT_REFCOUNT_INC(attrs);
|
||||
attrs->entry = entry;
|
||||
attrs->source = source;
|
||||
attrs->entry = entry;
|
||||
memcpy(&attrs->source, source, sizeof(git_attr_file_source));
|
||||
*out = attrs;
|
||||
return 0;
|
||||
|
||||
@@ -108,11 +108,12 @@ int git_attr_file__load(
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_attr_file_entry *entry,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_source *source,
|
||||
git_attr_file_parser parser,
|
||||
bool allow_macros)
|
||||
{
|
||||
int error = 0;
|
||||
git_commit *commit = NULL;
|
||||
git_tree *tree = NULL;
|
||||
git_tree_entry *tree_entry = NULL;
|
||||
git_blob *blob = NULL;
|
||||
@@ -128,11 +129,11 @@ int git_attr_file__load(
|
||||
|
||||
*out = NULL;
|
||||
|
||||
switch (source) {
|
||||
case GIT_ATTR_FILE__IN_MEMORY:
|
||||
switch (source->type) {
|
||||
case GIT_ATTR_FILE_SOURCE_MEMORY:
|
||||
/* in-memory attribute file doesn't need data */
|
||||
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 ||
|
||||
(error = git_blob_lookup(&blob, repo, &id)) < 0)
|
||||
return error;
|
||||
@@ -145,7 +146,7 @@ int git_attr_file__load(
|
||||
git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize);
|
||||
break;
|
||||
}
|
||||
case GIT_ATTR_FILE__FROM_FILE: {
|
||||
case GIT_ATTR_FILE_SOURCE_FILE: {
|
||||
int fd = -1;
|
||||
|
||||
/* For open or read errors, pretend that we got ENOTFOUND. */
|
||||
@@ -162,10 +163,31 @@ 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)
|
||||
case GIT_ATTR_FILE_SOURCE_COMMIT: {
|
||||
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) {
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
@@ -182,7 +204,7 @@ int git_attr_file__load(
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -210,11 +232,11 @@ int git_attr_file__load(
|
||||
/* write cache breakers */
|
||||
if (nonexistent)
|
||||
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));
|
||||
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));
|
||||
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);
|
||||
/* else always cacheable */
|
||||
|
||||
@@ -224,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;
|
||||
@@ -232,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;
|
||||
@@ -245,15 +269,15 @@ int git_attr_file__out_of_date(
|
||||
else if (file->nonexistent)
|
||||
return 1;
|
||||
|
||||
switch (file->source) {
|
||||
case GIT_ATTR_FILE__IN_MEMORY:
|
||||
switch (file->source.type) {
|
||||
case GIT_ATTR_FILE_SOURCE_MEMORY:
|
||||
return 0;
|
||||
|
||||
case GIT_ATTR_FILE__FROM_FILE:
|
||||
case GIT_ATTR_FILE_SOURCE_FILE:
|
||||
return git_futils_filestamp_check(
|
||||
&file->cache_data.stamp, file->entry->fullpath);
|
||||
|
||||
case GIT_ATTR_FILE__FROM_INDEX: {
|
||||
case GIT_ATTR_FILE_SOURCE_INDEX: {
|
||||
int error;
|
||||
git_oid id;
|
||||
|
||||
@@ -264,21 +288,34 @@ 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;
|
||||
case GIT_ATTR_FILE_SOURCE_COMMIT: {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -389,6 +426,7 @@ int git_attr_file__lookup_one(
|
||||
int git_attr_file__load_standalone(git_attr_file **out, const char *path)
|
||||
{
|
||||
git_buf content = GIT_BUF_INIT;
|
||||
git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE };
|
||||
git_attr_file *file = NULL;
|
||||
int error;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
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_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0)
|
||||
goto out;
|
||||
|
||||
@@ -37,12 +37,30 @@
|
||||
(GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
|
||||
|
||||
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_SOURCE_MEMORY = 0,
|
||||
GIT_ATTR_FILE_SOURCE_FILE = 1,
|
||||
GIT_ATTR_FILE_SOURCE_INDEX = 2,
|
||||
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;
|
||||
|
||||
extern const char *git_attr__true;
|
||||
@@ -124,7 +142,7 @@ extern int git_attr_get_many_with_session(
|
||||
const char **values_out,
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
uint32_t flags,
|
||||
git_attr_options *opts,
|
||||
const char *path,
|
||||
size_t num_attr,
|
||||
const char **names);
|
||||
@@ -142,7 +160,7 @@ typedef int (*git_attr_file_parser)(
|
||||
int git_attr_file__new(
|
||||
git_attr_file **out,
|
||||
git_attr_file_entry *entry,
|
||||
git_attr_file_source source);
|
||||
git_attr_file_source *source);
|
||||
|
||||
void git_attr_file__free(git_attr_file *file);
|
||||
|
||||
@@ -151,7 +169,7 @@ int git_attr_file__load(
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_attr_file_entry *ce,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_source *source,
|
||||
git_attr_file_parser parser,
|
||||
bool allow_macros);
|
||||
|
||||
@@ -159,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);
|
||||
|
||||
@@ -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
|
||||
* 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) {
|
||||
GIT_REFCOUNT_OWN(old, NULL);
|
||||
@@ -136,7 +136,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
|
||||
return error;
|
||||
|
||||
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);
|
||||
|
||||
@@ -158,41 +158,42 @@ static int attr_cache_lookup(
|
||||
git_attr_file_entry **out_entry,
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename)
|
||||
git_attr_file_source *source)
|
||||
{
|
||||
int error = 0;
|
||||
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_file_entry *entry = NULL;
|
||||
git_attr_file *file = NULL;
|
||||
|
||||
/* 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;
|
||||
|
||||
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)
|
||||
return -1;
|
||||
|
||||
filename = p->ptr;
|
||||
} else {
|
||||
filename = source->filename;
|
||||
}
|
||||
|
||||
relfile = filename;
|
||||
if (wd && !git__prefixcmp(relfile, wd))
|
||||
relfile += strlen(wd);
|
||||
if (wd && !git__prefixcmp(filename, wd))
|
||||
filename += strlen(wd);
|
||||
|
||||
/* check cache for existing entry */
|
||||
if ((error = attr_cache_lock(cache)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
entry = attr_cache_lookup_entry(cache, relfile);
|
||||
if (!entry)
|
||||
error = attr_cache_make_entry(&entry, repo, relfile);
|
||||
else if (entry->file[source] != NULL) {
|
||||
file = entry->file[source];
|
||||
entry = attr_cache_lookup_entry(cache, filename);
|
||||
|
||||
if (!entry) {
|
||||
error = attr_cache_make_entry(&entry, repo, filename);
|
||||
} else if (entry->file[source->type] != NULL) {
|
||||
file = entry->file[source->type];
|
||||
GIT_REFCOUNT_INC(file);
|
||||
}
|
||||
|
||||
@@ -210,9 +211,7 @@ int git_attr_cache__get(
|
||||
git_attr_file **out,
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_source *source,
|
||||
git_attr_file_parser parser,
|
||||
bool allow_macros)
|
||||
{
|
||||
@@ -221,19 +220,21 @@ int git_attr_cache__get(
|
||||
git_attr_file_entry *entry = NULL;
|
||||
git_attr_file *file = NULL, *updated = NULL;
|
||||
|
||||
if ((error = attr_cache_lookup(
|
||||
&file, &entry, repo, attr_session, source, base, filename)) < 0)
|
||||
if ((error = attr_cache_lookup(&file, &entry, repo, attr_session, source)) < 0)
|
||||
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)
|
||||
error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser, allow_macros);
|
||||
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;
|
||||
}
|
||||
@@ -260,7 +261,7 @@ int git_attr_cache__get(
|
||||
|
||||
bool git_attr_cache__is_cached(
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
git_attr_file_source_t source_type,
|
||||
const char *filename)
|
||||
{
|
||||
git_attr_cache *cache = git_repository_attr_cache(repo);
|
||||
@@ -273,7 +274,7 @@ bool git_attr_cache__is_cached(
|
||||
if ((entry = git_strmap_get(files, filename)) == NULL)
|
||||
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(
|
||||
git_attr_file **file,
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_attr_file_source source,
|
||||
const char *base,
|
||||
const char *filename,
|
||||
git_attr_file_source *source,
|
||||
git_attr_file_parser parser,
|
||||
bool allow_macros);
|
||||
|
||||
extern bool git_attr_cache__is_cached(
|
||||
git_repository *repo,
|
||||
git_attr_file_source source,
|
||||
const char *path);
|
||||
git_attr_file_source_t source_type,
|
||||
const char *filename);
|
||||
|
||||
extern int git_attr_cache__alloc_file_entry(
|
||||
git_attr_file_entry **out,
|
||||
|
||||
15
src/blob.c
15
src/blob.c
@@ -421,7 +421,7 @@ int git_blob_filter(
|
||||
int error = 0;
|
||||
git_filter_list *fl = NULL;
|
||||
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(path);
|
||||
@@ -441,14 +441,19 @@ int git_blob_filter(
|
||||
return 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)
|
||||
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,
|
||||
GIT_FILTER_TO_WORKTREE, flags))) {
|
||||
GIT_FILTER_TO_WORKTREE, &filter_opts))) {
|
||||
|
||||
error = git_filter_list_apply_to_blob(out, fl, blob);
|
||||
|
||||
|
||||
@@ -1513,7 +1513,7 @@ static int blob_content_to_file(
|
||||
int flags = data->opts.file_open_flags;
|
||||
mode_t file_mode = data->opts.file_mode ?
|
||||
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;
|
||||
mode_t mode;
|
||||
git_filter_list *fl = NULL;
|
||||
@@ -1536,13 +1536,13 @@ static int blob_content_to_file(
|
||||
return fd;
|
||||
}
|
||||
|
||||
filter_opts.attr_session = &data->attr_session;
|
||||
filter_opts.temp_buf = &data->tmp;
|
||||
filter_session.attr_session = &data->attr_session;
|
||||
filter_session.temp_buf = &data->tmp;
|
||||
|
||||
if (!data->opts.disable_filters &&
|
||||
(error = git_filter_list__load_ext(
|
||||
(error = git_filter_list__load(
|
||||
&fl, data->repo, blob, hint_path,
|
||||
GIT_FILTER_TO_WORKTREE, &filter_opts))) {
|
||||
GIT_FILTER_TO_WORKTREE, &filter_session))) {
|
||||
p_close(fd);
|
||||
return error;
|
||||
}
|
||||
@@ -2064,7 +2064,7 @@ static int checkout_write_merge(
|
||||
git_merge_file_result result = {0};
|
||||
git_filebuf output = GIT_FILEBUF_INIT;
|
||||
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;
|
||||
|
||||
if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
|
||||
@@ -2114,12 +2114,12 @@ static int checkout_write_merge(
|
||||
in_data.ptr = (char *)result.ptr;
|
||||
in_data.size = result.len;
|
||||
|
||||
filter_opts.attr_session = &data->attr_session;
|
||||
filter_opts.temp_buf = &data->tmp;
|
||||
filter_session.attr_session = &data->attr_session;
|
||||
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),
|
||||
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)
|
||||
goto done;
|
||||
} else {
|
||||
|
||||
75
src/filter.c
75
src/filter.c
@@ -19,12 +19,12 @@
|
||||
#include "array.h"
|
||||
|
||||
struct git_filter_source {
|
||||
git_repository *repo;
|
||||
const char *path;
|
||||
git_oid oid; /* zero if unknown (which is likely) */
|
||||
uint16_t filemode; /* zero if unknown */
|
||||
git_filter_mode_t mode;
|
||||
uint32_t flags;
|
||||
git_repository *repo;
|
||||
const char *path;
|
||||
git_oid oid; /* zero if unknown (which is likely) */
|
||||
uint16_t filemode; /* zero if unknown */
|
||||
git_filter_mode_t mode;
|
||||
git_filter_options options;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -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)
|
||||
{
|
||||
return src->flags;
|
||||
return src->options.flags;
|
||||
}
|
||||
|
||||
static int filter_list_new(
|
||||
@@ -416,7 +416,8 @@ static int filter_list_new(
|
||||
fl->source.repo = src->repo;
|
||||
fl->source.path = fl->path;
|
||||
fl->source.mode = src->mode;
|
||||
fl->source.flags = src->flags;
|
||||
|
||||
memcpy(&fl->source.options, &src->options, sizeof(git_filter_options));
|
||||
|
||||
*out = fl;
|
||||
return 0;
|
||||
@@ -425,25 +426,30 @@ static int filter_list_new(
|
||||
static int filter_list_check_attributes(
|
||||
const char ***out,
|
||||
git_repository *repo,
|
||||
git_attr_session *attr_session,
|
||||
git_filter_session *filter_session,
|
||||
git_filter_def *fdef,
|
||||
const git_filter_source *src)
|
||||
{
|
||||
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;
|
||||
int error;
|
||||
|
||||
GIT_ERROR_CHECK_ALLOC(strs);
|
||||
|
||||
if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
|
||||
flags |= GIT_ATTR_CHECK_NO_SYSTEM;
|
||||
if ((src->options.flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
|
||||
attr_opts.flags |= GIT_ATTR_CHECK_NO_SYSTEM;
|
||||
|
||||
if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
|
||||
flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
|
||||
if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
|
||||
attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
|
||||
|
||||
if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
|
||||
attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_COMMIT;
|
||||
attr_opts.commit_id = src->options.commit_id;
|
||||
}
|
||||
|
||||
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 (error == GIT_ENOTFOUND && !fdef->nmatches) {
|
||||
@@ -488,17 +494,17 @@ int git_filter_list_new(
|
||||
src.repo = repo;
|
||||
src.path = NULL;
|
||||
src.mode = mode;
|
||||
src.flags = flags;
|
||||
src.options.flags = flags;
|
||||
return filter_list_new(out, &src);
|
||||
}
|
||||
|
||||
int git_filter_list__load_ext(
|
||||
int git_filter_list__load(
|
||||
git_filter_list **filters,
|
||||
git_repository *repo,
|
||||
git_blob *blob, /* can be NULL */
|
||||
const char *path,
|
||||
git_filter_mode_t mode,
|
||||
git_filter_options *filter_opts)
|
||||
git_filter_session *filter_session)
|
||||
{
|
||||
int error = 0;
|
||||
git_filter_list *fl = NULL;
|
||||
@@ -515,7 +521,8 @@ int git_filter_list__load_ext(
|
||||
src.repo = repo;
|
||||
src.path = path;
|
||||
src.mode = mode;
|
||||
src.flags = filter_opts->flags;
|
||||
|
||||
memcpy(&src.options, &filter_session->options, sizeof(git_filter_options));
|
||||
|
||||
if (blob)
|
||||
git_oid_cpy(&src.oid, git_blob_id(blob));
|
||||
@@ -529,7 +536,8 @@ int git_filter_list__load_ext(
|
||||
|
||||
if (fdef->nattrs > 0) {
|
||||
error = filter_list_check_attributes(
|
||||
&values, repo, filter_opts->attr_session, fdef, &src);
|
||||
&values, repo,
|
||||
filter_session, fdef, &src);
|
||||
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
error = 0;
|
||||
@@ -556,7 +564,7 @@ int git_filter_list__load_ext(
|
||||
if ((error = filter_list_new(&fl, &src)) < 0)
|
||||
break;
|
||||
|
||||
fl->temp_buf = filter_opts->temp_buf;
|
||||
fl->temp_buf = filter_session->temp_buf;
|
||||
}
|
||||
|
||||
fe = git_array_alloc(fl->filters);
|
||||
@@ -580,6 +588,23 @@ int git_filter_list__load_ext(
|
||||
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(
|
||||
git_filter_list **filters,
|
||||
git_repository *repo,
|
||||
@@ -588,12 +613,12 @@ int git_filter_list_load(
|
||||
git_filter_mode_t mode,
|
||||
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(
|
||||
filters, repo, blob, path, mode, &filter_opts);
|
||||
return git_filter_list__load(
|
||||
filters, repo, blob, path, mode, &filter_session);
|
||||
}
|
||||
|
||||
void git_filter_list_free(git_filter_list *fl)
|
||||
|
||||
10
src/filter.h
10
src/filter.h
@@ -16,24 +16,24 @@
|
||||
#define GIT_FILTER_BYTES_TO_CHECK_NUL 8000
|
||||
|
||||
typedef struct {
|
||||
git_filter_options options;
|
||||
git_attr_session *attr_session;
|
||||
git_buf *temp_buf;
|
||||
uint32_t flags;
|
||||
} git_filter_options;
|
||||
} git_filter_session;
|
||||
|
||||
#define GIT_FILTER_OPTIONS_INIT {0}
|
||||
#define GIT_FILTER_SESSION_INIT {GIT_FILTER_OPTIONS_INIT, 0}
|
||||
|
||||
extern int git_filter_global_init(void);
|
||||
|
||||
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_repository *repo,
|
||||
git_blob *blob, /* can be NULL */
|
||||
const char *path,
|
||||
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.
|
||||
|
||||
11
src/ignore.c
11
src/ignore.c
@@ -247,11 +247,12 @@ static int push_ignore_file(
|
||||
const char *base,
|
||||
const char *filename)
|
||||
{
|
||||
int error = 0;
|
||||
git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_FILE, base, filename };
|
||||
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)
|
||||
return error;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
git_attr_file_source source = { GIT_ATTR_FILE_SOURCE_MEMORY, NULL, GIT_IGNORE_INTERNAL };
|
||||
int error;
|
||||
|
||||
if ((error = git_attr_cache__init(repo)) < 0)
|
||||
return error;
|
||||
|
||||
error = git_attr_cache__get(out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL,
|
||||
GIT_IGNORE_INTERNAL, NULL, false);
|
||||
error = git_attr_cache__get(out, repo, NULL, &source, NULL, false);
|
||||
|
||||
/* if internal rules list is empty, insert default rules */
|
||||
if (!error && !(*out)->rules.length)
|
||||
|
||||
@@ -236,6 +236,7 @@ void test_attr_lookup__check_attr_examples(void)
|
||||
void test_attr_lookup__from_buffer(void)
|
||||
{
|
||||
git_attr_file *file;
|
||||
git_attr_file_source source = {0};
|
||||
|
||||
struct attr_expected cases[] = {
|
||||
{ "abc", "foo", EXPECT_TRUE, NULL },
|
||||
@@ -250,7 +251,7 @@ void test_attr_lookup__from_buffer(void)
|
||||
{ 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));
|
||||
|
||||
|
||||
@@ -71,11 +71,11 @@ void test_attr_repo__get_one(void)
|
||||
}
|
||||
|
||||
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(
|
||||
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
|
||||
g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
|
||||
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)
|
||||
@@ -92,11 +92,11 @@ void test_attr_repo__get_one_start_deep(void)
|
||||
}
|
||||
|
||||
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(
|
||||
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
|
||||
g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
|
||||
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)
|
||||
@@ -341,7 +341,7 @@ void test_attr_repo__sysdir_with_session(void)
|
||||
g_repo = cl_git_sandbox_reopen();
|
||||
|
||||
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[1], "2");
|
||||
|
||||
@@ -132,3 +132,63 @@ void test_filter_bare__sanitizes(void)
|
||||
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)
|
||||
|
||||
/* confirm that ignore files were 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(
|
||||
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
|
||||
g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitignore"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb
vendored
Normal file
BIN
tests/resources/crlf.git/objects/05/5c8729cdcc372500a08db659c045e16c4409fb
vendored
Normal file
Binary file not shown.
BIN
tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d
vendored
Normal file
BIN
tests/resources/crlf.git/objects/1e/c507638b806aba45d6142082885f2a9e88322d
vendored
Normal file
Binary file not shown.
BIN
tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c
vendored
Normal file
BIN
tests/resources/crlf.git/objects/44/b0be18671a284f1156117b6338edac2663341c
vendored
Normal file
Binary file not shown.
BIN
tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0
vendored
Normal file
BIN
tests/resources/crlf.git/objects/55/1b8fce462bba005ab6d34a2244d8a3f6b03dd0
vendored
Normal file
Binary file not shown.
3
tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0
vendored
Normal file
3
tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
x╔▐M
|
||||
б0┘]Гs%3сDtА
╪ю$≥bа6╔F╪╬Q╪│╩ВО╔2McРnSWU`▌6*Ж╬C║·д╫GЛ╒w╝в,┴|S▄и,╡Й\┴╕Ю≤ы#▀ТYЖ╝8t│);
qхахЁчй
|
||||
≈Э▓5цУV╕G≥А═-Щ╗⌠~▀÷ш╔2=Ы`яаж╡╣╕╔mlу?1Ф°3хcn╤
╨HЦ]aОjч@│U
|
||||
1
tests/resources/crlf.git/refs/heads/ident
vendored
Normal file
1
tests/resources/crlf.git/refs/heads/ident
vendored
Normal file
@@ -0,0 +1 @@
|
||||
b8986fec0f7bde90f78ac72706e782d82f24f2f0
|
||||
1
tests/resources/crlf.git/refs/heads/no-ident
vendored
Normal file
1
tests/resources/crlf.git/refs/heads/no-ident
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1ec507638b806aba45d6142082885f2a9e88322d
|
||||
Reference in New Issue
Block a user