Skip to content

Commit 6eb996b

Browse files
iabervongitster
authored andcommitted
Add support for external programs for handling native fetches
transport_get() can call transport_native_helper_init() to have list and fetch-ref operations handled by running a separate program as: git remote-<something> <remote> [<url>] This program then accepts, on its stdin, "list" and "fetch <hex> <name>" commands; the former prints out a list of available refs and either their hashes or what they are symrefs to, while the latter fetches them into the local object database and prints a newline when done. Signed-off-by: Daniel Barkalow <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 07a4a3b commit 6eb996b

File tree

4 files changed

+243
-0
lines changed

4 files changed

+243
-0
lines changed

Documentation/git-remote-helpers.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
git-remote-helpers(1)
2+
=====================
3+
4+
NAME
5+
----
6+
git-remote-helpers - Helper programs for interoperation with remote git
7+
8+
SYNOPSIS
9+
--------
10+
'git remote-<transport>' <remote>
11+
12+
DESCRIPTION
13+
-----------
14+
15+
These programs are normally not used directly by end users, but are
16+
invoked by various git programs that interact with remote repositories
17+
when the repository they would operate on will be accessed using
18+
transport code not linked into the main git binary. Various particular
19+
helper programs will behave as documented here.
20+
21+
COMMANDS
22+
--------
23+
24+
Commands are given by the caller on the helper's standard input, one per line.
25+
26+
'capabilities'::
27+
Lists the capabilities of the helper, one per line, ending
28+
with a blank line.
29+
30+
'list'::
31+
Lists the refs, one per line, in the format "<value> <name>
32+
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
33+
a symref, or "?" to indicate that the helper could not get the
34+
value of the ref. A space-separated list of attributes follows
35+
the name; unrecognized attributes are ignored. After the
36+
complete list, outputs a blank line.
37+
38+
'fetch' <sha1> <name>::
39+
Fetches the given object, writing the necessary objects to the
40+
database. Outputs a blank line when the fetch is
41+
complete. Only objects which were reported in the ref list
42+
with a sha1 may be fetched this way.
43+
+
44+
Supported if the helper has the "fetch" capability.
45+
46+
If a fatal error occurs, the program writes the error message to
47+
stderr and exits. The caller should expect that a suitable error
48+
message has been printed if the child closes the connection without
49+
completing a valid response for the current command.
50+
51+
Additional commands may be supported, as may be determined from
52+
capabilities reported by the helper.
53+
54+
CAPABILITIES
55+
------------
56+
57+
'fetch'::
58+
This helper supports the 'fetch' command.
59+
60+
REF LIST ATTRIBUTES
61+
-------------------
62+
63+
None are defined yet, but the caller must accept any which are supplied.
64+
65+
Documentation
66+
-------------
67+
Documentation by Daniel Barkalow.
68+
69+
GIT
70+
---
71+
Part of the linkgit:git[1] suite

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ LIB_OBJS += symlinks.o
549549
LIB_OBJS += tag.o
550550
LIB_OBJS += trace.o
551551
LIB_OBJS += transport.o
552+
LIB_OBJS += transport-helper.o
552553
LIB_OBJS += tree-diff.o
553554
LIB_OBJS += tree.o
554555
LIB_OBJS += tree-walk.o

