long-command-runner 0.2.0 → 0.3.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:
|
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
|