You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
3.9 KiB
175 lines
3.9 KiB
#!/usr/bin/env ruby |
|
|
|
require "base64" |
|
require "optparse" |
|
require "socket" |
|
|
|
usage_output = "USAGE:\n github-fast-env SCRIPT_PATH [options]" |
|
|
|
$options = {:verbose => false} |
|
OptionParser.new do |options| |
|
options.banner = usage_output |
|
options.on("-v", "--verbose", "Show verbose output") do |
|
$options[:verbose] = true |
|
end |
|
end.parse! |
|
|
|
if not ARGV or ARGV.empty? |
|
$stderr.puts "error: missing argument (script path)\n\n" |
|
$stderr.puts usage_output |
|
exit 1 |
|
end |
|
|
|
if ARGV.length > 1 |
|
$stderr.puts "error: only one script expected\n\n" |
|
$stderr.puts usage_output |
|
exit 1 |
|
end |
|
|
|
# TODO: support arguments |
|
# TODO: forward signals |
|
script_path = File.realpath(ARGV[0]) |
|
|
|
control_socket_path = "/tmp/github-fast-envd.sock" |
|
|
|
$control_socket = UNIXSocket.new(control_socket_path) |
|
|
|
def log(level, message) |
|
if level == "error" or $options[:verbose] |
|
$stderr.puts "[github-fast-env] #{level}: #{message}" |
|
end |
|
end |
|
|
|
def read_command(control_socket) |
|
ready_ios = IO.select([control_socket], [], [], 10) |
|
|
|
if not ready_ios |
|
log "error", "timeout while communicating with github-fast-envd" |
|
exit 1 |
|
end |
|
|
|
response = control_socket.readline.strip.split(" ", 2) |
|
|
|
if response.empty? |
|
log "error", "malformed response from github-fast-envd" |
|
exit 1 |
|
end |
|
|
|
command = response[0] |
|
|
|
if command == "error" |
|
if response.length < 2 |
|
log "error", "malformed error response from github-fast-envd" |
|
exit 1 |
|
end |
|
|
|
error_message = response[1] |
|
|
|
log "error", "#{error_message}" |
|
exit 1 |
|
end |
|
|
|
if command == "script_error" |
|
if response.length < 2 |
|
log "error", "malformed script error response from github-fast-envd" |
|
exit 1 |
|
end |
|
|
|
error_message = Base64.decode64(response[1]) |
|
|
|
$stderr.puts error_message |
|
exit 1 |
|
end |
|
|
|
arguments = response[1].nil? ? [] : response[1].split(" ") |
|
|
|
return command, arguments |
|
end |
|
|
|
log "info", "connected to control socket" |
|
|
|
encoded_script_path = Base64.encode64(script_path).delete("\n") |
|
$control_socket.puts "new v1 #{encoded_script_path}" |
|
|
|
pipes = {"stdin" => nil, "stdout" => nil, "stderr" => nil} |
|
|
|
while true |
|
command, arguments = read_command($control_socket) |
|
|
|
if command == "ready" |
|
break |
|
end |
|
|
|
if not ["stdin", "stdout", "stderr"].include?(command) or arguments.empty? |
|
log "error", "malformed response" |
|
exit 1 |
|
end |
|
|
|
pipe_path = arguments[0] |
|
|
|
log "info", "connecting to #{pipe_path}" |
|
|
|
if command == "stdin" |
|
pipes[command] = File::open(pipe_path, "w") |
|
else |
|
pipes[command] = File::open(pipe_path, "r") |
|
end |
|
|
|
pipes[command].sync = true |
|
|
|
log "info", "connected" |
|
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"]) |
|
log "trace", read_ios.inspect |
|
|
|
ready_read_ios, _, _ = IO.select(read_ios, [], []) |
|
|
|
log "trace", "ready read IOs: #{ready_read_ios.inspect}" |
|
|
|
ready_read_ios.each do |ready_read_io| |
|
begin |
|
if ready_read_io.equal? $stdin |
|
log "trace", "writing to stdin" |
|
pipes["stdin"].write ready_read_io.readpartial(4096) |
|
elsif ready_read_io.equal? pipes["stdout"] |
|
log "trace", "reading from stdout" |
|
$stdout.write ready_read_io.readpartial(4096) |
|
elsif ready_read_io.equal? pipes["stderr"] |
|
log "trace", "reading from stderr" |
|
$stderr.write ready_read_io.readpartial(4096) |
|
elsif ready_read_io.equal? $control_socket |
|
log "trace", "reading from control socket" |
|
command, arguments = read_command($control_socket) |
|
|
|
if command != "done" |
|
log "error", "malformed response from github-fast-envd" |
|
end |
|
|
|
if !arguments.empty? |
|
exit_code = arguments[0] |
|
end |
|
else |
|
log "warn", "received input from unknown stream" |
|
end |
|
rescue EOFError |
|
log "trace", "closing stream" |
|
ready_read_io.close |
|
end |
|
end |
|
|
|
read_ios = read_ios.select {|x| not x.closed?} |
|
end |
|
|
|
exit_code_is_numeric = Integer(exit_code) != nil rescue false |
|
|
|
if exit_code_is_numeric |
|
exit Integer(exit_code) |
|
end
|
|
|