@@ -18,7 +18,9 @@ struct helper_data
18
18
unsigned fetch : 1 ,
19
19
import : 1 ,
20
20
option : 1 ,
21
- push : 1 ;
21
+ push : 1 ,
22
+ connect : 1 ,
23
+ no_disconnect_req : 1 ;
22
24
/* These go from remote name (as in "list") to private name */
23
25
struct refspec * refspecs ;
24
26
int refspec_nr ;
@@ -37,12 +39,12 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
37
39
die_errno ("Full write to remote helper failed" );
38
40
}
39
41
40
- static int recvline ( struct helper_data * helper , struct strbuf * buffer )
42
+ static int recvline_fh ( FILE * helper , struct strbuf * buffer )
41
43
{
42
44
strbuf_reset (buffer );
43
45
if (debug )
44
46
fprintf (stderr , "Debug: Remote helper: Waiting...\n" );
45
- if (strbuf_getline (buffer , helper -> out , '\n' ) == EOF ) {
47
+ if (strbuf_getline (buffer , helper , '\n' ) == EOF ) {
46
48
if (debug )
47
49
fprintf (stderr , "Debug: Remote helper quit.\n" );
48
50
exit (128 );
@@ -53,6 +55,11 @@ static int recvline(struct helper_data *helper, struct strbuf *buffer)
53
55
return 0 ;
54
56
}
55
57
58
+ static int recvline (struct helper_data * helper , struct strbuf * buffer )
59
+ {
60
+ return recvline_fh (helper -> out , buffer );
61
+ }
62
+
56
63
static void xchgline (struct helper_data * helper , struct strbuf * buffer )
57
64
{
58
65
sendline (helper , buffer );
@@ -77,6 +84,15 @@ const char *remove_ext_force(const char *url)
77
84
return url ;
78
85
}
79
86
87
+ static void do_take_over (struct transport * transport )
88
+ {
89
+ struct helper_data * data ;
90
+ data = (struct helper_data * )transport -> data ;
91
+ transport_take_over (transport , data -> helper );
92
+ fclose (data -> out );
93
+ free (data );
94
+ }
95
+
80
96
static struct child_process * get_helper (struct transport * transport )
81
97
{
82
98
struct helper_data * data = transport -> data ;
@@ -103,12 +119,12 @@ static struct child_process *get_helper(struct transport *transport)
103
119
if (start_command (helper ))
104
120
die ("Unable to run helper: git %s" , helper -> argv [0 ]);
105
121
data -> helper = helper ;
122
+ data -> no_disconnect_req = 0 ;
106
123
107
124
/*
108
125
* Open the output as FILE* so strbuf_getline() can be used.
109
126
* Do this with duped fd because fclose() will close the fd,
110
127
* and stuff like taking over will require the fd to remain.
111
- *
112
128
*/
113
129
duped = dup (helper -> out );
114
130
if (duped < 0 )
@@ -146,6 +162,8 @@ static struct child_process *get_helper(struct transport *transport)
146
162
refspec_nr + 1 ,
147
163
refspec_alloc );
148
164
refspecs [refspec_nr ++ ] = strdup (buf .buf + strlen ("refspec " ));
165
+ } else if (!strcmp (capname , "connect" )) {
166
+ data -> connect = 1 ;
149
167
} else if (mandatory ) {
150
168
die ("Unknown madatory capability %s. This remote "
151
169
"helper probably needs newer version of Git.\n" ,
@@ -175,8 +193,10 @@ static int disconnect_helper(struct transport *transport)
175
193
if (data -> helper ) {
176
194
if (debug )
177
195
fprintf (stderr , "Debug: Disconnecting.\n" );
178
- strbuf_addf (& buf , "\n" );
179
- sendline (data , & buf );
196
+ if (!data -> no_disconnect_req ) {
197
+ strbuf_addf (& buf , "\n" );
198
+ sendline (data , & buf );
199
+ }
180
200
close (data -> helper -> in );
181
201
close (data -> helper -> out );
182
202
fclose (data -> out );
@@ -370,12 +390,94 @@ static int fetch_with_import(struct transport *transport,
370
390
return 0 ;
371
391
}
372
392
393
+ static int process_connect_service (struct transport * transport ,
394
+ const char * name , const char * exec )
395
+ {
396
+ struct helper_data * data = transport -> data ;
397
+ struct strbuf cmdbuf = STRBUF_INIT ;
398
+ struct child_process * helper ;
399
+ int r , duped , ret = 0 ;
400
+ FILE * input ;
401
+
402
+ helper = get_helper (transport );
403
+
404
+ /*
405
+ * Yes, dup the pipe another time, as we need unbuffered version
406
+ * of input pipe as FILE*. fclose() closes the underlying fd and
407
+ * stream buffering only can be changed before first I/O operation
408
+ * on it.
409
+ */
410
+ duped = dup (helper -> out );
411
+ if (duped < 0 )
412
+ die_errno ("Can't dup helper output fd" );
413
+ input = xfdopen (duped , "r" );
414
+ setvbuf (input , NULL , _IONBF , 0 );
415
+
416
+ /*
417
+ * Handle --upload-pack and friends. This is fire and forget...
418
+ * just warn if it fails.
419
+ */
420
+ if (strcmp (name , exec )) {
421
+ r = set_helper_option (transport , "servpath" , exec );
422
+ if (r > 0 )
423
+ warning ("Setting remote service path not supported by protocol." );
424
+ else if (r < 0 )
425
+ warning ("Invalid remote service path." );
426
+ }
427
+
428
+ if (data -> connect )
429
+ strbuf_addf (& cmdbuf , "connect %s\n" , name );
430
+ else
431
+ goto exit ;
432
+
433
+ sendline (data , & cmdbuf );
434
+ recvline_fh (input , & cmdbuf );
435
+ if (!strcmp (cmdbuf .buf , "" )) {
436
+ data -> no_disconnect_req = 1 ;
437
+ if (debug )
438
+ fprintf (stderr , "Debug: Smart transport connection "
439
+ "ready.\n" );
440
+ ret = 1 ;
441
+ } else if (!strcmp (cmdbuf .buf , "fallback" )) {
442
+ if (debug )
443
+ fprintf (stderr , "Debug: Falling back to dumb "
444
+ "transport.\n" );
445
+ } else
446
+ die ("Unknown response to connect: %s" ,
447
+ cmdbuf .buf );
448
+
449
+ exit :
450
+ fclose (input );
451
+ return ret ;
452
+ }
453
+
454
+ static int process_connect (struct transport * transport ,
455
+ int for_push )
456
+ {
457
+ struct helper_data * data = transport -> data ;
458
+ const char * name ;
459
+ const char * exec ;
460
+
461
+ name = for_push ? "git-receive-pack" : "git-upload-pack" ;
462
+ if (for_push )
463
+ exec = data -> transport_options .receivepack ;
464
+ else
465
+ exec = data -> transport_options .uploadpack ;
466
+
467
+ return process_connect_service (transport , name , exec );
468
+ }
469
+
373
470
static int fetch (struct transport * transport ,
374
471
int nr_heads , struct ref * * to_fetch )
375
472
{
376
473
struct helper_data * data = transport -> data ;
377
474
int i , count ;
378
475
476
+ if (process_connect (transport , 0 )) {
477
+ do_take_over (transport );
478
+ return transport -> fetch (transport , nr_heads , to_fetch );
479
+ }
480
+
379
481
count = 0 ;
380
482
for (i = 0 ; i < nr_heads ; i ++ )
381
483
if (!(to_fetch [i ]-> status & REF_STATUS_UPTODATE ))
@@ -403,6 +505,11 @@ static int push_refs(struct transport *transport,
403
505
struct child_process * helper ;
404
506
struct ref * ref ;
405
507
508
+ if (process_connect (transport , 1 )) {
509
+ do_take_over (transport );
510
+ return transport -> push_refs (transport , remote_refs , flags );
511
+ }
512
+
406
513
if (!remote_refs )
407
514
return 0 ;
408
515
@@ -543,6 +650,11 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
543
650
544
651
helper = get_helper (transport );
545
652
653
+ if (process_connect (transport , for_push )) {
654
+ do_take_over (transport );
655
+ return transport -> get_refs_list (transport , for_push );
656
+ }
657
+
546
658
if (data -> push && for_push )
547
659
write_str_in_full (helper -> in , "list for-push\n" );
548
660
else
0 commit comments