Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

stty: stdin isn't a terminal #226

Closed
dnagir opened this Issue · 21 comments

5 participants

@dnagir

This only appears when using guard-rspectable.

The interactors/readline must be causing it.
But the issue is probably related to RSpec too.

Any suggestions how it can be fixed?

@netzpirat netzpirat closed this issue from a commit
@netzpirat netzpirat Use a direct file descriptor with stty.
JRuby doesn't inherit TTY to subprocesses, so when using stty, an
error message "stty: stdin isn't a terminal" is shown and the
terminal settings coudn't be restoredi properly.

The workaround uses now /dev/tty instead using the TTY for STDIN.

This fixes #226.
0bcdd48
@netzpirat netzpirat closed this in 0bcdd48
@dnagir

Unfortunately this doesn't fix the error. Using guad from master and still getting those annoying messages.

@netzpirat
Owner

This is the one and only use of stty in Guard and the given error message comes from stty.

$ rvm use jruby
Using /Users/michi/.rvm/gems/jruby-1.6.5.1
$ ruby -e '`stty -g`'
stty: stdin isn't a terminal
$ ruby -e '`stty -g -f /dev/tty`'
$

Can you replace -f /dev/tty with 2>/dev/null and test what happens then?

@dnagir

Unfortunately I'm already away from my laptop. Will not be able to do it now.
Did you try that commit? Maybe it works for you but something is wrong on my side.

I think it's better to reopen the issue to make sure it won't slip through.

@netzpirat netzpirat reopened this
@thibaudgg thibaudgg referenced this issue from a commit
Thibaud Guillaume-Gentil Oops #226 not yet fixed :) [ci skip] 2acb77c
@netzpirat
Owner

@dnagir Instead of assuming that /dev/stty is the current terminal, we let stty figure out which is the correct one. In case where this doesn't work properly (JRuby), the error is just being ignored for now. Can your please test to see if that annoying error message is gone?

@dnagir

Not fixed yet. What actually changed?

> bin/guard -g focus --verbose
Guard uses GNTP to send notifications.
Guard is now watching at '/Users/dnagir/proj/abc'
DEBUG (13:47:56): Hook :start_begin executed for Guard::RSpectacle
Starting RSpectacle test environment
DEBUG (13:48:03): Command execution: which editor > /dev/null 2>&1 
DEBUG (13:48:03): Command execution: which nano > /dev/null 2>&1 
DEBUG (13:48:06): Command execution: ls /Volumes/ramdisk 
ls: /Volumes/ramdisk: No such file or directory
RSpectacle is ready!
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
Enable remote shell at port port=9332                          | ETA:  --:--:--
Starting local Neo4j using db /Users/dnagir/proj/abc/db/neo4j-test
  193/193:     100% |==========================================| Time: 00:00:35

Finished in 35.42 seconds
193 examples, 0 failures, 15 pending
DEBUG (13:48:50): Hook :start_end executed for Guard::RSpectacle
DEBUG (13:48:50): Command execution: hash stty
DEBUG (13:48:51): Command execution: stty -g 2>/dev/null
DEBUG (13:48:51): Command execution: infocmp -C
DEBUG (13:48:51): Command execution: infocmp -C -r
DEBUG (13:48:51): Command execution: infocmp -C -r
DEBUG (13:48:51): Command execution: stty size
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: infocmp -C -r
DEBUG (13:48:51): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: stty -g
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (13:48:51): Command execution: stty  -echo -icrnl cbreak -ixoff
stty: stdin isn't a terminal
@netzpirat
Owner

The change was to replace -f /dev/tty with 2>/dev/null with this commit and from the debug output I see that it works, because there's no stty: stdin isn't a terminal message after stty -g 2>/dev/null.

The message comes from the calls stty size, stty -a, stty -g and stty -echo -icrnl cbreak -ixoff, but they are not part of Guard. Please open a new issue at the Guard that executes these commands.

@netzpirat netzpirat closed this
@dnagir

Well, maybe it is fixed for one command, but apparently The same massage is still there.
Maybe you could address it as part of this issue? Why open another one? The stty stuff is still there wherever it comes from.

I'm not sure how the new issue would be different from this one.

@netzpirat
Owner

