greenhat 0.1.5 → 0.3.2
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/lib/greenhat/accessors/disk.rb +58 -2
- data/lib/greenhat/accessors/gitlab.rb +75 -0
- data/lib/greenhat/accessors/memory.rb +10 -10
- data/lib/greenhat/accessors/process.rb +10 -1
- data/lib/greenhat/cli.rb +148 -63
- data/lib/greenhat/color.rb +27 -0
- data/lib/greenhat/logbot.rb +9 -9
- data/lib/greenhat/settings.rb +51 -3
- data/lib/greenhat/shell/args.rb +146 -0
- data/lib/greenhat/shell/cat.rb +25 -73
- data/lib/greenhat/shell/color_string.rb +43 -0
- data/lib/greenhat/shell/disk.rb +30 -42
- data/lib/greenhat/shell/faststats.rb +104 -58
- data/lib/greenhat/shell/field_helper.rb +75 -0
- data/lib/greenhat/shell/filter_help.rb +162 -0
- data/lib/greenhat/shell/gitlab.rb +61 -2
- data/lib/greenhat/shell/help.rb +98 -15
- data/lib/greenhat/shell/list.rb +46 -0
- data/lib/greenhat/shell/log.rb +115 -209
- data/lib/greenhat/shell/page.rb +39 -0
- data/lib/greenhat/shell/process.rb +57 -2
- data/lib/greenhat/shell/report.rb +70 -60
- data/lib/greenhat/shell/shell_helper.rb +654 -0
- data/lib/greenhat/shell.rb +27 -13
- data/lib/greenhat/thing/file_types.rb +54 -7
- data/lib/greenhat/thing/formatters/json_shellwords.rb +0 -3
- data/lib/greenhat/thing/formatters/nginx.rb +44 -0
- data/lib/greenhat/thing/formatters/syslog.rb +39 -0
- data/lib/greenhat/thing/helpers.rb +4 -4
- data/lib/greenhat/thing/kind.rb +9 -2
- data/lib/greenhat/thing/spinner.rb +3 -3
- data/lib/greenhat/thing.rb +25 -3
- data/lib/greenhat/tty/columns.rb +44 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat.rb +16 -14
- metadata +42 -17
- data/lib/greenhat/shell/helper.rb +0 -541
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: greenhat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Davin Walker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: amazing_print
|
@@ -53,49 +53,49 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.14'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: minitest-reporters
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '1.4'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '1.4'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '13.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '13.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rubocop
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
90
|
-
type: :
|
89
|
+
version: '1.12'
|
90
|
+
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '1.12'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: actionview
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
@@ -109,19 +109,19 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '6.1'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: activesupport
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '6.1'
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
124
|
+
version: '6.1'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: did_you_mean
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -360,6 +360,20 @@ dependencies:
|
|
360
360
|
- - "~>"
|
361
361
|
- !ruby/object:Gem::Version
|
362
362
|
version: '0.12'
|
363
|
+
- !ruby/object:Gem::Dependency
|
364
|
+
name: tty-which
|
365
|
+
requirement: !ruby/object:Gem::Requirement
|
366
|
+
requirements:
|
367
|
+
- - "~>"
|
368
|
+
- !ruby/object:Gem::Version
|
369
|
+
version: '0.5'
|
370
|
+
type: :runtime
|
371
|
+
prerelease: false
|
372
|
+
version_requirements: !ruby/object:Gem::Requirement
|
373
|
+
requirements:
|
374
|
+
- - "~>"
|
375
|
+
- !ruby/object:Gem::Version
|
376
|
+
version: '0.5'
|
363
377
|
- !ruby/object:Gem::Dependency
|
364
378
|
name: warning
|
365
379
|
requirement: !ruby/object:Gem::Requirement
|
@@ -386,6 +400,7 @@ files:
|
|
386
400
|
- bin/greenhat
|
387
401
|
- lib/greenhat.rb
|
388
402
|
- lib/greenhat/accessors/disk.rb
|
403
|
+
- lib/greenhat/accessors/gitlab.rb
|
389
404
|
- lib/greenhat/accessors/logs/production.rb
|
390
405
|
- lib/greenhat/accessors/logs/sidekiq.rb
|
391
406
|
- lib/greenhat/accessors/memory.rb
|
@@ -393,22 +408,29 @@ files:
|
|
393
408
|
- lib/greenhat/accessors/process.rb
|
394
409
|
- lib/greenhat/archive.rb
|
395
410
|
- lib/greenhat/cli.rb
|
411
|
+
- lib/greenhat/color.rb
|
396
412
|
- lib/greenhat/host.rb
|
397
413
|
- lib/greenhat/logbot.rb
|
398
414
|
- lib/greenhat/pry_helpers.rb
|
399
415
|
- lib/greenhat/settings.rb
|
400
416
|
- lib/greenhat/shell.rb
|
417
|
+
- lib/greenhat/shell/args.rb
|
401
418
|
- lib/greenhat/shell/cat.rb
|
419
|
+
- lib/greenhat/shell/color_string.rb
|
402
420
|
- lib/greenhat/shell/disk.rb
|
403
421
|
- lib/greenhat/shell/faststats.rb
|
422
|
+
- lib/greenhat/shell/field_helper.rb
|
423
|
+
- lib/greenhat/shell/filter_help.rb
|
404
424
|
- lib/greenhat/shell/gitlab.rb
|
405
425
|
- lib/greenhat/shell/help.rb
|
406
|
-
- lib/greenhat/shell/
|
426
|
+
- lib/greenhat/shell/list.rb
|
407
427
|
- lib/greenhat/shell/log.rb
|
408
428
|
- lib/greenhat/shell/memory.rb
|
409
429
|
- lib/greenhat/shell/network.rb
|
430
|
+
- lib/greenhat/shell/page.rb
|
410
431
|
- lib/greenhat/shell/process.rb
|
411
432
|
- lib/greenhat/shell/report.rb
|
433
|
+
- lib/greenhat/shell/shell_helper.rb
|
412
434
|
- lib/greenhat/thing.rb
|
413
435
|
- lib/greenhat/thing/file_types.rb
|
414
436
|
- lib/greenhat/thing/formatters/api_json.rb
|
@@ -423,8 +445,10 @@ files:
|
|
423
445
|
- lib/greenhat/thing/formatters/json.rb
|
424
446
|
- lib/greenhat/thing/formatters/json_shellwords.rb
|
425
447
|
- lib/greenhat/thing/formatters/multiline_json.rb
|
448
|
+
- lib/greenhat/thing/formatters/nginx.rb
|
426
449
|
- lib/greenhat/thing/formatters/raw.rb
|
427
450
|
- lib/greenhat/thing/formatters/shellwords.rb
|
451
|
+
- lib/greenhat/thing/formatters/syslog.rb
|
428
452
|
- lib/greenhat/thing/formatters/table.rb
|
429
453
|
- lib/greenhat/thing/formatters/time_json.rb
|
430
454
|
- lib/greenhat/thing/formatters/time_shellwords.rb
|
@@ -435,6 +459,7 @@ files:
|
|
435
459
|
- lib/greenhat/thing/kind.rb
|
436
460
|
- lib/greenhat/thing/spinner.rb
|
437
461
|
- lib/greenhat/thing/super_log.rb
|
462
|
+
- lib/greenhat/tty/columns.rb
|
438
463
|
- lib/greenhat/tty/custom_line.rb
|
439
464
|
- lib/greenhat/tty/line.rb
|
440
465
|
- lib/greenhat/tty/reader.rb
|
@@ -1,541 +0,0 @@
|
|
1
|
-
module GreenHat
|
2
|
-
# Common Helpers
|
3
|
-
# rubocop:disable Metrics/ModuleLength
|
4
|
-
module ShellHelper
|
5
|
-
# Generic Parameter Parsing
|
6
|
-
def self.param_parse(params)
|
7
|
-
# Turn Params into Hash
|
8
|
-
opts = params.flat_map { |param| param_opt_scan(param) }
|
9
|
-
|
10
|
-
# Collect and Remove Args
|
11
|
-
args = params.each_with_object({}) { |param, obj| param_arg_scan(param, obj) }
|
12
|
-
|
13
|
-
# Move Special Arguments
|
14
|
-
opts.reject! do |opt|
|
15
|
-
if param_special_opts.include? opt.field
|
16
|
-
args[opt.field] = opt.value.split(',').map(&:to_sym)
|
17
|
-
true
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Remove Opts and Args
|
22
|
-
params.reject! do |param|
|
23
|
-
opt_field_remove?(opts, param) || arg_field_remove?(args, param)
|
24
|
-
end
|
25
|
-
|
26
|
-
[params, opts, args]
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.opt_field_remove?(opts, param)
|
30
|
-
opts.any? do |opt|
|
31
|
-
param.include? "--#{opt.field}#{opt.bang ? '!' : nil}=#{opt.value}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.arg_field_remove?(args, param)
|
36
|
-
args.keys.any? { |field| param.include? "--#{field}" }
|
37
|
-
end
|
38
|
-
|
39
|
-
# Def Param Scan (Split -- values into keys)
|
40
|
-
def self.param_opt_scan(param)
|
41
|
-
param.scan(/--([^=]+)=(.*)/).map do |field, value|
|
42
|
-
bang = false
|
43
|
-
if field.include? '!'
|
44
|
-
field.delete!('!')
|
45
|
-
bang = true
|
46
|
-
end
|
47
|
-
|
48
|
-
{ field: field.to_sym, value: value, bang: bang }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Params that should be set as Args
|
53
|
-
# Comma Delimited
|
54
|
-
# --slice=thing,thing2
|
55
|
-
# --except=time,params
|
56
|
-
# --round=2
|
57
|
-
|
58
|
-
def self.param_special_opts
|
59
|
-
%i[
|
60
|
-
slice except stats uniq pluck round archive start end sort limit
|
61
|
-
]
|
62
|
-
end
|
63
|
-
|
64
|
-
# Parameter Extraction
|
65
|
-
# Special Opts: --slice, --except
|
66
|
-
def self.param_arg_scan(param, obj)
|
67
|
-
# TODO: Why is capture group doing two arrays
|
68
|
-
param.scan(/--([^=]+)$/).flatten.each do |field|
|
69
|
-
obj[field.to_sym] = param_arg_defaults(field.to_sym)
|
70
|
-
end
|
71
|
-
|
72
|
-
obj
|
73
|
-
end
|
74
|
-
|
75
|
-
# Arg Defaults
|
76
|
-
def self.param_arg_defaults(field)
|
77
|
-
case field
|
78
|
-
when :round then 2
|
79
|
-
when :limit then [TTY::Screen.height / 2]
|
80
|
-
when *param_special_opts then []
|
81
|
-
else
|
82
|
-
true
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Use File Process for Output
|
87
|
-
def self.file_output(files)
|
88
|
-
results = file_process(files) do |file|
|
89
|
-
[
|
90
|
-
file.friendly_name,
|
91
|
-
file.output(false),
|
92
|
-
"\n"
|
93
|
-
]
|
94
|
-
end
|
95
|
-
|
96
|
-
ShellHelper.show(results.flatten)
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.file_process(files, &block)
|
100
|
-
files.map do |file|
|
101
|
-
next if file.output(false).empty?
|
102
|
-
|
103
|
-
block.call(file)
|
104
|
-
end.flatten
|
105
|
-
end
|
106
|
-
|
107
|
-
# Pagination Helper
|
108
|
-
def self.page(data)
|
109
|
-
TTY::Pager.page do |pager|
|
110
|
-
data.flatten.each do |output|
|
111
|
-
pager.write("\n#{output}") # write line to the pager
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Show Data / Auto Paginate Helper
|
117
|
-
def self.show(data, args = {})
|
118
|
-
# If Block of String
|
119
|
-
if data.instance_of?(String)
|
120
|
-
TTY::Pager.page data
|
121
|
-
return true
|
122
|
-
end
|
123
|
-
|
124
|
-
# If raw just print out
|
125
|
-
if args.raw
|
126
|
-
puts data.join("\n")
|
127
|
-
return true
|
128
|
-
end
|
129
|
-
|
130
|
-
# Check if content needs to paged, or if auto_height is off
|
131
|
-
if !args.page && count_rows(data)
|
132
|
-
puts data.map { |x| entry_show(x, args) }.compact.join("\n")
|
133
|
-
return true
|
134
|
-
end
|
135
|
-
|
136
|
-
# Default Pager
|
137
|
-
TTY::Pager.page do |pager|
|
138
|
-
data.each do |entry|
|
139
|
-
output = entry_show(entry, args)
|
140
|
-
|
141
|
-
next if output.blank?
|
142
|
-
|
143
|
-
pager.write("\n#{output}") # write line to the pager
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Array/Hash and String pagination check. Don't unncessarily loop through everything
|
149
|
-
def self.count_rows(data)
|
150
|
-
height = TTY::Screen.height
|
151
|
-
size = 0
|
152
|
-
|
153
|
-
data.each do |entry|
|
154
|
-
size += case entry
|
155
|
-
when Hash then entry.keys.count
|
156
|
-
when Array then entry.count
|
157
|
-
else
|
158
|
-
1
|
159
|
-
end
|
160
|
-
|
161
|
-
break if size > height
|
162
|
-
end
|
163
|
-
|
164
|
-
height > size
|
165
|
-
end
|
166
|
-
|
167
|
-
# Entry Shower
|
168
|
-
def self.entry_show(entry, args)
|
169
|
-
case entry
|
170
|
-
when Hash then render_table(entry, args)
|
171
|
-
when String, Float, Integer then entry
|
172
|
-
when Array
|
173
|
-
entry.map { |x| x.ai(multiline: false) }.join("\n")
|
174
|
-
else
|
175
|
-
LogBot.warn('Shell Show', "Unknown #{entry.class}")
|
176
|
-
nil
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Print the Table in a Nice way
|
181
|
-
def self.render_table(entry, args)
|
182
|
-
table = TTY::Table.new(header: entry.keys, rows: [entry], orientation: :vertical)
|
183
|
-
|
184
|
-
table.render(:unicode, padding: [0, 1, 0, 1]) do |renderer|
|
185
|
-
renderer.border.style = :cyan
|
186
|
-
|
187
|
-
renderer.filter = lambda do |val, _row_index, col_index|
|
188
|
-
if col_index == 1
|
189
|
-
if val.numeric?
|
190
|
-
# TODO: Better Casting?
|
191
|
-
val = val.to_f.round(args.round.first.to_s.to_i) if args.round
|
192
|
-
val.to_s.colorize(:blue)
|
193
|
-
else
|
194
|
-
val.to_s
|
195
|
-
end
|
196
|
-
else
|
197
|
-
val.to_s
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
# Fall Back to Amazing Inspect
|
203
|
-
rescue StandardError => e
|
204
|
-
LogBot.warn('Table', message: e.message, backtrace: e.backtrace.first) if ENV['DEBUG']
|
205
|
-
|
206
|
-
[
|
207
|
-
entry.ai,
|
208
|
-
('_' * (TTY::Screen.width / 3)).colorize(:cyan),
|
209
|
-
"\n"
|
210
|
-
].join("\n")
|
211
|
-
end
|
212
|
-
|
213
|
-
# Main Entry Point for Filtering
|
214
|
-
def self.filter_start(log_list, filter_type, args, opts)
|
215
|
-
# Convert to Things
|
216
|
-
logs = ShellHelper.find_things(log_list, args).select(&:processed?)
|
217
|
-
|
218
|
-
# Ignore Archive/Host Dividers
|
219
|
-
if args[:combine]
|
220
|
-
results = logs.reject(&:blank?).map(&:data).flatten.compact
|
221
|
-
ShellHelper.filter(results, filter_type, args, opts)
|
222
|
-
else
|
223
|
-
# Iterate and Preserve Archive/Host Index
|
224
|
-
logs.each_with_object({}) do |log, obj|
|
225
|
-
# Ignore Empty Results / No Thing
|
226
|
-
next if log&.blank?
|
227
|
-
|
228
|
-
obj[log.friendly_name] = ShellHelper.filter(log.data, filter_type, args, opts)
|
229
|
-
|
230
|
-
obj
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
# Filter Logic
|
236
|
-
# TODO: Simplify
|
237
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
238
|
-
def self.filter(data, type = :all?, args = {}, opts = {})
|
239
|
-
results = data.clone.flatten.compact
|
240
|
-
results.select! do |row|
|
241
|
-
opts.send(type) do |opt|
|
242
|
-
filter_row_key(row, opt)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
# Time Filtering
|
247
|
-
results = filter_time(results, args) if args[:start] || args[:end]
|
248
|
-
|
249
|
-
# Strip Results if Slice is defined
|
250
|
-
results = filter_slice(results, args[:slice]) if args[:slice]
|
251
|
-
|
252
|
-
# Strip Results if Except is defined
|
253
|
-
results = filter_except(results, args[:except]) if args[:except]
|
254
|
-
|
255
|
-
# Remove Blank from either slice or except
|
256
|
-
results.reject!(&:empty?)
|
257
|
-
|
258
|
-
# Sort
|
259
|
-
results.sort_by! { |x| x.slice(*args[:sort]).values } if args[:sort]
|
260
|
-
|
261
|
-
# JSON Formatting
|
262
|
-
results = results.map { |x| Oj.dump(x) } if args[:json]
|
263
|
-
|
264
|
-
# Show Unique Only
|
265
|
-
results = filter_uniq(results, args[:uniq]) if args.key?(:uniq)
|
266
|
-
|
267
|
-
# Reverse
|
268
|
-
results.reverse! if args[:reverse]
|
269
|
-
|
270
|
-
# Count occurrences / Skip Results
|
271
|
-
return filter_stats(results, args[:stats]) if args[:stats]
|
272
|
-
|
273
|
-
# Pluck
|
274
|
-
results = filter_pluck(results, args[:pluck]) if args.key?(:pluck)
|
275
|
-
|
276
|
-
# Limit
|
277
|
-
if args[:limit]
|
278
|
-
results[0..args[:limit].map(&:to_s).join.to_i]
|
279
|
-
else
|
280
|
-
results
|
281
|
-
end
|
282
|
-
end
|
283
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
284
|
-
|
285
|
-
# Filter Start and End Times
|
286
|
-
# rubocop:disable Metrics/MethodLength
|
287
|
-
# TODO: This is a bit icky, simplify/dry
|
288
|
-
def self.filter_time(results, args)
|
289
|
-
if args.start
|
290
|
-
begin
|
291
|
-
time_start = Time.parse(args.start.first.to_s)
|
292
|
-
|
293
|
-
results.select! do |x|
|
294
|
-
if x.time
|
295
|
-
time_start < x.time
|
296
|
-
else
|
297
|
-
true
|
298
|
-
end
|
299
|
-
end
|
300
|
-
rescue StandardError
|
301
|
-
puts 'Unable to Process Start Time Filter'.colorize(:red)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
if args.end
|
306
|
-
begin
|
307
|
-
time_start = Time.parse(args.end.first.to_s)
|
308
|
-
|
309
|
-
results.select! do |x|
|
310
|
-
if x.time
|
311
|
-
time_start > x.time
|
312
|
-
else
|
313
|
-
true
|
314
|
-
end
|
315
|
-
end
|
316
|
-
rescue StandardError
|
317
|
-
puts 'Unable to Process End Time Filter'.colorize(:red)
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
results
|
322
|
-
end
|
323
|
-
# rubocop:enable Metrics/MethodLength
|
324
|
-
|
325
|
-
def self.filter_except(results, except)
|
326
|
-
# Avoid Empty Results
|
327
|
-
if slice.empty?
|
328
|
-
filter_empty_arg('slice')
|
329
|
-
return results
|
330
|
-
end
|
331
|
-
|
332
|
-
results.map { |row| row.except(*except) }
|
333
|
-
end
|
334
|
-
|
335
|
-
def self.filter_slice(results, slice)
|
336
|
-
# Avoid Empty Results
|
337
|
-
if slice.empty?
|
338
|
-
filter_empty_arg('slice')
|
339
|
-
return results
|
340
|
-
end
|
341
|
-
|
342
|
-
results.map { |row| row.slice(*slice) }
|
343
|
-
end
|
344
|
-
|
345
|
-
def self.filter_pluck(results, pluck)
|
346
|
-
# Avoid Empty Results
|
347
|
-
if pluck.empty?
|
348
|
-
filter_empty_arg('pluck')
|
349
|
-
return results
|
350
|
-
end
|
351
|
-
|
352
|
-
results.map { |x| x.slice(*pluck).values }.flatten
|
353
|
-
end
|
354
|
-
|
355
|
-
def self.filter_uniq(results, unique)
|
356
|
-
# Avoid Empty Results
|
357
|
-
if unique.empty?
|
358
|
-
filter_empty_arg('uniq')
|
359
|
-
return results
|
360
|
-
end
|
361
|
-
|
362
|
-
unique.map do |field|
|
363
|
-
results.uniq { |x| x[field] }
|
364
|
-
end.flatten
|
365
|
-
end
|
366
|
-
|
367
|
-
def self.filter_stats(results, stats)
|
368
|
-
# Avoid Empty Results
|
369
|
-
if stats.empty?
|
370
|
-
filter_empty_arg('stats')
|
371
|
-
return results
|
372
|
-
end
|
373
|
-
|
374
|
-
stats.map do |stat|
|
375
|
-
occurrences = filter_count_occurrences(results, stat)
|
376
|
-
occurrences.sort_by(&:last).to_h
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
# Helper to Count occurrences
|
381
|
-
def self.filter_count_occurrences(results, stat)
|
382
|
-
results.each_with_object(Hash.new(0)) do |entry, counts|
|
383
|
-
next unless entry.key? stat
|
384
|
-
|
385
|
-
counts[entry[stat]] += 1
|
386
|
-
|
387
|
-
counts
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
def self.filter_empty_arg(arg)
|
392
|
-
puts [
|
393
|
-
'Ignoring'.colorize(:light_yellow),
|
394
|
-
"--#{arg}".colorize(:cyan),
|
395
|
-
'it requires an argument'.colorize(:red)
|
396
|
-
].join(' ')
|
397
|
-
end
|
398
|
-
|
399
|
-
# Break out filter row logic into separate method
|
400
|
-
def self.filter_row_key(row, param)
|
401
|
-
# Ignore Other Logic if Field isn't even included
|
402
|
-
return false unless row.key? param.field
|
403
|
-
|
404
|
-
# Not Included Param
|
405
|
-
included = row[param.field].to_s.include? param.value.to_s
|
406
|
-
|
407
|
-
if param.bang
|
408
|
-
!included
|
409
|
-
else
|
410
|
-
included
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
# Total Count Helper
|
415
|
-
def self.total_count(results)
|
416
|
-
results.each do |k, v|
|
417
|
-
puts k
|
418
|
-
puts "Total: #{v.count.to_s.colorize(:blue)}"
|
419
|
-
puts
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
# Total Log List Manipulator
|
424
|
-
def self.prepare_list(log_list, base_list = nil)
|
425
|
-
base_list ||= GreenHat::ShellHelper::Log.list
|
426
|
-
|
427
|
-
# Assume all
|
428
|
-
log_list.push '*' if log_list.empty?
|
429
|
-
|
430
|
-
# Map for All
|
431
|
-
log_list = base_list.map(&:name) if log_list == ['*']
|
432
|
-
|
433
|
-
log_list
|
434
|
-
end
|
435
|
-
|
436
|
-
# Shortcut find things
|
437
|
-
def self.find_things(log_list, args = {})
|
438
|
-
things = log_list.uniq.flat_map do |log|
|
439
|
-
Thing.where name: log
|
440
|
-
end
|
441
|
-
|
442
|
-
# Host / Archive
|
443
|
-
things.select! { |x| x.archive? args.archive } if args.archive
|
444
|
-
|
445
|
-
things
|
446
|
-
end
|
447
|
-
|
448
|
-
# Main Entry Point for Searching
|
449
|
-
def self.search_start(log_list, filter_type, args, opts)
|
450
|
-
# Convert to Things
|
451
|
-
logs = ShellHelper.find_things(log_list, args)
|
452
|
-
|
453
|
-
logs.each_with_object({}) do |log, obj|
|
454
|
-
# Ignore Empty Results / No Thing
|
455
|
-
next if log&.data.blank?
|
456
|
-
|
457
|
-
obj[log.friendly_name] = ShellHelper.search(log.data, filter_type, args, opts)
|
458
|
-
|
459
|
-
obj
|
460
|
-
end
|
461
|
-
end
|
462
|
-
|
463
|
-
# Generic Search Helper / String/Regex
|
464
|
-
def self.search(data, type = :all?, args = {}, opts = {})
|
465
|
-
results = data.clone.flatten.compact
|
466
|
-
|
467
|
-
results.select! do |row|
|
468
|
-
opts.send(type) do |opt|
|
469
|
-
search_row(row, opt)
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
# Strip Results if Slice is defined
|
474
|
-
results.map! { |row| row.slice(*args[:slice]) } if args[:slice]
|
475
|
-
|
476
|
-
# Strip Results if Except is defined
|
477
|
-
results.map! { |row| row.except(*args[:except]) } if args[:except]
|
478
|
-
|
479
|
-
# Remove Blank from either slice or except
|
480
|
-
results.reject!(&:empty?)
|
481
|
-
|
482
|
-
results
|
483
|
-
end
|
484
|
-
|
485
|
-
# Break out filter row logic into separate method
|
486
|
-
def self.search_row(row, param)
|
487
|
-
# Not Included Param
|
488
|
-
included = row.to_s.include? param.value
|
489
|
-
|
490
|
-
if param.bang
|
491
|
-
!included
|
492
|
-
else
|
493
|
-
included
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
# Color Reader Helper
|
498
|
-
def self.pastel
|
499
|
-
@pastel ||= Pastel.new
|
500
|
-
end
|
501
|
-
|
502
|
-
# Number Helper
|
503
|
-
# https://gitlab.com/zedtux/human_size_to_number/-/blob/master/lib/human_size_to_number/helper.rb
|
504
|
-
def self.human_size_to_number(string)
|
505
|
-
size, unit = string.scan(/(\d*\.?\d+)\s?(Bytes?|KB|MB|GB|TB)/i).first
|
506
|
-
number = size.to_f
|
507
|
-
|
508
|
-
number = case unit.downcase
|
509
|
-
when 'byte', 'bytes'
|
510
|
-
number
|
511
|
-
when 'kb'
|
512
|
-
number * 1024
|
513
|
-
when 'mb'
|
514
|
-
number * 1024 * 1024
|
515
|
-
when 'gb'
|
516
|
-
number * 1024 * 1024 * 1024
|
517
|
-
when 'tb'
|
518
|
-
number * 1024 * 1024 * 1024 * 1024
|
519
|
-
end
|
520
|
-
number.round
|
521
|
-
end
|
522
|
-
|
523
|
-
# TODO: Needed?
|
524
|
-
def self.filter_and(data, params = {})
|
525
|
-
result = data.clone.flatten.compact
|
526
|
-
params.each do |k, v|
|
527
|
-
result.select! do |row|
|
528
|
-
if row.key? k.to_sym
|
529
|
-
row[k.to_sym].include? v
|
530
|
-
else
|
531
|
-
false
|
532
|
-
end
|
533
|
-
end
|
534
|
-
next
|
535
|
-
end
|
536
|
-
|
537
|
-
result
|
538
|
-
end
|
539
|
-
end
|
540
|
-
# rubocop:enable Metrics/ModuleLength
|
541
|
-
end
|