763d98aedd85d69fc393b172ccfd8e4d8c0d75dd
   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 int promisor_remote_config(const char *var, const char *value, void *data)
  44{
  45        const char *name;
  46        int namelen;
  47        const char *subkey;
  48
  49        if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
  50                return 0;
  51
  52        if (!strcmp(subkey, "promisor")) {
  53                char *remote_name;
  54
  55                if (!git_config_bool(var, value))
  56                        return 0;
  57
  58                remote_name = xmemdupz(name, namelen);
  59
  60                if (!promisor_remote_lookup(remote_name, NULL))
  61                        promisor_remote_new(remote_name);
  62
  63                free(remote_name);
  64                return 0;
  65        }
  66
  67        return 0;
  68}
  69
  70static int initialized;
  71
  72static void promisor_remote_init(void)
  73{
  74        if (initialized)
  75                return;
  76        initialized = 1;
  77
  78        git_config(promisor_remote_config, NULL);
  79}
  80
  81static void promisor_remote_clear(void)
  82{
  83        while (promisors) {
  84                struct promisor_remote *r = promisors;
  85                promisors = promisors->next;
  86                free(r);
  87        }
  88
  89        promisors_tail = &promisors;
  90}
  91
  92void promisor_remote_reinit(void)
  93{
  94        initialized = 0;
  95        promisor_remote_clear();
  96        promisor_remote_init();
  97}
  98
  99struct promisor_remote *promisor_remote_find(const char *remote_name)
 100{
 101        promisor_remote_init();
 102
 103        if (!remote_name)
 104                return promisors;
 105
 106        return promisor_remote_lookup(remote_name, NULL);
 107}
 108
 109int has_promisor_remote(void)
 110{
 111        return !!promisor_remote_find(NULL);
 112}
 113
 114static int remove_fetched_oids(struct repository *repo,
 115                               struct object_id **oids,
 116                               int oid_nr, int to_free)
 117{
 118        int i, remaining_nr = 0;
 119        int *remaining = xcalloc(oid_nr, sizeof(*remaining));
 120        struct object_id *old_oids = *oids;
 121        struct object_id *new_oids;
 122
 123        for (i = 0; i < oid_nr; i++)
 124                if (oid_object_info_extended(repo, &old_oids[i], NULL,
 125                                             OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 126                        remaining[i] = 1;
 127                        remaining_nr++;
 128                }
 129
 130        if (remaining_nr) {
 131                int j = 0;
 132                new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
 133                for (i = 0; i < oid_nr; i++)
 134                        if (remaining[i])
 135                                oidcpy(&new_oids[j++], &old_oids[i]);
 136                *oids = new_oids;
 137                if (to_free)
 138                        free(old_oids);
 139        }
 140
 141        free(remaining);
 142
 143        return remaining_nr;
 144}
 145
 146int promisor_remote_get_direct(struct repository *repo,
 147                               const struct object_id *oids,
 148                               int oid_nr)
 149{
 150        struct promisor_remote *r;
 151        struct object_id *remaining_oids = (struct object_id *)oids;
 152        int remaining_nr = oid_nr;
 153        int to_free = 0;
 154        int res = -1;
 155
 156        promisor_remote_init();
 157
 158        for (r = promisors; r; r = r->next) {
 159                if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
 160                        if (remaining_nr == 1)
 161                                continue;
 162                        remaining_nr = remove_fetched_oids(repo, &remaining_oids,
 163                                                         remaining_nr, to_free);
 164                        if (remaining_nr) {
 165                                to_free = 1;
 166                                continue;
 167                        }
 168                }
 169                res = 0;
 170                break;
 171        }
 172
 173        if (to_free)
 174                free(remaining_oids);
 175
 176        return res;
 177}