I can just repeat myself: the other commands are not part of Guard. They should be fixed in the gem that executes these commands, because it's problem with these gems and not Guard.

@dnagir

Ok. But how do you know that? How can I determine who executes those commands?

@Maher4Ever

@dnagir IMHO I don't think there is still anything to fix in Guard now. The root of the problem lies in the fact that "JRuby doesn't inherit TTY to subprocesses" as @netzpirat explained it. So it's a JRuby bug as I see it.
The only thing to be done now is to inform guard-rspectacle developers so that they can also ignore these warnings.

@netzpirat
Owner

I know that these commands doesn't come from Guard because grep never lies:

$ cd ~/Repositories/guard
$ grep -R stty *
lib/guard/interactors/readline.rb:      store_terminal_settings if stty_exists?
lib/guard/interactors/readline.rb:      restore_terminal_settings if stty_exists?
lib/guard/interactors/readline.rb:    # Detects whether or not the stty command exists
lib/guard/interactors/readline.rb:    # @return [Boolean] the status of stty
lib/guard/interactors/readline.rb:    def stty_exists?
lib/guard/interactors/readline.rb:      system('hash', 'stty')
lib/guard/interactors/readline.rb:      @stty_save = `stty -g 2>/dev/null`.chomp
lib/guard/interactors/readline.rb:      system('stty', @stty_save, '2>/dev/null')
spec/guard/interactors/readline_spec.rb:    context 'when running on a system that has stty' do
spec/guard/interactors/readline_spec.rb:      before { subject.should_receive(:stty_exists?).and_return(true) }
spec/guard/interactors/readline_spec.rb:    context 'when running on a system without stty' do
spec/guard/interactors/readline_spec.rb:      before { subject.should_receive(:stty_exists?).and_return(false) }
spec/guard/interactors/readline_spec.rb:    context 'when running on a system that has stty' do
spec/guard/interactors/readline_spec.rb:      before { subject.should_receive(:stty_exists?).and_return(true) }
spec/guard/interactors/readline_spec.rb:    context 'when running on a system without stty' do
spec/guard/interactors/readline_spec.rb:      before { subject.should_receive(:stty_exists?).and_return(false) }

The only two system calls to stty are hiding the errors:

lib/guard/interactors/readline.rb:      @stty_save = `stty -g 2>/dev/null`.chomp
lib/guard/interactors/readline.rb:      system('stty', @stty_save, '2>/dev/null')

These commands also do not come from guard-rspectacle:

$ cd Repositories/guard-rspectacle
$ grep -R stty * | wc -l
    0

There is a JRuby bug about this issue, and it cannot be solved because of the JVM design.

How can you determine who executes those commands? Have a look at your Guardfile and Gemfile to see which Gems you're using. Then have a look at the source code or quickly clone it and use grep.

@dnagir

Thanks guys for the help.

I created an empty Guardfile and even then it gives me:

> bin/guard --verbose
ERROR: No guards found in Guardfile, please add at least one.
Guard uses GNTP to send notifications.
Guard is now watching at '/Users/dnagir/proj/abc'
DEBUG (08:49:50): Command execution: hash stty
DEBUG (08:49:50): Command execution: stty -g 2>/dev/null
DEBUG (08:49:50): Command execution: infocmp -C
DEBUG (08:49:50): Command execution: infocmp -C -r
DEBUG (08:49:50): Command execution: infocmp -C -r
DEBUG (08:49:50): Command execution: stty size
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: infocmp -C -r
DEBUG (08:49:50): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: stty -g
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: stty -a
stty: stdin isn't a terminal
DEBUG (08:49:50): Command execution: stty  -echo -icrnl cbreak -ixoff
stty: stdin isn't a terminal

So if it's not Guard executing the commands (implicitly or explicitly) then I have not idea what :(

I realise that JRuby doesn't inherit tty, but what executes the commands in the first place if not Guard?

Don't you see that behaviour yourself on JRuby?

@Maher4Ever

Ok, so i did a quick grep on the gems used by Guard and it seems that the readline gem is the one using the other stty commands:

