Merge branch 'cb/t3404-shellquote' into maint
[git] / builtin / fetch-pack.c
1 #include "builtin.h"
2 #include "pkt-line.h"
3 #include "fetch-pack.h"
4 #include "remote.h"
5 #include "connect.h"
6 #include "sha1-array.h"
7
8 static const char fetch_pack_usage[] =
9 "git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] "
10 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
11 "[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
12
13 static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
14                                  const char *name, int namelen)
15 {
16         struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
17         unsigned char sha1[20];
18
19         if (namelen > 41 && name[40] == ' ' && !get_sha1_hex(name, sha1)) {
20                 hashcpy(ref->old_sha1, sha1);
21                 name += 41;
22                 namelen -= 41;
23         }
24
25         memcpy(ref->name, name, namelen);
26         ref->name[namelen] = '\0';
27         (*nr)++;
28         ALLOC_GROW(*sought, *nr, *alloc);
29         (*sought)[*nr - 1] = ref;
30 }
31
32 static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
33                              const char *string)
34 {
35         add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
36 }
37
38 int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
39 {
40         int i, ret;
41         struct ref *ref = NULL;
42         const char *dest = NULL;
43         struct ref **sought = NULL;
44         int nr_sought = 0, alloc_sought = 0;
45         int fd[2];
46         char *pack_lockfile = NULL;
47         char **pack_lockfile_ptr = NULL;
48         struct child_process *conn;
49         struct fetch_pack_args args;
50         struct sha1_array shallow = SHA1_ARRAY_INIT;
51
52         packet_trace_identity("fetch-pack");
53
54         memset(&args, 0, sizeof(args));
55         args.uploadpack = "git-upload-pack";
56
57         for (i = 1; i < argc && *argv[i] == '-'; i++) {
58                 const char *arg = argv[i];
59
60                 if (starts_with(arg, "--upload-pack=")) {
61                         args.uploadpack = arg + 14;
62                         continue;
63                 }
64                 if (starts_with(arg, "--exec=")) {
65                         args.uploadpack = arg + 7;
66                         continue;
67                 }
68                 if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
69                         args.quiet = 1;
70                         continue;
71                 }
72                 if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
73                         args.lock_pack = args.keep_pack;
74                         args.keep_pack = 1;
75                         continue;
76                 }
77                 if (!strcmp("--thin", arg)) {
78                         args.use_thin_pack = 1;
79                         continue;
80                 }
81                 if (!strcmp("--include-tag", arg)) {
82                         args.include_tag = 1;
83                         continue;
84                 }
85                 if (!strcmp("--all", arg)) {
86                         args.fetch_all = 1;
87                         continue;
88                 }
89                 if (!strcmp("--stdin", arg)) {
90                         args.stdin_refs = 1;
91                         continue;
92                 }
93                 if (!strcmp("--diag-url", arg)) {
94                         args.diag_url = 1;
95                         continue;
96                 }
97                 if (!strcmp("-v", arg)) {
98                         args.verbose = 1;
99                         continue;
100                 }
101                 if (starts_with(arg, "--depth=")) {
102                         args.depth = strtol(arg + 8, NULL, 0);
103                         continue;
104                 }
105                 if (!strcmp("--no-progress", arg)) {
106                         args.no_progress = 1;
107                         continue;
108                 }
109                 if (!strcmp("--stateless-rpc", arg)) {
110                         args.stateless_rpc = 1;
111                         continue;
112                 }
113                 if (!strcmp("--lock-pack", arg)) {
114                         args.lock_pack = 1;
115                         pack_lockfile_ptr = &pack_lockfile;
116                         continue;
117                 }
118                 if (!strcmp("--check-self-contained-and-connected", arg)) {
119                         args.check_self_contained_and_connected = 1;
120                         continue;
121                 }
122                 if (!strcmp("--cloning", arg)) {
123                         args.cloning = 1;
124                         continue;
125                 }
126                 if (!strcmp("--update-shallow", arg)) {
127                         args.update_shallow = 1;
128                         continue;
129                 }
130                 usage(fetch_pack_usage);
131         }
132
133         if (i < argc)
134                 dest = argv[i++];
135         else
136                 usage(fetch_pack_usage);
137
138         /*
139          * Copy refs from cmdline to growable list, then append any
140          * refs from the standard input:
141          */
142         for (; i < argc; i++)
143                 add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
144         if (args.stdin_refs) {
145                 if (args.stateless_rpc) {
146                         /* in stateless RPC mode we use pkt-line to read
147                          * from stdin, until we get a flush packet
148                          */
149                         for (;;) {
150                                 char *line = packet_read_line(0, NULL);
151                                 if (!line)
152                                         break;
153                                 add_sought_entry(&sought, &nr_sought,  &alloc_sought, line);
154                         }
155                 }
156                 else {
157                         /* read from stdin one ref per line, until EOF */
158                         struct strbuf line = STRBUF_INIT;
159                         while (strbuf_getline(&line, stdin, '\n') != EOF)
160                                 add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
161                         strbuf_release(&line);
162                 }
163         }
164
165         if (args.stateless_rpc) {
166                 conn = NULL;
167                 fd[0] = 0;
168                 fd[1] = 1;
169         } else {
170                 int flags = args.verbose ? CONNECT_VERBOSE : 0;
171                 if (args.diag_url)
172                         flags |= CONNECT_DIAG_URL;
173                 conn = git_connect(fd, dest, args.uploadpack,
174                                    flags);
175                 if (!conn)
176                         return args.diag_url ? 0 : 1;
177         }
178         get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
179
180         ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
181                          &shallow, pack_lockfile_ptr);
182         if (pack_lockfile) {
183                 printf("lock %s\n", pack_lockfile);
184                 fflush(stdout);
185         }
186         if (args.check_self_contained_and_connected &&
187             args.self_contained_and_connected) {
188                 printf("connectivity-ok\n");
189                 fflush(stdout);
190         }
191         close(fd[0]);
192         close(fd[1]);
193         if (finish_connect(conn))
194                 return 1;
195
196         ret = !ref;
197
198         /*
199          * If the heads to pull were given, we should have consumed
200          * all of them by matching the remote.  Otherwise, 'git fetch
201          * remote no-such-ref' would silently succeed without issuing
202          * an error.
203          */
204         for (i = 0; i < nr_sought; i++) {
205                 if (!sought[i] || sought[i]->matched)
206                         continue;
207                 error("no such remote ref %s", sought[i]->name);
208                 ret = 1;
209         }
210
211         while (ref) {
212                 printf("%s %s\n",
213                        sha1_to_hex(ref->old_sha1), ref->name);
214                 ref = ref->next;
215         }
216
217         return ret;
218 }