4 #include "run-command.h"
16 struct child_process
*helper
;
22 /* These go from remote name (as in "list") to private name */
23 struct refspec
*refspecs
;
27 static void sendline(struct helper_data
*helper
, struct strbuf
*buffer
)
30 fprintf(stderr
, "Debug: Remote helper: -> %s", buffer
->buf
);
31 if (write_in_full(helper
->helper
->in
, buffer
->buf
, buffer
->len
)
33 die_errno("Full write to remote helper failed");
36 static int recvline(struct helper_data
*helper
, struct strbuf
*buffer
)
40 fprintf(stderr
, "Debug: Remote helper: Waiting...\n");
41 if (strbuf_getline(buffer
, helper
->out
, '\n') == EOF
) {
43 fprintf(stderr
, "Debug: Remote helper quit.\n");
48 fprintf(stderr
, "Debug: Remote helper: <- %s\n", buffer
->buf
);
52 static void xchgline(struct helper_data
*helper
, struct strbuf
*buffer
)
54 sendline(helper
, buffer
);
55 recvline(helper
, buffer
);
58 static void write_constant(int fd
, const char *str
)
61 fprintf(stderr
, "Debug: Remote helper: -> %s", str
);
62 if (write_in_full(fd
, str
, strlen(str
)) != strlen(str
))
63 die_errno("Full write to remote helper failed");
66 static struct child_process
*get_helper(struct transport
*transport
)
68 struct helper_data
*data
= transport
->data
;
69 struct strbuf buf
= STRBUF_INIT
;
70 struct child_process
*helper
;
71 const char **refspecs
= NULL
;
73 int refspec_alloc
= 0;
78 helper
= xcalloc(1, sizeof(*helper
));
82 helper
->argv
= xcalloc(4, sizeof(*helper
->argv
));
83 strbuf_addf(&buf
, "remote-%s", data
->name
);
84 helper
->argv
[0] = strbuf_detach(&buf
, NULL
);
85 helper
->argv
[1] = transport
->remote
->name
;
86 helper
->argv
[2] = transport
->url
;
88 if (start_command(helper
))
89 die("Unable to run helper: git %s", helper
->argv
[0]);
90 data
->helper
= helper
;
92 write_constant(helper
->in
, "capabilities\n");
94 data
->out
= xfdopen(helper
->out
, "r");
103 if (*buf
.buf
== '*') {
104 capname
= buf
.buf
+ 1;
110 fprintf(stderr
, "Debug: Got cap %s\n", capname
);
111 if (!strcmp(capname
, "fetch"))
113 else if (!strcmp(capname
, "option"))
115 else if (!strcmp(capname
, "push"))
117 else if (!strcmp(capname
, "import"))
119 else if (!data
->refspecs
&& !prefixcmp(capname
, "refspec ")) {
123 refspecs
[refspec_nr
++] = strdup(buf
.buf
+ strlen("refspec "));
124 } else if (mandatory
) {
125 die("Unknown madatory capability %s. This remote "
126 "helper probably needs newer version of Git.\n",
132 data
->refspec_nr
= refspec_nr
;
133 data
->refspecs
= parse_fetch_refspec(refspec_nr
, refspecs
);
134 for (i
= 0; i
< refspec_nr
; i
++) {
135 free((char *)refspecs
[i
]);
139 strbuf_release(&buf
);
141 fprintf(stderr
, "Debug: Capabilities complete.\n");
145 static int disconnect_helper(struct transport
*transport
)
147 struct helper_data
*data
= transport
->data
;
148 struct strbuf buf
= STRBUF_INIT
;
152 fprintf(stderr
, "Debug: Disconnecting.\n");
153 strbuf_addf(&buf
, "\n");
154 sendline(data
, &buf
);
155 close(data
->helper
->in
);
157 finish_command(data
->helper
);
158 free((char *)data
->helper
->argv
[0]);
159 free(data
->helper
->argv
);
166 static const char *unsupported_options
[] = {
167 TRANS_OPT_UPLOADPACK
,
168 TRANS_OPT_RECEIVEPACK
,
172 static const char *boolean_options
[] = {
178 static int set_helper_option(struct transport
*transport
,
179 const char *name
, const char *value
)
181 struct helper_data
*data
= transport
->data
;
182 struct strbuf buf
= STRBUF_INIT
;
183 int i
, ret
, is_bool
= 0;
185 get_helper(transport
);
190 for (i
= 0; i
< ARRAY_SIZE(unsupported_options
); i
++) {
191 if (!strcmp(name
, unsupported_options
[i
]))
195 for (i
= 0; i
< ARRAY_SIZE(boolean_options
); i
++) {
196 if (!strcmp(name
, boolean_options
[i
])) {
202 strbuf_addf(&buf
, "option %s ", name
);
204 strbuf_addstr(&buf
, value
? "true" : "false");
206 quote_c_style(value
, &buf
, NULL
, 0);
207 strbuf_addch(&buf
, '\n');
209 xchgline(data
, &buf
);
211 if (!strcmp(buf
.buf
, "ok"))
213 else if (!prefixcmp(buf
.buf
, "error")) {
215 } else if (!strcmp(buf
.buf
, "unsupported"))
218 warning("%s unexpectedly said: '%s'", data
->name
, buf
.buf
);
221 strbuf_release(&buf
);
225 static void standard_options(struct transport
*t
)
230 int no_progress
= v
< 0 || (!t
->progress
&& !isatty(1));
232 set_helper_option(t
, "progress", !no_progress
? "true" : "false");
234 n
= snprintf(buf
, sizeof(buf
), "%d", v
+ 1);
235 if (n
>= sizeof(buf
))
236 die("impossibly large verbosity value");
237 set_helper_option(t
, "verbosity", buf
);
240 static int release_helper(struct transport
*transport
)
242 struct helper_data
*data
= transport
->data
;
243 free_refspec(data
->refspec_nr
, data
->refspecs
);
244 data
->refspecs
= NULL
;
245 disconnect_helper(transport
);
246 free(transport
->data
);
250 static int fetch_with_fetch(struct transport
*transport
,
251 int nr_heads
, struct ref
**to_fetch
)
253 struct helper_data
*data
= transport
->data
;
255 struct strbuf buf
= STRBUF_INIT
;
257 standard_options(transport
);
259 for (i
= 0; i
< nr_heads
; i
++) {
260 const struct ref
*posn
= to_fetch
[i
];
261 if (posn
->status
& REF_STATUS_UPTODATE
)
264 strbuf_addf(&buf
, "fetch %s %s\n",
265 sha1_to_hex(posn
->old_sha1
), posn
->name
);
268 strbuf_addch(&buf
, '\n');
269 sendline(data
, &buf
);
272 recvline(data
, &buf
);
274 if (!prefixcmp(buf
.buf
, "lock ")) {
275 const char *name
= buf
.buf
+ 5;
276 if (transport
->pack_lockfile
)
277 warning("%s also locked %s", data
->name
, name
);
279 transport
->pack_lockfile
= xstrdup(name
);
284 warning("%s unexpectedly said: '%s'", data
->name
, buf
.buf
);
286 strbuf_release(&buf
);
290 static int get_importer(struct transport
*transport
, struct child_process
*fastimport
)
292 struct child_process
*helper
= get_helper(transport
);
293 memset(fastimport
, 0, sizeof(*fastimport
));
294 fastimport
->in
= helper
->out
;
295 fastimport
->argv
= xcalloc(5, sizeof(*fastimport
->argv
));
296 fastimport
->argv
[0] = "fast-import";
297 fastimport
->argv
[1] = "--quiet";
299 fastimport
->git_cmd
= 1;
300 return start_command(fastimport
);
303 static int fetch_with_import(struct transport
*transport
,
304 int nr_heads
, struct ref
**to_fetch
)
306 struct child_process fastimport
;
307 struct helper_data
*data
= transport
->data
;
310 struct strbuf buf
= STRBUF_INIT
;
312 get_helper(transport
);
314 if (get_importer(transport
, &fastimport
))
315 die("Couldn't run fast-import");
317 for (i
= 0; i
< nr_heads
; i
++) {
319 if (posn
->status
& REF_STATUS_UPTODATE
)
322 strbuf_addf(&buf
, "import %s\n", posn
->name
);
323 sendline(data
, &buf
);
326 disconnect_helper(transport
);
327 finish_command(&fastimport
);
328 free(fastimport
.argv
);
329 fastimport
.argv
= NULL
;
331 for (i
= 0; i
< nr_heads
; i
++) {
334 if (posn
->status
& REF_STATUS_UPTODATE
)
337 private = apply_refspecs(data
->refspecs
, data
->refspec_nr
, posn
->name
);
339 private = strdup(posn
->name
);
340 read_ref(private, posn
->old_sha1
);
343 strbuf_release(&buf
);
347 static int fetch(struct transport
*transport
,
348 int nr_heads
, struct ref
**to_fetch
)
350 struct helper_data
*data
= transport
->data
;
354 for (i
= 0; i
< nr_heads
; i
++)
355 if (!(to_fetch
[i
]->status
& REF_STATUS_UPTODATE
))
362 return fetch_with_fetch(transport
, nr_heads
, to_fetch
);
365 return fetch_with_import(transport
, nr_heads
, to_fetch
);
370 static int push_refs(struct transport
*transport
,
371 struct ref
*remote_refs
, int flags
)
373 int force_all
= flags
& TRANSPORT_PUSH_FORCE
;
374 int mirror
= flags
& TRANSPORT_PUSH_MIRROR
;
375 struct helper_data
*data
= transport
->data
;
376 struct strbuf buf
= STRBUF_INIT
;
377 struct child_process
*helper
;
383 helper
= get_helper(transport
);
387 for (ref
= remote_refs
; ref
; ref
= ref
->next
) {
389 hashcpy(ref
->new_sha1
, ref
->peer_ref
->new_sha1
);
393 ref
->deletion
= is_null_sha1(ref
->new_sha1
);
394 if (!ref
->deletion
&&
395 !hashcmp(ref
->old_sha1
, ref
->new_sha1
)) {
396 ref
->status
= REF_STATUS_UPTODATE
;
403 strbuf_addstr(&buf
, "push ");
404 if (!ref
->deletion
) {
406 strbuf_addch(&buf
, '+');
408 strbuf_addstr(&buf
, ref
->peer_ref
->name
);
410 strbuf_addstr(&buf
, sha1_to_hex(ref
->new_sha1
));
412 strbuf_addch(&buf
, ':');
413 strbuf_addstr(&buf
, ref
->name
);
414 strbuf_addch(&buf
, '\n');
419 transport
->verbose
= flags
& TRANSPORT_PUSH_VERBOSE
? 1 : 0;
420 standard_options(transport
);
422 if (flags
& TRANSPORT_PUSH_DRY_RUN
) {
423 if (set_helper_option(transport
, "dry-run", "true") != 0)
424 die("helper %s does not support dry-run", data
->name
);
427 strbuf_addch(&buf
, '\n');
428 sendline(data
, &buf
);
435 recvline(data
, &buf
);
439 if (!prefixcmp(buf
.buf
, "ok ")) {
440 status
= REF_STATUS_OK
;
441 refname
= buf
.buf
+ 3;
442 } else if (!prefixcmp(buf
.buf
, "error ")) {
443 status
= REF_STATUS_REMOTE_REJECT
;
444 refname
= buf
.buf
+ 6;
446 die("expected ok/error, helper said '%s'\n", buf
.buf
);
448 msg
= strchr(refname
, ' ');
450 struct strbuf msg_buf
= STRBUF_INIT
;
454 if (!unquote_c_style(&msg_buf
, msg
, &end
))
455 msg
= strbuf_detach(&msg_buf
, NULL
);
458 strbuf_release(&msg_buf
);
460 if (!strcmp(msg
, "no match")) {
461 status
= REF_STATUS_NONE
;
465 else if (!strcmp(msg
, "up to date")) {
466 status
= REF_STATUS_UPTODATE
;
470 else if (!strcmp(msg
, "non-fast forward")) {
471 status
= REF_STATUS_REJECT_NONFASTFORWARD
;
478 ref
= find_ref_by_name(ref
, refname
);
480 ref
= find_ref_by_name(remote_refs
, refname
);
482 warning("helper reported unexpected status of %s", refname
);
486 ref
->status
= status
;
487 ref
->remote_status
= msg
;
489 strbuf_release(&buf
);
493 static int has_attribute(const char *attrs
, const char *attr
) {
500 const char *space
= strchrnul(attrs
, ' ');
501 if (len
== space
- attrs
&& !strncmp(attrs
, attr
, len
))
509 static struct ref
*get_refs_list(struct transport
*transport
, int for_push
)
511 struct helper_data
*data
= transport
->data
;
512 struct child_process
*helper
;
513 struct ref
*ret
= NULL
;
514 struct ref
**tail
= &ret
;
516 struct strbuf buf
= STRBUF_INIT
;
518 helper
= get_helper(transport
);
520 if (data
->push
&& for_push
)
521 write_str_in_full(helper
->in
, "list for-push\n");
523 write_str_in_full(helper
->in
, "list\n");
527 recvline(data
, &buf
);
532 eov
= strchr(buf
.buf
, ' ');
534 die("Malformed response in ref list: %s", buf
.buf
);
535 eon
= strchr(eov
+ 1, ' ');
539 *tail
= alloc_ref(eov
+ 1);
540 if (buf
.buf
[0] == '@')
541 (*tail
)->symref
= xstrdup(buf
.buf
+ 1);
542 else if (buf
.buf
[0] != '?')
543 get_sha1_hex(buf
.buf
, (*tail
)->old_sha1
);
545 if (has_attribute(eon
+ 1, "unchanged")) {
546 (*tail
)->status
|= REF_STATUS_UPTODATE
;
547 read_ref((*tail
)->name
, (*tail
)->old_sha1
);
550 tail
= &((*tail
)->next
);
553 fprintf(stderr
, "Debug: Read ref listing.\n");
554 strbuf_release(&buf
);
556 for (posn
= ret
; posn
; posn
= posn
->next
)
557 resolve_remote_symref(posn
, ret
);
562 int transport_helper_init(struct transport
*transport
, const char *name
)
564 struct helper_data
*data
= xcalloc(sizeof(*data
), 1);
567 if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
570 transport
->data
= data
;
571 transport
->set_option
= set_helper_option
;
572 transport
->get_refs_list
= get_refs_list
;
573 transport
->fetch
= fetch
;
574 transport
->push_refs
= push_refs
;
575 transport
->disconnect
= release_helper
;