git
/
promisor-remote.c
292 строки · 7.0 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "gettext.h"5#include "hex.h"6#include "object-store-ll.h"7#include "promisor-remote.h"8#include "config.h"9#include "trace2.h"10#include "transport.h"11#include "strvec.h"12#include "packfile.h"13#include "environment.h"14
15struct promisor_remote_config {16struct promisor_remote *promisors;17struct promisor_remote **promisors_tail;18};19
20static int fetch_objects(struct repository *repo,21const char *remote_name,22const struct object_id *oids,23int oid_nr)24{
25struct child_process child = CHILD_PROCESS_INIT;26int i;27FILE *child_in;28int quiet;29
30if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0)) {31static int warning_shown;32if (!warning_shown) {33warning_shown = 1;34warning(_("lazy fetching disabled; some objects may not be available"));35}36return -1;37}38
39child.git_cmd = 1;40child.in = -1;41if (repo != the_repository)42prepare_other_repo_env(&child.env, repo->gitdir);43strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",44"fetch", remote_name, "--no-tags",45"--no-write-fetch-head", "--recurse-submodules=no",46"--filter=blob:none", "--stdin", NULL);47if (!git_config_get_bool("promisor.quiet", &quiet) && quiet)48strvec_push(&child.args, "--quiet");49if (start_command(&child))50die(_("promisor-remote: unable to fork off fetch subprocess"));51child_in = xfdopen(child.in, "w");52
53trace2_data_intmax("promisor", repo, "fetch_count", oid_nr);54
55for (i = 0; i < oid_nr; i++) {56if (fputs(oid_to_hex(&oids[i]), child_in) < 0)57die_errno(_("promisor-remote: could not write to fetch subprocess"));58if (fputc('\n', child_in) < 0)59die_errno(_("promisor-remote: could not write to fetch subprocess"));60}61
62if (fclose(child_in) < 0)63die_errno(_("promisor-remote: could not close stdin to fetch subprocess"));64return finish_command(&child) ? -1 : 0;65}
66
67static struct promisor_remote *promisor_remote_new(struct promisor_remote_config *config,68const char *remote_name)69{
70struct promisor_remote *r;71
72if (*remote_name == '/') {73warning(_("promisor remote name cannot begin with '/': %s"),74remote_name);75return NULL;76}77
78FLEX_ALLOC_STR(r, name, remote_name);79
80*config->promisors_tail = r;81config->promisors_tail = &r->next;82
83return r;84}
85
86static struct promisor_remote *promisor_remote_lookup(struct promisor_remote_config *config,87const char *remote_name,88struct promisor_remote **previous)89{
90struct promisor_remote *r, *p;91
92for (p = NULL, r = config->promisors; r; p = r, r = r->next)93if (!strcmp(r->name, remote_name)) {94if (previous)95*previous = p;96return r;97}98
99return NULL;100}
101
102static void promisor_remote_move_to_tail(struct promisor_remote_config *config,103struct promisor_remote *r,104struct promisor_remote *previous)105{
106if (!r->next)107return;108
109if (previous)110previous->next = r->next;111else112config->promisors = r->next ? r->next : r;113r->next = NULL;114*config->promisors_tail = r;115config->promisors_tail = &r->next;116}
117
118static int promisor_remote_config(const char *var, const char *value,119const struct config_context *ctx UNUSED,120void *data)121{
122struct promisor_remote_config *config = data;123const char *name;124size_t namelen;125const char *subkey;126
127if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)128return 0;129
130if (!strcmp(subkey, "promisor")) {131char *remote_name;132
133if (!git_config_bool(var, value))134return 0;135
136remote_name = xmemdupz(name, namelen);137
138if (!promisor_remote_lookup(config, remote_name, NULL))139promisor_remote_new(config, remote_name);140
141free(remote_name);142return 0;143}144if (!strcmp(subkey, "partialclonefilter")) {145struct promisor_remote *r;146char *remote_name = xmemdupz(name, namelen);147
148r = promisor_remote_lookup(config, remote_name, NULL);149if (!r)150r = promisor_remote_new(config, remote_name);151
152free(remote_name);153
154if (!r)155return 0;156
157return git_config_string(&r->partial_clone_filter, var, value);158}159
160return 0;161}
162
163static void promisor_remote_init(struct repository *r)164{
165struct promisor_remote_config *config;166
167if (r->promisor_remote_config)168return;169config = r->promisor_remote_config =170xcalloc(1, sizeof(*r->promisor_remote_config));171config->promisors_tail = &config->promisors;172
173repo_config(r, promisor_remote_config, config);174
175if (r->repository_format_partial_clone) {176struct promisor_remote *o, *previous;177
178o = promisor_remote_lookup(config,179r->repository_format_partial_clone,180&previous);181if (o)182promisor_remote_move_to_tail(config, o, previous);183else184promisor_remote_new(config, r->repository_format_partial_clone);185}186}
187
188void promisor_remote_clear(struct promisor_remote_config *config)189{
190while (config->promisors) {191struct promisor_remote *r = config->promisors;192config->promisors = config->promisors->next;193free(r);194}195
196config->promisors_tail = &config->promisors;197}
198
199void repo_promisor_remote_reinit(struct repository *r)200{
201promisor_remote_clear(r->promisor_remote_config);202FREE_AND_NULL(r->promisor_remote_config);203promisor_remote_init(r);204}
205
206struct promisor_remote *repo_promisor_remote_find(struct repository *r,207const char *remote_name)208{
209promisor_remote_init(r);210
211if (!remote_name)212return r->promisor_remote_config->promisors;213
214return promisor_remote_lookup(r->promisor_remote_config, remote_name, NULL);215}
216
217int repo_has_promisor_remote(struct repository *r)218{
219return !!repo_promisor_remote_find(r, NULL);220}
221
222static int remove_fetched_oids(struct repository *repo,223struct object_id **oids,224int oid_nr, int to_free)225{
226int i, remaining_nr = 0;227int *remaining = xcalloc(oid_nr, sizeof(*remaining));228struct object_id *old_oids = *oids;229struct object_id *new_oids;230
231for (i = 0; i < oid_nr; i++)232if (oid_object_info_extended(repo, &old_oids[i], NULL,233OBJECT_INFO_SKIP_FETCH_OBJECT)) {234remaining[i] = 1;235remaining_nr++;236}237
238if (remaining_nr) {239int j = 0;240CALLOC_ARRAY(new_oids, remaining_nr);241for (i = 0; i < oid_nr; i++)242if (remaining[i])243oidcpy(&new_oids[j++], &old_oids[i]);244*oids = new_oids;245if (to_free)246free(old_oids);247}248
249free(remaining);250
251return remaining_nr;252}
253
254void promisor_remote_get_direct(struct repository *repo,255const struct object_id *oids,256int oid_nr)257{
258struct promisor_remote *r;259struct object_id *remaining_oids = (struct object_id *)oids;260int remaining_nr = oid_nr;261int to_free = 0;262int i;263
264if (oid_nr == 0)265return;266
267promisor_remote_init(repo);268
269for (r = repo->promisor_remote_config->promisors; r; r = r->next) {270if (fetch_objects(repo, r->name, remaining_oids, remaining_nr) < 0) {271if (remaining_nr == 1)272continue;273remaining_nr = remove_fetched_oids(repo, &remaining_oids,274remaining_nr, to_free);275if (remaining_nr) {276to_free = 1;277continue;278}279}280goto all_fetched;281}282
283for (i = 0; i < remaining_nr; i++) {284if (is_promisor_object(&remaining_oids[i]))285die(_("could not fetch %s from promisor remote"),286oid_to_hex(&remaining_oids[i]));287}288
289all_fetched:290if (to_free)291free(remaining_oids);292}
293