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 <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Daniel Barkalow committed
Aug 5, 2009 at 01:01 UTC
6eb996b5707b6d14cf9875a9231f4e909a443665
4 files changed
+243
Documentation/git-remote-helpers.txt
new
+71
@@ -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
+1
@@ -549,6 +549,7 @@ LIB_OBJS += symlinks.o
549
LIB_OBJS += tag.o
550
LIB_OBJS += trace.o
551
LIB_OBJS += transport.o
552
+LIB_OBJS += transport-helper.o
553
LIB_OBJS += tree-diff.o
554
LIB_OBJS += tree.o
555
LIB_OBJS += tree-walk.o
transport-helper.c
new
+168
@@ -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
+3
@@ -77,4 +77,7 @@ void transport_unlock_pack(struct transport *transport);
77
int transport_disconnect(struct transport *transport);
78
char *transport_anonymize_url(const char *url);
79
80
+/* Transport methods defined outside transport.c */
81
+int transport_helper_init(struct transport *transport);
82
+
83
#endif