| 
11 | 11 | #include "strvec.h"  | 
12 | 12 | #include "packfile.h"  | 
13 | 13 | #include "environment.h"  | 
 | 14 | +#include "url.h"  | 
 | 15 | +#include "version.h"  | 
14 | 16 | 
 
  | 
15 | 17 | struct promisor_remote_config {  | 
16 | 18 | 	struct promisor_remote *promisors;  | 
@@ -221,6 +223,18 @@ int repo_has_promisor_remote(struct repository *r)  | 
221 | 223 | 	return !!repo_promisor_remote_find(r, NULL);  | 
222 | 224 | }  | 
223 | 225 | 
 
  | 
 | 226 | +int repo_has_accepted_promisor_remote(struct repository *r)  | 
 | 227 | +{  | 
 | 228 | +	struct promisor_remote *p;  | 
 | 229 | + | 
 | 230 | +	promisor_remote_init(r);  | 
 | 231 | + | 
 | 232 | +	for (p = r->promisor_remote_config->promisors; p; p = p->next)  | 
 | 233 | +		if (p->accepted)  | 
 | 234 | +			return 1;  | 
 | 235 | +	return 0;  | 
 | 236 | +}  | 
 | 237 | + | 
224 | 238 | static int remove_fetched_oids(struct repository *repo,  | 
225 | 239 | 			       struct object_id **oids,  | 
226 | 240 | 			       int oid_nr, int to_free)  | 
@@ -292,3 +306,185 @@ void promisor_remote_get_direct(struct repository *repo,  | 
292 | 306 | 	if (to_free)  | 
293 | 307 | 		free(remaining_oids);  | 
294 | 308 | }  | 
 | 309 | + | 
 | 310 | +static int allow_unsanitized(char ch)  | 
 | 311 | +{  | 
 | 312 | +	if (ch == ',' || ch == ';' || ch == '%')  | 
 | 313 | +		return 0;  | 
 | 314 | +	return ch > 32 && ch < 127;  | 
 | 315 | +}  | 
 | 316 | + | 
 | 317 | +static void promisor_info_vecs(struct repository *repo,  | 
 | 318 | +			       struct strvec *names,  | 
 | 319 | +			       struct strvec *urls)  | 
 | 320 | +{  | 
 | 321 | +	struct promisor_remote *r;  | 
 | 322 | + | 
 | 323 | +	promisor_remote_init(repo);  | 
 | 324 | + | 
 | 325 | +	for (r = repo->promisor_remote_config->promisors; r; r = r->next) {  | 
 | 326 | +		char *url;  | 
 | 327 | +		char *url_key = xstrfmt("remote.%s.url", r->name);  | 
 | 328 | + | 
 | 329 | +		strvec_push(names, r->name);  | 
 | 330 | +		strvec_push(urls, git_config_get_string(url_key, &url) ? NULL : url);  | 
 | 331 | + | 
 | 332 | +		free(url);  | 
 | 333 | +		free(url_key);  | 
 | 334 | +	}  | 
 | 335 | +}  | 
 | 336 | + | 
 | 337 | +char *promisor_remote_info(struct repository *repo)  | 
 | 338 | +{  | 
 | 339 | +	struct strbuf sb = STRBUF_INIT;  | 
 | 340 | +	int advertise_promisors = 0;  | 
 | 341 | +	struct strvec names = STRVEC_INIT;  | 
 | 342 | +	struct strvec urls = STRVEC_INIT;  | 
 | 343 | + | 
 | 344 | +	git_config_get_bool("promisor.advertise", &advertise_promisors);  | 
 | 345 | + | 
 | 346 | +	if (!advertise_promisors)  | 
 | 347 | +		return NULL;  | 
 | 348 | + | 
 | 349 | +	promisor_info_vecs(repo, &names, &urls);  | 
 | 350 | + | 
 | 351 | +	if (!names.nr)  | 
 | 352 | +		return NULL;  | 
 | 353 | + | 
 | 354 | +	for (size_t i = 0; i < names.nr; i++) {  | 
 | 355 | +		if (i)  | 
 | 356 | +			strbuf_addch(&sb, ';');  | 
 | 357 | +		strbuf_addstr(&sb, "name=");  | 
 | 358 | +		strbuf_addstr_urlencode(&sb, names.v[i], allow_unsanitized);  | 
 | 359 | +		if (urls.v[i]) {  | 
 | 360 | +			strbuf_addstr(&sb, ",url=");  | 
 | 361 | +			strbuf_addstr_urlencode(&sb, urls.v[i], allow_unsanitized);  | 
 | 362 | +		}  | 
 | 363 | +	}  | 
 | 364 | + | 
 | 365 | +	redact_non_printables(&sb);  | 
 | 366 | + | 
 | 367 | +	strvec_clear(&names);  | 
 | 368 | +	strvec_clear(&urls);  | 
 | 369 | + | 
 | 370 | +	return strbuf_detach(&sb, NULL);  | 
 | 371 | +}  | 
 | 372 | + | 
 | 373 | +enum accept_promisor {  | 
 | 374 | +	ACCEPT_NONE = 0,  | 
 | 375 | +	ACCEPT_ALL  | 
 | 376 | +};  | 
 | 377 | + | 
 | 378 | +static int should_accept_remote(enum accept_promisor accept,  | 
 | 379 | +				const char *remote_name UNUSED,  | 
 | 380 | +				const char *remote_url UNUSED)  | 
 | 381 | +{  | 
 | 382 | +	if (accept == ACCEPT_ALL)  | 
 | 383 | +		return 1;  | 
 | 384 | + | 
 | 385 | +	BUG("Unhandled 'enum accept_promisor' value '%d'", accept);  | 
 | 386 | +}  | 
 | 387 | + | 
 | 388 | +static void filter_promisor_remote(struct strvec *accepted, const char *info)  | 
 | 389 | +{  | 
 | 390 | +	struct strbuf **remotes;  | 
 | 391 | +	const char *accept_str;  | 
 | 392 | +	enum accept_promisor accept = ACCEPT_NONE;  | 
 | 393 | + | 
 | 394 | +	if (!git_config_get_string_tmp("promisor.acceptfromserver", &accept_str)) {  | 
 | 395 | +		if (!accept_str || !*accept_str || !strcasecmp("None", accept_str))  | 
 | 396 | +			accept = ACCEPT_NONE;  | 
 | 397 | +		else if (!strcasecmp("All", accept_str))  | 
 | 398 | +			accept = ACCEPT_ALL;  | 
 | 399 | +		else  | 
 | 400 | +			warning(_("unknown '%s' value for '%s' config option"),  | 
 | 401 | +				accept_str, "promisor.acceptfromserver");  | 
 | 402 | +	}  | 
 | 403 | + | 
 | 404 | +	if (accept == ACCEPT_NONE)  | 
 | 405 | +		return;  | 
 | 406 | + | 
 | 407 | +	/* Parse remote info received */  | 
 | 408 | + | 
 | 409 | +	remotes = strbuf_split_str(info, ';', 0);  | 
 | 410 | + | 
 | 411 | +	for (size_t i = 0; remotes[i]; i++) {  | 
 | 412 | +		struct strbuf **elems;  | 
 | 413 | +		const char *remote_name = NULL;  | 
 | 414 | +		const char *remote_url = NULL;  | 
 | 415 | +		char *decoded_name = NULL;  | 
 | 416 | +		char *decoded_url = NULL;  | 
 | 417 | + | 
 | 418 | +		strbuf_strip_suffix(remotes[i], ";");  | 
 | 419 | +		elems = strbuf_split(remotes[i], ',');  | 
 | 420 | + | 
 | 421 | +		for (size_t j = 0; elems[j]; j++) {  | 
 | 422 | +			int res;  | 
 | 423 | +			strbuf_strip_suffix(elems[j], ",");  | 
 | 424 | +			res = skip_prefix(elems[j]->buf, "name=", &remote_name) ||  | 
 | 425 | +				skip_prefix(elems[j]->buf, "url=", &remote_url);  | 
 | 426 | +			if (!res)  | 
 | 427 | +				warning(_("unknown element '%s' from remote info"),  | 
 | 428 | +					elems[j]->buf);  | 
 | 429 | +		}  | 
 | 430 | + | 
 | 431 | +		if (remote_name)  | 
 | 432 | +			decoded_name = url_percent_decode(remote_name);  | 
 | 433 | +		if (remote_url)  | 
 | 434 | +			decoded_url = url_percent_decode(remote_url);  | 
 | 435 | + | 
 | 436 | +		if (decoded_name && should_accept_remote(accept, decoded_name, decoded_url))  | 
 | 437 | +			strvec_push(accepted, decoded_name);  | 
 | 438 | + | 
 | 439 | +		strbuf_list_free(elems);  | 
 | 440 | +		free(decoded_name);  | 
 | 441 | +		free(decoded_url);  | 
 | 442 | +	}  | 
 | 443 | + | 
 | 444 | +	strbuf_list_free(remotes);  | 
 | 445 | +}  | 
 | 446 | + | 
 | 447 | +char *promisor_remote_reply(const char *info)  | 
 | 448 | +{  | 
 | 449 | +	struct strvec accepted = STRVEC_INIT;  | 
 | 450 | +	struct strbuf reply = STRBUF_INIT;  | 
 | 451 | + | 
 | 452 | +	filter_promisor_remote(&accepted, info);  | 
 | 453 | + | 
 | 454 | +	if (!accepted.nr)  | 
 | 455 | +		return NULL;  | 
 | 456 | + | 
 | 457 | +	for (size_t i = 0; i < accepted.nr; i++) {  | 
 | 458 | +		if (i)  | 
 | 459 | +			strbuf_addch(&reply, ';');  | 
 | 460 | +		strbuf_addstr_urlencode(&reply, accepted.v[i], allow_unsanitized);  | 
 | 461 | +	}  | 
 | 462 | + | 
 | 463 | +	strvec_clear(&accepted);  | 
 | 464 | + | 
 | 465 | +	return strbuf_detach(&reply, NULL);  | 
 | 466 | +}  | 
 | 467 | + | 
 | 468 | +void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes)  | 
 | 469 | +{  | 
 | 470 | +	struct strbuf **accepted_remotes = strbuf_split_str(remotes, ';', 0);  | 
 | 471 | + | 
 | 472 | +	for (size_t i = 0; accepted_remotes[i]; i++) {  | 
 | 473 | +		struct promisor_remote *p;  | 
 | 474 | +		char *decoded_remote;  | 
 | 475 | + | 
 | 476 | +		strbuf_strip_suffix(accepted_remotes[i], ";");  | 
 | 477 | +		decoded_remote = url_percent_decode(accepted_remotes[i]->buf);  | 
 | 478 | + | 
 | 479 | +		p = repo_promisor_remote_find(r, decoded_remote);  | 
 | 480 | +		if (p)  | 
 | 481 | +			p->accepted = 1;  | 
 | 482 | +		else  | 
 | 483 | +			warning(_("accepted promisor remote '%s' not found"),  | 
 | 484 | +				decoded_remote);  | 
 | 485 | + | 
 | 486 | +		free(decoded_remote);  | 
 | 487 | +	}  | 
 | 488 | + | 
 | 489 | +	strbuf_list_free(accepted_remotes);  | 
 | 490 | +}  | 
0 commit comments