long-command-runner 0.2.0 → 0.3.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52ed0ae54876241ebf67b4fad432492782745247b45f69ac2815eb3f1a24ed3c
|
4
|
+
data.tar.gz: 5394c9c043976a7842aa1201a3e76d09dbd849212641181a8220b320efc2b604
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dde08e22ddb8396d3d3dd97dc115fad4b8034cf89c5d1042de489fd52fe4e392a72d00bfdb453039db70f247dd4bc008f58863bfa38e87239a3c756ce3ed063a
|
7
|
+
data.tar.gz: f89f3c02c3e055cb69714e2a267628dc9773d8d00eb061f774e9015527f631b0e479e8b737fac5471fc63b1368207b1f52c82a733ccd18ba890aa235948ac456
|
@@ -6,7 +6,7 @@ module LCR
|
|
6
6
|
# This class aims to contain the runing script.
|
7
7
|
class Container
|
8
8
|
# The expected Language environment:
|
9
|
-
ENVIRONMENT = 'LANGUAGE
|
9
|
+
ENVIRONMENT = { 'LANGUAGE' => 'en' }.freeze
|
10
10
|
|
11
11
|
# Get the standard input IO of the process.
|
12
12
|
#
|
@@ -38,7 +38,7 @@ module LCR
|
|
38
38
|
# @param [Hash] opts The option to pass to Open3.popen3.
|
39
39
|
def initialize(command, opts = {})
|
40
40
|
safe_command = quote_sanitize(command)
|
41
|
-
@stdin, @stdout, @stderr, @wait_thr = Open3.popen3(
|
41
|
+
@stdin, @stdout, @stderr, @wait_thr = Open3.popen3(ENVIRONMENT, "bash -c \"#{safe_command}\"", opts)
|
42
42
|
end
|
43
43
|
|
44
44
|
# Is the last launched command is still running.
|
@@ -69,6 +69,13 @@ module LCR
|
|
69
69
|
@wait_thr.pid
|
70
70
|
end
|
71
71
|
|
72
|
+
def children
|
73
|
+
get_children = lambda do |pid|
|
74
|
+
`pgrep -P #{pid}`.split("\n").map { |c_pid| [c_pid.to_i, get_children.call(c_pid)] }.to_h
|
75
|
+
end
|
76
|
+
get_children.call(pid)
|
77
|
+
end
|
78
|
+
|
72
79
|
private
|
73
80
|
|
74
81
|
def quote_sanitize(cmd)
|
@@ -29,11 +29,9 @@ module LCR
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# access to the array of streams.
|
32
|
-
#
|
32
|
+
# Be carefull accessing these, because you may prevent line_reader to run correctly.
|
33
33
|
# @return [Array<IO>]
|
34
|
-
|
35
|
-
@streams.dup
|
36
|
-
end
|
34
|
+
attr_reader :streams
|
37
35
|
|
38
36
|
# Blocking method to read on the streams (you may call it in a dedicated thread).
|
39
37
|
#
|
@@ -103,7 +101,7 @@ module LCR
|
|
103
101
|
# puts "read_on(buffers:#{buffers}, streams_lines:#{stream_newlines}, io:#{io}, line:#{line})"
|
104
102
|
if io.eof?
|
105
103
|
stream_newlines[line] = [buffers[line]] unless buffers[line].nil?
|
106
|
-
|
104
|
+
buffers[line] = nil
|
107
105
|
return false
|
108
106
|
end
|
109
107
|
r = io.read_nonblock(MAX_READ_CHAR)
|
@@ -16,12 +16,18 @@ module LCR
|
|
16
16
|
# The constant used to get the percetange of completion of the command.
|
17
17
|
PERCENT_INDICATOR = /(.*\s|^)((\d+)([,.]\d*)?)%.*/.freeze
|
18
18
|
|
19
|
-
# Get the mesured progress in percentage.
|
19
|
+
# [Float] Get the mesured progress in percentage.
|
20
20
|
# This is just the result of parsing stdout lines with {PERCENT_INDICATOR}.
|
21
21
|
# So this percentage is comming from the thread not this library.
|
22
|
-
attr_reader :progress
|
22
|
+
attr_reader :progress
|
23
|
+
# [Benchmark::Tms] The time mesured of execution in the runner thread.
|
24
|
+
attr_reader :tms
|
23
25
|
|
24
26
|
# Initializer takes the command as a plain string.
|
27
|
+
# @param [String] command The command to run (can be a one-line shell script)
|
28
|
+
# @option opts [Boolean] :do_progress_on Set to `'stderr'`, if you want to use
|
29
|
+
# stderr to get the progression percentage instead of the default: `'stdout'`.
|
30
|
+
# Any other value will deactivate the feature.
|
25
31
|
# You can optionaly pass a block that will be called when the command generate
|
26
32
|
# outputs:
|
27
33
|
# @yield [nl_stdout, nl_stderr] call when at least a line comes on stdout or stderr.
|
@@ -30,13 +36,14 @@ module LCR
|
|
30
36
|
# @yieldparam [String | nil] nl_stderr The new line without the return line character.
|
31
37
|
# This may be nil if only a new line has been found on stdout.
|
32
38
|
# @yieldreturn [void] It is ignored.
|
33
|
-
def initialize(command, &on_input)
|
39
|
+
def initialize(command, opts = {}, &on_input)
|
34
40
|
@command = command
|
35
41
|
@container = nil
|
36
42
|
@launch_lock = Mutex.new
|
37
43
|
@on_input = on_input
|
38
44
|
@progress = 0.0
|
39
45
|
@tms = nil
|
46
|
+
@do_progress_on = opts[:do_progress_on] || 'stdout'
|
40
47
|
end
|
41
48
|
|
42
49
|
# Is the last launched command is still running.
|
@@ -122,13 +129,14 @@ module LCR
|
|
122
129
|
def kill(signal)
|
123
130
|
return nil if @container.nil?
|
124
131
|
|
125
|
-
|
132
|
+
children = @container.children
|
133
|
+
Runner.kill_children(signal, @container.pid, children)
|
126
134
|
rescue Errno::ESRCH
|
127
135
|
nil
|
128
136
|
end
|
129
137
|
|
130
138
|
# Old get the time really spend ('real' part of `time` command)
|
131
|
-
# DEPRECATED: use tms access now.
|
139
|
+
# DEPRECATED: use tms.real access now.
|
132
140
|
def time_real
|
133
141
|
warn '[DEPRECATION] use :tms instead of :time_real'
|
134
142
|
return nil if @tms.nil?
|
@@ -136,28 +144,46 @@ module LCR
|
|
136
144
|
@tms.real
|
137
145
|
end
|
138
146
|
|
139
|
-
#
|
140
|
-
# DEPRECATED: use tms access now.
|
147
|
+
# Get the total time spent in user space (sum of tms.cutime + tms.utime)
|
141
148
|
def time_user
|
142
|
-
warn '[DEPRECATION] use :tms instead of :time_user'
|
143
149
|
return nil if @tms.nil?
|
144
150
|
|
145
151
|
@tms.cutime + @tms.utime
|
146
152
|
end
|
147
153
|
|
148
|
-
#
|
149
|
-
# DEPRECATED: use tms access now.
|
154
|
+
# Get the total time spent in system space (sum of tms.cstime + tms.stime)
|
150
155
|
def time_sys
|
151
|
-
warn '[DEPRECATION] use :tms instead of :time_user'
|
152
156
|
return nil if @tms.nil?
|
153
157
|
|
154
158
|
@tms.cstime + @tms.stime
|
155
159
|
end
|
156
160
|
|
161
|
+
def self.dead?(pid)
|
162
|
+
Process.kill(0, pid)
|
163
|
+
false
|
164
|
+
rescue Errno::ESRCH
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.kill_children(signal, pid, children)
|
169
|
+
n = Process.kill(signal, pid)
|
170
|
+
sleep 0.1
|
171
|
+
children.keys.reject { |c_pid| dead? c_pid }.each do |c_pid|
|
172
|
+
# the not dead
|
173
|
+
n += kill_children(signal, c_pid, children[c_pid])
|
174
|
+
end
|
175
|
+
n
|
176
|
+
end
|
177
|
+
|
157
178
|
private
|
158
179
|
|
159
180
|
def on_newline(nl_stdout, nl_stderr)
|
160
|
-
|
181
|
+
nl_progress = if @do_progress_on == 'stdout'
|
182
|
+
nl_stdout
|
183
|
+
elsif @do_progress_on == 'stderr'
|
184
|
+
nl_stderr
|
185
|
+
end
|
186
|
+
manage_progress(nl_progress) unless nl_progress.nil?
|
161
187
|
@on_input&.call(nl_stdout, nl_stderr)
|
162
188
|
end
|
163
189
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: long-command-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roland Laurès
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|