Merge branch 'jk/reflog-date' into next
[git] / transport-helper.c
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_str_in_full(helper->in, "capabilities\n");
41
42         file = xfdopen(helper->out, "r");
43         while (1) {
44                 if (strbuf_getline(&buf, file, '\n') == EOF)
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) {
59                 write_str_in_full(data->helper->in, "\n");
60                 close(data->helper->in);
61                 finish_command(data->helper);
62                 free((char *)data->helper->argv[0]);
63                 free(data->helper->argv);
64                 free(data->helper);
65                 data->helper = NULL;
66         }
67         return 0;
68 }
69
70 static int fetch_with_fetch(struct transport *transport,
71                             int nr_heads, const struct ref **to_fetch)
72 {
73         struct child_process *helper = get_helper(transport);
74         FILE *file = xfdopen(helper->out, "r");
75         int i;
76         struct strbuf buf = STRBUF_INIT;
77
78         for (i = 0; i < nr_heads; i++) {
79                 const struct ref *posn = to_fetch[i];
80                 if (posn->status & REF_STATUS_UPTODATE)
81                         continue;
82
83                 strbuf_addf(&buf, "fetch %s %s\n",
84                             sha1_to_hex(posn->old_sha1), posn->name);
85                 write_in_full(helper->in, buf.buf, buf.len);
86                 strbuf_reset(&buf);
87
88                 if (strbuf_getline(&buf, file, '\n') == EOF)
89                         exit(128); /* child died, message supplied already */
90         }
91         return 0;
92 }
93
94 static int fetch(struct transport *transport,
95                  int nr_heads, const struct ref **to_fetch)
96 {
97         struct helper_data *data = transport->data;
98         int i, count;
99
100         count = 0;
101         for (i = 0; i < nr_heads; i++)
102                 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
103                         count++;
104
105         if (!count)
106                 return 0;
107
108         if (data->fetch)
109                 return fetch_with_fetch(transport, nr_heads, to_fetch);
110
111         return -1;
112 }
113
114 static struct ref *get_refs_list(struct transport *transport, int for_push)
115 {
116         struct child_process *helper;
117         struct ref *ret = NULL;
118         struct ref **tail = &ret;
119         struct ref *posn;
120         struct strbuf buf = STRBUF_INIT;
121         FILE *file;
122
123         helper = get_helper(transport);
124
125         write_str_in_full(helper->in, "list\n");
126
127         file = xfdopen(helper->out, "r");
128         while (1) {
129                 char *eov, *eon;
130                 if (strbuf_getline(&buf, file, '\n') == EOF)
131                         exit(128); /* child died, message supplied already */
132
133                 if (!*buf.buf)
134                         break;
135
136                 eov = strchr(buf.buf, ' ');
137                 if (!eov)
138                         die("Malformed response in ref list: %s", buf.buf);
139                 eon = strchr(eov + 1, ' ');
140                 *eov = '\0';
141                 if (eon)
142                         *eon = '\0';
143                 *tail = alloc_ref(eov + 1);
144                 if (buf.buf[0] == '@')
145                         (*tail)->symref = xstrdup(buf.buf + 1);
146                 else if (buf.buf[0] != '?')
147                         get_sha1_hex(buf.buf, (*tail)->old_sha1);
148                 tail = &((*tail)->next);
149         }
150         strbuf_release(&buf);
151
152         for (posn = ret; posn; posn = posn->next)
153                 resolve_remote_symref(posn, ret);
154
155         return ret;
156 }
157
158 int transport_helper_init(struct transport *transport, const char *name)
159 {
160         struct helper_data *data = xcalloc(sizeof(*data), 1);
161         data->name = name;
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 }