]> git.proxmox.com Git - libgit2.git/blob - src/remote.c
Implement sending haves
[libgit2.git] / src / remote.c
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"
33
34 static int refspec_parse(git_refspec *refspec, const char *str)
35 {
36 char *delim;
37
38 memset(refspec, 0x0, sizeof(git_refspec));
39
40 if (*str == '+') {
41 refspec->force = 1;
42 str++;
43 }
44
45 delim = strchr(str, ':');
46 if (delim == NULL)
47 return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
48
49 refspec->src = git__strndup(str, delim - str);
50 if (refspec->src == NULL)
51 return GIT_ENOMEM;
52
53 refspec->dst = git__strdup(delim + 1);
54 if (refspec->dst == NULL) {
55 free(refspec->src);
56 refspec->src = NULL;
57 return GIT_ENOMEM;
58 }
59
60 return GIT_SUCCESS;
61 }
62
63 static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
64 {
65 const char *val;
66 int error;
67
68 error = git_config_get_string(cfg, var, &val);
69 if (error < GIT_SUCCESS)
70 return error;
71
72 return refspec_parse(refspec, val);
73 }
74
75 int git_remote_get(git_remote **out, git_config *cfg, const char *name)
76 {
77 git_remote *remote;
78 char *buf = NULL;
79 const char *val;
80 int ret, error, buf_len;
81
82 remote = git__malloc(sizeof(git_remote));
83 if (remote == NULL)
84 return GIT_ENOMEM;
85
86 memset(remote, 0x0, sizeof(git_remote));
87 remote->name = git__strdup(name);
88 if (remote->name == NULL) {
89 error = GIT_ENOMEM;
90 goto cleanup;
91 }
92
93 /* "fetch" is the longest var name we're interested in */
94 buf_len = STRLEN("remote.") + STRLEN(".fetch") + strlen(name) + 1;
95 buf = git__malloc(buf_len);
96 if (buf == NULL) {
97 error = GIT_ENOMEM;
98 goto cleanup;
99 }
100
101 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "url");
102 if (ret < 0) {
103 error = git__throw(GIT_EOSERR, "Failed to build config var name");
104 goto cleanup;
105 }
106
107 error = git_config_get_string(cfg, buf, &val);
108 if (error < GIT_SUCCESS) {
109 error = git__rethrow(error, "Remote's url doesn't exist");
110 goto cleanup;
111 }
112
113 remote->url = git__strdup(val);
114 if (remote->url == NULL) {
115 error = GIT_ENOMEM;
116 goto cleanup;
117 }
118
119 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "fetch");
120 if (ret < 0) {
121 error = git__throw(GIT_EOSERR, "Failed to build config var name");
122 goto cleanup;
123 }
124
125 error = parse_remote_refspec(cfg, &remote->fetch, buf);
126 if (error < GIT_SUCCESS) {
127 error = git__rethrow(error, "Failed to get fetch refspec");
128 goto cleanup;
129 }
130
131 ret = snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "push");
132 if (ret < 0) {
133 error = git__throw(GIT_EOSERR, "Failed to build config var name");
134 goto cleanup;
135 }
136
137 error = parse_remote_refspec(cfg, &remote->push, buf);
138 /* Not finding push is fine */
139 if (error == GIT_ENOTFOUND)
140 error = GIT_SUCCESS;
141
142 if (error < GIT_SUCCESS)
143 goto cleanup;
144
145 *out = remote;
146
147 cleanup:
148 free(buf);
149 if (error < GIT_SUCCESS)
150 git_remote_free(remote);
151
152 return error;
153 }
154
155 const char *git_remote_name(struct git_remote *remote)
156 {
157 return remote->name;
158 }
159
160 const char *git_remote_url(struct git_remote *remote)
161 {
162 return remote->url;
163 }
164
165 const git_refspec *git_remote_fetchspec(struct git_remote *remote)
166 {
167 return &remote->fetch;
168 }
169
170 const git_refspec *git_remote_pushspec(struct git_remote *remote)
171 {
172 return &remote->push;
173 }
174
175 int git_remote_connect(git_remote *remote, int direction)
176 {
177 int error;
178 git_transport *t;
179
180 error = git_transport_new(&t, remote->url);
181 if (error < GIT_SUCCESS)
182 return git__rethrow(error, "Failed to create transport");
183
184 error = git_transport_connect(t, direction);
185 if (error < GIT_SUCCESS) {
186 error = git__rethrow(error, "Failed to connect the transport");
187 goto cleanup;
188 }
189
190 remote->transport = t;
191
192 cleanup:
193 if (error < GIT_SUCCESS)
194 git_transport_free(t);
195
196 return error;
197 }
198
199 int git_remote_ls(git_remote *remote, git_headarray *refs)
200 {
201 return git_transport_ls(remote->transport, refs);
202 }
203
204 void git_remote_free(git_remote *remote)
205 {
206 free(remote->fetch.src);
207 free(remote->fetch.dst);
208 free(remote->push.src);
209 free(remote->push.dst);
210 free(remote->url);
211 free(remote->name);
212 if (remote->transport != NULL) {
213 if (remote->transport->connected)
214 git_transport_close(remote->transport);
215 git_transport_free(remote->transport);
216 }
217 free(remote);
218 }