cmds 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/Rakefile +7 -2
- data/bin/rake +3 -0
- data/bin/rspec +3 -0
- data/cmds.gemspec +1 -1
- data/lib/cmds/cmd.rb +376 -0
- data/lib/cmds/debug.rb +2 -2
- data/lib/cmds/erb_context.rb +3 -3
- data/lib/cmds/io_handler.rb +2 -2
- data/lib/cmds/pipe.rb +1 -1
- data/lib/cmds/result.rb +10 -6
- data/lib/cmds/shell_eruby.rb +2 -2
- data/lib/cmds/spawn.rb +251 -0
- data/lib/cmds/sugar.rb +145 -222
- data/lib/cmds/util/defaults.rb +71 -0
- data/lib/cmds/util/params.rb +56 -0
- data/lib/cmds/util/tokenize_option.rb +118 -0
- data/lib/cmds/util/tokenize_options.rb +50 -0
- data/lib/cmds/util.rb +35 -195
- data/lib/cmds/version.rb +2 -2
- data/lib/cmds.rb +3 -36
- data/scratch/proxy.rb +1 -1
- data/spec/cmds/assert_spec.rb +1 -1
- data/spec/cmds/capture_spec.rb +9 -25
- data/spec/cmds/chomp_spec.rb +7 -7
- data/spec/cmds/curry_spec.rb +1 -1
- data/spec/cmds/err_spec.rb +9 -6
- data/spec/cmds/error_spec.rb +6 -6
- data/spec/cmds/ok_spec.rb +2 -2
- data/spec/cmds/out_spec.rb +7 -7
- data/spec/cmds/{sub_spec.rb → prepare_spec.rb} +20 -32
- data/spec/cmds/stream_spec.rb +4 -4
- data/spec/cmds/util/tokenize_option_spec.rb +119 -0
- data/spec/cmds_spec.rb +11 -0
- metadata +15 -12
- data/lib/cmds/capture.rb +0 -47
- data/lib/cmds/stream.rb +0 -239
- data/spec/cmds/expand_option_hash_spec.rb +0 -61
- data/test/bin/dspec +0 -1
data/lib/cmds/spawn.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
# stdlib
|
2
|
+
require 'open3'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
# deps
|
6
|
+
require 'nrser'
|
7
|
+
require 'nrser/refinements'
|
8
|
+
|
9
|
+
# project
|
10
|
+
require 'cmds/pipe'
|
11
|
+
require 'cmds/io_handler'
|
12
|
+
|
13
|
+
using NRSER
|
14
|
+
|
15
|
+
module Cmds
|
16
|
+
# internal core function to spawn and stream inputs and/or outputs using
|
17
|
+
# threads.
|
18
|
+
#
|
19
|
+
# originally inspired by
|
20
|
+
#
|
21
|
+
# https://nickcharlton.net/posts/ruby-subprocesses-with-stdout-stderr-streams.html
|
22
|
+
#
|
23
|
+
# with major modifications from looking at Ruby's open3 module.
|
24
|
+
#
|
25
|
+
# @param [String] cmd
|
26
|
+
# shell-ready command string.
|
27
|
+
#
|
28
|
+
# @param [nil | String | #read] input
|
29
|
+
# string or readable input. here so that Cmds instances can pass their
|
30
|
+
# `@input` instance variable -- `&io_block` overrides it.
|
31
|
+
#
|
32
|
+
# @param [#call & (#arity ∈ {0, 1})] &io_block
|
33
|
+
# optional block to handle io. behavior depends on arity:
|
34
|
+
#
|
35
|
+
# - arity `0`
|
36
|
+
# - block is called and expected to return an object
|
37
|
+
# suitable for input (`nil`, `String` or `IO`-like).
|
38
|
+
# - arity `1`
|
39
|
+
# - block is called with the {Cmds::IOHandler} instance for the
|
40
|
+
# execution, which it can use to handle input and outputs.
|
41
|
+
#
|
42
|
+
# @raise [ArgumentError]
|
43
|
+
# if `&io_block` has arity greater than 1.
|
44
|
+
#
|
45
|
+
def self.spawn cmd, input = nil, &io_block
|
46
|
+
Cmds.debug "entering Cmds#really_stream",
|
47
|
+
cmd: cmd,
|
48
|
+
input: input,
|
49
|
+
io_block: io_block
|
50
|
+
|
51
|
+
# create the handler that will be yielded to the input block
|
52
|
+
handler = Cmds::IOHandler.new
|
53
|
+
|
54
|
+
# handle input
|
55
|
+
#
|
56
|
+
# if a block was provided it overrides the `input` argument.
|
57
|
+
#
|
58
|
+
if io_block
|
59
|
+
case io_block.arity
|
60
|
+
when 0
|
61
|
+
# when the input block takes no arguments it returns the input
|
62
|
+
input = io_block.call
|
63
|
+
when 1
|
64
|
+
# when the input block takes one argument, give it the handler and
|
65
|
+
# ignore the return value
|
66
|
+
io_block.call handler
|
67
|
+
|
68
|
+
# if input was assigned to the handler in the block, use it as input
|
69
|
+
input = handler.in unless handler.in.nil?
|
70
|
+
else
|
71
|
+
# bad block provided
|
72
|
+
raise ArgumentError.new <<-BLOCK.squish
|
73
|
+
provided input block must have arity 0 or 1
|
74
|
+
BLOCK
|
75
|
+
end # case io_block.arity
|
76
|
+
end # if io_block
|
77
|
+
|
78
|
+
# hash of options that will be passed to `spawn`
|
79
|
+
spawn_opts = {}
|
80
|
+
|
81
|
+
Cmds.debug "looking at input...",
|
82
|
+
input: input
|
83
|
+
|
84
|
+
# (possibly) create the input pipe... this will be nil if the provided
|
85
|
+
# input is io-like. in this case it will be used directly in the
|
86
|
+
# `spawn` options.
|
87
|
+
in_pipe = case input
|
88
|
+
when nil, String
|
89
|
+
Cmds.debug "input is a String or nil, creating pipe..."
|
90
|
+
|
91
|
+
in_pipe = Cmds::Pipe.new "INPUT", :in
|
92
|
+
spawn_opts[:in] = in_pipe.r
|
93
|
+
|
94
|
+
# don't buffer input
|
95
|
+
in_pipe.w.sync = true
|
96
|
+
in_pipe
|
97
|
+
|
98
|
+
else
|
99
|
+
Cmds.debug "input should be io-like, setting spawn opt.",
|
100
|
+
input: input
|
101
|
+
if input == $stdin
|
102
|
+
Cmds.debug "input is $stdin."
|
103
|
+
end
|
104
|
+
spawn_opts[:in] = input
|
105
|
+
nil
|
106
|
+
|
107
|
+
end # case input
|
108
|
+
|
109
|
+
# (possibly) create the output pipes.
|
110
|
+
#
|
111
|
+
# `stream` can be told to send it's output to either:
|
112
|
+
#
|
113
|
+
# 1. a Proc that will invoked with each line.
|
114
|
+
# 2. an io-like object that can be provided as `spawn`'s `:out` or
|
115
|
+
# `:err` options.
|
116
|
+
#
|
117
|
+
# in case (1) a `Cmds::Pipe` wrapping read and write piped `IO` instances
|
118
|
+
# will be created and assigned to the relevant of `out_pipe` or `err_pipe`.
|
119
|
+
#
|
120
|
+
# in case (2) the io-like object will be sent directly to `spawn` and
|
121
|
+
# the relevant `out_pipe` or `err_pipe` will be `nil`.
|
122
|
+
#
|
123
|
+
out_pipe, err_pipe = [
|
124
|
+
["ERROR", :err],
|
125
|
+
["OUTPUT", :out],
|
126
|
+
].map do |name, sym|
|
127
|
+
Cmds.debug "looking at #{ name }..."
|
128
|
+
# see if hanlder.out or hanlder.err is a Proc
|
129
|
+
if handler.send(sym).is_a? Proc
|
130
|
+
Cmds.debug "#{ name } is a Proc, creating pipe..."
|
131
|
+
pipe = Cmds::Pipe.new name, sym
|
132
|
+
# the corresponding :out or :err option for spawn needs to be
|
133
|
+
# the pipe's write handle
|
134
|
+
spawn_opts[sym] = pipe.w
|
135
|
+
# return the pipe
|
136
|
+
pipe
|
137
|
+
|
138
|
+
else
|
139
|
+
Cmds.debug "#{ name } should be io-like, setting spawn opt.",
|
140
|
+
output: handler.send(sym)
|
141
|
+
spawn_opts[sym] = handler.send(sym)
|
142
|
+
# the pipe is nil!
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
end # map outputs
|
146
|
+
|
147
|
+
Cmds.debug "spawning...",
|
148
|
+
cmd: cmd,
|
149
|
+
opts: spawn_opts
|
150
|
+
|
151
|
+
pid = Process.spawn cmd, spawn_opts
|
152
|
+
|
153
|
+
Cmds.debug "spawned.",
|
154
|
+
pid: pid
|
155
|
+
|
156
|
+
wait_thread = Process.detach pid
|
157
|
+
wait_thread[:name] = "WAIT"
|
158
|
+
|
159
|
+
Cmds.debug "wait thread created.",
|
160
|
+
thread: wait_thread
|
161
|
+
|
162
|
+
# close child ios if created
|
163
|
+
# the spawned process will read from in_pipe.r so we don't need it
|
164
|
+
in_pipe.r.close if in_pipe
|
165
|
+
# and we don't need to write to the output pipes, that will also happen
|
166
|
+
# in the spawned process
|
167
|
+
[out_pipe, err_pipe].each {|pipe| pipe.w.close if pipe}
|
168
|
+
|
169
|
+
# create threads to handle any pipes that were created
|
170
|
+
|
171
|
+
in_thread = if in_pipe
|
172
|
+
Thread.new do
|
173
|
+
Thread.current[:name] = in_pipe.name
|
174
|
+
Cmds.debug "thread started, writing input..."
|
175
|
+
|
176
|
+
in_pipe.w.write input unless input.nil?
|
177
|
+
|
178
|
+
Cmds.debug "write done, closing in_pipe.w..."
|
179
|
+
in_pipe.w.close
|
180
|
+
|
181
|
+
Cmds.debug "thread done."
|
182
|
+
end # Thread
|
183
|
+
end
|
184
|
+
|
185
|
+
out_thread, err_thread = [out_pipe, err_pipe].map do |pipe|
|
186
|
+
if pipe
|
187
|
+
Thread.new do
|
188
|
+
Thread.current[:name] = pipe.name
|
189
|
+
Cmds.debug "thread started"
|
190
|
+
|
191
|
+
loop do
|
192
|
+
Cmds.debug "blocking on gets..."
|
193
|
+
line = pipe.r.gets
|
194
|
+
if line.nil?
|
195
|
+
Cmds.debug "received nil, output done."
|
196
|
+
else
|
197
|
+
Cmds.debug <<-BLOCK.squish
|
198
|
+
received #{ line.bytesize } bytes, passing to handler.
|
199
|
+
BLOCK
|
200
|
+
end
|
201
|
+
handler.thread_send_line pipe.sym, line
|
202
|
+
break if line.nil?
|
203
|
+
end
|
204
|
+
|
205
|
+
Cmds.debug "reading done, closing pipe.r (unless already closed)..."
|
206
|
+
pipe.r.close unless pipe.r.closed?
|
207
|
+
|
208
|
+
Cmds.debug "thread done."
|
209
|
+
end # thread
|
210
|
+
end # if pipe
|
211
|
+
end # map threads
|
212
|
+
|
213
|
+
Cmds.debug "handing off main thread control to the handler..."
|
214
|
+
begin
|
215
|
+
handler.start
|
216
|
+
|
217
|
+
Cmds.debug "handler done."
|
218
|
+
|
219
|
+
ensure
|
220
|
+
# wait for the threads to complete
|
221
|
+
Cmds.debug "joining threads..."
|
222
|
+
|
223
|
+
[in_thread, out_thread, err_thread, wait_thread].each do |thread|
|
224
|
+
if thread
|
225
|
+
Cmds.debug "joining #{ thread[:name] } thread..."
|
226
|
+
thread.join
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
Cmds.debug "all threads done."
|
231
|
+
end
|
232
|
+
|
233
|
+
status = wait_thread.value.exitstatus
|
234
|
+
Cmds.debug "exit status: #{ status.inspect }"
|
235
|
+
|
236
|
+
Cmds.debug "checking @assert and exit status..."
|
237
|
+
if @assert && status != 0
|
238
|
+
# we don't necessarily have the err output, so we can't include it
|
239
|
+
# in the error message
|
240
|
+
msg = <<-BLOCK.squish
|
241
|
+
streamed command `#{ cmd }` exited with status #{ status }
|
242
|
+
BLOCK
|
243
|
+
|
244
|
+
raise SystemCallError.new msg, status
|
245
|
+
end
|
246
|
+
|
247
|
+
Cmds.debug "streaming completed."
|
248
|
+
|
249
|
+
return status
|
250
|
+
end # .spawn
|
251
|
+
end # Cmds
|
data/lib/cmds/sugar.rb
CHANGED
@@ -3,270 +3,193 @@
|
|
3
3
|
# global methods
|
4
4
|
# ==============
|
5
5
|
|
6
|
-
#
|
7
|
-
def Cmds *args, &
|
8
|
-
Cmds.capture *args, &
|
6
|
+
# @see Cmds.capture
|
7
|
+
def Cmds template, *args, **kwds, &input_block
|
8
|
+
Cmds.capture template, *args, **kwds, &input_block
|
9
9
|
end
|
10
10
|
|
11
|
-
# proxies to `Cmds::ok?`
|
12
|
-
def Cmds? *args, &block
|
13
|
-
Cmds.ok? *args, &block
|
14
|
-
end
|
15
11
|
|
16
|
-
#
|
17
|
-
def Cmds
|
18
|
-
Cmds.
|
12
|
+
# @see Cmds.ok?
|
13
|
+
def Cmds? template, *args, **kwds, &io_block
|
14
|
+
Cmds.ok? template, *args, **kwds, &io_block
|
19
15
|
end
|
20
16
|
|
21
|
-
class Cmds
|
22
|
-
# class methods
|
23
|
-
# =============
|
24
|
-
|
25
|
-
# create a new Cmd from template and subs and call it
|
26
|
-
# @return [Result]
|
27
|
-
def self.capture template, *subs, &input_block
|
28
|
-
new(template, options(subs, input_block)).capture
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.ok? template, *subs, &input_block
|
32
|
-
new(template, options(subs, input_block)).ok?
|
33
|
-
end
|
34
17
|
|
35
|
-
|
36
|
-
|
37
|
-
|
18
|
+
# @see Cmds.assert
|
19
|
+
def Cmds! template, *args, **kwds, &io_block
|
20
|
+
Cmds.assert template, *args, **kwds, &io_block
|
21
|
+
end
|
38
22
|
|
39
|
-
def self.assert template, *subs, &input_block
|
40
|
-
new(
|
41
|
-
template,
|
42
|
-
options(subs, input_block).merge!(assert: true)
|
43
|
-
).capture
|
44
|
-
end
|
45
23
|
|
24
|
+
module Cmds
|
25
|
+
# create a new {Cmd} instance with the template and parameters and
|
26
|
+
# calls {Cmd#prepare}.
|
27
|
+
#
|
28
|
+
# @param [String] template
|
29
|
+
# ERB template parameters are rendered into to create the command string.
|
30
|
+
#
|
31
|
+
# @param [Array<Object>] *args
|
32
|
+
# positional parameters for rendering into the template.
|
33
|
+
#
|
34
|
+
# @param [Hash{Symbol => Object}] **kwds
|
35
|
+
# keyword parameters for rendering into the template.
|
36
|
+
#
|
37
|
+
# @return [String]
|
38
|
+
# rendered and formatted command string ready to be executed.
|
39
|
+
#
|
40
|
+
def self.prepare template, *args, **kwds
|
41
|
+
Cmd.new(template).prepare *args, **kwds
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# create a new {Cmd} from template with parameters and call {Cmds#capture}
|
46
|
+
# on it.
|
47
|
+
#
|
48
|
+
# @param template (see .prepare)
|
49
|
+
# @param *args (see .prepare)
|
50
|
+
# @param **kwds (see .prepare)
|
51
|
+
#
|
52
|
+
# @param [#call] &input_block
|
53
|
+
# optional block that returns a string or IO-like readable object to be
|
54
|
+
# used as input for the execution.
|
55
|
+
#
|
56
|
+
# @return [Result]
|
57
|
+
# result with command string, exist status, stdout and stderr.
|
58
|
+
#
|
59
|
+
def self.capture template, *args, **kwds, &input_block
|
60
|
+
Cmd.new(template).capture *args, **kwds, &input_block
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# create a new {Cmd} from template with parameters and call {Cmd#ok?}
|
65
|
+
# on it.
|
66
|
+
#
|
67
|
+
# @param template (see .prepare)
|
68
|
+
# @param *args (see .prepare)
|
69
|
+
# @param **kwds (see .prepare)
|
70
|
+
# @param &io_block (see Cmds.spawn)
|
71
|
+
#
|
72
|
+
# @return [Result]
|
73
|
+
# result with command string, exist status, stdout and stderr.
|
74
|
+
#
|
75
|
+
def self.ok? template, *args, **kwds, &io_block
|
76
|
+
Cmd.new(template).ok? *args, **kwds, &io_block
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def self.error? template, *args, **kwds, &io_block
|
81
|
+
Cmd.new(template).error? *args, **kwds, &io_block
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# create a new {Cmd} and
|
86
|
+
def self.assert template, *args, **kwds, &io_block
|
87
|
+
Cmd.new(template).capture(*args, **kwds, &io_block).assert
|
88
|
+
end
|
89
|
+
|
90
|
+
|
46
91
|
def self.stream template, *subs, &input_block
|
47
|
-
Cmds.new(template).stream *subs, &input_block
|
92
|
+
Cmds::Cmd.new(template).stream *subs, &input_block
|
48
93
|
end
|
49
|
-
|
94
|
+
|
95
|
+
|
50
96
|
def self.stream! template, *subs, &input_block
|
51
|
-
Cmds.new(template, assert: true).stream *subs, &input_block
|
97
|
+
Cmds::Cmd.new(template, assert: true).stream *subs, &input_block
|
52
98
|
end # ::stream!
|
53
99
|
|
54
|
-
|
55
|
-
#
|
100
|
+
|
101
|
+
# creates a new {Cmd}, captures and returns stdout
|
102
|
+
# (sugar for `Cmds.capture(template, *args, **kwds, &input_block).out`).
|
56
103
|
#
|
57
|
-
#
|
58
|
-
# (sugar for `Cmds.capture(*template, *subs, &input_block).out`).
|
59
|
-
#
|
60
|
-
# @see .capture
|
61
|
-
# @see Result#out
|
104
|
+
# @see Cmd.out
|
62
105
|
#
|
63
|
-
# @param template
|
64
|
-
# @param
|
65
|
-
# @param
|
106
|
+
# @param template (see .prepare)
|
107
|
+
# @param *args (see .prepare)
|
108
|
+
# @param **kwds (see .prepare)
|
109
|
+
# @param &input_block (see .capture)
|
66
110
|
#
|
67
|
-
# @return [String]
|
111
|
+
# @return [String]
|
112
|
+
# the command's stdout.
|
68
113
|
#
|
69
|
-
def self.out template, *
|
70
|
-
|
114
|
+
def self.out template, *args, **kwds, &input_block
|
115
|
+
Cmd.new(template).out *args, **kwds, &input_block
|
71
116
|
end
|
72
|
-
|
73
|
-
|
74
|
-
#
|
117
|
+
|
118
|
+
|
119
|
+
# creates a new {Cmd}, captures and returns stdout. raises an error if the
|
120
|
+
# command fails.
|
75
121
|
#
|
76
|
-
#
|
122
|
+
# @see Cmd.out!
|
77
123
|
#
|
78
|
-
# @see .
|
79
|
-
# @see
|
124
|
+
# @param template (see .prepare)
|
125
|
+
# @param *args (see .prepare)
|
126
|
+
# @param **kwds (see .prepare)
|
127
|
+
# @param &input_block (see .capture)
|
80
128
|
#
|
81
|
-
# @
|
82
|
-
#
|
83
|
-
# @param input_block [Proc] see {.capture}.
|
129
|
+
# @return [String]
|
130
|
+
# the command's stdout.
|
84
131
|
#
|
85
|
-
# @
|
132
|
+
# @raise [SystemCallError]
|
133
|
+
# if the command fails (non-zero exit status).
|
86
134
|
#
|
87
|
-
|
88
|
-
|
89
|
-
def self.out! template, *subs, &input_block
|
90
|
-
Cmds.new(
|
91
|
-
template,
|
92
|
-
options(subs, input_block).merge!(assert: true),
|
93
|
-
).capture.out
|
135
|
+
def self.out! template, *args, **kwds, &input_block
|
136
|
+
Cmd.new(template).out! *args, **kwds, &input_block
|
94
137
|
end
|
95
|
-
|
96
|
-
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# captures and chomps stdout
|
100
|
-
# (sugar for `Cmds.out(*template, *subs, &input_block).chomp`).
|
138
|
+
|
139
|
+
|
140
|
+
# captures a new {Cmd}, captures and chomps stdout
|
141
|
+
# (sugar for `Cmds.out(template, *args, **kwds, &input_block).chomp`).
|
101
142
|
#
|
102
143
|
# @see .out
|
103
144
|
#
|
104
|
-
# @param template
|
105
|
-
# @param
|
106
|
-
# @param
|
145
|
+
# @param template (see .prepare)
|
146
|
+
# @param *args (see .prepare)
|
147
|
+
# @param **kwds (see .prepare)
|
148
|
+
# @param &input_block (see .capture)
|
107
149
|
#
|
108
|
-
# @return [String]
|
150
|
+
# @return [String]
|
151
|
+
# the command's chomped stdout.
|
109
152
|
#
|
110
|
-
def self.chomp template, *
|
111
|
-
out(template, *
|
153
|
+
def self.chomp template, *args, **kwds, &input_block
|
154
|
+
out(template, *args, **kwds, &input_block).chomp
|
112
155
|
end
|
113
|
-
|
114
|
-
|
115
|
-
# @api sugar
|
116
|
-
#
|
156
|
+
|
157
|
+
|
117
158
|
# captures and chomps stdout, raising an error if the command fails.
|
118
|
-
# (sugar for `Cmds.out!(
|
159
|
+
# (sugar for `Cmds.out!(template, *args, **kwds, &input_block).chomp`).
|
119
160
|
#
|
120
161
|
# @see .out!
|
121
162
|
#
|
122
|
-
# @param template
|
123
|
-
# @param
|
124
|
-
# @param
|
163
|
+
# @param template (see .prepare)
|
164
|
+
# @param *args (see .prepare)
|
165
|
+
# @param **kwds (see .prepare)
|
166
|
+
# @param &input_block (see .capture)
|
125
167
|
#
|
126
|
-
# @return [String]
|
168
|
+
# @return [String]
|
169
|
+
# the command's chomped stdout.
|
127
170
|
#
|
128
|
-
# @raise [SystemCallError]
|
171
|
+
# @raise [SystemCallError]
|
172
|
+
# if the command fails (non-zero exit status).
|
129
173
|
#
|
130
|
-
def self.chomp! template, *
|
131
|
-
out!(template, *
|
174
|
+
def self.chomp! template, *args, **kwds, &input_block
|
175
|
+
out!(template, *args, **kwds, &input_block).chomp
|
132
176
|
end
|
133
|
-
|
134
|
-
|
135
|
-
# @api sugar
|
136
|
-
#
|
177
|
+
|
178
|
+
|
137
179
|
# captures and returns stderr
|
138
|
-
# (sugar for `Cmds.capture(template, *
|
180
|
+
# (sugar for `Cmds.capture(template, *args, **kwds, &input_block).err`).
|
139
181
|
#
|
140
182
|
# @see .capture
|
141
|
-
# @see Result#err
|
142
|
-
#
|
143
|
-
# @param template [String] see {.capture}.
|
144
|
-
# @param subs [Array] see {.capture}.
|
145
|
-
# @param input_block [Proc] see {.capture}.
|
146
|
-
#
|
147
|
-
# @return [String] the command's stderr.
|
148
|
-
#
|
149
|
-
def self.err template, *subs, &input_block
|
150
|
-
capture(template, *subs, &input_block).err
|
151
|
-
end
|
152
|
-
|
153
|
-
# instance methods
|
154
|
-
# ================
|
155
|
-
|
156
|
-
alias_method :call, :capture
|
157
|
-
|
158
|
-
def ok?
|
159
|
-
stream == 0
|
160
|
-
end
|
161
|
-
|
162
|
-
def error?
|
163
|
-
stream != 0
|
164
|
-
end
|
165
|
-
|
166
|
-
# def assert
|
167
|
-
# capture.raise_error
|
168
|
-
# end
|
169
|
-
|
170
|
-
def proxy
|
171
|
-
stream do |io|
|
172
|
-
io.in = $stdin
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
# @api sugar
|
178
|
-
#
|
179
|
-
# captures and returns stdout
|
180
|
-
# (sugar for `#capture(*subs, &input_block).out`).
|
181
|
-
#
|
182
|
-
# @see #capture
|
183
|
-
# @see Result#out
|
184
|
-
#
|
185
|
-
# @param subs [Array] see {.capture}.
|
186
|
-
# @param input_block [Proc] see {.capture}.
|
187
|
-
#
|
188
|
-
# @return [String] the command's stdout.
|
189
|
-
#
|
190
|
-
def out *subs, &input_block
|
191
|
-
capture(*subs, &input_block).out
|
192
|
-
end
|
193
|
-
|
194
|
-
|
195
|
-
# @api sugar
|
196
|
-
#
|
197
|
-
# captures and returns stdout
|
198
|
-
# (sugar for `#capture(*subs, &input_block).out`).
|
199
|
-
#
|
200
|
-
# @see #capture
|
201
|
-
# @see Result#out
|
202
|
-
#
|
203
|
-
# @param subs [Array] see {.capture}.
|
204
|
-
# @param input_block [Proc] see {.capture}.
|
205
|
-
#
|
206
|
-
# @return [String] the command's stdout.
|
207
|
-
#
|
208
|
-
# @raise [SystemCallError] if the command fails (non-zero exit status).
|
209
|
-
#
|
210
|
-
def out! *subs, &input_block
|
211
|
-
self.class.new(
|
212
|
-
@template,
|
213
|
-
merge_options(subs, input_block).merge!(assert: true),
|
214
|
-
).capture.out
|
215
|
-
end
|
216
|
-
|
217
|
-
|
218
|
-
# @api sugar
|
219
183
|
#
|
220
|
-
#
|
221
|
-
#
|
184
|
+
# @param template (see .prepare)
|
185
|
+
# @param *args (see .prepare)
|
186
|
+
# @param **kwds (see .prepare)
|
187
|
+
# @param &input_block (see .capture)
|
222
188
|
#
|
223
|
-
# @
|
189
|
+
# @return [String]
|
190
|
+
# the command's stderr.
|
224
191
|
#
|
225
|
-
|
226
|
-
|
227
|
-
#
|
228
|
-
# @return [String] the command's chomped stdout.
|
229
|
-
#
|
230
|
-
def chomp *subs, &input_block
|
231
|
-
out(*subs, &input_block).chomp
|
232
|
-
end
|
233
|
-
|
234
|
-
|
235
|
-
# @api sugar
|
236
|
-
#
|
237
|
-
# captures and chomps stdout, raising an error if the command failed.
|
238
|
-
# (sugar for `#out!(*subs, &input_block).chomp`).
|
239
|
-
#
|
240
|
-
# @see #capture
|
241
|
-
# @see Result#out
|
242
|
-
#
|
243
|
-
# @param subs [Array] see {.capture}.
|
244
|
-
# @param input_block [Proc] see {.capture}.
|
245
|
-
#
|
246
|
-
# @return [String] the command's chomped stdout.
|
247
|
-
#
|
248
|
-
# @raise [SystemCallError] if the command fails (non-zero exit status).
|
249
|
-
#
|
250
|
-
def chomp! *subs, &input_block
|
251
|
-
out!(*subs, &input_block).chomp
|
252
|
-
end
|
253
|
-
|
254
|
-
|
255
|
-
# @api sugar
|
256
|
-
#
|
257
|
-
# captures and returns stdout
|
258
|
-
# (sugar for `#capture(*subs, &input_block).err`).
|
259
|
-
#
|
260
|
-
# @param subs [Array] see {.capture}.
|
261
|
-
# @param input_block [Proc] see {.capture}.
|
262
|
-
#
|
263
|
-
# @see #capture
|
264
|
-
# @see Result#err
|
265
|
-
#
|
266
|
-
# @return [String] the command's stderr.
|
267
|
-
#
|
268
|
-
def err *subs, &input_block
|
269
|
-
capture(*subs, &input_block).err
|
192
|
+
def self.err template, *args, **kwds, &input_block
|
193
|
+
capture(template, *args, **kwds, &input_block).err
|
270
194
|
end
|
271
|
-
|
272
|
-
end # class Cmds
|
195
|
+
end # Cmds
|