for_each_reflog(): reimplement using iterators
Allow references with reflogs to be iterated over using a ref_iterator. The latter is implemented as a files_reflog_iterator, which in turn uses dir_iterator to read the "logs" directory. Note that reflog iteration doesn't correctly handle per-worktree reflogs (either before or after this patch). Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Haggerty committed
Jun 18, 2016 at 06:15 UTC
2880d16f09635f9d43247b27fd7e6508b992e599
2 files changed
+78
-42
refs/files-backend.c
+71
-42
@@ -2,6 +2,7 @@
2
#include "../refs.h"
3
#include "refs-internal.h"
4
#include "../iterator.h"
5
+#include "../dir-iterator.h"
6
#include "../lockfile.h"
7
#include "../object.h"
8
#include "../dir.h"
@@ -3291,60 +3292,88 @@ int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_dat
3292
strbuf_release(&sb);
3293
return ret;
3294
}
3294
-/*
3295
- * Call fn for each reflog in the namespace indicated by name. name
3296
- * must be empty or end with '/'. Name will be used as a scratch
3297
- * space, but its contents will be restored before return.
3298
- */
3299
-static int do_for_each_reflog(struct strbuf *name, each_ref_fn fn, void *cb_data)
3300
-{
3301
- DIR *d = opendir(git_path("logs/%s", name->buf));
3302
- int retval = 0;
3303
- struct dirent *de;
3304
- int oldlen = name->len;
3295
3306
- if (!d)
3307
- return name->len ? errno : 0;
3296
+struct files_reflog_iterator {
3297
+ struct ref_iterator base;
3298
3309
- while ((de = readdir(d)) != NULL) {
3310
- struct stat st;
3299
+ struct dir_iterator *dir_iterator;
3300
+ struct object_id oid;
3301
+};
3302
3312
- if (de->d_name[0] == '.')
3303
+static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
3304
+{
3305
+ struct files_reflog_iterator *iter =
3306
+ (struct files_reflog_iterator *)ref_iterator;
3307
+ struct dir_iterator *diter = iter->dir_iterator;
3308
+ int ok;
3309
+
3310
+ while ((ok = dir_iterator_advance(diter)) == ITER_OK) {
3311
+ int flags;
3312
+
3313
+ if (!S_ISREG(diter->st.st_mode))
3314
continue;
3314
- if (ends_with(de->d_name, ".lock"))
3315
+ if (diter->basename[0] == '.')
3316
+ continue;
3317
+ if (ends_with(diter->basename, ".lock"))
3318
continue;
3316
- strbuf_addstr(name, de->d_name);
3317
- if (stat(git_path("logs/%s", name->buf), &st) < 0) {
3318
- ; /* silently ignore */
3319
- } else {
3320
- if (S_ISDIR(st.st_mode)) {
3321
- strbuf_addch(name, '/');
3322
- retval = do_for_each_reflog(name, fn, cb_data);
3323
- } else {
3324
- struct object_id oid;
3319
3326
- if (read_ref_full(name->buf, 0, oid.hash, NULL))
3327
- error("bad ref for %s", name->buf);
3328
- else
3329
- retval = fn(name->buf, &oid, 0, cb_data);
3330
- }
3331
- if (retval)
3332
- break;
3320
+ if (read_ref_full(diter->relative_path, 0,
3321
+ iter->oid.hash, &flags)) {
3322
+ error("bad ref for %s", diter->path.buf);
3323
+ continue;
3324
}
3334
- strbuf_setlen(name, oldlen);
3325
+
3326
+ iter->base.refname = diter->relative_path;
3327
+ iter->base.oid = &iter->oid;
3328
+ iter->base.flags = flags;
3329
+ return ITER_OK;
3330
}
3336
- closedir(d);
3337
- return retval;
3331
+
3332
+ iter->dir_iterator = NULL;
3333
+ if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
3334
+ ok = ITER_ERROR;
3335
+ return ok;
3336
+}
3337
+
3338
+static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
3339
+ struct object_id *peeled)
3340
+{
3341
+ die("BUG: ref_iterator_peel() called for reflog_iterator");
3342
+}
3343
+
3344
+static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
3345
+{
3346
+ struct files_reflog_iterator *iter =
3347
+ (struct files_reflog_iterator *)ref_iterator;
3348
+ int ok = ITER_DONE;
3349
+
3350
+ if (iter->dir_iterator)
3351
+ ok = dir_iterator_abort(iter->dir_iterator);
3352
+
3353
+ base_ref_iterator_free(ref_iterator);
3354
+ return ok;
3355
+}
3356
+
3357
+static struct ref_iterator_vtable files_reflog_iterator_vtable = {
3358
+ files_reflog_iterator_advance,
3359
+ files_reflog_iterator_peel,
3360
+ files_reflog_iterator_abort
3361
+};
3362
+
3363
+struct ref_iterator *files_reflog_iterator_begin(void)
3364
+{
3365
+ struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
3366
+ struct ref_iterator *ref_iterator = &iter->base;
3367
+
3368
+ base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
3369
+ iter->dir_iterator = dir_iterator_begin(git_path("logs"));
3370
+ return ref_iterator;
3371
}
3372
3373
int for_each_reflog(each_ref_fn fn, void *cb_data)
3374
{
3342
- int retval;
3343
- struct strbuf name;
3344
- strbuf_init(&name, PATH_MAX);
3345
- retval = do_for_each_reflog(&name, fn, cb_data);
3346
- strbuf_release(&name);
3347
- return retval;
3375
+ return do_for_each_ref_iterator(files_reflog_iterator_begin(),
3376
+ fn, cb_data);
3377
}
3378
3379
static int ref_update_reject_duplicates(struct string_list *refnames,
refs/refs-internal.h
+7
@@ -404,6 +404,13 @@ struct ref_iterator *files_ref_iterator_begin(const char *submodule,
404
const char *prefix,
405
unsigned int flags);
406
407
+/*
408
+ * Iterate over the references in the main ref_store that have a
409
+ * reflog. The paths within a directory are iterated over in arbitrary
410
+ * order.
411
+ */
412
+struct ref_iterator *files_reflog_iterator_begin(void);
413
+
414
/* Internal implementation of reference iteration: */
415
416
/*