]>
Commit | Line | Data |
---|---|---|
6eb996b5 DB |
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; | |
292ce46b | 13 | FILE *out; |
6eb996b5 DB |
14 | unsigned fetch : 1; |
15 | }; | |
16 | ||
17 | static struct child_process *get_helper(struct transport *transport) | |
18 | { | |
19 | struct helper_data *data = transport->data; | |
20 | struct strbuf buf = STRBUF_INIT; | |
21 | struct child_process *helper; | |
6eb996b5 DB |
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 | ||
3d913526 | 40 | write_str_in_full(helper->in, "capabilities\n"); |
2d14d65c | 41 | |
292ce46b | 42 | data->out = xfdopen(helper->out, "r"); |
6eb996b5 | 43 | while (1) { |
292ce46b | 44 | if (strbuf_getline(&buf, data->out, '\n') == EOF) |
6eb996b5 DB |
45 | exit(128); /* child died, message supplied already */ |
46 | ||
47 | if (!*buf.buf) | |
48 | break; | |
49 | if (!strcmp(buf.buf, "fetch")) | |
50 | data->fetch = 1; | |
51 | } | |
52 | return data->helper; | |
53 | } | |
54 | ||
55 | static int disconnect_helper(struct transport *transport) | |
56 | { | |
57 | struct helper_data *data = transport->data; | |
58 | if (data->helper) { | |
3d913526 | 59 | write_str_in_full(data->helper->in, "\n"); |
6eb996b5 | 60 | close(data->helper->in); |
292ce46b | 61 | fclose(data->out); |
6eb996b5 DB |
62 | finish_command(data->helper); |
63 | free((char *)data->helper->argv[0]); | |
64 | free(data->helper->argv); | |
65 | free(data->helper); | |
66 | data->helper = NULL; | |
67 | } | |
68 | return 0; | |
69 | } | |
70 | ||
71 | static int fetch_with_fetch(struct transport *transport, | |
72 | int nr_heads, const struct ref **to_fetch) | |
73 | { | |
292ce46b | 74 | struct helper_data *data = transport->data; |
6eb996b5 DB |
75 | int i; |
76 | struct strbuf buf = STRBUF_INIT; | |
77 | ||
78 | for (i = 0; i < nr_heads; i++) { | |
1088261f | 79 | const struct ref *posn = to_fetch[i]; |
6eb996b5 DB |
80 | if (posn->status & REF_STATUS_UPTODATE) |
81 | continue; | |
2d14d65c DB |
82 | |
83 | strbuf_addf(&buf, "fetch %s %s\n", | |
84 | sha1_to_hex(posn->old_sha1), posn->name); | |
292ce46b | 85 | } |
2d14d65c | 86 | |
292ce46b SP |
87 | strbuf_addch(&buf, '\n'); |
88 | if (write_in_full(data->helper->in, buf.buf, buf.len) != buf.len) | |
89 | die_errno("cannot send fetch to %s", data->name); | |
90 | ||
91 | while (1) { | |
92 | strbuf_reset(&buf); | |
93 | if (strbuf_getline(&buf, data->out, '\n') == EOF) | |
6eb996b5 | 94 | exit(128); /* child died, message supplied already */ |
292ce46b SP |
95 | |
96 | if (!prefixcmp(buf.buf, "lock ")) { | |
97 | const char *name = buf.buf + 5; | |
98 | if (transport->pack_lockfile) | |
99 | warning("%s also locked %s", data->name, name); | |
100 | else | |
101 | transport->pack_lockfile = xstrdup(name); | |
102 | } | |
103 | else if (!buf.len) | |
104 | break; | |
105 | else | |
106 | warning("%s unexpectedly said: '%s'", data->name, buf.buf); | |
6eb996b5 | 107 | } |
292ce46b | 108 | strbuf_release(&buf); |
6eb996b5 DB |
109 | return 0; |
110 | } | |
111 | ||
112 | static int fetch(struct transport *transport, | |
113 | int nr_heads, const struct ref **to_fetch) | |
114 | { | |
115 | struct helper_data *data = transport->data; | |
116 | int i, count; | |
117 | ||
118 | count = 0; | |
119 | for (i = 0; i < nr_heads; i++) | |
120 | if (!(to_fetch[i]->status & REF_STATUS_UPTODATE)) | |
121 | count++; | |
122 | ||
123 | if (!count) | |
124 | return 0; | |
125 | ||
126 | if (data->fetch) | |
127 | return fetch_with_fetch(transport, nr_heads, to_fetch); | |
128 | ||
129 | return -1; | |
130 | } | |
131 | ||
132 | static struct ref *get_refs_list(struct transport *transport, int for_push) | |
133 | { | |
292ce46b | 134 | struct helper_data *data = transport->data; |
6eb996b5 DB |
135 | struct child_process *helper; |
136 | struct ref *ret = NULL; | |
137 | struct ref **tail = &ret; | |
138 | struct ref *posn; | |
139 | struct strbuf buf = STRBUF_INIT; | |
6eb996b5 DB |
140 | |
141 | helper = get_helper(transport); | |
2d14d65c | 142 | |
3d913526 | 143 | write_str_in_full(helper->in, "list\n"); |
6eb996b5 | 144 | |
6eb996b5 DB |
145 | while (1) { |
146 | char *eov, *eon; | |
292ce46b | 147 | if (strbuf_getline(&buf, data->out, '\n') == EOF) |
6eb996b5 DB |
148 | exit(128); /* child died, message supplied already */ |
149 | ||
150 | if (!*buf.buf) | |
151 | break; | |
152 | ||
153 | eov = strchr(buf.buf, ' '); | |
154 | if (!eov) | |
155 | die("Malformed response in ref list: %s", buf.buf); | |
156 | eon = strchr(eov + 1, ' '); | |
157 | *eov = '\0'; | |
158 | if (eon) | |
159 | *eon = '\0'; | |
160 | *tail = alloc_ref(eov + 1); | |
161 | if (buf.buf[0] == '@') | |
162 | (*tail)->symref = xstrdup(buf.buf + 1); | |
163 | else if (buf.buf[0] != '?') | |
164 | get_sha1_hex(buf.buf, (*tail)->old_sha1); | |
165 | tail = &((*tail)->next); | |
166 | } | |
167 | strbuf_release(&buf); | |
168 | ||
169 | for (posn = ret; posn; posn = posn->next) | |
170 | resolve_remote_symref(posn, ret); | |
171 | ||
172 | return ret; | |
173 | } | |
174 | ||
c9e388bb | 175 | int transport_helper_init(struct transport *transport, const char *name) |
6eb996b5 DB |
176 | { |
177 | struct helper_data *data = xcalloc(sizeof(*data), 1); | |
c9e388bb | 178 | data->name = name; |
6eb996b5 DB |
179 | |
180 | transport->data = data; | |
181 | transport->get_refs_list = get_refs_list; | |
182 | transport->fetch = fetch; | |
183 | transport->disconnect = disconnect_helper; | |
184 | return 0; | |
185 | } |