odb/source: make `read_alternates()` function pluggable

Introduce a new callback function in `struct odb_source` to make the function pluggable. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 5, 2026 at 15:19 UTC 7ae23630c3ed012180edc88f0a9615a0d570a77c
4 files changed +59 -22
odb.c
+4 -22
@@ -131,10 +131,10 @@ out:
131 return usable;
132 }
133
134 -static void parse_alternates(const char *string,
135 - int sep,
136 - const char *relative_base,
137 - struct strvec *out)
134 +void parse_alternates(const char *string,
135 + int sep,
136 + const char *relative_base,
137 + struct strvec *out)
138 {
139 struct strbuf pathbuf = STRBUF_INIT;
140 struct strbuf buf = STRBUF_INIT;
@@ -198,24 +198,6 @@ static void parse_alternates(const char *string,
198 strbuf_release(&buf);
199 }
200
201 -static void odb_source_read_alternates(struct odb_source *source,
202 - struct strvec *out)
203 -{
204 - struct strbuf buf = STRBUF_INIT;
205 - char *path;
206 -
207 - path = xstrfmt("%s/info/alternates", source->path);
208 - if (strbuf_read_file(&buf, path, 1024) < 0) {
209 - warn_on_fopen_errors(path);
210 - free(path);
211 - return;
212 - }
213 - parse_alternates(buf.buf, '\n', source->path, out);
214 -
215 - strbuf_release(&buf);
216 - free(path);
217 -}
218 -
201 static struct odb_source *odb_add_alternate_recursively(struct object_database *odb,
202 const char *source,
203 int depth)
odb.h
+5
@@ -500,4 +500,9 @@ int odb_write_object_stream(struct object_database *odb,
500 struct odb_write_stream *stream, size_t len,
501 struct object_id *oid);
502
503 +void parse_alternates(const char *string,
504 + int sep,
505 + const char *relative_base,
506 + struct strvec *out);
507 +
508 #endif /* ODB_H */
odb/source-files.c
+22
@@ -2,9 +2,11 @@
2 #include "abspath.h"
3 #include "chdir-notify.h"
4 #include "object-file.h"
5 +#include "odb.h"
6 #include "odb/source.h"
7 #include "odb/source-files.h"
8 #include "packfile.h"
9 +#include "strbuf.h"
10
11 static void odb_source_files_reparent(const char *name UNUSED,
12 const char *old_cwd,
@@ -117,6 +119,25 @@ static int odb_source_files_write_object_stream(struct odb_source *source,
119 return odb_source_loose_write_stream(source, stream, len, oid);
120 }
121
122 +static int odb_source_files_read_alternates(struct odb_source *source,
123 + struct strvec *out)
124 +{
125 + struct strbuf buf = STRBUF_INIT;
126 + char *path;
127 +
128 + path = xstrfmt("%s/info/alternates", source->path);
129 + if (strbuf_read_file(&buf, path, 1024) < 0) {
130 + warn_on_fopen_errors(path);
131 + free(path);
132 + return 0;
133 + }
134 + parse_alternates(buf.buf, '\n', source->path, out);
135 +
136 + strbuf_release(&buf);
137 + free(path);
138 + return 0;
139 +}
140 +
141 struct odb_source_files *odb_source_files_new(struct object_database *odb,
142 const char *path,
143 bool local)
@@ -137,6 +158,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
158 files->base.freshen_object = odb_source_files_freshen_object;
159 files->base.write_object = odb_source_files_write_object;
160 files->base.write_object_stream = odb_source_files_write_object_stream;
161 + files->base.read_alternates = odb_source_files_read_alternates;
162
163 /*
164 * Ideally, we would only ever store absolute paths in the source. This
odb/source.h
+28
@@ -54,6 +54,7 @@ struct object_id;
54 struct object_info;
55 struct odb_read_stream;
56 struct odb_write_stream;
57 +struct strvec;
58
59 /*
60 * A callback function that can be used to iterate through objects. If given,
@@ -231,6 +232,19 @@ struct odb_source {
232 int (*write_object_stream)(struct odb_source *source,
233 struct odb_write_stream *stream, size_t len,
234 struct object_id *oid);
235 +
236 + /*
237 + * This callback is expected to read the list of alternate object
238 + * database sources connected to it and write them into the `strvec`.
239 + *
240 + * The result is expected to be paths to the alternates. All paths must
241 + * be resolved to absolute paths.
242 + *
243 + * The callback is expected to return 0 on success, a negative error
244 + * code otherwise.
245 + */
246 + int (*read_alternates)(struct odb_source *source,
247 + struct strvec *out);
248 };
249
250 /*
@@ -384,4 +398,18 @@ static inline int odb_source_write_object_stream(struct odb_source *source,
398 return source->write_object_stream(source, stream, len, oid);
399 }
400
401 +/*
402 + * Read the list of alternative object database sources from the given backend
403 + * and populate the `strvec` with them. The listing is not recursive -- that
404 + * is, if any of the yielded alternate sources has alternates itself, those
405 + * will not be yielded as part of this function call.
406 + *
407 + * Return 0 on success, a negative error code otherwise.
408 + */
409 +static inline int odb_source_read_alternates(struct odb_source *source,
410 + struct strvec *out)
411 +{
412 + return source->read_alternates(source, out);
413 +}
414 +
415 #endif