process_executer 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec0548ff8356b9466db5fe9c9992e134010c9842561e1b0c0b95a5418fb2c2d2
4
- data.tar.gz: 7b9ead3538f7117b453a5353ad0a1ed352b7c60fa86fbacaa12081ff32b411cb
3
+ metadata.gz: f568a98075e32879207b26949346e4181eed2d2432c9665e84ddb015d5ded96c
4
+ data.tar.gz: bcc6f74e77155a251d4ad561495f6edb1b6cf95bccc23b7de7322a0897d4a0af
5
5
  SHA512:
6
- metadata.gz: a35f9cd143bf7236efbb107a8de130784c195bedb83e95262cc26ae7e2b7e586b7230bdf1ad680c508a5dd8b2c3398c89290ad01a1e5914e165179c298bf5b11
7
- data.tar.gz: 5dabb78fd2151f587078b3a139974eb390e23e86be961ce93a7d4f65dd161007e8a175b36b208d13939d38cd5dab41f0a446e7d5213aee34c7f07273c4804f49
6
+ metadata.gz: 0fc886fade1e486d6acb6c32864a469a6d77700c596dd15a47c4e59e440bfda06b3a1ca506fc4a9be8f7d3bea831525329e735d9cb30d5c01d48395571f9164c
7
+ data.tar.gz: cab6c4b4d5d1761ac46df3aff8c02c44fed93d071bc6c74fdba802c04175321520c92556c8a43fe79bf3f56d9fb80b82e1b7b60ff50c1bdea8fdcf94bb2e22fd
data/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ All notable changes to the process_executer gem will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## v1.1.0 (2024-02-02)
9
+
10
+ [Full Changelog](https://github.com/main-branch/process_executer/compare/v1.0.2..v1.1.0)
11
+
12
+ Changes since v1.0.2:
13
+
14
+ * a473281 ProcessExecuter.spawn should indicate if the subprocess timed out or not (#43)
15
+
16
+ ## v1.0.2 (2024-02-01)
17
+
18
+ [Full Changelog](https://github.com/main-branch/process_executer/compare/v1.0.1..v1.0.2)
19
+
20
+ Changes since v1.0.1:
21
+
22
+ * 76ffb91 An invalid timeout value should raise an ArgumentError (#41)
23
+ * b748819 Release v1.0.1 (#40)
24
+
25
+ ## v1.0.1 (2024-01-04)
26
+
27
+ [Full Changelog](https://github.com/main-branch/process_executer/compare/v1.0.0..v1.0.1)
28
+
29
+ Changes since v1.0.0:
30
+
31
+ * f434aa1 Add an experimental build for jruby-head on windows (#15)
32
+ * 97dbcf5 Make updates resulting from doc review (#38)
33
+ * 93eab18 Release v1.0.0 (#37)
34
+
8
35
  ## v1.0.0 (2023-12-31)
9
36
 
10
37
  [Full Changelog](https://github.com/main-branch/process_executer/compare/v0.7.0..v1.0.0)
data/README.md CHANGED
@@ -77,7 +77,15 @@ important behaviorial differences:
77
77
  2. A timeout can be specified using the `:timeout` option
78
78
 
79
79
  If the command does not terminate before the timeout, the process is killed by
80
- sending it the SIGKILL signal.
80
+ sending it the SIGKILL signal. The returned status object's `timeout?` attribute will
81
+ return `true`. For example:
82
+
83
+ ```ruby
84
+ status = ProcessExecuter.spawn('sleep 10', timeout: 0.01)
85
+ status.signaled? #=> true
86
+ status.termsig #=> 9
87
+ status.timeout? #=> true
88
+ ```
81
89
 
82
90
  ## Installation
83
91
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'forwardable'
4
4
  require 'ostruct'
5
+ require 'pp'
5
6
 
6
7
  module ProcessExecuter
7
8
  # Validate ProcessExecuter::Executer#spawn options and return Process.spawn options
@@ -27,13 +28,14 @@ module ProcessExecuter
27
28
  close_others chdir
28
29
  ].freeze
29
30
 
30
- # These options are allowed but should NOT be passed to `Process.spawn`
31
+ # These options are allowed by `ProcessExecuter.spawn` but should NOT be passed
32
+ # to `Process.spawn`
31
33
  #
32
34
  NON_SPAWN_OPTIONS = %i[
33
35
  timeout
34
36
  ].freeze
35
37
 
36
- # Any `SPAWN_OPTIONS`` set to this value will not be passed to `Process.spawn`
38
+ # Any `SPAWN_OPTIONS` set to `NOT_SET` will not be passed to `Process.spawn`
37
39
  #
38
40
  NOT_SET = :not_set
39
41
 
@@ -76,7 +78,7 @@ module ProcessExecuter
76
78
  # @param options [Hash] Process.spawn options plus additional options listed below.
77
79
  #
78
80
  # See [Process.spawn](https://ruby-doc.org/core/Process.html#method-c-spawn)
79
- # for a list of valid.
81
+ # for a list of valid options that can be passed to `Process.spawn`.
80
82
  #
81
83
  # @option options [Integer, Float, nil] :timeout
82
84
  # Number of seconds to wait for the process to terminate. Any number
@@ -86,6 +88,7 @@ module ProcessExecuter
86
88
  def initialize(**options)
87
89
  assert_no_unknown_options(options)
88
90
  @options = DEFAULTS.merge(options)
91
+ assert_timeout_is_valid
89
92
  end
90
93
 
91
94
  # Returns the options to be passed to Process.spawn
@@ -129,6 +132,24 @@ module ProcessExecuter
129
132
  raise ArgumentError, "Unknown options: #{unknown_options.join(', ')}" unless unknown_options.empty?
130
133
  end
131
134
 
135
+ # Raise an error if timeout is not a real non-negative number
136
+ # @return [void]
137
+ # @raise [ArgumentError] if timeout is not a real non-negative number
138
+ # @api private
139
+ def assert_timeout_is_valid
140
+ return if @options[:timeout].nil?
141
+ return if @options[:timeout].is_a?(Numeric) && @options[:timeout].real? && !@options[:timeout].negative?
142
+
143
+ raise ArgumentError, invalid_timeout_message
144
+ end
145
+
146
+ # The message to be used when raising an error for an invalid timeout
147
+ # @return [String]
148
+ # @api private
149
+ def invalid_timeout_message
150
+ "timeout must be nil or a real non-negative number but was #{options[:timeout].pretty_inspect}"
151
+ end
152
+
132
153
  # Determine if the given option is a valid option
133
154
  # @param option [Symbol] the option to be tested
134
155
  # @return [Boolean] true if the given option is a valid option
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module ProcessExecuter
6
+ # A simple delegator for Process::Status that adds a `timeout?` attribute
7
+ #
8
+ # @api public
9
+ #
10
+ class Status < SimpleDelegator
11
+ extend Forwardable
12
+
13
+ # Create a new Status object from a Process::Status and timeout flag
14
+ #
15
+ # @param status [Process::Status] the status to delegate to
16
+ # @param timeout [Boolean] true if the process timed out
17
+ #
18
+ # @example
19
+ # status = Process.wait2(pid).last
20
+ # timeout = false
21
+ # ProcessExecuter::Status.new(status, timeout)
22
+ #
23
+ # @api public
24
+ #
25
+ def initialize(status, timeout)
26
+ super(status)
27
+ @timeout = timeout
28
+ end
29
+
30
+ # @!attribute [r] timeout?
31
+ #
32
+ # True if the process timed out and was sent the SIGKILL signal
33
+ #
34
+ # @example
35
+ # status = ProcessExecuter.spawn('sleep 10', timeout: 0.01)
36
+ # status.timeout? # => true
37
+ #
38
+ # @return [Boolean]
39
+ #
40
+ # @api public
41
+ #
42
+ def timeout? = @timeout
43
+ end
44
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ProcessExecuter
4
4
  # The current Gem version
5
- VERSION = '1.0.0'
5
+ VERSION = '1.1.0'
6
6
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'process_executer/monitored_pipe'
4
4
  require 'process_executer/options'
5
+ require 'process_executer/status'
5
6
 
6
7
  require 'timeout'
7
8
 
@@ -12,7 +13,8 @@ require 'timeout'
12
13
  module ProcessExecuter
13
14
  # Execute the specified command as a subprocess and return the exit status
14
15
  #
15
- # This method blocks until the command has terminated.
16
+ # This is a convenience method that calls Process.spawn and blocks until the
17
+ # command has terminated.
16
18
  #
17
19
  # The command will be send the SIGKILL signal if it does not terminate within
18
20
  # the specified timeout.
@@ -38,7 +40,7 @@ module ProcessExecuter
38
40
  # documentation for valid command and options
39
41
  #
40
42
  # @see ProcessExecuter::Options#initialize See ProcessExecuter::Options#initialize
41
- # for additional options that may be specified
43
+ # for options that may be specified
42
44
  #
43
45
  # @param command [Array<String>] the command to execute
44
46
  # @param options_hash [Hash] the options to use when exectuting the command
@@ -58,16 +60,16 @@ module ProcessExecuter
58
60
  # @param pid [Integer] the process id
59
61
  # @param options [ProcessExecuter::Options] the options used
60
62
  #
61
- # @return [Process::Status] the status of the process
63
+ # @return [ProcessExecuter::Status] the status of the process
62
64
  #
63
65
  # @api private
64
66
  #
65
67
  private_class_method def self.wait_for_process(pid, options)
66
68
  Timeout.timeout(options.timeout) do
67
- Process.wait2(pid).last
69
+ ProcessExecuter::Status.new(Process.wait2(pid).last, false)
68
70
  end
69
71
  rescue Timeout::Error
70
72
  Process.kill('KILL', pid)
71
- Process.wait2(pid).last
73
+ ProcessExecuter::Status.new(Process.wait2(pid).last, true)
72
74
  end
73
75
  end
@@ -18,7 +18,8 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.metadata['homepage_uri'] = spec.homepage
20
20
  spec.metadata['source_code_uri'] = 'https://github.com/main-branch/process_executer'
21
- spec.metadata['changelog_uri'] = 'https://rubydoc.info/gems/process_executer/file/CHANGELOG.md'
21
+ spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md"
22
+ spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}"
22
23
 
23
24
  # Specify which files should be added to the gem when it is released.
24
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_executer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Couball
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-31 00:00:00.000000000 Z
11
+ date: 2024-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler-audit
@@ -190,6 +190,7 @@ files:
190
190
  - lib/process_executer.rb
191
191
  - lib/process_executer/monitored_pipe.rb
192
192
  - lib/process_executer/options.rb
193
+ - lib/process_executer/status.rb
193
194
  - lib/process_executer/version.rb
194
195
  - process_executer.gemspec
195
196
  homepage: https://github.com/main-branch/process_executer
@@ -199,7 +200,8 @@ metadata:
199
200
  allowed_push_host: https://rubygems.org
200
201
  homepage_uri: https://github.com/main-branch/process_executer
201
202
  source_code_uri: https://github.com/main-branch/process_executer
202
- changelog_uri: https://rubydoc.info/gems/process_executer/file/CHANGELOG.md
203
+ changelog_uri: https://rubydoc.info/gems/process_executer/1.1.0/file/CHANGELOG.md
204
+ documentation_uri: https://rubydoc.info/gems/process_executer/1.1.0
203
205
  rubygems_mfa_required: 'true'
204
206
  post_install_message:
205
207
  rdoc_options: []