[GSoC PATCH 2/3] pack-write: add helper to fill promisor file after repack
- From
LorenzoPegorari <lorenzo.pegorari2002@gmail.com>
- Date
- Mar 21, 2026, 21:28 UTC
- Message-ID
- <3c0702f81b3e4a57cd38284ab90f8277da3fcd40.1774125871.git.lorenzo.pegorari2002@gmail.com>
- In-Reply-To
- <cover.1774125871.git.lorenzo.pegorari2002@gmail.com>
Create a `copy_all_promisor_files()` helper function used to copy the contents of all ".promisor" files in a `repository` inside another ".promisor" file.
This function can be used to preserve the contents of all ".promisor" files inside a new ".promisor" file, for example when a repack happens.
This function is written in such a way so that it will read all the ".promisor" files inside the given `repository` line by line, and copy only the lines that are not already present in the destination file. This is done to avoid copying the same lines multiple times that may come from multiple (redundant) packfiles. A better way to achieve this might be (is definitely) possible.
Signed-off-by: LorenzoPegorari <lorenzo.pegorari2002@gmail.com> --- pack-write.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pack.h | 1 + 2 files changed, 63 insertions(+)
diff --git a/pack-write.c b/pack-write.c index 6a2023327e..3620e6bd02 100644 --- a/pack-write.c +++ b/pack-write.c @@ -621,3 +621,65 @@ void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_ if (err) die(_("could not write '%s' promisor file"), promisor_name); } + +void copy_all_promisor_files(struct repository *repo, const char *promisor_name) +{ + struct strbuf promisor_source_name = STRBUF_INIT; + struct strbuf read_source = STRBUF_INIT, read_dest = STRBUF_INIT; + struct strbuf write_dest = STRBUF_INIT; + int err; + + FILE *dest = xfopen(promisor_name, "r+"); + + struct packed_git *p; + repo_for_each_pack(repo, p) { + if (!p->pack_promisor) + continue; + + strbuf_reset(&promisor_source_name); + strbuf_addstr(&promisor_source_name, p->pack_name); + strbuf_strip_suffix(&promisor_source_name, ".pack"); + strbuf_addstr(&promisor_source_name, ".promisor"); + FILE *source = xfopen(promisor_source_name.buf, "r"); + + /* + * For each line of the promisor source file, check if it already + * is in the promisor dest file. If not, add it to write_dest, so + * that it will be written in the dest file. + */ + while (strbuf_getline(&read_source, source) != EOF) { + if (fseek(dest, 0L, SEEK_SET)) + die_errno(_("fseek failed")); + int is_source_in_dest = 0; + while (strbuf_getline(&read_dest, dest) != EOF) { + if (!strbuf_cmp(&read_source, &read_dest)) { + is_source_in_dest = 1; + break; + } + } + if (!is_source_in_dest) { + strbuf_addbuf(&write_dest, &read_source); + strbuf_addstr(&write_dest, "\n"); + } + } + + if (write_dest.len) { + strbuf_strip_suffix(&write_dest, "\n"); + if (fseek(dest, 0L, SEEK_END)) + die_errno(_("fseek failed")); + fprintf(dest, "%s\n", write_dest.buf); + fflush(dest); + strbuf_reset(&write_dest); + } + + err = ferror(source); + err |= fclose(source); + if (err) + die(_("could not read '%s' promisor file"), promisor_source_name.buf); + } + + err = ferror(dest); + err |= fclose(dest); + if (err) + die(_("could not write '%s' promisor file"), promisor_name); +} diff --git a/pack.h b/pack.h index ec76472e49..509e90edba 100644 --- a/pack.h +++ b/pack.h @@ -105,6 +105,7 @@ char *index_pack_lockfile(struct repository *r, int fd, int *is_well_formed); struct ref; void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought); +void copy_all_promisor_files(struct repository *repo, const char *promisor_name); char *write_rev_file(struct repository *repo, const char *rev_name,
-- 2.43.0