]>
Commit | Line | Data |
---|---|---|
9b288516 DB |
1 | #include "cache.h" |
2 | #include "transport.h" | |
3 | #include "run-command.h" | |
4 | ||
5 | static const struct transport_ops rsync_transport; | |
6 | ||
7 | static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { | |
8 | const char **argv; | |
9 | int argc; | |
10 | int err; | |
11 | ||
12 | argv = xmalloc((refspec_nr + 11) * sizeof(char *)); | |
13 | argv[0] = "http-push"; | |
14 | argc = 1; | |
15 | if (flags & TRANSPORT_PUSH_ALL) | |
16 | argv[argc++] = "--all"; | |
17 | if (flags & TRANSPORT_PUSH_FORCE) | |
18 | argv[argc++] = "--force"; | |
19 | argv[argc++] = transport->url; | |
20 | while (refspec_nr--) | |
21 | argv[argc++] = *refspec++; | |
22 | argv[argc] = NULL; | |
23 | err = run_command_v_opt(argv, RUN_GIT_CMD); | |
24 | switch (err) { | |
25 | case -ERR_RUN_COMMAND_FORK: | |
26 | error("unable to fork for %s", argv[0]); | |
27 | case -ERR_RUN_COMMAND_EXEC: | |
28 | error("unable to exec %s", argv[0]); | |
29 | break; | |
30 | case -ERR_RUN_COMMAND_WAITPID: | |
31 | case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: | |
32 | case -ERR_RUN_COMMAND_WAITPID_SIGNAL: | |
33 | case -ERR_RUN_COMMAND_WAITPID_NOEXIT: | |
34 | error("%s died with strange error", argv[0]); | |
35 | } | |
36 | return !!err; | |
37 | } | |
38 | ||
39 | static const struct transport_ops curl_transport = { | |
40 | /* set_option */ NULL, | |
41 | /* push */ curl_transport_push | |
42 | }; | |
43 | ||
44 | static const struct transport_ops bundle_transport = { | |
45 | }; | |
46 | ||
47 | struct git_transport_data { | |
48 | unsigned thin : 1; | |
49 | ||
50 | const char *receivepack; | |
51 | }; | |
52 | ||
53 | static int set_git_option(struct transport *connection, | |
54 | const char *name, const char *value) | |
55 | { | |
56 | struct git_transport_data *data = connection->data; | |
57 | if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) { | |
58 | data->receivepack = value; | |
59 | return 0; | |
60 | } else if (!strcmp(name, TRANS_OPT_THIN)) { | |
61 | data->thin = !!value; | |
62 | return 0; | |
63 | } | |
64 | return 1; | |
65 | } | |
66 | ||
67 | static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { | |
68 | struct git_transport_data *data = transport->data; | |
69 | const char **argv; | |
70 | char *rem; | |
71 | int argc; | |
72 | int err; | |
73 | ||
74 | argv = xmalloc((refspec_nr + 11) * sizeof(char *)); | |
75 | argv[0] = "send-pack"; | |
76 | argc = 1; | |
77 | if (flags & TRANSPORT_PUSH_ALL) | |
78 | argv[argc++] = "--all"; | |
79 | if (flags & TRANSPORT_PUSH_FORCE) | |
80 | argv[argc++] = "--force"; | |
81 | if (data->receivepack) { | |
82 | char *rp = xmalloc(strlen(data->receivepack) + 16); | |
83 | sprintf(rp, "--receive-pack=%s", data->receivepack); | |
84 | argv[argc++] = rp; | |
85 | } | |
86 | if (data->thin) | |
87 | argv[argc++] = "--thin"; | |
88 | rem = xmalloc(strlen(transport->remote->name) + 10); | |
89 | sprintf(rem, "--remote=%s", transport->remote->name); | |
90 | argv[argc++] = rem; | |
91 | argv[argc++] = transport->url; | |
92 | while (refspec_nr--) | |
93 | argv[argc++] = *refspec++; | |
94 | argv[argc] = NULL; | |
95 | err = run_command_v_opt(argv, RUN_GIT_CMD); | |
96 | switch (err) { | |
97 | case -ERR_RUN_COMMAND_FORK: | |
98 | error("unable to fork for %s", argv[0]); | |
99 | case -ERR_RUN_COMMAND_EXEC: | |
100 | error("unable to exec %s", argv[0]); | |
101 | break; | |
102 | case -ERR_RUN_COMMAND_WAITPID: | |
103 | case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: | |
104 | case -ERR_RUN_COMMAND_WAITPID_SIGNAL: | |
105 | case -ERR_RUN_COMMAND_WAITPID_NOEXIT: | |
106 | error("%s died with strange error", argv[0]); | |
107 | } | |
108 | return !!err; | |
109 | } | |
110 | ||
111 | static const struct transport_ops git_transport = { | |
112 | /* set_option */ set_git_option, | |
113 | /* push */ git_transport_push | |
114 | }; | |
115 | ||
116 | static int is_local(const char *url) | |
117 | { | |
118 | const char *colon = strchr(url, ':'); | |
119 | const char *slash = strchr(url, '/'); | |
120 | return !colon || (slash && slash < colon); | |
121 | } | |
122 | ||
123 | static int is_file(const char *url) | |
124 | { | |
125 | struct stat buf; | |
126 | if (stat(url, &buf)) | |
127 | return 0; | |
128 | return S_ISREG(buf.st_mode); | |
129 | } | |
130 | ||
131 | struct transport *transport_get(struct remote *remote, const char *url, | |
132 | int fetch) | |
133 | { | |
134 | struct transport *ret = NULL; | |
135 | if (!prefixcmp(url, "rsync://")) { | |
136 | ret = xmalloc(sizeof(*ret)); | |
137 | ret->data = NULL; | |
138 | ret->ops = &rsync_transport; | |
139 | } else if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://") || | |
140 | !prefixcmp(url, "ftp://")) { | |
141 | ret = xmalloc(sizeof(*ret)); | |
142 | ret->ops = &curl_transport; | |
143 | ret->data = NULL; | |
144 | } else if (is_local(url) && is_file(url)) { | |
145 | ret = xmalloc(sizeof(*ret)); | |
146 | ret->data = NULL; | |
147 | ret->ops = &bundle_transport; | |
148 | } else { | |
149 | struct git_transport_data *data = xcalloc(1, sizeof(*data)); | |
150 | ret = xcalloc(1, sizeof(*ret)); | |
151 | ret->data = data; | |
152 | data->thin = 1; | |
153 | data->receivepack = "git-receive-pack"; | |
154 | if (remote && remote->receivepack) | |
155 | data->receivepack = remote->receivepack; | |
156 | ret->ops = &git_transport; | |
157 | } | |
158 | if (ret) { | |
159 | ret->remote = remote; | |
160 | ret->url = url; | |
161 | ret->fetch = !!fetch; | |
162 | } | |
163 | return ret; | |
164 | } | |
165 | ||
166 | int transport_set_option(struct transport *transport, | |
167 | const char *name, const char *value) | |
168 | { | |
169 | int ret = 1; | |
170 | if (transport->ops->set_option) | |
171 | ret = transport->ops->set_option(transport, name, value); | |
172 | if (ret < 0) | |
173 | fprintf(stderr, "For '%s' option %s cannot be set to '%s'\n", | |
174 | transport->url, name, value); | |
175 | if (ret > 0) | |
176 | fprintf(stderr, "For '%s' option %s is ignored\n", | |
177 | transport->url, name); | |
178 | return ret; | |
179 | } | |
180 | ||
181 | int transport_push(struct transport *transport, | |
182 | int refspec_nr, const char **refspec, int flags) | |
183 | { | |
184 | if (!transport->ops->push) | |
185 | return 1; | |
186 | return transport->ops->push(transport, refspec_nr, refspec, flags); | |
187 | } | |
188 | ||
189 | int transport_disconnect(struct transport *transport) | |
190 | { | |
191 | int ret = 0; | |
192 | if (transport->ops->disconnect) | |
193 | ret = transport->ops->disconnect(transport); | |
194 | free(transport); | |
195 | return ret; | |
196 | } |