Raw
1 #include "git-compat-util.h"
2 #include "repack.h"
3 #include "hex.h"
4 #include "pack.h"
5 #include "packfile.h"
6 #include "path.h"
7 #include "repository.h"
8 #include "run-command.h"
9 #include "oidset.h"
10
11 struct write_oid_context {
12 struct child_process *cmd;
13 const struct git_hash_algo *algop;
14 const struct oidset *to_drop;
15 };
16
17 /*
18 * Write oid to the given struct child_process's stdin, starting it first if
19 * necessary.
20 */
21 static int write_oid(const struct object_id *oid,
22 struct object_info *oi UNUSED,
23 void *data)
24 {
25 struct write_oid_context *ctx = data;
26 struct child_process *cmd = ctx->cmd;
27
28 /*
29 * Objects in to_drop are being removed from the repository, so
30 * omit them from the rebuilt promisor pack. Each such object is a
31 * promisor object and therefore remains recoverable from the
32 * promisor remote.
33 */
34 if (ctx->to_drop && oidset_contains(ctx->to_drop, oid))
35 return 0;
36
37 if (cmd->in == -1) {
38 if (start_command(cmd))
39 die(_("could not start pack-objects to repack promisor objects"));
40 }
41
42 if (write_in_full(cmd->in, oid_to_hex(oid), ctx->algop->hexsz) < 0 ||
43 write_in_full(cmd->in, "\n", 1) < 0)
44 die(_("failed to feed promisor objects to pack-objects"));
45 return 0;
46 }
47
48 static void finish_repacking_promisor_objects(struct repository *repo,
49 struct child_process *cmd,
50 struct string_list *names,
51 const char *packtmp)
52 {
53 struct strbuf line = STRBUF_INIT;
54 FILE *out;
55
56 close(cmd->in);
57
58 out = xfdopen(cmd->out, "r");
59 while (strbuf_getline_lf(&line, out) != EOF) {
60 struct string_list_item *item;
61 char *promisor_name;
62
63 if (line.len != repo->hash_algo->hexsz)
64 die(_("repack: Expecting full hex object ID lines only from pack-objects."));
65 item = string_list_append(names, line.buf);
66
67 /*
68 * pack-objects creates the .pack and .idx files, but not the
69 * .promisor file. Create the .promisor file, which is empty.
70 *
71 * NEEDSWORK: fetch-pack sometimes generates non-empty
72 * .promisor files containing the ref names and associated
73 * hashes at the point of generation of the corresponding
74 * packfile, but this would not preserve their contents. Maybe
75 * concatenate the contents of all .promisor files instead of
76 * just creating a new empty file.
77 */
78 promisor_name = mkpathdup("%s-%s.promisor", packtmp,
79 line.buf);
80 write_promisor_file(promisor_name, NULL, 0);
81
82 item->util = generated_pack_populate(item->string, packtmp);
83
84 free(promisor_name);
85 }
86
87 fclose(out);
88 if (finish_command(cmd))
89 die(_("could not finish pack-objects to repack promisor objects"));
90 strbuf_release(&line);
91 }
92
93 void repack_promisor_objects(struct repository *repo,
94 const struct pack_objects_args *args,
95 struct string_list *names, const char *packtmp,
96 const struct oidset *to_drop)
97 {
98 struct write_oid_context ctx;
99 struct child_process cmd = CHILD_PROCESS_INIT;
100
101 prepare_pack_objects(&cmd, args, packtmp);
102 cmd.in = -1;
103
104 /*
105 * NEEDSWORK: Giving pack-objects only the OIDs without any ordering
106 * hints may result in suboptimal deltas in the resulting pack. See if
107 * the OIDs can be sent with fake paths such that pack-objects can use a
108 * {type -> existing pack order} ordering when computing deltas instead
109 * of a {type -> size} ordering, which may produce better deltas.
110 */
111 ctx.cmd = &cmd;
112 ctx.algop = repo->hash_algo;
113 ctx.to_drop = to_drop;
114 odb_for_each_object(repo->objects, NULL, write_oid, &ctx,
115 ODB_FOR_EACH_OBJECT_PROMISOR_ONLY);
116
117 if (cmd.in == -1) {
118 /* No packed objects; cmd was never started */
119 child_process_clear(&cmd);
120 return;
121 }
122
123 finish_repacking_promisor_objects(repo, &cmd, names, packtmp);
124 }
125
126 void pack_geometry_repack_promisors(struct repository *repo,
127 const struct pack_objects_args *args,
128 const struct pack_geometry *geometry,
129 struct string_list *names,
130 const char *packtmp)
131 {
132 struct child_process cmd = CHILD_PROCESS_INIT;
133 FILE *in;
134
135 if (!geometry->promisor_split)
136 return;
137
138 prepare_pack_objects(&cmd, args, packtmp);
139 strvec_push(&cmd.args, "--stdin-packs");
140 cmd.in = -1;
141 if (start_command(&cmd))
142 die(_("could not start pack-objects to repack promisor packs"));
143
144 in = xfdopen(cmd.in, "w");
145 for (size_t i = 0; i < geometry->promisor_split; i++)
146 fprintf(in, "%s\n", pack_basename(geometry->promisor_pack[i]));
147 for (size_t i = geometry->promisor_split; i < geometry->promisor_pack_nr; i++)
148 fprintf(in, "^%s\n", pack_basename(geometry->promisor_pack[i]));
149 fclose(in);
150
151 finish_repacking_promisor_objects(repo, &cmd, names, packtmp);
152 }