commit - 4ddc9d7454d1838afd08981593a8b32332f3725f
commit + 9d88153b9f990652b2dd274efb7b561fc1446708
blob - ed6de8db29817b25f285cd13c8395a03bfa2e2aa
blob + 6e68ff331dae7881c9b5fdd240f869c658aedce6
--- gotd/repo_write.c
+++ gotd/repo_write.c
return got_error(GOT_ERR_PRIVSEP_NO_FD);
return NULL;
+}
+
+static char *
+get_datestr(time_t *time, char *datebuf)
+{
+ struct tm mytm, *tm;
+ char *p, *s;
+
+ tm = gmtime_r(time, &mytm);
+ if (tm == NULL)
+ return NULL;
+ s = asctime_r(tm, datebuf);
+ if (s == NULL)
+ return NULL;
+ p = strchr(s, '\n');
+ if (p)
+ *p = '\0';
+ return s;
+}
+
+static const struct got_error *
+print_commit_or_tag(int fd, struct got_object_id *id)
+{
+ const struct got_error *err;
+ struct got_object_id *commit_id;
+ struct got_commit_object *commit = NULL;
+ struct got_tag_object *tag = NULL;
+ char *commit_id_str = NULL;
+ char *logmsg = NULL, *datestr;
+ const char *author = NULL, *committer = NULL;
+ char datebuf[26];
+ time_t time;
+ int obj_type;
+
+ err = got_object_open_as_commit(&commit, repo_write.repo, id);
+ if (err) {
+ if (err->code != GOT_ERR_OBJ_TYPE)
+ return err;
+
+ err = got_object_open_as_tag(&tag, repo_write.repo, id);
+ if (err)
+ return err;
+
+ dprintf(fd, "Tag: %s\n", got_object_tag_get_name(tag));
+ dprintf(fd, "Tagger: %s\n", got_object_tag_get_tagger(tag));
+
+ obj_type = got_object_tag_get_object_type(tag);
+ if (obj_type != GOT_OBJ_TYPE_COMMIT)
+ goto done;
+
+ commit_id = got_object_tag_get_object_id(tag);
+ err = got_object_open_as_commit(&commit, repo_write.repo,
+ commit_id);
+ if (err)
+ goto done;
+ } else
+ commit_id = id;
+
+ err = got_object_id_str(&commit_id_str, commit_id);
+ if (err)
+ goto done;
+
+ err = got_object_commit_get_logmsg(&logmsg, commit);
+ if (err)
+ goto done;
+
+ committer = got_object_commit_get_committer(commit);
+ author = got_object_commit_get_author(commit);
+ dprintf(fd, "Commit: %s\n", commit_id_str);
+ dprintf(fd, "Committer: %s\n", committer);
+ datestr = get_datestr(&time, datebuf);
+ dprintf(fd, "Date: %s\n", datestr);
+ if (strcmp(author, committer) != 0)
+ dprintf(fd, "Author: %s\n", author);
+ dprintf(fd, "Log message:\n%s\n", logmsg);
+done:
+ if (commit)
+ got_object_commit_close(commit);
+ if (tag)
+ got_object_tag_close(tag);
+ free(commit_id_str);
+ free(logmsg);
+ return err;
+}
+
+static const struct got_error *
+notify_created_ref(const char *refname, uint8_t *sha1,
+ struct gotd_imsgev *iev, int fd)
+{
+ const struct got_error *err;
+ struct got_object_id id;
+ char *id_str;
+
+ memset(&id, 0, sizeof(id));
+ memcpy(id.sha1, sha1, sizeof(id.sha1));
+
+ err = got_object_id_str(&id_str, &id);
+ if (err)
+ return err;
+
+ dprintf(fd, "Created %s: %s\n", refname, id_str);
+ err = print_commit_or_tag(fd, &id);
+ free(id_str);
+ return err;
}
+static const struct got_error *
+notify_removed_ref(const char *refname, uint8_t *sha1,
+ struct gotd_imsgev *iev, int fd)
+{
+ const struct got_error *err;
+ struct got_object_id id;
+ char *id_str;
+
+ memset(&id, 0, sizeof(id));
+ memcpy(id.sha1, sha1, sizeof(id.sha1));
+
+ err = got_object_id_str(&id_str, &id);
+ if (err)
+ return err;
+
+ dprintf(fd, "Removed %s: %s\n", refname, id_str);
+ free(id_str);
+ return err;
+}
+
+static const struct got_error *
+notify_changed_ref(const char *refname, uint8_t *old_sha1,
+ uint8_t *new_sha1, struct gotd_imsgev *iev, int fd)
+{
+ const struct got_error *err;
+ struct got_object_id old_id, new_id;
+ char *old_id_str = NULL, *new_id_str = NULL;
+
+ memset(&old_id, 0, sizeof(old_id));
+ memcpy(old_id.sha1, old_sha1, sizeof(old_id.sha1));
+ memset(&new_id, 0, sizeof(new_id));
+ memcpy(new_id.sha1, new_sha1, sizeof(new_id.sha1));
+
+ err = got_object_id_str(&old_id_str, &old_id);
+ if (err)
+ return err;
+ err = got_object_id_str(&new_id_str, &new_id);
+ if (err)
+ goto done;
+
+ dprintf(fd, "Changed %s: %s\n", refname, new_id_str);
+ dprintf(fd, "(formerly %s)\n", old_id_str);
+
+ /* TODO: Walk commits and determine the new set... */
+done:
+ free(old_id_str);
+ free(new_id_str);
+ return err;
+}
+
+static const struct got_error *
+render_notification(struct imsg *imsg, struct gotd_imsgev *iev)
+{
+ const struct got_error *err = NULL;
+ struct gotd_imsg_notification_content ireq;
+ size_t datalen;
+ char *refname;
+
+ if (imsg->fd == -1)
+ return got_error(GOT_ERR_PRIVSEP_NO_FD);
+
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ if (datalen < sizeof(ireq))
+ return got_error(GOT_ERR_PRIVSEP_LEN);
+
+ memcpy(&ireq, imsg->data, sizeof(ireq));
+
+ if (datalen != sizeof(ireq) + ireq.refname_len)
+ return got_error(GOT_ERR_PRIVSEP_LEN);
+
+ refname = strndup(imsg->data + sizeof(ireq), ireq.refname_len);
+ if (refname == NULL)
+ return got_error_from_errno("strndup");
+
+ switch (ireq.action) {
+ case GOTD_NOTIF_ACTION_CREATED:
+ err = notify_created_ref(refname, ireq.new_id, iev, imsg->fd);
+ break;
+ case GOTD_NOTIF_ACTION_REMOVED:
+ err = notify_removed_ref(refname, ireq.old_id, iev, imsg->fd);
+ break;
+ case GOTD_NOTIF_ACTION_CHANGED:
+ err = notify_changed_ref(refname, ireq.old_id, ireq.new_id,
+ iev, imsg->fd);
+ break;
+ }
+
+ free(refname);
+ return err;
+}
+
static void
repo_write_dispatch_session(int fd, short event, void *arg)
{
log_warnx("update refs: %s", err->msg);
}
break;
+ case GOTD_IMSG_NOTIFY:
+ err = render_notification(&imsg, iev);
+ if (err)
+ log_warnx("render notification: %s", err->msg);
+ break;
default:
log_debug("unexpected imsg %d", imsg.hdr.type);
break;