-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
/
Copy pathsystem_command.rb
124 lines (103 loc) · 3.36 KB
/
system_command.rb
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
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
require 'open3'
class Cask::SystemCommand
def self.run(executable, options={})
command = _process_options(executable, options)
odebug "Executing: #{command.utf8_inspect}"
processed_stdout = ''
processed_stderr = ''
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = Open3.popen3(*command.map(&:to_s))
if options[:input]
Array(options[:input]).each { |line| raw_stdin.puts line }
end
raw_stdin.close_write
while line = raw_stdout.gets
processed_stdout << line
ohai line.chomp if options[:print_stdout]
end
while line = raw_stderr.gets
processed_stderr << line
ohai line.chomp if options[:print_stderr]
end
raw_stdout.close_read
raw_stderr.close_read
# Ruby 1.8 sets $?. Ruby 1.9+ has raw_wait_thr, and does not set $?.
processed_exit_status = raw_wait_thr.nil? ? $? : raw_wait_thr.value
_assert_success(processed_exit_status, command, processed_stdout) if options[:must_succeed]
Cask::SystemCommand::Result.new(command, processed_stdout, processed_stderr, processed_exit_status)
end
def self.run!(command, options={})
run(command, options.merge(:must_succeed => true))
end
def self._process_options(executable, options)
options.assert_valid_keys :input, :print_stdout, :print_stderr, :args, :must_succeed, :sudo
sudo_prefix = %w{/usr/bin/sudo -E --}
command = [executable]
options[:print_stderr] = true if !options.key?(:print_stderr)
command.unshift(*sudo_prefix) if options[:sudo]
command.concat(options[:args]) if options.key?(:args) and !options[:args].empty?
command
end
def self._assert_success(status, command, output)
unless status and status.success?
raise CaskCommandFailedError.new(command.utf8_inspect, output, status)
end
end
end
class Cask::SystemCommand::Result
attr_accessor :command, :stdout, :stderr, :exit_status
def initialize(command, stdout, stderr, exit_status)
@command = command
@stdout = stdout
@stderr = stderr
@exit_status = exit_status
end
def plist
@plist ||= self.class._parse_plist(@command, @stdout)
end
def success?
@exit_status == 0
end
def merged_output
@merged_output ||= @stdout + @stderr
end
def to_s
@stdout
end
def self._warn_plist_garbage(command, garbage)
return true unless garbage =~ %r{\S}
external = File.basename(command.first)
lines = garbage.strip.split("\n")
opoo "Non-XML stdout from #{external}:"
STDERR.puts lines.map {|l| " #{l}"}
end
def self._parse_plist(command, output)
begin
raise CaskError.new("Empty plist input") unless output =~ %r{\S}
output.sub!(%r{\A(.*?)(<\?\s*xml)}m, '\2')
_warn_plist_garbage(command, $1) if Cask.debug
output.sub!(%r{(<\s*/\s*plist\s*>)(.*?)\Z}m, '\1')
_warn_plist_garbage(command, $2)
xml = Plist::parse_xml(output)
unless xml.respond_to?(:keys) and xml.keys.size > 0
raise CaskError.new(<<-ERRMSG)
Empty result parsing plist output from command.
command was:
#{command.utf8_inspect}
output we attempted to parse:
#{output}
ERRMSG
end
xml
rescue Plist::ParseError => e
raise CaskError.new(<<-ERRMSG)
Error parsing plist output from command.
command was:
#{command.utf8_inspect}
error was:
#{e}
output we attempted to parse:
#{output}
ERRMSG
end
end
end