From 257f2db5d3e6d734861890ed4f1d81607f1702fe Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Mon, 16 Feb 2026 14:23:13 +0100 Subject: [PATCH] promisor-remote: keep advertised filters in memory Currently, advertised filters are only kept in memory temporarily during parsing, or persisted to disk if `promisor.storeFields` contains 'partialCloneFilter'. In a following commit though, we will add a `--filter=auto` option. This option will enable the client to use the filters that the server is suggesting for the promisor remotes the client accepts. To use them even if `promisor.storeFields` is not configured, these filters should be stored somewhere for the current session. Let's add an `advertised_filter` field to `struct promisor_remote` for that purpose. To ensure that the filters are available in all cases, filter_promisor_remote() captures them into a temporary list and applies them to the `promisor_remote` structs after the potential configuration reload. Then the accepted remotes are marked as `accepted` in the repository state. This ensures that subsequent calls to look up accepted remotes (like in the filter construction below) actually find them. In a following commit, we will add a `--filter=auto` option that will enable a client to use the filters suggested by the server for the promisor remotes the client accepted. To enable the client to construct a filter spec based on these filters, let's also add a `promisor_remote_construct_filter(repo)` function. This function: - iterates over all accepted promisor remotes in the repository, - collects the filters advertised for them (using `advertised_filter` added in this commit, and - generates a single filter spec for them. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- promisor-remote.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ promisor-remote.h | 7 ++++++ 2 files changed, 65 insertions(+) diff --git a/promisor-remote.c b/promisor-remote.c index 59997dd4c7..f3bafb7731 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -193,6 +193,7 @@ void promisor_remote_clear(struct promisor_remote_config *config) while (config->promisors) { struct promisor_remote *r = config->promisors; free(r->partial_clone_filter); + free(r->advertised_filter); config->promisors = config->promisors->next; free(r); } @@ -837,6 +838,7 @@ static void filter_promisor_remote(struct repository *repo, struct store_info *store_info = NULL; struct string_list_item *item; bool reload_config = false; + struct string_list accepted_filters = STRING_LIST_INIT_DUP; if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) { if (!*accept_str || !strcasecmp("None", accept_str)) @@ -879,6 +881,13 @@ static void filter_promisor_remote(struct repository *repo, reload_config = true; strvec_push(accepted, advertised->name); + + /* Capture advertised filters for accepted remotes */ + if (advertised->filter) { + struct string_list_item *i; + i = string_list_append(&accepted_filters, advertised->name); + i->util = xstrdup(advertised->filter); + } } promisor_info_free(advertised); @@ -890,6 +899,25 @@ static void filter_promisor_remote(struct repository *repo, if (reload_config) repo_promisor_remote_reinit(repo); + + /* Apply accepted remote filters to the stable repo state */ + for_each_string_list_item(item, &accepted_filters) { + struct promisor_remote *r = repo_promisor_remote_find(repo, item->string); + if (r) { + free(r->advertised_filter); + r->advertised_filter = item->util; + item->util = NULL; + } + } + + string_list_clear(&accepted_filters, 1); + + /* Mark the remotes as accepted in the repository state */ + for (size_t i = 0; i < accepted->nr; i++) { + struct promisor_remote *r = repo_promisor_remote_find(repo, accepted->v[i]); + if (r) + r->accepted = 1; + } } char *promisor_remote_reply(const char *info) @@ -935,3 +963,33 @@ void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes string_list_clear(&accepted_remotes, 0); } + +char *promisor_remote_construct_filter(struct repository *repo) +{ + struct promisor_remote *r; + struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; + struct strbuf err = STRBUF_INIT; + char *result = NULL; + + promisor_remote_init(repo); + + for (r = repo->promisor_remote_config->promisors; r; r = r->next) { + if (r->accepted && r->advertised_filter) + if (gently_parse_list_objects_filter(&filter_options, + r->advertised_filter, + &err)) { + warning(_("promisor remote '%s' advertised invalid filter '%s': %s"), + r->name, r->advertised_filter, err.buf); + strbuf_reset(&err); + continue; + } + } + + if (filter_options.choice) + result = xstrdup(expand_list_objects_filter_spec(&filter_options)); + + list_objects_filter_release(&filter_options); + strbuf_release(&err); + + return result; +} diff --git a/promisor-remote.h b/promisor-remote.h index 263d331a55..d227299fd0 100644 --- a/promisor-remote.h +++ b/promisor-remote.h @@ -15,6 +15,7 @@ struct object_id; struct promisor_remote { struct promisor_remote *next; char *partial_clone_filter; + char *advertised_filter; unsigned int accepted : 1; const char name[FLEX_ARRAY]; }; @@ -67,4 +68,10 @@ void mark_promisor_remotes_as_accepted(struct repository *repo, const char *remo */ int repo_has_accepted_promisor_remote(struct repository *r); +/* + * Use the filters from the accepted remotes to create a combined + * filter (useful in `--filter=auto` mode). + */ +char *promisor_remote_construct_filter(struct repository *repo); + #endif /* PROMISOR_REMOTE_H */