]> asedeno.scripts.mit.edu Git - git.git/blob - remote.c
Move remote parsing into a library file out of builtin-push.
[git.git] / remote.c
1 #include "cache.h"
2 #include "remote.h"
3 #include "refs.h"
4
5 static struct remote **remotes;
6 static int allocated_remotes;
7
8 #define BUF_SIZE (2048)
9 static char buffer[BUF_SIZE];
10
11 static 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
20 static 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
29 static 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
61 static 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
101 static 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
132 static char *default_remote_name = NULL;
133 static const char *current_branch = NULL;
134 static int current_branch_len = 0;
135
136 static 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
186 static 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
204 struct 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 }