314
return ch > 32 && ch < 127;
315
}
316
317
+static const char promisor_field_filter[] = "partialCloneFilter";
318
+static const char promisor_field_token[] = "token";
319
+
320
+/*
321
+ * List of optional field names that can be used in the
322
+ * "promisor-remote" protocol capability (others must be
323
+ * ignored). Each field should correspond to a configurable property
324
+ * of a remote that can be relevant for the client.
325
+ */
326
+static const char *known_fields[] = {
327
+ promisor_field_filter, /* Filter used for partial clone */
328
+ promisor_field_token, /* Authentication token for the remote */
329
+ NULL
330
+};
331
+
332
+/*
333
+ * Check if 'field' is in the list of the known field names for the
334
+ * "promisor-remote" protocol capability.
335
+ */
336
+static int is_known_field(const char *field)
337
+{
338
+ const char **p;
339
+
340
+ for (p = known_fields; *p; p++)
341
+ if (!strcasecmp(*p, field))
342
+ return 1;
343
+ return 0;
344
+}
345
+
346
+static int is_valid_field(struct string_list_item *item, void *cb_data)
347
+{
348
+ const char *field = item->string;
349
+ const char *config_key = (const char *)cb_data;
350
+
351
+ if (!is_known_field(field)) {
352
+ warning(_("unsupported field '%s' in '%s' config"), field, config_key);
353
+ return 0;
354
+ }
355
+ return 1;
356
+}
357
+
358
+static char *fields_from_config(struct string_list *fields_list, const char *config_key)
359
+{
360
+ char *fields = NULL;
361
+
362
+ if (!repo_config_get_string(the_repository, config_key, &fields) && *fields) {
363
+ string_list_split_in_place_f(fields_list, fields, ",", -1,
364
+ STRING_LIST_SPLIT_TRIM |
365
+ STRING_LIST_SPLIT_NONEMPTY);
366
+ filter_string_list(fields_list, 0, is_valid_field, (void *)config_key);
367
+ }
368
+
369
+ return fields;
370
+}
371
+
372
+static struct string_list *fields_sent(void)
373
+{
374
+ static struct string_list fields_list = STRING_LIST_INIT_NODUP;
375
+ static int initialized;
376
+
377
+ if (!initialized) {
378
+ fields_list.cmp = strcasecmp;
379
+ fields_from_config(&fields_list, "promisor.sendFields");
380
+ initialized = 1;
381
+ }
382
+
383
+ return &fields_list;
384
+}
385
+
386
/*
387
* Struct for promisor remotes involved in the "promisor-remote"
388
* protocol capability.
395
struct promisor_info {
396
const char *name;
397
const char *url;
398
+ const char *filter;
399
+ const char *token;
400
};
401
402
static void promisor_info_list_clear(struct string_list *list)
405
struct promisor_info *p = list->items[i].util;
406
free((char *)p->name);
407
free((char *)p->url);
408
+ free((char *)p->filter);
409
+ free((char *)p->token);
410
}
411
string_list_clear(list, 1);
412
}
413
414
+static void set_one_field(struct promisor_info *p,
415
+ const char *field, const char *value)
416
+{
417
+ if (!strcasecmp(field, promisor_field_filter))
418
+ p->filter = xstrdup(value);
419
+ else if (!strcasecmp(field, promisor_field_token))
420
+ p->token = xstrdup(value);
421
+ else
422
+ BUG("invalid field '%s'", field);
423
+}
424
+
425
+static void set_fields(struct promisor_info *p,
426
+ struct string_list *field_names)
427
+{
428
+ struct string_list_item *item;
429
+
430
+ for_each_string_list_item(item, field_names) {
431
+ char *key = xstrfmt("remote.%s.%s", p->name, item->string);
432
+ const char *val;
433
+ if (!repo_config_get_string_tmp(the_repository, key, &val) && *val)
434
+ set_one_field(p, item->string, val);
435
+ free(key);
436
+ }
437
+}
438
+
439
/*
440
* Populate 'list' with promisor remote information from the config.
343
- * The 'util' pointer of each list item will hold a 'struct promisor_info'.
441
+ * The 'util' pointer of each list item will hold a 'struct
442
+ * promisor_info'. Except "name" and "url", only members of that
443
+ * struct specified by the 'field_names' list are set (using values
444
+ * from the configuration).
445
*/
345
-static void promisor_config_info_list(struct repository *repo, struct string_list *list)
446
+static void promisor_config_info_list(struct repository *repo,
447
+ struct string_list *list,
448
+ struct string_list *field_names)
449
{
450
struct promisor_remote *r;
451
463
new_info->name = xstrdup(r->name);
464
new_info->url = xstrdup(url);
465
466
+ if (field_names)
467
+ set_fields(new_info, field_names);
468
+
469
item = string_list_append(list, new_info->name);
470
item->util = new_info;
471
}
486
if (!advertise_promisors)
487
return NULL;
488
383
- promisor_config_info_list(repo, &config_info);
489
+ promisor_config_info_list(repo, &config_info, fields_sent());
490
491
if (!config_info.nr)
492
return NULL;
501
strbuf_addstr_urlencode(&sb, p->name, allow_unsanitized);
502
strbuf_addstr(&sb, ",url=");
503
strbuf_addstr_urlencode(&sb, p->url, allow_unsanitized);
504
+
505
+ if (p->filter) {
506
+ strbuf_addf(&sb, ",%s=", promisor_field_filter);
507
+ strbuf_addstr_urlencode(&sb, p->filter, allow_unsanitized);
508
+ }
509
+ if (p->token) {
510
+ strbuf_addf(&sb, ",%s=", promisor_field_token);
511
+ strbuf_addstr_urlencode(&sb, p->token, allow_unsanitized);
512
+ }
513
}
514
515
promisor_info_list_clear(&config_info);
590
return;
591
592
if (accept != ACCEPT_ALL) {
478
- promisor_config_info_list(repo, &config_info);
593
+ promisor_config_info_list(repo, &config_info, NULL);
594
string_list_sort(&config_info);
595
}
596
609
elems = strbuf_split(remotes[i], ',');
610
611
for (size_t j = 0; elems[j]; j++) {
497
- int res;
612
strbuf_strip_suffix(elems[j], ",");
499
- res = skip_prefix(elems[j]->buf, "name=", &remote_name) ||
613
+ if (!skip_prefix(elems[j]->buf, "name=", &remote_name))
614
skip_prefix(elems[j]->buf, "url=", &remote_url);
501
- if (!res)
502
- warning(_("unknown element '%s' from remote info"),
503
- elems[j]->buf);
615
}
616
617
if (remote_name)