subprocess 1.5.3 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
- 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 ![Ruby](https://github.com/stripe/subprocess/workflows/Ruby/badge.svg) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/stripe/subprocess/Subprocess)
|
2
2
|
|
3
3
|
![Jacques Cousteau Submarine](http://i.imgur.com/lmej24F.jpg)
|
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
|