filter->filter_spec.buf + orig_len);
}
+char *list_objects_filter_combine(const struct string_list *specs)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!specs->nr)
+ return NULL;
+
+ if (specs->nr == 1)
+ return xstrdup(specs->items[0].string);
+
+ strbuf_addstr(&buf, "combine:");
+
+ for (size_t i = 0; i < specs->nr; i++) {
+ const char *spec = specs->items[i].string;
+ if (i > 0)
+ strbuf_addch(&buf, '+');
+
+ strbuf_addstr_urlencode(&buf, spec, allow_unencoded);
+ }
+
+ return strbuf_detach(&buf, NULL);
+}
+
+void list_objects_filter_resolve_auto(struct list_objects_filter_options *filter_options,
+ char *new_filter, struct strbuf *errbuf)
+{
+ if (filter_options->choice != LOFC_AUTO)
+ return;
+
+ list_objects_filter_release(filter_options);
+
+ if (new_filter)
+ gently_parse_list_objects_filter(filter_options, new_filter, errbuf);
+}
+
/*
* Changes filter_options into an equivalent LOFC_COMBINE filter options
* instance. Does not do anything if filter_options is already LOFC_COMBINE.
#include "strbuf.h"
struct option;
+struct string_list;
/*
* The list of defined filters for list-objects.
struct list_objects_filter_options *dest,
const struct list_objects_filter_options *src);
+/*
+ * Combine the filter specs in 'specs' into a combined filter string
+ * like "combine:<spec1>+<spec2>", where <spec1>, <spec2>, etc are
+ * properly urlencoded. If 'specs' contains no element, NULL is
+ * returned. If 'specs' contains a single element, a copy of that
+ * element is returned.
+ */
+char *list_objects_filter_combine(const struct string_list *specs);
+
+/*
+ * Check if 'filter_options' are an 'auto' filter, and if that's the
+ * case populate it with the filter specified by 'new_filter'.
+ */
+void list_objects_filter_resolve_auto(
+ struct list_objects_filter_options *filter_options,
+ char *new_filter,
+ struct strbuf *errbuf);
+
#endif /* LIST_OBJECTS_FILTER_OPTIONS_H */
#include "unit-test.h"
#include "list-objects-filter-options.h"
#include "strbuf.h"
+#include "string-list.h"
/* Helper to test gently_parse_list_objects_filter() */
static void check_gentle_parse(const char *filter_spec,
check_gentle_parse("combine:blob:none+auto", 0, 1, 0);
check_gentle_parse("combine:auto+auto", 0, 1, 0);
}
+
+/* Helper to test list_objects_filter_combine() */
+static void check_combine(const char **specs, size_t nr, const char *expected)
+{
+ struct string_list spec_list = STRING_LIST_INIT_NODUP;
+ char *actual;
+
+ for (size_t i = 0; i < nr; i++)
+ string_list_append(&spec_list, specs[i]);
+
+ actual = list_objects_filter_combine(&spec_list);
+
+ cl_assert_equal_s(actual, expected);
+
+ free(actual);
+ string_list_clear(&spec_list, 0);
+}
+
+void test_list_objects_filter_options__combine_helper(void)
+{
+ const char *empty[] = { NULL };
+ const char *one[] = { "blob:none" };
+ const char *two[] = { "blob:none", "tree:0" };
+ const char *complex[] = { "blob:limit=1k", "object:type=tag" };
+ const char *needs_encoding[] = { "blob:none", "combine:tree:0+blob:limit=1k" };
+
+ check_combine(empty, 0, NULL);
+ check_combine(one, 1, "blob:none");
+ check_combine(two, 2, "combine:blob:none+tree:0");
+ check_combine(complex, 2, "combine:blob:limit=1k+object:type=tag");
+ check_combine(needs_encoding, 2, "combine:blob:none+combine:tree:0%2bblob:limit=1k");
+}