git

Форк
0
/
list-objects-filter-options.c 
418 строк · 10.8 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "config.h"
5
#include "gettext.h"
6
#include "list-objects-filter-options.h"
7
#include "promisor-remote.h"
8
#include "trace.h"
9
#include "url.h"
10
#include "parse-options.h"
11

12
static int parse_combine_filter(
13
	struct list_objects_filter_options *filter_options,
14
	const char *arg,
15
	struct strbuf *errbuf);
16

17
const char *list_object_filter_config_name(enum list_objects_filter_choice c)
18
{
19
	switch (c) {
20
	case LOFC_DISABLED:
21
		/* we have no name for "no filter at all" */
22
		break;
23
	case LOFC_BLOB_NONE:
24
		return "blob:none";
25
	case LOFC_BLOB_LIMIT:
26
		return "blob:limit";
27
	case LOFC_TREE_DEPTH:
28
		return "tree";
29
	case LOFC_SPARSE_OID:
30
		return "sparse:oid";
31
	case LOFC_OBJECT_TYPE:
32
		return "object:type";
33
	case LOFC_COMBINE:
34
		return "combine";
35
	case LOFC__COUNT:
36
		/* not a real filter type; just the count of all filters */
37
		break;
38
	}
39
	BUG("list_object_filter_config_name: invalid argument '%d'", c);
40
}
41

42
int gently_parse_list_objects_filter(
43
	struct list_objects_filter_options *filter_options,
44
	const char *arg,
45
	struct strbuf *errbuf)
46
{
47
	const char *v0;
48

49
	if (!arg)
50
		return 0;
51

52
	if (filter_options->choice)
53
		BUG("filter_options already populated");
54

55
	if (!strcmp(arg, "blob:none")) {
56
		filter_options->choice = LOFC_BLOB_NONE;
57
		return 0;
58

59
	} else if (skip_prefix(arg, "blob:limit=", &v0)) {
60
		if (git_parse_ulong(v0, &filter_options->blob_limit_value)) {
61
			filter_options->choice = LOFC_BLOB_LIMIT;
62
			return 0;
63
		}
64

65
	} else if (skip_prefix(arg, "tree:", &v0)) {
66
		if (!git_parse_ulong(v0, &filter_options->tree_exclude_depth)) {
67
			strbuf_addstr(errbuf, _("expected 'tree:<depth>'"));
68
			return 1;
69
		}
70
		filter_options->choice = LOFC_TREE_DEPTH;
71
		return 0;
72

73
	} else if (skip_prefix(arg, "sparse:oid=", &v0)) {
74
		filter_options->sparse_oid_name = xstrdup(v0);
75
		filter_options->choice = LOFC_SPARSE_OID;
76
		return 0;
77

78
	} else if (skip_prefix(arg, "sparse:path=", &v0)) {
79
		if (errbuf) {
80
			strbuf_addstr(
81
				errbuf,
82
				_("sparse:path filters support has been dropped"));
83
		}
84
		return 1;
85

86
	} else if (skip_prefix(arg, "object:type=", &v0)) {
87
		int type = type_from_string_gently(v0, strlen(v0), 1);
88
		if (type < 0) {
89
			strbuf_addf(errbuf, _("'%s' for 'object:type=<type>' is "
90
					      "not a valid object type"), v0);
91
			return 1;
92
		}
93

94
		filter_options->object_type = type;
95
		filter_options->choice = LOFC_OBJECT_TYPE;
96

97
		return 0;
98

99
	} else if (skip_prefix(arg, "combine:", &v0)) {
100
		return parse_combine_filter(filter_options, v0, errbuf);
101

102
	}
103
	/*
104
	 * Please update _git_fetch() in git-completion.bash when you
105
	 * add new filters
106
	 */
107

108
	strbuf_addf(errbuf, _("invalid filter-spec '%s'"), arg);
109

110
	list_objects_filter_init(filter_options);
111
	return 1;
112
}
113

114
static const char *RESERVED_NON_WS = "~`!@#$^&*()[]{}\\;'\",<>?";
115

116
static int has_reserved_character(
117
	struct strbuf *sub_spec, struct strbuf *errbuf)
118
{
119
	const char *c = sub_spec->buf;
120
	while (*c) {
121
		if (*c <= ' ' || strchr(RESERVED_NON_WS, *c)) {
122
			strbuf_addf(
123
				errbuf,
124
				_("must escape char in sub-filter-spec: '%c'"),
125
				*c);
126
			return 1;
127
		}
128
		c++;
129
	}
130

131
	return 0;
132
}
133

134
static int parse_combine_subfilter(
135
	struct list_objects_filter_options *filter_options,
136
	struct strbuf *subspec,
137
	struct strbuf *errbuf)
138
{
139
	size_t new_index = filter_options->sub_nr;
140
	char *decoded;
141
	int result;
142

143
	ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
144
		      filter_options->sub_alloc);
145
	list_objects_filter_init(&filter_options->sub[new_index]);
146

