]>
Commit | Line | Data |
---|---|---|
9c82357b | 1 | /* |
bb742ede | 2 | * Copyright (C) 2009-2011 the libgit2 contributors |
9c82357b | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
9c82357b CMN |
6 | */ |
7 | ||
8 | #include "git2/remote.h" | |
9 | #include "git2/config.h" | |
10 | #include "git2/types.h" | |
11 | ||
12 | #include "config.h" | |
13 | #include "repository.h" | |
14 | #include "remote.h" | |
e1d88030 | 15 | #include "fetch.h" |
441f57c2 | 16 | #include "refs.h" |
9c82357b CMN |
17 | |
18 | static int refspec_parse(git_refspec *refspec, const char *str) | |
19 | { | |
20 | char *delim; | |
21 | ||
22 | memset(refspec, 0x0, sizeof(git_refspec)); | |
23 | ||
24 | if (*str == '+') { | |
25 | refspec->force = 1; | |
26 | str++; | |
27 | } | |
28 | ||
29 | delim = strchr(str, ':'); | |
30 | if (delim == NULL) | |
31 | return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'"); | |
32 | ||
33 | refspec->src = git__strndup(str, delim - str); | |
34 | if (refspec->src == NULL) | |
35 | return GIT_ENOMEM; | |
36 | ||
37 | refspec->dst = git__strdup(delim + 1); | |
38 | if (refspec->dst == NULL) { | |
3286c408 | 39 | git__free(refspec->src); |
9c82357b CMN |
40 | refspec->src = NULL; |
41 | return GIT_ENOMEM; | |
42 | } | |
43 | ||
44 | return GIT_SUCCESS; | |
45 | } | |
46 | ||
47 | static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var) | |
48 | { | |
49 | const char *val; | |
50 | int error; | |
51 | ||
52 | error = git_config_get_string(cfg, var, &val); | |
53 | if (error < GIT_SUCCESS) | |
54 | return error; | |
55 | ||
2dc31040 | 56 | return refspec_parse(refspec, val); |
9c82357b CMN |
57 | } |
58 | ||
778e1c73 CMN |
59 | int git_remote_new(git_remote **out, git_repository *repo, const char *url) |
60 | { | |
61 | git_remote *remote; | |
62 | ||
63 | remote = git__malloc(sizeof(git_remote)); | |
64 | if (remote == NULL) | |
65 | return GIT_ENOMEM; | |
66 | ||
67 | memset(remote, 0x0, sizeof(git_remote)); | |
68 | remote->repo = repo; | |
69 | remote->url = git__strdup(url); | |
70 | if (remote->url == NULL) { | |
3286c408 | 71 | git__free(remote); |
778e1c73 CMN |
72 | return GIT_ENOMEM; |
73 | } | |
74 | ||
75 | *out = remote; | |
76 | return GIT_SUCCESS; | |
77 | } | |
78 | ||
9c82357b CMN |
79 | int git_remote_get(git_remote **out, git_config *cfg, const char *name) |
80 | { | |
81 | git_remote *remote; | |
82 | char *buf = NULL; | |
83 | const char *val; | |
84 | int ret, error, buf_len; | |
85 | ||
86 | remote = git__malloc(sizeof(git_remote)); | |
87 | if (remote == NULL) | |
88 | return GIT_ENOMEM; | |
89 | ||
90 | memset(remote, 0x0, sizeof(git_remote)); | |
91 | remote->name = git__strdup(name); | |
92 | if (remote->name == NULL) { | |
93 | error = GIT_ENOMEM; | |
94 | goto cleanup; | |
95 | } | |
96 | ||
97 | /* "fetch" is the longest var name we're interested in */ | |
932669b8 | 98 | buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1; |
9c82357b CMN |
99 | buf = git__malloc(buf_len); |
100 | if (buf == NULL) { | |
101 | error = GIT_ENOMEM; | |
102 | goto cleanup; | |
103 | } | |
104 | ||
84dd3820 | 105 | ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "url"); |
9c82357b CMN |
106 | if (ret < 0) { |
107 | error = git__throw(GIT_EOSERR, "Failed to build config var name"); | |
108 | goto cleanup; | |
109 | } | |
110 | ||
111 | error = git_config_get_string(cfg, buf, &val); | |
112 | if (error < GIT_SUCCESS) { | |
87d9869f | 113 | error = git__rethrow(error, "Remote's url doesn't exist"); |
9c82357b CMN |
114 | goto cleanup; |
115 | } | |
116 | ||
44daec42 | 117 | remote->repo = cfg->repo; |
9c82357b CMN |
118 | remote->url = git__strdup(val); |
119 | if (remote->url == NULL) { | |
120 | error = GIT_ENOMEM; | |
121 | goto cleanup; | |
122 | } | |
123 | ||
84dd3820 | 124 | ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "fetch"); |
9c82357b CMN |
125 | if (ret < 0) { |
126 | error = git__throw(GIT_EOSERR, "Failed to build config var name"); | |
127 | goto cleanup; | |
128 | } | |
129 | ||
2dc31040 CMN |
130 | error = parse_remote_refspec(cfg, &remote->fetch, buf); |
131 | if (error < GIT_SUCCESS) { | |
132 | error = git__rethrow(error, "Failed to get fetch refspec"); | |
9c82357b | 133 | goto cleanup; |
2dc31040 | 134 | } |
9c82357b | 135 | |
84dd3820 | 136 | ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "push"); |
9c82357b CMN |
137 | if (ret < 0) { |
138 | error = git__throw(GIT_EOSERR, "Failed to build config var name"); | |
139 | goto cleanup; | |
140 | } | |
141 | ||
2dc31040 CMN |
142 | error = parse_remote_refspec(cfg, &remote->push, buf); |
143 | /* Not finding push is fine */ | |
144 | if (error == GIT_ENOTFOUND) | |
145 | error = GIT_SUCCESS; | |
9c82357b | 146 | |
9c82357b CMN |
147 | if (error < GIT_SUCCESS) |
148 | goto cleanup; | |
149 | ||
150 | *out = remote; | |
151 | ||
152 | cleanup: | |
3286c408 | 153 | git__free(buf); |
9c82357b CMN |
154 | if (error < GIT_SUCCESS) |
155 | git_remote_free(remote); | |
156 | ||
157 | return error; | |
158 | } | |
159 | ||
160 | const char *git_remote_name(struct git_remote *remote) | |
161 | { | |
162 | return remote->name; | |
163 | } | |
164 | ||
165 | const char *git_remote_url(struct git_remote *remote) | |
166 | { | |
167 | return remote->url; | |
168 | } | |
169 | ||
170 | const git_refspec *git_remote_fetchspec(struct git_remote *remote) | |
171 | { | |
172 | return &remote->fetch; | |
173 | } | |
174 | ||
175 | const git_refspec *git_remote_pushspec(struct git_remote *remote) | |
176 | { | |
177 | return &remote->push; | |
178 | } | |
179 | ||
0ac2726f | 180 | int git_remote_connect(git_remote *remote, int direction) |
9ba49bb5 CMN |
181 | { |
182 | int error; | |
183 | git_transport *t; | |
184 | ||
185 | error = git_transport_new(&t, remote->url); | |
186 | if (error < GIT_SUCCESS) | |
187 | return git__rethrow(error, "Failed to create transport"); | |
188 | ||
b5a8aa94 | 189 | error = t->connect(t, direction); |
9ba49bb5 CMN |
190 | if (error < GIT_SUCCESS) { |
191 | error = git__rethrow(error, "Failed to connect the transport"); | |
192 | goto cleanup; | |
193 | } | |
194 | ||
195 | remote->transport = t; | |
196 | ||
197 | cleanup: | |
198 | if (error < GIT_SUCCESS) | |
b5a8aa94 | 199 | t->free(t); |
9ba49bb5 CMN |
200 | |
201 | return error; | |
202 | } | |
203 | ||
204 | int git_remote_ls(git_remote *remote, git_headarray *refs) | |
205 | { | |
b5a8aa94 | 206 | return remote->transport->ls(remote->transport, refs); |
9ba49bb5 CMN |
207 | } |
208 | ||
48a65a07 CMN |
209 | int git_remote_download(char **filename, git_remote *remote) |
210 | { | |
95057b85 CMN |
211 | int error; |
212 | ||
213 | if ((error = git_fetch_negotiate(remote)) < 0) | |
214 | return git__rethrow(error, "Error negotiating"); | |
215 | ||
48a65a07 CMN |
216 | return git_fetch_download_pack(filename, remote); |
217 | } | |
218 | ||
441f57c2 CMN |
219 | int git_remote_update_tips(struct git_remote *remote) |
220 | { | |
221 | int error = GIT_SUCCESS; | |
517bda19 | 222 | unsigned int i = 0; |
441f57c2 CMN |
223 | char refname[GIT_PATH_MAX]; |
224 | git_headarray *refs = &remote->refs; | |
225 | git_remote_head *head; | |
226 | git_reference *ref; | |
227 | struct git_refspec *spec = &remote->fetch; | |
228 | ||
229 | memset(refname, 0x0, sizeof(refname)); | |
230 | ||
517bda19 CMN |
231 | if (refs->len == 0) |
232 | return GIT_SUCCESS; | |
233 | ||
234 | /* HEAD is only allowed to be the first in the list */ | |
235 | head = refs->heads[0]; | |
236 | if (!strcmp(head->name, GIT_HEAD_FILE)) { | |
237 | error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1); | |
238 | i = 1; | |
239 | if (error < GIT_SUCCESS) | |
240 | return git__rethrow(error, "Failed to update FETCH_HEAD"); | |
241 | } | |
242 | ||
243 | for (; i < refs->len; ++i) { | |
441f57c2 | 244 | head = refs->heads[i]; |
517bda19 | 245 | |
441f57c2 CMN |
246 | error = git_refspec_transform(refname, sizeof(refname), spec, head->name); |
247 | if (error < GIT_SUCCESS) | |
248 | return error; | |
249 | ||
250 | error = git_reference_create_oid(&ref, remote->repo, refname, &head->oid, 1); | |
251 | if (error < GIT_SUCCESS) | |
252 | return error; | |
253 | } | |
254 | ||
255 | return GIT_SUCCESS; | |
256 | } | |
257 | ||
9c82357b CMN |
258 | void git_remote_free(git_remote *remote) |
259 | { | |
2aae2188 CMN |
260 | if (remote == NULL) |
261 | return; | |
262 | ||
3286c408 VM |
263 | git__free(remote->fetch.src); |
264 | git__free(remote->fetch.dst); | |
265 | git__free(remote->push.src); | |
266 | git__free(remote->push.dst); | |
267 | git__free(remote->url); | |
268 | git__free(remote->name); | |
9ba49bb5 CMN |
269 | if (remote->transport != NULL) { |
270 | if (remote->transport->connected) | |
b5a8aa94 CMN |
271 | remote->transport->close(remote->transport); |
272 | ||
273 | remote->transport->free(remote->transport); | |
9ba49bb5 | 274 | } |
3286c408 | 275 | git__free(remote); |
9c82357b | 276 | } |