forked from asynchrony/ruby-activeldap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand.rb
112 lines (101 loc) · 2.64 KB
/
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
require "thread"
require "socket"
require "shellwords"
module Command
class Error < StandardError
attr_reader :command, :result
def initialize(command, result)
@command = command
@result = result
super("#{command}: #{result}")
end
end
module_function
def detach_io
require 'fcntl'
[TCPSocket, ::File].each do |c|
ObjectSpace.each_object(c) do |io|
begin
unless io.closed?
io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
end
rescue SystemCallError,IOError => e
end
end
end
end
def run(cmd, *args, &block)
raise ArgumentError, "command isn't specified" if cmd.nil?
if args.any? {|x| x.nil?}
raise ArgumentError, "args has nil: #{args.inspect}"
end
return java_run(cmd, *args, &block) if Object.respond_to?(:java)
in_r, in_w = IO.pipe
out_r, out_w = IO.pipe
pid = exit_status = nil
Thread.exclusive do
verbose = $VERBOSE
# ruby(>=1.8)'s fork terminates other threads with warning messages
$VERBOSE = nil
pid = fork do
$VERBOSE = verbose
detach_io
out = STDERR.dup
STDIN.reopen(in_r)
in_r.close
STDOUT.reopen(out_w)
STDERR.reopen(out_w)
out_w.close
exec(cmd, *args.collect {|arg| arg.to_s})
exit!(-1)
end
$VERBOSE = verbose
end
yield(out_r, in_w) if block_given?
in_r.close unless in_r.closed?
out_w.close unless out_w.closed?
pid, status = Process.waitpid2(pid)
[status.exited? && status.exitstatus.zero?, out_r.read]
end
def java_run(cmd, *args, &block)
runtime = java.lang.Runtime.get_runtime
process = runtime.exec([cmd, *args].to_java(:string))
input = JavaReaderWrapper.new(process.get_input_stream)
output = JavaWriterWrapper.new(process.get_output_stream)
error = JavaReaderWrapper.new(process.get_error_stream)
yield(input, output) if block_given?
output.close
success = process.wait_for.zero?
[success, input.read + error.read]
end
class JavaReaderWrapper
def initialize(input)
@input = input
end
def read
result = ""
while (c = @input.read) != -1
result << c.chr
end
result
end
end
class JavaWriterWrapper
def initialize(output)
output = java.io.OutputStreamWriter.new(output)
@output = java.io.BufferedWriter.new(output)
end
def puts(*messages)
messages.each do |message|
message += "\n" if /\n/ !~ message
@output.write(message)
end
end
def flush
@output.flush
end
def close
@output.close
end
end
end