public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
From: Christian Couder <christian.couder@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
	"Patrick Steinhardt" <ps@pks.im>, "Taylor Blau" <me@ttaylorr.com>,
	"Karthik Nayak" <karthik.188@gmail.com>,
	"Elijah Newren" <newren@gmail.com>,
	"Jean-Noël Avila" <avila.jn@gmail.com>,
	"Christian Couder" <christian.couder@gmail.com>,
	"Christian Couder" <chriscool@tuxfamily.org>
Subject: [PATCH v2 6/8] list-objects-filter-options: support 'auto' mode for --filter
Date: Wed,  4 Feb 2026 12:08:11 +0100	[thread overview]
Message-ID: <20260204110818.2919273-7-christian.couder@gmail.com> (raw)
In-Reply-To: <20260204110818.2919273-1-christian.couder@gmail.com>

In a following commit, we are going to allow passing "auto" as a
<filterspec> to the `--filter=<filterspec>` option, but only for some
commands. Other commands that support the `--filter=<filterspec>`
option should still die() when 'auto' is passed.

Let's set up the "list-objects-filter-options.{c,h}" infrastructure to
support that:

- Add a new `unsigned int allow_auto_filter : 1;` flag to
  `struct list_objects_filter_options` which specifies if "auto" is
  accepted or not by the current command.
- Change gently_parse_list_objects_filter() to parse "auto" if it's
  accepted.
- Make sure we die() if "auto" is combined with another filter.
- Update list_objects_filter_release() to preserve the
  allow_auto_filter flag, as this function is often called (via
  opt_parse_list_objects_filter) to reset the struct before parsing a
  new value.

Let's also update `list-objects-filter.c` to recognize the new
`LOFC_AUTO` choice. Since "auto" must be resolved to a concrete filter
before filtering actually begins, initializing a filter with
`LOFC_AUTO` is invalid and will trigger a BUG().

Note that ideally combining "auto" with "auto" could be allowed, but in
practice, it's probably not worth the added code complexity. And if we
really want it, nothing prevents us to allow it in future work.

If we ever want to give a meaning to combining "auto" with a different
filter too, nothing prevents us to do that in future work either.

Also note that the new `allow_auto_filter` flag depends on the command,
not user choices, so it should be reset to the command default when
`struct list_objects_filter_options` instances are reset.

While at it, let's add a new "u-list-objects-filter-options.c" file for
`struct list_objects_filter_options` related unit tests. For now it
only tests gently_parse_list_objects_filter() though.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 Makefile                                     |  1 +
 list-objects-filter-options.c                | 37 ++++++++++++--
 list-objects-filter-options.h                |  6 +++
 list-objects-filter.c                        |  8 +++
 t/meson.build                                |  1 +
 t/unit-tests/u-list-objects-filter-options.c | 53 ++++++++++++++++++++
 6 files changed, 103 insertions(+), 3 deletions(-)
 create mode 100644 t/unit-tests/u-list-objects-filter-options.c

diff --git a/Makefile b/Makefile
index 8aa489f3b6..04256f747c 100644
--- a/Makefile
+++ b/Makefile
@@ -1516,6 +1516,7 @@ CLAR_TEST_SUITES += u-dir
 CLAR_TEST_SUITES += u-example-decorate
 CLAR_TEST_SUITES += u-hash
 CLAR_TEST_SUITES += u-hashmap
+CLAR_TEST_SUITES += u-list-objects-filter-options
 CLAR_TEST_SUITES += u-mem-pool
 CLAR_TEST_SUITES += u-oid-array
 CLAR_TEST_SUITES += u-oidmap
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 7420bf81fe..ad92cbaa37 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -20,6 +20,8 @@ const char *list_object_filter_config_name(enum list_objects_filter_choice c)
 	case LOFC_DISABLED:
 		/* we have no name for "no filter at all" */
 		break;
+	case LOFC_AUTO:
+		return "auto";
 	case LOFC_BLOB_NONE:
 		return "blob:none";
 	case LOFC_BLOB_LIMIT:
