greenhat 0.3.4 → 0.5.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 +4 -4
- data/bin/greenhat +2 -6
- data/lib/greenhat/accessors/disk.rb +1 -3
- data/lib/greenhat/accessors/gitlab.rb +7 -2
- data/lib/greenhat/accessors/memory.rb +1 -1
- data/lib/greenhat/archive.rb +19 -8
- data/lib/greenhat/cli.rb +35 -135
- data/lib/greenhat/entrypoint.rb +170 -0
- data/lib/greenhat/host.rb +25 -37
- data/lib/greenhat/settings.rb +33 -5
- data/lib/greenhat/shell/args.rb +22 -9
- data/lib/greenhat/shell/faststats.rb +23 -3
- data/lib/greenhat/shell/field_helper.rb +1 -1
- data/lib/greenhat/shell/filter_help.rb +217 -162
- data/lib/greenhat/shell/gitlab.rb +1 -0
- data/lib/greenhat/shell/log.rb +150 -25
- data/lib/greenhat/shell/markdown.rb +21 -25
- data/lib/greenhat/shell/old_search_helper.rb +54 -0
- data/lib/greenhat/shell/page.rb +1 -1
- data/lib/greenhat/shell/pipe.rb +31 -0
- data/lib/greenhat/shell/platform.rb +28 -0
- data/lib/greenhat/shell/query.rb +378 -0
- data/lib/greenhat/shell/report.rb +76 -24
- data/lib/greenhat/shell/shell_helper.rb +42 -393
- data/lib/greenhat/shell.rb +19 -4
- data/lib/greenhat/thing/file_types.rb +51 -1
- data/lib/greenhat/thing/formatters/api_json.rb +4 -2
- data/lib/greenhat/thing/formatters/bracket_log.rb +1 -1
- data/lib/greenhat/thing/formatters/colon_split_strip.rb +2 -2
- data/lib/greenhat/thing/formatters/dotenv.rb +1 -1
- data/lib/greenhat/thing/formatters/format.rb +0 -11
- data/lib/greenhat/thing/formatters/free_m.rb +2 -2
- data/lib/greenhat/thing/formatters/json.rb +43 -15
- data/lib/greenhat/thing/formatters/json_shellwords.rb +3 -2
- data/lib/greenhat/thing/formatters/kube_json.rb +3 -2
- data/lib/greenhat/thing/formatters/multiline_json.rb +1 -1
- data/lib/greenhat/thing/formatters/nginx.rb +11 -3
- data/lib/greenhat/thing/formatters/table.rb +3 -3
- data/lib/greenhat/thing/formatters/time_space.rb +0 -16
- data/lib/greenhat/thing/helpers.rb +12 -11
- data/lib/greenhat/thing/info_format.rb +4 -4
- data/lib/greenhat/thing/kind.rb +5 -0
- data/lib/greenhat/thing/super_log.rb +0 -101
- data/lib/greenhat/thing.rb +31 -25
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat/views/api.slim +55 -0
- data/lib/greenhat/views/chart.slim +42 -0
- data/lib/greenhat/views/chart_template.slim +31 -0
- data/lib/greenhat/views/chartkick.js +21 -0
- data/lib/greenhat/views/css.slim +47 -0
- data/lib/greenhat/views/gitaly.slim +53 -0
- data/lib/greenhat/views/headers.slim +16 -0
- data/lib/greenhat/views/index-old.slim +51 -0
- data/lib/greenhat/views/index.slim +14 -14
- data/lib/greenhat/views/info.slim +17 -18
- data/lib/greenhat/views/production.slim +55 -0
- data/lib/greenhat/views/sidekiq.slim +55 -0
- data/lib/greenhat/views/time.slim +63 -0
- data/lib/greenhat/views/workhorse.slim +16 -0
- data/lib/greenhat/web/api.rb +94 -0
- data/lib/greenhat/web/chartkick_shim.rb +14 -0
- data/lib/greenhat/web/faststats.rb +44 -0
- data/lib/greenhat/web/gitaly.rb +65 -0
- data/lib/greenhat/web/helpers.rb +198 -0
- data/lib/greenhat/web/production.rb +104 -0
- data/lib/greenhat/web/sidekiq.rb +73 -0
- data/lib/greenhat/web/stats_helpers.rb +74 -0
- data/lib/greenhat/web/time.rb +36 -0
- data/lib/greenhat/web/workhorse.rb +43 -0
- data/lib/greenhat/web.rb +63 -19
- data/lib/greenhat.rb +2 -0
- metadata +74 -5
data/lib/greenhat/shell/log.rb
CHANGED
@@ -2,7 +2,9 @@ module GreenHat
|
|
2
2
|
# CLI Helper
|
3
3
|
module Shell
|
4
4
|
# Logs
|
5
|
+
# rubocop:disable Metrics/ModuleLength
|
5
6
|
module Log
|
7
|
+
extend Spinner # TODO: DEBUGGING REMOVE
|
6
8
|
def self.auto_complete(list, word)
|
7
9
|
# Argument Parsing
|
8
10
|
files, flags, _args = Args.parse(list)
|
@@ -19,8 +21,8 @@ module GreenHat
|
|
19
21
|
elsif matches.count > 1
|
20
22
|
puts "#{'Filter Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
|
21
23
|
"--#{Cli.common_substr(matches)}"
|
22
|
-
|
23
|
-
|
24
|
+
# -----------------------------------
|
25
|
+
# TODO: Fix Icky Double Nesting
|
24
26
|
elsif files.count.nonzero?
|
25
27
|
matches = FieldHelper.fields_find(files, word, flags)
|
26
28
|
|
@@ -58,25 +60,30 @@ module GreenHat
|
|
58
60
|
puts " General full text by file searching. See #{'search_help'.pastel(:blue)}"
|
59
61
|
puts
|
60
62
|
|
63
|
+
puts ' save'.pastel(:green)
|
64
|
+
puts ' Save the last query result into a new searchable object'
|
65
|
+
puts
|
66
|
+
|
67
|
+
puts ' write'.pastel(:green)
|
68
|
+
puts ' Write the last query result into a local file'
|
69
|
+
puts
|
70
|
+
|
71
|
+
puts ' visualize'.pastel(:green)
|
72
|
+
puts ' Load web services and formulate last query for the UI'
|
73
|
+
puts
|
74
|
+
|
61
75
|
puts ShellHelper::List.help
|
62
76
|
|
63
77
|
puts "See #{'examples'.pastel(:bright_blue)} for query examples"
|
64
78
|
end
|
65
79
|
|
66
|
-
def self.filter_help(
|
67
|
-
|
68
|
-
|
69
|
-
else
|
70
|
-
list = ShellHelper::Filter.help_index.select do |k, _v|
|
71
|
-
k.to_s.include? args.first
|
72
|
-
end
|
73
|
-
|
74
|
-
puts list.values.map { |x| x.join("\n") }.join("\n\n")
|
75
|
-
end
|
80
|
+
def self.filter_help(raw = {})
|
81
|
+
args, flags, _args = Args.parse(raw)
|
82
|
+
ShellHelper.show(ShellHelper::Filter.help(args.first), flags)
|
76
83
|
end
|
77
84
|
|
78
85
|
def self.ls(args = [])
|
79
|
-
ShellHelper::List.list(args,
|
86
|
+
ShellHelper::List.list(args, Thing.list)
|
80
87
|
end
|
81
88
|
|
82
89
|
def self.show(raw = {})
|
@@ -89,6 +96,95 @@ module GreenHat
|
|
89
96
|
ShellHelper.show files.map(&:data).flatten
|
90
97
|
end
|
91
98
|
|
99
|
+
def self.save(raw = [])
|
100
|
+
if ShellHelper::Log.last.nil?
|
101
|
+
puts 'No previous query found'.pastel(:red)
|
102
|
+
puts 'Run a query first then save to store as a new log'
|
103
|
+
puts
|
104
|
+
puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'save'.pastel(:green)}"
|
105
|
+
true
|
106
|
+
end
|
107
|
+
|
108
|
+
name = if raw.empty?
|
109
|
+
Cli.prompt.ask('Log/name to save the results to? '.pastel(:yellow))
|
110
|
+
else
|
111
|
+
raw.first
|
112
|
+
end
|
113
|
+
|
114
|
+
if name.blank?
|
115
|
+
puts 'Name required'.pastel(:red)
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
|
119
|
+
results = ShellHelper.filter_internal ShellHelper::Log.last
|
120
|
+
|
121
|
+
# Don't save empty results
|
122
|
+
if results.empty?
|
123
|
+
puts 'No results'.pastel(:red)
|
124
|
+
ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
|
128
|
+
Thing.new.query_save(results, name)
|
129
|
+
puts "#{name.pastel(:green)} Saved!"
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.write(raw = [])
|
133
|
+
if ShellHelper::Log.last.nil?
|
134
|
+
puts 'No previous query found'.pastel(:red)
|
135
|
+
puts 'Run a query first then write'
|
136
|
+
puts
|
137
|
+
puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'save'.pastel(:green)}"
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
name = if raw.empty?
|
142
|
+
Cli.prompt.ask('Log/name to save the results to? '.pastel(:yellow))
|
143
|
+
else
|
144
|
+
raw.first
|
145
|
+
end
|
146
|
+
|
147
|
+
if name.blank?
|
148
|
+
puts 'Name required'.pastel(:red)
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
|
152
|
+
results = ShellHelper.filter_internal ShellHelper::Log.last
|
153
|
+
|
154
|
+
# Don't save empty results
|
155
|
+
if results.empty?
|
156
|
+
puts 'No results'.pastel(:red)
|
157
|
+
ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
|
158
|
+
return false
|
159
|
+
end
|
160
|
+
|
161
|
+
all = results.map { |row| Oj.dump(row) }
|
162
|
+
File.write(name, all.join("\n"))
|
163
|
+
puts "#{name.pastel(:green)} File Written!"
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.visualize
|
167
|
+
if ShellHelper::Log.last.nil?
|
168
|
+
puts 'No previous query found'.pastel(:red)
|
169
|
+
puts 'Run a query first then visualize to load it in the chart web page'
|
170
|
+
puts
|
171
|
+
puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'visualize'.pastel(:green)}"
|
172
|
+
return true
|
173
|
+
end
|
174
|
+
|
175
|
+
# Load Required Files
|
176
|
+
require 'greenhat/web'
|
177
|
+
|
178
|
+
unless GreenHat::Web.alive?
|
179
|
+
GreenHat::Web.start
|
180
|
+
sleep 0.2
|
181
|
+
end
|
182
|
+
|
183
|
+
url = "http://localhost:4567/chart/time?query=#{CGI.escape(ShellHelper::Log.last)}"
|
184
|
+
|
185
|
+
GreenHat::Platform.open url
|
186
|
+
end
|
187
|
+
|
92
188
|
# ========================================================================
|
93
189
|
# Filter (See Filter Help)
|
94
190
|
# ========================================================================
|
@@ -99,21 +195,23 @@ module GreenHat
|
|
99
195
|
def self.filter(raw)
|
100
196
|
# Print Helper
|
101
197
|
if raw == ['help']
|
102
|
-
filter_help
|
198
|
+
filter_help(raw)
|
103
199
|
return true
|
104
200
|
end
|
105
201
|
|
202
|
+
ShellHelper::Log.last = raw
|
203
|
+
|
106
204
|
# Argument Parsing
|
107
205
|
files, flags, args = Args.parse(raw)
|
108
206
|
|
109
207
|
# Prepare Log List
|
110
|
-
files = ShellHelper.prepare_list(files
|
208
|
+
files = ShellHelper.prepare_list(files)
|
111
209
|
|
112
|
-
results =
|
210
|
+
results = Query.start(files, flags, args)
|
113
211
|
|
114
212
|
# Skip and Print Total if set
|
115
213
|
if flags[:total]
|
116
|
-
ShellHelper.total_count(results)
|
214
|
+
ShellHelper.total_count(results, flags)
|
117
215
|
return true
|
118
216
|
end
|
119
217
|
|
@@ -126,13 +224,13 @@ module GreenHat
|
|
126
224
|
# Check Search Results
|
127
225
|
if results.instance_of?(Hash) && results.values.flatten.empty?
|
128
226
|
puts 'No results'.pastel(:red)
|
227
|
+
ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
|
228
|
+
elsif flags[:pipe]
|
229
|
+
Pipe.show(results, flags[:pipe])
|
129
230
|
else
|
130
231
|
# This causes the key 'colorized' output to also be included
|
131
232
|
ShellHelper.show(results.to_a.compact.flatten, flags)
|
132
233
|
end
|
133
|
-
|
134
|
-
# log filter --path='cloud/gitlab-automation' --path='/pull' --all
|
135
|
-
# log filter --project=thingy --other_filter=asdf *
|
136
234
|
rescue StandardError => e
|
137
235
|
LogBot.fatal('Filter', message: e.message)
|
138
236
|
ap e.backtrace
|
@@ -161,9 +259,25 @@ module GreenHat
|
|
161
259
|
puts 'Count/% occurences for both user and remote ip fields'.pastel(:bright_green)
|
162
260
|
puts 'gitlab-rails/api_json.log --stats=meta.user,meta.remote_ip --exists=meta.user'
|
163
261
|
puts
|
164
|
-
end
|
165
262
|
|
263
|
+
puts 'Sidekiq jobs that took over 5 seconds excluding LdapSyncWorker jobs'.pastel(:bright_green)
|
264
|
+
puts 'sidekiq/current --duration_s>=5 --class!=LdapSyncWorker'
|
265
|
+
puts
|
266
|
+
|
267
|
+
puts 'Search access logs for runner requests, exclude specific runner version'.pastel(:bright_green)
|
268
|
+
puts 'nginx/gitlab_access.log --http_user_agent=gitlab-runner --http_user_agent!=13.12.0'
|
269
|
+
puts
|
270
|
+
|
271
|
+
puts 'Get a list of unique Gitaly error messages for a specific project'.pastel(:bright_green)
|
272
|
+
puts 'filter --level=error --grpc.request.glProjectPath=path/to/project gitaly/current --slice=error --uniq=error'
|
273
|
+
puts
|
274
|
+
|
275
|
+
puts 'Show workhorse duration/URI. Filter by duration bounds'.pastel(:bright_green)
|
276
|
+
puts 'gitlab-workhorse/current --duration_ms>=30000 --duration_ms<=45000 --slice=duration_ms,uri'
|
277
|
+
puts
|
278
|
+
end
|
166
279
|
# rubocop:enable Layout/LineLength
|
280
|
+
|
167
281
|
# ========================================================================
|
168
282
|
# Search (Full Text / String Search)
|
169
283
|
# ========================================================================
|
@@ -178,13 +292,14 @@ module GreenHat
|
|
178
292
|
|
179
293
|
# Skip and Print Total if set
|
180
294
|
if flags[:total]
|
181
|
-
ShellHelper.total_count(results)
|
295
|
+
ShellHelper.total_count(results, flags)
|
182
296
|
return true
|
183
297
|
end
|
184
298
|
|
185
299
|
# Check Search Results
|
186
300
|
if results.values.flatten.empty?
|
187
301
|
puts 'No results'.pastel(:red)
|
302
|
+
ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
|
188
303
|
else
|
189
304
|
# This causes the key 'colorized' output to also be included
|
190
305
|
ShellHelper.show(results.to_a.compact.flatten, flags)
|
@@ -249,7 +364,7 @@ module GreenHat
|
|
249
364
|
puts 'log search --text=BuildHooksWorker --text!=start --slice=enqueued_at sidekiq/current'
|
250
365
|
puts
|
251
366
|
end
|
252
|
-
# rubocop:enable Metrics/MethodLength
|
367
|
+
# rubocop:enable Metrics/MethodLength,Metrics/ModuleLength
|
253
368
|
|
254
369
|
# ------------------------------------------------------------------------
|
255
370
|
end
|
@@ -260,10 +375,20 @@ module GreenHat
|
|
260
375
|
module ShellHelper
|
261
376
|
# Log Helpers
|
262
377
|
module Log
|
263
|
-
def self.
|
264
|
-
|
378
|
+
def self.last=(value)
|
379
|
+
@last = value.join(' ')
|
380
|
+
end
|
381
|
+
|
382
|
+
def self.last
|
383
|
+
@last
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.no_files_warning(files)
|
387
|
+
puts "No matching files found for pattern #{files.to_s.pastel(:yellow)}"
|
388
|
+
puts "See #{'ls'.pastel(:blue)} for available files"
|
265
389
|
end
|
266
390
|
end
|
391
|
+
|
267
392
|
# --------
|
268
393
|
end
|
269
394
|
end
|
@@ -58,6 +58,9 @@ module GreenHat
|
|
58
58
|
''
|
59
59
|
]
|
60
60
|
|
61
|
+
# GitLab Version
|
62
|
+
output << "**GitLab #{gitlab_version}**\n" if gitlab_manifest || gitlab_status
|
63
|
+
|
61
64
|
# OS
|
62
65
|
output << "**OS**\n"
|
63
66
|
|
@@ -79,8 +82,6 @@ module GreenHat
|
|
79
82
|
end
|
80
83
|
|
81
84
|
# Gitlab
|
82
|
-
output << "**GitLab**\n" if gitlab_manifest || gitlab_status
|
83
|
-
output << gitlab_version if gitlab_manifest
|
84
85
|
output << gitlab_services if gitlab_status
|
85
86
|
|
86
87
|
output << ''
|
@@ -127,8 +128,11 @@ module GreenHat
|
|
127
128
|
output << exception_errors if exceptions_log
|
128
129
|
output << gitaly_errors if gitaly_log
|
129
130
|
|
130
|
-
# Keep Alphabetical Sort
|
131
|
-
|
131
|
+
# Keep Alphabetical Sort / Allow for only one
|
132
|
+
slice_size = (output.size / 3.to_f).round
|
133
|
+
slice_size = 1 unless slice_size.positive?
|
134
|
+
|
135
|
+
groups = output.each_slice(slice_size).to_a
|
132
136
|
|
133
137
|
table = TTY::Table.new do |t|
|
134
138
|
loop do
|
@@ -169,7 +173,8 @@ module GreenHat
|
|
169
173
|
results = ShellHelper.filter_internal([
|
170
174
|
'gitlab-rails/application_json.log',
|
171
175
|
'--message!="Cannot obtain an exclusive lease"',
|
172
|
-
'--severity=error'
|
176
|
+
'--severity=error',
|
177
|
+
"--archive=#{archive.name}"
|
173
178
|
].join(' '))
|
174
179
|
|
175
180
|
"Application: #{results.count}"
|
@@ -192,7 +197,13 @@ module GreenHat
|
|
192
197
|
end
|
193
198
|
|
194
199
|
def gitlab_version
|
195
|
-
|
200
|
+
txt = gitlab_manifest.data.dig(:software, :'gitlab-rails', :display_version) || gitlab_manifest.data.build_version
|
201
|
+
|
202
|
+
if txt.include? '-ce'
|
203
|
+
txt += ' - [😱 CE](https://about.gitlab.com/support/statement-of-support.html#free-and-community-edition-users)!'
|
204
|
+
end
|
205
|
+
|
206
|
+
"Version: #{txt}"
|
196
207
|
end
|
197
208
|
|
198
209
|
def hostname
|
@@ -285,21 +296,6 @@ module GreenHat
|
|
285
296
|
].join
|
286
297
|
end
|
287
298
|
|
288
|
-
# def memory_perc
|
289
|
-
# total = ShellHelper.human_size_to_number(meminfo.data['MemTotal'])
|
290
|
-
# free = ShellHelper.human_size_to_number(meminfo.data['MemFree'])
|
291
|
-
# used = percent((total - free), total)
|
292
|
-
|
293
|
-
# [
|
294
|
-
# title('Usage'),
|
295
|
-
# ' ['.pastel(:bright_black),
|
296
|
-
# '='.pastel(:green) * (used / 2),
|
297
|
-
# ' ' * (50 - used / 2),
|
298
|
-
# ']'.pastel(:bright_black),
|
299
|
-
# " #{100 - percent(free, total)}%".pastel(:green) # Inverse
|
300
|
-
# ].join
|
301
|
-
# end
|
302
|
-
|
303
299
|
def memory_free
|
304
300
|
free = free_m.data.find { |x| x.kind == 'Mem' }
|
305
301
|
|
@@ -307,10 +303,10 @@ module GreenHat
|
|
307
303
|
|
308
304
|
pad = 6
|
309
305
|
list = [
|
310
|
-
"#{title('Total', pad)} #{number_to_human_size(free.total.to_i * 1024**2)}",
|
311
|
-
"#{title('Used', pad)} #{number_to_human_size(free.used.to_i * 1024**2)}",
|
312
|
-
"#{title('Free', pad)} #{number_to_human_size(free.free.to_i * 1024**2)}",
|
313
|
-
"#{title('Avail', pad)} #{number_to_human_size(free.available.to_i * 1024**2)}"
|
306
|
+
"#{title('Total', pad)} #{number_to_human_size(free.total.to_i * (1024**2))}",
|
307
|
+
"#{title('Used', pad)} #{number_to_human_size(free.used.to_i * (1024**2))}",
|
308
|
+
"#{title('Free', pad)} #{number_to_human_size(free.free.to_i * (1024**2))}",
|
309
|
+
"#{title('Avail', pad)} #{number_to_human_size(free.available.to_i * (1024**2))}"
|
314
310
|
]
|
315
311
|
|
316
312
|
# Keep Alphabetical Sort
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# Deprecating search stuff
|
3
|
+
module ShellHelper
|
4
|
+
# Main Entry Point for Searching
|
5
|
+
# def self.search_start(log_list, filter_type, args, opts)
|
6
|
+
def self.search_start(files, flags, args)
|
7
|
+
# Convert to Things
|
8
|
+
logs = ShellHelper.find_things(files, flags)
|
9
|
+
|
10
|
+
logs.each_with_object({}) do |log, obj|
|
11
|
+
# Ignore Empty Results / No Thing
|
12
|
+
next if log&.data.blank?
|
13
|
+
|
14
|
+
obj[log.friendly_name] = ShellHelper.search(log.data, flags, args)
|
15
|
+
|
16
|
+
obj
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generic Search Helper / String/Regex
|
21
|
+
def self.search(data, flags = {}, args = {})
|
22
|
+
results = data.clone.flatten.compact
|
23
|
+
results.select! do |row|
|
24
|
+
args.send(flags.logic) do |arg|
|
25
|
+
search_row(row, arg, flags)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Strip Results if Slice is defined
|
30
|
+
results.map! { |row| row.slice(*flags[:slice]) } if flags[:slice]
|
31
|
+
|
32
|
+
# Strip Results if Except is defined
|
33
|
+
results.map! { |row| row.except(*flags[:except]) } if flags[:except]
|
34
|
+
|
35
|
+
# Remove Blank from either slice or except
|
36
|
+
results.reject!(&:empty?)
|
37
|
+
|
38
|
+
results
|
39
|
+
end
|
40
|
+
|
41
|
+
# Break out filter row logic into separate method
|
42
|
+
def self.search_row(row, arg, flags)
|
43
|
+
# Sensitivity Check / Check for Match
|
44
|
+
included = filter_row_entry(row.to_s, arg, flags)
|
45
|
+
|
46
|
+
# Pivot of off include vs exclude
|
47
|
+
if arg.bang
|
48
|
+
!included
|
49
|
+
else
|
50
|
+
included
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/greenhat/shell/page.rb
CHANGED
@@ -8,7 +8,7 @@ module GreenHat
|
|
8
8
|
# Pass if Explicitly Set / Inverse for skip
|
9
9
|
return !flags[:page] if flags.key? :page
|
10
10
|
|
11
|
-
LogBot.debug('Page', count_rows(data, flags)) if ENV['DEBUG']
|
11
|
+
LogBot.debug('Page Skip', count_rows(data, flags)) if ENV['DEBUG']
|
12
12
|
|
13
13
|
count_rows(data, flags)
|
14
14
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# Helper for piping arguments
|
3
|
+
module Pipe
|
4
|
+
def self.show(results, arg)
|
5
|
+
uuid = SecureRandom.uuid # File Placeholder
|
6
|
+
write(results, uuid)
|
7
|
+
command(uuid, arg)
|
8
|
+
delete(uuid)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Final execution into pipe
|
12
|
+
def self.command(uuid, arg)
|
13
|
+
puts `cat "#{file(uuid)}" | #{arg}`
|
14
|
+
end
|
15
|
+
|
16
|
+
# File path helper
|
17
|
+
def self.file(uuid)
|
18
|
+
"#{$TMP}/#{uuid}.txt"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Helper to write all into split lines for pipe
|
22
|
+
def self.write(results, uuid)
|
23
|
+
File.write(file(uuid), results.map(&:flatten).flatten.join("\n"))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Clean up created file
|
27
|
+
def self.delete(uuid)
|
28
|
+
File.delete file(uuid)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# Common Helpers
|
3
|
+
module Platform
|
4
|
+
def self.platform
|
5
|
+
if @platform
|
6
|
+
@platform
|
7
|
+
else
|
8
|
+
require 'tty-platform'
|
9
|
+
@platform ||= TTY::Platform.new
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.open(url = 'http://localhost:4567/chart/time')
|
15
|
+
cmd = if platform.linux? || platform.unix?
|
16
|
+
'xdg-open'
|
17
|
+
elsif platform.mac?
|
18
|
+
'open'
|
19
|
+
end
|
20
|
+
|
21
|
+
# platform.windows? # => false
|
22
|
+
# platform.unix? # => true
|
23
|
+
# platform.linux? # => false
|
24
|
+
# platform.mac? # => true
|
25
|
+
system("#{cmd} '#{url}'")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|