summaryrefslogtreecommitdiff
path: root/repack-promisor.c
diff options
context:
space:
mode:
Diffstat (limited to 'repack-promisor.c')
-rw-r--r--repack-promisor.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/repack-promisor.c b/repack-promisor.c
new file mode 100644
index 0000000000..ee6e0669f6
--- /dev/null
+++ b/repack-promisor.c
@@ -0,0 +1,102 @@
+#include "git-compat-util.h"
+#include "repack.h"
+#include "hex.h"
+#include "pack.h"
+#include "packfile.h"
+#include "path.h"
+#include "repository.h"
+#include "run-command.h"
+
+struct write_oid_context {
+ struct child_process *cmd;
+ const struct git_hash_algo *algop;
+};
+
+/*
+ * Write oid to the given struct child_process's stdin, starting it first if
+ * necessary.
+ */
+static int write_oid(const struct object_id *oid,
+ struct packed_git *pack UNUSED,
+ uint32_t pos UNUSED, void *data)
+{
+ struct write_oid_context *ctx = data;
+ struct child_process *cmd = ctx->cmd;
+
+ if (cmd->in == -1) {
+ if (start_command(cmd))
+ die(_("could not start pack-objects to repack promisor objects"));
+ }
+
+ if (write_in_full(cmd->in, oid_to_hex(oid), ctx->algop->hexsz) < 0 ||
+ write_in_full(cmd->in, "\n", 1) < 0)
+ die(_("failed to feed promisor objects to pack-objects"));
+ return 0;
+}
+
+void repack_promisor_objects(struct repository *repo,
+ const struct pack_objects_args *args,
+ struct string_list *names, const char *packtmp)
+{
+ struct write_oid_context ctx;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+
+ prepare_pack_objects(&cmd, args, packtmp);
+ cmd.in = -1;
+
+ /*
+ * NEEDSWORK: Giving pack-objects only the OIDs without any ordering
+ * hints may result in suboptimal deltas in the resulting pack. See if
+ * the OIDs can be sent with fake paths such that pack-objects can use a
+ * {type -> existing pack order} ordering when computing deltas instead
+ * of a {type -> size} ordering, which may produce better deltas.
+ */
+ ctx.cmd = &cmd;
+ ctx.algop = repo->hash_algo;
+ for_each_packed_object(repo, write_oid, &ctx,
+ FOR_EACH_OBJECT_PROMISOR_ONLY);
+
+ if (cmd.in == -1) {
+ /* No packed objects; cmd was never started */
+ child_process_clear(&cmd);
+ return;
+ }
+
+ close(cmd.in);
+
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+ char *promisor_name;
+
+ if (line.len != repo->hash_algo->hexsz)
+ die(_("repack: Expecting full hex object ID lines only from pack-objects."));
+ item = string_list_append(names, line.buf);
+
+ /*
+ * pack-objects creates the .pack and .idx files, but not the
+ * .promisor file. Create the .promisor file, which is empty.
+ *
+ * NEEDSWORK: fetch-pack sometimes generates non-empty
+ * .promisor files containing the ref names and associated
+ * hashes at the point of generation of the corresponding
+ * packfile, but this would not preserve their contents. Maybe
+ * concatenate the contents of all .promisor files instead of
+ * just creating a new empty file.
+ */
+ promisor_name = mkpathdup("%s-%s.promisor", packtmp,
+ line.buf);
+ write_promisor_file(promisor_name, NULL, 0);
+
+ item->util = generated_pack_populate(item->string, packtmp);
+
+ free(promisor_name);
+ }
+
+ fclose(out);
+ if (finish_command(&cmd))
+ die(_("could not finish pack-objects to repack promisor objects"));
+ strbuf_release(&line);
+}