cmds 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|