@@ -52,7 +54,16 @@ int gently_parse_list_objects_filter(
 	if (filter_options->choice)
 		BUG("filter_options already populated");
 
-	if (!strcmp(arg, "blob:none")) {
+	if (!strcmp(arg, "auto")) {
+		if (!filter_options->allow_auto_filter) {
+			strbuf_addstr(errbuf,
+				      _("'auto' filter not supported by this command"));
+			return 1;
+		}
+		filter_options->choice = LOFC_AUTO;
+		return 0;
+
+	} else if (!strcmp(arg, "blob:none")) {
 		filter_options->choice = LOFC_BLOB_NONE;
 		return 0;
 
@@ -146,10 +157,22 @@ static int parse_combine_subfilter(
 
 	decoded = url_percent_decode(subspec->buf);
 
-	result = has_reserved_character(subspec, errbuf) ||
-		gently_parse_list_objects_filter(
+	result = has_reserved_character(subspec, errbuf);
+	if (result)
+		goto cleanup;
+
+	result = gently_parse_list_objects_filter(
 			&filter_options->sub[new_index], decoded, errbuf);
+	if (result)
+		goto cleanup;
+
+	result = (filter_options->sub[new_index].choice == LOFC_AUTO);
+	if (result) {
+		strbuf_addstr(errbuf, _("an 'auto' filter cannot be combined"));
+		goto cleanup;
+	}
 
+cleanup:
 	free(decoded);
 	return result;
 }
@@ -263,6 +286,9 @@ void parse_list_objects_filter(
 	} else {
 		struct list_objects_filter_options *sub;
 
+		if (filter_options->choice == LOFC_AUTO)
+			die(_("an 'auto' filter is incompatible with any other filter"));
+
 		/*
 		 * Make filter_options an LOFC_COMBINE spec so we can trivially
 		 * add subspecs to it.
@@ -277,6 +303,9 @@ void parse_list_objects_filter(
 		if (gently_parse_list_objects_filter(sub, arg, &errbuf))
 			die("%s", errbuf.buf);
 
+		if (sub->choice == LOFC_AUTO)
+			die(_("an 'auto' filter is incompatible with any other filter"));
+
 		strbuf_addch(&filter_options->filter_spec, '+');
 		filter_spec_append_urlencode(filter_options, arg);
 	}
@@ -317,6 +346,7 @@ void list_objects_filter_release(
 	struct list_objects_filter_options *filter_options)
 {
 	size_t sub;
+	unsigned int allow_auto_filter = filter_options->allow_auto_filter;
 
 	if (!filter_options)
 		return;
@@ -326,6 +356,7 @@ void list_objects_filter_release(
 		list_objects_filter_release(&filter_options->sub[sub]);
 	free(filter_options->sub);
 	list_objects_filter_init(filter_options);
+	filter_options->allow_auto_filter = allow_auto_filter;
 }
 
 void partial_clone_register(
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 7b2108b986..77d7bbc846 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -18,6 +18,7 @@ enum list_objects_filter_choice {
 	LOFC_SPARSE_OID,
 	LOFC_OBJECT_TYPE,
 	LOFC_COMBINE,
+	LOFC_AUTO,
 	LOFC__COUNT /* must be last */
 };
 
@@ -50,6 +51,11 @@ struct list_objects_filter_options {
 	 */
 	unsigned int no_filter : 1;
 
+	/*
+	 * Is LOFC_AUTO a valid option?
+	 */
+	unsigned int allow_auto_filter : 1;
+
 	/*
 	 * BEGIN choice-specific parsed values from within the filter-spec. Only
 	 * some values will be defined for any given choice.
diff --git a/list-objects-filter.c b/list-objects-filter.c
index acd65ebb73..78316e7f90 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -745,6 +745,13 @@ static void filter_combine__init(
 	filter->finalize_omits_fn = filter_combine__finalize_omits;
 }
 
+static void filter_auto__init(
+	struct list_objects_filter_options *filter_options UNUSED,
+	struct filter *filter UNUSED)
+{
+	BUG("LOFC_AUTO should have been resolved before initializing the filter");
+}
+
 typedef void (*filter_init_fn)(
 	struct list_objects_filter_options *filter_options,
 	struct filter *filter);
@@ -760,6 +767,7 @@ static filter_init_fn s_filters[] = {
 	filter_sparse_oid__init,
 	filter_object_type__init,
 	filter_combine__init,
+	filter_auto__init,
 };
 
 struct filter *list_objects_filter__init(
diff --git a/t/meson.build b/t/meson.build
index 459c52a489..0bd66cc6ce 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -4,6 +4,7 @@ clar_test_suites = [
   'unit-tests/u-example-decorate.c',
   'unit-tests/u-hash.c',
   'unit-tests/u-hashmap.c',
+  'unit-tests/u-list-objects-filter-options.c',
   'unit-tests/u-mem-pool.c',
   'unit-tests/u-oid-array.c',
   'unit-tests/u-oidmap.c',
diff --git a/t/unit-tests/u-list-objects-filter-options.c b/t/unit-tests/u-list-objects-filter-options.c
new file mode 100644
index 0000000000..f7d73701b5
--- /dev/null
+++ b/t/unit-tests/u-list-objects-filter-options.c
@@ -0,0 +1,53 @@
+#include "unit-test.h"
+#include "list-objects-filter-options.h"
+#include "strbuf.h"
+
+/* Helper to test gently_parse_list_objects_filter() */
+static void check_gentle_parse(const char *filter_spec,
+			       int expect_success,
+			       int allow_auto,
+			       enum list_objects_filter_choice expected_choice)
+{
+	struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
+	struct strbuf errbuf = STRBUF_INIT;
+	int ret;
+
+	filter_options.allow_auto_filter = allow_auto;
+
+	ret = gently_parse_list_objects_filter(&filter_options, filter_spec, &errbuf);
+
+	if (expect_success) {
+		cl_assert_equal_i(ret, 0);
+		cl_assert_equal_i(expected_choice, filter_options.choice);
+		cl_assert_equal_i(errbuf.len, 0);
+	} else {
+		cl_assert(ret != 0);
+		cl_assert(errbuf.len > 0);
+	}
+
+	strbuf_release(&errbuf);
+	list_objects_filter_release(&filter_options);
+}
+
+void test_list_objects_filter_options__regular_filters(void)
+{
+	check_gentle_parse("blob:none", 1, 0, LOFC_BLOB_NONE);
+	check_gentle_parse("blob:none", 1, 1, LOFC_BLOB_NONE);
+	check_gentle_parse("blob:limit=5k", 1, 0, LOFC_BLOB_LIMIT);
+	check_gentle_parse("blob:limit=5k", 1, 1, LOFC_BLOB_LIMIT);
+	check_gentle_parse("combine:blob:none+tree:0", 1, 0, LOFC_COMBINE);
+	check_gentle_parse("combine:blob:none+tree:0", 1, 1, LOFC_COMBINE);
+}
+
+void test_list_objects_filter_options__auto_allowed(void)
+{
+	check_gentle_parse("auto", 1, 1, LOFC_AUTO);
+	check_gentle_parse("auto", 0, 0, 0);
+}
+
+void test_list_objects_filter_options__combine_auto_fails(void)
+{
+	check_gentle_parse("combine:auto+blob:none", 0, 1, 0);
+	check_gentle_parse("combine:blob:none+auto", 0, 1, 0);
+	check_gentle_parse("combine:auto+auto", 0, 1, 0);
+}
-- 
2.53.0.rc2.10.g12663a1c75.dirty


  parent reply	other threads:[~2026-02-04 11:08 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-23 11:11 [PATCH 0/9] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2025-12-23 11:11 ` [PATCH 1/9] promisor-remote: refactor initialising field lists Christian Couder
2025-12-23 11:11 ` [PATCH 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2026-02-04 10:20     ` Christian Couder
2025-12-23 11:11 ` [PATCH 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2025-12-23 11:11 ` [PATCH 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2025-12-23 11:11 ` [PATCH 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2025-12-26 13:33   ` Jean-Noël AVILA
2026-02-04 11:19     ` Christian Couder
2025-12-23 11:11 ` [PATCH 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2026-02-04 10:21     ` Christian Couder
2025-12-23 11:11 ` [PATCH 7/9] list-objects-filter-options: implement auto filter resolution Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2026-02-04 10:29     ` Christian Couder
2026-02-11 11:48       ` Patrick Steinhardt
2026-02-12 10:07         ` Christian Couder
2025-12-23 11:11 ` [PATCH 8/9] promisor-remote: keep advertised filter in memory Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2026-02-04 10:57     ` Christian Couder
2026-02-11 11:48       ` Patrick Steinhardt
2026-02-11 16:59         ` Junio C Hamano
2026-02-12 10:07           ` Christian Couder
2025-12-23 11:11 ` [PATCH 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-01-07 10:05   ` Patrick Steinhardt
2026-02-04 11:06     ` Christian Couder
2026-02-04 11:08 ` [PATCH v2 0/8] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2026-02-04 11:08   ` [PATCH v2 1/8] promisor-remote: refactor initialising field lists Christian Couder
2026-02-04 11:08   ` [PATCH v2 2/8] promisor-remote: allow a client to store fields Christian Couder
2026-02-04 11:08   ` [PATCH v2 3/8] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-04 11:08   ` [PATCH v2 4/8] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-04 11:08   ` [PATCH v2 5/8] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-11 11:48     ` Patrick Steinhardt
2026-02-12 10:06       ` Christian Couder
2026-02-04 11:08   ` Christian Couder [this message]
2026-02-04 11:08   ` [PATCH v2 7/8] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-04 11:08   ` [PATCH v2 8/8] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-02-11 11:48     ` Patrick Steinhardt
2026-02-12 10:07       ` Christian Couder
2026-02-12 10:08   ` [PATCH v3 0/9] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2026-02-12 10:08     ` [PATCH v3 1/9] promisor-remote: refactor initialising field lists Christian Couder
2026-02-12 10:08     ` [PATCH v3 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-02-12 10:08     ` [PATCH v3 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-12 10:08     ` [PATCH v3 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-12 10:08     ` [PATCH v3 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-12 10:08     ` [PATCH v3 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-02-14  2:35       ` Jeff King
2026-02-16 13:26         ` Christian Couder
2026-02-12 10:08     ` [PATCH v3 7/9] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-12 10:08     ` [PATCH v3 8/9] promisor-remote: change promisor_remote_reply()'s signature Christian Couder
2026-02-13 11:25       ` Patrick Steinhardt
2026-02-12 10:08     ` [PATCH v3 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-02-13 11:26       ` Patrick Steinhardt
2026-02-13 11:26     ` [PATCH v3 0/9] Implement `promisor.storeFields` and `--filter=auto` Patrick Steinhardt
2026-02-16 13:23     ` [PATCH v4 " Christian Couder
2026-02-16 13:23       ` [PATCH v4 1/9] promisor-remote: refactor initialising field lists Christian Couder
2026-02-16 13:23       ` [PATCH v4 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-02-16 13:23       ` [PATCH v4 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-16 13:23       ` [PATCH v4 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-16 13:23       ` [PATCH v4 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-16 13:23       ` [PATCH v4 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-02-16 13:23       ` [PATCH v4 7/9] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-16 13:23       ` [PATCH v4 8/9] promisor-remote: change promisor_remote_reply()'s signature Christian Couder
2026-02-16 13:23       ` [PATCH v4 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260204110818.2919273-7-christian.couder@gmail.com \
    --to=christian.couder@gmail.com \
    --cc=avila.jn@gmail.com \
    --cc=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=karthik.188@gmail.com \
    --cc=me@ttaylorr.com \
    --cc=newren@gmail.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox