Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2 #include "builtin.h"
3 #include "abspath.h"
4 #include "config.h"
5 #include "environment.h"
6 #include "gettext.h"
7 #include "parse-options.h"
8 #include "midx.h"
9 #include "strbuf.h"
10 #include "trace2.h"
11 #include "odb.h"
12 #include "odb/source.h"
13 #include "replace-object.h"
14 #include "repository.h"
15
16 #define BUILTIN_MIDX_WRITE_USAGE \
17 N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]\n" \
18 " [--[no-]bitmap] [--[no-]incremental] [--[no-]stdin-packs]\n" \
19 " [--refs-snapshot=<path>] [--[no-]write-chain-file]\n" \
20 " [--base=<checksum>]")
21
22 #define BUILTIN_MIDX_COMPACT_USAGE \
23 N_("git multi-pack-index [<options>] compact [--[no-]incremental]\n" \
24 " [--[no-]bitmap] [--base=<checksum>] [--[no-]write-chain-file]\n" \
25 " <from> <to>")
26
27 #define BUILTIN_MIDX_VERIFY_USAGE \
28 N_("git multi-pack-index [<options>] verify")
29
30 #define BUILTIN_MIDX_EXPIRE_USAGE \
31 N_("git multi-pack-index [<options>] expire")
32
33 #define BUILTIN_MIDX_REPACK_USAGE \
34 N_("git multi-pack-index [<options>] repack [--batch-size=<size>]")
35
36 static char const * const builtin_multi_pack_index_write_usage[] = {
37 BUILTIN_MIDX_WRITE_USAGE,
38 NULL
39 };
40 static char const * const builtin_multi_pack_index_compact_usage[] = {
41 BUILTIN_MIDX_COMPACT_USAGE,
42 NULL
43 };
44 static char const * const builtin_multi_pack_index_verify_usage[] = {
45 BUILTIN_MIDX_VERIFY_USAGE,
46 NULL
47 };
48 static char const * const builtin_multi_pack_index_expire_usage[] = {
49 BUILTIN_MIDX_EXPIRE_USAGE,
50 NULL
51 };
52 static char const * const builtin_multi_pack_index_repack_usage[] = {
53 BUILTIN_MIDX_REPACK_USAGE,
54 NULL
55 };
56 static char const * const builtin_multi_pack_index_usage[] = {
57 BUILTIN_MIDX_WRITE_USAGE,
58 BUILTIN_MIDX_COMPACT_USAGE,
59 BUILTIN_MIDX_VERIFY_USAGE,
60 BUILTIN_MIDX_EXPIRE_USAGE,
61 BUILTIN_MIDX_REPACK_USAGE,
62 NULL
63 };
64
65 static struct opts_multi_pack_index {
66 char *object_dir;
67 const char *preferred_pack;
68 const char *incremental_base;
69 char *refs_snapshot;
70 unsigned long batch_size;
71 unsigned flags;
72 int stdin_packs;
73 } opts;
74
75
76 static int parse_object_dir(const struct option *opt, const char *arg,
77 int unset)
78 {
79 char **value = opt->value;
80 free(*value);
81 if (unset)
82 *value = xstrdup(the_repository->objects->sources->path);
83 else
84 *value = real_pathdup(arg, 1);
85 return 0;
86 }
87
88 static struct odb_source *handle_object_dir_option(struct repository *repo)
89 {
90 struct odb_source *source = odb_find_source(repo->objects, opts.object_dir);
91 if (!source)
92 source = odb_add_to_alternates_memory(repo->objects, opts.object_dir);
93 return source;
94 }
95
96 static struct option common_opts[] = {
97 OPT_CALLBACK(0, "object-dir", &opts.object_dir,
98 N_("directory"),
99 N_("object directory containing set of packfile and pack-index pairs"),
100 parse_object_dir),
101 OPT_BIT(0, "progress", &opts.flags, N_("force progress reporting"),
102 MIDX_PROGRESS),
103 OPT_END(),
104 };
105
106 static struct option *add_common_options(struct option *prev)
107 {
108 return parse_options_concat(common_opts, prev);
109 }
110
111 static int git_multi_pack_index_write_config(const char *var, const char *value,
112 const struct config_context *ctx UNUSED,
113 void *cb UNUSED)
114 {
115 if (!strcmp(var, "pack.writebitmaphashcache")) {
116 if (git_config_bool(var, value))
117 opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
118 else
119 opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE;
120 }
121
122 if (!strcmp(var, "pack.writebitmaplookuptable")) {
123 if (git_config_bool(var, value))
124 opts.flags |= MIDX_WRITE_BITMAP_LOOKUP_TABLE;
125 else
126 opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE;
127 }
128
129 /*
130 * We should never make a fall-back call to 'git_default_config', since
131 * this was already called in 'cmd_multi_pack_index()'.
132 */
133 return 0;
134 }
135
136 static void read_packs_from_stdin(struct string_list *to)
137 {
138 struct strbuf buf = STRBUF_INIT;
139 while (strbuf_getline(&buf, stdin) != EOF)
140 string_list_append(to, buf.buf);
141 string_list_sort(to);
142
143 strbuf_release(&buf);
144 }
145
146 static int cmd_multi_pack_index_write(int argc, const char **argv,
147 const char *prefix,
148 struct repository *repo)
149 {
150 struct option *options;
151 static struct option builtin_multi_pack_index_write_options[] = {
152 OPT_STRING(0, "preferred-pack", &opts.preferred_pack,
153 N_("preferred-pack"),
154 N_("pack for reuse when computing a multi-pack bitmap")),
155 OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
156 MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
157 OPT_STRING(0, "base", &opts.incremental_base, N_("checksum"),
158 N_("base MIDX for incremental writes")),
159 OPT_BIT(0, "incremental", &opts.flags,
160 N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
161 OPT_NEGBIT(0, "write-chain-file", &opts.flags,
162 N_("write the multi-pack-index chain file"),
163 MIDX_WRITE_NO_CHAIN),
164 OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
165 N_("write multi-pack index containing only given indexes")),
166 OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
167 N_("refs snapshot for selecting bitmap commits")),
168 OPT_END(),
169 };
170 struct odb_source *source;
171 int ret;
172
173 opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
174
175 repo_config(the_repository, git_multi_pack_index_write_config, NULL);
176
177 options = add_common_options(builtin_multi_pack_index_write_options);
178
179 trace2_cmd_mode(argv[0]);
180
181 if (isatty(2))
182 opts.flags |= MIDX_PROGRESS;
183 argc = parse_options(argc, argv, prefix,
184 options, builtin_multi_pack_index_write_usage,
185 0);
186 if (argc)
187 usage_with_options(builtin_multi_pack_index_write_usage,
188 options);
189
190 if (opts.flags & MIDX_WRITE_NO_CHAIN &&
191 !(opts.flags & MIDX_WRITE_INCREMENTAL)) {
192 error(_("cannot use %s without %s"),
193 "--no-write-chain-file", "--incremental");
194 usage_with_options(builtin_multi_pack_index_write_usage,
195 options);
196 }
197
198 if (opts.incremental_base &&
199 !(opts.flags & MIDX_WRITE_NO_CHAIN)) {
200 error(_("cannot use --base without --no-write-chain-file"));
201 usage_with_options(builtin_multi_pack_index_write_usage,
202 options);
203 }
204
205 source = handle_object_dir_option(repo);
206
207 FREE_AND_NULL(options);
208
209 if (opts.stdin_packs) {
210 struct string_list packs = STRING_LIST_INIT_DUP;
211
212 read_packs_from_stdin(&packs);
213
214 ret = write_midx_file_only(source, &packs,
215 opts.preferred_pack,
216 opts.refs_snapshot,
217 opts.incremental_base, opts.flags);
218
219 string_list_clear(&packs, 0);
220 free(opts.refs_snapshot);
221
222 return ret;
223
224 }
225
226 ret = write_midx_file(source, opts.preferred_pack,
227 opts.refs_snapshot, opts.flags);
228
229 free(opts.refs_snapshot);
230 return ret;
231 }
232
233 static int cmd_multi_pack_index_compact(int argc, const char **argv,
234 const char *prefix,
235 struct repository *repo)
236 {
237 struct multi_pack_index *m, *cur;
238 struct multi_pack_index *from_midx = NULL;
239 struct multi_pack_index *to_midx = NULL;
240 struct odb_source *source;
241 int ret;
242
243 struct option *options;
244 static struct option builtin_multi_pack_index_compact_options[] = {
245 OPT_STRING(0, "base", &opts.incremental_base, N_("checksum"),
246 N_("base MIDX for incremental writes")),
247 OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
248 MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
249 OPT_BIT(0, "incremental", &opts.flags,
250 N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
251 OPT_NEGBIT(0, "write-chain-file", &opts.flags,
252 N_("write the multi-pack-index chain file"),
253 MIDX_WRITE_NO_CHAIN),
254 OPT_END(),
255 };
256
257 repo_config(repo, git_multi_pack_index_write_config, NULL);
258
259 options = add_common_options(builtin_multi_pack_index_compact_options);
260
261 trace2_cmd_mode(argv[0]);
262
263 if (isatty(2))
264 opts.flags |= MIDX_PROGRESS;
265 argc = parse_options(argc, argv, prefix,
266 options, builtin_multi_pack_index_compact_usage,
267 0);
268
269 if (argc != 2)
270 usage_with_options(builtin_multi_pack_index_compact_usage,
271 options);
272
273 if (opts.flags & MIDX_WRITE_NO_CHAIN &&
274 !(opts.flags & MIDX_WRITE_INCREMENTAL)) {
275 error(_("cannot use %s without %s"),
276 "--no-write-chain-file", "--incremental");
277 usage_with_options(builtin_multi_pack_index_compact_usage,
278 options);
279 }
280
281 source = handle_object_dir_option(the_repository);
282
283 FREE_AND_NULL(options);
284
285 m = get_multi_pack_index(source);
286
287 for (cur = m; cur && !(from_midx && to_midx); cur = cur->base_midx) {
288 const char *midx_csum = midx_get_checksum_hex(cur);
289
290 if (!from_midx && !strcmp(midx_csum, argv[0]))
291 from_midx = cur;
292 if (!to_midx && !strcmp(midx_csum, argv[1]))
293 to_midx = cur;
294 }
295
296 if (!from_midx)
297 die(_("could not find MIDX: %s"), argv[0]);
298 if (!to_midx)
299 die(_("could not find MIDX: %s"), argv[1]);
300 if (from_midx == to_midx)
301 die(_("MIDX compaction endpoints must be unique"));
302
303 for (m = from_midx; m; m = m->base_midx) {
304 if (m == to_midx)
305 die(_("MIDX %s must be an ancestor of %s"), argv[0], argv[1]);
306 }
307
308 ret = write_midx_file_compact(source, from_midx, to_midx,
309 opts.incremental_base, opts.flags);
310
311 return ret;
312 }
313
314 static int cmd_multi_pack_index_verify(int argc, const char **argv,
315 const char *prefix,
316 struct repository *repo UNUSED)
317 {
318 struct option *options;
319 static struct option builtin_multi_pack_index_verify_options[] = {
320 OPT_END(),
321 };
322 struct odb_source *source;
323
324 options = add_common_options(builtin_multi_pack_index_verify_options);
325
326 trace2_cmd_mode(argv[0]);
327
328 if (isatty(2))
329 opts.flags |= MIDX_PROGRESS;
330 argc = parse_options(argc, argv, prefix,
331 options, builtin_multi_pack_index_verify_usage,
332 0);
333 if (argc)
334 usage_with_options(builtin_multi_pack_index_verify_usage,
335 options);
336 source = handle_object_dir_option(the_repository);
337
338 FREE_AND_NULL(options);
339
340 return verify_midx_file(source, opts.flags);
341 }
342
343 static int cmd_multi_pack_index_expire(int argc, const char **argv,
344 const char *prefix,
345 struct repository *repo UNUSED)
346 {
347 struct option *options;
348 static struct option builtin_multi_pack_index_expire_options[] = {
349 OPT_END(),
350 };
351 struct odb_source *source;
352
353 options = add_common_options(builtin_multi_pack_index_expire_options);
354
355 trace2_cmd_mode(argv[0]);
356
357 if (isatty(2))
358 opts.flags |= MIDX_PROGRESS;
359 argc = parse_options(argc, argv, prefix,
360 options, builtin_multi_pack_index_expire_usage,
361 0);
362 if (argc)
363 usage_with_options(builtin_multi_pack_index_expire_usage,
364 options);
365 source = handle_object_dir_option(the_repository);
366
367 FREE_AND_NULL(options);
368
369 return expire_midx_packs(source, opts.flags);
370 }
371
372 static int cmd_multi_pack_index_repack(int argc, const char **argv,
373 const char *prefix,
374 struct repository *repo UNUSED)
375 {
376 struct option *options;
377 static struct option builtin_multi_pack_index_repack_options[] = {
378 OPT_UNSIGNED(0, "batch-size", &opts.batch_size,
379 N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
380 OPT_END(),
381 };
382 struct odb_source *source;
383
384 options = add_common_options(builtin_multi_pack_index_repack_options);
385
386 trace2_cmd_mode(argv[0]);
387
388 if (isatty(2))
389 opts.flags |= MIDX_PROGRESS;
390 argc = parse_options(argc, argv, prefix,
391 options,
392 builtin_multi_pack_index_repack_usage,
393 0);
394 if (argc)
395 usage_with_options(builtin_multi_pack_index_repack_usage,
396 options);
397 source = handle_object_dir_option(the_repository);
398
399 FREE_AND_NULL(options);
400
401 return midx_repack(source, (size_t)opts.batch_size, opts.flags);
402 }
403
404 int cmd_multi_pack_index(int argc,
405 const char **argv,
406 const char *prefix,
407 struct repository *repo)
408 {
409 int res;
410 parse_opt_subcommand_fn *fn = NULL;
411 struct option builtin_multi_pack_index_options[] = {
412 OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
413 OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
414 OPT_SUBCOMMAND("compact", &fn, cmd_multi_pack_index_compact),
415 OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
416 OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
417 OPT_END(),
418 };
419 struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
420
421 disable_replace_refs();
422
423 repo_config(the_repository, git_default_config, NULL);
424
425 if (the_repository &&
426 the_repository->objects &&
427 the_repository->objects->sources)
428 opts.object_dir = xstrdup(the_repository->objects->sources->path);
429
430 argc = parse_options(argc, argv, prefix, options,
431 builtin_multi_pack_index_usage, 0);
432 FREE_AND_NULL(options);
433
434 res = fn(argc, argv, prefix, repo);
435
436 free(opts.object_dir);
437 return res;
438 }