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: 732ddcf74afb4d4a3f7e5990e4761e4fabbea37824890c98e8cc236c3339a317
4
- data.tar.gz: 3209440517bcfcb93e020e01a3484e029487af1e61b95e86d932db6c27b30c7e
3
+ metadata.gz: 52ed0ae54876241ebf67b4fad432492782745247b45f69ac2815eb3f1a24ed3c
4
+ data.tar.gz: 5394c9c043976a7842aa1201a3e76d09dbd849212641181a8220b320efc2b604
5
5
  SHA512:
6
- metadata.gz: ac8cc65bf6dfc634469ca90d9312183aa17c7ec3d7d6649bddfc505879babbf0adadc503124a384d6fe3d78aa335d2d90e230bdfb7cf1d8670bfae04496efd6e
7
- data.tar.gz: 004ca4095874c144356593c7ceedef1c8a3983b2f6a5fbf18cfd0da5ca154fac670bc64cc81acf22644a5e5603e47a026fb1231c96b69c0cfdf1bf4644e86f19
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=en'
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("#{ENVIRONMENT} bash -c \"#{safe_command}\"", opts)
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
- # The intance variable is duplicated to prevent modification of the array.
32
+ # Be carefull accessing these, because you may prevent line_reader to run correctly.
33
33
  # @return [Array<IO>]
34
- def streams
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
- # buffers[line] = ''
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, :tms
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
- Process.kill(signal, @container.pid)
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
- # Old get the time in user space spend ('user' part of `time` command)
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
- # old get the time system space spend ('sys' part of `time` command)
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
- manage_progress(nl_stdout) unless nl_stdout.nil?
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
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module LCR
4
4
  # Version of the library.
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
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.2.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-06-07 00:00:00.000000000 Z
11
+ date: 2019-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry