subprocess 1.5.3 → 1.5.6
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 +26 -1
- data/lib/subprocess/version.rb +1 -1
- data/lib/subprocess.rb +100 -40
- data/rbi/subprocess.rbi +312 -0
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c82ea2c42d9357af9202aba5f361f28b50a60bba6d3350e3387f8bf71f7748e6
|
|
4
|
+
data.tar.gz: d12996089cab0fd638c31af1d2f73b1de63486eb482867887571c62e6fa0ec8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 609beb788615d91132bf09e5febfc71eb8ae78d3534b1549f3a50389c340602c71119302e9718beb59d5344639a6de2577a01255876866e2661ccb674c626f17
|
|
7
|
+
data.tar.gz: 24e299e7a5337bbd5ea995fe72171e872d430081a207544fda7e5ab406d75fae4e98c8ec542ede5acced032f3765efd1f97dfbe839bfccb2c92d31b04c90f6d7
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Subprocess
|
|
1
|
+
# Subprocess  [](http://rubydoc.info/github/stripe/subprocess/Subprocess)
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
@@ -65,6 +65,31 @@ differences, but if we have missed something, please file an issue.
|
|
|
65
65
|
[python]: http://docs.python.org/library/subprocess.html
|
|
66
66
|
[rubydoc]: http://rubydoc.info/github/stripe/subprocess/Subprocess
|
|
67
67
|
|
|
68
|
+
Maintenance
|
|
69
|
+
-----------
|
|
70
|
+
|
|
71
|
+
Steps to release a new version:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Work directly on master
|
|
75
|
+
git checkout master
|
|
76
|
+
|
|
77
|
+
# -- edit version in lib/subprocess/version.rb --
|
|
78
|
+
|
|
79
|
+
# Update RBI files
|
|
80
|
+
bundle exec rake sord
|
|
81
|
+
|
|
82
|
+
# Subsequent commands reference the version
|
|
83
|
+
VERSION=1.5.5
|
|
84
|
+
git commit -am "Bump version to $VERSION"
|
|
85
|
+
git tag "v$VERSION"
|
|
86
|
+
git push origin master --tags
|
|
87
|
+
bundle exec rake publish
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If you get errors, ask someone to add you to `bindings/rubygems-api-key` in
|
|
91
|
+
Vault or ask someone who already has permissions. See <http://go/password-vault>
|
|
92
|
+
|
|
68
93
|
Acknowledgements
|
|
69
94
|
----------------
|
|
70
95
|
|
data/lib/subprocess/version.rb
CHANGED
data/lib/subprocess.rb
CHANGED
|
@@ -16,7 +16,13 @@ module Subprocess
|
|
|
16
16
|
|
|
17
17
|
# An alias for `Process.new`. Mostly here to better emulate the Python API.
|
|
18
18
|
#
|
|
19
|
+
# @param [Array<String>] cmd See {Process#initialize}
|
|
20
|
+
# @param [Hash] opts See {Process#initialize}
|
|
21
|
+
# @yield [process] See {Process#initialize}
|
|
22
|
+
# @yieldparam process [Process] See {Process#initialize}
|
|
19
23
|
# @return [Process] A process with the given arguments
|
|
24
|
+
#
|
|
25
|
+
# @see Process#initialize
|
|
20
26
|
def self.popen(cmd, opts={}, &blk)
|
|
21
27
|
Process.new(cmd, opts, &blk)
|
|
22
28
|
end
|
|
@@ -28,6 +34,11 @@ module Subprocess
|
|
|
28
34
|
# fills up, as neither file descriptor will be read from. To avoid this, use
|
|
29
35
|
# {Process#communicate} from a passed block.
|
|
30
36
|
#
|
|
37
|
+
# @param [Array<String>] cmd See {Process#initialize}
|
|
38
|
+
# @param [Hash] opts See {Process#initialize}
|
|
39
|
+
# @yield [process] See {Process#initialize}
|
|
40
|
+
# @yieldparam process [Process] See {Process#initialize}
|
|
41
|
+
#
|
|
31
42
|
# @return [::Process::Status] The exit status of the process
|
|
32
43
|
#
|
|
33
44
|
# @see Process#initialize
|
|
@@ -58,6 +69,11 @@ module Subprocess
|
|
|
58
69
|
# fills up, as neither file descriptor will be read from. To avoid this, use
|
|
59
70
|
# {Process#communicate} from a passed block.
|
|
60
71
|
#
|
|
72
|
+
# @param [Array<String>] cmd See {Process#initialize}
|
|
73
|
+
# @param [Hash] opts See {Process#initialize}
|
|
74
|
+
# @yield [process] See {Process#initialize}
|
|
75
|
+
# @yieldparam process [Process] See {Process#initialize}
|
|
76
|
+
#
|
|
61
77
|
# @raise [NonZeroExit] if the process returned a non-zero exit status (i.e.,
|
|
62
78
|
# was terminated with an error or was killed by a signal)
|
|
63
79
|
# @return [::Process::Status] The exit status of the process
|
|
@@ -70,11 +86,16 @@ module Subprocess
|
|
|
70
86
|
end
|
|
71
87
|
|
|
72
88
|
# Like {Subprocess::check_call}, but return the contents of `stdout`, much
|
|
73
|
-
# like
|
|
89
|
+
# like {::Kernel#system}.
|
|
74
90
|
#
|
|
75
91
|
# @example Get the system load
|
|
76
92
|
# system_load = Subprocess.check_output(['uptime']).split(' ').last(3)
|
|
77
93
|
#
|
|
94
|
+
# @param [Array<String>] cmd See {Process#initialize}
|
|
95
|
+
# @param [Hash] opts See {Process#initialize}
|
|
96
|
+
# @yield [process] See {Process#initialize}
|
|
97
|
+
# @yieldparam process [Process] See {Process#initialize}
|
|
98
|
+
#
|
|
78
99
|
# @raise [NonZeroExit] if the process returned a non-zero exit status (i.e.,
|
|
79
100
|
# was terminated with an error or was killed by a signal)
|
|
80
101
|
# @return [String] The contents of `stdout`
|
|
@@ -130,16 +151,17 @@ module Subprocess
|
|
|
130
151
|
|
|
131
152
|
# Error class representing a process's abnormal exit.
|
|
132
153
|
class NonZeroExit < StandardError
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
154
|
+
# @note This is intended only for use in user-facing error messages. In
|
|
155
|
+
# particular, no shell quoting of any sort is performed when
|
|
156
|
+
# constructing this string, meaning that blindly running it in a shell
|
|
157
|
+
# might have different semantics than the original command.
|
|
158
|
+
#
|
|
159
|
+
# @return [String] The command and arguments for the process that exited
|
|
160
|
+
# abnormally.
|
|
161
|
+
attr_reader :command
|
|
162
|
+
|
|
163
|
+
# @return [::Process::Status] The Ruby status object returned by `waitpid`
|
|
164
|
+
attr_reader :status
|
|
143
165
|
|
|
144
166
|
# Return an instance of {NonZeroExit}.
|
|
145
167
|
#
|
|
@@ -163,12 +185,15 @@ module Subprocess
|
|
|
163
185
|
|
|
164
186
|
# Error class representing a timeout during a call to `communicate`
|
|
165
187
|
class CommunicateTimeout < StandardError
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
#
|
|
170
|
-
attr_reader :
|
|
188
|
+
# @return [String] Content read from stdout before the timeout
|
|
189
|
+
attr_reader :stdout
|
|
190
|
+
|
|
191
|
+
# @return [String] Content read from stderr before the timeout
|
|
192
|
+
attr_reader :stderr
|
|
171
193
|
|
|
194
|
+
# @param [Array<String>] cmd
|
|
195
|
+
# @param [String] stdout
|
|
196
|
+
# @param [String] stderr
|
|
172
197
|
def initialize(cmd, stdout, stderr)
|
|
173
198
|
@stdout = stdout
|
|
174
199
|
@stderr = stderr
|
|
@@ -181,22 +206,24 @@ module Subprocess
|
|
|
181
206
|
# functions on {Subprocess} (especially {Subprocess::check_call} and
|
|
182
207
|
# {Subprocess::check_output}).
|
|
183
208
|
class Process
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
#
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
209
|
+
# @return [IO] The `IO` that is connected to this process's `stdin`.
|
|
210
|
+
attr_reader :stdin
|
|
211
|
+
|
|
212
|
+
# @return [IO] The `IO` that is connected to this process's `stdout`.
|
|
213
|
+
attr_reader :stdout
|
|
214
|
+
|
|
215
|
+
# @return [IO] The `IO` that is connected to this process's `stderr`.
|
|
216
|
+
attr_reader :stderr
|
|
217
|
+
|
|
218
|
+
# @return [Array<String>] The command this process was invoked with.
|
|
219
|
+
attr_reader :command
|
|
220
|
+
|
|
221
|
+
# @return [Integer] The process ID of the spawned process.
|
|
222
|
+
attr_reader :pid
|
|
223
|
+
|
|
224
|
+
# @return [::Process::Status, nil] The exit status code of the process.
|
|
225
|
+
# Only set after the process has exited.
|
|
226
|
+
attr_reader :status
|
|
200
227
|
|
|
201
228
|
# Create a new process.
|
|
202
229
|
#
|
|
@@ -204,15 +231,15 @@ module Subprocess
|
|
|
204
231
|
# style of an `argv` array). Unlike Python's subprocess module, `cmd`
|
|
205
232
|
# cannot be a String.
|
|
206
233
|
#
|
|
207
|
-
# @option opts [IO,
|
|
234
|
+
# @option opts [IO, Integer, String, Subprocess::PIPE, nil] :stdin The `IO`,
|
|
208
235
|
# file descriptor number, or file name to use for the process's standard
|
|
209
236
|
# input. If the magic value {Subprocess::PIPE} is passed, a new pipe will
|
|
210
237
|
# be opened.
|
|
211
|
-
# @option opts [IO,
|
|
238
|
+
# @option opts [IO, Integer, String, Subprocess::PIPE, nil] :stdout The `IO`,
|
|
212
239
|
# file descriptor number, or file name to use for the process's standard
|
|
213
240
|
# output. If the magic value {Subprocess::PIPE} is passed, a pipe will be
|
|
214
241
|
# opened and attached to the process.
|
|
215
|
-
# @option opts [IO,
|
|
242
|
+
# @option opts [IO, Integer, String, Subprocess::PIPE, Subprocess::STDOUT,
|
|
216
243
|
# nil] :stderr The `IO`, file descriptor number, or file name to use for
|
|
217
244
|
# the process's standard error. If the special value {Subprocess::PIPE} is
|
|
218
245
|
# passed, a pipe will be opened and attached to the process. If the
|
|
@@ -223,12 +250,12 @@ module Subprocess
|
|
|
223
250
|
# child process.
|
|
224
251
|
# @option opts [Hash<String, String>] :env The environment to use in the
|
|
225
252
|
# child process.
|
|
226
|
-
# @option opts [Array<
|
|
253
|
+
# @option opts [Array<Integer>] :retain_fds An array of file descriptor
|
|
227
254
|
# numbers that should not be closed before executing the child process.
|
|
228
255
|
# Note that, unlike Python (which has :close_fds defaulting to false), all
|
|
229
256
|
# file descriptors not specified here will be closed.
|
|
230
257
|
# @option opts [Hash] :exec_opts A hash that will be merged into the options
|
|
231
|
-
# hash of the call to {Kernel#exec}.
|
|
258
|
+
# hash of the call to {::Kernel#exec}.
|
|
232
259
|
#
|
|
233
260
|
# @option opts [Proc] :preexec_fn A function that will be called in the
|
|
234
261
|
# child process immediately before executing `cmd`.
|
|
@@ -403,7 +430,10 @@ module Subprocess
|
|
|
403
430
|
|
|
404
431
|
stdout, stderr = "", ""
|
|
405
432
|
|
|
406
|
-
|
|
433
|
+
# NB: Always force encoding to binary so we handle unicode or binary input
|
|
434
|
+
# correctly across multiple write_nonblock calls, since we manually slice
|
|
435
|
+
# the input depending on how many bytes were written
|
|
436
|
+
input = input.dup.force_encoding('BINARY') unless input.nil?
|
|
407
437
|
|
|
408
438
|
@stdin.close if (input.nil? || input.empty?) && !@stdin.nil?
|
|
409
439
|
|
|
@@ -469,7 +499,7 @@ module Subprocess
|
|
|
469
499
|
@stdin.close
|
|
470
500
|
wait_w.delete(@stdin)
|
|
471
501
|
end
|
|
472
|
-
input[
|
|
502
|
+
input = input[written..input.length]
|
|
473
503
|
if input.empty?
|
|
474
504
|
@stdin.close
|
|
475
505
|
wait_w.delete(@stdin)
|
|
@@ -494,15 +524,23 @@ module Subprocess
|
|
|
494
524
|
|
|
495
525
|
# Does exactly what it says on the box.
|
|
496
526
|
#
|
|
497
|
-
# @param [String, Symbol,
|
|
527
|
+
# @param [String, Symbol, Integer] signal The signal to send to the child
|
|
498
528
|
# process. Accepts all the same arguments as Ruby's built-in
|
|
499
529
|
# {::Process::kill}, for instance a string like "INT" or "SIGINT", or a
|
|
500
530
|
# signal number like 2.
|
|
531
|
+
#
|
|
532
|
+
# @return [Integer] See {::Process.kill}
|
|
533
|
+
#
|
|
534
|
+
# @see ::Process.kill
|
|
501
535
|
def send_signal(signal)
|
|
502
536
|
::Process.kill(signal, pid)
|
|
503
537
|
end
|
|
504
538
|
|
|
505
539
|
# Sends `SIGTERM` to the process.
|
|
540
|
+
#
|
|
541
|
+
# @return [Integer] See {send_signal}
|
|
542
|
+
#
|
|
543
|
+
# @see send_signal
|
|
506
544
|
def terminate
|
|
507
545
|
send_signal("TERM")
|
|
508
546
|
end
|
|
@@ -512,6 +550,10 @@ module Subprocess
|
|
|
512
550
|
# descriptor should appear to the child and to this process, respectively.
|
|
513
551
|
# "mine" is only non-nil in the case of a pipe (in fact, we just return a
|
|
514
552
|
# list of length one, since ruby will unpack nils from missing list items).
|
|
553
|
+
#
|
|
554
|
+
# @param [IO, Integer, String, nil] fd
|
|
555
|
+
# @param [String] mode
|
|
556
|
+
# @return [Array<IO>]
|
|
515
557
|
def parse_fd(fd, mode)
|
|
516
558
|
fds = case fd
|
|
517
559
|
when PIPE
|
|
@@ -533,6 +575,9 @@ module Subprocess
|
|
|
533
575
|
|
|
534
576
|
# The pair to parse_fd, returns whether or not the file descriptor was
|
|
535
577
|
# opened by us (and therefore should be closed by us).
|
|
578
|
+
#
|
|
579
|
+
# @param [IO, Integer, String, nil] fd
|
|
580
|
+
# @return [Boolean]
|
|
536
581
|
def our_fd?(fd)
|
|
537
582
|
case fd
|
|
538
583
|
when PIPE, String
|
|
@@ -543,6 +588,12 @@ module Subprocess
|
|
|
543
588
|
end
|
|
544
589
|
|
|
545
590
|
# Call IO.select timing out at Time `timeout_at`. If `timeout_at` is nil, never times out.
|
|
591
|
+
#
|
|
592
|
+
# @param [Array<IO>, nil] read_array
|
|
593
|
+
# @param [Array<IO>, nil] write_array
|
|
594
|
+
# @param [Array<IO>, nil] err_array
|
|
595
|
+
# @param [Integer, Float, nil] timeout_at
|
|
596
|
+
# @return [Array<Array<IO>>, nil]
|
|
546
597
|
def select_until(read_array, write_array, err_array, timeout_at)
|
|
547
598
|
if !timeout_at
|
|
548
599
|
return IO.select(read_array, write_array, err_array)
|
|
@@ -561,6 +612,7 @@ module Subprocess
|
|
|
561
612
|
@sigchld_global_read = nil
|
|
562
613
|
@sigchld_pipe_pid = nil
|
|
563
614
|
|
|
615
|
+
# @return [void]
|
|
564
616
|
def self.handle_sigchld
|
|
565
617
|
# We'd like to just notify everything in `@sigchld_fds`, but
|
|
566
618
|
# ruby signal handlers are not executed atomically with respect
|
|
@@ -583,6 +635,7 @@ module Subprocess
|
|
|
583
635
|
# and we want to let the process itself do that. In practice, we're not
|
|
584
636
|
# likely to have that many in-flight subprocesses, so this is probably not a
|
|
585
637
|
# big deal.
|
|
638
|
+
# @return [void]
|
|
586
639
|
def self.wakeup_sigchld
|
|
587
640
|
@sigchld_mutex.synchronize do
|
|
588
641
|
@sigchld_fds.values.each do |fd|
|
|
@@ -598,6 +651,9 @@ module Subprocess
|
|
|
598
651
|
end
|
|
599
652
|
end
|
|
600
653
|
|
|
654
|
+
# @param [Integer] pid
|
|
655
|
+
# @param [IO] fd
|
|
656
|
+
# @return [void]
|
|
601
657
|
def self.register_pid(pid, fd)
|
|
602
658
|
@sigchld_mutex.synchronize do
|
|
603
659
|
@sigchld_fds[pid] = fd
|
|
@@ -615,6 +671,8 @@ module Subprocess
|
|
|
615
671
|
end
|
|
616
672
|
end
|
|
617
673
|
|
|
674
|
+
# @param [Integer] pid
|
|
675
|
+
# @return [void]
|
|
618
676
|
def self.unregister_pid(pid)
|
|
619
677
|
@sigchld_mutex.synchronize do
|
|
620
678
|
if @sigchld_fds.length == 1
|
|
@@ -624,6 +682,8 @@ module Subprocess
|
|
|
624
682
|
end
|
|
625
683
|
end
|
|
626
684
|
|
|
685
|
+
# @param [Integer] pid
|
|
686
|
+
# @return [void]
|
|
627
687
|
def self.catching_sigchld(pid)
|
|
628
688
|
IO.pipe do |self_read, self_write|
|
|
629
689
|
begin
|
data/rbi/subprocess.rbi
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
|
|
3
|
+
# THIS FILE IS AUTOGENERATED. DO NOT EDIT.
|
|
4
|
+
# To regenerate from YARD comments:
|
|
5
|
+
#
|
|
6
|
+
# bundle exec rake sord
|
|
7
|
+
#
|
|
8
|
+
# A Ruby clone of Python's subprocess module.
|
|
9
|
+
#
|
|
10
|
+
# @see http://docs.python.org/2/library/subprocess.html
|
|
11
|
+
module ::Subprocess
|
|
12
|
+
PIPE = T.let(-1, T.untyped)
|
|
13
|
+
STDOUT = T.let(-2, T.untyped)
|
|
14
|
+
VERSION = T.let('1.5.5', T.untyped)
|
|
15
|
+
|
|
16
|
+
# An alias for `Process.new`. Mostly here to better emulate the Python API.
|
|
17
|
+
#
|
|
18
|
+
# _@param_ `cmd` — See {Process#initialize}
|
|
19
|
+
#
|
|
20
|
+
# _@param_ `opts` — See {Process#initialize}
|
|
21
|
+
#
|
|
22
|
+
# _@return_ — A process with the given arguments
|
|
23
|
+
#
|
|
24
|
+
# _@see_ `Process#initialize`
|
|
25
|
+
sig { params(cmd: T::Array[String], opts: T::Hash[T.untyped, T.untyped], blk: T.nilable(T.proc.params(process: Process).void)).returns(Process) }
|
|
26
|
+
def self.popen(cmd, opts = {}, &blk); end
|
|
27
|
+
|
|
28
|
+
# Call and wait for the return of a given process.
|
|
29
|
+
#
|
|
30
|
+
# _@param_ `cmd` — See {Process#initialize}
|
|
31
|
+
#
|
|
32
|
+
# _@param_ `opts` — See {Process#initialize}
|
|
33
|
+
#
|
|
34
|
+
# _@return_ — The exit status of the process
|
|
35
|
+
#
|
|
36
|
+
# _@note_ — If you call this function with `:stdout => PIPE` or `:stderr => PIPE`,
|
|
37
|
+
# this function will block indefinitely as soon as the OS's pipe buffer
|
|
38
|
+
# fills up, as neither file descriptor will be read from. To avoid this, use
|
|
39
|
+
# {Process#communicate} from a passed block.
|
|
40
|
+
#
|
|
41
|
+
# _@see_ `Process#initialize`
|
|
42
|
+
sig { params(cmd: T::Array[String], opts: T::Hash[T.untyped, T.untyped], blk: T.nilable(T.proc.params(process: Process).void)).returns(::Process::Status) }
|
|
43
|
+
def self.call(cmd, opts = {}, &blk); end
|
|
44
|
+
|
|
45
|
+
# Like {Subprocess::call}, except raise a {NonZeroExit} if the process did not
|
|
46
|
+
# terminate successfully.
|
|
47
|
+
#
|
|
48
|
+
# _@param_ `cmd` — See {Process#initialize}
|
|
49
|
+
#
|
|
50
|
+
# _@param_ `opts` — See {Process#initialize}
|
|
51
|
+
#
|
|
52
|
+
# _@return_ — The exit status of the process
|
|
53
|
+
#
|
|
54
|
+
# Grep a file for a string
|
|
55
|
+
# ```ruby
|
|
56
|
+
# Subprocess.check_call(%W{grep -q llama ~/favorite_animals})
|
|
57
|
+
# ```
|
|
58
|
+
#
|
|
59
|
+
# Communicate with a child process
|
|
60
|
+
# ```ruby
|
|
61
|
+
# Subprocess.check_call(%W{sendmail -t}, :stdin => Subprocess::PIPE) do |p|
|
|
62
|
+
# p.communicate <<-EMAIL
|
|
63
|
+
# From: alpaca@example.com
|
|
64
|
+
# To: llama@example.com
|
|
65
|
+
# Subject: I am so fluffy.
|
|
66
|
+
#
|
|
67
|
+
# SO FLUFFY!
|
|
68
|
+
# http://upload.wikimedia.org/wikipedia/commons/3/3e/Unshorn_alpaca_grazing.jpg
|
|
69
|
+
# EMAIL
|
|
70
|
+
# end
|
|
71
|
+
# ```
|
|
72
|
+
#
|
|
73
|
+
# _@note_ — If you call this function with `:stdout => PIPE` or `:stderr => PIPE`,
|
|
74
|
+
# this function will block indefinitely as soon as the OS's pipe buffer
|
|
75
|
+
# fills up, as neither file descriptor will be read from. To avoid this, use
|
|
76
|
+
# {Process#communicate} from a passed block.
|
|
77
|
+
#
|
|
78
|
+
# _@see_ `Process#initialize`
|
|
79
|
+
sig { params(cmd: T::Array[String], opts: T::Hash[T.untyped, T.untyped], blk: T.nilable(T.proc.params(process: Process).void)).returns(::Process::Status) }
|
|
80
|
+
def self.check_call(cmd, opts = {}, &blk); end
|
|
81
|
+
|
|
82
|
+
# Like {Subprocess::check_call}, but return the contents of `stdout`, much
|
|
83
|
+
# like {::Kernel#system}.
|
|
84
|
+
#
|
|
85
|
+
# _@param_ `cmd` — See {Process#initialize}
|
|
86
|
+
#
|
|
87
|
+
# _@param_ `opts` — See {Process#initialize}
|
|
88
|
+
#
|
|
89
|
+
# _@return_ — The contents of `stdout`
|
|
90
|
+
#
|
|
91
|
+
# Get the system load
|
|
92
|
+
# ```ruby
|
|
93
|
+
# system_load = Subprocess.check_output(['uptime']).split(' ').last(3)
|
|
94
|
+
# ```
|
|
95
|
+
#
|
|
96
|
+
# _@see_ `Process#initialize`
|
|
97
|
+
sig { params(cmd: T::Array[String], opts: T::Hash[T.untyped, T.untyped], blk: T.nilable(T.proc.params(process: Process).void)).returns(String) }
|
|
98
|
+
def self.check_output(cmd, opts = {}, &blk); end
|
|
99
|
+
|
|
100
|
+
# Print a human readable interpretation of a process exit status.
|
|
101
|
+
#
|
|
102
|
+
# _@param_ `status` — The status returned by `waitpid2`.
|
|
103
|
+
#
|
|
104
|
+
# _@param_ `convert_high_exit` — Whether to convert exit statuses greater than 128 into the usual convention for exiting after trapping a signal. (e.g. many programs will exit with status 130 after receiving a SIGINT / signal 2.)
|
|
105
|
+
#
|
|
106
|
+
# _@return_ — Text interpretation
|
|
107
|
+
sig { params(status: ::Process::Status, convert_high_exit: T::Boolean).returns(String) }
|
|
108
|
+
def self.status_to_s(status, convert_high_exit = true); end
|
|
109
|
+
|
|
110
|
+
# Error class representing a process's abnormal exit.
|
|
111
|
+
class NonZeroExit < StandardError
|
|
112
|
+
# Return an instance of {NonZeroExit}.
|
|
113
|
+
#
|
|
114
|
+
# _@param_ `cmd` — The command that returned a non-zero status.
|
|
115
|
+
#
|
|
116
|
+
# _@param_ `status` — The status returned by `waitpid`.
|
|
117
|
+
sig { params(cmd: T::Array[String], status: ::Process::Status).void }
|
|
118
|
+
def initialize(cmd, status); end
|
|
119
|
+
|
|
120
|
+
# _@return_ — The command and arguments for the process that exited
|
|
121
|
+
# abnormally.
|
|
122
|
+
#
|
|
123
|
+
# _@note_ — This is intended only for use in user-facing error messages. In
|
|
124
|
+
# particular, no shell quoting of any sort is performed when
|
|
125
|
+
# constructing this string, meaning that blindly running it in a shell
|
|
126
|
+
# might have different semantics than the original command.
|
|
127
|
+
sig { returns(String) }
|
|
128
|
+
attr_reader :command
|
|
129
|
+
|
|
130
|
+
# _@return_ — The Ruby status object returned by `waitpid`
|
|
131
|
+
sig { returns(::Process::Status) }
|
|
132
|
+
attr_reader :status
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Error class representing a timeout during a call to `communicate`
|
|
136
|
+
class CommunicateTimeout < StandardError
|
|
137
|
+
# _@param_ `cmd`
|
|
138
|
+
#
|
|
139
|
+
# _@param_ `stdout`
|
|
140
|
+
#
|
|
141
|
+
# _@param_ `stderr`
|
|
142
|
+
sig { params(cmd: T::Array[String], stdout: String, stderr: String).void }
|
|
143
|
+
def initialize(cmd, stdout, stderr); end
|
|
144
|
+
|
|
145
|
+
# _@return_ — Content read from stdout before the timeout
|
|
146
|
+
sig { returns(String) }
|
|
147
|
+
attr_reader :stdout
|
|
148
|
+
|
|
149
|
+
# _@return_ — Content read from stderr before the timeout
|
|
150
|
+
sig { returns(String) }
|
|
151
|
+
attr_reader :stderr
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# A child process. The preferred way of spawning a subprocess is through the
|
|
155
|
+
# functions on {Subprocess} (especially {Subprocess::check_call} and
|
|
156
|
+
# {Subprocess::check_output}).
|
|
157
|
+
class Process
|
|
158
|
+
# Create a new process.
|
|
159
|
+
#
|
|
160
|
+
# _@param_ `cmd` — The command to run and its arguments (in the style of an `argv` array). Unlike Python's subprocess module, `cmd` cannot be a String.
|
|
161
|
+
sig { params(cmd: T::Array[String], opts: T::Hash[T.untyped, T.untyped], blk: T.nilable(T.proc.params(process: Process).void)).void }
|
|
162
|
+
def initialize(cmd, opts = {}, &blk); end
|
|
163
|
+
|
|
164
|
+
# Poll the child, setting (and returning) its status. If the child has not
|
|
165
|
+
# terminated, return nil and exit immediately
|
|
166
|
+
#
|
|
167
|
+
# _@return_ — The exit status of the process
|
|
168
|
+
sig { returns(T.nilable(::Process::Status)) }
|
|
169
|
+
def poll; end
|
|
170
|
+
|
|
171
|
+
# Wait for the child to return, setting and returning the status of the
|
|
172
|
+
# child.
|
|
173
|
+
#
|
|
174
|
+
# _@return_ — The exit status of the process
|
|
175
|
+
sig { returns(::Process::Status) }
|
|
176
|
+
def wait; end
|
|
177
|
+
|
|
178
|
+
# Do nonblocking reads from `fd`, appending all data read into `buf`.
|
|
179
|
+
#
|
|
180
|
+
# _@param_ `fd` — The file to read from.
|
|
181
|
+
#
|
|
182
|
+
# _@param_ `buf` — A buffer to append the read data to.
|
|
183
|
+
#
|
|
184
|
+
# _@return_ — Whether `fd` was closed due to an exceptional
|
|
185
|
+
# condition (`EOFError` or `EPIPE`).
|
|
186
|
+
sig { params(fd: IO, buf: T.nilable(String)).returns(T::Boolean) }
|
|
187
|
+
def drain_fd(fd, buf = nil); end
|
|
188
|
+
|
|
189
|
+
# Write the (optional) input to the process's `stdin` and read the contents of
|
|
190
|
+
# `stdout` and `stderr`. If a block is provided, stdout and stderr are yielded as they
|
|
191
|
+
# are read. Otherwise they are buffered in memory and returned when the process
|
|
192
|
+
# exits. Do this all using `IO::select`, so we don't deadlock due to full pipe
|
|
193
|
+
# buffers.
|
|
194
|
+
#
|
|
195
|
+
# This is only really useful if you set some of `:stdin`, `:stdout`, and
|
|
196
|
+
# `:stderr` to {Subprocess::PIPE}.
|
|
197
|
+
#
|
|
198
|
+
# _@param_ `input` — A string to feed to the child's standard input.
|
|
199
|
+
#
|
|
200
|
+
# _@param_ `timeout_s` — Raise {Subprocess::CommunicateTimeout} if communicate does not finish after timeout_s seconds.
|
|
201
|
+
#
|
|
202
|
+
# _@return_ — An array of two elements: the data read from the
|
|
203
|
+
# child's standard output and standard error, respectively.
|
|
204
|
+
# Returns nil if a block is provided.
|
|
205
|
+
sig { params(input: T.nilable(String), timeout_s: T.nilable(Numeric)).returns([String, String]) }
|
|
206
|
+
def communicate(input = nil, timeout_s = nil); end
|
|
207
|
+
|
|
208
|
+
# Does exactly what it says on the box.
|
|
209
|
+
#
|
|
210
|
+
# _@param_ `signal` — The signal to send to the child process. Accepts all the same arguments as Ruby's built-in {::Process::kill}, for instance a string like "INT" or "SIGINT", or a signal number like 2.
|
|
211
|
+
#
|
|
212
|
+
# _@return_ — See {::Process.kill}
|
|
213
|
+
#
|
|
214
|
+
# _@see_ `::Process.kill`
|
|
215
|
+
sig { params(signal: T.any(String, Symbol, Integer)).returns(Integer) }
|
|
216
|
+
def send_signal(signal); end
|
|
217
|
+
|
|
218
|
+
# Sends `SIGTERM` to the process.
|
|
219
|
+
#
|
|
220
|
+
# _@return_ — See {send_signal}
|
|
221
|
+
#
|
|
222
|
+
# _@see_ `send_signal`
|
|
223
|
+
sig { returns(Integer) }
|
|
224
|
+
def terminate; end
|
|
225
|
+
|
|
226
|
+
# Return a pair of values (child, mine), which are how the given file
|
|
227
|
+
# descriptor should appear to the child and to this process, respectively.
|
|
228
|
+
# "mine" is only non-nil in the case of a pipe (in fact, we just return a
|
|
229
|
+
# list of length one, since ruby will unpack nils from missing list items).
|
|
230
|
+
#
|
|
231
|
+
# _@param_ `fd`
|
|
232
|
+
#
|
|
233
|
+
# _@param_ `mode`
|
|
234
|
+
sig { params(fd: T.nilable(T.any(IO, Integer, String)), mode: String).returns(T::Array[IO]) }
|
|
235
|
+
def parse_fd(fd, mode); end
|
|
236
|
+
|
|
237
|
+
# The pair to parse_fd, returns whether or not the file descriptor was
|
|
238
|
+
# opened by us (and therefore should be closed by us).
|
|
239
|
+
#
|
|
240
|
+
# _@param_ `fd`
|
|
241
|
+
sig { params(fd: T.nilable(T.any(IO, Integer, String))).returns(T::Boolean) }
|
|
242
|
+
def our_fd?(fd); end
|
|
243
|
+
|
|
244
|
+
# Call IO.select timing out at Time `timeout_at`. If `timeout_at` is nil, never times out.
|
|
245
|
+
#
|
|
246
|
+
# _@param_ `read_array`
|
|
247
|
+
#
|
|
248
|
+
# _@param_ `write_array`
|
|
249
|
+
#
|
|
250
|
+
# _@param_ `err_array`
|
|
251
|
+
#
|
|
252
|
+
# _@param_ `timeout_at`
|
|
253
|
+
sig do
|
|
254
|
+
params(
|
|
255
|
+
read_array: T.nilable(T::Array[IO]),
|
|
256
|
+
write_array: T.nilable(T::Array[IO]),
|
|
257
|
+
err_array: T.nilable(T::Array[IO]),
|
|
258
|
+
timeout_at: T.nilable(T.any(Integer, Float))
|
|
259
|
+
).returns(T.nilable(T::Array[T::Array[IO]]))
|
|
260
|
+
end
|
|
261
|
+
def select_until(read_array, write_array, err_array, timeout_at); end
|
|
262
|
+
|
|
263
|
+
sig { void }
|
|
264
|
+
def self.handle_sigchld; end
|
|
265
|
+
|
|
266
|
+
# Wake up everyone. We can't tell who we should wake up without `wait`ing,
|
|
267
|
+
# and we want to let the process itself do that. In practice, we're not
|
|
268
|
+
# likely to have that many in-flight subprocesses, so this is probably not a
|
|
269
|
+
# big deal.
|
|
270
|
+
sig { void }
|
|
271
|
+
def self.wakeup_sigchld; end
|
|
272
|
+
|
|
273
|
+
# _@param_ `pid`
|
|
274
|
+
#
|
|
275
|
+
# _@param_ `fd`
|
|
276
|
+
sig { params(pid: Integer, fd: IO).void }
|
|
277
|
+
def self.register_pid(pid, fd); end
|
|
278
|
+
|
|
279
|
+
# _@param_ `pid`
|
|
280
|
+
sig { params(pid: Integer).void }
|
|
281
|
+
def self.unregister_pid(pid); end
|
|
282
|
+
|
|
283
|
+
# _@param_ `pid`
|
|
284
|
+
sig { params(pid: Integer).void }
|
|
285
|
+
def self.catching_sigchld(pid); end
|
|
286
|
+
|
|
287
|
+
# _@return_ — The `IO` that is connected to this process's `stdin`.
|
|
288
|
+
sig { returns(IO) }
|
|
289
|
+
attr_reader :stdin
|
|
290
|
+
|
|
291
|
+
# _@return_ — The `IO` that is connected to this process's `stdout`.
|
|
292
|
+
sig { returns(IO) }
|
|
293
|
+
attr_reader :stdout
|
|
294
|
+
|
|
295
|
+
# _@return_ — The `IO` that is connected to this process's `stderr`.
|
|
296
|
+
sig { returns(IO) }
|
|
297
|
+
attr_reader :stderr
|
|
298
|
+
|
|
299
|
+
# _@return_ — The command this process was invoked with.
|
|
300
|
+
sig { returns(T::Array[String]) }
|
|
301
|
+
attr_reader :command
|
|
302
|
+
|
|
303
|
+
# _@return_ — The process ID of the spawned process.
|
|
304
|
+
sig { returns(Integer) }
|
|
305
|
+
attr_reader :pid
|
|
306
|
+
|
|
307
|
+
# _@return_ — The exit status code of the process.
|
|
308
|
+
# Only set after the process has exited.
|
|
309
|
+
sig { returns(T.nilable(::Process::Status)) }
|
|
310
|
+
attr_reader :status
|
|
311
|
+
end
|
|
312
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: subprocess
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.5.
|
|
4
|
+
version: 1.5.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carl Jackson
|
|
@@ -12,7 +12,7 @@ authors:
|
|
|
12
12
|
autorequire:
|
|
13
13
|
bindir: bin
|
|
14
14
|
cert_chain: []
|
|
15
|
-
date:
|
|
15
|
+
date: 2022-06-08 00:00:00.000000000 Z
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
18
|
name: minitest
|
|
@@ -56,6 +56,20 @@ dependencies:
|
|
|
56
56
|
- - ">="
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
58
|
version: '0'
|
|
59
|
+
- !ruby/object:Gem::Dependency
|
|
60
|
+
name: sord
|
|
61
|
+
requirement: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
type: :development
|
|
67
|
+
prerelease: false
|
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0'
|
|
59
73
|
description: Control and communicate with spawned processes
|
|
60
74
|
email:
|
|
61
75
|
- carl@stripe.com
|
|
@@ -70,6 +84,7 @@ files:
|
|
|
70
84
|
- README.md
|
|
71
85
|
- lib/subprocess.rb
|
|
72
86
|
- lib/subprocess/version.rb
|
|
87
|
+
- rbi/subprocess.rbi
|
|
73
88
|
homepage: https://github.com/stripe/subprocess
|
|
74
89
|
licenses:
|
|
75
90
|
- MIT
|