sproc 0.2.0 → 0.6.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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/sproc.rb +1 -0
- data/lib/sproc/core.rb +89 -63
- data/lib/sproc/osinfo.rb +55 -0
- data/lib/sproc/reporting.rb +196 -0
- data/lib/sproc/version.rb +1 -1
- data/sproc.gemspec +18 -17
- metadata +7 -5
- data/lib/sproc/utils.rb +0 -53
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a736ea3eebf9855455803021aa1dd57589e1784f92f841f63984d64c1bb5cce2
|
|
4
|
+
data.tar.gz: 0ead0dc9e4609cb8adc976dd743f427bbe9d8ee9be39d78b6ab743804b0c13d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee15b0602c7b22c813a47aca5c0c3a824624ad0794145aaa9382763e6f6ce54eaf5418fe0df9b2974c7c1945609c74d8f6f32630bc987e10eaa5bed137a8fffb
|
|
7
|
+
data.tar.gz: ac59da1176212f4d34b9100ba6353bb81923a059fbd7229c91622386e320e1a96514319deacf920ad3b0347796e6adf15f856422d987fb63bdd29935e2fb9dc3
|
data/Gemfile.lock
CHANGED
data/lib/sproc.rb
CHANGED
data/lib/sproc/core.rb
CHANGED
|
@@ -7,17 +7,16 @@ module SProc
|
|
|
7
7
|
# Defines the shell under which to invoke the sub-process
|
|
8
8
|
module ShellType
|
|
9
9
|
SHELL_TYPES = [
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
# - For current ubuntu, it seems to be 'dash'
|
|
13
|
-
NATIVE = 0,
|
|
10
|
+
# Start the process without any shell
|
|
11
|
+
NONE = 0,
|
|
14
12
|
# Will create a 'bash' instance and run the subprocess
|
|
15
13
|
# within that instance.
|
|
16
14
|
BASH = 1
|
|
17
15
|
].freeze
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
# The
|
|
18
|
+
# The available execution states of a the subprocess
|
|
19
|
+
# running within an SProc instance.
|
|
21
20
|
module ExecutionState
|
|
22
21
|
NOT_STARTED = 0
|
|
23
22
|
RUNNING = 1
|
|
@@ -58,10 +57,13 @@ module SProc
|
|
|
58
57
|
# from the process as it is running (default nil)
|
|
59
58
|
# @param stderr_callback a callback that will receive all stderr output
|
|
60
59
|
# from the process as it is running (default nil)
|
|
60
|
+
# @param env a hash containing key/value pairs of strings that
|
|
61
|
+
# set the environment variable 'key' to 'value'. If value
|
|
62
|
+
# is nil, that env variable is unset
|
|
61
63
|
#
|
|
62
64
|
# example callback signature: def my_stdout_cb(line)
|
|
63
|
-
def initialize(type
|
|
64
|
-
stderr_callback
|
|
65
|
+
def initialize(type: ShellType::NONE, stdout_callback: nil,
|
|
66
|
+
stderr_callback: nil, env: {})
|
|
65
67
|
@run_opts = {
|
|
66
68
|
type: type,
|
|
67
69
|
stdout_callback: stdout_callback,
|
|
@@ -69,10 +71,50 @@ module SProc
|
|
|
69
71
|
}
|
|
70
72
|
@runner = TaskRunner.new(@run_opts)
|
|
71
73
|
@execution_thread = nil
|
|
74
|
+
@env = env
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Start the sub-process and block until it has completed.
|
|
78
|
+
#
|
|
79
|
+
#
|
|
80
|
+
# @cmd the command to execute
|
|
81
|
+
# @args an array with all arguments to the cmd
|
|
82
|
+
# @opts a hash with options that influence the spawned process
|
|
83
|
+
# the supported options are: chdir umask unsetenv_others
|
|
84
|
+
# See Process.spawn for definitions
|
|
85
|
+
#
|
|
86
|
+
# @return this SubProcess instance
|
|
87
|
+
def exec_sync(cmd, *args, **opts)
|
|
88
|
+
exec(true, @env, cmd, *args, **opts)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Start the process non-blocking. Use one of the wait... methods
|
|
92
|
+
# to later block on the process.
|
|
93
|
+
# @return this SubProcess instance
|
|
94
|
+
def exec_async(cmd, *args, **opts)
|
|
95
|
+
exec(false, @env, cmd, *args, **opts)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# check if this process has completed with exit code 0
|
|
99
|
+
# (success) or not
|
|
100
|
+
def exit_zero?
|
|
101
|
+
return false unless execution_state == ExecutionState::COMPLETED
|
|
102
|
+
|
|
103
|
+
task_info[:process_status].exitstatus.zero?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Block caller until this subprocess has completed or aborted
|
|
107
|
+
# @return the TaskInfo struct of the completed process
|
|
108
|
+
def wait_on_completion
|
|
109
|
+
return if @execution_thread.nil?
|
|
110
|
+
|
|
111
|
+
@execution_thread.join
|
|
112
|
+
task_info
|
|
72
113
|
end
|
|
73
114
|
|
|
74
115
|
# Return the execution state of this SubProcess. Note that it is not
|
|
75
116
|
# identical with the life-cycle of the underlying ProcessStatus object
|
|
117
|
+
#
|
|
76
118
|
# @return current ExecutionState
|
|
77
119
|
def execution_state
|
|
78
120
|
return ExecutionState::NOT_STARTED if @execution_thread.nil?
|
|
@@ -106,35 +148,10 @@ module SProc
|
|
|
106
148
|
raise RuntimeError("Unhandled process status: #{status.inspect}")
|
|
107
149
|
end
|
|
108
150
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
exec(true, cmd, *args, **opts)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Start the process non-blocking. Use one of the wait... methods
|
|
117
|
-
# to later block on the process.
|
|
118
|
-
# @return this SubProcess instance
|
|
119
|
-
def exec_async(cmd, *args, **opts)
|
|
120
|
-
exec(false, cmd, *args, **opts)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# check if this process has completed with exit code 0
|
|
124
|
-
# (success) or not
|
|
125
|
-
def exit_zero?
|
|
126
|
-
return false unless execution_state == ExecutionState::COMPLETED
|
|
127
|
-
|
|
128
|
-
task_info[:process_status].exitstatus.zero?
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Block caller until this subprocess has completed or aborted
|
|
132
|
-
# @return the TaskInfo struct of the completed process
|
|
133
|
-
def wait_on_completion
|
|
134
|
-
return if @execution_thread.nil?
|
|
135
|
-
|
|
136
|
-
@execution_thread.join
|
|
137
|
-
task_info
|
|
151
|
+
# @return the TaskInfo representing this SubProcess, nil if
|
|
152
|
+
# process has not started
|
|
153
|
+
def task_info
|
|
154
|
+
@runner.task_info
|
|
138
155
|
end
|
|
139
156
|
|
|
140
157
|
# blocks until all processes in the given array are completed/aborted.
|
|
@@ -170,7 +187,7 @@ module SProc
|
|
|
170
187
|
# # start 3 processes asyncronously
|
|
171
188
|
# nof_processes = 3
|
|
172
189
|
# p_array = (1..nof_processes).collect do
|
|
173
|
-
# SubProcess.new(SubProcess::
|
|
190
|
+
# SubProcess.new(SubProcess::NONE).exec_async('ping', ['127.0.0.1'])
|
|
174
191
|
# end
|
|
175
192
|
#
|
|
176
193
|
# # block until a process completes and then immediately start a new process
|
|
@@ -201,12 +218,6 @@ module SProc
|
|
|
201
218
|
all_proc
|
|
202
219
|
end
|
|
203
220
|
|
|
204
|
-
# @return the TaskInfo representing this SubProcess, nil if
|
|
205
|
-
# process has not started
|
|
206
|
-
def task_info
|
|
207
|
-
@runner.task_info
|
|
208
|
-
end
|
|
209
|
-
|
|
210
221
|
# return processes that are no longer running
|
|
211
222
|
def self.get_finished(running_proc)
|
|
212
223
|
running_proc.select do |p|
|
|
@@ -218,13 +229,15 @@ module SProc
|
|
|
218
229
|
|
|
219
230
|
private
|
|
220
231
|
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
# a helper method that supports both synch/async execution
|
|
233
|
+
# depending on the supplied args
|
|
234
|
+
def exec(synch, env, cmd, *args, **opts)
|
|
235
|
+
raise 'Subprocess already running!' unless @execution_thread.nil? || !@execution_thread.alive?
|
|
223
236
|
|
|
224
237
|
# kick-off a fresh task runner and execution thread
|
|
225
238
|
@runner = TaskRunner.new(@run_opts)
|
|
226
239
|
@execution_thread = Thread.new do
|
|
227
|
-
@runner.execute(cmd, *args, **opts)
|
|
240
|
+
@runner.execute(env, cmd, *args, **opts)
|
|
228
241
|
end
|
|
229
242
|
@execution_thread.join if synch
|
|
230
243
|
self
|
|
@@ -238,8 +251,11 @@ module SProc
|
|
|
238
251
|
|
|
239
252
|
include ShellType
|
|
240
253
|
|
|
254
|
+
# Restrict the options to Process.spawn that we support to these
|
|
255
|
+
SUPPORTED_SPAWN_OPTS = %i[chdir umask unsetenv_others]
|
|
256
|
+
|
|
241
257
|
DEFAULT_OPTS = {
|
|
242
|
-
type:
|
|
258
|
+
type: NONE,
|
|
243
259
|
stdout_callback: nil,
|
|
244
260
|
stderr_callback: nil
|
|
245
261
|
}.freeze
|
|
@@ -250,12 +266,12 @@ module SProc
|
|
|
250
266
|
end
|
|
251
267
|
|
|
252
268
|
# Runs the process and blocks until it is completed or aborted.
|
|
253
|
-
# The stdout and stdin streams are continuously read in
|
|
269
|
+
# The stdout and stdin streams are continuously read in parallel with
|
|
254
270
|
# the process execution.
|
|
255
|
-
def execute(cmd, *args, **opts)
|
|
271
|
+
def execute(env, cmd, *args, **opts)
|
|
256
272
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
257
273
|
begin
|
|
258
|
-
shell_out_via_popen(cmd, *args, **opts)
|
|
274
|
+
shell_out_via_popen(env, cmd, *args, **opts)
|
|
259
275
|
rescue StandardError => e
|
|
260
276
|
@task_info[:exception] = e
|
|
261
277
|
end
|
|
@@ -266,14 +282,26 @@ module SProc
|
|
|
266
282
|
|
|
267
283
|
private
|
|
268
284
|
|
|
269
|
-
def
|
|
285
|
+
def valid_opts(**opts)
|
|
286
|
+
return opts if opts.nil? || opts.empty?
|
|
287
|
+
|
|
288
|
+
supported = {}
|
|
289
|
+
SUPPORTED_SPAWN_OPTS.each { |o| supported[o] = opts[o] if opts.has_key?(o) }
|
|
290
|
+
supported
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def shell_out_via_popen(env, cmd, *args, **opts)
|
|
294
|
+
opts = valid_opts(**opts)
|
|
270
295
|
args = case @opts[:type]
|
|
271
|
-
when
|
|
272
|
-
when BASH
|
|
296
|
+
when NONE then get_args_native(cmd, *args, **opts)
|
|
297
|
+
when BASH then get_args_bash(cmd, *args, **opts)
|
|
273
298
|
else raise ArgumentError, "Unknown task type: #{@type}!!"
|
|
274
299
|
end
|
|
300
|
+
|
|
275
301
|
SProc.logger&.debug { "Start: #{task_info[:cmd_str]}" }
|
|
276
|
-
|
|
302
|
+
SProc.logger&.debug { "Supplying env: #{env}" } unless env.nil?
|
|
303
|
+
SProc.logger&.debug { "Spawn options: #{opts}" } unless opts.nil?
|
|
304
|
+
Open3.popen3(env, *args) do |stdin, stdout, stderr, thread|
|
|
277
305
|
@task_info[:popen_thread] = thread
|
|
278
306
|
threads = do_while_process_running(stdin, stdout, stderr)
|
|
279
307
|
@task_info[:process_status] = thread.value
|
|
@@ -306,16 +334,14 @@ module SProc
|
|
|
306
334
|
def process_output_stream(stream, stream_cache = nil,
|
|
307
335
|
process_callback = nil)
|
|
308
336
|
Thread.new do
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
stream_cache << raw_line unless stream_cache.nil?
|
|
313
|
-
end
|
|
314
|
-
rescue IOError => e
|
|
315
|
-
l = SProc.logger
|
|
316
|
-
l&.warn { 'Stream closed before all output were read!' }
|
|
317
|
-
l&.warn { e.message }
|
|
337
|
+
until (raw_line = stream.gets).nil?
|
|
338
|
+
process_callback&.call(raw_line)
|
|
339
|
+
stream_cache << raw_line unless stream_cache.nil?
|
|
318
340
|
end
|
|
341
|
+
rescue IOError => e
|
|
342
|
+
l = SProc.logger
|
|
343
|
+
l&.warn { 'Stream closed before all output were read!' }
|
|
344
|
+
l&.warn { e.message }
|
|
319
345
|
end
|
|
320
346
|
end
|
|
321
347
|
end
|
data/lib/sproc/osinfo.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'rbconfig'
|
|
2
|
+
|
|
3
|
+
# helper methods to find out os and execution environment
|
|
4
|
+
module SProc
|
|
5
|
+
module OSInfo
|
|
6
|
+
# the supported exec environments
|
|
7
|
+
module OS
|
|
8
|
+
WINDOWS = 0
|
|
9
|
+
LINUX = 1
|
|
10
|
+
MINGW = 2
|
|
11
|
+
CYGWIN = 3
|
|
12
|
+
OSX = 4
|
|
13
|
+
BSD = 5
|
|
14
|
+
UNKNOWN = 100
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# returns the current execution environment
|
|
18
|
+
def self.os_context
|
|
19
|
+
case RbConfig::CONFIG['host_os']
|
|
20
|
+
when /mswin/ then OS::WINDOWS
|
|
21
|
+
when /mingw/ then OS::MINGW
|
|
22
|
+
when /cygwin/ then OS::CYGWIN
|
|
23
|
+
when /darwin/ then OS::OSX
|
|
24
|
+
when /linux/ then OS::LINUX
|
|
25
|
+
when /bsd/ then OS::BSD
|
|
26
|
+
else OS::UNKNOWN
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# return the current underlying operating system
|
|
31
|
+
def self.host_os
|
|
32
|
+
if [OS::WINDOWS, OS::MINGW, OS::CYGWIN].include?(os_context)
|
|
33
|
+
OS::WINDOWS
|
|
34
|
+
else
|
|
35
|
+
os_context
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def on_windows?
|
|
40
|
+
host_os == OS::WINDOWS
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def on_linux?
|
|
44
|
+
os_context == OS::LINUX
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def on_bsd?
|
|
48
|
+
os_context == OS::BSD
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def on_osx?
|
|
52
|
+
os_context == OS::OSX
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
require_relative 'core'
|
|
2
|
+
|
|
3
|
+
# This module is written to provide sub-process
|
|
4
|
+
# execution with some human readable logging of process start/stop/errors
|
|
5
|
+
#
|
|
6
|
+
# It wraps SProc instances and execution with calls to logging methods
|
|
7
|
+
# that tries to make the resulting log user friendly
|
|
8
|
+
module SProc
|
|
9
|
+
module Reporting
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :logger
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def logger
|
|
15
|
+
Reporting.logger
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Run a process synchronuously via the native shell and log
|
|
19
|
+
# output suitable for a build log
|
|
20
|
+
#
|
|
21
|
+
# @param cmd_name a String containing a descriptive
|
|
22
|
+
# name for what the process will do.
|
|
23
|
+
# @param cmd, args, opts see SProc.exec_sync
|
|
24
|
+
#
|
|
25
|
+
# @return the SProc instance containing the completed process
|
|
26
|
+
def report_sync(cmd_name, cmd, *args, **opts)
|
|
27
|
+
p = create_proc_and_log(cmd_name,
|
|
28
|
+
ShellType::NONE, :exec_sync,
|
|
29
|
+
cmd, args, opts)
|
|
30
|
+
report_completed(p)
|
|
31
|
+
p
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Run a process asynchronuously via the native shell and log
|
|
35
|
+
# output suitable for a build log
|
|
36
|
+
#
|
|
37
|
+
# @param cmd_name a String containing a descriptive
|
|
38
|
+
# name for what the process will do.
|
|
39
|
+
# @param cmd, args, opts see SProc.exec_sync
|
|
40
|
+
#
|
|
41
|
+
# @return the created SProc instance
|
|
42
|
+
def report_async(cmd_name, cmd, *args, **opts)
|
|
43
|
+
create_proc_and_log(cmd_name,
|
|
44
|
+
ShellType::NONE, :exec_async,
|
|
45
|
+
cmd, args, opts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Run a process asynchronuously via the Bash shell and log
|
|
49
|
+
# output suitable for a build log
|
|
50
|
+
#
|
|
51
|
+
# @param cmd_name a String containing a descriptive
|
|
52
|
+
# name for what the process will do.
|
|
53
|
+
# @param cmd, args, opts see SProc.exec_sync
|
|
54
|
+
#
|
|
55
|
+
# @return the created SProc instance
|
|
56
|
+
def report_async_within_bash(cmd_name, cmd, *args, **opts)
|
|
57
|
+
create_proc_and_log(cmd_name,
|
|
58
|
+
ShellType::BASH, :exec_async,
|
|
59
|
+
cmd, args, opts)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Log output from a completed/aborted process
|
|
63
|
+
#
|
|
64
|
+
# @param process the SProc instance that has run
|
|
65
|
+
# @return true/false corresponding to process success
|
|
66
|
+
def report_completed(process)
|
|
67
|
+
friendly_name = if @log_friendly_name_map&.key?(process)
|
|
68
|
+
"#{@log_friendly_name_map[process]}"
|
|
69
|
+
else
|
|
70
|
+
process.task_info[:cmd_str][0,10] + "..."
|
|
71
|
+
end
|
|
72
|
+
started_ok = true
|
|
73
|
+
case process.execution_state
|
|
74
|
+
when ExecutionState::COMPLETED
|
|
75
|
+
process.exit_zero? && log_completed_ok(friendly_name, process.task_info)
|
|
76
|
+
!process.exit_zero? && log_completed_err(friendly_name, process.task_info)
|
|
77
|
+
when ExecutionState::ABORTED
|
|
78
|
+
log_aborted(friendly_name, process.task_info)
|
|
79
|
+
started_ok = false
|
|
80
|
+
when ExecutionState::FAILED_TO_START
|
|
81
|
+
log_failed_start(friendly_name, process.task_info)
|
|
82
|
+
started_ok = false
|
|
83
|
+
else
|
|
84
|
+
log_unexpected(friendly_name, process.task_info)
|
|
85
|
+
end
|
|
86
|
+
started_ok && process.exit_zero?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def create_proc_and_log(cmd_name, type, method, cmd, args, opts)
|
|
92
|
+
log_start(cmd_name, type, method, cmd, args, **opts)
|
|
93
|
+
p = SProc.new(type: type).send(method, cmd, args, **opts)
|
|
94
|
+
@log_friendly_name_map ||= {}
|
|
95
|
+
@log_friendly_name_map[p] = cmd_name
|
|
96
|
+
p
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def log_method_result_ok(friendly_name, delta)
|
|
100
|
+
logger.info do
|
|
101
|
+
"#{friendly_name} completed successfully after #{delta.round(3)}s"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def log_method_result_error(friendly_name_method, delta, exc)
|
|
106
|
+
logger.error do
|
|
107
|
+
"#{friendly_name_method} aborted by #{exc.class} after #{delta.round(3)}s\n"\
|
|
108
|
+
"Exception info: #{exc.message}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
logger.debug do
|
|
112
|
+
exc.backtrace.to_s
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def log_start(cmd_name, type, method, cmd, *args, **opts)
|
|
117
|
+
logger.info do
|
|
118
|
+
async_str = method == :exec_async ? 'asynchronuously' : 'synchronuously'
|
|
119
|
+
type_str = type == ShellType::NONE ? 'without shell' : 'within the bash shell'
|
|
120
|
+
"'#{cmd_name}' executing #{async_str} #{type_str}..."
|
|
121
|
+
end
|
|
122
|
+
logger.debug do
|
|
123
|
+
msg = String.new("Starting #{cmd}")
|
|
124
|
+
msg << " with args: #{args.flatten.inspect}" unless args.nil? || args.empty?
|
|
125
|
+
msg << " and opts: #{opts.inspect}" unless opts.nil? || opts.empty?
|
|
126
|
+
msg
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def log_one_dll(regex, cmd_str, time)
|
|
131
|
+
m = regex.match(cmd_str)
|
|
132
|
+
s = m.nil? ? cmd_str : m[1]
|
|
133
|
+
max = 45
|
|
134
|
+
s = s.length > max ? s.slice(0..max - 1) : s.ljust(max)
|
|
135
|
+
logger.info { "#{s} took #{time.round(3)}s." }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def log_aborted(friendly_name, p_info)
|
|
139
|
+
logger.error do
|
|
140
|
+
"'#{friendly_name}' aborted!\n"\
|
|
141
|
+
"When running: #{p_info[:cmd_str]}\n"\
|
|
142
|
+
"#{merge_proc_output(p_info)}"\
|
|
143
|
+
"#{p_info[:process_status] unless p_info[:process_status].nil?}"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def log_failed_start(friendly_name, p_info)
|
|
148
|
+
logger.error do
|
|
149
|
+
"'#{friendly_name}' not run!\n"\
|
|
150
|
+
"Could not start process using: #{p_info[:cmd_str]}\n"\
|
|
151
|
+
"#{merge_proc_output(p_info)}"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def log_completed_ok(friendly_name, p_info)
|
|
156
|
+
logger.info do
|
|
157
|
+
"'#{friendly_name}' completed successfully after #{p_info[:wall_time].round(3)}s"
|
|
158
|
+
end
|
|
159
|
+
logger.debug do
|
|
160
|
+
"Cmd: #{p_info[:cmd_str]}"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def log_completed_err(friendly_name, p_info)
|
|
165
|
+
logger.error do
|
|
166
|
+
"'#{friendly_name}' completed with exit code "\
|
|
167
|
+
"#{p_info[:process_status].exitstatus}\n"\
|
|
168
|
+
"When running: #{p_info[:cmd_str]}\n"\
|
|
169
|
+
"after #{p_info[:wall_time].round(3)}s\n"\
|
|
170
|
+
"#{merge_proc_output(p_info)}"
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def log_unexpected(friendly_name, p_info)
|
|
175
|
+
logger.error do
|
|
176
|
+
"'#{friendly_name}' caused unexpected error!"\
|
|
177
|
+
' Trying to display info on a running process'\
|
|
178
|
+
"(#{p_info[:cmd_str]})"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# @return String with sections for each non-empty output stream
|
|
183
|
+
# and exception messages
|
|
184
|
+
def merge_proc_output(p_info)
|
|
185
|
+
inf_str = %i[stdout stderr].collect do |sym|
|
|
186
|
+
next('') if p_info[sym].empty?
|
|
187
|
+
|
|
188
|
+
"--- #{sym} ---\n#{p_info[sym]}"
|
|
189
|
+
end.join("\n")
|
|
190
|
+
|
|
191
|
+
exc = p_info[:exception]
|
|
192
|
+
inf_str << "--- exception ---\n#{exc}\n" unless exc.nil?
|
|
193
|
+
inf_str
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
data/lib/sproc/version.rb
CHANGED
data/sproc.gemspec
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
3
|
+
require_relative 'lib/sproc/version'
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name =
|
|
6
|
+
spec.name = 'sproc'
|
|
7
7
|
spec.version = SProc::VERSION
|
|
8
|
-
spec.authors = [
|
|
9
|
-
spec.email = [
|
|
8
|
+
spec.authors = ['Anders Rillbert']
|
|
9
|
+
spec.email = ['anders.rillbert@kutso.se']
|
|
10
10
|
|
|
11
|
-
spec.summary =
|
|
12
|
-
spec.description =
|
|
13
|
-
|
|
14
|
-
spec.
|
|
15
|
-
spec.
|
|
11
|
+
spec.summary = 'Spawn commands as asynch/synch subprocesses.'
|
|
12
|
+
spec.description = 'Easier invokation of asynch/synch commands with '\
|
|
13
|
+
'a reasonable easy and flexible interface for processing stdout and stderr'
|
|
14
|
+
spec.homepage = 'https://github.com/rillbert/sproc'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
|
16
17
|
|
|
17
|
-
spec.metadata[
|
|
18
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
18
19
|
|
|
19
|
-
spec.metadata[
|
|
20
|
-
spec.metadata[
|
|
21
|
-
spec.metadata[
|
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
21
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
22
|
+
spec.metadata['changelog_uri'] = spec.homepage
|
|
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.
|
|
25
26
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
27
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
27
28
|
end
|
|
28
|
-
spec.bindir =
|
|
29
|
+
spec.bindir = 'exe'
|
|
29
30
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
30
|
-
spec.require_paths = [
|
|
31
|
+
spec.require_paths = ['lib']
|
|
31
32
|
|
|
32
33
|
# Developer dependencies
|
|
33
|
-
spec.add_development_dependency
|
|
34
|
+
spec.add_development_dependency 'minitest', '~> 5.1'
|
|
34
35
|
|
|
35
36
|
# Uncomment to register a new dependency of your gem
|
|
36
|
-
# spec.add_dependency "example-gem", "~> 1.0"
|
|
37
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
|
37
38
|
|
|
38
39
|
# For more information and examples about making a new gem, checkout our
|
|
39
40
|
# guide at: https://bundler.io/guides/creating_gem.html
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sproc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anders Rillbert
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-03-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -24,7 +24,8 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '5.1'
|
|
27
|
-
description:
|
|
27
|
+
description: Easier invokation of asynch/synch commands with a reasonable easy and
|
|
28
|
+
flexible interface for processing stdout and stderr
|
|
28
29
|
email:
|
|
29
30
|
- anders.rillbert@kutso.se
|
|
30
31
|
executables: []
|
|
@@ -42,7 +43,8 @@ files:
|
|
|
42
43
|
- bin/setup
|
|
43
44
|
- lib/sproc.rb
|
|
44
45
|
- lib/sproc/core.rb
|
|
45
|
-
- lib/sproc/
|
|
46
|
+
- lib/sproc/osinfo.rb
|
|
47
|
+
- lib/sproc/reporting.rb
|
|
46
48
|
- lib/sproc/version.rb
|
|
47
49
|
- sproc.gemspec
|
|
48
50
|
homepage: https://github.com/rillbert/sproc
|
|
@@ -71,5 +73,5 @@ requirements: []
|
|
|
71
73
|
rubygems_version: 3.1.4
|
|
72
74
|
signing_key:
|
|
73
75
|
specification_version: 4
|
|
74
|
-
summary:
|
|
76
|
+
summary: Spawn commands as asynch/synch subprocesses.
|
|
75
77
|
test_files: []
|
data/lib/sproc/utils.rb
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
require 'rbconfig'
|
|
2
|
-
|
|
3
|
-
# utility to find out info about our execution environment
|
|
4
|
-
module OSInfo
|
|
5
|
-
# the supported exec environments
|
|
6
|
-
module OS
|
|
7
|
-
WINDOWS = 0
|
|
8
|
-
LINUX = 1
|
|
9
|
-
MINGW = 2
|
|
10
|
-
CYGWIN = 3
|
|
11
|
-
OSX = 4
|
|
12
|
-
BSD = 5
|
|
13
|
-
UNKNOWN = 100
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# returns the current execution environment
|
|
17
|
-
def self.os_context
|
|
18
|
-
case RbConfig::CONFIG['host_os']
|
|
19
|
-
when /mswin/ then OS::WINDOWS
|
|
20
|
-
when /mingw/ then OS::MINGW
|
|
21
|
-
when /cygwin/ then OS::CYGWIN
|
|
22
|
-
when /darwin/ then OS::OSX
|
|
23
|
-
when /linux/ then OS::LINUX
|
|
24
|
-
when /bsd/ then OS::BSD
|
|
25
|
-
else OS::UNKNOWN
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# return the current underlying operating system
|
|
30
|
-
def self.host_os
|
|
31
|
-
if [OS::WINDOWS, OS::MINGW, OS::CYGWIN].include?(os_context)
|
|
32
|
-
OS::WINDOWS
|
|
33
|
-
else
|
|
34
|
-
os_context
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def on_windows?
|
|
39
|
-
host_os == OS::WINDOWS
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def on_linux?
|
|
43
|
-
os_context == OS::LINUX
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def on_bsd?
|
|
47
|
-
os_context == OS::BSD
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def on_osx?
|
|
51
|
-
os_context == OS::OSX
|
|
52
|
-
end
|
|
53
|
-
end
|