From 541ff315011cef55d7340ce7f584869f021fefdc Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 11 Dec 2013 12:06:02 +0900 Subject: [PATCH 1/3] use io/console if possible --- lib/heroku/auth.rb | 53 +++++++++++++++++++++------------------ lib/heroku/command/run.rb | 19 ++++++-------- lib/heroku/helpers.rb | 40 +++++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/lib/heroku/auth.rb b/lib/heroku/auth.rb index 1f3a6a76d..b2880a87b 100644 --- a/lib/heroku/auth.rb +++ b/lib/heroku/auth.rb @@ -5,6 +5,11 @@ require "netrc" +begin + require "io/console" +rescue LoadError +end + class Heroku::Auth class << self include Heroku::Helpers @@ -169,13 +174,13 @@ def echo_off with_tty do system "stty -echo" end - end + end unless defined?($stdin.noecho) def echo_on with_tty do system "stty echo" end - end + end unless defined?($stdin.noecho) def ask_for_credentials puts "Enter your Heroku credentials." @@ -184,35 +189,35 @@ def ask_for_credentials user = ask print "Password (typing will be hidden): " - password = running_on_windows? ? ask_for_password_on_windows : ask_for_password + password = ask_for_password [user, api_key(user, password)] end - def ask_for_password_on_windows - require "Win32API" - char = nil - password = '' + if !defined?($stdin.noecho) and running_on_windows? + def ask_for_password + require "Win32API" + char = nil + password = '' - while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do - break if char == 10 || char == 13 # received carriage return or newline - if char == 127 || char == 8 # backspace and delete - password.slice!(-1, 1) - else - # windows might throw a -1 at us so make sure to handle RangeError - (password << char.chr) rescue RangeError + while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do + break if char == 10 || char == 13 # received carriage return or newline + if char == 127 || char == 8 # backspace and delete + password.slice!(-1, 1) + else + # windows might throw a -1 at us so make sure to handle RangeError + (password << char.chr) rescue RangeError + end + end + puts + return password + end + else + def ask_for_password + noecho_tty do |tty| + ask.tap {puts if tty} end end - puts - return password - end - - def ask_for_password - echo_off - password = ask - puts - echo_on - return password end def ask_for_and_save_credentials diff --git a/lib/heroku/command/run.rb b/lib/heroku/command/run.rb index 9ed3b5049..1c9f0c992 100644 --- a/lib/heroku/command/run.rb +++ b/lib/heroku/command/run.rb @@ -120,8 +120,7 @@ def run_attached(command) end def rendezvous_session(rendezvous_url, &on_connect) - begin - set_buffer(false) + raw_tty do rendezvous = Heroku::Client::Rendezvous.new( :rendezvous_url => rendezvous_url, :connect_timeout => (ENV["HEROKU_CONNECT_TIMEOUT"] || 120).to_i, @@ -130,16 +129,14 @@ def rendezvous_session(rendezvous_url, &on_connect) :output => $stdout) rendezvous.on_connect(&on_connect) rendezvous.start - rescue Timeout::Error - error "\nTimeout awaiting process" - rescue OpenSSL::SSL::SSLError - error "Authentication error" - rescue Errno::ECONNREFUSED, Errno::ECONNRESET - error "\nError connecting to process" - rescue Interrupt - ensure - set_buffer(true) end + rescue Timeout::Error + error "\nTimeout awaiting process" + rescue OpenSSL::SSL::SSLError + error "Authentication error" + rescue Errno::ECONNREFUSED, Errno::ECONNRESET + error "\nError connecting to process" + rescue Interrupt end def console_history_dir diff --git a/lib/heroku/helpers.rb b/lib/heroku/helpers.rb index 5d413745f..6ba61bb16 100644 --- a/lib/heroku/helpers.rb +++ b/lib/heroku/helpers.rb @@ -199,12 +199,42 @@ def json_decode(json) nil end - def set_buffer(enable) - with_tty do - if enable - `stty icanon echo` + if defined?($stdin.noecho) + def noecho_tty(&block) + $stdin.noecho {yield true} + rescue Errno::ENOTTY + yield false + end + + def raw_tty(&block) + $stdin.noecho {yield true} + rescue Errno::ENOTTY + yield false + end + else + def noecho_tty(&block) + if $stdin.tty? + begin + `stty echo` + yield + ensure + `stty -echo` + end + else + yield + end + end + + def raw_tty(&block) + if $stdin.tty? + begin + `stty icanon echo` + yield + ensure + `stty -icanon -echo` + end else - `stty -icanon -echo` + yield end end end From 09a5217b0c4f18df41fb1343afd49a4f82f1ff50 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 11 Dec 2013 14:32:21 +0900 Subject: [PATCH 2/3] stty is no longer needed at cleanup --- lib/heroku/cli.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/heroku/cli.rb b/lib/heroku/cli.rb index 591705fa1..328db6a6d 100644 --- a/lib/heroku/cli.rb +++ b/lib/heroku/cli.rb @@ -27,7 +27,6 @@ def self.start(*args) Heroku::Command.load Heroku::Command.run(command, args) rescue Interrupt - `stty icanon echo` error("Command cancelled.") rescue => error styled_error(error) From 2d1c043b7c308f19e827d8685df58d420f450a07 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 11 Dec 2013 14:32:52 +0900 Subject: [PATCH 3/3] use false for portability --- lib/heroku/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/heroku/cli.rb b/lib/heroku/cli.rb index 328db6a6d..4fca01e7b 100644 --- a/lib/heroku/cli.rb +++ b/lib/heroku/cli.rb @@ -30,7 +30,7 @@ def self.start(*args) error("Command cancelled.") rescue => error styled_error(error) - exit(1) + exit(false) end end