* [PATCH] refs: refactor reflog reading code to be reusable
@ 2006-09-30 21:29 Jeff King
0 siblings, 0 replies; only message in thread
From: Jeff King @ 2006-09-30 21:29 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
This just moves code around; the behavior of read_ref_at (currently the
only user) should be identical.
Signed-off-by: Jeff King <peff@peff.net>
---
This patch is in preparation for doing more interesting things with
reflogs, like git-describe.
refs.c | 176 +++++++++++++++++++++++++++++++++++++++------------------------
refs.h | 21 ++++++++
2 files changed, 130 insertions(+), 67 deletions(-)
diff --git a/refs.c b/refs.c
index 3d4cdd1..f5dfe4d 100644
--- a/refs.c
+++ b/refs.c
@@ -615,83 +615,125 @@ int write_ref_sha1(struct ref_lock *lock
return 0;
}
-int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
+int reflog_open(struct reflog *log, const char *ref)
{
- const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
- char *tz_c;
- int logfd, tz;
+ int logfd;
struct stat st;
- unsigned long date;
- unsigned char logged_sha1[20];
- logfile = git_path("logs/%s", ref);
- logfd = open(logfile, O_RDONLY, 0);
+ log->file = xstrdup(git_path("logs/%s", ref));
+ logfd = open(log->file, O_RDONLY, 0);
if (logfd < 0)
- die("Unable to read log %s: %s", logfile, strerror(errno));
+ return -1;
fstat(logfd, &st);
- if (!st.st_size)
- die("Log %s is empty.", logfile);
- logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0);
+ log->size = st.st_size;
+ log->data = mmap(NULL, log->size, PROT_READ, MAP_PRIVATE, logfd, 0);
close(logfd);
+ return 0;
+}
- lastrec = NULL;
- rec = logend = logdata + st.st_size;
- while (logdata < rec) {
- if (logdata < rec && *(rec-1) == '\n')
- rec--;
- lastgt = NULL;
- while (logdata < rec && *(rec-1) != '\n') {
- rec--;
- if (*rec == '>')
- lastgt = rec;
- }
- if (!lastgt)
- die("Log %s is corrupt.", logfile);
- date = strtoul(lastgt + 1, &tz_c, 10);
- if (date <= at_time) {
- if (lastrec) {
- if (get_sha1_hex(lastrec, logged_sha1))
- die("Log %s is corrupt.", logfile);
- if (get_sha1_hex(rec + 41, sha1))
- die("Log %s is corrupt.", logfile);
- if (hashcmp(logged_sha1, sha1)) {
- tz = strtoul(tz_c, NULL, 10);
- fprintf(stderr,
- "warning: Log %s has gap after %s.\n",
- logfile, show_rfc2822_date(date, tz));
- }
- }
- else if (date == at_time) {
- if (get_sha1_hex(rec + 41, sha1))
- die("Log %s is corrupt.", logfile);
- }
- else {
- if (get_sha1_hex(rec + 41, logged_sha1))
- die("Log %s is corrupt.", logfile);
- if (hashcmp(logged_sha1, sha1)) {
- tz = strtoul(tz_c, NULL, 10);
- fprintf(stderr,
- "warning: Log %s unexpectedly ended on %s.\n",
- logfile, show_rfc2822_date(date, tz));
- }
- }
- munmap((void*)logdata, st.st_size);
+void reflog_close(struct reflog *log)
+{
+ free(log->file);
+ munmap((void *)log->data, log->size);
+}
+
+int reflog_next(struct reflog *log, struct reflog_entry *out)
+{
+ const char *rec, *lastgt;
+ char *tz_c;
+
+ rec = log->rec;
+ if (rec == log->data)
+ return 0;
+
+ lastgt = NULL;
+ if (log->data < rec && *(rec-1) == '\n')
+ rec--;
+ while (log->data < rec && *(rec-1) != '\n') {
+ rec--;
+ if (*rec == '>')
+ lastgt = rec;
+ }
+ if (log->data == rec - 1)
+ rec--;
+ if (!lastgt)
+ die("Log %s is corrupt (nolastgt).", log->file);
+
+ out->date = strtoul(lastgt + 1, &tz_c, 10);
+ out->tz = strtoul(tz_c, NULL, 10);
+ out->rec = rec;
+ out->log = log;
+ log->rec = rec;
+
+ return 1;
+}
+
+void reflog_start(struct reflog *log)
+{
+ log->rec = log->data + log->size;
+}
+
+void reflog_entry_from(const struct reflog_entry *e, unsigned char *sha1)
+{
+ if (get_sha1_hex(e->rec, sha1))
+ die("Log %s is corrupt.", e->log->file);
+}
+
+void reflog_entry_to(const struct reflog_entry *e, unsigned char *sha1)
+{
+ if (get_sha1_hex(e->rec+41, sha1))
+ die("Log %s is corrupt.", e->log->file);
+}
+
+int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
+{
+ struct reflog log;
+ struct reflog_entry cur, last;
+ int last_is_valid;
+ unsigned char sha1_from[20];
+ unsigned char sha1_to[20];
+
+ if (reflog_open(&log, ref) < 0)
+ die("Unable to read log %s: %s", log.file, strerror(errno));
+
+ last_is_valid = 0;
+ reflog_start(&log);
+ do {
+ if (!reflog_next(&log, &cur)) {
+ if (!last_is_valid)
+ die("Log %s is empty.", log.file);
+ reflog_entry_to(&last, sha1);
+ fprintf(stderr,
+ "warning: Log %s only goes back to %s.\n",
+ log.file,
+ show_rfc2822_date(last.date, last.tz));
+ reflog_close(&log);
return 0;
}
- lastrec = rec;
+ last = cur;
+ last_is_valid = 1;
+ } while (at_time < cur.date);
+
+ reflog_entry_to(&cur, sha1_to);
+ if (last_is_valid) {
+ reflog_entry_from(&last, sha1_from);
+ if (hashcmp(sha1_to, sha1_from)) {
+ fprintf(stderr,
+ "warning: Log %s has gap after %s.\n",
+ log.file,
+ show_rfc2822_date(cur.date, cur.tz));
+ }
+ }
+ else if(cur.date != at_time) {
+ if (hashcmp(sha1_to, sha1)) {
+ fprintf(stderr,
+ "warning: Log %s unexpectedly ended on %s.\n",
+ log.file,
+ show_rfc2822_date(cur.date, cur.tz));
+ }
}
- rec = logdata;
- while (rec < logend && *rec != '>' && *rec != '\n')
- rec++;
- if (rec == logend || *rec == '\n')
- die("Log %s is corrupt.", logfile);
- date = strtoul(rec + 1, &tz_c, 10);
- tz = strtoul(tz_c, NULL, 10);
- if (get_sha1_hex(logdata, sha1))
- die("Log %s is corrupt.", logfile);
- munmap((void*)logdata, st.st_size);
- fprintf(stderr, "warning: Log %s only goes back to %s.\n",
- logfile, show_rfc2822_date(date, tz));
+ reflog_close(&log);
+ hashcpy(sha1, sha1_to);
return 0;
}
diff --git a/refs.h b/refs.h
index 0d4d79e..9f2667b 100644
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,20 @@ struct ref_lock {
int force_write;
};
+struct reflog {
+ char *file;
+ const char *data;
+ unsigned long size;
+ const char *rec;
+};
+
+struct reflog_entry {
+ unsigned long date;
+ unsigned tz;
+ const char *rec;
+ const struct reflog *log;
+};
+
/*
* Calls the specified function for each ref file until it returns nonzero,
* and returns the value
@@ -44,4 +58,11 @@ extern int read_ref_at(const char *ref,
/** Returns 0 if target has the right format for a ref. **/
extern int check_ref_format(const char *target);
+int reflog_open(struct reflog *log, const char *ref);
+void reflog_close(struct reflog *log);
+void reflog_start(struct reflog *log);
+int reflog_next(struct reflog *log, struct reflog_entry *out);
+void reflog_entry_from(const struct reflog_entry *e, unsigned char *sha1);
+void reflog_entry_to(const struct reflog_entry *e, unsigned char *sha1);
+
#endif /* REFS_H */
--
1.4.2.1.g67e7-dirty
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2006-09-30 21:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-30 21:29 [PATCH] refs: refactor reflog reading code to be reusable Jeff King
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).