Thread (73 messages) 73 messages, 3 authors, 2026-03-05
STALE107d

[PATCH 16/17] odb/source: make `write_alternate()` function pluggable

From: Patrick Steinhardt <hidden>
Date: 2026-02-23 16:18:53
Subsystem: the rest · Maintainer: Linus Torvalds

Introduce a new callback function in `struct odb_source` to make the
function pluggable.

Signed-off-by: Patrick Steinhardt <redacted>
---
 odb.c              | 52 --------------------------------------------------
 odb/source-files.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 odb/source.h       | 26 +++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 52 deletions(-)
diff --git a/odb.c b/odb.c
index d9424cdfd0..84a31084d3 100644
--- a/odb.c
+++ b/odb.c
@@ -236,58 +236,6 @@ static struct odb_source *odb_add_alternate_recursively(struct object_database *
 	return alternate;
 }
 
-static int odb_source_write_alternate(struct odb_source *source,
-				      const char *alternate)
-{
-	struct lock_file lock = LOCK_INIT;
-	char *path = xstrfmt("%s/%s", source->path, "info/alternates");
-	FILE *in, *out;
-	int found = 0;
-	int ret;
-
-	hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
-	out = fdopen_lock_file(&lock, "w");
-	if (!out) {
-		ret = error_errno(_("unable to fdopen alternates lockfile"));
-		goto out;
-	}
-
-	in = fopen(path, "r");
-	if (in) {
-		struct strbuf line = STRBUF_INIT;
-
-		while (strbuf_getline(&line, in) != EOF) {
-			if (!strcmp(alternate, line.buf)) {
-				found = 1;
-				break;
-			}
-			fprintf_or_die(out, "%s\n", line.buf);
-		}
-
-		strbuf_release(&line);
-		fclose(in);
-	} else if (errno != ENOENT) {
-		ret = error_errno(_("unable to read alternates file"));
-		goto out;
-	}
-
-	if (found) {
-		rollback_lock_file(&lock);
-	} else {
-		fprintf_or_die(out, "%s\n", alternate);
-		if (commit_lock_file(&lock)) {
-			ret = error_errno(_("unable to move new alternates file into place"));
-			goto out;
-		}
-	}
-
-	ret = 0;
-
-out:
-	free(path);
-	return ret;
-}
-
 void odb_add_to_alternates_file(struct object_database *odb,
 				const char *dir)
 {
diff --git a/odb/source-files.c b/odb/source-files.c
index 199c55cfa4..c32cd67b26 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -1,12 +1,15 @@
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "chdir-notify.h"
+#include "gettext.h"
+#include "lockfile.h"
 #include "object-file.h"
 #include "odb.h"
 #include "odb/source.h"
 #include "odb/source-files.h"
 #include "packfile.h"
 #include "strbuf.h"
+#include "write-or-die.h"
 
 static void odb_source_files_reparent(const char *name UNUSED,
 				      const char *old_cwd,
@@ -138,6 +141,58 @@ static int odb_source_files_read_alternates(struct odb_source *source,
 	return 0;
 }
 
+static int odb_source_files_write_alternate(struct odb_source *source,
+					    const char *alternate)
+{
+	struct lock_file lock = LOCK_INIT;
+	char *path = xstrfmt("%s/%s", source->path, "info/alternates");
+	FILE *in, *out;
+	int found = 0;
+	int ret;
+
+	hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
+	out = fdopen_lock_file(&lock, "w");
+	if (!out) {
+		ret = error_errno(_("unable to fdopen alternates lockfile"));
+		goto out;
+	}
+
+	in = fopen(path, "r");
+	if (in) {
+		struct strbuf line = STRBUF_INIT;
+
+		while (strbuf_getline(&line, in) != EOF) {
+			if (!strcmp(alternate, line.buf)) {
+				found = 1;
+				break;
+			}
+			fprintf_or_die(out, "%s\n", line.buf);
+		}
+
+		strbuf_release(&line);
+		fclose(in);
+	} else if (errno != ENOENT) {
+		ret = error_errno(_("unable to read alternates file"));
+		goto out;
+	}
+
+	if (found) {
+		rollback_lock_file(&lock);
+	} else {
+		fprintf_or_die(out, "%s\n", alternate);
+		if (commit_lock_file(&lock)) {
+			ret = error_errno(_("unable to move new alternates file into place"));
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	free(path);
+	return ret;
+}
+
 struct odb_source_files *odb_source_files_new(struct object_database *odb,
 					      const char *path,
 					      bool local)
@@ -159,6 +214,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
 	files->base.write_object = odb_source_files_write_object;
 	files->base.write_object_stream = odb_source_files_write_object_stream;
 	files->base.read_alternates = odb_source_files_read_alternates;
+	files->base.write_alternate = odb_source_files_write_alternate;
 
 	/*
 	 * Ideally, we would only ever store absolute paths in the source. This
diff --git a/odb/source.h b/odb/source.h
index 14f5d56f68..cf301679da 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -244,6 +244,19 @@ struct odb_source {
 	 */
 	int (*read_alternates)(struct odb_source *source,
 			       struct strvec *out);
+
+	/*
+	 * This callback is expected to persist the singular alternate passed
+	 * to it into its list of alternates. Any pre-existing alternates are
+	 * expected to remain active. Subsequent calls to `read_alternates` are
+	 * thus expected to yield the pre-existing list of alternates plus the
+	 * newly added alternate appended to its end.
+	 *
+	 * The callback is expected to return 0 on success, a negative error
+	 * code otherwise.
+	 */
+	int (*write_alternate)(struct odb_source *source,
+			       const char *alternate);
 };
 
 /*
@@ -408,4 +421,17 @@ static inline int odb_source_read_alternates(struct odb_source *source,
 	return source->read_alternates(source, out);
 }
 
+/*
+ * Write and persist a new alternate object database source for the given
+ * source. Any preexisting alternates are expected to stay valid, and the new
+ * alternate shall be appended to the end of the list.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static inline int odb_source_write_alternate(struct odb_source *source,
+					      const char *alternate)
+{
+	return source->write_alternate(source, alternate);
+}
+
 #endif
-- 
2.53.0.536.g309c995771.dirty
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help