b79a84ce3a5c0f46a0c1bbe82ba96514d18dbd63
   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 void promisor_remote_init(void)
  71{
  72        static int initialized;
  73
  74        if (initialized)
  75                return;
  76        initialized = 1;
  77
  78        git_config(promisor_remote_config, NULL);
  79}
  80
  81struct promisor_remote *promisor_remote_find(const char *remote_name)
  82{
  83        promisor_remote_init();
  84
  85        if (!remote_name)
  86                return promisors;
  87
  88        return promisor_remote_lookup(remote_name, NULL);
  89}
  90
  91int has_promisor_remote(void)
  92{
  93        return !!promisor_remote_find(NULL);
  94}
  95
  96static int remove_fetched_oids(struct repository *repo,
  97                               struct object_id **oids,
  98                               int oid_nr, int to_free)
  99{
 100        int i, remaining_nr = 0;
 101        int *remaining = xcalloc(oid_nr, sizeof(*remaining));
 102        struct object_id *old_oids = *oids;
 103        struct object_id *new_oids;
 104
 105        for (i = 0; i < oid_nr; i++)
 106                if (oid_object_info_extended(repo, &old_oids[i], NULL,
 107                                             OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 108                        remaining[i] = 1;
 109                        remaining_nr++;
 110                }
 111
 112        if (remaining_nr) {
 113                int j = 0;
 114                new_oids = xcalloc(remaining_nr, sizeof(*new_oids));
 115                for (i = 0; i < oid_nr; i++)
 116                        if (remaining[i])
 117                                oidcpy(&new_oids[j++], &old_oids[i]);
 118                *oids = new_oids;
 119                if (to_free)
 120                        free(old_oids);
 121        }
 122
 123        free(remaining);
 124
 125        return remaining_nr;
 126}
 127
 128int promisor_remote_get_direct(struct repository *repo,
 129                               const struct object_id *oids,
 130                               int oid_nr)
 131{
 132        struct promisor_remote *r;
 133        struct object_id *remaining_oids = (struct object_id *)oids;
 134        int remaining_nr = oid_nr;
 135        int to_free = 0;
 136        int res = -1;
 137
 138        promisor_remote_init();
 139
 140        for (r = promisors; r; r = r->next) {
 141                if (fetch_objects(r->name, remaining_oids, remaining_nr) < 0) {
 142                        if (remaining_nr == 1)
 143                                continue;
 144                        remaining_nr = remove_fetched_oids(repo, &remaining_oids,
 145                                                         remaining_nr, to_free);
 146                        if (remaining_nr) {
 147                                to_free = 1;
 148                                continue;
 149                        }
 150                }
 151                res = 0;
 152                break;
 153        }
 154
 155        if (to_free)
 156                free(remaining_oids);
 157
 158        return res;
 159}