Merge branch 'cc/promisor-auto-config-url'
Promisor remote handling has been refactored and fixed in preparation for auto-configuration of advertised remotes. * cc/promisor-auto-config-url: t5710: use proper file:// URIs for absolute paths promisor-remote: remove the 'accepted' strvec promisor-remote: keep accepted promisor_info structs alive promisor-remote: refactor accept_from_server() promisor-remote: refactor has_control_char() promisor-remote: refactor should_accept_remote() control flow promisor-remote: reject empty name or URL in advertised remote promisor-remote: clarify that a remote is ignored promisor-remote: pass config entry to all_fields_match() directly promisor-remote: try accepted remotes before others in get_direct()main
commit
a19de4d24a
|
|
@ -848,6 +848,10 @@ advertised, it can reply with "promisor-remote=<pr-names>" where
|
|||
where `pr-name` is the urlencoded name of a promisor remote the server
|
||||
advertised and the client accepts.
|
||||
|
||||
The promisor remotes that the client accepted will be tried before the
|
||||
other configured promisor remotes when the client attempts to fetch
|
||||
missing objects.
|
||||
|
||||
Note that, everywhere in this document, the ';' and ',' characters
|
||||
MUST be encoded if they appear in `pr-name` or `field-value`.
|
||||
|
||||
|
|
|
|||
|
|
@ -268,11 +268,35 @@ static int remove_fetched_oids(struct repository *repo,
|
|||
return remaining_nr;
|
||||
}
|
||||
|
||||
static int try_promisor_remotes(struct repository *repo,
|
||||
struct object_id **remaining_oids,
|
||||
int *remaining_nr, int *to_free,
|
||||
bool accepted_only)
|
||||
{
|
||||
struct promisor_remote *r = repo->promisor_remote_config->promisors;
|
||||
|
||||
for (; r; r = r->next) {
|
||||
if (accepted_only != r->accepted)
|
||||
continue;
|
||||
if (fetch_objects(repo, r->name, *remaining_oids, *remaining_nr) < 0) {
|
||||
if (*remaining_nr == 1)
|
||||
continue;
|
||||
*remaining_nr = remove_fetched_oids(repo, remaining_oids,
|
||||
*remaining_nr, *to_free);
|
||||
if (*remaining_nr) {
|
||||
*to_free = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 1; /* all fetched */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void promisor_remote_get_direct(struct repository *repo,
|
||||
const struct object_id *oids,
|
||||
int oid_nr)
|
||||
{
|
||||
struct promisor_remote *r;
|
||||
struct object_id *remaining_oids = (struct object_id *)oids;
|
||||
int remaining_nr = oid_nr;
|
||||
int to_free = 0;
|
||||
|
|
@ -283,19 +307,13 @@ void promisor_remote_get_direct(struct repository *repo,
|
|||
|
||||
promisor_remote_init(repo);
|
||||
|
||||
for (r = repo->promisor_remote_config->promisors; r; r = r->next) {
|
||||
if (fetch_objects(repo, r->name, remaining_oids, remaining_nr) < 0) {
|
||||
if (remaining_nr == 1)
|
||||
continue;
|
||||
remaining_nr = remove_fetched_oids(repo, &remaining_oids,
|
||||
remaining_nr, to_free);
|
||||
if (remaining_nr) {
|
||||
to_free = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Try accepted remotes first (those the server told us to use) */
|
||||
if (try_promisor_remotes(repo, &remaining_oids, &remaining_nr,
|
||||
&to_free, true))
|
||||
goto all_fetched;
|
||||
if (try_promisor_remotes(repo, &remaining_oids, &remaining_nr,
|
||||
&to_free, false))
|
||||
goto all_fetched;
|
||||
}
|
||||
|
||||
for (i = 0; i < remaining_nr; i++) {
|
||||
if (is_promisor_object(repo, &remaining_oids[i]))
|
||||
|
|
@ -557,6 +575,12 @@ enum accept_promisor {
|
|||
ACCEPT_ALL
|
||||
};
|
||||
|
||||
/*
|
||||
* Check if a specific field and its advertised value match the local
|
||||
* configuration of a given promisor remote.
|
||||
*
|
||||
* Returns 1 if they match, 0 otherwise.
|
||||
*/
|
||||
static int match_field_against_config(const char *field, const char *value,
|
||||
struct promisor_info *config_info)
|
||||
{
|
||||
|
|
@ -568,9 +592,18 @@ static int match_field_against_config(const char *field, const char *value,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the advertised fields match the local configuration.
|
||||
*
|
||||
* When 'config_entry' is NULL (ACCEPT_ALL mode), every checked field
|
||||
* must match at least one remote in 'config_info'.
|
||||
*
|
||||
* When 'config_entry' points to a specific remote's config, the
|
||||
* checked fields are compared against that single remote only.
|
||||
*/
|
||||
static int all_fields_match(struct promisor_info *advertised,
|
||||
struct string_list *config_info,
|
||||
int in_list)
|
||||
struct promisor_info *config_entry)
|
||||
{
|
||||
struct string_list *fields = fields_checked();
|
||||
struct string_list_item *item_checked;
|
||||
|
|
@ -579,7 +612,6 @@ static int all_fields_match(struct promisor_info *advertised,
|
|||
int match = 0;
|
||||
const char *field = item_checked->string;
|
||||
const char *value = NULL;
|
||||
struct string_list_item *item;
|
||||
|
||||
if (!strcasecmp(field, promisor_field_filter))
|
||||
value = advertised->filter;
|
||||
|
|
@ -589,7 +621,11 @@ static int all_fields_match(struct promisor_info *advertised,
|
|||
if (!value)
|
||||
return 0;
|
||||
|
||||
if (in_list) {
|
||||
if (config_entry) {
|
||||
match = match_field_against_config(field, value,
|
||||
config_entry);
|
||||
} else {
|
||||
struct string_list_item *item;
|
||||
for_each_string_list_item(item, config_info) {
|
||||
struct promisor_info *p = item->util;
|
||||
if (match_field_against_config(field, value, p)) {
|
||||
|
|
@ -597,12 +633,6 @@ static int all_fields_match(struct promisor_info *advertised,
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item = string_list_lookup(config_info, advertised->name);
|
||||
if (item) {
|
||||
struct promisor_info *p = item->util;
|
||||
match = match_field_against_config(field, value, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
|
|
@ -612,6 +642,14 @@ static int all_fields_match(struct promisor_info *advertised,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static bool has_control_char(const char *s)
|
||||
{
|
||||
for (const char *c = s; *c; c++)
|
||||
if (iscntrl(*c))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int should_accept_remote(enum accept_promisor accept,
|
||||
struct promisor_info *advertised,
|
||||
struct string_list *config_info)
|
||||
|
|
@ -621,8 +659,13 @@ static int should_accept_remote(enum accept_promisor accept,
|
|||
const char *remote_name = advertised->name;
|
||||
const char *remote_url = advertised->url;
|
||||
|
||||
if (!remote_url || !*remote_url)
|
||||
BUG("no or empty URL advertised for remote '%s'; "
|
||||
"this remote should have been rejected earlier",
|
||||
remote_name);
|
||||
|
||||
if (accept == ACCEPT_ALL)
|
||||
return all_fields_match(advertised, config_info, 1);
|
||||
return all_fields_match(advertised, config_info, NULL);
|
||||
|
||||
/* Get config info for that promisor remote */
|
||||
item = string_list_lookup(config_info, remote_name);
|
||||
|
|
@ -634,23 +677,19 @@ static int should_accept_remote(enum accept_promisor accept,
|
|||
p = item->util;
|
||||
|
||||
if (accept == ACCEPT_KNOWN_NAME)
|
||||
return all_fields_match(advertised, config_info, 0);
|
||||
return all_fields_match(advertised, config_info, p);
|
||||
|
||||
if (accept != ACCEPT_KNOWN_URL)
|
||||
BUG("Unhandled 'enum accept_promisor' value '%d'", accept);
|
||||
|
||||
if (!remote_url || !*remote_url) {
|
||||
warning(_("no or empty URL advertised for remote '%s'"), remote_name);
|
||||
if (strcmp(p->url, remote_url)) {
|
||||
warning(_("known remote named '%s' but with URL '%s' instead of '%s', "
|
||||
"ignoring this remote"),
|
||||
remote_name, p->url, remote_url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(p->url, remote_url))
|
||||
return all_fields_match(advertised, config_info, 0);
|
||||
|
||||
warning(_("known remote named '%s' but with URL '%s' instead of '%s'"),
|
||||
remote_name, p->url, remote_url);
|
||||
|
||||
return 0;
|
||||
return all_fields_match(advertised, config_info, p);
|
||||
}
|
||||
|
||||
static int skip_field_name_prefix(const char *elem, const char *field_name, const char **value)
|
||||
|
|
@ -691,9 +730,9 @@ static struct promisor_info *parse_one_advertised_remote(const char *remote_info
|
|||
|
||||
string_list_clear(&elem_list, 0);
|
||||
|
||||
if (!info->name || !info->url) {
|
||||
warning(_("server advertised a promisor remote without a name or URL: %s"),
|
||||
remote_info);
|
||||
if (!info->name || !*info->name || !info->url || !*info->url) {
|
||||
warning(_("server advertised a promisor remote without a name or URL: '%s', "
|
||||
"ignoring this remote"), remote_info);
|
||||
promisor_info_free(info);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -741,18 +780,14 @@ static bool valid_filter(const char *filter, const char *remote_name)
|
|||
return !res;
|
||||
}
|
||||
|
||||
/* Check that a token doesn't contain any control character */
|
||||
static bool valid_token(const char *token, const char *remote_name)
|
||||
{
|
||||
const char *c = token;
|
||||
|
||||
for (; *c; c++)
|
||||
if (iscntrl(*c)) {
|
||||
warning(_("invalid token '%s' for remote '%s' "
|
||||
"will not be stored"),
|
||||
token, remote_name);
|
||||
return false;
|
||||
}
|
||||
if (has_control_char(token)) {
|
||||
warning(_("invalid token '%s' for remote '%s' "
|
||||
"will not be stored"),
|
||||
token, remote_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -827,20 +862,12 @@ static bool promisor_store_advertised_fields(struct promisor_info *advertised,
|
|||
return reload_config;
|
||||
}
|
||||
|
||||
static void filter_promisor_remote(struct repository *repo,
|
||||
struct strvec *accepted,
|
||||
const char *info)
|
||||
static enum accept_promisor accept_from_server(struct repository *repo)
|
||||
{
|
||||
const char *accept_str;
|
||||
enum accept_promisor accept = ACCEPT_NONE;
|
||||
struct string_list config_info = STRING_LIST_INIT_NODUP;
|
||||
struct string_list remote_info = STRING_LIST_INIT_DUP;
|
||||
struct store_info *store_info = NULL;
|
||||
struct string_list_item *item;
|
||||
bool reload_config = false;
|
||||
struct string_list accepted_filters = STRING_LIST_INIT_DUP;
|
||||
|
||||
if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) {
|
||||
if (!repo_config_get_string_tmp(repo, "promisor.acceptfromserver", &accept_str)) {
|
||||
if (!*accept_str || !strcasecmp("None", accept_str))
|
||||
accept = ACCEPT_NONE;
|
||||
else if (!strcasecmp("KnownUrl", accept_str))
|
||||
|
|
@ -854,6 +881,20 @@ static void filter_promisor_remote(struct repository *repo,
|
|||
accept_str, "promisor.acceptfromserver");
|
||||
}
|
||||
|
||||
return accept;
|
||||
}
|
||||
|
||||
static void filter_promisor_remote(struct repository *repo,
|
||||
struct string_list *accepted_remotes,
|
||||
const char *info)
|
||||
{
|
||||
struct string_list config_info = STRING_LIST_INIT_NODUP;
|
||||
struct string_list remote_info = STRING_LIST_INIT_DUP;
|
||||
struct store_info *store_info = NULL;
|
||||
struct string_list_item *item;
|
||||
bool reload_config = false;
|
||||
enum accept_promisor accept = accept_from_server(repo);
|
||||
|
||||
if (accept == ACCEPT_NONE)
|
||||
return;
|
||||
|
||||
|
|
@ -880,17 +921,10 @@ static void filter_promisor_remote(struct repository *repo,
|
|||
if (promisor_store_advertised_fields(advertised, store_info))
|
||||
reload_config = true;
|
||||
|
||||
strvec_push(accepted, advertised->name);
|
||||
|
||||
/* Capture advertised filters for accepted remotes */
|
||||
if (advertised->filter) {
|
||||
struct string_list_item *i;
|
||||
i = string_list_append(&accepted_filters, advertised->name);
|
||||
i->util = xstrdup(advertised->filter);
|
||||
}
|
||||
string_list_append(accepted_remotes, advertised->name)->util = advertised;
|
||||
} else {
|
||||
promisor_info_free(advertised);
|
||||
}
|
||||
|
||||
promisor_info_free(advertised);
|
||||
}
|
||||
|
||||
promisor_info_list_clear(&config_info);
|
||||
|
|
@ -900,39 +934,36 @@ static void filter_promisor_remote(struct repository *repo,
|
|||
if (reload_config)
|
||||
repo_promisor_remote_reinit(repo);
|
||||
|
||||
/* Apply accepted remote filters to the stable repo state */
|
||||
for_each_string_list_item(item, &accepted_filters) {
|
||||
struct promisor_remote *r = repo_promisor_remote_find(repo, item->string);
|
||||
/* Apply accepted remotes to the stable repo state */
|
||||
for_each_string_list_item(item, accepted_remotes) {
|
||||
struct promisor_info *info = item->util;
|
||||
struct promisor_remote *r = repo_promisor_remote_find(repo, info->name);
|
||||
|
||||
if (r) {
|
||||
free(r->advertised_filter);
|
||||
r->advertised_filter = item->util;
|
||||
item->util = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
string_list_clear(&accepted_filters, 1);
|
||||
|
||||
/* Mark the remotes as accepted in the repository state */
|
||||
for (size_t i = 0; i < accepted->nr; i++) {
|
||||
struct promisor_remote *r = repo_promisor_remote_find(repo, accepted->v[i]);
|
||||
if (r)
|
||||
r->accepted = 1;
|
||||
if (info->filter) {
|
||||
free(r->advertised_filter);
|
||||
r->advertised_filter = xstrdup(info->filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void promisor_remote_reply(const char *info, char **accepted_out)
|
||||
{
|
||||
struct strvec accepted = STRVEC_INIT;
|
||||
struct string_list accepted_remotes = STRING_LIST_INIT_NODUP;
|
||||
|
||||
filter_promisor_remote(the_repository, &accepted, info);
|
||||
filter_promisor_remote(the_repository, &accepted_remotes, info);
|
||||
|
||||
if (accepted_out) {
|
||||
if (accepted.nr) {
|
||||
if (accepted_remotes.nr) {
|
||||
struct strbuf reply = STRBUF_INIT;
|
||||
for (size_t i = 0; i < accepted.nr; i++) {
|
||||
if (i)
|
||||
struct string_list_item *item;
|
||||
|
||||
for_each_string_list_item(item, &accepted_remotes) {
|
||||
if (reply.len)
|
||||
strbuf_addch(&reply, ';');
|
||||
strbuf_addstr_urlencode(&reply, accepted.v[i], allow_unsanitized);
|
||||
strbuf_addstr_urlencode(&reply, item->string, allow_unsanitized);
|
||||
}
|
||||
*accepted_out = strbuf_detach(&reply, NULL);
|
||||
} else {
|
||||
|
|
@ -940,7 +971,7 @@ void promisor_remote_reply(const char *info, char **accepted_out)
|
|||
}
|
||||
}
|
||||
|
||||
strvec_clear(&accepted);
|
||||
promisor_info_list_clear(&accepted_remotes);
|
||||
}
|
||||
|
||||
void mark_promisor_remotes_as_accepted(struct repository *r, const char *remotes)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,31 @@ copy_to_lop () {
|
|||
cp "$path" "$path2"
|
||||
}
|
||||
|
||||
# On Windows, `pwd` returns a path like 'D:/foo/bar'. Prepend '/' to turn
|
||||
# it into '/D:/foo/bar', which is what git expects in file:// URLs on Windows.
|
||||
# On Unix, the path already starts with '/', so this is a no-op.
|
||||
pwd_path=$(pwd)
|
||||
case "$pwd_path" in
|
||||
[a-zA-Z]:*) pwd_path="/$pwd_path" ;;
|
||||
esac
|
||||
|
||||
# Allowed characters: alphanumeric, standard path/URI (_ . ~ / : -),
|
||||
# and those percent-encoded below (% space = , ;)
|
||||
rest=$(printf "%s" "$pwd_path" | tr -d 'a-zA-Z0-9_.~/:% =,;-')
|
||||
if test -n "$rest"
|
||||
then
|
||||
skip_all="PWD contains unsupported special characters"
|
||||
test_done
|
||||
fi
|
||||
|
||||
TRASH_DIRECTORY_URL="file://$pwd_path"
|
||||
|
||||
encoded_path=$(printf "%s" "$pwd_path" |
|
||||
sed -e 's/%/%25/g' -e 's/ /%20/g' -e 's/=/%3D/g' \
|
||||
-e 's/;/%3B/g' -e 's/,/%2C/g')
|
||||
|
||||
ENCODED_TRASH_DIRECTORY_URL="file://$encoded_path"
|
||||
|
||||
test_expect_success "setup for testing promisor remote advertisement" '
|
||||
# Create another bare repo called "lop" (for Large Object Promisor)
|
||||
git init --bare lop &&
|
||||
|
|
@ -88,7 +113,7 @@ test_expect_success "setup for testing promisor remote advertisement" '
|
|||
initialize_server 1 "$oid" &&
|
||||
|
||||
# Configure lop as promisor remote for server
|
||||
git -C server remote add lop "file://$(pwd)/lop" &&
|
||||
git -C server remote add lop "$TRASH_DIRECTORY_URL/lop" &&
|
||||
git -C server config remote.lop.promisor true &&
|
||||
|
||||
git -C lop config uploadpack.allowFilter true &&
|
||||
|
|
@ -104,7 +129,7 @@ test_expect_success "clone with promisor.advertise set to 'true'" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -119,7 +144,7 @@ test_expect_success "clone with promisor.advertise set to 'false'" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -137,7 +162,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'None'" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=None \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -156,8 +181,8 @@ test_expect_success "init + fetch with promisor.advertise set to 'true'" '
|
|||
git -C client init &&
|
||||
git -C client config remote.lop.promisor true &&
|
||||
git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" &&
|
||||
git -C client config remote.lop.url "file://$(pwd)/lop" &&
|
||||
git -C client config remote.server.url "file://$(pwd)/server" &&
|
||||
git -C client config remote.lop.url "$TRASH_DIRECTORY_URL/lop" &&
|
||||
git -C client config remote.server.url "$TRASH_DIRECTORY_URL/server" &&
|
||||
git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" &&
|
||||
git -C client config promisor.acceptfromserver All &&
|
||||
GIT_NO_LAZY_FETCH=0 git -C client fetch --filter="blob:limit=5k" server &&
|
||||
|
|
@ -166,6 +191,75 @@ test_expect_success "init + fetch with promisor.advertise set to 'true'" '
|
|||
check_missing_objects server 1 "$oid"
|
||||
'
|
||||
|
||||
test_expect_success "clone with two promisors but only one advertised" '
|
||||
git -C server config promisor.advertise true &&
|
||||
test_when_finished "rm -rf client unused_lop" &&
|
||||
|
||||
# Create a promisor that will be configured but not be used
|
||||
git init --bare unused_lop &&
|
||||
|
||||
# Clone from server to create a client
|
||||
GIT_TRACE="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
|
||||
-c remote.unused_lop.promisor=true \
|
||||
-c remote.unused_lop.fetch="+refs/heads/*:refs/remotes/unused_lop/*" \
|
||||
-c remote.unused_lop.url="$TRASH_DIRECTORY_URL/unused_lop" \
|
||||
-c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
# Check that "unused_lop" appears before "lop" in the config
|
||||
printf "remote.%s.promisor true\n" "unused_lop" "lop" "origin" >expect &&
|
||||
git -C client config get --all --show-names --regexp "^remote\..*\.promisor$" >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
# Check that "lop" was tried
|
||||
test_grep " fetch lop " trace &&
|
||||
# Check that "unused_lop" was not contacted
|
||||
# This means "lop", the accepted promisor, was tried first
|
||||
test_grep ! " fetch unused_lop " trace &&
|
||||
|
||||
# Check that the largest object is still missing on the server
|
||||
check_missing_objects server 1 "$oid"
|
||||
'
|
||||
|
||||
test_expect_success "init + fetch two promisors but only one advertised" '
|
||||
git -C server config promisor.advertise true &&
|
||||
test_when_finished "rm -rf client unused_lop" &&
|
||||
|
||||
# Create a promisor that will be configured but not be used
|
||||
git init --bare unused_lop &&
|
||||
|
||||
mkdir client &&
|
||||
git -C client init &&
|
||||
git -C client config remote.unused_lop.promisor true &&
|
||||
git -C client config remote.unused_lop.fetch "+refs/heads/*:refs/remotes/unused_lop/*" &&
|
||||
git -C client config remote.unused_lop.url "$TRASH_DIRECTORY_URL/unused_lop" &&
|
||||
git -C client config remote.lop.promisor true &&
|
||||
git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" &&
|
||||
git -C client config remote.lop.url "$TRASH_DIRECTORY_URL/lop" &&
|
||||
git -C client config remote.server.url "$TRASH_DIRECTORY_URL/server" &&
|
||||
git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" &&
|
||||
git -C client config promisor.acceptfromserver All &&
|
||||
|
||||
# Check that "unused_lop" appears before "lop" in the config
|
||||
printf "remote.%s.promisor true\n" "unused_lop" "lop" >expect &&
|
||||
git -C client config get --all --show-names --regexp "^remote\..*\.promisor$" >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
GIT_TRACE="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git -C client fetch --filter="blob:limit=5k" server &&
|
||||
|
||||
# Check that "lop" was tried
|
||||
test_grep " fetch lop " trace &&
|
||||
# Check that "unused_lop" was not contacted
|
||||
# This means "lop", the accepted promisor, was tried first
|
||||
test_grep ! " fetch unused_lop " trace &&
|
||||
|
||||
# Check that the largest object is still missing on the server
|
||||
check_missing_objects server 1 "$oid"
|
||||
'
|
||||
|
||||
test_expect_success "clone with promisor.acceptfromserver set to 'KnownName'" '
|
||||
git -C server config promisor.advertise true &&
|
||||
test_when_finished "rm -rf client" &&
|
||||
|
|
@ -173,7 +267,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'KnownName'" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=KnownName \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -188,7 +282,7 @@ test_expect_success "clone with 'KnownName' and different remote names" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.serverTwo.promisor=true \
|
||||
-c remote.serverTwo.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.serverTwo.url="file://$(pwd)/lop" \
|
||||
-c remote.serverTwo.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=KnownName \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -225,7 +319,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'KnownUrl'" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=KnownUrl \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -242,7 +336,7 @@ test_expect_success "clone with 'KnownUrl' and different remote urls" '
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/serverTwo" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/serverTwo" \
|
||||
-c promisor.acceptfromserver=KnownUrl \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -257,7 +351,7 @@ test_expect_success "clone with 'KnownUrl' and url not configured on the server"
|
|||
git -C server config promisor.advertise true &&
|
||||
test_when_finished "rm -rf client" &&
|
||||
|
||||
test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" &&
|
||||
test_when_finished "git -C server config set remote.lop.url \"$TRASH_DIRECTORY_URL/lop\"" &&
|
||||
git -C server config unset remote.lop.url &&
|
||||
|
||||
# Clone from server to create a client
|
||||
|
|
@ -266,7 +360,7 @@ test_expect_success "clone with 'KnownUrl' and url not configured on the server"
|
|||
# missing, so the remote name will be used instead which will fail.
|
||||
test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=KnownUrl \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -278,7 +372,7 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" '
|
|||
git -C server config promisor.advertise true &&
|
||||
test_when_finished "rm -rf client" &&
|
||||
|
||||
test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" &&
|
||||
test_when_finished "git -C server config set remote.lop.url \"$TRASH_DIRECTORY_URL/lop\"" &&
|
||||
git -C server config set remote.lop.url "" &&
|
||||
|
||||
# Clone from server to create a client
|
||||
|
|
@ -287,7 +381,7 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" '
|
|||
# so the remote name will be used instead which will fail.
|
||||
test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=KnownUrl \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
@ -311,13 +405,12 @@ test_expect_success "clone with promisor.sendFields" '
|
|||
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
|
||||
-c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
# Check that fields are properly transmitted
|
||||
ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") &&
|
||||
PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" &&
|
||||
PR1="name=lop,url=$ENCODED_TRASH_DIRECTORY_URL/lop,partialCloneFilter=blob:none" &&
|
||||
PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" &&
|
||||
test_grep "clone< promisor-remote=$PR1;$PR2" trace &&
|
||||
test_grep "clone> promisor-remote=lop;otherLop" trace &&
|
||||
|
|
@ -342,15 +435,14 @@ test_expect_success "clone with promisor.checkFields" '
|
|||
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
|
||||
-c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c remote.lop.partialCloneFilter="blob:none" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
-c promisor.checkFields=partialcloneFilter \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
# Check that fields are properly transmitted
|
||||
ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") &&
|
||||
PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" &&
|
||||
PR1="name=lop,url=$ENCODED_TRASH_DIRECTORY_URL/lop,partialCloneFilter=blob:none" &&
|
||||
PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" &&
|
||||
test_grep "clone< promisor-remote=$PR1;$PR2" trace &&
|
||||
test_grep "clone> promisor-remote=lop" trace &&
|
||||
|
|
@ -380,7 +472,7 @@ test_expect_success "clone with promisor.storeFields=partialCloneFilter" '
|
|||
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
|
||||
-c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c remote.lop.token="fooYYY" \
|
||||
-c remote.lop.partialCloneFilter="blob:none" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
|
|
@ -432,7 +524,7 @@ test_expect_success "clone and fetch with --filter=auto" '
|
|||
|
||||
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
|
||||
-c remote.lop.promisor=true \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter=auto server client 2>err &&
|
||||
|
||||
|
|
@ -489,7 +581,7 @@ test_expect_success "clone with promisor.advertise set to 'true' but don't delet
|
|||
# Clone from server to create a client
|
||||
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
|
||||
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
|
||||
-c remote.lop.url="file://$(pwd)/lop" \
|
||||
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
|
||||
-c promisor.acceptfromserver=All \
|
||||
--no-local --filter="blob:limit=5k" server client &&
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue