[GSoC PATCH v2 2/4] pack-write: add helper to fill promisor file after repack
- From
LorenzoPegorari <lorenzo.pegorari2002@gmail.com>
- Date
- Mar 22, 2026, 19:18 UTC
- Message-ID
- <0bb031e7443bb53abbbb0afaa347285d6d8cf7b8.1774205661.git.lorenzo.pegorari2002@gmail.com>
- In-Reply-To
- <cover.1774205661.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. There might be another better/cleaner way to achieve this.
Signed-off-by: LorenzoPegorari <lorenzo.pegorari2002@gmail.com> --- pack-write.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pack.h | 1 + 2 files changed, 62 insertions(+)
diff --git a/pack-write.c b/pack-write.c index 6a2023327e..583e40b423 100644 --- a/pack-write.c +++ b/pack-write.c @@ -13,6 +13,7 @@ #include "path.h" #include "repository.h" #include "strbuf.h" +#include "strmap.h" void reset_pack_idx_option(struct pack_idx_option *opts) { @@ -621,3 +622,63 @@ 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 strset dest_content = STRSET_INIT; + struct strbuf read_line = STRBUF_INIT; + struct strbuf promisor_source_name = STRBUF_INIT; + struct strbuf write_dest = STRBUF_INIT; + FILE *dest, *source; + struct packed_git *p; + int err; + + dest = xfopen(promisor_name, "r+"); + while (strbuf_getline(&read_line, dest) != EOF) + strset_add(&dest_content, read_line.buf); + + 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"); + 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_line, source) != EOF) { + if (strset_add(&dest_content, read_line.buf)) { + strbuf_addbuf(&write_dest, &read_line); + strbuf_addstr(&write_dest, "\n"); + } + } + + err = ferror(source); + err |= fclose(source); + if (err) + die(_("could not read '%s' promisor file"), promisor_source_name.buf); + } + + 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); + } + + err = ferror(dest); + err |= fclose(dest); + if (err) + die(_("could not write '%s' promisor file"), promisor_name); + + strbuf_release(&read_line); + strbuf_release(&promisor_source_name); + strbuf_release(&write_dest); + strset_clear(&dest_content); +} 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