greenhat 0.2.0 → 0.3.3
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 +13 -13
- data/lib/greenhat/accessors/gitlab.rb +75 -0
- data/lib/greenhat/accessors/memory.rb +10 -10
- data/lib/greenhat/accessors/process.rb +4 -0
- data/lib/greenhat/cli.rb +147 -58
- data/lib/greenhat/color.rb +27 -0
- data/lib/greenhat/logbot.rb +9 -9
- data/lib/greenhat/settings.rb +27 -7
- data/lib/greenhat/shell/args.rb +146 -0
- data/lib/greenhat/shell/cat.rb +25 -73
- data/lib/greenhat/shell/color_string.rb +8 -8
- data/lib/greenhat/shell/disk.rb +31 -4
- data/lib/greenhat/shell/faststats.rb +103 -56
- 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 +118 -104
- data/lib/greenhat/shell/page.rb +11 -5
- data/lib/greenhat/shell/process.rb +29 -17
- data/lib/greenhat/shell/report.rb +37 -47
- data/lib/greenhat/shell/shell_helper.rb +661 -0
- data/lib/greenhat/shell.rb +23 -9
- data/lib/greenhat/thing/file_types.rb +31 -5
- data/lib/greenhat/thing/formatters/json_shellwords.rb +0 -3
- data/lib/greenhat/thing/formatters/nginx.rb +44 -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 +4 -0
- data/lib/greenhat/version.rb +1 -1
- data/lib/greenhat.rb +15 -14
- metadata +38 -18
- data/lib/greenhat/shell/filter.rb +0 -128
- data/lib/greenhat/shell/helper.rb +0 -584
@@ -0,0 +1,75 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# Common Helpers
|
3
|
+
module FieldHelper
|
4
|
+
def self.fields_find(files, word, flags = {})
|
5
|
+
fields = ShellHelper.find_things(files, flags).map(&:fields).flatten.uniq
|
6
|
+
|
7
|
+
if word.blank?
|
8
|
+
puts 'Possible Fields:'.pastel(:bright_blue)
|
9
|
+
puts ShellHelper.field_table(fields)
|
10
|
+
|
11
|
+
return [] # Empty Result
|
12
|
+
end
|
13
|
+
|
14
|
+
list_select(fields, word)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.list_select(list, word)
|
18
|
+
list.select! { |x| x[/^#{Regexp.escape(word)}/] }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.filter_flags(word)
|
22
|
+
if word.blank?
|
23
|
+
puts 'Filter Options:'.pastel(:bright_blue)
|
24
|
+
puts ShellHelper.field_table(filter_opts, 6)
|
25
|
+
puts
|
26
|
+
|
27
|
+
return []
|
28
|
+
end
|
29
|
+
|
30
|
+
list_select(filter_opts, word)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.filter_opts
|
34
|
+
%w[
|
35
|
+
archive case combine end exact except exists json limit or page pluck
|
36
|
+
raw reverse round slice sort start stats table_style text time_zone
|
37
|
+
total truncate uniq
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.filter_auto_completes
|
42
|
+
%w[
|
43
|
+
except exists pluck slice sort stats uniq
|
44
|
+
]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.field_auto_complete?(word)
|
48
|
+
return false if word.blank?
|
49
|
+
|
50
|
+
filter_auto_completes.include? word.split('=', 2).first
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.field_auto_complete(word, files, flags = {})
|
54
|
+
# Prevent weird dupes
|
55
|
+
return nil if word[-1] == ','
|
56
|
+
|
57
|
+
# Command Manipulation
|
58
|
+
cmd, fields = word.split('=', 2)
|
59
|
+
complete = fields.split(',')[0..-2]
|
60
|
+
auto = fields.split(',').last
|
61
|
+
|
62
|
+
# Field Finder
|
63
|
+
matches = fields_find(files, auto, flags)
|
64
|
+
|
65
|
+
if matches.count == 1
|
66
|
+
"--#{cmd}=#{(complete + matches).join(',')}"
|
67
|
+
elsif matches.count > 1
|
68
|
+
puts "#{'Field Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
|
69
|
+
|
70
|
+
list = [Cli.common_substr(matches.map(&:to_s))]
|
71
|
+
"--#{cmd}=#{(complete + list).join(',')}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module GreenHat
|
2
|
+
# CLI Helper
|
3
|
+
module ShellHelper
|
4
|
+
# Unify Filter / Filter Help
|
5
|
+
module Filter
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
7
|
+
def self.help
|
8
|
+
puts "\u2500".pastel(:cyan) * 20
|
9
|
+
puts 'Filter'.pastel(:yellow)
|
10
|
+
puts "\u2500".pastel(:cyan) * 20
|
11
|
+
|
12
|
+
puts 'Options'.pastel(:blue)
|
13
|
+
puts '--raw'.pastel(:green)
|
14
|
+
puts ' Disable formatting and page/less'
|
15
|
+
puts
|
16
|
+
|
17
|
+
puts '--page'.pastel(:green)
|
18
|
+
puts ' Specifically enable or disable paging'
|
19
|
+
puts ' E.g. --page (default to true), --page=true, --page=false'
|
20
|
+
puts
|
21
|
+
|
22
|
+
puts '--round'.pastel(:green)
|
23
|
+
puts ' Attempt to round all integers. Default: 2.'
|
24
|
+
puts ' E.g. --round, --round=3, --round=0'
|
25
|
+
puts
|
26
|
+
|
27
|
+
puts '--limit'.pastel(:green)
|
28
|
+
puts ' Limit total output lines. Disabled by default. Default without value is based on screen height'
|
29
|
+
puts ' E.g. --limit, --limit=5'
|
30
|
+
puts
|
31
|
+
|
32
|
+
puts '--json'.pastel(:green)
|
33
|
+
puts ' Print output back into JSON'
|
34
|
+
puts
|
35
|
+
|
36
|
+
puts '--or'.pastel(:green)
|
37
|
+
puts ' Filters will use OR instead of AND (all match vs any match)'
|
38
|
+
puts
|
39
|
+
|
40
|
+
puts '--total'.pastel(:green)
|
41
|
+
puts ' Print only total count of matching entries'
|
42
|
+
puts
|
43
|
+
|
44
|
+
puts '--fields'.pastel(:green)
|
45
|
+
puts ' Print only Available fields for selected files'
|
46
|
+
puts
|
47
|
+
|
48
|
+
puts '--slice'.pastel(:green)
|
49
|
+
puts ' Extract specific fields from entries (slice multiple with comma)'
|
50
|
+
puts ' Ex: --slice=path or --slice=path,params'
|
51
|
+
puts
|
52
|
+
|
53
|
+
puts '--except'.pastel(:green)
|
54
|
+
puts ' Exclude specific fields (except multiple with comma)'
|
55
|
+
puts ' Ex: --except=params --except=params,path'
|
56
|
+
puts
|
57
|
+
|
58
|
+
puts '--exists'.pastel(:green)
|
59
|
+
puts ' Ensure field exists regardless of contents'
|
60
|
+
puts ' Ex: --exists=params --exists=params,path'
|
61
|
+
puts
|
62
|
+
|
63
|
+
puts '--stats'.pastel(:green)
|
64
|
+
puts ' Order/Count occurrances by field. Combine with `truncate` for key names'
|
65
|
+
puts ' Ex: --stats=params --except=params,path'
|
66
|
+
puts
|
67
|
+
|
68
|
+
puts '--uniq'.pastel(:green)
|
69
|
+
puts ' Show unique values only'
|
70
|
+
puts ' Ex: --uniq=params --uniq=params,path'
|
71
|
+
puts
|
72
|
+
|
73
|
+
puts '--pluck'.pastel(:green)
|
74
|
+
puts ' Extract values from entries'
|
75
|
+
puts ' Ex: --pluck=params --pluck=params,path'
|
76
|
+
puts
|
77
|
+
|
78
|
+
puts '--archive'.pastel(:green)
|
79
|
+
puts ' Limit to specific archvie name (partial matching /inclusive). Matching SOS tar.gz name'
|
80
|
+
puts ' Ex: --archive=dev-gitlab_20210622154626, --archive=202106,202107'
|
81
|
+
puts
|
82
|
+
|
83
|
+
puts '--sort'.pastel(:green)
|
84
|
+
puts ' Sort by multiple fields'
|
85
|
+
puts ' Ex: --sort=duration_s,db_duration_s'
|
86
|
+
puts
|
87
|
+
|
88
|
+
puts '--reverse'.pastel(:green)
|
89
|
+
puts ' Reverse all results'
|
90
|
+
puts ' Ex: --reverse'
|
91
|
+
puts
|
92
|
+
|
93
|
+
puts '--combine'.pastel(:green)
|
94
|
+
puts ' Omit archive identifier dividers. Useful with sort or time filters'
|
95
|
+
puts ' Ex: --combine'
|
96
|
+
puts
|
97
|
+
|
98
|
+
puts '--case'.pastel(:green)
|
99
|
+
puts ' Exact case match. Defaults to case insensitive'
|
100
|
+
puts ' Ex: --case; --name=Jon, --name=jane --case'
|
101
|
+
puts
|
102
|
+
|
103
|
+
puts '--exact'.pastel(:green)
|
104
|
+
puts ' Exact parameter/value match. Defaults to partial match'
|
105
|
+
puts ' Ex: --field=CommonPartial --exact'
|
106
|
+
puts
|
107
|
+
|
108
|
+
puts '--start'.pastel(:green)
|
109
|
+
puts ' Show events after specified time. Filtered by the `time` field'
|
110
|
+
puts ' Use with `--end` for between selections'
|
111
|
+
puts ' Ex: log filter --start="2021-06-22 14:44 UTC" --end="2021-06-22 14:45 UTC"'
|
112
|
+
puts
|
113
|
+
|
114
|
+
puts '--end'.pastel(:green)
|
115
|
+
puts ' Show events before specified time. Filtered by the `time` field'
|
116
|
+
puts ' Use with `--start` for between selections'
|
117
|
+
puts ' Ex: log filter --end="2021-06-22"'
|
118
|
+
puts
|
119
|
+
|
120
|
+
puts '--time_zone'.pastel(:green)
|
121
|
+
puts ' Manipulate the `time` field into a specific timezone'
|
122
|
+
puts ' Ex: log filter --time_zone=EDT'
|
123
|
+
puts
|
124
|
+
|
125
|
+
puts '--text'.pastel(:green)
|
126
|
+
puts ' Full entry text searching (slow)'
|
127
|
+
puts ' --text="anything here"'
|
128
|
+
puts
|
129
|
+
|
130
|
+
puts '--table_style'.pastel(:green)
|
131
|
+
puts ' Renderer used for formatted output. basic, ascii, or unicode(default)'
|
132
|
+
puts ' Ex: log filter --table_style=base'
|
133
|
+
puts
|
134
|
+
|
135
|
+
puts '--truncate'.pastel(:green)
|
136
|
+
puts ' Truncate field length. On by default (4 rows). Performance issues!'
|
137
|
+
puts ' Disable with --truncate=0'.pastel(:bright_red)
|
138
|
+
puts ' Ex: --truncate=200, --truncate=2048"'
|
139
|
+
puts
|
140
|
+
|
141
|
+
puts 'Field Searching'.pastel(:blue)
|
142
|
+
puts ' --[key]=[value]'
|
143
|
+
puts ' Search in key for value'
|
144
|
+
puts ' Example: --path=mirror/pull'
|
145
|
+
puts
|
146
|
+
|
147
|
+
puts 'Search specific logs'.pastel(:blue)
|
148
|
+
puts ' Any non dash parameters will be the log list to search from'
|
149
|
+
puts " Ex: log filter --path=api sidekiq/current (hint: use `#{'ls'.pastel(:yellow)}` for log names"
|
150
|
+
puts
|
151
|
+
|
152
|
+
puts 'Example Queries'.pastel(:blue)
|
153
|
+
puts " Also see #{'examples'.pastel(:bright_blue)} for even more examples"
|
154
|
+
puts ' log filter --class=BuildFinishedWorker sidekiq/current --slice=time,message'
|
155
|
+
puts ' log filter gitlab-rails/api_json.log --slice=ua --uniq=ua --ua=gitlab-runner'
|
156
|
+
|
157
|
+
puts
|
158
|
+
end
|
159
|
+
# rubocop:enable Metrics/MethodLength
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -3,16 +3,75 @@ module GreenHat
|
|
3
3
|
module Shell
|
4
4
|
# Logs
|
5
5
|
module Gitlab
|
6
|
+
def self.ls
|
7
|
+
help
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.help
|
11
|
+
puts "\u2500".pastel(:cyan) * 20
|
12
|
+
puts "#{'GitLab'.pastel(:yellow)} - Tanuki power"
|
13
|
+
puts "\u2500".pastel(:cyan) * 20
|
14
|
+
|
15
|
+
puts 'Command Summary'.pastel(:blue)
|
16
|
+
|
17
|
+
puts ' services'.pastel(:green)
|
18
|
+
puts ' Show services status and version'
|
19
|
+
puts
|
20
|
+
|
21
|
+
puts ' status'.pastel(:green)
|
22
|
+
puts ' Show gitlab-ctl status'
|
23
|
+
puts
|
24
|
+
|
25
|
+
puts ' architecture'.pastel(:green)
|
26
|
+
puts ' Show node responsibility. E.g. Webservice, Gitaly, and etc'
|
27
|
+
puts
|
28
|
+
|
29
|
+
puts ' version'.pastel(:green)
|
30
|
+
puts ' Show GitLab software version'
|
31
|
+
puts
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.architecture
|
35
|
+
results = Archive.all.map { |x| GitLab.identify_node(x) }
|
36
|
+
|
37
|
+
GitLab.node_types.each do |entry|
|
38
|
+
list = results.select { |x| (x.services & entry.pattern).any? }.map(&:host).join(', ')
|
39
|
+
next if list.blank?
|
40
|
+
|
41
|
+
puts entry.name.pastel(:bright_green)
|
42
|
+
puts list
|
43
|
+
puts
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
6
47
|
def self.version
|
7
48
|
Thing.where(type: 'gitlab/version-manifest.json').each do |file|
|
8
49
|
next unless file.data
|
9
50
|
|
10
51
|
puts file.friendly_name
|
11
|
-
puts Semantic::Version.new(file.data.build_version).to_s.
|
52
|
+
puts Semantic::Version.new(file.data.build_version).to_s.pastel(:yellow)
|
12
53
|
puts
|
13
54
|
end
|
14
55
|
end
|
15
56
|
|
57
|
+
# Print service info / shared report method
|
58
|
+
def self.services(raw = {})
|
59
|
+
_files, flags, _args = Args.parse(raw, [:truncate])
|
60
|
+
|
61
|
+
results = {}
|
62
|
+
|
63
|
+
Archive.all.each do |archive|
|
64
|
+
result = GitLab.services(archive)
|
65
|
+
next unless result
|
66
|
+
|
67
|
+
# Generated Output
|
68
|
+
results[archive.friendly_name.pastel(:blue)] = result
|
69
|
+
end
|
70
|
+
|
71
|
+
# Print
|
72
|
+
ShellHelper.show(results, flags)
|
73
|
+
end
|
74
|
+
|
16
75
|
def self.status
|
17
76
|
Thing.where(type: 'gitlab_status').each do |file|
|
18
77
|
next unless file.data
|
@@ -27,7 +86,7 @@ module GreenHat
|
|
27
86
|
|
28
87
|
[
|
29
88
|
"#{service.status}:",
|
30
|
-
service.name.ljust(pad).
|
89
|
+
service.name.ljust(pad).pastel(color),
|
31
90
|
"#{service.pid_uptime};".ljust(pad)
|
32
91
|
|
33
92
|
]
|
data/lib/greenhat/shell/help.rb
CHANGED
@@ -1,15 +1,98 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
1
|
+
module GreenHat
|
2
|
+
# Root Level Shell / Splitting Help into its own file
|
3
|
+
module Shell
|
4
|
+
# rubocop:disable Layout/LineLength
|
5
|
+
def self.help
|
6
|
+
puts 'Quickstart'.pastel(:blue)
|
7
|
+
puts " Commands are organized by submodule: #{'log'.pastel(:blue)}, #{'cat'.pastel(:blue)}, #{'faststats'.pastel(:blue)}"
|
8
|
+
puts " Use #{'help'.pastel(:bright_blue)} for available commands in each module"
|
9
|
+
puts
|
10
|
+
|
11
|
+
puts ' Example Commands'
|
12
|
+
puts ' log filter sidekiq/current'.pastel(:yellow)
|
13
|
+
puts ' disk free'.pastel(:yellow)
|
14
|
+
puts
|
15
|
+
|
16
|
+
puts 'Top Level Commands'.pastel(:blue)
|
17
|
+
puts ' report'.pastel(:green)
|
18
|
+
puts ' Show summary report of SOS Report. OS, CPU, Memory, Disk, and etc'
|
19
|
+
puts ' --raw, no pagination'
|
20
|
+
puts ' --archive=<redis/archive>, filter by archive name'
|
21
|
+
puts
|
22
|
+
|
23
|
+
puts ' ps,df,netstat,free,uptime,uname'.pastel(:green)
|
24
|
+
puts ' Show common files from archives / Emulate terminal commands'
|
25
|
+
puts
|
26
|
+
|
27
|
+
puts ' Noisy Output'.pastel(:green)
|
28
|
+
puts " Use #{'quiet'.pastel(:blue)} or to #{'debug'.pastel(:blue)} to toggle greenhat logging"
|
29
|
+
puts
|
30
|
+
|
31
|
+
cli_shortcuts
|
32
|
+
|
33
|
+
puts "See #{'about'.pastel(:bright_blue)} for more details about GreenHat"
|
34
|
+
end
|
35
|
+
# rubocop:enable Layout/LineLength
|
36
|
+
|
37
|
+
def self.cli_shortcuts
|
38
|
+
puts "\u2500".pastel(:cyan) * 25
|
39
|
+
puts 'Nav / Keyboard Shortcuts'.pastel(:blue)
|
40
|
+
puts "\u2500".pastel(:cyan) * 25
|
41
|
+
puts <<~BLOCK
|
42
|
+
| Hotkey | Description |
|
43
|
+
| ------------------- | ----------------------- |
|
44
|
+
| Ctrl + U | Clear Input |
|
45
|
+
| Ctrl + A | Go to beginning |
|
46
|
+
| Ctrl + E | Go to End |
|
47
|
+
| Ctrl + Left/Right | Move left/right by word |
|
48
|
+
| Ctrl + D, Ctrl + Z | Exit |
|
49
|
+
| Ctrl + C, Shift Tab | Up one module |
|
50
|
+
BLOCK
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.about
|
55
|
+
puts "\u2500".pastel(:cyan) * 20
|
56
|
+
puts "About GreenHat #{GreenHat::VERSION}".pastel(:yellow)
|
57
|
+
puts "\u2500".pastel(:cyan) * 20
|
58
|
+
|
59
|
+
puts 'TLDR; Put in SOS reports, run commands, and find stuffs'.pastel(:green)
|
60
|
+
puts
|
61
|
+
|
62
|
+
puts <<~BLOCK
|
63
|
+
General overview (OS, Memory, Disk, GitLab)
|
64
|
+
#{'report'.pastel(:bright_cyan)}
|
65
|
+
|
66
|
+
Log Searching
|
67
|
+
#{'log filter sidekiq/current --job_status=done --sort=duration_s,db_duration_s --slice=duration_s,db_duration_s --reverse'.pastel(:bright_cyan)}
|
68
|
+
|
69
|
+
Read File(s) across SOS archives
|
70
|
+
#{'cat uptime'.pastel(:bright_cyan)} or #{'cat mount etc/fstab'.pastel(:bright_cyan)}
|
71
|
+
|
72
|
+
BLOCK
|
73
|
+
|
74
|
+
puts 'What it does / How it works'.pastel(:blue)
|
75
|
+
puts
|
76
|
+
puts <<~BLOCK
|
77
|
+
GreenHat is a support utility to enhance troubleshooting with GitLabSOS Reports and log files. Make it easy to find stuff
|
78
|
+
|
79
|
+
Supplied input files are staged, unpacked, identified, and normalized.
|
80
|
+
This enables other utilities to automatically find and present data. (Faststats, report, and etc)
|
81
|
+
|
82
|
+
BLOCK
|
83
|
+
|
84
|
+
puts 'Commands and Submodules'.pastel(:blue)
|
85
|
+
puts
|
86
|
+
puts <<~BLOCK
|
87
|
+
Greenhat is broken down into different "modules". Each module has its own commands. For example: log, cat, and faststats.
|
88
|
+
You can "cd" into or execute commands directly against with their names.
|
89
|
+
|
90
|
+
- Direct: #{'log filter sidekiq/current'.pastel(:cyan)}
|
91
|
+
- Or within: First #{'log'.pastel(:cyan)}, then #{'filter sidekiq/current'.pastel(:cyan)}
|
92
|
+
|
93
|
+
You can find the list of commands and submodules of each with #{'help'.pastel(:yellow)}
|
94
|
+
|
95
|
+
BLOCK
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module GreenHat
|
2
|
+
module ShellHelper
|
3
|
+
# Helper to handle listing of files
|
4
|
+
module List
|
5
|
+
# List Files Helpers
|
6
|
+
def self.list(raw = [], files)
|
7
|
+
filter, flags, _args = Args.parse(raw)
|
8
|
+
|
9
|
+
# Sort
|
10
|
+
files.sort_by!(&:name)
|
11
|
+
|
12
|
+
# Simplified vs Full. Full file name/path / or just file kinds
|
13
|
+
all = flags.key?(:all) || flags.key?(:a)
|
14
|
+
|
15
|
+
# Short & Uniq
|
16
|
+
files.uniq!(&:name) unless all
|
17
|
+
|
18
|
+
# Filter / Pattern
|
19
|
+
files.select! { |f| filter.any? { |x| f.name.include? x } } unless filter.empty?
|
20
|
+
|
21
|
+
# Print
|
22
|
+
files.each do |log|
|
23
|
+
if all
|
24
|
+
puts "- #{log.friendly_name}"
|
25
|
+
else
|
26
|
+
puts "- #{log.name.pastel(:yellow)}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Unified Help
|
32
|
+
def self.help
|
33
|
+
puts ' ls'.pastel(:green)
|
34
|
+
puts ' List available files'
|
35
|
+
puts ' Options'.pastel(:cyan)
|
36
|
+
puts ' -a, --all, show full file name/path including source'
|
37
|
+
puts ' <string> filter available'
|
38
|
+
puts ' Examples'.pastel(:cyan)
|
39
|
+
puts ' ls -a rails'
|
40
|
+
puts ' ls sys'
|
41
|
+
puts
|
42
|
+
end
|
43
|
+
# ----
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|