raykit 0.0.469 → 0.0.471

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.
@@ -1,343 +1,343 @@
1
- require "open3"
2
- require "timeout"
3
- require "json"
4
- require "yaml"
5
- require "logger"
6
- require "securerandom"
7
-
8
- BUFFER_SIZE = 1024 unless defined?(BUFFER_SIZE)
9
-
10
- module Raykit
11
- # Functionality to support executing and logging system commands
12
- class Command
13
- @@commands = []
14
- # The timeout in seconds, defaults to 0 if not specified
15
- attr_accessor :timeout
16
- # The working directory, defaults the current directory if not specified
17
- attr_accessor :directory
18
- # The start time
19
- attr_accessor :start_time
20
- # The execution time in seconds
21
- attr_accessor :elapsed
22
- attr_accessor :command, :output, :error, :exitstatus, :user, :machine, :logging_enabled, :success_log_level
23
-
24
- def init_defaults
25
- @timeout = 0
26
- @directory = Dir.pwd
27
- @output = +""
28
- @error = +""
29
- @exitstatus = 0
30
- @user = Environment.user
31
- @machine = Environment.machine
32
- @logging_enabled = true
33
- end
34
-
35
- def initialize(command)
36
- #def initialize(command, timeout = 0, success_log_level = Logger::DEBUG, logging_enabled = true)
37
- timeout = 0
38
- success_log_level = nil
39
- logging_enabled = false
40
- @@commands = []
41
- init_defaults
42
- @success_log_level = success_log_level
43
- @logging_enabled = logging_enabled
44
- @command = command
45
- @timeout = timeout
46
- #t = Time.now
47
- @elapsed = 0
48
- #run if @command.length.positive?
49
- self
50
- end
51
-
52
- def set_timeout(timeout)
53
- @timeout = timeout
54
- self
55
- end
56
-
57
- def run
58
- # puts '---running---'
59
- @start_time = Time.now
60
- @elapsed = 0
61
- timer = Timer.new
62
- if @timeout.zero?
63
- @output, @error, process_status = Open3.capture3(@command)
64
- @exitstatus = process_status.exitstatus
65
- else
66
- # =================================================
67
- #puts "@timeout is #{@timeout}"
68
- Open3.popen3(@command, chdir: @directory) do |_stdin, stdout, stderr, thread|
69
- tick = 1
70
- pid = thread.pid
71
- start = Time.now
72
- while ((Time.now - start) < @timeout) && thread.alive?
73
- Kernel.select([stdout, stderr], nil, nil, tick)
74
- begin
75
- @output << stdout.read_nonblock(BUFFER_SIZE)
76
- #@error << stderr.read_nonblock(BUFFER_SIZE)
77
- rescue IO::WaitReadable
78
- rescue EOFError
79
- #puts "rescue block entered"
80
- @exitstatus = thread.value.exitstatus
81
- until stdout.eof?
82
- @output << stdout.read_nonblock(BUFFER_SIZE)
83
- end
84
- until stderr.eof?
85
- @error << stderr.read_nonblock(BUFFER_SIZE)
86
- end
87
- break
88
- end
89
-
90
- #begin
91
- # @output << stdout.read_nonblock(BUFFER_SIZE)
92
- # @error << stderr.read_nonblock(BUFFER_SIZE)
93
- #rescue IO::WaitReadable
94
- #rescue EOFError
95
- # @exitstatus = thread.value.exitstatus
96
- # until stdout.eof?
97
- # @output << stdout.read_nonblock(BUFFER_SIZE)
98
- # end
99
- # until stderr.eof?
100
- # @error << stderr.read_nonblock(BUFFER_SIZE)
101
- # end
102
- # break
103
- #end
104
- end
105
- sleep 1
106
- if thread.alive?
107
- if Gem.win_platform?
108
- `taskkill /f /pid #{pid}`
109
- else
110
- Process.kill("TERM", pid)
111
- end
112
- @exitstatus = 5
113
- @error = +"timed out"
114
- else
115
- @exitstatus = thread.value.exitstatus
116
- end
117
- end
118
-
119
- # =================================================
120
- end
121
- @elapsed = timer.elapsed
122
- if @logging_enabled
123
- log
124
- if @exitstatus != 0
125
- to_log_event.to_seq
126
- else
127
- # puts '---logging---'
128
- unless @success_log_level.nil?
129
- e = to_log_event
130
- e["Level"] = "Verbose" if @success_log_level == "Verbose"
131
- e["Level"] = "Debug" if @success_log_level == Logger::DEBUG
132
- e["Level"] = "Information" if @success_log_level == Logger::INFO
133
- e["Level"] = "Warning" if @elapsed > 60 * 2
134
- e.to_seq
135
- end
136
- end
137
- end
138
- self
139
- end
140
-
141
- def to_log_event
142
- secrets = Secrets.new
143
- msg = secrets.hide(@command)
144
- level = "Verbose"
145
- level = "Warning" if @exitstatus != 0
146
- output = @output
147
- error = @error
148
- output = @output[-1000..-1] if @output.length > 1200
149
- error = @error[-1000..-1] if @error.length > 1200
150
- Raykit::LogEvent.new(level, msg, {
151
- "SourceContext" => "Raykit::Command",
152
- "Category" => "Command",
153
- "Timeout" => @timeout,
154
- "Directory" => @directory,
155
- "Output" => output,
156
- "Error" => error,
157
- "ExitStatus" => @exitstatus,
158
- "Elapsed" => elapsed_str,
159
- "ElapsedSeconds" => @elapsed,
160
- })
161
- end
162
-
163
- def log
164
- # --- Rolling File JSON -----
165
- log = Logger.new("#{Raykit::Environment.log_dir}/Raykit.Commands.txt", "daily")
166
- log.formatter = proc do |_severity, _datetime, _progname, msg|
167
- "#{msg}\n"
168
- end
169
- secrets = Secrets.new
170
- msg = secrets.hide(@command) # "?"# self.summary(false)
171
- level = "Verbose"
172
- level = "Warning" if @exitstatus != 0
173
- event = Raykit::LogEvent.new(level, msg, {
174
- "Timeout" => @timeout,
175
- "Directory" => @directory,
176
- "Output" => @output,
177
- "Error" => @error,
178
- "ExitStatus" => @exitstatus,
179
- "Elapsed" => elapsed_str,
180
- })
181
- log.info event.to_json
182
- # ---------------------------
183
- begin
184
- json = JSON.generate(to_hash)
185
- log_filename = "#{Environment.get_dev_dir("log")}/Raykit.Command/#{SecureRandom.uuid}.json"
186
- log_dir = File.dirname(log_filename)
187
- FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
188
- File.open(log_filename, "w") { |f| f.write(json) }
189
- if !@exitstatus.nil? && @exitstatus.zero?
190
- LOG.log("Raykit.Command", Logger::Severity::INFO, json)
191
- else
192
- LOG.log("Raykit.Command", Logger::Severity::ERROR, json)
193
- end
194
- rescue JSON::GeneratorError => e
195
- puts to_hash.to_s
196
- puts e.to_s
197
- json = JSON.generate(to_hash)
198
- end
199
- end
200
-
201
- def elapsed_str
202
- if elapsed < 1.0
203
- end
204
- "#{format("%.0f", elapsed)}s"
205
- end
206
-
207
- def summary(show_directory = false)
208
- checkmark = "\u2713"
209
- # warning="\u26A0"
210
- error = "\u0058"
211
- symbol = Rainbow(checkmark.encode("utf-8")).green
212
- symbol = Rainbow(error.encode("utf-8")).red if @exitstatus != 0
213
- cmd = "#{Rainbow(SECRETS.hide(@command)).yellow}"
214
- if show_directory
215
- puts "#{symbol} #{cmd} " + Rainbow("#{elapsed_str}").cyan
216
- puts Rainbow(" #{@directory}").white + " "
217
- else
218
- puts "#{symbol} #{Rainbow(SECRETS.hide(@command)).yellow} " + Rainbow("#{elapsed_str}").cyan
219
- #puts "#{symbol} #{Rainbow(SECRETS.hide(@command)).yellow} (#{elapsed_str})"
220
- end
221
- self
222
- end
223
-
224
- def details_on_failure
225
- if @exitstatus != 0
226
- details
227
- end
228
- self
229
- end
230
-
231
- def details
232
- #puts " exit_code: " + @exitstatus.to_s
233
- summary
234
- if @output.length > 0
235
- @output.lines.each do |line|
236
- puts " " + line
237
- end
238
- end
239
- if @error.length > 0
240
- @error.lines.each do |line|
241
- puts " " + line
242
- end
243
- end
244
- self
245
- end
246
-
247
- def to_markdown
248
- checkmark = "\u2713"
249
- error = "\u0058"
250
- symbol = checkmark.encode("utf-8")
251
- symbol = error.encode("utf-8") if @exitstatus != 0
252
- cmd = "#{SECRETS.hide(@command)}"
253
- md = "#{symbol} #{SECRETS.hide(@command)} (#{elapsed_str})"
254
- md
255
- end
256
-
257
- def save
258
- filename = "#{Environment.get_dev_dir("log")}/Commands/#{SecureRandom.uuid}"
259
- log_dir = File.dirname(filename)
260
- FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
261
-
262
- File.open(filename, "w") do |f|
263
- f.write(JSON.pretty_generate(to_hash))
264
- end
265
- self
266
- end
267
-
268
- def save_as(filename)
269
- File.open(filename, "w") do |f|
270
- f.write(JSON.pretty_generate(to_hash))
271
- end
272
- self
273
- end
274
-
275
- def log_to_file(filename)
276
- File.delete(filename) if File.exist?(filename)
277
- File.open(filename, "w") { |f|
278
- f.puts output
279
- f.puts error
280
- }
281
- self
282
- end
283
-
284
- def to_hash
285
- hash = {}
286
- hash[:command] = @command
287
- hash[:directory] = @directory
288
- hash[:timeout] = @timeout
289
- hash[:start_time] = @start_time
290
- hash[:elapsed] = @elapsed
291
- hash[:output] = @output.force_encoding("ISO-8859-1").encode("UTF-8")
292
- hash[:error] = @error.force_encoding("ISO-8859-1").encode("UTF-8")
293
- hash[:exitstatus] = @exitstatus
294
- hash[:user] = @user
295
- hash[:machine] = @machine
296
- hash[:context] = "Raykit.Command"
297
- hash
298
- end
299
-
300
- def from_hash(hash)
301
- @command = hash["command"]
302
- @directory = hash["directory"]
303
- @timeout = hash["timeout"]
304
- @start_time = hash["start_time"]
305
- @elapsed = hash["elapsed"]
306
- @output = hash["output"]
307
- @error = hash["error"]
308
- @exitstatus = hash["exitstatus"]
309
- @user = hash["user"] if hash.include?("user")
310
- @machine = hash["machine"] if hash.include?("machine")
311
- end
312
-
313
- def self.parse(json)
314
- cmd = Command.new("")
315
- cmd.from_hash(JSON.parse(json))
316
- cmd
317
- end
318
-
319
- def self.parse_yaml_commands(yaml)
320
- # commands=Array.new()
321
- data = YAML.safe_load(yaml)
322
- commands = get_script_commands(data)
323
- end
324
-
325
- def self.get_script_commands(hash)
326
- commands = []
327
- if hash.key?("script")
328
- hash["script"].each do |cmd|
329
- commands << cmd
330
- end
331
- end
332
- hash.each do |_k, v|
333
- next unless v.is_a?(Hash)
334
-
335
- subcommands = get_script_commands(v)
336
- subcommands.each do |c|
337
- commands << c
338
- end
339
- end
340
- commands
341
- end
342
- end
343
- end
1
+ require "open3"
2
+ require "timeout"
3
+ require "json"
4
+ require "yaml"
5
+ require "logger"
6
+ require "securerandom"
7
+
8
+ BUFFER_SIZE = 1024 unless defined?(BUFFER_SIZE)
9
+
10
+ module Raykit
11
+ # Functionality to support executing and logging system commands
12
+ class Command
13
+ @@commands = []
14
+ # The timeout in seconds, defaults to 0 if not specified
15
+ attr_accessor :timeout
16
+ # The working directory, defaults the current directory if not specified
17
+ attr_accessor :directory
18
+ # The start time
19
+ attr_accessor :start_time
20
+ # The execution time in seconds
21
+ attr_accessor :elapsed
22
+ attr_accessor :command, :output, :error, :exitstatus, :user, :machine, :logging_enabled, :success_log_level
23
+
24
+ def init_defaults
25
+ @timeout = 0
26
+ @directory = Dir.pwd
27
+ @output = +""
28
+ @error = +""
29
+ @exitstatus = 0
30
+ @user = Environment.user
31
+ @machine = Environment.machine
32
+ @logging_enabled = true
33
+ end
34
+
35
+ def initialize(command)
36
+ #def initialize(command, timeout = 0, success_log_level = Logger::DEBUG, logging_enabled = true)
37
+ timeout = 0
38
+ success_log_level = nil
39
+ logging_enabled = false
40
+ @@commands = []
41
+ init_defaults
42
+ @success_log_level = success_log_level
43
+ @logging_enabled = logging_enabled
44
+ @command = command
45
+ @timeout = timeout
46
+ #t = Time.now
47
+ @elapsed = 0
48
+ #run if @command.length.positive?
49
+ self
50
+ end
51
+
52
+ def set_timeout(timeout)
53
+ @timeout = timeout
54
+ self
55
+ end
56
+
57
+ def run
58
+ # puts '---running---'
59
+ @start_time = Time.now
60
+ @elapsed = 0
61
+ timer = Timer.new
62
+ if @timeout.zero?
63
+ @output, @error, process_status = Open3.capture3(@command)
64
+ @exitstatus = process_status.exitstatus
65
+ else
66
+ # =================================================
67
+ #puts "@timeout is #{@timeout}"
68
+ Open3.popen3(@command, chdir: @directory) do |_stdin, stdout, stderr, thread|
69
+ tick = 1
70
+ pid = thread.pid
71
+ start = Time.now
72
+ while ((Time.now - start) < @timeout) && thread.alive?
73
+ Kernel.select([stdout, stderr], nil, nil, tick)
74
+ begin
75
+ @output << stdout.read_nonblock(BUFFER_SIZE)
76
+ #@error << stderr.read_nonblock(BUFFER_SIZE)
77
+ rescue IO::WaitReadable
78
+ rescue EOFError
79
+ #puts "rescue block entered"
80
+ @exitstatus = thread.value.exitstatus
81
+ until stdout.eof?
82
+ @output << stdout.read_nonblock(BUFFER_SIZE)
83
+ end
84
+ until stderr.eof?
85
+ @error << stderr.read_nonblock(BUFFER_SIZE)
86
+ end
87
+ break
88
+ end
89
+
90
+ #begin
91
+ # @output << stdout.read_nonblock(BUFFER_SIZE)
92
+ # @error << stderr.read_nonblock(BUFFER_SIZE)
93
+ #rescue IO::WaitReadable
94
+ #rescue EOFError
95
+ # @exitstatus = thread.value.exitstatus
96
+ # until stdout.eof?
97
+ # @output << stdout.read_nonblock(BUFFER_SIZE)
98
+ # end
99
+ # until stderr.eof?
100
+ # @error << stderr.read_nonblock(BUFFER_SIZE)
101
+ # end
102
+ # break
103
+ #end
104
+ end
105
+ sleep 1
106
+ if thread.alive?
107
+ if Gem.win_platform?
108
+ `taskkill /f /pid #{pid}`
109
+ else
110
+ Process.kill("TERM", pid)
111
+ end
112
+ @exitstatus = 5
113
+ @error = +"timed out"
114
+ else
115
+ @exitstatus = thread.value.exitstatus
116
+ end
117
+ end
118
+
119
+ # =================================================
120
+ end
121
+ @elapsed = timer.elapsed
122
+ if @logging_enabled
123
+ log
124
+ if @exitstatus != 0
125
+ to_log_event.to_seq
126
+ else
127
+ # puts '---logging---'
128
+ unless @success_log_level.nil?
129
+ e = to_log_event
130
+ e["Level"] = "Verbose" if @success_log_level == "Verbose"
131
+ e["Level"] = "Debug" if @success_log_level == Logger::DEBUG
132
+ e["Level"] = "Information" if @success_log_level == Logger::INFO
133
+ e["Level"] = "Warning" if @elapsed > 60 * 2
134
+ e.to_seq
135
+ end
136
+ end
137
+ end
138
+ self
139
+ end
140
+
141
+ def to_log_event
142
+ secrets = Secrets.new
143
+ msg = secrets.hide(@command)
144
+ level = "Verbose"
145
+ level = "Warning" if @exitstatus != 0
146
+ output = @output
147
+ error = @error
148
+ output = @output[-1000..-1] if @output.length > 1200
149
+ error = @error[-1000..-1] if @error.length > 1200
150
+ Raykit::LogEvent.new(level, msg, {
151
+ "SourceContext" => "Raykit::Command",
152
+ "Category" => "Command",
153
+ "Timeout" => @timeout,
154
+ "Directory" => @directory,
155
+ "Output" => output,
156
+ "Error" => error,
157
+ "ExitStatus" => @exitstatus,
158
+ "Elapsed" => elapsed_str,
159
+ "ElapsedSeconds" => @elapsed,
160
+ })
161
+ end
162
+
163
+ def log
164
+ # --- Rolling File JSON -----
165
+ log = Logger.new("#{Raykit::Environment.log_dir}/Raykit.Commands.txt", "daily")
166
+ log.formatter = proc do |_severity, _datetime, _progname, msg|
167
+ "#{msg}\n"
168
+ end
169
+ secrets = Secrets.new
170
+ msg = secrets.hide(@command) # "?"# self.summary(false)
171
+ level = "Verbose"
172
+ level = "Warning" if @exitstatus != 0
173
+ event = Raykit::LogEvent.new(level, msg, {
174
+ "Timeout" => @timeout,
175
+ "Directory" => @directory,
176
+ "Output" => @output,
177
+ "Error" => @error,
178
+ "ExitStatus" => @exitstatus,
179
+ "Elapsed" => elapsed_str,
180
+ })
181
+ log.info event.to_json
182
+ # ---------------------------
183
+ begin
184
+ json = JSON.generate(to_hash)
185
+ log_filename = "#{Environment.get_dev_dir("log")}/Raykit.Command/#{SecureRandom.uuid}.json"
186
+ log_dir = File.dirname(log_filename)
187
+ FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
188
+ File.open(log_filename, "w") { |f| f.write(json) }
189
+ if !@exitstatus.nil? && @exitstatus.zero?
190
+ LOG.log("Raykit.Command", Logger::Severity::INFO, json)
191
+ else
192
+ LOG.log("Raykit.Command", Logger::Severity::ERROR, json)
193
+ end
194
+ rescue JSON::GeneratorError => e
195
+ puts to_hash.to_s
196
+ puts e.to_s
197
+ json = JSON.generate(to_hash)
198
+ end
199
+ end
200
+
201
+ def elapsed_str
202
+ if elapsed < 1.0
203
+ end
204
+ "#{format("%.0f", elapsed)}s"
205
+ end
206
+
207
+ def summary(show_directory = false)
208
+ checkmark = "\u2713"
209
+ # warning="\u26A0"
210
+ error = "\u0058"
211
+ symbol = Rainbow(checkmark.encode("utf-8")).green
212
+ symbol = Rainbow(error.encode("utf-8")).red if @exitstatus != 0
213
+ cmd = "#{Rainbow(SECRETS.hide(@command)).yellow}"
214
+ if show_directory
215
+ puts "#{symbol} #{cmd} " + Rainbow("#{elapsed_str}").cyan
216
+ puts Rainbow(" #{@directory}").white + " "
217
+ else
218
+ puts "#{symbol} #{Rainbow(SECRETS.hide(@command)).yellow} " + Rainbow("#{elapsed_str}").cyan
219
+ #puts "#{symbol} #{Rainbow(SECRETS.hide(@command)).yellow} (#{elapsed_str})"
220
+ end
221
+ self
222
+ end
223
+
224
+ def details_on_failure
225
+ if @exitstatus != 0
226
+ details
227
+ end
228
+ self
229
+ end
230
+
231
+ def details
232
+ #puts " exit_code: " + @exitstatus.to_s
233
+ summary
234
+ if @output.length > 0
235
+ @output.lines.each do |line|
236
+ puts " " + line
237
+ end
238
+ end
239
+ if @error.length > 0
240
+ @error.lines.each do |line|
241
+ puts " " + line
242
+ end
243
+ end
244
+ self
245
+ end
246
+
247
+ def to_markdown
248
+ checkmark = "\u2713"
249
+ error = "\u0058"
250
+ symbol = checkmark.encode("utf-8")
251
+ symbol = error.encode("utf-8") if @exitstatus != 0
252
+ cmd = "#{SECRETS.hide(@command)}"
253
+ md = "#{symbol} #{SECRETS.hide(@command)} (#{elapsed_str})"
254
+ md
255
+ end
256
+
257
+ def save
258
+ filename = "#{Environment.get_dev_dir("log")}/Commands/#{SecureRandom.uuid}"
259
+ log_dir = File.dirname(filename)
260
+ FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
261
+
262
+ File.open(filename, "w") do |f|
263
+ f.write(JSON.pretty_generate(to_hash))
264
+ end
265
+ self
266
+ end
267
+
268
+ def save_as(filename)
269
+ File.open(filename, "w") do |f|
270
+ f.write(JSON.pretty_generate(to_hash))
271
+ end
272
+ self
273
+ end
274
+
275
+ def log_to_file(filename)
276
+ File.delete(filename) if File.exist?(filename)
277
+ File.open(filename, "w") { |f|
278
+ f.puts output
279
+ f.puts error
280
+ }
281
+ self
282
+ end
283
+
284
+ def to_hash
285
+ hash = {}
286
+ hash[:command] = @command
287
+ hash[:directory] = @directory
288
+ hash[:timeout] = @timeout
289
+ hash[:start_time] = @start_time
290
+ hash[:elapsed] = @elapsed
291
+ hash[:output] = @output.force_encoding("ISO-8859-1").encode("UTF-8")
292
+ hash[:error] = @error.force_encoding("ISO-8859-1").encode("UTF-8")
293
+ hash[:exitstatus] = @exitstatus
294
+ hash[:user] = @user
295
+ hash[:machine] = @machine
296
+ hash[:context] = "Raykit.Command"
297
+ hash
298
+ end
299
+
300
+ def from_hash(hash)
301
+ @command = hash["command"]
302
+ @directory = hash["directory"]
303
+ @timeout = hash["timeout"]
304
+ @start_time = hash["start_time"]
305
+ @elapsed = hash["elapsed"]
306
+ @output = hash["output"]
307
+ @error = hash["error"]
308
+ @exitstatus = hash["exitstatus"]
309
+ @user = hash["user"] if hash.include?("user")
310
+ @machine = hash["machine"] if hash.include?("machine")
311
+ end
312
+
313
+ def self.parse(json)
314
+ cmd = Command.new("")
315
+ cmd.from_hash(JSON.parse(json))
316
+ cmd
317
+ end
318
+
319
+ def self.parse_yaml_commands(yaml)
320
+ # commands=Array.new()
321
+ data = YAML.safe_load(yaml)
322
+ commands = get_script_commands(data)
323
+ end
324
+
325
+ def self.get_script_commands(hash)
326
+ commands = []
327
+ if hash.key?("script")
328
+ hash["script"].each do |cmd|
329
+ commands << cmd
330
+ end
331
+ end
332
+ hash.each do |_k, v|
333
+ next unless v.is_a?(Hash)
334
+
335
+ subcommands = get_script_commands(v)
336
+ subcommands.each do |c|
337
+ commands << c
338
+ end
339
+ end
340
+ commands
341
+ end
342
+ end
343
+ end