eradman/entr

Support ncurses-style subprocesses when reload flag is passed?

thomasjm opened this issue · 5 comments

I'm interested in running a terminal UI app with entr, but it doesn't seem to work in reloading mode.

For example, find . | entr htop successfully launches htop.

But find . | entr -r htop doesn't launch the UI and actually hangs my terminal, and can't even be interrupted with Ctrl+C.

Maybe this is just a matter of connecting the subprocess to the pseudo-terminal of the main process in the reloading case?

This isn't going to work because the -r changes the way a utility is run

  1. STDIN is closed so that entr can read keyboard input Ctrl-C, q, spacebar
  2. The session leader is set so that all child processes receive a signal
  3. entr does not wait for the child to exit

If you run ps -x you will probably see that htop is in the state T, which means it was halted by the OS for attempting to read stdin without a tty.

What is the use case for running htop with entr? You can probably work around this by sending tmux commands

htop was just an example, the actual use case is to run a unit testing library that presents its results in a terminal UI app (this one).

Huh, I think it would be cool if there were a mode that supported TUI apps, by leaving them connected to STDIN and telling them when they should exit via SIGINT. But I'd understand if that's out of scope for this tool.

Yeah, I don't see making the restart option accommodate terminal UIs. This is little more mental work to type, but if you're using tmux you can use entr to send keyboard commands to cancel and/or restart tests

find . | entr  tmux send-keys -t 1 C-c "./run-tests" C-m

Where C-c is the key(s) to cancel tests followed by commands to run

entr does not wait for the child to exit

This one seems problematic for non-TUI subprocesses as well. What I'm reloading something that tries to access a shared resource, and entr starts up a new one before the old one has a chance to clean up? Seems like a --wait-for-child flag would be nice in some circumstances.

STDIN is closed so that entr can read keyboard input

Just thinking out loud here -- what if you forwarded the data from stdin to the stdin of the new process using a pipe? That would allow entr to watch what's going on with stdin while allowing the subprocess to see it too. Although personally I think it's kind of weird that entr is controlled via stdin at all, since normally the exit functionality (Ctrl-C/q) is done by the shell delivering the interrupt signal. I didn't know about the spacebar thing, but that could be done with a signal as well (like Ctrl-\, SIGQUIT). Of course you couldn't add many commands this way since modern terminal emulators only do like 3 signals :).

Anyway, thanks for the quick responses and feel free to close!

The restart option does wait for the child process to exit after sending SIGTERM, you can see this by running a web server

$ ls *.py | entr -r python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [06/Aug/2021 19:31:25] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [06/Aug/2021 19:31:25] code 404, message File not found
127.0.0.1 - - [06/Aug/2021 19:31:25] "GET /favicon.ico HTTP/1.1" 404 -
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Whereas if did not wait you would see OSError: [Errno 48] Address already in use. If this doesn't work then there may be something else happening (fork'd process that is blocking signals?)

Thinking further about the TUI problem with the restart option. It has been years since I tried to solve this. I think you are right that stdin and stdout could be handled by pipes, although it would need to be a virtual TTY.