piotrmurach / tty-command

Execute shell commands with pretty output logging and capture stdout, stderr and exit status.
https://ttytoolkit.org
MIT License
400 stars 34 forks source link

Can't run shells in interactive mode #58

Open fsateler opened 4 years ago

fsateler commented 4 years ago

Describe the problem

Shells cannot be run with TTY::Command. Keyboard input is not read by the shell.

Steps to reproduce the problem

require 'tty-command'

cmd = TTY::Command.new(pty: true, printer: :quiet)

cmd.run(*ARGV)

Actual behaviour

(slightly edited to remove identifying information)

% bundle exec ruby ./test.rb dash
$ ls
oh no input is going nowhere
^C
$ ^C
$ but ctrl-c is handled?

^C
$ ctrl-d does nothing
^C
$ ^C
$ ^C
$ i have to kill this from another shell
zsh: terminated  bundle exec ruby ./test.rb

% bundle exec ruby ./test.rb bash
bash: cannot set terminal process group (84144): Inappropriate ioctl for device
bash: no job control in this shell
$ input does not go to the shell

ctrl c kills the process
^CTraceback (most recent call last):
    5: from ./test.rb:6:in `<main>'
    4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
    3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
    2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
    1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt

 bundle exec ruby ./test.rb zsh
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
ls
I can't even get a prompt on zsh
^CTraceback (most recent call last):
    5: from ./test.rb:6:in `<main>'
    4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
    3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
    2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
    1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt

% bundle exec ruby ./test.rb ssh $some_host
<snip MOTD banner>
$ ls
^CTraceback (most recent call last):
    5: from ./test.rb:6:in `<main>'
    4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
    3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
    2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
    1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt

Expected behaviour

A working interactive shell.

Describe your environment

piotrmurach commented 4 years ago

Hi Felipe 👋

Thanks for rasing the issue and using tty-command.

Would you have time to investigate potential fix?

ryansch commented 4 years ago

It looks like the issue is that ProcessRunner only tries to write to stdin once when the command is started: https://github.com/piotrmurach/tty-command/blob/da308658f0cb96db78d5b3b25985fae0434973a0/lib/tty/command/process_runner.rb#L46

I think to be able to wrap interactive commands, we would need another thread to manage stdin.

ryansch commented 4 years ago

I was able to use https://github.com/stripe/subprocess to wrap an interactive command.

codefriar commented 3 years ago

@ryansch - mind providing a code snippet to show how you used subprocess to solve this?

piotrmurach commented 3 years ago

@codefriar I'd like this to be fixed in the tty-command project. I maintain many Ruby projects and have limited time. Thus I need help and encourage any contributions that get us closer to resolving this problem. Unfortunately, your comment doesn't get us in this direction. This is not the place to seek explanations on how to use other libraries and I suggest you open an issue in the other project.

codefriar commented 3 years ago

@piotrmurach My apologies. My initial read of @ryansch 's comment was that he'd gotten this to work in tty-command perhaps by utilizing the subprocess command. I was hoping to prompt him to share his fix for tty-command.

vitobotta commented 2 years ago

Hi all, is this possible now? When I run a shell in a subprocess with pty: true (for example kubectl to open a shell in a pod in Kubernetes), the shell starts and I can press keys etc but when I press enter nothing happens in the shell. Any suggestion? Thanks!

ryansch commented 2 years ago

I just wrote https://github.com/outstand/dash/blob/cd7c740afd1dc7fa809afd630e8a50ee68e391ca/lib/state.rb#L65 to integrate Subprocess a bit more with this gem. At least this way I get similar logging output!

ryansch commented 2 years ago

@codefriar I finally did... ^

ryansch commented 2 years ago

I looked at the differences between tty-command and subprocess and I think subprocess works here because it gives the caller the ability to directly connect the spawned process to STDIN, STDOUT, STDERR.

piotrmurach commented 2 years ago

@ryansch Do you have any suggestions on helping tackle this issue in tty-command itself? I'm all for exposing streams to connect directly. This is important to solve. Any help would be really appreciated!

ryansch commented 2 years ago

I had originally thought about grafting subprocess into this gem but I think exposing the streams might be all we need. I'll see if I can't work up an experiment to test it.

keithrbennett commented 4 months ago

@codefriar , @ryansch I just read this thread and wanted to offer an alternative data point that I did interpret your posts as trying to fix or work arouind this issue rather than recommending or documenting the use of other gems. Thanks for your efforts.