progeny 0.1.0 → 0.2.1
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/CHANGELOG.md +12 -0
- data/README.md +9 -11
- data/lib/progeny/command.rb +50 -8
- data/lib/progeny/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4f23739dbbe8891bbb0026f7fbf5bb6357cdcaf0c28bb2ea1a63626caa99c6f
|
4
|
+
data.tar.gz: 62c248b3cdd19972bd4bf53abc1d66bb7479c5f6281f5e84f56c9212b79bed4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 663f90dca5e05f44a85c861191038bc4b4f4fa5f8306da00ebf2466db2423ac4ab12928cc30d00f855b06bb661c216ba173e09eb8d25fcc7b234da2dfd81df0e
|
7
|
+
data.tar.gz: 0e3320602a1555c41567d21c07947b7ad860ba1156659c3ebd5c2bdddb4108f43ad5400fc5cebefe0e7e8a47619ebc5fea0460b89be13258d1ce5bd25970c981
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.1] - 2024-05-16
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
|
7
|
+
- Use `frozen_string_literal`.
|
8
|
+
|
9
|
+
## [0.2.0] - 2023-05-05
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- `Progeny::Command#spawn_with_pipes` for easier migration from `posix-spawn`.
|
14
|
+
|
3
15
|
## [0.1.0] - 2023-05-03
|
4
16
|
|
5
17
|
- Initial release. Forked `posix-spawn` gem.
|
data/README.md
CHANGED
@@ -12,10 +12,11 @@ strings and is therefore not well-suited to streaming large quantities of data
|
|
12
12
|
in and out of commands. That said, it has some benefits:
|
13
13
|
|
14
14
|
- **Simple** - requires little code for simple stream input and capture.
|
15
|
-
- **Internally non-blocking** (using `select(2)`) - handles all pipe hang
|
16
|
-
due to exceeding `PIPE_BUF` limits on one or more streams.
|
17
|
-
- **Uses Ruby under the hood** - It leverages Ruby's `
|
18
|
-
|
15
|
+
- **Internally non-blocking** (using `select(2)`) - handles all pipe hang
|
16
|
+
cases due to exceeding `PIPE_BUF` limits on one or more streams.
|
17
|
+
- **Uses Ruby under the hood** - It leverages Ruby's `Process.spawn` behind
|
18
|
+
the scenes so it's widely supported and consistently getting performance
|
19
|
+
updates.
|
19
20
|
|
20
21
|
`Progeny::Command` takes the [standard `Process::spawn`
|
21
22
|
arguments](https://ruby-doc.org/current/Process.html#method-c-spawn) when
|
@@ -132,10 +133,9 @@ end
|
|
132
133
|
```
|
133
134
|
|
134
135
|
You will need to remove the include statements and replace any use of `#spawn`
|
135
|
-
with Ruby's native `Process.spawn` and `#popen4` with
|
136
|
+
with Ruby's native `Process.spawn` and `#popen4` with `Progeny::Command.spawn_with_pipes`
|
136
137
|
```diff
|
137
138
|
- require 'posix/spawn'
|
138
|
-
+ require 'open3'
|
139
139
|
|
140
140
|
class YourSpawnerClass
|
141
141
|
- include POSIX::Spawn
|
@@ -148,16 +148,14 @@ class YourSpawnerClass
|
|
148
148
|
|
149
149
|
def calculate(expression)
|
150
150
|
- pid, in, out, err = popen4('bc')
|
151
|
-
+ in, out, err
|
152
|
-
+ pid = wait_thr[:pid] # if pid is needed
|
151
|
+
+ pid, in, out, err = Progeny::Command.spawn_with_pipes('bc')
|
153
152
|
in.write(expression)
|
154
153
|
in.close
|
155
154
|
out.read
|
156
155
|
ensure
|
157
156
|
[in, out, err].each { |io| io.close if !io.closed? }
|
158
|
-
|
159
|
-
|
160
|
-
+ wait_thr.value
|
157
|
+
Process::waitpid(pid)
|
158
|
+
$?
|
161
159
|
end
|
162
160
|
end
|
163
161
|
```
|
data/lib/progeny/command.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
module Progeny
|
4
3
|
# Progeny::Command includes logic for executing child processes and
|
5
4
|
# reading/writing from their standard input, output, and error streams. It's
|
@@ -123,6 +122,41 @@ module Progeny
|
|
123
122
|
new(*(args + [{ :noexec => true }.merge(options)]))
|
124
123
|
end
|
125
124
|
|
125
|
+
# Spawn a child process with all standard IO streams piped in and out of
|
126
|
+
# the spawning process. Supports the standard `Process.spawn` interface.
|
127
|
+
#
|
128
|
+
# Returns a [pid, stdin, stdout, stderr] tuple, where pid is the new
|
129
|
+
# process's pid, stdin is a writeable IO object, and stdout / stderr are
|
130
|
+
# readable IO objects. The caller should take care to close all IO objects
|
131
|
+
# when finished and the child process's status must be collected by a call
|
132
|
+
# to Process::waitpid or equivalent.
|
133
|
+
def self.spawn_with_pipes(*argv)
|
134
|
+
if argv.last.is_a?(Hash)
|
135
|
+
opts = argv.pop.dup
|
136
|
+
else
|
137
|
+
opts = {}
|
138
|
+
end
|
139
|
+
|
140
|
+
ird, iwr = IO.pipe
|
141
|
+
ord, owr = IO.pipe
|
142
|
+
erd, ewr = IO.pipe
|
143
|
+
|
144
|
+
opts = opts.merge(
|
145
|
+
# redirect fds # close other sides
|
146
|
+
:in => ird, iwr => :close,
|
147
|
+
:out => owr, ord => :close,
|
148
|
+
:err => ewr, erd => :close
|
149
|
+
)
|
150
|
+
pid = spawn(*(argv + [opts]))
|
151
|
+
[pid, iwr, ord, erd]
|
152
|
+
ensure
|
153
|
+
# we're in the parent, close child-side fds
|
154
|
+
[ird, owr, ewr].each { |fd| fd.close if fd }
|
155
|
+
end
|
156
|
+
|
157
|
+
# All data written to the child process's stdin stream as a String.
|
158
|
+
attr_reader :input
|
159
|
+
|
126
160
|
# All data written to the child process's stdout stream as a String.
|
127
161
|
attr_reader :out
|
128
162
|
|
@@ -149,14 +183,14 @@ module Progeny
|
|
149
183
|
# immediately when a new instance of this object is created, or
|
150
184
|
# can be called explicitly when creating the Command via `build`.
|
151
185
|
def exec!
|
152
|
-
stdin, stdout, stderr
|
153
|
-
@pid =
|
186
|
+
pid, stdin, stdout, stderr = self.class.spawn_with_pipes(@env, *@argv, @options)
|
187
|
+
@pid = pid
|
154
188
|
|
155
189
|
# async read from all streams into buffers
|
156
190
|
read_and_write(@input, stdin, stdout, stderr, @timeout, @max)
|
157
191
|
|
158
|
-
#
|
159
|
-
@status =
|
192
|
+
# wait for the termination of the process and return exit status
|
193
|
+
@status = waitpid(pid)
|
160
194
|
rescue Object
|
161
195
|
[stdin, stdout, stderr].each { |fd| fd.close rescue nil }
|
162
196
|
if @status.nil?
|
@@ -165,7 +199,7 @@ module Progeny
|
|
165
199
|
else
|
166
200
|
::Process.kill('-TERM', pid) rescue nil
|
167
201
|
end
|
168
|
-
@status =
|
202
|
+
@status = waitpid(pid) rescue nil
|
169
203
|
end
|
170
204
|
raise
|
171
205
|
ensure
|
@@ -195,7 +229,7 @@ module Progeny
|
|
195
229
|
# exceeds the amount specified by the max argument.
|
196
230
|
def read_and_write(input, stdin, stdout, stderr, timeout=nil, max=nil)
|
197
231
|
max = nil if max && max <= 0
|
198
|
-
@out, @err = '', ''
|
232
|
+
@out, @err = +'', +''
|
199
233
|
|
200
234
|
# force all string and IO encodings to BINARY under 1.9 for now
|
201
235
|
if @out.respond_to?(:force_encoding) and stdin.respond_to?(:set_encoding)
|
@@ -268,5 +302,13 @@ module Progeny
|
|
268
302
|
|
269
303
|
[@out, @err]
|
270
304
|
end
|
305
|
+
|
306
|
+
# Wait for the child process to exit
|
307
|
+
#
|
308
|
+
# Returns the Process::Status object obtained by reaping the process.
|
309
|
+
def waitpid(pid)
|
310
|
+
Process::waitpid(pid)
|
311
|
+
$?
|
312
|
+
end
|
271
313
|
end
|
272
314
|
end
|
data/lib/progeny/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: progeny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luan Vieira
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -59,7 +59,7 @@ metadata:
|
|
59
59
|
homepage_uri: https://github.com/luanzeba/progeny
|
60
60
|
source_code_uri: https://github.com/luanzeba/progeny
|
61
61
|
changelog_uri: https://github.com/luanzeba/progeny/blob/main/CHANGELOG.md
|
62
|
-
post_install_message:
|
62
|
+
post_install_message:
|
63
63
|
rdoc_options: []
|
64
64
|
require_paths:
|
65
65
|
- lib
|
@@ -74,8 +74,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
requirements: []
|
77
|
-
rubygems_version: 3.
|
78
|
-
signing_key:
|
77
|
+
rubygems_version: 3.0.3.1
|
78
|
+
signing_key:
|
79
79
|
specification_version: 4
|
80
|
-
summary: A
|
80
|
+
summary: A process spawn wrapper with a nice interface and extra options.
|
81
81
|
test_files: []
|