]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Implement cooperative caching
[libgit2.git] / src / remote.c
CommitLineData
9c82357b
CMN
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "git2/remote.h"
27#include "git2/config.h"
28#include "git2/types.h"
29
30#include "config.h"
31#include "repository.h"
32#include "remote.h"
e1d88030 33#include "fetch.h"
9c82357b
CMN
34
35static int refspec_parse(git_refspec *refspec, const char *str)
36{
37 char *delim;
38
39 memset(refspec, 0x0, sizeof(git_refspec));
40
41 if (*str == '+') {
42 refspec->force = 1;
43 str++;
44 }
45
46 delim = strchr(str, ':');
47 if (delim == NULL)
48 return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
49
50 refspec->src = git__strndup(str, delim - str);
51 if (refspec->src == NULL)
52 return GIT_ENOMEM;
53
54 refspec->dst = git__strdup(delim + 1);
55 if (refspec->dst == NULL) {
56 free(refspec->src);
57 refspec->src = NULL;
58 return GIT_ENOMEM;
59 }
60
61 return GIT_SUCCESS;
62}
63
64static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
65{
66 const char *val;
67 int error;
68
69 error = git_config_get_string(cfg, var, &val);
70 if (error < GIT_SUCCESS)
71 return error;
72
2dc31040 73 return refspec_parse(refspec, val);
9c82357b
CMN
74}
75
76int git_remote_get(git_remote **out, git_config *cfg, const char *name)
77{
78 git_remote *remote;
79 char *buf = NULL;
80 const char *val;
81 int ret, error, buf_len;
82
83 remote = git__malloc(sizeof(git_remote));
84 if (remote == NULL)
85 return GIT_ENOMEM;
86
87 memset(remote, 0x0, sizeof(git_remote));
88 remote->name = git__strdup(name);
89 if (remote->name == NULL) {
90 error = GIT_ENOMEM;
91 goto cleanup;
92 }
93
94 /* "fetch" is the longest var name we're interested in */
95 buf_len = STRLEN("remote.") + STRLEN(".fetch") + strlen(name) + 1;
96 buf = git__malloc(buf_len);
97 if (buf == NULL) {
98 error = GIT_ENOMEM;
99 goto cleanup;
100 }
101
102 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "url");
103 if (ret < 0) {
104 error = git__throw(GIT_EOSERR, "Failed to build config var name");
105 goto cleanup;
106 }
107
108 error = git_config_get_string(cfg, buf, &val);
109 if (error < GIT_SUCCESS) {
110 error = git__rethrow(error, "Remote's url doesn't exist");
111 goto cleanup;
112 }
113
44daec42 114 remote->repo = cfg->repo;
9c82357b
CMN
115 remote->url = git__strdup(val);
116 if (remote->url == NULL) {
117 error = GIT_ENOMEM;
118 goto cleanup;
119 }
120
121 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "fetch");
122 if (ret < 0) {
123 error = git__throw(GIT_EOSERR, "Failed to build config var name");
124 goto cleanup;
125 }
126
2dc31040
CMN
127 error = parse_remote_refspec(cfg, &remote->fetch, buf);
128 if (error < GIT_SUCCESS) {
129 error = git__rethrow(error, "Failed to get fetch refspec");
9c82357b 130 goto cleanup;
2dc31040 131 }
9c82357b
CMN
132
133 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "push");
134 if (ret < 0) {
135 error = git__throw(GIT_EOSERR, "Failed to build config var name");
136 goto cleanup;
137 }
138
2dc31040
CMN
139 error = parse_remote_refspec(cfg, &remote->push, buf);
140 /* Not finding push is fine */
141 if (error == GIT_ENOTFOUND)
142 error = GIT_SUCCESS;
9c82357b 143
9c82357b
CMN
144 if (error < GIT_SUCCESS)
145 goto cleanup;
146
147 *out = remote;
148
149cleanup:
150 free(buf);
151 if (error < GIT_SUCCESS)
152 git_remote_free(remote);
153
154 return error;
155}
156
157const char *git_remote_name(struct git_remote *remote)
158{
159 return remote->name;
160}
161
162const char *git_remote_url(struct git_remote *remote)
163{
164 return remote->url;
165}
166
167const git_refspec *git_remote_fetchspec(struct git_remote *remote)
168{
169 return &remote->fetch;
170}
171
172const git_refspec *git_remote_pushspec(struct git_remote *remote)
173{
174 return &remote->push;
175}
176
0ac2726f 177int git_remote_connect(git_remote *remote, int direction)
9ba49bb5
CMN
178{
179 int error;
180 git_transport *t;
181
182 error = git_transport_new(&t, remote->url);
183 if (error < GIT_SUCCESS)
184 return git__rethrow(error, "Failed to create transport");
185
0ac2726f 186 error = git_transport_connect(t, direction);
9ba49bb5
CMN
187 if (error < GIT_SUCCESS) {
188 error = git__rethrow(error, "Failed to connect the transport");
189 goto cleanup;
190 }
191
192 remote->transport = t;
193
194cleanup:
195 if (error < GIT_SUCCESS)
196 git_transport_free(t);
197
198 return error;
199}
200
201int git_remote_ls(git_remote *remote, git_headarray *refs)
202{
203 return git_transport_ls(remote->transport, refs);
204}
205
e1d88030
CMN
206int git_remote_negotiate(git_remote *remote)
207{
208 return git_fetch_negotiate(remote);
209}
210
48a65a07
CMN
211int git_remote_download(char **filename, git_remote *remote)
212{
213 return git_fetch_download_pack(filename, remote);
214}
215
e1d88030
CMN
216git_headarray *git_remote_tips(git_remote *remote)
217{
218 return &remote->refs;
219}
220
9c82357b
CMN
221void git_remote_free(git_remote *remote)
222{
223 free(remote->fetch.src);
224 free(remote->fetch.dst);
225 free(remote->push.src);
226 free(remote->push.dst);
227 free(remote->url);
228 free(remote->name);
9ba49bb5
CMN
229 if (remote->transport != NULL) {
230 if (remote->transport->connected)
231 git_transport_close(remote->transport);
232 git_transport_free(remote->transport);
233 }
9c82357b
CMN
234 free(remote);
235}