Hello community,
here is the log from the commit of package entr for openSUSE:Factory checked in at 2017-11-08 15:10:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/entr (Old)
and /work/SRC/openSUSE:Factory/.entr.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "entr"
Wed Nov 8 15:10:41 2017 rev:2 rq:539446 version:3.9
Changes:
--------
--- /work/SRC/openSUSE:Factory/entr/entr.changes 2017-07-10 11:07:33.162868728 +0200
+++ /work/SRC/openSUSE:Factory/.entr.new/entr.changes 2017-11-08 15:10:46.460644641 +0100
@@ -1,0 +2,18 @@
+Tue Nov 7 03:00:10 UTC 2017 - aavindraa@gmail.com
+
+- Bump to 3.9
+ * Fix use of poll(2) to avoid possible busy-loop on Linux
+ * Disable keyboard input if STDIN read fails
+- Includes changes from 3.8
+ * Run the utility if spacebar is pressed
+ * 'q' for quit
+- Includes changes from 3.7
+ * Terminate subprocess in restart mode if a file under watch
+ disappears
+ * Allow NOTE_ATTRIB to set '/_' only if file mode changes
+ * New '-s' option executes commands using $SHELL -c
+ * Print usage and exit if input is from tty instead of pipe
+- Switch to bz2 download (smaller filesize)
+- Cleanup with spec-cleaner
+
+-------------------------------------------------------------------
Old:
----
entr-3.6.tar.gz
New:
----
entr-3.9.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ entr.spec ++++++
--- /var/tmp/diff_new_pack.joH7Je/_old 2017-11-08 15:10:47.240616166 +0100
+++ /var/tmp/diff_new_pack.joH7Je/_new 2017-11-08 15:10:47.244616020 +0100
@@ -1,7 +1,7 @@
#
# spec file for package entr
#
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
# Copyright (c) 2016 Daniel Lichtenberger
#
# All modifications and additions to the file contributed by third parties
@@ -18,13 +18,13 @@
Name: entr
-Version: 3.6
+Version: 3.9
Release: 0
Summary: A utility for running arbitrary commands when files change
License: ISC
Group: Development/Tools/Other
Url: https://bitbucket.org/eradman/entr
-Source0: https://bitbucket.org/eradman/entr/get/entr-%{version}.tar.gz
+Source0: https://bitbucket.org/eradman/entr/get/entr-%{version}.tar.bz2
Source1: LICENSE
%description
@@ -50,7 +50,6 @@
make %{?_smp_mflags} test
%files
-%defattr(-,root,root,-)
%doc LICENSE NEWS README.md
%{_bindir}/%{name}
%{_mandir}/man1/%{name}.1%{ext_man}
++++++ entr-3.6.tar.gz -> entr-3.9.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/.hg_archival.txt new/eradman-entr-332fd96a324a/.hg_archival.txt
--- old/eradman-entr-c15b0be493fc/.hg_archival.txt 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/.hg_archival.txt 2017-09-19 20:58:52.000000000 +0200
@@ -1,4 +1,4 @@
repo: 49108c05f40cf0f2abceacff753c2df1cd22e1ec
-node: c15b0be493fc70e6e13c2a7fa451486aa1bc71a3
+node: 332fd96a324a7771b0d2252027c44eb972fd38dc
branch: default
-tag: entr-3.6
+tag: entr-3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/.hgtags new/eradman-entr-332fd96a324a/.hgtags
--- old/eradman-entr-c15b0be493fc/.hgtags 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/.hgtags 2017-09-19 20:58:52.000000000 +0200
@@ -110,3 +110,6 @@
0000000000000000000000000000000000000000 entr-3.4
5321b01c9dabf8cf6d5bacd10c56b126215a1fe3 entr-3.4
6977480460701561ce674ff03173bd9a8722fee7 entr-3.5
+c15b0be493fc70e6e13c2a7fa451486aa1bc71a3 entr-3.6
+c5b62bde107d1b30af43fccc0398a5694a9b6b67 entr-3.7
+592856d50559bc48fef4b27cc5c2bc4eacb69428 entr-3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/Makefile.bsd new/eradman-entr-332fd96a324a/Makefile.bsd
--- old/eradman-entr-c15b0be493fc/Makefile.bsd 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/Makefile.bsd 2017-09-19 20:58:52.000000000 +0200
@@ -1,6 +1,6 @@
PREFIX ?= /usr/local
MANPREFIX ?= ${PREFIX}/man
-RELEASE = 3.6
+RELEASE = 3.9
CPPFLAGS += -DRELEASE=\"${RELEASE}\"
all: versioncheck entr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/NEWS new/eradman-entr-332fd96a324a/NEWS
--- old/eradman-entr-c15b0be493fc/NEWS 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/NEWS 2017-09-19 20:58:52.000000000 +0200
@@ -1,5 +1,22 @@
= Release History
+== 3.9: September 19, 2017
+
+ - Fix use of poll(2) to avoid possible busy-loop on Linux
+ - Disable keyboard input if reading STDIN fails
+
+== 3.8: August 11, 2017
+
+ - Run the utility if the spacebar is pressed
+ - 'q' for quit
+
+== 3.7: February 27, 2017
+
+ - Terminate subprocess in restart mode if a file under watch disappears
+ - Allow NOTE_ATTRIB to set '/_' only if file mode changes
+ - New '-s' option executes commands using $SHELL -c
+ - Print usage and exit if input is from a terminal instead of a pipe
+
== 3.6: July 01, 2016
- Do not print warning if _TTY_PATH cannot be opened (for chroot, docker, ...)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/README.md new/eradman-entr-332fd96a324a/README.md
--- old/eradman-entr-c15b0be493fc/README.md 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/README.md 2017-09-19 20:58:52.000000000 +0200
@@ -1,13 +1,12 @@
Event Notify Test Runner
========================
-A utility for running arbitrary commands when files change. Uses
-[kqueue(2)][kqueue_2] or [inotify(7)][inotify_7] to avoid polling. `entr` was
-written to make rapid feedback and automated testing natural and completely
-ordinary.
+A utility for running arbitrary commands when files change. Uses [kqueue(2)] or
+[inotify(7)] to avoid polling. `entr` was written to make rapid feedback and
+automated testing natural and completely ordinary.
-Installation - BSD, Mac OS, and Linux
--------------------------------------
+Source Installation - BSD, Mac OS, and Linux
+--------------------------------------------
./configure
make test
@@ -15,23 +14,18 @@
To see available build options run `./configure -h`
-Installation - Mac OS/Homebrew
-------------------------------
+Binary Installation
+-------------------
- brew install entr
+The following distributions provide `entr` as part of their main
+package repository:
-Installation - Ports
---------------------
+* OpenBSD and FreeBSD
+* Mac OS using Homebrew or MacPorts
+* Debian, Ubuntu, Fedora, and Alpine Linux
-Available in OpenBSD ports, FreeBSD ports, and pkgsrc under `sysutils/entr`.
-
-Installation - Debian
----------------------
-
- apt-get install entr
-
-Examples from `man entr`
-------------------------
+Man Page Examples
+-----------------
Rebuild a project if source files change, limiting output to the first 20 lines:
@@ -41,6 +35,10 @@
$ ls *.js | entr -r node app.js
+Launch and auto-reload a node.js server as a background task:
+
+ $ (ls *.js | entr -r node app.js &)
+
Clear the screen and run a query after the SQL script is updated:
$ echo my.sql | entr -p psql -f /_
@@ -53,15 +51,15 @@
----
A release history as well as features in the upcoming release are covered in the
-[NEWS][NEWS] file.
+[NEWS] file.
License
-------
-Source is under and ISC-style license. See the [LICENSE][LICENSE] file for more
-detailed information on the license used for compatibility libraries.
+Source is under and ISC-style license. See the [LICENSE] file for more detailed
+information on the license used for compatibility libraries.
-[kqueue_2]: http://www.openbsd.org/cgi-bin/man.cgi?query=kqueue&manpath=OpenBSD+Current&format=html
-[inotify_7]: http://man.he.net/?section=all&topic=inotify
+[kqueue(2)]: http://man.openbsd.org/OpenBSD-current/man2/kqueue.2
+[inotify(7)]: http://man.he.net/?section=all&topic=inotify
[NEWS]: http://www.bitbucket.org/eradman/entr/src/default/NEWS
[LICENSE]: http://www.bitbucket.org/eradman/entr/src/default/LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/entr.1 new/eradman-entr-332fd96a324a/entr.1
--- old/eradman-entr-c15b0be493fc/entr.1 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/entr.1 2017-09-19 20:58:52.000000000 +0200
@@ -13,7 +13,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd May 17, 2016
+.Dd September 14, 2017
.Dt ENTR 1
.Os
.Sh NAME
@@ -21,10 +21,9 @@
.Nd run arbitrary commands when files change
.Sh SYNOPSIS
.Nm
-.Op Fl cdpr
+.Op Fl cdprs
.Ar utility
-.Op Ar argument ...
-.Op Ar /_
+.Op Ar argument /_ ...
.Sh DESCRIPTION
A list of files provided on the standard input and the
.Ar utility
@@ -64,21 +63,47 @@
waits for the
.Ar utility
to exit to ensure that resources such as sockets have been closed.
+.It Fl s
+Evaluate the first argument using the interpreter specified by the
+.Ev SHELL
+environment variable.
+When this flag is set, the name of the shell and exit code is printed after each
+invocation.
.El
.Pp
-The first occurrence of
+The first argument named
.Ar /_
-on the command line will be replaced with the absolute path of the first file that was modified.
+is replaced with the absolute path of the first file to trigger an event.
If the restart option is used the first file under watch is treated as the default.
+.Sh COMMANDS
+.Nm
+listens for keyboard input and responds to the following commands:
+.Bl -tag -width Ic
+.It SPACE
+Execute the utility immediately.
+If the
+.Ql -r
+option is set this will terminate and restart the child process as if a file
+change event had occurred.
+.It q
+Quit; equivalent pressing Ctrl\-C.
+.El
.Sh ENVIRONMENT
If
.Ev PAGER
is undefined,
-.Nm entr
+.Nm
will assign
.Pa /bin/cat
to prevent interactive utilities from waiting for
keyboard input if output does not fit on the screen.
+.Pp
+If
+.Ev SHELL
+is undefined,
+.Nm entr
+will use
+.Pa /bin/sh .
.Sh EXIT STATUS
The
.Nm
@@ -98,12 +123,16 @@
.Sh EXAMPLES
Rebuild a project if source files change, limiting output to the first 20 lines:
.Pp
-.Dl $ find src/ | entr sh -c 'make | head -n 20'
+.Dl $ find src/ | entr -s 'make | head -n 20'
.Pp
Launch and auto-reload a node.js server:
.Pp
.Dl $ ls *.js | entr -r node app.js
.Pp
+Launch and auto-reload a node.js server as a background task:
+.Pp
+.Dl $ (ls *.js | entr -r node app.js &)
+.Pp
Clear the screen and run a query after the SQL script is updated:
.Pp
.Dl $ echo my.sql | entr -p psql -f /_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/entr.c new/eradman-entr-332fd96a324a/entr.c
--- old/eradman-entr-c15b0be493fc/entr.c 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/entr.c 2017-09-19 20:58:52.000000000 +0200
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include "missing/compat.h"
@@ -63,6 +64,7 @@
void (*xwarnx)(const char *, ...);
void (*xerrx)(int, const char *, ...);
int (*xlist_dir)(char *);
+int (*xtcsetattr)(int fd, int action, const struct termios *tp);
/* globals */
@@ -75,6 +77,7 @@
int dirwatch_opt;
int restart_opt;
int postpone_opt;
+int shell_opt;
/* forwards */
@@ -102,6 +105,7 @@
short argv_index;
int n_files;
int i;
+ struct kevent evSet;
if ((*test_runner_main))
return(test_runner_main(argc, argv));
@@ -119,6 +123,7 @@
xwarnx = warnx;
xerrx = errx;
xlist_dir = list_dir;
+ xtcsetattr = tcsetattr;
/* call usage() if no command is supplied */
if (argc < 2) usage();
@@ -142,12 +147,19 @@
/* prevent interactive utilities from paging output */
setenv("PAGER", "/bin/cat", 0);
+ /* ensure a shell is available to use */
+ setenv("SHELL", "/bin/sh", 0);
+
/* sequential scan may depend on a 0 at the end */
files = calloc(rl.rlim_cur+1, sizeof(WatchFile *));
if ((kq = kqueue()) == -1)
err(1, "cannot create kqueue");
+ /* expect file list from a pipe */
+ if (isatty(fileno(stdin)))
+ usage();
+
/* read input and populate watch list, skipping non-regular files */
n_files = process_input(stdin, files, rl.rlim_cur);
if (n_files == 0)
@@ -167,6 +179,11 @@
close(ttyfd);
}
+ /* Use keyboard input as a trigger */
+ EV_SET(&evSet, STDIN_FILENO, EVFILT_READ, EV_ADD, NOTE_LOWAT, 1, NULL);
+ if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1)
+ err(1, "failed to register stdin");
+
watch_loop(kq, argv+argv_index);
return 1;
}
@@ -176,7 +193,7 @@
void
usage() {
fprintf(stderr, "release: %s\n", RELEASE);
- fprintf(stderr, "usage: entr [-cdpr] utility [args, [/_], ...] < filenames\n");
+ fprintf(stderr, "usage: entr [-cdprs] utility [argument [/_] ...] < filenames\n");
exit(1);
}
@@ -281,7 +298,7 @@
/* read arguments until we reach a command */
for (argc=1; argv[argc] != 0 && argv[argc][0] == '-'; argc++);
- while ((ch = getopt(argc, argv, "cdpr")) != -1) {
+ while ((ch = getopt(argc, argv, "cdprs")) != -1) {
switch (ch) {
case 'c':
clear_opt = 1;
@@ -295,13 +312,17 @@
case 'r':
restart_opt = 1;
break;
+ case 's':
+ shell_opt = 1;
+ break;
default:
usage();
}
}
- /* no command to run */
if (argv[optind] == '\0')
usage();
+ if ((shell_opt == 1) && (argv[optind+1] != '\0'))
+ xerrx(1, "-s requires commands to be formatted as a single argument");
return optind;
}
@@ -322,21 +343,34 @@
if (restart_opt == 1)
terminate_utility();
- /* clone argv on each invocation to make the implementation of more
- * complex subsitution rules possible and easy
- */
- for (argc=0; argv[argc]; argc++);
- arg_buf = malloc(ARG_MAX);
- new_argv = calloc(argc+1, sizeof(char *));
- for (m=0, i=0, p=arg_buf; ifn, p));
- m++;
+ if (shell_opt == 1) {
+ /* run argv[1] with a shell using the leading edge as $0 */
+ argc = 4;
+ arg_buf = malloc(ARG_MAX);
+ new_argv = calloc(argc+1, sizeof(char *));
+ (void) xrealpath(leading_edge->fn, arg_buf);
+ new_argv[0] = getenv("SHELL");
+ new_argv[1] = "-c";
+ new_argv[2] = argv[0];
+ new_argv[3] = arg_buf;
+ }
+ else {
+ /* clone argv on each invocation to make the implementation of more
+ * complex subsitution rules possible and easy
+ */
+ for (argc=0; argv[argc]; argc++);
+ arg_buf = malloc(ARG_MAX);
+ new_argv = calloc(argc+1, sizeof(char *));
+ for (m=0, i=0, p=arg_buf; ifn, p));
+ m++;
+ }
+ else
+ p += strlcpy(p, argv[i], ARG_MAX - (p - arg_buf));
+ p++;
}
- else
- p += strlcpy(p, argv[i], ARG_MAX - (p - arg_buf));
- p++;
}
pid = xfork();
@@ -360,8 +394,12 @@
}
child_pid = pid;
- if (restart_opt == 0)
+ if (restart_opt == 0) {
xwaitpid(pid, &status, 0);
+ if (shell_opt == 1)
+ fprintf(stdout, "%s returned exit code %d\n",
+ basename(getenv("SHELL")), WEXITSTATUS(status));
+ }
xfree(arg_buf);
xfree(new_argv);
@@ -386,8 +424,10 @@
if (file->fd == -1) nanosleep(&delay, NULL);
else break;
}
- if (file->fd == -1)
+ if (file->fd == -1) {
+ terminate_utility();
err(1, "cannot open '%s'", file->fn);
+ }
EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0,
file);
@@ -445,37 +485,62 @@
int dir_modified = 0;
int leading_edge_set = 0;
struct stat sb;
+ struct termios canonical_tty, character_tty;
+ char c;
leading_edge = files[0]; /* default */
if (postpone_opt == 0)
run_utility(argv);
+ /* disabling/restore line buffering and local echo */
+ tcgetattr(STDIN_FILENO, &canonical_tty);
+ character_tty = canonical_tty;
+ character_tty.c_lflag &= ~(ICANON|ECHO);
+
main:
- if ((reopen_only == 1) || (collate_only == 1))
+ xtcsetattr(STDIN_FILENO, TCSADRAIN, &character_tty);
+ if ((reopen_only == 1) || (collate_only == 1)) {
nev = xkevent(kq, NULL, 0, evList, 32, &evTimeout);
+ }
else {
nev = xkevent(kq, NULL, 0, evList, 32, NULL);
dir_modified = 0;
}
+
+ if (nev == -1)
+ err(1, "kevent failed");
+
/* escape for test runner */
if ((nev == -2) && (collate_only == 0))
return;
for (i=0; iis_dir == 1)
dir_modified += compare_dir_contents(file);
- else if (leading_edge_set == 0)
- if ((reopen_only == 0) && (collate_only == 0)) {
- leading_edge = file;
- leading_edge_set = 1;
- }
}
+ xtcsetattr(0, TCSADRAIN, &canonical_tty);
collate_only = 0;
for (i=0; iis_dir == 1) && (dir_modified == 0))
continue;
@@ -513,6 +580,12 @@
do_exec = 1;
file->mode = sb.st_mode;
}
+ else if (evList[i].fflags & NOTE_ATTRIB)
+ continue;
+ if ((file->is_dir == 0) && (leading_edge_set == 0)) {
+ leading_edge = file;
+ leading_edge_set = 1;
+ }
}
if (collate_only == 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/entr_spec.c new/eradman-entr-332fd96a324a/entr_spec.c
--- old/eradman-entr-c15b0be493fc/entr_spec.c 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/entr_spec.c 2017-09-19 20:58:52.000000000 +0200
@@ -84,12 +84,15 @@
dirwatch_opt = 0;
postpone_opt = 0;
restart_opt = 0;
+ shell_opt = 0;
leading_edge = 0;
files = calloc(max_files, sizeof(WatchFile *));
for (i=0; ifn, "main.rb", sizeof(files[0]->fn));
+ watch_file(kq, files[0]);
+
+ ctx.event.nlist = 0;
+ watch_loop(kq, argv);
+
+ ok(strcmp(leading_edge->fn, "main.rb") == 0);
+ ok(ctx.event.nset == 1);
+ ok(ctx.event.Set[0].ident);
+ ok(ctx.event.Set[0].filter == EVFILT_VNODE);
+ ok(ctx.event.Set[0].flags == (EV_CLEAR|EV_ADD)); /* open */
+ ok(ctx.event.Set[0].fflags == (NOTE_ALL));
+ ok(ctx.event.Set[0].udata == files[0]);
+
+ ok(ctx.exec.count == 1);
+ ok(ctx.exec.file != 0);
+ ok(strcmp(ctx.exec.file, "/bin/Xsh") == 0); /* FIXME */
+ ok(strcmp(ctx.exec.argv[0], "/bin/Xsh") == 0);
+ ok(strcmp(ctx.exec.argv[1], "-c") == 0);
+ ok(strcmp(ctx.exec.argv[2], "ruby main.rb") == 0);
+ return 0;
+}
+
+/*
* Parse command line arguments up to but not including the utility to execute
*/
int set_options_01() {
@@ -717,6 +756,38 @@
ok(argv_offset == 1);
ok(restart_opt == 0);
ok(clear_opt == 0);
+ ok(shell_opt == 0);
+ return 0;
+}
+
+/*
+ * Run arguments in a shell
+ */
+int set_options_06() {
+ int argv_offset;
+ char *argv[] = { "entr", "-s", "make test", NULL };
+
+ argv_offset = set_options(argv);
+
+ ok(argv_offset == 2);
+ ok(restart_opt == 0);
+ ok(clear_opt == 0);
+ ok(shell_opt == 1);
+ return 0;
+}
+
+/*
+ * All command must be formatted as a single argument when run in a shell
+ */
+int set_options_07() {
+ int argv_offset;
+ char *argv[] = { "entr", "-s", "make", "test", NULL };
+
+ argv_offset = set_options(argv);
+
+ ok(argv_offset == 2);
+ ok(shell_opt == 1);
+ ok(ctx.exit.count == 1);
return 0;
}
@@ -856,6 +927,7 @@
xerrx = fake_errx;
xwarnx = fake_warnx;
xlist_dir = fake_list_dir;
+ xtcsetattr = fake_tcsetattr;
/* all tests */
run(process_input_01);
@@ -871,11 +943,14 @@
run(watch_fd_exec_07);
run(watch_fd_exec_08);
run(watch_fd_exec_09);
+ run(watch_fd_shell_01);
run(set_options_01);
run(set_options_02);
run(set_options_03);
run(set_options_04);
run(set_options_05);
+ run(set_options_06);
+ run(set_options_07);
run(watch_fd_restart_01);
run(watch_fd_restart_02);
run(run_utility_01);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/missing/kqueue_inotify.c new/eradman-entr-332fd96a324a/missing/kqueue_inotify.c
--- old/eradman-entr-c15b0be493fc/missing/kqueue_inotify.c 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/missing/kqueue_inotify.c 2017-09-19 20:58:52.000000000 +0200
@@ -17,10 +17,12 @@
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -32,6 +34,7 @@
/* globals */
extern WatchFile **files;
+int read_stdin;
/* forwards */
@@ -54,7 +57,7 @@
#define EVENT_SIZE (sizeof (struct inotify_event))
#define EVENT_BUF_LEN (32 * (EVENT_SIZE + 16))
-#define IN_ALL IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE
+#define IN_ALL IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE
/*
* Conveniently inotify and kqueue ids both have the type `int`
@@ -65,8 +68,9 @@
}
/*
- * Emulate kqueue(2). Only the flags used in entr.c are considered
- * Returns the number of eventlist structs filled by this call
+ * Emulate kqueue(2). Only monitors STDIN for EVFILT_READ and only the
+ * EVFILT_VNODE flags used in entr.c are considered. Returns the number of
+ * eventlist structs filled by this call
*/
int
kevent(int kq, const struct kevent *changelist, int nchanges, struct
@@ -81,14 +85,31 @@
u_int fflags;
const struct kevent *kev;
int ignored;
- struct pollfd pfd;
- struct stat sb;
+ struct pollfd *pfd;
+ int nfds;
+
+ pfd = calloc(2, sizeof(struct pollfd));
+ pfd[0].fd = kq;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = STDIN_FILENO;
+ pfd[1].events = POLLIN;
if (nchanges > 0) {
ignored = 0;
for (n=0; nudata;
+
+ if (kev->filter == EVFILT_READ) {
+ if (kev->flags & EV_ADD)
+ read_stdin = 1;
+ if (kev->flags & EV_DELETE)
+ read_stdin = 0;
+ }
+
+ if (kev->filter != EVFILT_VNODE)
+ continue;
+
if (kev->flags & EV_DELETE) {
inotify_rm_watch(kq /* ifd */, kev->ident);
file->fd = -1; /* invalidate */
@@ -107,50 +128,74 @@
return nchanges - ignored;
}
- pfd.fd = kq;
- pfd.events = POLLIN;
- if (timeout != 0 && (poll(&pfd, 1, timeout->tv_nsec/1000000) == 0))
- return 0;
+ if (read_stdin == 1)
+ nfds = 2; /* inotify and stdin */
+ else
+ nfds = 1; /* inotify */
+ if (timeout == NULL)
+ poll(pfd, nfds, -1);
+ else
+ poll(pfd, nfds, timeout->tv_nsec/1000000);
n = 0;
do {
- pos = 0;
- len = read(kq /* ifd */, &buf, EVENT_BUF_LEN);
- if (len < 0) {
- /* SA_RESTART doesn't work for inotify fds */
- if (errno == EINTR)
- continue;
- else
- perror("read");
+ if (pfd[0].revents & (POLLERR|POLLNVAL))
+ errx(1, "bad fd %d", pfd[0].fd);
+ if (pfd[0].revents & POLLIN) {
+ pos = 0;
+ len = read(kq /* ifd */, &buf, EVENT_BUF_LEN);
+ if (len < 0) {
+ /* SA_RESTART doesn't work for inotify fds */
+ if (errno == EINTR)
+ continue;
+ else
+ errx(1, "read of fd %d failed", pfd[0].fd);
+ }
+ while ((pos < len) && (n < nevents)) {
+ iev = (struct inotify_event *) &buf[pos];
+ pos += EVENT_SIZE + iev->len;
+
+ /* convert iev->mask; to comparable kqueue flags */
+ fflags = 0;
+ if (iev->mask & IN_DELETE_SELF) fflags |= NOTE_DELETE;
+ if (iev->mask & IN_CLOSE_WRITE) fflags |= NOTE_WRITE;
+ if (iev->mask & IN_CREATE) fflags |= NOTE_WRITE;
+ if (iev->mask & IN_MOVE_SELF) fflags |= NOTE_RENAME;
+ if (iev->mask & IN_ATTRIB) fflags |= NOTE_ATTRIB;
+ if (fflags == 0) continue;
+
+ /* merge events if we're not acting on a new file descriptor */
+ if ((n > 0) && (eventlist[n-1].ident == iev->wd))
+ fflags |= eventlist[--n].fflags;
+
+ eventlist[n].ident = iev->wd;
+ eventlist[n].filter = EVFILT_VNODE;
+ eventlist[n].flags = 0;
+ eventlist[n].fflags = fflags;
+ eventlist[n].data = 0;
+ eventlist[n].udata = file_by_descriptor(iev->wd);
+ if (eventlist[n].udata)
+ n++;
+ }
}
- while ((pos < len) && (n < nevents)) {
- iev = (struct inotify_event *) &buf[pos];
- pos += EVENT_SIZE + iev->len;
-
- /* convert iev->mask; to comparable kqueue flags */
- fflags = 0;
- if (iev->mask & IN_DELETE_SELF) fflags |= NOTE_DELETE;
- if (iev->mask & IN_CLOSE_WRITE) fflags |= NOTE_WRITE;
- if (iev->mask & IN_CREATE) fflags |= NOTE_WRITE;
- if (iev->mask & IN_MOVE_SELF) fflags |= NOTE_RENAME;
- if (iev->mask & IN_ATTRIB) fflags |= NOTE_ATTRIB;
- if (fflags == 0) continue;
-
- /* merge events if we're not acting on a new file descriptor */
- if ((n > 0) && (eventlist[n-1].ident == iev->wd))
- fflags |= eventlist[--n].fflags;
-
- eventlist[n].ident = iev->wd;
- eventlist[n].filter = EVFILT_VNODE;
- eventlist[n].flags = 0;
- eventlist[n].fflags = fflags;
- eventlist[n].data = 0;
- eventlist[n].udata = file_by_descriptor(iev->wd);
- if (eventlist[n].udata)
+ if (read_stdin == 1) {
+ if (pfd[1].revents & (POLLERR|POLLNVAL))
+ errx(1, "bad fd %d", pfd[1].fd);
+ else if (pfd[1].revents & (POLLHUP|POLLIN)) {
+ fflags = 0;
+ eventlist[n].ident = pfd[1].fd;
+ eventlist[n].filter = EVFILT_READ;
+ eventlist[n].flags = 0;
+ eventlist[n].fflags = fflags;
+ eventlist[n].data = 0;
+ eventlist[n].udata = NULL;
n++;
+ break;
+ }
}
}
- while ((poll(&pfd, 1, 50) > 0));
-
+ while ((poll(pfd, nfds, 50) > 0));
+
+ (void) free(pfd);
return n;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/missing/sys/event.h new/eradman-entr-332fd96a324a/missing/sys/event.h
--- old/eradman-entr-c15b0be493fc/missing/sys/event.h 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/missing/sys/event.h 2017-09-19 20:58:52.000000000 +0200
@@ -27,6 +27,7 @@
#include
#include
+#define EVFILT_READ (-1)
#define EVFILT_VNODE (-4) /* attached to vnodes */
/* actions */
@@ -40,6 +41,11 @@
#define EV_CLEAR 0x0020 /* clear event state after reporting */
/*
+ * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
+ */
+#define NOTE_LOWAT 0x0001 /* low water mark */
+
+/*
* data/hint flags for EVFILT_VNODE, shared with userspace
*/
#define NOTE_DELETE 0x0001 /* vnode was removed */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/eradman-entr-c15b0be493fc/system_test.sh new/eradman-entr-332fd96a324a/system_test.sh
--- old/eradman-entr-c15b0be493fc/system_test.sh 2016-07-01 16:20:59.000000000 +0200
+++ new/eradman-entr-332fd96a324a/system_test.sh 2017-09-19 20:58:52.000000000 +0200
@@ -17,7 +17,7 @@
# test runner
trap 'printf "$0: exit code $? on line $LINENO\nFAIL: $this\n"; exit 1' ERR \
- 2> /dev/null || exec bash $0 "$@"
+ 2> /dev/null || exec bash $0 "$@"
typeset -i tests=0
function try { let tests+=1; this="$1"; }
@@ -29,11 +29,17 @@
function zz { sleep 0.25; }
function setup { rm -f $tmp/*; touch $tmp/file{1,2}; zz; }
-tmp=$(cd $(mktemp -dt entr_system_test.XXXXXXXXXX); pwd -P)
+tmp=$(cd $(mktemp -d ${TMPDIR:-/tmp}/entr-system-test-XXXXXX); pwd -P)
+tsession=$(basename $tmp)
+
+clear_tty='test -t 0 && stty echo icanon'
+clear_tmux='tmux kill-session -t $tsession 2>/dev/null || true'
+clear_tmp='rm -r $tmp'
+trap "$clear_tty; $clear_tmux; $clear_tmp" EXIT
# required utilities
-utils="hg vim"
+utils="hg vim tmux"
for util in $utils; do
p=$(which $util 2> /dev/null) || {
echo "ERROR: could not locate the '$util' utility" >&2
@@ -42,12 +48,16 @@
}
done
-# tests
+# fast tests
try "no arguments"
./entr 2> /dev/null || code=$?
assert $code 1
+try "no input"
+ ./entr echo "vroom" 2> /dev/null || code=$?
+ assert $code 1
+
try "reload and clear options with no utility to run"
./entr -r -c 2> /dev/null || code=$?
assert $code 1
@@ -62,6 +72,27 @@
rmdir $tmp/dir1
assert $code 1
+# terminal tests
+
+unset TMUX
+
+try "spacebar triggers utility"
+ setup
+ tmux new-session -s $tsession -d
+ echo "waiting" > $tmp/file1
+ echo "finished" > $tmp/file2
+ tmux send-keys -t $tsession:0 \
+ "ls $tmp/file2 | ./entr -p cp $tmp/file2 $tmp/file1" C-m ; zz
+ assert "$(cat $tmp/file1)" "waiting"
+ tmux send-keys -t $tsession:0 "xyz" C-m ; zz
+ assert "$(cat $tmp/file1)" "waiting"
+ tmux send-keys -t $tsession:0 " " ; zz
+ assert "$(cat $tmp/file1)" "finished"
+ tmux send-keys -t $tsession:0 "q" ; zz
+ tmux kill-session -t $tsession
+
+# file system tests
+
try "exec single shell utility and exit when a file is added to an implicit watch path"
setup
ls $tmp/file* | ./entr -dp sh -c 'echo ping' >$tmp/exec.out 2>$tmp/exec.err \
@@ -252,12 +283,10 @@
setup
ls $tmp/file* | ./entr -p cat /_ > $tmp/exec.out &
bgpid=$! ; zz
- echo 123 > $tmp/file2 ; zz
- echo 456 > $tmp/file1
- echo 789 > $tmp/file2 ; zz
+ echo 456 > $tmp/file1 ; zz
kill -INT $bgpid
wait $bgpid || assert "$?" "130"
- assert "$(cat $tmp/exec.out)" "$(printf '123\n456')"
+ assert "$(cat $tmp/exec.out)" "456"
try "exec single shell utility using utility substitution"
setup
@@ -283,19 +312,50 @@
try "exec an interactive utility when a file changes"
setup
- ls $tmp/file* | ./entr -p sh -c 'tty | colrm 9' 2> /dev/null > $tmp/exec.out &
+ ls $tmp/file* | ./entr -p sh -c 'tty | cut -c1-8' 2> /dev/null > $tmp/exec.out &
bgpid=$! ; zz
echo 456 >> $tmp/file2 ; zz
kill -INT $bgpid
wait $bgpid || assert "$?" "130"
- if ! tty > /dev/null ; then
+ if ! test -t 0 ; then
skip "A TTY is not available"
else
assert "$(cat $tmp/exec.out | tr '/pts' '/tty')" "/dev/tty"
fi
-# cleanup
-rm -r $tmp
+try "exec a command using shell option"
+ setup
+ ls $tmp/file* | ./entr -ps 'file $0; exit 2' >$tmp/exec.out 2>$tmp/exec.err &
+ bgpid=$! ; zz
+ echo 456 >> $tmp/file2 ; zz
+ kill -INT $bgpid
+ wait $bgpid || assert "$?" "130"
+ assert "$(cat $tmp/exec.err)" ""
+ assert "$(head -n1 $tmp/exec.out)" "$(printf ${tmp}'/file2: ASCII text')"
+
+try "exec a command as a background task"
+ setup
+ (ls $tmp/file* | ./entr -ps 'echo terminating; kill $$' >$tmp/exec.out 2>$tmp/exec.err &)
+ zz
+ echo 456 >> $tmp/file2 ; zz
+ assert "$(cat $tmp/exec.err)" ""
+ assert "$(head -n1 $tmp/exec.out)" "terminating"
+
+# extra slow tests that rely on timeouts
+
+try "ensure that all subprocesses are terminated in restart mode when a file is removed"
+ setup
+ cat <<-SCRIPT > $tmp/go.sh
+ #!/bin/sh
+ trap 'echo "caught signal"; exit' TERM
+ echo "running"; sleep 10
+ SCRIPT
+ chmod +x $tmp/go.sh
+ ls $tmp/file2 | ./entr -r sh -c "$tmp/go.sh" 2> /dev/null > $tmp/exec.out &
+ bgpid=$! ; zz
+ rm $tmp/file2; sleep 2
+ pgrep -P $bgpid > /dev/null || assert "$?" "1"
+ assert "$(cat $tmp/exec.out)" "$(printf 'running\ncaught signal')"
+this="exit 0"
echo; echo "$tests tests PASSED"
-exit 0