6a8856f475502d806456d3cf8186495f0e58f733
   1#include "cache.h"
   2#include "object-store.h"
   3#include "promisor-remote.h"
   4#include "config.h"
   5#include "fetch-object.h"
   6
   7static struct promisor_remote *promisors;
   8static struct promisor_remote **promisors_tail = &promisors;
   9
  10static struct promisor_remote *promisor_remote_new(const char *remote_name)
  11{
  12        struct promisor_remote *r;
  13
  14        if (*remote_name == '/') {
  15                warning(_("promisor remote name cannot begin with '/': %s"),
  16                        remote_name);
  17                return NULL;
  18        }
  19
  20        FLEX_ALLOC_STR(r, name, remote_name);
  21
  22        *promisors_tail = r;
  23        promisors_tail = &r->next;
  24
  25        return r;
  26}
  27
  28static struct promisor_remote *promisor_remote_lookup(const char *remote_name,
  29                                                      struct promisor_remote **previous)
  30{
  31        struct promisor_remote *r, *p;
  32
  33        for (p = NULL, r = promisors; r; p = r, r = r->next)
  34                if (!strcmp(r->name, remote_name)) {
  35                        if (previous)
  36                                *previous = p;
  37                        return r;
  38                }
  39
  40        return NULL;
  41}
  42
  43static void promisor_remote_move_to_tail(struct promisor_remote *r,
  44                                         struct promisor_remote *previous)
  45{
  46        if (previous)
  47                previous->next = r->next;
  48        else
  49                promisors = r->next ? r->next : r;
  50        r->next = NULL;
  51        *promisors_tail = r;
  52        promisors_tail = &r->next;
  53}
  54
  55static int promisor_remote_config(const char *var, const char *value, void *data)
  56{
  57        const char *name;
  58        int namelen;
  59        const char *subkey;
  60
  61        if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
  62                return 0;
  63
  64        if (!strcmp(subkey, "promisor")) {
  65                char *remote_name;
  66
  67                if (!git_config_bool(var, value))
  68                        return 0;
  69
  70                remote_name = xmemdupz(name, namelen);
  71
  72                if (!promisor_remote_lookup(remote_name, NULL))
  73                        promisor_remote_new(remote_name);
  74
  75                free(remote_name);
  76                return 0;
  77        }
  78
  79        return 0;
  80}
  81
  82static int initialized;
  83
  84static void promisor_remote_init(void)
  85{
  86        if (initialized)
  87                return;
  88        initialized = 1;
  89
  90        git_config(promisor_remote_config, NULL);
  91
  92        if (repository_format_partial_clone) {
  93                struct promisor_remote *o, *previous;
  94
  95                o = promisor_remote_lookup(repository_format_partial_clone,
  96                                           &previous);
  97                if (o)
  98                        promisor_remote_move_to_tail(o, previous);
  99                else
 100                        promisor_remote_new(repository_format_partial_clone);
 101        }
 102}
 103
 104static void promisor_remote_clear(void)
 105{
 106        while (promisors) {
 107                struct promisor_remote *r = promisors;
 108                promisors = promisors->next;
 109                free(r);
 110        }
 111
 112        promisors_tail = &promisors;
 113}
 114
 115void promisor_remote_reinit(void)
 116{
 117        initialized = 0;
 118        promisor_remote_clear();
 119        promisor_remote_init();
 120}
 121
 122struct promisor_remote *promisor_remote_find(const char *remote_name)
 123{
 124        promisor_remote_init();
 125
 126        if (!remote_name)
 127                return promisors;
 128
 129        return promisor_remote_lookup(remote_name, NULL);
 130}
 131
 132int has_promisor_remote(void)
 133{
 134        return !!promisor_remote_find(NULL);
 135}
 136
 137static int remove_fetched_oids(struct repository *repo,
 138                               struct object_id **oids,
 139                               int oid_nr, int to_free)
 140{
 141        int i, remaining_nr = 0;
 142        int *remaining = xcalloc(oid_nr, sizeof(*remaining));
 143        struct object_id *old_oids = *oids;
 144        struct object_id *new_oids;
 145
 146        for (i = 0; i < oid_nr; i++)
 147                if (oid_object_info_extended(repo, &old_oids[i], NULL,
 148                                             OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 149                        remaining[i] = 1;
 150                        remaining_nr++;
 151                }
 152
 153        if (remaining_nr) {
 154                int j = 0;
 155                new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
 156                for (i = 0; i < oid_nr; i++)
 157                        if (remaining[i])
 158                                oidcpy(&new_oids[j++], &old_oids[i]);
 159                *oids = new_oids;
 160                if (to_free)
 161                        free(old_oids);
 162        }
 163
 164        free(remaining);
 165
 166        return remaining_nr;
 167}
 168
 169int promisor_remote_get_direct(struct repository *repo,
 170                               const struct object_id *oids,
 171                               int oid_nr)
 172{
 173        struct promisor_remote *r;
 174        struct object_id *remaining_oids = (struct object_id *)oids;
 175        int remaining_nr = oid_nr;
 176        int to_free = 0;
 177        int res = -1;
 178
 179        promisor_remote_init();
 180
 181        for (r = promisors; r; r = r->next) {
 182                if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
 183                        if (remaining_nr == 1)
 184                                continue;
 185                        remaining_nr = remove_fetched_oids(repo, &remaining_oids,
 186                                                         remaining_nr, to_free);
 187                        if (remaining_nr) {
 188                                to_free = 1;
 189                                continue;
 190                        }
 191                }
 192                res = 0;
 193                break;
 194        }
 195
 196        if (to_free)
 197                free(remaining_oids);
 198
 199        return res;
 200}