Add the ability to write alternates when creating the object database.
This change allows us to remove the `write_alternates()` callback in a
subsequent patch.
Signed-off-by: Patrick Steinhardt <ps@xxxxxx>
---
odb/source-files.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
odb/source.h | 18 +++++++++++---
setup.c | 4 ++-
3 files changed, 89 insertions(+), 6 deletions(-)
diff --git a/odb/source-files.c b/odb/source-files.c
index b7b3a297bb..5e77b21d9f 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -18,6 +18,7 @@
#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
+#include "strmap.h"
#include "strvec.h"
#include "tree.h"
#include "write-or-die.h"
@@ -51,9 +52,14 @@ static void odb_source_files_close(struct odb_source *source)
odb_source_close(&files->packed->base);
}
-static int odb_source_files_create_on_disk(struct odb_source *source)
+static int odb_source_files_create_on_disk(struct odb_source *source,
+ const struct odb_create_on_disk_options *opts)
{
struct strbuf path = STRBUF_INIT;
+ struct strset seen = STRSET_INIT;
+ struct strbuf line = STRBUF_INIT;
+ FILE *f = NULL;
+ int ret;
safe_create_dir(source->odb->repo, source->path, 1);
@@ -64,8 +70,71 @@ static int odb_source_files_create_on_disk(struct odb_source *source)
strbuf_addf(&path, "%s/info", source->path);
safe_create_dir(source->odb->repo, path.buf, 1);
+ if (opts->alternates && opts->alternates->nr) {
+ strbuf_reset(&path);
+ strbuf_addf(&path, "%s/info/alternates", source->path);
+
+ /*
+ * The alternates file may already exist, e.g. when it has been
+ * seeded from a template directory. Read any preexisting
+ * entries so that we don't end up writing duplicates.
+ */
+ f = fopen(path.buf, "r");
+ if (f) {
+ while (strbuf_getline(&line, f) != EOF)
+ strset_add(&seen, line.buf);
+
+ if (ferror(f)) {
+ ret = error_errno(_("unable to read alternates file"));
+ goto out;
+ }
+
+ fclose(f);
+ } else if (errno != ENOENT) {
+ ret = error_errno(_("unable to read alternates file"));
+ goto out;
+ }
+
+ f = fopen(path.buf, "a");
+ if (!f) {
+ ret = error_errno(_("unable to open alternates file for writing"));
+ goto out;
+ }
+
+ for (size_t i = 0; i < opts->alternates->nr; i++) {
+ const char *alternate = opts->alternates->v[i];
+
+ if (!strset_add(&seen, alternate))
+ continue;
+
+ fprintf(f, "%s\n", alternate);
+ }
+
+ if (ferror(f)) {
+ ret = error_errno(_("unable to write alternates file"));
+ goto out;
+ }
+
+ ret = fclose(f);
+ f = NULL;
+ if (ret) {
+ ret = error_errno(_("unable to write alternates file"));
+ goto out;
+ }
+ }
+
+ /* Reprepare the object database to activate alternates. */
+ odb_reprepare(source->odb);
+
+ ret = 0;
+
+out:
+ if (f)
+ fclose(f);
+ strbuf_release(&line);
strbuf_release(&path);
- return 0;
+ strset_clear(&seen);
+ return ret;
}
static void odb_source_files_prepare(struct odb_source *source,
diff --git a/odb/source.h b/odb/source.h
index ea8675247e..86b82fab3b 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -5,6 +5,7 @@
#include "object.h"
#include "odb.h"
#include "odb/transaction.h"
+#include "strvec.h"
enum odb_source_type {
/*
@@ -26,6 +27,15 @@ enum odb_source_type {
ODB_SOURCE_INMEMORY,
};
+struct odb_create_on_disk_options {
+ /*
+ * Alternates that shall be written into the newly created object
+ * database. Whether or not this option can be handled is specific to
+ * the backend.
+ */
+ const struct strvec *alternates;
+};
+
/*
* Convert between the enum and its name. Returns the equivalent of "unknown"
* for unknown types.
@@ -106,7 +116,8 @@ struct odb_source {
* This callback may be NULL in case the source does not need any
* on-disk setup.
*/
- int (*create_on_disk)(struct odb_source *source);
+ int (*create_on_disk)(struct odb_source *source,
+ const struct odb_create_on_disk_options *opts);
/*
* This callback is expected to prepare the source so that it becomes
@@ -356,11 +367,12 @@ static inline void odb_source_close(struct odb_source *source)
* Create on-disk data structures that are required for this source to operate
* correctly. Returns 0 on success, a negative error code otherwise.
*/
-static inline int odb_source_create_on_disk(struct odb_source *source)
+static inline int odb_source_create_on_disk(struct odb_source *source,
+ const struct odb_create_on_disk_options *opts)
{
if (!source->create_on_disk)
return 0;
- return source->create_on_disk(source);
+ return source->create_on_disk(source, opts);
}
/*
diff --git a/setup.c b/setup.c
index e654e27d05..426cc7dff8 100644
--- a/setup.c
+++ b/setup.c
@@ -2649,6 +2649,8 @@ static int create_default_files(struct repository *repo,
void create_object_database(struct repository *repo)
{
+ struct odb_create_on_disk_options opts = { 0 };
+
/*
* Create the "objects" directory in the common directory. This is done
* so that the repository can be discovered regardless of the backend
@@ -2668,7 +2670,7 @@ void create_object_database(struct repository *repo)
repo->objects = odb_new(repo, ODB_NEW_HONOR_ENV);
- if (odb_source_create_on_disk(repo->objects->sources) < 0)
+ if (odb_source_create_on_disk(repo->objects->sources, &opts) < 0)
die(_("failed creating object database"));
}
--
2.55.0.822.g20453c30eb.dirty