From bbdda36e4c1e86c26938a3204cba16fa5097e84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Mon, 25 May 2020 18:13:28 +0200 Subject: [PATCH] Add interactive mode --- github-fast-env.rb | 44 ++++++++++++++++++++++++++++++++++++-------- github-fast-envd.rb | 32 +++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/github-fast-env.rb b/github-fast-env.rb index bf13d59..d287834 100755 --- a/github-fast-env.rb +++ b/github-fast-env.rb @@ -1,17 +1,21 @@ #!/usr/bin/env ruby require "base64" +require "io/console" require "optparse" require "socket" usage_output = "USAGE:\n github-fast-env SCRIPT_PATH [options]" -$options = {:verbose => false} +$options = {:verbose => false, :interactive => false} OptionParser.new do |options| options.banner = usage_output options.on("-v", "--verbose", "Show verbose output") do $options[:verbose] = true end + options.on("-i", "--interactive", "Run an interactive session using a pseudoterminal") do + $options[:interactive] = true + end end.parse! if not ARGV or ARGV.empty? @@ -34,9 +38,13 @@ control_socket_path = "/tmp/github-fast-envd.sock" $control_socket = UNIXSocket.new(control_socket_path) +$original_stdin = $stdin.dup +$original_stdout = $stdout.dup +$origianl_stderr = $stderr.dup + def log(level, message) if level == "error" or $options[:verbose] - $stderr.puts "[github-fast-env] #{level}: #{message}" + $origianl_stderr.puts "[github-fast-env] #{level}: #{message}" end end @@ -89,7 +97,12 @@ end log "info", "connected to control socket" encoded_script_path = Base64.encode64(script_path).delete("\n") -$control_socket.puts "new v1 named-pipes #{encoded_script_path}" + +if $options[:interactive] + $control_socket.puts "new v1 pseudoterminal #{encoded_script_path}" +else + $control_socket.puts "new v1 named-pipes #{encoded_script_path}" +end pipes = {"stdin" => nil, "stdout" => nil, "stderr" => nil} @@ -115,10 +128,27 @@ while true pipes["stderr"] = File::open("#{pipe_base_path}.stderr", "r") pipes["stderr"].sync = true + read_ios = [$control_socket, $stdin, pipes["stdout"], pipes["stderr"]] + log "info", "connected via named pipes" elsif command == "pseudoterminal" - log "error", "not yet implemented" - exit 1 + if arguments.empty? + log "error", "malformed response" + exit 1 + end + + pseudoterminal_path = Base64.decode64(arguments[0]) + + log "info", "connecting to pseudoterminal at #{pseudoterminal_path}" + + pseudoterminal_io = File::open(pseudoterminal_path, File::RDWR | File::NOCTTY) + + pipes["stdin"] = pseudoterminal_io + pipes["stdout"] = pseudoterminal_io + + read_ios = [$control_socket, $stdin, pipes["stdout"]] + + log "info", "connected via pseudoterminal" else log "error", "malformed response" exit 1 @@ -128,8 +158,6 @@ end log "info", "ready" $control_socket.puts "ready" -read_ios = [$control_socket, $stdin, pipes["stdout"], pipes["stderr"]] - exit_code = "unknown" while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) or read_ios.include?(pipes["stderr"]) @@ -165,7 +193,7 @@ while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) o log "warn", "received input from unknown stream" end rescue EOFError - log "trace", "closing stream" + log "trace", "closing stream #{ready_read_io}" ready_read_io.close end end diff --git a/github-fast-envd.rb b/github-fast-envd.rb index a61492f..d177ffc 100755 --- a/github-fast-envd.rb +++ b/github-fast-envd.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require "base64" +require "io/console" require "socket" #require "/data/github/current/config/environment" @@ -116,6 +117,35 @@ def set_up_named_pipes(control_socket, connection_id) $stderr.reopen(stderr) end +def set_up_pseudoterminal(control_socket) + require "pty" + + master, client = PTY.open + master.raw! + + File.chmod 0600, client.path + + client_path = Base64.encode64(client.path).delete("\n") + client.close + + control_socket.puts "pseudoterminal #{client_path}" + + $stderr.puts " set up pseudoterminal" + + control_socket.puts "ready" + + response = control_socket.readline.strip + + if response != "ready" + raise ClientError.new "invalid command" + Kernel.exit! + end + + $stdin.reopen(master) + $stdout.reopen(master) + $stderr.reopen(master) +end + while true control_socket = control_server.accept $stderr.puts "- new connection" @@ -157,7 +187,7 @@ while true if mode == "named-pipes" set_up_named_pipes(control_socket, connection_id) else - raise ClientError.new "not yet implemented" + set_up_pseudoterminal(control_socket) end original_stderr.puts " executing script " + script_path