odb/source: make `write_alternate()` 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
eb9635d83b7ef16df527db3e84def9d0c772344d
3 files changed
+82
-52
odb.c
-52
@@ -236,58 +236,6 @@ static struct odb_source *odb_add_alternate_recursively(struct object_database *
236
return alternate;
237
}
238
239
-static int odb_source_write_alternate(struct odb_source *source,
240
- const char *alternate)
241
-{
242
- struct lock_file lock = LOCK_INIT;
243
- char *path = xstrfmt("%s/%s", source->path, "info/alternates");
244
- FILE *in, *out;
245
- int found = 0;
246
- int ret;
247
-
248
- hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
249
- out = fdopen_lock_file(&lock, "w");
250
- if (!out) {
251
- ret = error_errno(_("unable to fdopen alternates lockfile"));
252
- goto out;
253
- }
254
-
255
- in = fopen(path, "r");
256
- if (in) {
257
- struct strbuf line = STRBUF_INIT;
258
-
259
- while (strbuf_getline(&line, in) != EOF) {
260
- if (!strcmp(alternate, line.buf)) {
261
- found = 1;
262
- break;
263
- }
264
- fprintf_or_die(out, "%s\n", line.buf);
265
- }
266
-
267
- strbuf_release(&line);
268
- fclose(in);
269
- } else if (errno != ENOENT) {
270
- ret = error_errno(_("unable to read alternates file"));
271
- goto out;
272
- }
273
-
274
- if (found) {
275
- rollback_lock_file(&lock);
276
- } else {
277
- fprintf_or_die(out, "%s\n", alternate);
278
- if (commit_lock_file(&lock)) {
279
- ret = error_errno(_("unable to move new alternates file into place"));
280
- goto out;
281
- }
282
- }
283
-
284
- ret = 0;
285
-
286
-out:
287
- free(path);
288
- return ret;
289
-}
290
-
239
void odb_add_to_alternates_file(struct object_database *odb,
240
const char *dir)
241
{
odb/source-files.c
+56
@@ -1,12 +1,15 @@
1
#include "git-compat-util.h"
2
#include "abspath.h"
3
#include "chdir-notify.h"
4
+#include "gettext.h"
5
+#include "lockfile.h"
6
#include "object-file.h"
7
#include "odb.h"
8
#include "odb/source.h"
9
#include "odb/source-files.h"
10
#include "packfile.h"
11
#include "strbuf.h"
12
+#include "write-or-die.h"
13
14
static void odb_source_files_reparent(const char *name UNUSED,
15
const char *old_cwd,
@@ -138,6 +141,58 @@ static int odb_source_files_read_alternates(struct odb_source *source,
141
return 0;
142
}
143
144
+static int odb_source_files_write_alternate(struct odb_source *source,
145
+ const char *alternate)
146
+{
147
+ struct lock_file lock = LOCK_INIT;
148
+ char *path = xstrfmt("%s/%s", source->path, "info/alternates");
149
+ FILE *in, *out;
150
+ int found = 0;
151
+ int ret;
152
+
153
+ hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
154
+ out = fdopen_lock_file(&lock, "w");
155
+ if (!out) {
156
+ ret = error_errno(_("unable to fdopen alternates lockfile"));
157
+ goto out;
158
+ }
159
+
160
+ in = fopen(path, "r");
161
+ if (in) {
162
+ struct strbuf line = STRBUF_INIT;
163
+
164
+ while (strbuf_getline(&line, in) != EOF) {
165
+ if (!strcmp(alternate, line.buf)) {
166
+ found = 1;
167
+ break;
168
+ }
169
+ fprintf_or_die(out, "%s\n", line.buf);
170
+ }
171
+
172
+ strbuf_release(&line);
173
+ fclose(in);
174
+ } else if (errno != ENOENT) {
175
+ ret = error_errno(_("unable to read alternates file"));
176
+ goto out;
177
+ }
178
+
179
+ if (found) {
180
+ rollback_lock_file(&lock);
181
+ } else {
182
+ fprintf_or_die(out, "%s\n", alternate);
183
+ if (commit_lock_file(&lock)) {
184
+ ret = error_errno(_("unable to move new alternates file into place"));
185
+ goto out;
186
+ }
187
+ }
188
+
189
+ ret = 0;
190
+
191
+out:
192
+ free(path);
193
+ return ret;
194
+}
195
+
196
struct odb_source_files *odb_source_files_new(struct object_database *odb,
197
const char *path,
198
bool local)
@@ -159,6 +214,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
214
files->base.write_object = odb_source_files_write_object;
215
files->base.write_object_stream = odb_source_files_write_object_stream;
216
files->base.read_alternates = odb_source_files_read_alternates;
217
+ files->base.write_alternate = odb_source_files_write_alternate;
218
219
/*
220
* Ideally, we would only ever store absolute paths in the source. This
odb/source.h
+26
@@ -245,6 +245,19 @@ struct odb_source {
245
*/
246
int (*read_alternates)(struct odb_source *source,
247
struct strvec *out);
248
+
249
+ /*
250
+ * This callback is expected to persist the singular alternate passed
251
+ * to it into its list of alternates. Any pre-existing alternates are
252
+ * expected to remain active. Subsequent calls to `read_alternates` are
253
+ * thus expected to yield the pre-existing list of alternates plus the
254
+ * newly added alternate appended to its end.
255
+ *
256
+ * The callback is expected to return 0 on success, a negative error
257
+ * code otherwise.
258
+ */
259
+ int (*write_alternate)(struct odb_source *source,
260
+ const char *alternate);
261
};
262
263
/*
@@ -412,4 +425,17 @@ static inline int odb_source_read_alternates(struct odb_source *source,
425
return source->read_alternates(source, out);
426
}
427
428
+/*
429
+ * Write and persist a new alternate object database source for the given
430
+ * source. Any preexisting alternates are expected to stay valid, and the new
431
+ * alternate shall be appended to the end of the list.
432
+ *
433
+ * Returns 0 on success, a negative error code otherwise.
434
+ */
435
+static inline int odb_source_write_alternate(struct odb_source *source,
436
+ const char *alternate)
437
+{
438
+ return source->write_alternate(source, alternate);
439
+}
440
+
441
#endif