7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# File 'lib/frontkick/command.rb', line 7
def self.exec(*env_cmd, **opts, &block)
env, cmd = env_cmd.size >= 2 ? env_cmd : [{}, env_cmd.first]
cmd_array = cmd.is_a?(Array) ? cmd : [cmd]
opts[:timeout_kill] = true unless opts.has_key?(:timeout_kill)
opts[:timeout_kill_signal] = 'SIGINT' unless opts.has_key?(:timeout_kill_signal)
exit_code, duration = nil
stdin, stdout, stderr, wait_thr, pid = nil
if opts[:out]
if opts[:out].is_a?(String)
out = File.open(opts[:out], 'w')
out.sync = true
else
out = opts[:out]
end
else
out = StringIO.new
end
if opts[:err]
if opts[:err].is_a?(String)
err = File.open(opts[:err], 'w')
err.sync = true
else
err = opts[:err]
end
else
err = StringIO.new
end
if opts[:dry_run]
command = build_command(env, cmd_array)
return Result.new(:stdout => command, :stderr => '', :exit_code => 0, :duration => 0)
end
popen3_opts = self.popen3_opts(opts)
lock_fd = file_lock(opts[:exclusive], opts[:exclusive_blocking]) if opts[:exclusive]
begin
::Timeout.timeout(opts[:timeout], Frontkick::TimeoutLocal) do
duration = Benchmark.realtime do
if opts[:popen2e]
stdin, stdout, wait_thr = Open3.popen2e(env, *cmd_array, popen3_opts)
out_thr = Thread.new {
begin
while true
out.write stdout.readpartial(4096)
end
rescue EOFError
end
}
stdin.close
pid = wait_thr.pid
yield(wait_thr) if block_given?
out_thr.join
exit_code = wait_thr.value.exitstatus
process_wait(pid)
else
stdin, stdout, stderr, wait_thr = Open3.popen3(env, *cmd_array, popen3_opts)
out_thr = Thread.new {
begin
while true
out.write stdout.readpartial(4096)
end
rescue EOFError
end
}
err_thr = Thread.new {
begin
while true
err.write stderr.readpartial(4096)
end
rescue EOFError
end
}
stdin.close
pid = wait_thr.pid
yield(wait_thr) if block_given?
out_thr.join
err_thr.join
exit_code = wait_thr.value.exitstatus
process_wait(pid)
end
end
end
rescue Frontkick::TimeoutLocal => e
if opts[:timeout_kill]
Process.kill(opts[:timeout_kill_signal], pid)
exit_code = wait_thr.value.exitstatus
process_wait(pid)
end
command = build_command(env, cmd_array)
raise Frontkick::Timeout.new(pid, command, opts[:timeout_kill])
ensure
stdin.close if stdin and !stdin.closed?
stdout.close if stdout and !stdout.closed?
stderr.close if stderr and !stderr.closed?
wait_thr.kill if wait_thr and !wait_thr.stop?
lock_fd.flock(File::LOCK_UN) if lock_fd
if opts[:out] and opts[:out].is_a?(String)
out.close rescue nil
end
if opts[:err] and opts[:err].is_a?(String)
err.close rescue nil
end
end
Result.new(
:stdout => opts[:out] ? opts[:out] : out.string,
:stderr => opts[:err] ? opts[:err] : err.string,
:exit_code => exit_code, :duration => duration
)
end
|