]>
Commit | Line | Data |
---|---|---|
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 | |
35 | static 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 | ||
64 | static 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 | ||
76 | int 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 | ||
149 | cleanup: | |
150 | free(buf); | |
151 | if (error < GIT_SUCCESS) | |
152 | git_remote_free(remote); | |
153 | ||
154 | return error; | |
155 | } | |
156 | ||
157 | const char *git_remote_name(struct git_remote *remote) | |
158 | { | |
159 | return remote->name; | |
160 | } | |
161 | ||
162 | const char *git_remote_url(struct git_remote *remote) | |
163 | { | |
164 | return remote->url; | |
165 | } | |
166 | ||
167 | const git_refspec *git_remote_fetchspec(struct git_remote *remote) | |
168 | { | |
169 | return &remote->fetch; | |
170 | } | |
171 | ||
172 | const git_refspec *git_remote_pushspec(struct git_remote *remote) | |
173 | { | |
174 | return &remote->push; | |
175 | } | |
176 | ||
0ac2726f | 177 | int 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 | ||
194 | cleanup: | |
195 | if (error < GIT_SUCCESS) | |
196 | git_transport_free(t); | |
197 | ||
198 | return error; | |
199 | } | |
200 | ||
201 | int git_remote_ls(git_remote *remote, git_headarray *refs) | |
202 | { | |
203 | return git_transport_ls(remote->transport, refs); | |
204 | } | |
205 | ||
e1d88030 CMN |
206 | int git_remote_negotiate(git_remote *remote) |
207 | { | |
208 | return git_fetch_negotiate(remote); | |
209 | } | |
210 | ||
48a65a07 CMN |
211 | int git_remote_download(char **filename, git_remote *remote) |
212 | { | |
213 | return git_fetch_download_pack(filename, remote); | |
214 | } | |
215 | ||
e1d88030 CMN |
216 | git_headarray *git_remote_tips(git_remote *remote) |
217 | { | |
218 | return &remote->refs; | |
219 | } | |
220 | ||
9c82357b CMN |
221 | void 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 | } |