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 - aavind...@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 <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <termios.h>
 
 #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; i<argc; i++) {
-               new_argv[i] = p;
-               if ((m < 1) && (strcmp(argv[i], "/_")) == 0) {
-                       p += strlen(xrealpath(leading_edge->fn, 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; i<argc; i++) {
+                       new_argv[i] = p;
+                       if ((m < 1) && (strcmp(argv[i], "/_")) == 0) {
+                               p += strlen(xrealpath(leading_edge->fn, 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; i<nev; i++) {
+               if (evList[i].filter == EVFILT_READ) {
+                       if (read(STDIN_FILENO, &c, 1) < 1) {
+                               EV_SET(&evSet, STDIN_FILENO, EVFILT_READ,
+                                   EV_DELETE, NOTE_LOWAT, 0, NULL);
+                               if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1)
+                                       err(1, "failed to remove READ event");
+                       }
+                       else {
+                               if (c == ' ')
+                                       do_exec = 1;
+                               if (c == 'q')
+                                       kill(getpid(), SIGINT);
+                       }
+               }
                if (evList[i].filter != EVFILT_VNODE)
                        continue;
                file = (WatchFile *)evList[i].udata;
                if (file->is_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; i<nev; i++) {
+               if (evList[i].filter != EVFILT_VNODE)
+                       continue;
                file = (WatchFile *)evList[i].udata;
                if (evList[i].fflags & NOTE_DELETE ||
                    evList[i].fflags & NOTE_RENAME) {
@@ -495,6 +560,8 @@
        }
 
        for (i=0; i<nev && reopen_only == 0; i++) {
+               if (evList[i].filter != EVFILT_VNODE)
+                       continue;
                file = (WatchFile *)evList[i].udata;
                if ((file->is_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; i<max_files; i++)
                files[i] = calloc(1, sizeof(WatchFile));
        /* initialize test context */
        memset(&ctx, 0, sizeof(ctx));
+
+       setenv("SHELL", "/bin/Xsh", 1);
 }
 
 void sighandler(int signum) {
@@ -139,6 +142,11 @@
 fake_free(void *ptr) {
 }
 
+int
+fake_tcsetattr(int fd, int action, const struct termios *tp) {
+    return 0;
+}
+
 /* mock objects */
 
 /*
@@ -639,6 +647,37 @@
 }
 
 /*
+ * In submit mode only the first argment is used
+ */
+int watch_fd_shell_01() {
+       int kq = kqueue();
+       char *argv[] = { "ruby main.rb", NULL };
+
+       shell_opt = 1;
+       strlcpy(files[0]->fn, "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 <sys/event.h>
 #include <sys/types.h>
 
+#include <err.h>
 #include <errno.h>
 #include <limits.h>
 #include <poll.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
@@ -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; n<nchanges; n++) {
                        kev = changelist + (sizeof(struct kevent)*n);
                        file = (WatchFile *)kev->udata;
+
+                       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 <sys/types.h>
 #include <sys/time.h>
 
+#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


Reply via email to