147
	decoded = url_percent_decode(subspec->buf);
148

149
	result = has_reserved_character(subspec, errbuf) ||
150
		gently_parse_list_objects_filter(
151
			&filter_options->sub[new_index], decoded, errbuf);
152

153
	free(decoded);
154
	return result;
155
}
156

157
static int parse_combine_filter(
158
	struct list_objects_filter_options *filter_options,
159
	const char *arg,
160
	struct strbuf *errbuf)
161
{
162
	struct strbuf **subspecs = strbuf_split_str(arg, '+', 0);
163
	size_t sub;
164
	int result = 0;
165

166
	if (!subspecs[0]) {
167
		strbuf_addstr(errbuf, _("expected something after combine:"));
168
		result = 1;
169
		goto cleanup;
170
	}
171

172
	for (sub = 0; subspecs[sub] && !result; sub++) {
173
		if (subspecs[sub + 1]) {
174
			/*
175
			 * This is not the last subspec. Remove trailing "+" so
176
			 * we can parse it.
177
			 */
178
			size_t last = subspecs[sub]->len - 1;
179
			assert(subspecs[sub]->buf[last] == '+');
180
			strbuf_remove(subspecs[sub], last, 1);
181
		}
182
		result = parse_combine_subfilter(
183
			filter_options, subspecs[sub], errbuf);
184
	}
185

186
	filter_options->choice = LOFC_COMBINE;
187

188
cleanup:
189
	strbuf_list_free(subspecs);
190
	if (result)
191
		list_objects_filter_release(filter_options);
192
	return result;
193
}
194

195
static int allow_unencoded(char ch)
196
{
197
	if (ch <= ' ' || ch == '%' || ch == '+')
198
		return 0;
199
	return !strchr(RESERVED_NON_WS, ch);
200
}
201

202
static void filter_spec_append_urlencode(
203
	struct list_objects_filter_options *filter, const char *raw)
204
{
205
	size_t orig_len = filter->filter_spec.len;
206
	strbuf_addstr_urlencode(&filter->filter_spec, raw, allow_unencoded);
207
	trace_printf("Add to combine filter-spec: %s\n",
208
		     filter->filter_spec.buf + orig_len);
209
}
210

211
/*
212
 * Changes filter_options into an equivalent LOFC_COMBINE filter options
213
 * instance. Does not do anything if filter_options is already LOFC_COMBINE.
214
 */
215
static void transform_to_combine_type(
216
	struct list_objects_filter_options *filter_options)
217
{
218
	assert(filter_options->choice);
219
	if (filter_options->choice == LOFC_COMBINE)
220
		return;
221
	{
222
		const int initial_sub_alloc = 2;
223
		struct list_objects_filter_options *sub_array =
224
			xcalloc(initial_sub_alloc, sizeof(*sub_array));
225
		sub_array[0] = *filter_options;
226
		list_objects_filter_init(filter_options);
227
		filter_options->sub = sub_array;
228
		filter_options->sub_alloc = initial_sub_alloc;
229
	}
230
	filter_options->sub_nr = 1;
231
	filter_options->choice = LOFC_COMBINE;
232
	strbuf_addstr(&filter_options->filter_spec, "combine:");
233
	filter_spec_append_urlencode(
234
		filter_options,
235
		list_objects_filter_spec(&filter_options->sub[0]));
236
	/*
237
	 * We don't need the filter_spec strings for subfilter specs, only the
238
	 * top level.
239
	 */
240
	strbuf_release(&filter_options->sub[0].filter_spec);
241
}
242

243
void list_objects_filter_die_if_populated(
244
	struct list_objects_filter_options *filter_options)
245
{
246
	if (filter_options->choice)
247
		die(_("multiple filter-specs cannot be combined"));
248
}
249

250
void parse_list_objects_filter(
251
	struct list_objects_filter_options *filter_options,
252
	const char *arg)
253
{
254
	struct strbuf errbuf = STRBUF_INIT;
255
	int parse_error;
256

257
	if (!filter_options->filter_spec.buf)
258
		BUG("filter_options not properly initialized");
259

260
	if (!filter_options->choice) {
261
		strbuf_addstr(&filter_options->filter_spec, arg);
262

263
		parse_error = gently_parse_list_objects_filter(
264
			filter_options, arg, &errbuf);
265
	} else {
266
		struct list_objects_filter_options *sub;
267

268
		/*
269
		 * Make filter_options an LOFC_COMBINE spec so we can trivially
270
		 * add subspecs to it.
271
		 */
272
		transform_to_combine_type(filter_options);
273

274
		strbuf_addch(&filter_options->filter_spec, '+');
275
		filter_spec_append_urlencode(filter_options, arg);
276
		ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
277
			      filter_options->sub_alloc);
278
		sub = &filter_options->sub[filter_options->sub_nr - 1];
279

280
		list_objects_filter_init(sub);
281
		parse_error = gently_parse_list_objects_filter(sub, arg,
282
							       &errbuf);
283
	}
