process_executer 1.0.0 → 1.1.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 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: []