Repository navigation
Expand file tree
/
Copy pathshell.rb
More file actions
82 lines (65 loc) · 2.23 KB
/
Copy pathshell.rb
File metadata and controls
82 lines (65 loc) · 2.23 KB
1
2
3
4
5
6
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
require "timeout"
require "benchmark"
module MiniMagick
##
# Sends commands to the shell (more precisely, it sends commands directly to
# the operating system).
#
# @private
#
class Shell
def run(command, options = {})
stdout, stderr, status = execute(command, stdin: options[:stdin])
if status != 0 && options.fetch(:whiny, MiniMagick.whiny)
fail MiniMagick::Error, "`#{command.join(" ")}` failed with error:\n#{stderr}"
end
#$stderr.print(stderr) unless options[:stderr] == false
[stdout, stderr, status]
end
def execute(command, options = {})
stdout, stderr, status =
log(command.join(" ")) do
send("execute_#{MiniMagick.shell_api.gsub("-", "_")}", command, options)
end
[stdout, stderr, status.exitstatus]
rescue Errno::ENOENT, IOError
["", "executable not found: \"#{command.first}\"", 127]
end
private
def execute_open3(command, options = {})
require "open3"
in_w, out_r, err_r, subprocess_thread = Open3.popen3(*command)
capture_command(in_w, out_r, err_r, subprocess_thread, options)
end
def execute_posix_spawn(command, options = {})
require "posix-spawn"
child = POSIX::Spawn::Child.new(*command, input: options[:stdin].to_s, timeout: MiniMagick.timeout)
[child.out, child.err, child.status]
rescue POSIX::Spawn::TimeoutExceeded
raise Timeout::Error
end
def capture_command(in_w, out_r, err_r, subprocess_thread, options)
[in_w, out_r, err_r].each(&:binmode)
stdout_reader = Thread.new { out_r.read }
stderr_reader = Thread.new { err_r.read }
begin
in_w.write options[:stdin].to_s
rescue Errno::EPIPE
end
in_w.close
Timeout.timeout(MiniMagick.timeout) { subprocess_thread.join }
[stdout_reader.value, stderr_reader.value, subprocess_thread.value]
rescue Timeout::Error => error
Process.kill("TERM", subprocess_thread.pid)
raise error
ensure
[out_r, err_r].each(&:close)
end
def log(command, &block)
value = nil
duration = Benchmark.realtime { value = block.call }
MiniMagick.logger.debug "[%.2fs] %s" % [duration, command]
value
end
end
end