Move remote parsing into a library file out of builtin-push.
[git/git.git] / builtin-push.c
CommitLineData
755225de
LT
1/*
2 * "git push"
3 */
4#include "cache.h"
5#include "refs.h"
6#include "run-command.h"
7#include "builtin.h"
5751f490 8#include "remote.h"
755225de 9
d23842fd 10static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
755225de 11
bcc785f6 12static int all, tags, force, thin = 1, verbose;
d23842fd 13static const char *receivepack;
755225de 14
96f1e58f
DR
15static const char **refspec;
16static int refspec_nr;
755225de
LT
17
18static void add_refspec(const char *ref)
19{
20 int nr = refspec_nr + 1;
21 refspec = xrealloc(refspec, nr * sizeof(char *));
22 refspec[nr-1] = ref;
23 refspec_nr = nr;
24}
25
8da19775 26static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
755225de
LT
27{
28 /* Ignore the "refs/" at the beginning of the refname */
29 ref += 5;
30
cc44c765 31 if (!prefixcmp(ref, "tags/"))
9befac47 32 add_refspec(xstrdup(ref));
755225de
LT
33 return 0;
34}
35
36static void expand_refspecs(void)
37{
38 if (all) {
39 if (refspec_nr)
40 die("cannot mix '--all' and a refspec");
41
42 /*
43 * No need to expand "--all" - we'll just use
44 * the "--all" flag to send-pack
45 */
46 return;
47 }
48 if (!tags)
49 return;
cb5d709f 50 for_each_ref(expand_one_ref, NULL);
755225de
LT
51}
52
d46ae3f0
JH
53struct wildcard_cb {
54 const char *from_prefix;
55 int from_prefix_len;
56 const char *to_prefix;
57 int to_prefix_len;
58 int force;
59};
60
61static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
62{
63 struct wildcard_cb *cb = cb_data;
64 int len = strlen(ref);
65 char *expanded, *newref;
66
67 if (len < cb->from_prefix_len ||
68 memcmp(cb->from_prefix, ref, cb->from_prefix_len))
69 return 0;
70 expanded = xmalloc(len * 2 + cb->force +
71 (cb->to_prefix_len - cb->from_prefix_len) + 2);
72 newref = expanded + cb->force;
73 if (cb->force)
74 expanded[0] = '+';
75 memcpy(newref, ref, len);
76 newref[len] = ':';
77 memcpy(newref + len + 1, cb->to_prefix, cb->to_prefix_len);
78 strcpy(newref + len + 1 + cb->to_prefix_len,
79 ref + cb->from_prefix_len);
80 add_refspec(expanded);
81 return 0;
82}
83
84static int wildcard_ref(const char *ref)
85{
86 int len;
87 const char *colon;
88 struct wildcard_cb cb;
89
90 memset(&cb, 0, sizeof(cb));
91 if (ref[0] == '+') {
92 cb.force = 1;
93 ref++;
94 }
95 len = strlen(ref);
96 colon = strchr(ref, ':');
97 if (! (colon && ref < colon &&
98 colon[-2] == '/' && colon[-1] == '*' &&
99 /* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */
100 7 <= len &&
101 ref[len-2] == '/' && ref[len-1] == '*') )
102 return 0 ;
103 cb.from_prefix = ref;
104 cb.from_prefix_len = colon - ref - 1;
105 cb.to_prefix = colon + 1;
106 cb.to_prefix_len = len - (colon - ref) - 2;
107 for_each_ref(expand_wildcard_ref, &cb);
108 return 1;
109}
110
755225de
LT
111static void set_refspecs(const char **refs, int nr)
112{
113 if (nr) {
d46ae3f0
JH
114 int i;
115 for (i = 0; i < nr; i++) {
116 const char *ref = refs[i];
117 if (!strcmp("tag", ref)) {
118 char *tag;
119 int len;
120 if (nr <= ++i)
121 die("tag shorthand without <tag>");
122 len = strlen(refs[i]) + 11;
123 tag = xmalloc(len);
124 strcpy(tag, "refs/tags/");
125 strcat(tag, refs[i]);
126 ref = tag;
411fb8ba 127 }
d46ae3f0
JH
128 else if (wildcard_ref(ref))
129 continue;
130 add_refspec(ref);
411fb8ba 131 }
755225de
LT
132 }
133 expand_refspecs();
134}
135
755225de
LT
136static int do_push(const char *repo)
137{
5751f490 138 int i, errs;
441c823e 139 int common_argc;
755225de
LT
140 const char **argv;
141 int argc;
5751f490 142 struct remote *remote = remote_get(repo);
755225de 143
5751f490 144 if (!remote)
755225de
LT
145 die("bad repository '%s'", repo);
146
5751f490
DB
147 if (remote->receivepack) {
148 char *rp = xmalloc(strlen(remote->receivepack) + 16);
149 sprintf(rp, "--receive-pack=%s", remote->receivepack);
150 receivepack = rp;
151 }
152 if (!refspec && !all && !tags && remote->push_refspec_nr) {
153 for (i = 0; i < remote->push_refspec_nr; i++) {
154 if (!wildcard_ref(remote->push_refspec[i]))
155 add_refspec(remote->push_refspec[i]);
156 }
157 }
158
755225de
LT
159 argv = xmalloc((refspec_nr + 10) * sizeof(char *));
160 argv[0] = "dummy-send-pack";
161 argc = 1;
162 if (all)
163 argv[argc++] = "--all";
164 if (force)
165 argv[argc++] = "--force";
d23842fd
UKK
166 if (receivepack)
167 argv[argc++] = receivepack;
441c823e 168 common_argc = argc;
755225de 169
fd1d1b05 170 errs = 0;
5751f490 171 for (i = 0; i < remote->uri_nr; i++) {
60b7f38e 172 int err;
441c823e
NH
173 int dest_argc = common_argc;
174 int dest_refspec_nr = refspec_nr;
175 const char **dest_refspec = refspec;
5751f490 176 const char *dest = remote->uri[i];
df91ba36 177 const char *sender = "send-pack";
cc44c765
JH
178 if (!prefixcmp(dest, "http://") ||
179 !prefixcmp(dest, "https://"))
df91ba36 180 sender = "http-push";
441c823e
NH
181 else if (thin)
182 argv[dest_argc++] = "--thin";
755225de 183 argv[0] = sender;
441c823e
NH
184 argv[dest_argc++] = dest;
185 while (dest_refspec_nr--)
186 argv[dest_argc++] = *dest_refspec++;
187 argv[dest_argc] = NULL;
bcc785f6
LT
188 if (verbose)
189 fprintf(stderr, "Pushing to %s\n", dest);
df91ba36 190 err = run_command_v_opt(argv, RUN_GIT_CMD);
60b7f38e 191 if (!err)
755225de 192 continue;
39878b0c 193
5751f490 194 error("failed to push to '%s'", remote->uri[i]);
60b7f38e 195 switch (err) {
755225de 196 case -ERR_RUN_COMMAND_FORK:
fd1d1b05 197 error("unable to fork for %s", sender);
755225de 198 case -ERR_RUN_COMMAND_EXEC:
fd1d1b05
JH
199 error("unable to exec %s", sender);
200 break;
755225de
LT
201 case -ERR_RUN_COMMAND_WAITPID:
202 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
203 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
204 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
fd1d1b05 205 error("%s died with strange error", sender);
755225de 206 }
fd1d1b05 207 errs++;
755225de 208 }
fd1d1b05 209 return !!errs;
755225de
LT
210}
211
a633fca0 212int cmd_push(int argc, const char **argv, const char *prefix)
755225de
LT
213{
214 int i;
5751f490 215 const char *repo = NULL; /* default repository */
755225de
LT
216
217 for (i = 1; i < argc; i++) {
218 const char *arg = argv[i];
219
220 if (arg[0] != '-') {
221 repo = arg;
222 i++;
223 break;
224 }
bcc785f6
LT
225 if (!strcmp(arg, "-v")) {
226 verbose=1;
227 continue;
228 }
cc44c765 229 if (!prefixcmp(arg, "--repo=")) {
bcc785f6
LT
230 repo = arg+7;
231 continue;
232 }
755225de
LT
233 if (!strcmp(arg, "--all")) {
234 all = 1;
235 continue;
236 }
237 if (!strcmp(arg, "--tags")) {
238 tags = 1;
239 continue;
240 }
8f615493 241 if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
755225de
LT
242 force = 1;
243 continue;
244 }
245 if (!strcmp(arg, "--thin")) {
246 thin = 1;
247 continue;
248 }
249 if (!strcmp(arg, "--no-thin")) {
250 thin = 0;
251 continue;
252 }
cc44c765 253 if (!prefixcmp(arg, "--receive-pack=")) {
d23842fd
UKK
254 receivepack = arg;
255 continue;
256 }
cc44c765 257 if (!prefixcmp(arg, "--exec=")) {
d23842fd 258 receivepack = arg;
755225de
LT
259 continue;
260 }
261 usage(push_usage);
262 }
263 set_refspecs(argv + i, argc - i);
264 return do_push(repo);
265}