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.incremental_base,
229 opts.flags);
230
231 free(opts.refs_snapshot);
232 return ret;
233 }
234
235 static int cmd_multi_pack_index_compact(int argc, const char **argv,
236 const char *prefix,
237 struct repository *repo)
238 {
239 struct multi_pack_index *m, *cur;
240 struct multi_pack_index *from_midx = NULL;
241 struct multi_pack_index *to_midx = NULL;
242 struct odb_source_files *source;
243 int ret;
244
245 struct option *options;
246 static struct option builtin_multi_pack_index_compact_options[] = {
247 OPT_STRING(0, "base", &opts.incremental_base, N_("checksum"),
248 N_("base MIDX for incremental writes")),
249 OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
250 MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
251 OPT_BIT(0, "incremental", &opts.flags,
252 N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
253 OPT_NEGBIT(0, "write-chain-file", &opts.flags,
254 N_("write the multi-pack-index chain file"),
255 MIDX_WRITE_NO_CHAIN),
256 OPT_END(),
257 };
258
259 repo_config(repo, git_multi_pack_index_write_config, NULL);
260
261 options = add_common_options(builtin_multi_pack_index_compact_options);
262
263 trace2_cmd_mode(argv[0]);
264
265 if (isatty(2))
266 opts.flags |= MIDX_PROGRESS;
267 argc = parse_options(argc, argv, prefix,
268 options, builtin_multi_pack_index_compact_usage,
269 0);
270
271 if (argc != 2)
272 usage_with_options(builtin_multi_pack_index_compact_usage,
273 options);
274
275 if (opts.flags & MIDX_WRITE_NO_CHAIN &&
276 !(opts.flags & MIDX_WRITE_INCREMENTAL)) {
277 error(_("cannot use %s without %s"),
278 "--no-write-chain-file", "--incremental");
279 usage_with_options(builtin_multi_pack_index_compact_usage,
280 options);
281 }
282
283 source = handle_object_dir_option(the_repository);
284
285 FREE_AND_NULL(options);
286
287 m = get_multi_pack_index(source->packed);
288
289 for (cur = m; cur && !(from_midx && to_midx); cur = cur->base_midx) {
290 const char *midx_csum = midx_get_checksum_hex(cur);
291
292 if (!from_midx && !strcmp(midx_csum, argv[0]))
293 from_midx = cur;
294 if (!to_midx && !strcmp(midx_csum, argv[1]))
295 to_midx = cur;
296 }
297
298 if (!from_midx)
299 die(_("could not find MIDX: %s"), argv[0]);
300 if (!to_midx)
301 die(_("could not find MIDX: %s"), argv[1]);
302 if (from_midx == to_midx)
303 die(_("MIDX compaction endpoints must be unique"));
304
305 for (m = from_midx; m; m = m->base_midx) {
306 if (m == to_midx)
307 die(_("MIDX %s must be an ancestor of %s"), argv[0], argv[1]);
308 }
309
310 ret = write_midx_file_compact(source->packed, from_midx, to_midx,
311 opts.incremental_base, opts.flags);
312
313 return ret;
314 }
315
316 static int cmd_multi_pack_index_verify(int argc, const char **argv,
317 const char *prefix,
318 struct repository *repo UNUSED)
319 {
320 struct option *options;
321 static struct option builtin_multi_pack_index_verify_options[] = {
322 OPT_END(),
323 };
324 struct odb_source_files *source;
325
326 options = add_common_options(builtin_multi_pack_index_verify_options);
327
328 trace2_cmd_mode(argv[0]);
329
330 if (isatty(2))
331 opts.flags |= MIDX_PROGRESS;
332 argc = parse_options(argc, argv, prefix,
333 options, builtin_multi_pack_index_verify_usage,
334 0);
335 if (argc)
336 usage_with_options(builtin_multi_pack_index_verify_usage,
337 options);
338 source = handle_object_dir_option(the_repository);
339
340 FREE_AND_NULL(options);
341
342 return verify_midx_file(source->packed, opts.flags);
343 }
344
345 static int cmd_multi_pack_index_expire(int argc, const char **argv,
346 const char *prefix,
347 struct repository *repo UNUSED)
348 {
349 struct option *options;
350 static struct option builtin_multi_pack_index_expire_options[] = {
351 OPT_END(),
352 };
353 struct odb_source_files *source;
354
355 options = add_common_options(builtin_multi_pack_index_expire_options);
356
357 trace2_cmd_mode(argv[0]);
358
359 if (isatty(2))
360 opts.flags |= MIDX_PROGRESS;
361 argc = parse_options(argc, argv, prefix,
362 options, builtin_multi_pack_index_expire_usage,
363 0);
364 if (argc)
365 usage_with_options(builtin_multi_pack_index_expire_usage,
366 options);
367 source = handle_object_dir_option(the_repository);
368
369 FREE_AND_NULL(options);
370
371 return expire_midx_packs(source->packed, opts.flags);
372 }
373
374 static int cmd_multi_pack_index_repack(int argc, const char **argv,
375 const char *prefix,
376 struct repository *repo UNUSED)
377 {
378 struct option *options;
379 static struct option builtin_multi_pack_index_repack_options[] = {
380 OPT_UNSIGNED(0, "batch-size", &opts.batch_size,
381 N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
382 OPT_END(),
383 };
384 struct odb_source_files *source;
385
386 options = add_common_options(builtin_multi_pack_index_repack_options);
387
388 trace2_cmd_mode(argv[0]);
389
390 if (isatty(2))
391 opts.flags |= MIDX_PROGRESS;
392 argc = parse_options(argc, argv, prefix,
393 options,
394 builtin_multi_pack_index_repack_usage,
395 0);
396 if (argc)
397 usage_with_options(builtin_multi_pack_index_repack_usage,
398 options);
399 source = handle_object_dir_option(the_repository);
400
401 FREE_AND_NULL(options);
402
403 return midx_repack(source->packed, (size_t)opts.batch_size, opts.flags);
404 }
405
406 int cmd_multi_pack_index(int argc,
407 const char **argv,
408 const char *prefix,
409 struct repository *repo)
410 {
411 int res;
412 parse_opt_subcommand_fn *fn = NULL;
413 struct option builtin_multi_pack_index_options[] = {
414 OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
415 OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
416 OPT_SUBCOMMAND("compact", &fn, cmd_multi_pack_index_compact),
417 OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
418 OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
419 OPT_END(),
420 };
421 struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
422
423 disable_replace_refs();
424
425 repo_config(the_repository, git_default_config, NULL);
426
427 if (the_repository &&
428 the_repository->objects &&
429 the_repository->objects->sources)
430 opts.object_dir = xstrdup(the_repository->objects->sources->path);
431
432 argc = parse_options(argc, argv, prefix, options,
433 builtin_multi_pack_index_usage, 0);
434 FREE_AND_NULL(options);
435
436 res = fn(argc, argv, prefix, repo);
437
438 free(opts.object_dir);
439 return res;
440 }