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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e16d4fb0220a00c09eba23fc3b5f43cf72facb831a8d70f8afb2e4c48507b964
4
- data.tar.gz: 6f852ef9c5fb2f0dafd6a153cc9045b5d37021f189e7da18d2ec137b7d9d3338
3
+ metadata.gz: c4f23739dbbe8891bbb0026f7fbf5bb6357cdcaf0c28bb2ea1a63626caa99c6f
4
+ data.tar.gz: 62c248b3cdd19972bd4bf53abc1d66bb7479c5f6281f5e84f56c9212b79bed4f
5
5
  SHA512:
6
- metadata.gz: 2f808a8bcdae021ab23ef31ad18df2c3d39b359f9b3752bc5924e143a00757359e64ff0586c617b1e8908cec1bb5e0f9b1076834edce27595e1733f76ddcdbc6
7
- data.tar.gz: 97bbb478f5c1ad1fabd55491784da44562d28d909be6f9c67586643f3e740fc1189e298cb2ea05a3ae46b0726a299f2d1cdba0307e19ffec31c83e3a41e7d049
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 cases
16
- due to exceeding `PIPE_BUF` limits on one or more streams.
17
- - **Uses Ruby under the hood** - It leverages Ruby's `Open3#popen3` and `Process.spawn`
18
- behind the scenes so it's widely supported and consistently getting performance updates.
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 Open3's `#popen3`.
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, wait_thr = Open3.popen3('bc')
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
- - Process::waitpid(pid)
159
- - $?
160
- + wait_thr.value
157
+ Process::waitpid(pid)
158
+ $?
161
159
  end
162
160
  end
163
161
  ```
@@ -1,5 +1,4 @@
1
- require "open3"
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, wait_thread = Open3.popen3(@env, *(@argv + [@options]))
153
- @pid = wait_thread[: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
- # wait_thr.value waits for the termination of the process and returns exit status
159
- @status = wait_thread.value
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 = wait_thread.value rescue nil
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
@@ -1,3 +1,3 @@
1
1
  module Progeny
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.1'
3
3
  end
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.0
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: 2023-05-03 00:00:00.000000000 Z
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.4.10
78
- signing_key:
77
+ rubygems_version: 3.0.3.1
78
+ signing_key:
79
79
  specification_version: 4
80
- summary: A popen3 wrapper with a nice interface and extra options.
80
+ summary: A process spawn wrapper with a nice interface and extra options.
81
81
  test_files: []