284
	if (parse_error)
285
		die("%s", errbuf.buf);
286
}
287

288
int opt_parse_list_objects_filter(const struct option *opt,
289
				  const char *arg, int unset)
290
{
291
	struct list_objects_filter_options *filter_options = opt->value;
292

293
	if (unset || !arg)
294
		list_objects_filter_set_no_filter(filter_options);
295
	else
296
		parse_list_objects_filter(filter_options, arg);
297
	return 0;
298
}
299

300
const char *list_objects_filter_spec(struct list_objects_filter_options *filter)
301
{
302
	if (!filter->filter_spec.len)
303
		BUG("no filter_spec available for this filter");
304
	return filter->filter_spec.buf;
305
}
306

307
const char *expand_list_objects_filter_spec(
308
	struct list_objects_filter_options *filter)
309
{
310
	if (filter->choice == LOFC_BLOB_LIMIT) {
311
		strbuf_release(&filter->filter_spec);
312
		strbuf_addf(&filter->filter_spec, "blob:limit=%lu",
313
			    filter->blob_limit_value);
314
	}
315

316
	return list_objects_filter_spec(filter);
317
}
318

319
void list_objects_filter_release(
320
	struct list_objects_filter_options *filter_options)
321
{
322
	size_t sub;
323

324
	if (!filter_options)
325
		return;
326
	strbuf_release(&filter_options->filter_spec);
327
	free(filter_options->sparse_oid_name);
328
	for (sub = 0; sub < filter_options->sub_nr; sub++)
329
		list_objects_filter_release(&filter_options->sub[sub]);
330
	free(filter_options->sub);
331
	list_objects_filter_init(filter_options);
332
}
333

334
void partial_clone_register(
335
	const char *remote,
336
	struct list_objects_filter_options *filter_options)
337
{
338
	struct promisor_remote *promisor_remote;
339
	char *cfg_name;
340
	char *filter_name;
341

342
	/* Check if it is already registered */
343
	if ((promisor_remote = repo_promisor_remote_find(the_repository, remote))) {
344
		if (promisor_remote->partial_clone_filter)
345
			/*
346
			 * Remote is already registered and a filter is already
347
			 * set, so we don't need to do anything here.
348
			 */
349
			return;
350
	} else {
351
		if (upgrade_repository_format(1) < 0)
352
			die(_("unable to upgrade repository format to support partial clone"));
353

354
		/* Add promisor config for the remote */
355
		cfg_name = xstrfmt("remote.%s.promisor", remote);
356
		git_config_set(cfg_name, "true");
357
		free(cfg_name);
358
	}
359

360
	/*
361
	 * Record the initial filter-spec in the config as
362
	 * the default for subsequent fetches from this remote.
363
	 */
364
	filter_name = xstrfmt("remote.%s.partialclonefilter", remote);
365
	/* NEEDSWORK: 'expand' result leaking??? */
366
	git_config_set(filter_name,
367
		       expand_list_objects_filter_spec(filter_options));
368
	free(filter_name);
369

370
	/* Make sure the config info are reset */
371
	repo_promisor_remote_reinit(the_repository);
372
}
373

374
void partial_clone_get_default_filter_spec(
375
	struct list_objects_filter_options *filter_options,
376
	const char *remote)
377
{
378
	struct promisor_remote *promisor = repo_promisor_remote_find(the_repository,
379
								     remote);
380
	struct strbuf errbuf = STRBUF_INIT;
381

382
	/*
383
	 * Parse default value, but silently ignore it if it is invalid.
384
	 */
385
	if (!promisor || !promisor->partial_clone_filter)
386
		return;
387

388
	strbuf_addstr(&filter_options->filter_spec,
389
		      promisor->partial_clone_filter);
390
	gently_parse_list_objects_filter(filter_options,
391
					 promisor->partial_clone_filter,
392
					 &errbuf);
393
	strbuf_release(&errbuf);
394
}
395

396
void list_objects_filter_copy(
397
	struct list_objects_filter_options *dest,
398
	const struct list_objects_filter_options *src)
399
{
400
	int i;
401

402
	/* Copy everything. We will overwrite the pointers shortly. */
403
	memcpy(dest, src, sizeof(struct list_objects_filter_options));
404

405
	strbuf_init(&dest->filter_spec, 0);
406
	strbuf_addbuf(&dest->filter_spec, &src->filter_spec);
407
	dest->sparse_oid_name = xstrdup_or_null(src->sparse_oid_name);
408

409
	ALLOC_ARRAY(dest->sub, dest->sub_alloc);
410
	for (i = 0; i < src->sub_nr; i++)
411
		list_objects_filter_copy(&dest->sub[i], &src->sub[i]);
412
}
413

414
void list_objects_filter_init(struct list_objects_filter_options *filter_options)
415
{
416
	struct list_objects_filter_options blank = LIST_OBJECTS_FILTER_INIT;
417
	memcpy(filter_options, &blank, sizeof(*filter_options));
418
}
419

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.