b032e81ac811e974ad6ff7fcd644922086499021
   1#include "cache.h"
   2#include "remote.h"
   3#include "refs.h"
   4
   5static struct remote **remotes;
   6static int allocated_remotes;
   7
   8#define BUF_SIZE (2048)
   9static char buffer[BUF_SIZE];
  10
  11static void add_push_refspec(struct remote *remote, const char *ref)
  12{
  13        int nr = remote->push_refspec_nr + 1;
  14        remote->push_refspec =
  15                xrealloc(remote->push_refspec, nr * sizeof(char *));
  16        remote->push_refspec[nr-1] = ref;
  17        remote->push_refspec_nr = nr;
  18}
  19
  20static void add_uri(struct remote *remote, const char *uri)
  21{
  22        int nr = remote->uri_nr + 1;
  23        remote->uri =
  24                xrealloc(remote->uri, nr * sizeof(char *));
  25        remote->uri[nr-1] = uri;
  26        remote->uri_nr = nr;
  27}
  28
  29static struct remote *make_remote(const char *name, int len)
  30{
  31        int i, empty = -1;
  32
  33        for (i = 0; i < allocated_remotes; i++) {
  34                if (!remotes[i]) {
  35                        if (empty < 0)
  36                                empty = i;
  37                } else {
  38                        if (len ? (!strncmp(name, remotes[i]->name, len) &&
  39                                   !remotes[i]->name[len]) :
  40                            !strcmp(name, remotes[i]->name))
  41                                return remotes[i];
  42                }
  43        }
  44
  45        if (empty < 0) {
  46                empty = allocated_remotes;
  47                allocated_remotes += allocated_remotes ? allocated_remotes : 1;
  48                remotes = xrealloc(remotes,
  49                                   sizeof(*remotes) * allocated_remotes);
  50                memset(remotes + empty, 0,
  51                       (allocated_remotes - empty) * sizeof(*remotes));
  52        }
  53        remotes[empty] = xcalloc(1, sizeof(struct remote));
  54        if (len)
  55                remotes[empty]->name = xstrndup(name, len);
  56        else
  57                remotes[empty]->name = xstrdup(name);
  58        return remotes[empty];
  59}
  60
  61static void read_remotes_file(struct remote *remote)
  62{
  63        FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
  64
  65        if (!f)
  66                return;
  67        while (fgets(buffer, BUF_SIZE, f)) {
  68                int value_list;
  69                char *s, *p;
  70
  71                if (!prefixcmp(buffer, "URL:")) {
  72                        value_list = 0;
  73                        s = buffer + 4;
  74                } else if (!prefixcmp(buffer, "Push:")) {
  75                        value_list = 1;
  76                        s = buffer + 5;
  77                } else
  78                        continue;
  79
  80                while (isspace(*s))
  81                        s++;
  82                if (!*s)
  83                        continue;
  84
  85                p = s + strlen(s);
  86                while (isspace(p[-1]))
  87                        *--p = 0;
  88
  89                switch (value_list) {
  90                case 0:
  91                        add_uri(remote, xstrdup(s));
  92                        break;
  93                case 1:
  94                        add_push_refspec(remote, xstrdup(s));
  95                        break;
  96                }
  97        }
  98        fclose(f);
  99}
 100
 101static void read_branches_file(struct remote *remote)
 102{
 103        const char *slash = strchr(remote->name, '/');
 104        int n = slash ? slash - remote->name : 1000;
 105        FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
 106        char *s, *p;
 107        int len;
 108
 109        if (!f)
 110                return;
 111        s = fgets(buffer, BUF_SIZE, f);
 112        fclose(f);
 113        if (!s)
 114                return;
 115        while (isspace(*s))
 116                s++;
 117        if (!*s)
 118                return;
 119        p = s + strlen(s);
 120        while (isspace(p[-1]))
 121                *--p = 0;
 122        len = p - s;
 123        if (slash)
 124                len += strlen(slash);
 125        p = xmalloc(len + 1);
 126        strcpy(p, s);
 127        if (slash)
 128                strcat(p, slash);
 129        add_uri(remote, p);
 130}
 131
 132static char *default_remote_name = NULL;
 133static const char *current_branch = NULL;
 134static int current_branch_len = 0;
 135
 136static int handle_config(const char *key, const char *value)
 137{
 138        const char *name;
 139        const char *subkey;
 140        struct remote *remote;
 141        if (!prefixcmp(key, "branch.") && current_branch &&
 142            !strncmp(key + 7, current_branch, current_branch_len) &&
 143            !strcmp(key + 7 + current_branch_len, ".remote")) {
 144                free(default_remote_name);
 145                default_remote_name = xstrdup(value);
 146        }
 147        if (prefixcmp(key,  "remote."))
 148                return 0;
 149        name = key + 7;
 150        subkey = strrchr(name, '.');
 151        if (!subkey)
 152                return error("Config with no key for remote %s", name);
 153        if (*subkey == '/') {
 154                warning("Config remote shorthand cannot begin with '/': %s", name);
 155                return 0;
 156        }
 157        remote = make_remote(name, subkey - name);
 158        if (!value) {
 159                /* if we ever have a boolean variable, e.g. "remote.*.disabled"
 160                 * [remote "frotz"]
 161                 *      disabled
 162                 * is a valid way to set it to true; we get NULL in value so
 163                 * we need to handle it here.
 164                 *
 165                 * if (!strcmp(subkey, ".disabled")) {
 166                 *      val = git_config_bool(key, value);
 167                 *      return 0;
 168                 * } else
 169                 *
 170                 */
 171                return 0; /* ignore unknown booleans */
 172        }
 173        if (!strcmp(subkey, ".url")) {
 174                add_uri(remote, xstrdup(value));
 175        } else if (!strcmp(subkey, ".push")) {
 176                add_push_refspec(remote, xstrdup(value));
 177        } else if (!strcmp(subkey, ".receivepack")) {
 178                if (!remote->receivepack)
 179                        remote->receivepack = xstrdup(value);
 180                else
 181                        error("more than one receivepack given, using the first");
 182        }
 183        return 0;
 184}
 185
 186static void read_config(void)
 187{
 188        unsigned char sha1[20];
 189        const char *head_ref;
 190        int flag;
 191        if (default_remote_name) // did this already
 192                return;
 193        default_remote_name = xstrdup("origin");
 194        current_branch = NULL;
 195        head_ref = resolve_ref("HEAD", sha1, 0, &flag);
 196        if (head_ref && (flag & REF_ISSYMREF) &&
 197            !prefixcmp(head_ref, "refs/heads/")) {
 198                current_branch = head_ref + strlen("refs/heads/");
 199                current_branch_len = strlen(current_branch);
 200        }
 201        git_config(handle_config);
 202}
 203
 204struct remote *remote_get(const char *name)
 205{
 206        struct remote *ret;
 207
 208        read_config();
 209        if (!name)
 210                name = default_remote_name;
 211        ret = make_remote(name, 0);
 212        if (name[0] != '/') {
 213                if (!ret->uri)
 214                        read_remotes_file(ret);
 215                if (!ret->uri)
 216                        read_branches_file(ret);
 217        }
 218        if (!ret->uri)
 219                add_uri(ret, name);
 220        if (!ret->uri)
 221                return NULL;
 222        return ret;
 223}