Add interactive mode
This commit is contained in:
		| @@ -1,17 +1,21 @@ | |||||||
| #!/usr/bin/env ruby | #!/usr/bin/env ruby | ||||||
|  |  | ||||||
| require "base64" | require "base64" | ||||||
|  | require "io/console" | ||||||
| require "optparse" | require "optparse" | ||||||
| require "socket" | require "socket" | ||||||
|  |  | ||||||
| usage_output = "USAGE:\n    github-fast-env SCRIPT_PATH [options]" | usage_output = "USAGE:\n    github-fast-env SCRIPT_PATH [options]" | ||||||
|  |  | ||||||
| $options = {:verbose => false} | $options = {:verbose => false, :interactive => false} | ||||||
| OptionParser.new do |options| | OptionParser.new do |options| | ||||||
| 	options.banner = usage_output | 	options.banner = usage_output | ||||||
| 	options.on("-v", "--verbose", "Show verbose output") do | 	options.on("-v", "--verbose", "Show verbose output") do | ||||||
| 		$options[:verbose] = true | 		$options[:verbose] = true | ||||||
| 	end | 	end | ||||||
|  | 	options.on("-i", "--interactive", "Run an interactive session using a pseudoterminal") do | ||||||
|  | 		$options[:interactive] = true | ||||||
|  | 	end | ||||||
| end.parse! | end.parse! | ||||||
|  |  | ||||||
| if not ARGV or ARGV.empty? | 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) | $control_socket = UNIXSocket.new(control_socket_path) | ||||||
|  |  | ||||||
|  | $original_stdin = $stdin.dup | ||||||
|  | $original_stdout = $stdout.dup | ||||||
|  | $origianl_stderr = $stderr.dup | ||||||
|  |  | ||||||
| def log(level, message) | def log(level, message) | ||||||
| 	if level == "error" or $options[:verbose] | 	if level == "error" or $options[:verbose] | ||||||
| 		$stderr.puts "[github-fast-env] #{level}: #{message}" | 		$origianl_stderr.puts "[github-fast-env] #{level}: #{message}" | ||||||
| 	end | 	end | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -89,7 +97,12 @@ end | |||||||
| log "info", "connected to control socket" | log "info", "connected to control socket" | ||||||
|  |  | ||||||
| encoded_script_path = Base64.encode64(script_path).delete("\n") | 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} | pipes = {"stdin" => nil, "stdout" => nil, "stderr" => nil} | ||||||
|  |  | ||||||
| @@ -115,10 +128,27 @@ while true | |||||||
| 		pipes["stderr"] = File::open("#{pipe_base_path}.stderr", "r") | 		pipes["stderr"] = File::open("#{pipe_base_path}.stderr", "r") | ||||||
| 		pipes["stderr"].sync = true | 		pipes["stderr"].sync = true | ||||||
|  |  | ||||||
|  | 		read_ios = [$control_socket, $stdin, pipes["stdout"], pipes["stderr"]] | ||||||
|  |  | ||||||
| 		log "info", "connected via named pipes" | 		log "info", "connected via named pipes" | ||||||
| 	elsif command == "pseudoterminal" | 	elsif command == "pseudoterminal" | ||||||
| 		log "error", "not yet implemented" | 		if arguments.empty? | ||||||
| 		exit 1 | 			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 | 	else | ||||||
| 		log "error", "malformed response" | 		log "error", "malformed response" | ||||||
| 		exit 1 | 		exit 1 | ||||||
| @@ -128,8 +158,6 @@ end | |||||||
| log "info", "ready" | log "info", "ready" | ||||||
| $control_socket.puts "ready" | $control_socket.puts "ready" | ||||||
|  |  | ||||||
| read_ios = [$control_socket, $stdin, pipes["stdout"], pipes["stderr"]] |  | ||||||
|  |  | ||||||
| exit_code = "unknown" | exit_code = "unknown" | ||||||
|  |  | ||||||
| while read_ios.include?($control_socket) or read_ios.include?(pipes["stdout"]) or read_ios.include?(pipes["stderr"]) | 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" | 				log "warn", "received input from unknown stream" | ||||||
| 			end | 			end | ||||||
| 		rescue EOFError | 		rescue EOFError | ||||||
| 			log "trace", "closing stream" | 			log "trace", "closing stream #{ready_read_io}" | ||||||
| 			ready_read_io.close | 			ready_read_io.close | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #!/usr/bin/env ruby | #!/usr/bin/env ruby | ||||||
|  |  | ||||||
| require "base64" | require "base64" | ||||||
|  | require "io/console" | ||||||
| require "socket" | require "socket" | ||||||
|  |  | ||||||
| #require "/data/github/current/config/environment" | #require "/data/github/current/config/environment" | ||||||
| @@ -116,6 +117,35 @@ def set_up_named_pipes(control_socket, connection_id) | |||||||
| 	$stderr.reopen(stderr) | 	$stderr.reopen(stderr) | ||||||
| end | 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 | while true | ||||||
| 	control_socket = control_server.accept | 	control_socket = control_server.accept | ||||||
| 	$stderr.puts "- new connection" | 	$stderr.puts "- new connection" | ||||||
| @@ -157,7 +187,7 @@ while true | |||||||
| 			if mode == "named-pipes" | 			if mode == "named-pipes" | ||||||
| 				set_up_named_pipes(control_socket, connection_id) | 				set_up_named_pipes(control_socket, connection_id) | ||||||
| 			else | 			else | ||||||
| 				raise ClientError.new "not yet implemented" | 				set_up_pseudoterminal(control_socket) | ||||||
| 			end | 			end | ||||||
|  |  | ||||||
| 			original_stderr.puts "  executing script " + script_path | 			original_stderr.puts "  executing script " + script_path | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user