5 #include "argv-array.h"
6 #include "list-objects.h"
7 #include "list-objects-filter.h"
8 #include "list-objects-filter-options.h"
12 static int parse_combine_filter(
13 struct list_objects_filter_options
*filter_options
,
15 struct strbuf
*errbuf
);
18 * Parse value of the argument to the "filter" keyword.
19 * On the command line this looks like:
21 * and in the pack protocol as:
24 * The filter keyword will be used by many commands.
25 * See Documentation/rev-list-options.txt for allowed values for <arg>.
27 * Capture the given arg as the "filter_spec". This can be forwarded to
28 * subordinate commands when necessary (although it's better to pass it through
29 * expand_list_objects_filter_spec() first). We also "intern" the arg for the
30 * convenience of the current command.
32 static int gently_parse_list_objects_filter(
33 struct list_objects_filter_options
*filter_options
,
35 struct strbuf
*errbuf
)
39 if (filter_options
->choice
)
40 BUG("filter_options already populated");
42 if (!strcmp(arg
, "blob:none")) {
43 filter_options
->choice
= LOFC_BLOB_NONE
;
46 } else if (skip_prefix(arg
, "blob:limit=", &v0
)) {
47 if (git_parse_ulong(v0
, &filter_options
->blob_limit_value
)) {
48 filter_options
->choice
= LOFC_BLOB_LIMIT
;
52 } else if (skip_prefix(arg
, "tree:", &v0
)) {
53 if (!git_parse_ulong(v0
, &filter_options
->tree_exclude_depth
)) {
54 strbuf_addstr(errbuf
, _("expected 'tree:<depth>'"));
57 filter_options
->choice
= LOFC_TREE_DEPTH
;
60 } else if (skip_prefix(arg
, "sparse:oid=", &v0
)) {
61 struct object_context oc
;
62 struct object_id sparse_oid
;
65 * Try to parse <oid-expression> into an OID for the current
66 * command, but DO NOT complain if we don't have the blob or
69 if (!get_oid_with_context(the_repository
, v0
, GET_OID_BLOB
,
71 filter_options
->sparse_oid_value
= oiddup(&sparse_oid
);
72 filter_options
->choice
= LOFC_SPARSE_OID
;
75 } else if (skip_prefix(arg
, "sparse:path=", &v0
)) {
79 _("sparse:path filters support has been dropped"));
83 } else if (skip_prefix(arg
, "combine:", &v0
)) {
84 return parse_combine_filter(filter_options
, v0
, errbuf
);
88 * Please update _git_fetch() in git-completion.bash when you
92 strbuf_addf(errbuf
, _("invalid filter-spec '%s'"), arg
);
94 memset(filter_options
, 0, sizeof(*filter_options
));
98 static const char *RESERVED_NON_WS
= "~`!@#$^&*()[]{}\\;'\",<>?";
100 static int has_reserved_character(
101 struct strbuf
*sub_spec
, struct strbuf
*errbuf
)
103 const char *c
= sub_spec
->buf
;
105 if (*c
<= ' ' || strchr(RESERVED_NON_WS
, *c
)) {
108 _("must escape char in sub-filter-spec: '%c'"),
118 static int parse_combine_subfilter(
119 struct list_objects_filter_options
*filter_options
,
120 struct strbuf
*subspec
,
121 struct strbuf
*errbuf
)
123 size_t new_index
= filter_options
->sub_nr
;
127 ALLOC_GROW_BY(filter_options
->sub
, filter_options
->sub_nr
, 1,
128 filter_options
->sub_alloc
);
130 decoded
= url_percent_decode(subspec
->buf
);
132 result
= has_reserved_character(subspec
, errbuf
) ||
133 gently_parse_list_objects_filter(
134 &filter_options
->sub
[new_index
], decoded
, errbuf
);
140 static int parse_combine_filter(
141 struct list_objects_filter_options
*filter_options
,
143 struct strbuf
*errbuf
)
145 struct strbuf
**subspecs
= strbuf_split_str(arg
, '+', 0);
150 strbuf_addstr(errbuf
, _("expected something after combine:"));
155 for (sub
= 0; subspecs
[sub
] && !result
; sub
++) {
156 if (subspecs
[sub
+ 1]) {
158 * This is not the last subspec. Remove trailing "+" so
161 size_t last
= subspecs
[sub
]->len
- 1;
162 assert(subspecs
[sub
]->buf
[last
] == '+');
163 strbuf_remove(subspecs
[sub
], last
, 1);
165 result
= parse_combine_subfilter(
166 filter_options
, subspecs
[sub
], errbuf
);
169 filter_options
->choice
= LOFC_COMBINE
;
172 strbuf_list_free(subspecs
);
174 list_objects_filter_release(filter_options
);
175 memset(filter_options
, 0, sizeof(*filter_options
));
180 static int allow_unencoded(char ch
)
182 if (ch
<= ' ' || ch
== '%' || ch
== '+')
184 return !strchr(RESERVED_NON_WS
, ch
);
187 static void filter_spec_append_urlencode(
188 struct list_objects_filter_options
*filter
, const char *raw
)
190 struct strbuf buf
= STRBUF_INIT
;
191 strbuf_addstr_urlencode(&buf
, raw
, allow_unencoded
);
192 trace_printf("Add to combine filter-spec: %s\n", buf
.buf
);
193 string_list_append(&filter
->filter_spec
, strbuf_detach(&buf
, NULL
));
197 * Changes filter_options into an equivalent LOFC_COMBINE filter options
198 * instance. Does not do anything if filter_options is already LOFC_COMBINE.
200 static void transform_to_combine_type(
201 struct list_objects_filter_options
*filter_options
)
203 assert(filter_options
->choice
);
204 if (filter_options
->choice
== LOFC_COMBINE
)
207 const int initial_sub_alloc
= 2;
208 struct list_objects_filter_options
*sub_array
=
209 xcalloc(initial_sub_alloc
, sizeof(*sub_array
));
210 sub_array
[0] = *filter_options
;
211 memset(filter_options
, 0, sizeof(*filter_options
));
212 filter_options
->sub
= sub_array
;
213 filter_options
->sub_alloc
= initial_sub_alloc
;
215 filter_options
->sub_nr
= 1;
216 filter_options
->choice
= LOFC_COMBINE
;
217 string_list_append(&filter_options
->filter_spec
, xstrdup("combine:"));
218 filter_spec_append_urlencode(
220 list_objects_filter_spec(&filter_options
->sub
[0]));
222 * We don't need the filter_spec strings for subfilter specs, only the
225 string_list_clear(&filter_options
->sub
[0].filter_spec
, /*free_util=*/0);
228 void list_objects_filter_die_if_populated(
229 struct list_objects_filter_options
*filter_options
)
231 if (filter_options
->choice
)
232 die(_("multiple filter-specs cannot be combined"));
235 void parse_list_objects_filter(
236 struct list_objects_filter_options
*filter_options
,
239 struct strbuf errbuf
= STRBUF_INIT
;
242 if (!filter_options
->choice
) {
243 string_list_append(&filter_options
->filter_spec
, xstrdup(arg
));
245 parse_error
= gently_parse_list_objects_filter(
246 filter_options
, arg
, &errbuf
);
249 * Make filter_options an LOFC_COMBINE spec so we can trivially
250 * add subspecs to it.
252 transform_to_combine_type(filter_options
);
254 string_list_append(&filter_options
->filter_spec
, xstrdup("+"));
255 filter_spec_append_urlencode(filter_options
, arg
);
256 ALLOC_GROW_BY(filter_options
->sub
, filter_options
->sub_nr
, 1,
257 filter_options
->sub_alloc
);
259 parse_error
= gently_parse_list_objects_filter(
260 &filter_options
->sub
[filter_options
->sub_nr
- 1], arg
,
264 die("%s", errbuf
.buf
);
267 int opt_parse_list_objects_filter(const struct option
*opt
,
268 const char *arg
, int unset
)
270 struct list_objects_filter_options
*filter_options
= opt
->value
;
273 list_objects_filter_set_no_filter(filter_options
);
275 parse_list_objects_filter(filter_options
, arg
);
279 const char *list_objects_filter_spec(struct list_objects_filter_options
*filter
)
281 if (!filter
->filter_spec
.nr
)
282 BUG("no filter_spec available for this filter");
283 if (filter
->filter_spec
.nr
!= 1) {
284 struct strbuf concatted
= STRBUF_INIT
;
285 strbuf_add_separated_string_list(
286 &concatted
, "", &filter
->filter_spec
);
287 string_list_clear(&filter
->filter_spec
, /*free_util=*/0);
289 &filter
->filter_spec
, strbuf_detach(&concatted
, NULL
));
292 return filter
->filter_spec
.items
[0].string
;
295 const char *expand_list_objects_filter_spec(
296 struct list_objects_filter_options
*filter
)
298 if (filter
->choice
== LOFC_BLOB_LIMIT
) {
299 struct strbuf expanded_spec
= STRBUF_INIT
;
300 strbuf_addf(&expanded_spec
, "blob:limit=%lu",
301 filter
->blob_limit_value
);
302 string_list_clear(&filter
->filter_spec
, /*free_util=*/0);
304 &filter
->filter_spec
,
305 strbuf_detach(&expanded_spec
, NULL
));
308 return list_objects_filter_spec(filter
);
311 void list_objects_filter_release(
312 struct list_objects_filter_options
*filter_options
)
318 string_list_clear(&filter_options
->filter_spec
, /*free_util=*/0);
319 free(filter_options
->sparse_oid_value
);
320 for (sub
= 0; sub
< filter_options
->sub_nr
; sub
++)
321 list_objects_filter_release(&filter_options
->sub
[sub
]);
322 free(filter_options
->sub
);
323 memset(filter_options
, 0, sizeof(*filter_options
));
326 void partial_clone_register(
328 struct list_objects_filter_options
*filter_options
)
331 * Record the name of the partial clone remote in the
332 * config and in the global variable -- the latter is
333 * used throughout to indicate that partial clone is
334 * enabled and to expect missing objects.
336 if (repository_format_partial_clone
&&
337 *repository_format_partial_clone
&&
338 strcmp(remote
, repository_format_partial_clone
))
339 die(_("cannot change partial clone promisor remote"));
341 git_config_set("core.repositoryformatversion", "1");
342 git_config_set("extensions.partialclone", remote
);
344 repository_format_partial_clone
= xstrdup(remote
);
347 * Record the initial filter-spec in the config as
348 * the default for subsequent fetches from this remote.
350 core_partial_clone_filter_default
=
351 xstrdup(expand_list_objects_filter_spec(filter_options
));
352 git_config_set("core.partialclonefilter",
353 core_partial_clone_filter_default
);
356 void partial_clone_get_default_filter_spec(
357 struct list_objects_filter_options
*filter_options
)
359 struct strbuf errbuf
= STRBUF_INIT
;
362 * Parse default value, but silently ignore it if it is invalid.
364 if (!core_partial_clone_filter_default
)
367 string_list_append(&filter_options
->filter_spec
,
368 core_partial_clone_filter_default
);
369 gently_parse_list_objects_filter(filter_options
,
370 core_partial_clone_filter_default
,
372 strbuf_release(&errbuf
);