Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to use -r with an interactive task? #1

Closed
jaresty opened this issue Jun 24, 2019 · 12 comments
Closed

Is it possible to use -r with an interactive task? #1

jaresty opened this issue Jun 24, 2019 · 12 comments

Comments

@jaresty
Copy link

jaresty commented Jun 24, 2019

I'd like to use entr to run a command that is interactive. If I don't say 'yes' to the command though, it holds the terminal and so it doesn't re-run unless I interact with that pane. It would be nice to be able to have entr kill the command on updates but still allow me to say 'yes' when I'm ready to let the command apply changes.

@eradman
Copy link
Owner

eradman commented Jun 27, 2019

Is the command you would like to run well-known, or is it proprietary? I would be helpful to see an example, since the solution is probably dependant on specific behaviors of the utility you're running.

@jaresty
Copy link
Author

jaresty commented Jun 27, 2019

It's an open-source command called fly. When I run fly set-pipeline it prompts me to say yes when there are changes. I don't want to just apply those changes every time, but it is helpful to see them. If I made another change to the watched file, I'd like for the fly set-pipeline process to be killed and restarted. If I use -r it can't accept my confirmation. If I don't use -r then it doesn't get killed if I make two separate changes so it'd only show the results from the first change.

@eradman
Copy link
Owner

eradman commented Jun 27, 2019

Looking at https://github.com/concourse/concourse/blob/master/fly/commands/set_pipeline.go it seems that -n can be used to skip the confirmation prompt. See if this works.

entr -r can't support this directly since the utility is run as a background task. On Unix-like systems background tasks are halted if they try to read from STDIN (To guard against this, entr closes STDIN when -r is used.)

If this doesn't work, we could run the command in a disconnected tmux session, but that would be a nussance.

@jaresty
Copy link
Author

jaresty commented Jun 27, 2019

It works as expected when run without -r; i.e. I'm able to interact with the command when required. How is the handling of the non--r case different?

@jaresty
Copy link
Author

jaresty commented Jun 27, 2019

I am aware of -n btw; I didn't want to use that since setting a pipeline is a dangerous operation to run without a prompt so I do want to confirm before going ahead.

@eradman
Copy link
Owner

eradman commented Jun 27, 2019

Try running this:

fly set-pipeline &

You should see the process state T meaning it was suspended for terminal interaction. Similarly, with -r entr is running the utility as a background process so that it can respond to input (keyboard, file system events) even if the child process is still running.

@jaresty
Copy link
Author

jaresty commented Jun 27, 2019

Thanks -- I understand the part about how running it in the background works. My question is more about why it works when I run entr without -r. Does entr run the job in the foreground in that case? Also, why is it necessary to run the task in the background when using -r?

@eradman
Copy link
Owner

eradman commented Jun 28, 2019

There are a couple things going on: without -r entr waits for the child process to end with waitpid(2). We understand that part.

With -r both the parent (entr) and the child (your utility) would read input from the same terminal. This would result in undefined behavior, and closing stdin on the child allows entr to accept keyboard input (q, <space>, Ctrl-C).

The second sticking point is that in restart mode entr needs signals to propagate. This mechanism is used to make the child the leader of it's own process group

if (restart_opt == 1) {
    setpgid(0, getpid());
}

Now when entr sends SIGTERM the utility and all of it's subprocess receive the signal. But setting a new process group is also what prevents the child from reading STDIN. If it does, the kernel will suspend it. Finding your process in the T state is confusing, so entr closes STDIN to raise an error instead.

@jaresty
Copy link
Author

jaresty commented Jun 28, 2019

Got it -- thank you for taking the time to explain. It does sound like this would not work the way I'm imagining. I guess I'll just deal with having to confirm every time for now. Great utility, btw -- I've found it to be flexible and useful for a wide variety of use cases.

@jaresty jaresty closed this as completed Jun 28, 2019
@eradman
Copy link
Owner

eradman commented Jul 1, 2019

Thanks for the kind words @jaresty! After working through this ticket I realized how difficult it is to see why the -r can't be used with an interactive task. I added a section
http://eradman.com/entrproject/ called Other Implementation Details which should help others who are trying to understand this behavior.

@jaresty
Copy link
Author

jaresty commented Jul 2, 2019

Thanks -- I read through the new docs section and it makes sense.

@mvrozanti
Copy link

mvrozanti commented Jul 17, 2019

Does that mean it's impossible to have -r work with interactive commands? I wanted to do something like echo filename | entr -r less /_

If entr didn't consume from stdin, and instead got the filenames from somewhere else, could this be doable?

This project is great and interactive usage is the only thing that isn't achievable at the moment. Even then, it's too handy. Thank you anyway

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants