subprocess 1.2.0 → 1.3.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 +7 -0
- data/README.md +1 -2
- data/lib/subprocess.rb +16 -91
- data/lib/subprocess/version.rb +1 -1
- metadata +15 -23
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 82c898802f4160693d7836102254e37c303db198
|
4
|
+
data.tar.gz: 71481f1fe51f83f84be323b801674c6ae34c8723
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f3b32e75da714a7eb24ab94fa5486ed190c128b5e1e92fa8545a9797c93ff74cdef92f45a8d3e54b8d6fd653284d85d5640f6c89b926d23f9cfdd01786bbbdf3
|
7
|
+
data.tar.gz: d7d449f41f1d7c2a2201af471916bdac29696cea27058ada2454d91de7ac6543cb56715ae56393dc61b9e9c2c1a31c1fce01b7b76934d1f929909e23307324d1
|
data/README.md
CHANGED
data/lib/subprocess.rb
CHANGED
@@ -111,12 +111,9 @@ module Subprocess
|
|
111
111
|
if Signal.respond_to?(:signame)
|
112
112
|
# ruby 2.0 way
|
113
113
|
sig_name = Signal.signame(sig_num)
|
114
|
-
|
114
|
+
else
|
115
115
|
# ruby 1.9 way
|
116
116
|
sig_name = Signal.list.key(sig_num)
|
117
|
-
else
|
118
|
-
# ruby 1.8 way
|
119
|
-
sig_name = Signal.list.index(sig_num)
|
120
117
|
end
|
121
118
|
|
122
119
|
if sig_name
|
@@ -221,12 +218,11 @@ module Subprocess
|
|
221
218
|
# numbers that should not be closed before executing the child process.
|
222
219
|
# Note that, unlike Python (which has :close_fds defaulting to false), all
|
223
220
|
# file descriptors not specified here will be closed.
|
221
|
+
# @option opts [Hash] :exec_opts A hash that will be merged into the options
|
222
|
+
# hash of the call to {Kernel#exec}.
|
224
223
|
#
|
225
224
|
# @option opts [Proc] :preexec_fn A function that will be called in the
|
226
|
-
# child process immediately before executing `cmd`.
|
227
|
-
# actually close file descriptors, but instead set them to auto-close on
|
228
|
-
# `exec` (using `FD_CLOEXEC`), so your application will probably continue
|
229
|
-
# to behave as expected.
|
225
|
+
# child process immediately before executing `cmd`.
|
230
226
|
#
|
231
227
|
# @yield [process] Yields the just-spawned {Process} to the optional block.
|
232
228
|
# This occurs after all of {Process}'s error handling has been completed,
|
@@ -235,6 +231,7 @@ module Subprocess
|
|
235
231
|
# @yieldparam process [Process] The process that was just spawned.
|
236
232
|
def initialize(cmd, opts={}, &blk)
|
237
233
|
raise ArgumentError, "cmd must be an Array" unless Array === cmd
|
234
|
+
raise ArgumentError, "cmd cannot be empty" if cmd.empty?
|
238
235
|
|
239
236
|
@command = cmd
|
240
237
|
|
@@ -253,69 +250,8 @@ module Subprocess
|
|
253
250
|
|
254
251
|
@pid = fork do
|
255
252
|
begin
|
256
|
-
require 'fcntl'
|
257
|
-
|
258
253
|
FileUtils.cd(opts[:cwd]) if opts[:cwd]
|
259
254
|
|
260
|
-
# The only way to mark an fd as CLOEXEC in ruby is to create an IO
|
261
|
-
# object wrapping it. In 1.8, however, there's no way to create that
|
262
|
-
# IO without it believing it owns the underlying fd, s.t. it will
|
263
|
-
# close the fd if the IO is GC'd before the exec. Since we don't want
|
264
|
-
# that, we stash a list of these IO objects to prevent them from
|
265
|
-
# getting GC'd, since we are about to exec, which will clean
|
266
|
-
# everything up anyways.
|
267
|
-
fds = []
|
268
|
-
|
269
|
-
# We have a whole ton of file descriptors that we don't want leaking
|
270
|
-
# into the child. Set them all to close when we exec away.
|
271
|
-
#
|
272
|
-
# Ruby 1.9+ note: exec has a :close_others argument (and 2.0 closes
|
273
|
-
# FDs by default). When we stop supporting Ruby 1.8, all of this can
|
274
|
-
# go away.
|
275
|
-
if File.directory?("/dev/fd")
|
276
|
-
# On many modern UNIX-y systems, we can perform an optimization by
|
277
|
-
# looking through /dev/fd, which is a sparse listing of all the
|
278
|
-
# descriptors we have open. This allows us to avoid an expensive
|
279
|
-
# linear scan.
|
280
|
-
Dir.foreach("/dev/fd") do |file|
|
281
|
-
fd = file.to_i
|
282
|
-
if file.start_with?('.') || fd < 3 || retained_fds.include?(fd)
|
283
|
-
next
|
284
|
-
end
|
285
|
-
begin
|
286
|
-
fds << mark_fd_cloexec(fd)
|
287
|
-
rescue Errno::EBADF
|
288
|
-
# The fd might have been closed by now; that's peaceful.
|
289
|
-
end
|
290
|
-
end
|
291
|
-
else
|
292
|
-
# This is the big hammer. There's not really a good way of doing
|
293
|
-
# this comprehensively across all platforms without just trying them
|
294
|
-
# all. We only go up to the soft limit here. If you've been messing
|
295
|
-
# with the soft limit, we might miss a few. Also, on OSX (perhaps
|
296
|
-
# BSDs in general?), where the soft limit means something completely
|
297
|
-
# different.
|
298
|
-
special = [@child_stdin, @child_stdout, @child_stderr].compact
|
299
|
-
special = Hash[special.map { |f| [f.fileno, f] }]
|
300
|
-
3.upto(::Process.getrlimit(::Process::RLIMIT_NOFILE).first) do |fd|
|
301
|
-
next if retained_fds.include?(fd)
|
302
|
-
begin
|
303
|
-
# I don't know why we need to do this, but OSX started freaking
|
304
|
-
# out when trying to dup2 below if FD_CLOEXEC had been set on a
|
305
|
-
# fresh IO instance referring to the same underlying file
|
306
|
-
# descriptor as what we were trying to dup2 from.
|
307
|
-
if special[fd]
|
308
|
-
special[fd].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
309
|
-
else
|
310
|
-
fds << mark_fd_cloexec(fd)
|
311
|
-
end
|
312
|
-
rescue Errno::EBADF # Ignore FDs that don't exist
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
# dup2 the correct descriptors into place. Note that this clears the
|
318
|
-
# FD_CLOEXEC flag on the new file descriptors (but not the old ones).
|
319
255
|
::STDIN.reopen(@child_stdin) if @child_stdin
|
320
256
|
::STDOUT.reopen(@child_stdout) if @child_stdout
|
321
257
|
if opts[:stderr] == STDOUT
|
@@ -333,19 +269,18 @@ module Subprocess
|
|
333
269
|
# Call the user back, maybe?
|
334
270
|
opts[:preexec_fn].call if opts[:preexec_fn]
|
335
271
|
|
336
|
-
|
337
|
-
# you want to exec a single thing *without* performing shell
|
338
|
-
# expansion. So this is the next best thing.
|
339
|
-
args = cmd
|
340
|
-
if cmd.length == 1
|
341
|
-
args = ["'" + cmd[0].gsub("'", "\\'") + "'"]
|
342
|
-
end
|
272
|
+
options = {close_others: true}.merge(opts.fetch(:exec_opts, {}))
|
343
273
|
if opts[:retain_fds]
|
344
|
-
|
345
|
-
retained_fds.each { |fd| redirects[fd] = fd }
|
346
|
-
args << redirects
|
274
|
+
retained_fds.each { |fd| options[fd] = fd }
|
347
275
|
end
|
348
|
-
|
276
|
+
|
277
|
+
# Ruby's Kernel#exec will call an exec(3) variant if called with two
|
278
|
+
# or more arguments, but when called with just a single argument will
|
279
|
+
# spawn a subshell with that argument as the command. Since we always
|
280
|
+
# want to call exec(3), we use the third exec form, which passes a
|
281
|
+
# [cmdname, argv0] array as its first argument and never invokes a
|
282
|
+
# subshell.
|
283
|
+
exec([cmd[0], cmd[0]], *cmd[1..-1], options)
|
349
284
|
|
350
285
|
rescue Exception => e
|
351
286
|
# Dump all errors up to the parent through the control socket
|
@@ -366,7 +301,7 @@ module Subprocess
|
|
366
301
|
control_w.close
|
367
302
|
|
368
303
|
# Any errors during the spawn process? We'll get past this point when the
|
369
|
-
# child execs and the OS closes control_w
|
304
|
+
# child execs and the OS closes control_w
|
370
305
|
begin
|
371
306
|
e = Marshal.load(control_r)
|
372
307
|
e = "Unknown Failure" unless e.is_a?(Exception) || e.is_a?(String)
|
@@ -547,16 +482,6 @@ module Subprocess
|
|
547
482
|
end
|
548
483
|
end
|
549
484
|
|
550
|
-
def mark_fd_cloexec(fd)
|
551
|
-
io = IO.new(fd)
|
552
|
-
io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
553
|
-
io
|
554
|
-
rescue ArgumentError => e
|
555
|
-
# Ruby maintains a self-pipe for thread interrupts, but it handles closing
|
556
|
-
# it on forks/execs
|
557
|
-
raise unless e.message == "The given fd is not accessible because RubyVM reserves it"
|
558
|
-
end
|
559
|
-
|
560
485
|
@sigchld_mutex = Mutex.new
|
561
486
|
@sigchld_fds = {}
|
562
487
|
@sigchld_old_handler = nil
|
data/lib/subprocess/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subprocess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Carl Jackson
|
@@ -13,54 +12,48 @@ authors:
|
|
13
12
|
autorequire:
|
14
13
|
bindir: bin
|
15
14
|
cert_chain: []
|
16
|
-
date:
|
15
|
+
date: 2016-06-09 00:00:00.000000000 Z
|
17
16
|
dependencies:
|
18
17
|
- !ruby/object:Gem::Dependency
|
19
18
|
name: minitest
|
20
19
|
requirement: !ruby/object:Gem::Requirement
|
21
|
-
none: false
|
22
20
|
requirements:
|
23
|
-
- - ~>
|
21
|
+
- - "~>"
|
24
22
|
- !ruby/object:Gem::Version
|
25
23
|
version: '5.0'
|
26
24
|
type: :development
|
27
25
|
prerelease: false
|
28
26
|
version_requirements: !ruby/object:Gem::Requirement
|
29
|
-
none: false
|
30
27
|
requirements:
|
31
|
-
- - ~>
|
28
|
+
- - "~>"
|
32
29
|
- !ruby/object:Gem::Version
|
33
30
|
version: '5.0'
|
34
31
|
- !ruby/object:Gem::Dependency
|
35
32
|
name: rake
|
36
33
|
requirement: !ruby/object:Gem::Requirement
|
37
|
-
none: false
|
38
34
|
requirements:
|
39
|
-
- -
|
35
|
+
- - ">="
|
40
36
|
- !ruby/object:Gem::Version
|
41
37
|
version: '0'
|
42
38
|
type: :development
|
43
39
|
prerelease: false
|
44
40
|
version_requirements: !ruby/object:Gem::Requirement
|
45
|
-
none: false
|
46
41
|
requirements:
|
47
|
-
- -
|
42
|
+
- - ">="
|
48
43
|
- !ruby/object:Gem::Version
|
49
44
|
version: '0'
|
50
45
|
- !ruby/object:Gem::Dependency
|
51
46
|
name: pry
|
52
47
|
requirement: !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
48
|
requirements:
|
55
|
-
- -
|
49
|
+
- - ">="
|
56
50
|
- !ruby/object:Gem::Version
|
57
51
|
version: '0'
|
58
52
|
type: :development
|
59
53
|
prerelease: false
|
60
54
|
version_requirements: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
55
|
requirements:
|
63
|
-
- -
|
56
|
+
- - ">="
|
64
57
|
- !ruby/object:Gem::Version
|
65
58
|
version: '0'
|
66
59
|
description: Control and communicate with spawned processes
|
@@ -74,33 +67,32 @@ executables: []
|
|
74
67
|
extensions: []
|
75
68
|
extra_rdoc_files: []
|
76
69
|
files:
|
77
|
-
- lib/subprocess/version.rb
|
78
|
-
- lib/subprocess.rb
|
79
70
|
- README.md
|
71
|
+
- lib/subprocess.rb
|
72
|
+
- lib/subprocess/version.rb
|
80
73
|
homepage: https://github.com/stripe/subprocess
|
81
74
|
licenses:
|
82
75
|
- MIT
|
76
|
+
metadata: {}
|
83
77
|
post_install_message:
|
84
78
|
rdoc_options: []
|
85
79
|
require_paths:
|
86
80
|
- lib
|
87
81
|
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
82
|
requirements:
|
90
|
-
- -
|
83
|
+
- - ">="
|
91
84
|
- !ruby/object:Gem::Version
|
92
85
|
version: '0'
|
93
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
-
none: false
|
95
87
|
requirements:
|
96
|
-
- -
|
88
|
+
- - ">="
|
97
89
|
- !ruby/object:Gem::Version
|
98
90
|
version: '0'
|
99
91
|
requirements: []
|
100
92
|
rubyforge_project:
|
101
|
-
rubygems_version:
|
93
|
+
rubygems_version: 2.2.2
|
102
94
|
signing_key:
|
103
|
-
specification_version:
|
95
|
+
specification_version: 4
|
104
96
|
summary: A port of Python's subprocess module to Ruby
|
105
97
|
test_files: []
|
106
98
|
has_rdoc:
|