diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-05-27 18:47:22 +0100 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2021-07-22 15:08:50 -0400 |
commit | 3779a04794333a0152a1d7ae39117278508c4680 (patch) | |
tree | be88b195e6db9710bb45e7640634b9350f13c0f0 | |
parent | 1cd863fd16a60517d2e42402c69238bf03b5dae0 (diff) | |
download | libgit2-3779a04794333a0152a1d7ae39117278508c4680.tar.gz |
attr: introduce `git_attr_options` for extended queries
Allow more advanced attribute queries using a `git_attr_options`, and
extended functions to use it. Presently there is no additional
configuration in a `git_attr_options` beyond the flags, but this is for
future growth.
-rw-r--r-- | include/git2/attr.h | 79 | ||||
-rw-r--r-- | src/attr.c | 75 | ||||
-rw-r--r-- | src/attr_file.h | 2 | ||||
-rw-r--r-- | src/filter.c | 8 | ||||
-rw-r--r-- | tests/attr/repo.c | 2 |
5 files changed, 146 insertions, 20 deletions
diff --git a/include/git2/attr.h b/include/git2/attr.h index a3ab5a7a2..306893c67 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -135,6 +135,19 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr); #define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3) /** +* An options structure for querying attributes. +*/ +typedef struct { + unsigned int version; + + /** A combination of GIT_ATTR_CHECK flags */ + unsigned int flags; +} 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. * * @param value_out Output of the value of the attribute. Use the GIT_ATTR_... @@ -157,6 +170,28 @@ GIT_EXTERN(int) git_attr_get( 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. * * Use this if you have a known list of attributes that you want to @@ -194,6 +229,30 @@ GIT_EXTERN(int) git_attr_get_many( 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. * * This callback will be invoked only once per attribute name, even if there @@ -232,6 +291,26 @@ GIT_EXTERN(int) git_attr_foreach( 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. * * Call this if you have reason to believe that the attributes files on diff --git a/src/attr.c b/src/attr.c index 86be08474..a2d78e68b 100644 --- a/src/attr.c +++ b/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, &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, flags, pathname, num_attr, names); + values, repo, NULL, opts, pathname, num_attr, names); } int git_attr_foreach( @@ -201,6 +233,20 @@ int git_attr_foreach( 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; git_vector files = GIT_VECTOR_INIT; @@ -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; @@ -331,7 +378,7 @@ 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 system = GIT_BUF_INIT, info = GIT_BUF_INIT; git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE }; @@ -379,7 +426,7 @@ static int attr_setup( (error = preload_attr_source(repo, attr_session, &index_source)) < 0) goto out; - if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 && + if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0) && (error = preload_attr_source(repo, attr_session, &head_source)) < 0) goto out; @@ -545,7 +592,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) { @@ -554,7 +601,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 */ @@ -584,7 +631,7 @@ static int collect_attr_files( info.repo = repo; info.attr_session = attr_session; - info.flags = flags; + info.flags = opts ? opts->flags : 0; info.workdir = workdir; if (git_repository_index__weakptr(&info.index, repo) < 0) git_error_clear(); /* no error even if there is no index */ @@ -604,7 +651,7 @@ static int collect_attr_files( 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) diff --git a/src/attr_file.h b/src/attr_file.h index 691dbda9e..5c8a41291 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -136,7 +136,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); diff --git a/src/filter.c b/src/filter.c index 6c09a6ad5..d139a5911 100644 --- a/src/filter.c +++ b/src/filter.c @@ -430,20 +430,20 @@ static int filter_list_check_attributes( 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; + attr_opts.flags |= GIT_ATTR_CHECK_NO_SYSTEM; if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0) - flags |= GIT_ATTR_CHECK_INCLUDE_HEAD; + attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD; error = git_attr_get_many_with_session( - strs, repo, attr_session, flags, src->path, fdef->nattrs, fdef->attrs); + strs, repo, 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) { diff --git a/tests/attr/repo.c b/tests/attr/repo.c index 8224e5c1e..eabc033eb 100644 --- a/tests/attr/repo.c +++ b/tests/attr/repo.c @@ -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"); |