rb-readline-0.4.2/lib/rbreadline.rb:         wr,wc = `stty size`.split(' ').map{|x| x.to_i}
rb-readline-0.4.2/lib/rbreadline.rb:      h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
rb-readline-0.4.2/lib/rbreadline.rb:      h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
rb-readline-0.4.2/lib/rbreadline.rb:      @readline_echoing_p = (`stty -a`.scan(/-*echo\b/).first == 'echo')
rb-readline-0.4.2/lib/rbreadline.rb:      if (`stty -a`.scan(/-parenb\b/).first == '-parenb')

So to fix this on your end, just use the simple interactor or disable it entirely and you (hopefully) won't see any warnings.
Check the section about the interactor in the README file to know how.

@dnagir

@Maher4Ever, thanks a lot for the help figuring this out.

Using simple interactor fixes it. I guess it would be good to have a note about it somewhere.

@netzpirat
Owner

The readline gem is only necessary on MRI, JRuby readline support is fine. This has been described in the Readline section of the Guard readme.

@thibaudgg thibaudgg referenced this issue from a commit
Thibaud Guillaume-Gentil Revert "Oops #226 not yet fixed :) [ci skip]"
This reverts commit 2acb77c.
cd8a122
@trevor

i see this with jruby 1.7.0pre2

small example based off guard-1.3.0/lib/guard/interactors/helpers/terminal.rb with irb:

% irb
irb(main):001:0> JRUBY_VERSION
=> "1.7.0.preview2"
irb(main):002:0> RUBY_VERSION
=> "1.9.3"
irb(main):003:0> `stty -g 2>/dev/null`
=> "gfmt1:cflag=4b00:iflag=2b02:lflag=4cf:oflag=3:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=38400:ospeed=38400\n"
irb(main):004:0> system("stty", "gfmt1:cflag=4b00:iflag=2b02:lflag=4cf:oflag=3:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=38400:ospeed=38400", "2>/dev/null")
stty: stdin isn't a terminal
=> false
@netzpirat
Owner

Strange, stty: stdin isn't a terminal should not be visible since we redirect STDERR to /dev/null. This works fine on my machine:

% irb
jruby-1.7.0.preview2 :001 > `stty`
stty: stdin isn't a terminal
 => "" 
jruby-1.7.0.preview2 :002 > `stty 2>/dev/null`
 => "" 
@trevor

it appears to be related to passing the redirect as an argument, i don't know enough about the internals to say why.

>> `stty 2>/dev/null`
""
>> system("stty 2>/dev/null")
false
>> system("stty", "2>/dev/null")
stty: stdin isn't a terminal
false
@netzpirat netzpirat referenced this issue from a commit
@netzpirat netzpirat Do not pass STDERR redirect as option to Kernel#system.
If we pass the redirect `2>/dev/null` as option to Kernel#system,
the option will be wrapped by quotes and the redirect will have no
effect on the command exectuion. See Guard Issue #226.
c919116
@netzpirat
Owner

Oh wow, now I understand the problem. I was wrong when I claimed that STDERR will always be redirected to /dev/null. It works fine in .store_terminal_settings, but fails in .restore_terminal_settings, because when we pass the redirection as command option to Kernel#system, it will wrap it in double quote, so the executed command will be someting like stty ... "2>/dev/null", which will not redirect STDERR. I'm very sorry about that.

Thanks a lot for sharing your findings! You made me a better Ruby programmer today :P

@trevor

that makes sense, completely forgot about that. glad i could help. :)

out of curiosity i looked up how homebrew does it if it's of interest for other scenarios:

https://github.com/mxcl/homebrew/blob/master/Library/Homebrew/utils.rb#L87

module Homebrew
  def self.system cmd, *args
    puts "#{cmd} #{args*' '}" if ARGV.verbose?
    fork do
      yield if block_given?
      args.collect!{|arg| arg.to_s}
      exec(cmd, *args) rescue nil
      exit! 1 # never gets here unless exec failed
    end
    Process.wait
    $?.success?
  end
end

. . .

# prints no output
def quiet_system cmd, *args
  Homebrew.system(cmd, *args) do
    # Redirect output streams to `/dev/null` instead of closing as some programs
    # will fail to execute if they can't write to an open stream.
    $stdout.reopen('/dev/null')
    $stderr.reopen('/dev/null')
  end
end
@pritchie

I think there might be a regression here. Pull request #402

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.