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