about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--catsit-watch.19
-rw-r--r--catsit-watch.c24
2 files changed, 30 insertions, 3 deletions
diff --git a/catsit-watch.1 b/catsit-watch.1
index 892fd18..5e97bdd 100644
--- a/catsit-watch.1
+++ b/catsit-watch.1
@@ -9,6 +9,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl ai
+.Op Fl d Ar delay
 .Op Fl f Ar file
 .Ar command ...
 .
@@ -17,7 +18,7 @@ The
 .Nm
 utility runs a command
 each time any of a set of files
-are modified.
+are written to.
 If any watched files are removed
 or if the command exits non-zero,
 .Nm
@@ -31,6 +32,12 @@ Append the path of
 the modified file
 to the arguments of
 .Ar command .
+.It Fl d Ar delay
+Wait
+.Ar delay
+milliseconds before running the command.
+Any further writes within that time
+do not trigger additional runs.
 .It Fl f Ar file
 Add
 .Ar file
diff --git a/catsit-watch.c b/catsit-watch.c
index ea64155..78d1cb2 100644
--- a/catsit-watch.c
+++ b/catsit-watch.c
@@ -65,10 +65,12 @@ int main(int argc, char *argv[]) {
 	fcntl(kq, F_SETFD, FD_CLOEXEC);
 
 	int init = 0;
+	int delay = 0;
 	int append = 0;
-	for (int opt; 0 < (opt = getopt(argc, argv, "af:i"));) {
+	for (int opt; 0 < (opt = getopt(argc, argv, "ad:f:i"));) {
 		switch (opt) {
 			break; case 'a': append = 1;
+			break; case 'd': delay = strtol(optarg, NULL, 10);
 			break; case 'f': watch(kq, optarg);
 			break; case 'i': init = 1;
 			break; default: return EX_USAGE;
@@ -96,9 +98,27 @@ int main(int argc, char *argv[]) {
 		int nevents = kevent(kq, NULL, 0, &event, 1, NULL);
 		if (nevents < 0) err(EX_OSERR, "kevent");
 
-		if (event.fflags & NOTE_DELETE) {
+		if (delay) {
+			struct kevent timer;
+			EV_SET(
+				&timer, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
+				0, delay, event.udata
+			);
+			nevents = kevent(kq, &timer, 1, NULL, 0, NULL);
+			if (nevents < 0) err(EX_OSERR, "kevent");
+			while (
+				event.filter != EVFILT_TIMER
+				&& !(event.fflags & NOTE_DELETE)
+			) {
+				nevents = kevent(kq, NULL, 0, &event, 1, NULL);
+				if (nevents < 0) err(EX_OSERR, "kevent");
+			}
+		}
+
+		if (event.filter == EVFILT_VNODE && event.fflags & NOTE_DELETE) {
 			errx(EX_TEMPFAIL, "%s: file removed", (char *)event.udata);
 		}
+
 		if (append) rest[argc] = (char *)event.udata;
 		run(rest);
 	}