transport-helper.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#include "cache.h"
2+
#include "transport.h"
3+
4+
#include "run-command.h"
5+
#include "commit.h"
6+
#include "diff.h"
7+
#include "revision.h"
8+
9+
struct helper_data
10+
{
11+
const char *name;
12+
struct child_process *helper;
13+
unsigned fetch : 1;
14+
};
15+
16+
static struct child_process *get_helper(struct transport *transport)
17+
{
18+
struct helper_data *data = transport->data;
19+
struct strbuf buf = STRBUF_INIT;
20+
struct child_process *helper;
21+
FILE *file;
22+
23+
if (data->helper)
24+
return data->helper;
25+
26+
helper = xcalloc(1, sizeof(*helper));
27+
helper->in = -1;
28+
helper->out = -1;
29+
helper->err = 0;
30+
helper->argv = xcalloc(4, sizeof(*helper->argv));
31+
strbuf_addf(&buf, "remote-%s", data->name);
32+
helper->argv[0] = strbuf_detach(&buf, NULL);
33+
helper->argv[1] = transport->remote->name;
34+
helper->argv[2] = transport->url;
35+
helper->git_cmd = 1;
36+
if (start_command(helper))
37+
die("Unable to run helper: git %s", helper->argv[0]);
38+
data->helper = helper;
39+
40+
write_in_full(data->helper->in, "capabilities\n", 13);
41+
file = fdopen(helper->out, "r");
42+
while (1) {
43+
if (strbuf_getline(&buf, file, '\n') == EOF)
44+
exit(128); /* child died, message supplied already */
45+
46+
if (!*buf.buf)
47+
break;
48+
if (!strcmp(buf.buf, "fetch"))
49+
data->fetch = 1;
50+
}
51+
return data->helper;
52+
}
53+
54+
static int disconnect_helper(struct transport *transport)
55+
{
56+
struct helper_data *data = transport->data;
57+
if (data->helper) {
58+
write_in_full(data->helper->in, "\n", 1);
59+
close(data->helper->in);
60+
finish_command(data->helper);
61+
free((char *)data->helper->argv[0]);
62+
free(data->helper->argv);
63+
free(data->helper);
64+
data->helper = NULL;
65+
}
66+
return 0;
67+
}
68+
69+
static int fetch_with_fetch(struct transport *transport,
70+
int nr_heads, const struct ref **to_fetch)
71+
{
72+
struct child_process *helper = get_helper(transport);
73+
FILE *file = fdopen(helper->out, "r");
74+
int i;
75+
struct strbuf buf = STRBUF_INIT;
76+
77+
for (i = 0; i < nr_heads; i++) {
78+
struct ref *posn = to_fetch[i];
79+
if (posn->status & REF_STATUS_UPTODATE)
80+
continue;
81+
write_in_full(helper->in, "fetch ", 6);
82+
write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40);
83+
write_in_full(helper->in, " ", 1);
84+
write_in_full(helper->in, posn->name, strlen(posn->name));
85+
write_in_full(helper->in, "\n", 1);
86+
if (strbuf_getline(&buf, file, '\n') == EOF)
87+
exit(128); /* child died, message supplied already */
88+
}
89+
return 0;
90+
}
91+
92+
static int fetch(struct transport *transport,
93+
int nr_heads, const struct ref **to_fetch)
94+
{
95+
struct helper_data *data = transport->data;
96+
int i, count;
97+
98+
count = 0;
99+
for (i = 0; i < nr_heads; i++)
100+
if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
101+
count++;
102+
103+
if (!count)
104+
return 0;
105+
106+
if (data->fetch)
107+
return fetch_with_fetch(transport, nr_heads, to_fetch);
108+
109+
return -1;
110+
}
111+
112+
static struct ref *get_refs_list(struct transport *transport, int for_push)
113+
{
114+
struct child_process *helper;
115+
struct ref *ret = NULL;
116+
struct ref **tail = &ret;
117+
struct ref *posn;
118+
struct strbuf buf = STRBUF_INIT;
119+
FILE *file;
120+
121+
helper = get_helper(transport);
122+
write_in_full(helper->in, "list\n", 5);
123+
124+
file = fdopen(helper->out, "r");
125+
while (1) {
126+
char *eov, *eon;
127+
if (strbuf_getline(&buf, file, '\n') == EOF)
128+
exit(128); /* child died, message supplied already */
129+
130+
if (!*buf.buf)
131+
break;
132+
133+
eov = strchr(buf.buf, ' ');
134+
if (!eov)
135+
die("Malformed response in ref list: %s", buf.buf);
136+
eon = strchr(eov + 1, ' ');
137+
*eov = '\0';
138+
if (eon)
139+
*eon = '\0';
140+
*tail = alloc_ref(eov + 1);
141+
if (buf.buf[0] == '@')
142+
(*tail)->symref = xstrdup(buf.buf + 1);
143+
else if (buf.buf[0] != '?')
144+
get_sha1_hex(buf.buf, (*tail)->old_sha1);
145+
tail = &((*tail)->next);
146+
}
147+
strbuf_release(&buf);
148+
149+
for (posn = ret; posn; posn = posn->next)
150+
resolve_remote_symref(posn, ret);
151+
152+
return ret;
153+
}
154+
155+
int transport_helper_init(struct transport *transport)
156+
{
157+
struct helper_data *data = xcalloc(sizeof(*data), 1);
158+
char *eom = strchr(transport->url, ':');
159+
if (!eom)
160+
return -1;
161+
data->name = xstrndup(transport->url, eom - transport->url);
162+
163+
transport->data = data;
164+
transport->get_refs_list = get_refs_list;
165+
transport->fetch = fetch;
166+
transport->disconnect = disconnect_helper;
167+
return 0;
168+
}

transport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,7 @@ void transport_unlock_pack(struct transport *transport);
7777
int transport_disconnect(struct transport *transport);
7878
char *transport_anonymize_url(const char *url);
7979

80+
/* Transport methods defined outside transport.c */
81+
int transport_helper_init(struct transport *transport);
82+
8083
#endif

0 commit comments

Comments
 (0)