Skip to content

Commit 1a38f36

Browse files
committed
list-objects-filter-options: implement auto filter resolution
In a following commit, we will need to aggregate filters from multiple accepted promisor remotes into a single filter. For that purpose, let's add a `list_objects_filter_combine()` helper function that takes a list of filter specifications and combines them into a single string. If multiple filters are provided, it constructs a "combine:..." filter, ensuring that sub-filters are properly URL-encoded using the existing `allow_unencoded` logic. 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 simplify the filter processing related to this new feature, let's also add a small `list_objects_filter_resolve_auto()` function. Signed-off-by: Christian Couder <[email protected]>
1 parent 34a5243 commit 1a38f36

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

list-objects-filter-options.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,41 @@ static void filter_spec_append_urlencode(
230230
filter->filter_spec.buf + orig_len);
231231
}
232232

233+
char *list_objects_filter_combine(const struct string_list *specs)
234+
{
235+
struct strbuf buf = STRBUF_INIT;
236+
237+
if (!specs->nr)
238+
return NULL;
239+
240+
if (specs->nr == 1)
241+
return xstrdup(specs->items[0].string);
242+
243+
strbuf_addstr(&buf, "combine:");
244+
245+
for (size_t i = 0; i < specs->nr; i++) {
246+
const char *spec = specs->items[i].string;
247+
if (i > 0)
248+
strbuf_addch(&buf, '+');
249+
250+
strbuf_addstr_urlencode(&buf, spec, allow_unencoded);
251+
}
252+
253+
return strbuf_detach(&buf, NULL);
254+
}
255+
256+
void list_objects_filter_resolve_auto(struct list_objects_filter_options *filter_options,
257+
char *new_filter, struct strbuf *errbuf)
258+
{
259+
if (filter_options->choice != LOFC_AUTO)
260+
return;
261+
262+
list_objects_filter_release(filter_options);
263+
264+
if (new_filter)
265+
gently_parse_list_objects_filter(filter_options, new_filter, errbuf);
266+
}
267+
233268
/*
234269
* Changes filter_options into an equivalent LOFC_COMBINE filter options
235270
* instance. Does not do anything if filter_options is already LOFC_COMBINE.

list-objects-filter-options.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "strbuf.h"
77

88
struct option;
9+
struct string_list;
910

1011
/*
1112
* The list of defined filters for list-objects.
@@ -168,4 +169,22 @@ void list_objects_filter_copy(
168169
struct list_objects_filter_options *dest,
169170
const struct list_objects_filter_options *src);
170171

172+
/*
173+
* Combine the filter specs in 'specs' into a combined filter string
174+
* like "combine:<spec1>+<spec2>", where <spec1>, <spec2>, etc are
175+
* properly urlencoded. If 'specs' contains no element, NULL is
176+
* returned. If 'specs' contains a single element, a copy of that
177+
* element is returned.
178+
*/
179+
char *list_objects_filter_combine(const struct string_list *specs);
180+
181+
/*
182+
* Check if 'filter_options' are an 'auto' filter, and if that's the
183+
* case populate it with the filter specified by 'new_filter'.
184+
*/
185+
void list_objects_filter_resolve_auto(
186+
struct list_objects_filter_options *filter_options,
187+
char *new_filter,
188+
struct strbuf *errbuf);
189+
171190
#endif /* LIST_OBJECTS_FILTER_OPTIONS_H */

t/unit-tests/u-list-objects-filter-options.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "unit-test.h"
22
#include "list-objects-filter-options.h"
33
#include "strbuf.h"
4+
#include "string-list.h"
45

56
/* Helper to test gently_parse_list_objects_filter() */
67
static void check_gentle_parse(const char *filter_spec,
@@ -51,3 +52,35 @@ void test_list_objects_filter_options__combine_auto_fails(void)
5152
check_gentle_parse("combine:blob:none+auto", 0, 1, 0);
5253
check_gentle_parse("combine:auto+auto", 0, 1, 0);
5354
}
55+
56+
/* Helper to test list_objects_filter_combine() */
57+
static void check_combine(const char **specs, size_t nr, const char *expected)
58+
{
59+
struct string_list spec_list = STRING_LIST_INIT_NODUP;
60+
char *actual;
61+
62+
for (size_t i = 0; i < nr; i++)
63+
string_list_append(&spec_list, specs[i]);
64+
65+
actual = list_objects_filter_combine(&spec_list);
66+
67+
cl_assert_equal_s(actual, expected);
68+
69+
free(actual);
70+
string_list_clear(&spec_list, 0);
71+
}
72+
73+
void test_list_objects_filter_options__combine_helper(void)
74+
{
75+
const char *empty[] = { NULL };
76+
const char *one[] = { "blob:none" };
77+
const char *two[] = { "blob:none", "tree:0" };
78+
const char *complex[] = { "blob:limit=1k", "object:type=tag" };
79+
const char *needs_encoding[] = { "blob:none", "combine:tree:0+blob:limit=1k" };
80+
81+
check_combine(empty, 0, NULL);
82+
check_combine(one, 1, "blob:none");
83+
check_combine(two, 2, "combine:blob:none+tree:0");
84+
check_combine(complex, 2, "combine:blob:limit=1k+object:type=tag");
85+
check_combine(needs_encoding, 2, "combine:blob:none+combine:tree:0%2bblob:limit=1k");
86+
}

0 commit comments

Comments
 (0)