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