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