92c4c12c1cadbed537edc3f4fc6105676c271cca
   1#include "cache.h"
   2#include "object-store.h"
   3#include "promisor-remote.h"
   4#include "config.h"
   5#include "transport.h"
   6
   7static int fetch_refs(const char *remote_name, struct ref *ref)
   8{
   9        struct remote *remote;
  10        struct transport *transport;
  11        int original_fetch_if_missing = fetch_if_missing;
  12        int res;
  13
  14        fetch_if_missing = 0;
  15        remote = remote_get(remote_name);
  16        if (!remote->url[0])
  17                die(_("Remote with no URL"));
  18        transport = transport_get(remote, remote->url[0]);
  19
  20        transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
  21        transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
  22        res = transport_fetch_refs(transport, ref);
  23        fetch_if_missing = original_fetch_if_missing;
  24
  25        return res;
  26}
  27
  28static int fetch_objects(const char *remote_name,
  29                         const struct object_id *oids,
  30                         int oid_nr)
  31{
  32        struct ref *ref = NULL;
  33        int i;
  34
  35        for (i = 0; i < oid_nr; i++) {
  36                struct ref *new_ref = alloc_ref(oid_to_hex(&oids[i]));
  37                oidcpy(&new_ref->old_oid, &oids[i]);
  38                new_ref->exact_oid = 1;
  39                new_ref->next = ref;
  40                ref = new_ref;
  41        }
  42        return fetch_refs(remote_name, ref);
  43}
  44
  45static struct promisor_remote *promisors;
  46static struct promisor_remote **promisors_tail = &promisors;
  47
  48static struct promisor_remote *promisor_remote_new(const char *remote_name)
  49{
  50        struct promisor_remote *r;
  51
  52        if (*remote_name == '/') {
  53                warning(_("promisor remote name cannot begin with '/': %s"),
  54                        remote_name);
  55                return NULL;
  56        }
  57
  58        FLEX_ALLOC_STR(r, name, remote_name);
  59
  60        *promisors_tail = r;
  61        promisors_tail = &r->next;
  62
  63        return r;
  64}
  65
  66static struct promisor_remote *promisor_remote_lookup(const char *remote_name,
  67                                                      struct promisor_remote **previous)
  68{
  69        struct promisor_remote *r, *p;
  70
  71        for (p = NULL, r = promisors; r; p = r, r = r->next)
  72                if (!strcmp(r->name, remote_name)) {
  73                        if (previous)
  74                                *previous = p;
  75                        return r;
  76                }
  77
  78        return NULL;
  79}
  80
  81static void promisor_remote_move_to_tail(struct promisor_remote *r,
  82                                         struct promisor_remote *previous)
  83{
  84        if (previous)
  85                previous->next = r->next;
  86        else
  87                promisors = r->next ? r->next : r;
  88        r->next = NULL;
  89        *promisors_tail = r;
  90        promisors_tail = &r->next;
  91}
  92
  93static int promisor_remote_config(const char *var, const char *value, void *data)
  94{
  95        const char *name;
  96        int namelen;
  97        const char *subkey;
  98
  99        if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
 100                return 0;
 101
 102        if (!strcmp(subkey, "promisor")) {
 103                char *remote_name;
 104
 105                if (!git_config_bool(var, value))
 106                        return 0;
 107
 108                remote_name = xmemdupz(name, namelen);
 109
 110                if (!promisor_remote_lookup(remote_name, NULL))
 111                        promisor_remote_new(remote_name);
 112
 113                free(remote_name);
 114                return 0;
 115        }
 116        if (!strcmp(subkey, "partialclonefilter")) {
 117                struct promisor_remote *r;
 118                char *remote_name = xmemdupz(name, namelen);
 119
 120                r = promisor_remote_lookup(remote_name, NULL);
 121                if (!r)
 122                        r = promisor_remote_new(remote_name);
 123
 124                free(remote_name);
 125
 126                if (!r)
 127                        return 0;
 128
 129                return git_config_string(&r->partial_clone_filter, var, value);
 130        }
 131
 132        return 0;
 133}
 134
 135static int initialized;
 136
 137static void promisor_remote_init(void)
 138{
 139        if (initialized)
 140                return;
 141        initialized = 1;
 142
 143        git_config(promisor_remote_config, NULL);
 144
 145        if (repository_format_partial_clone) {
 146                struct promisor_remote *o, *previous;
 147
 148                o = promisor_remote_lookup(repository_format_partial_clone,
 149                                           &previous);
 150                if (o)
 151                        promisor_remote_move_to_tail(o, previous);
 152                else
 153                        promisor_remote_new(repository_format_partial_clone);
 154        }
 155}
 156
 157static void promisor_remote_clear(void)
 158{
 159        while (promisors) {
 160                struct promisor_remote *r = promisors;
 161                promisors = promisors->next;
 162                free(r);
 163        }
 164
 165        promisors_tail = &promisors;
 166}
 167
 168void promisor_remote_reinit(void)
 169{
 170        initialized = 0;
 171        promisor_remote_clear();
 172        promisor_remote_init();
 173}
 174
 175struct promisor_remote *promisor_remote_find(const char *remote_name)
 176{
 177        promisor_remote_init();
 178
 179        if (!remote_name)
 180                return promisors;
 181
 182        return promisor_remote_lookup(remote_name, NULL);
 183}
 184
 185int has_promisor_remote(void)
 186{
 187        return !!promisor_remote_find(NULL);
 188}
 189
 190static int remove_fetched_oids(struct repository *repo,
 191                               struct object_id **oids,
 192                               int oid_nr, int to_free)
 193{
 194        int i, remaining_nr = 0;
 195        int *remaining = xcalloc(oid_nr, sizeof(*remaining));
 196        struct object_id *old_oids = *oids;
 197        struct object_id *new_oids;
 198
 199        for (i = 0; i < oid_nr; i++)
 200                if (oid_object_info_extended(repo, &old_oids[i], NULL,
 201                                             OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 202                        remaining[i] = 1;
 203                        remaining_nr++;
 204                }
 205
 206        if (remaining_nr) {
 207                int j = 0;
 208                new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
 209                for (i = 0; i < oid_nr; i++)
 210                        if (remaining[i])
 211                                oidcpy(&new_oids[j++], &old_oids[i]);
 212                *oids = new_oids;
 213                if (to_free)
 214                        free(old_oids);
 215        }
 216
 217        free(remaining);
 218
 219        return remaining_nr;
 220}
 221
 222int promisor_remote_get_direct(struct repository *repo,
 223                               const struct object_id *oids,
 224                               int oid_nr)
 225{
 226        struct promisor_remote *r;
 227        struct object_id *remaining_oids = (struct object_id *)oids;
 228        int remaining_nr = oid_nr;
 229        int to_free = 0;
 230        int res = -1;
 231
 232        promisor_remote_init();
 233
 234        for (r = promisors; r; r = r->next) {
 235                if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
 236                        if (remaining_nr == 1)
 237                                continue;
 238                        remaining_nr = remove_fetched_oids(repo, &remaining_oids,
 239                                                         remaining_nr, to_free);
 240                        if (remaining_nr) {
 241                                to_free = 1;
 242                                continue;
 243                        }
 244                }
 245                res = 0;
 246                break;
 247        }
 248
 249        if (to_free)
 250                free(remaining_oids);
 251
 252        return res;
 253}