Closed butsjoh closed 3 years ago
Ok it seems it works with the following. Leaving it for reference. So when i hit control+c when it is running it just returns back to the interactive cli prompt. Not sure though if that is expected to work like this but if you could give some insights on how it could work with other key combos that would be nice.
# frozen_string_literal: true
require_relative '../command'
module MyCli
module Commands
class Status < MyCli::Command
def initialize(options)
@options = options
end
def execute(input: $stdin, output: $stdout)
command(printer: :quiet).run('watch docker-compose ps')
rescue TTY::Command::ExitError
end
end
end
end
Hi Buts,
Thanks for using the TTY Toolkit!
When the command run returns non-zero exit it will raise the TTY::Command::ExitError
. This is a safety measure built-in into tty-command
as you don't want any script to progress any further. Alternatively, you can use run!
and write logic to handle failure scenario:
result = command(printer: :quiet).run('watch docker-compose ps')
if result.failure?
# handle or skip
end
Back to your original question. When you run any command via run
or run!
methods, it will be executed in a child process. In your case, the 'watch docker-compose ps
runs in a child process. The way to interact with this process is either through standard input/output or by sending a signal. From the shell, the way a user can terminate watch
command is with Ctrl+C
. If you wanted to use some other combination of keys to stop this child process, you could do so but you would find it a bit more involved and more brittle.
First of all, any Unix user expects to be able to interrupt a long-running process with Ctrl+C
. Secondly, even if you used the tty-reader
to handle, let's say Ctrl+k
keys, then you would need to somehow terminate the long-running watch
process yourself. In Ruby, the way to do this is by killing the child process. An example of this approach would be:
reader = TTY::Reader.new
reader.on(:keyctrl_k) do
parent_id = Process.pid
# find a child process that inherits from parent_id
# you would probably need to run some form of ps & grep
child_id = run("...")
Process.kill('SIGHUP', child_pid)
Process.detach(child_pid)
end
There may be other ways to handle what you want but that would be my approach given current implementation. However, I'm not sure I would actually go down this route given that Ctrl+C
is a widely recognised way to stop long-running processes and it makes your code fairly straightforward. I may consider adding a way to somehow retrieve a child process id when the command is run but it's not supported at the moment. I hope this helps.
Hi,
All of the tty stuff is amazing and before i start i would like to thank you for the effort you put into it.
I have a question about a specific usage of tty command for the cli i am trying to build.
I bootstrapped my cli with teletype and I am also using thor_repl to make my cli interactive. I don't really need to run one time scripts but rather have it run in a repl kind of fasion and that is working fine. But now i am stuck on trying to get something work with tty-command. I have a command (docker-compose ps) that i want to get refreshed once in a while to see the output of it and want to stop it when i do a certain key combo.
I tried with using the 'watch' command which calls the given command in certain intervals and that works kind of ok but problematic part is that i cannot exit out of it anymore unless i hit CTRL+C but that triggers the interrupted signal which stops everything.
Now is there a way that you can think of (also maybe using other tty tools like https://github.com/piotrmurach/tty-reader) to somehow trap a key combo while that command is running and have a way to stop it and return to the cli? Or is this just impossible todo cause that command would be a subprocess that is running? Or is there a way to catch the interrupt in some way to restart the cli again? Or are there other means to run a command in a loop and stop that loop on key combo?
Would be happy to have your thought or opinions since you are more familiar with the possibilities of the tool.
Thnx in advance.