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