#include "list-objects.h"
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
+#include "promisor-remote.h"
+#include "trace.h"
#include "url.h"
static int parse_combine_filter(
{
const char *v0;
+ if (!arg)
+ return 0;
+
if (filter_options->choice)
BUG("filter_options already populated");
struct strbuf *subspec,
struct strbuf *errbuf)
{
- size_t new_index = filter_options->sub_nr++;
+ size_t new_index = filter_options->sub_nr;
char *decoded;
int result;
- ALLOC_GROW(filter_options->sub, filter_options->sub_nr,
- filter_options->sub_alloc);
- memset(&filter_options->sub[new_index], 0,
- sizeof(*filter_options->sub));
+ ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
+ filter_options->sub_alloc);
decoded = url_percent_decode(subspec->buf);
return result;
}
-int parse_list_objects_filter(struct list_objects_filter_options *filter_options,
- const char *arg)
+static int allow_unencoded(char ch)
+{
+ if (ch <= ' ' || ch == '%' || ch == '+')
+ return 0;
+ return !strchr(RESERVED_NON_WS, ch);
+}
+
+static void filter_spec_append_urlencode(
+ struct list_objects_filter_options *filter, const char *raw)
{
struct strbuf buf = STRBUF_INIT;
+ strbuf_addstr_urlencode(&buf, raw, allow_unencoded);
+ trace_printf("Add to combine filter-spec: %s\n", buf.buf);
+ string_list_append(&filter->filter_spec, strbuf_detach(&buf, NULL));
+}
+
+/*
+ * Changes filter_options into an equivalent LOFC_COMBINE filter options
+ * instance. Does not do anything if filter_options is already LOFC_COMBINE.
+ */
+static void transform_to_combine_type(
+ struct list_objects_filter_options *filter_options)
+{
+ assert(filter_options->choice);
+ if (filter_options->choice == LOFC_COMBINE)
+ return;
+ {
+ const int initial_sub_alloc = 2;
+ struct list_objects_filter_options *sub_array =
+ xcalloc(initial_sub_alloc, sizeof(*sub_array));
+ sub_array[0] = *filter_options;
+ memset(filter_options, 0, sizeof(*filter_options));
+ filter_options->sub = sub_array;
+ filter_options->sub_alloc = initial_sub_alloc;
+ }
+ filter_options->sub_nr = 1;
+ filter_options->choice = LOFC_COMBINE;
+ string_list_append(&filter_options->filter_spec, xstrdup("combine:"));
+ filter_spec_append_urlencode(
+ filter_options,
+ list_objects_filter_spec(&filter_options->sub[0]));
+ /*
+ * We don't need the filter_spec strings for subfilter specs, only the
+ * top level.
+ */
+ string_list_clear(&filter_options->sub[0].filter_spec, /*free_util=*/0);
+}
+
+void list_objects_filter_die_if_populated(
+ struct list_objects_filter_options *filter_options)
+{
if (filter_options->choice)
die(_("multiple filter-specs cannot be combined"));
- string_list_append(&filter_options->filter_spec, xstrdup(arg));
- if (gently_parse_list_objects_filter(filter_options, arg, &buf))
- die("%s", buf.buf);
- return 0;
+}
+
+void parse_list_objects_filter(
+ struct list_objects_filter_options *filter_options,
+ const char *arg)
+{
+ struct strbuf errbuf = STRBUF_INIT;
+ int parse_error;
+
+ if (!filter_options->choice) {
+ string_list_append(&filter_options->filter_spec, xstrdup(arg));
+
+ parse_error = gently_parse_list_objects_filter(
+ filter_options, arg, &errbuf);
+ } else {
+ /*
+ * Make filter_options an LOFC_COMBINE spec so we can trivially
+ * add subspecs to it.
+ */
+ transform_to_combine_type(filter_options);
+
+ string_list_append(&filter_options->filter_spec, xstrdup("+"));
+ filter_spec_append_urlencode(filter_options, arg);
+ ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
+ filter_options->sub_alloc);
+
+ parse_error = gently_parse_list_objects_filter(
+ &filter_options->sub[filter_options->sub_nr - 1], arg,
+ &errbuf);
+ }
+ if (parse_error)
+ die("%s", errbuf.buf);
}
int opt_parse_list_objects_filter(const struct option *opt,
{
struct list_objects_filter_options *filter_options = opt->value;
- if (unset || !arg) {
+ if (unset || !arg)
list_objects_filter_set_no_filter(filter_options);
- return 0;
- }
-
- return parse_list_objects_filter(filter_options, arg);
+ else
+ parse_list_objects_filter(filter_options, arg);
+ return 0;
}
const char *list_objects_filter_spec(struct list_objects_filter_options *filter)
const char *remote,
struct list_objects_filter_options *filter_options)
{
- /*
- * Record the name of the partial clone remote in the
- * config and in the global variable -- the latter is
- * used throughout to indicate that partial clone is
- * enabled and to expect missing objects.
- */
- if (repository_format_partial_clone &&
- *repository_format_partial_clone &&
- strcmp(remote, repository_format_partial_clone))
- die(_("cannot change partial clone promisor remote"));
+ char *cfg_name;
+ char *filter_name;
- git_config_set("core.repositoryformatversion", "1");
- git_config_set("extensions.partialclone", remote);
+ /* Check if it is already registered */
+ if (!promisor_remote_find(remote)) {
+ git_config_set("core.repositoryformatversion", "1");
- repository_format_partial_clone = xstrdup(remote);
+ /* Add promisor config for the remote */
+ cfg_name = xstrfmt("remote.%s.promisor", remote);
+ git_config_set(cfg_name, "true");
+ free(cfg_name);
+ }
/*
* Record the initial filter-spec in the config as
* the default for subsequent fetches from this remote.
*/
- core_partial_clone_filter_default =
- xstrdup(expand_list_objects_filter_spec(filter_options));
- git_config_set("core.partialclonefilter",
- core_partial_clone_filter_default);
+ filter_name = xstrfmt("remote.%s.partialclonefilter", remote);
+ /* NEEDSWORK: 'expand' result leaking??? */
+ git_config_set(filter_name,
+ expand_list_objects_filter_spec(filter_options));
+ free(filter_name);
+
+ /* Make sure the config info are reset */
+ promisor_remote_reinit();
}
void partial_clone_get_default_filter_spec(
- struct list_objects_filter_options *filter_options)
+ struct list_objects_filter_options *filter_options,
+ const char *remote)
{
+ struct promisor_remote *promisor = promisor_remote_find(remote);
struct strbuf errbuf = STRBUF_INIT;
/*
* Parse default value, but silently ignore it if it is invalid.
*/
- if (!core_partial_clone_filter_default)
+ if (!promisor)
return;
string_list_append(&filter_options->filter_spec,
- core_partial_clone_filter_default);
+ promisor->partial_clone_filter);
gently_parse_list_objects_filter(filter_options,
- core_partial_clone_filter_default,
+ promisor->partial_clone_filter,
&errbuf);
strbuf_release(&errbuf);
}