Commit d7e8b9348cab441184b82c57cb2c847c11ffa5d8

Edward Thomson 2021-06-16T09:08:38

filter: add git_filter_options Allow filter users to provide an options structure instead of simply flags. This allows for future growth for filter options.

diff --git a/include/git2/filter.h b/include/git2/filter.h
index a0185ee..5458151 100644
--- a/include/git2/filter.h
+++ b/include/git2/filter.h
@@ -52,6 +52,19 @@ typedef enum {
 } git_filter_flag_t;
 
 /**
+ * Filtering options
+ */
+typedef struct {
+	unsigned int version;
+
+	/** See `git_filter_flag_t` above */
+	uint32_t flags;
+} 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
  *
  * This represents a filter that can be used to transform or even replace
@@ -104,6 +117,29 @@ GIT_EXTERN(int) git_filter_list_load(
 	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
  * is the name of the filter specified by the filter attribute.
diff --git a/src/filter.c b/src/filter.c
index 9606ac4..3309ab7 100644
--- a/src/filter.c
+++ b/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;
@@ -436,10 +437,10 @@ static int filter_list_check_attributes(
 
 	GIT_ERROR_CHECK_ALLOC(strs);
 
-	if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
+	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)
+	if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
 		attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
 
 	error = git_attr_get_many_with_session(
@@ -488,7 +489,7 @@ 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);
 }
 
@@ -515,7 +516,8 @@ int git_filter_list__load(
 	src.repo = repo;
 	src.path = path;
 	src.mode = mode;
-	src.flags = filter_session->flags;
+
+	memcpy(&src.options, &filter_session->options, sizeof(git_filter_options));
 
 	if (blob)
 		git_oid_cpy(&src.oid, git_blob_id(blob));
@@ -581,6 +583,23 @@ int git_filter_list__load(
 	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,
@@ -591,7 +610,7 @@ int git_filter_list_load(
 {
 	git_filter_session filter_session = GIT_FILTER_SESSION_INIT;
 
-	filter_session.flags = flags;
+	filter_session.options.flags = flags;
 
 	return git_filter_list__load(
 		filters, repo, blob, path, mode, &filter_session);
diff --git a/src/filter.h b/src/filter.h
index 31a776e..55ed50e 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -16,12 +16,12 @@
 #define GIT_FILTER_BYTES_TO_CHECK_NUL 8000
 
 typedef struct {
-	uint32_t flags;
+	git_filter_options options;
 	git_attr_session *attr_session;
 	git_buf *temp_buf;
 } git_filter_session;
 
-#define GIT_FILTER_SESSION_INIT {0}
+#define GIT_FILTER_SESSION_INIT {GIT_FILTER_OPTIONS_INIT, 0}
 
 extern int git_filter_global_init(void);