]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
remote: get rid of git_remote_negotiate
[libgit2.git] / src / remote.c
CommitLineData
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
18static 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
47static 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
59int 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
79int 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
152cleanup:
3286c408 153 git__free(buf);
9c82357b
CMN
154 if (error < GIT_SUCCESS)
155 git_remote_free(remote);
156
157 return error;
158}
159
160const char *git_remote_name(struct git_remote *remote)
161{
162 return remote->name;
163}
164
165const char *git_remote_url(struct git_remote *remote)
166{
167 return remote->url;
168}
169
170const git_refspec *git_remote_fetchspec(struct git_remote *remote)
171{
172 return &remote->fetch;
173}
174
175const git_refspec *git_remote_pushspec(struct git_remote *remote)
176{
177 return &remote->push;
178}
179
0ac2726f 180int 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
197cleanup:
198 if (error < GIT_SUCCESS)
b5a8aa94 199 t->free(t);
9ba49bb5
CMN
200
201 return error;
202}
203
204int 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
209int 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
219int 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
258void 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}