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