gorails 0.1.2 → 0.1.5
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/CHANGELOG.md +18 -1
- data/Gemfile.lock +1 -6
- data/bin/update-deps +95 -0
- data/exe/gorails +2 -1
- data/gorails.gemspec +0 -2
- data/lib/gorails/commands/railsbytes.rb +10 -10
- data/lib/gorails/commands/version.rb +15 -0
- data/lib/gorails/commands.rb +2 -5
- data/lib/gorails/version.rb +1 -1
- data/lib/gorails.rb +11 -20
- data/vendor/deps/cli-kit/REVISION +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +301 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +237 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +131 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +128 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +132 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args.rb +15 -0
- data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +29 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +256 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +141 -0
- data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
- data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +30 -0
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +165 -0
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +99 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +94 -0
- data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +89 -0
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +95 -0
- data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +284 -0
- data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +67 -0
- data/vendor/deps/cli-kit/lib/cli/kit/sorbet_runtime_stub.rb +142 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +253 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support.rb +10 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +350 -0
- data/vendor/deps/cli-kit/lib/cli/kit/util.rb +133 -0
- data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
- data/vendor/deps/cli-kit/lib/cli/kit.rb +151 -0
- data/vendor/deps/cli-ui/REVISION +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +180 -0
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +98 -0
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +216 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +116 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +176 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +149 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +112 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +300 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +58 -0
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +72 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +102 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +534 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +354 -0
- data/vendor/deps/cli-ui/lib/cli/ui/sorbet_runtime_stub.rb +143 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +46 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +292 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +82 -0
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +264 -0
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +53 -0
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +107 -0
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +6 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +37 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +75 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +91 -0
- data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +63 -0
- data/vendor/deps/cli-ui/lib/cli/ui.rb +356 -0
- metadata +58 -29
@@ -0,0 +1,256 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module Kit
|
6
|
+
module CommandHelp
|
7
|
+
extend T::Sig
|
8
|
+
include Kernel # for sorbet
|
9
|
+
|
10
|
+
sig { params(args: T::Array[String], name: String).void }
|
11
|
+
def call(args, name)
|
12
|
+
begin
|
13
|
+
defn = Args::Definition.new
|
14
|
+
opts = self.class.opts_class
|
15
|
+
opts.new(defn).install_to_definition
|
16
|
+
tokens = Args::Tokenizer.tokenize(args)
|
17
|
+
parse = Args::Parser.new(defn).parse(tokens)
|
18
|
+
result = Args::Evaluation.new(defn, parse)
|
19
|
+
opts_inst = opts.new(result)
|
20
|
+
rescue Args::Evaluation::TooManyPositions, Args::Evaluation::MissingRequiredPosition => e
|
21
|
+
STDERR.puts CLI::UI.fmt("{{red:{{bold:Error: #{e.message}}}}}")
|
22
|
+
STDERR.puts
|
23
|
+
STDERR.puts self.class.build_help
|
24
|
+
raise(AbortSilent)
|
25
|
+
rescue Args::Error => e
|
26
|
+
raise(Abort, e)
|
27
|
+
end
|
28
|
+
|
29
|
+
if opts_inst.helpflag
|
30
|
+
puts self.class.build_help
|
31
|
+
else
|
32
|
+
res = begin
|
33
|
+
opts.new(result)
|
34
|
+
rescue Args::Error => e
|
35
|
+
raise(Abort, e)
|
36
|
+
end
|
37
|
+
invoke_wrapper(res, name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# use to implement error handling
|
42
|
+
sig { params(op: T.untyped, name: String).void }
|
43
|
+
def invoke_wrapper(op, name)
|
44
|
+
invoke(op, name)
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(op: T.untyped, name: String).void }
|
48
|
+
def invoke(op, name)
|
49
|
+
raise(NotImplementedError, '#invoke must be implemented, or #call overridden')
|
50
|
+
end
|
51
|
+
|
52
|
+
sig { params(name: String).void }
|
53
|
+
def self.tool_name=(name)
|
54
|
+
@tool_name = name
|
55
|
+
end
|
56
|
+
|
57
|
+
sig { returns(String) }
|
58
|
+
def self._tool_name
|
59
|
+
unless @tool_name
|
60
|
+
raise 'You must set CLI::Kit::CommandHelp.tool_name='
|
61
|
+
end
|
62
|
+
|
63
|
+
@tool_name
|
64
|
+
end
|
65
|
+
|
66
|
+
module ClassMethods
|
67
|
+
extend T::Sig
|
68
|
+
include Kernel # for sorbet
|
69
|
+
|
70
|
+
DEFAULT_HELP_SECTIONS = [
|
71
|
+
:desc,
|
72
|
+
:long_desc,
|
73
|
+
:usage,
|
74
|
+
:examples,
|
75
|
+
:options,
|
76
|
+
]
|
77
|
+
|
78
|
+
sig { returns(String) }
|
79
|
+
def build_help
|
80
|
+
h = (@help_sections || DEFAULT_HELP_SECTIONS).map do |section|
|
81
|
+
case section
|
82
|
+
when :desc
|
83
|
+
build_desc
|
84
|
+
when :long_desc
|
85
|
+
@long_desc
|
86
|
+
when :usage
|
87
|
+
@usage_section ||= build_usage
|
88
|
+
when :examples
|
89
|
+
@examples_section ||= build_examples
|
90
|
+
when :options
|
91
|
+
@options_section ||= build_options
|
92
|
+
else
|
93
|
+
raise "Unknown help section: #{section}"
|
94
|
+
end
|
95
|
+
end.compact.map(&:chomp).join("\n\n") + "\n"
|
96
|
+
CLI::UI.fmt(h)
|
97
|
+
end
|
98
|
+
|
99
|
+
sig { returns(String) }
|
100
|
+
def _command_name
|
101
|
+
return @command_name if @command_name
|
102
|
+
|
103
|
+
last_camel = send(:name).split('::').last
|
104
|
+
last_camel.gsub(/([a-z])([A-Z])/, '\1-\2').downcase
|
105
|
+
end
|
106
|
+
|
107
|
+
sig { returns(String) }
|
108
|
+
def _desc
|
109
|
+
@desc
|
110
|
+
end
|
111
|
+
|
112
|
+
sig { returns(String) }
|
113
|
+
def build_desc
|
114
|
+
out = +"{{command:#{CommandHelp._tool_name} #{_command_name}}}"
|
115
|
+
if @desc
|
116
|
+
out << ": #{@desc}"
|
117
|
+
end
|
118
|
+
"{{bold:#{out}}}"
|
119
|
+
end
|
120
|
+
|
121
|
+
sig { returns(T.untyped) }
|
122
|
+
def opts_class
|
123
|
+
T.unsafe(self).const_get(:Opts) # rubocop:disable Sorbet/ConstantsFromStrings
|
124
|
+
rescue NameError
|
125
|
+
Class.new(CLI::Kit::Opts)
|
126
|
+
end
|
127
|
+
|
128
|
+
sig { returns(T.nilable(String)) }
|
129
|
+
def build_options
|
130
|
+
opts = opts_class
|
131
|
+
return(nil) unless opts
|
132
|
+
|
133
|
+
methods = []
|
134
|
+
loop do
|
135
|
+
methods.concat(opts.public_instance_methods(false))
|
136
|
+
break if opts.superclass == CLI::Kit::Opts
|
137
|
+
|
138
|
+
opts = opts.superclass
|
139
|
+
end
|
140
|
+
|
141
|
+
@defn = Args::Definition.new
|
142
|
+
o = opts.new(@defn)
|
143
|
+
o.install_to_definition
|
144
|
+
|
145
|
+
return nil if @defn.options.empty? && @defn.flags.empty?
|
146
|
+
|
147
|
+
merged = T.let(@defn.options, T::Array[T.any(Args::Definition::Option, Args::Definition::Flag)])
|
148
|
+
merged += @defn.flags
|
149
|
+
merged.sort_by!(&:name)
|
150
|
+
"{{bold:Options:}}\n" + merged.map do |o|
|
151
|
+
if o.is_a?(Args::Definition::Option)
|
152
|
+
z = ' ' + [o.short&.prepend('-'), o.long&.prepend('--')].compact.join(', ') + ' VALUE'
|
153
|
+
default = if o.dynamic_default?
|
154
|
+
'(generated default)'
|
155
|
+
elsif o.default.nil?
|
156
|
+
'(no default)'
|
157
|
+
else
|
158
|
+
"(default: #{o.default.inspect})"
|
159
|
+
end
|
160
|
+
z << if o.desc
|
161
|
+
" {{italic:{{gray:# #{o.desc} #{default}}}}}"
|
162
|
+
else
|
163
|
+
" {{italic:{{gray:# #{default}}}}}"
|
164
|
+
end
|
165
|
+
else
|
166
|
+
z = ' ' + [o.short&.prepend('-'), o.long&.prepend('--')].compact.join(', ')
|
167
|
+
if o.desc
|
168
|
+
z << " {{italic:{{gray:# #{o.desc}}}}}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
z
|
172
|
+
end.join("\n")
|
173
|
+
end
|
174
|
+
|
175
|
+
sig { params(sections: T::Array[Symbol]).void }
|
176
|
+
def help_sections(sections)
|
177
|
+
@help_sections = sections
|
178
|
+
end
|
179
|
+
|
180
|
+
sig { params(command_name: String).void }
|
181
|
+
def command_name(command_name)
|
182
|
+
if @command_name
|
183
|
+
raise(ArgumentError, "Command name already set to #{@command_name}")
|
184
|
+
end
|
185
|
+
|
186
|
+
@command_name = command_name
|
187
|
+
end
|
188
|
+
|
189
|
+
sig { params(desc: String).void }
|
190
|
+
def desc(desc)
|
191
|
+
if desc.size > 80
|
192
|
+
raise(ArgumentError, 'description must be 80 characters or less')
|
193
|
+
end
|
194
|
+
if @desc
|
195
|
+
raise(ArgumentError, 'description already set')
|
196
|
+
end
|
197
|
+
|
198
|
+
@desc = desc
|
199
|
+
end
|
200
|
+
|
201
|
+
sig { params(long_desc: String).void }
|
202
|
+
def long_desc(long_desc)
|
203
|
+
if @long_desc
|
204
|
+
raise(ArgumentError, 'long description already set')
|
205
|
+
end
|
206
|
+
|
207
|
+
@long_desc = long_desc
|
208
|
+
end
|
209
|
+
|
210
|
+
sig { returns(String) }
|
211
|
+
def build_usage
|
212
|
+
'{{bold:Usage:}}' + case (@usage || []).size
|
213
|
+
when 0
|
214
|
+
" {{command:#{CommandHelp._tool_name} #{_command_name}}} [options]\n"
|
215
|
+
when 1
|
216
|
+
" {{command:#{CommandHelp._tool_name} #{_command_name}}} #{@usage.first}\n"
|
217
|
+
else
|
218
|
+
"\n" + @usage.map do |usage|
|
219
|
+
" {{command:#{CommandHelp._tool_name} #{_command_name}}} #{usage}\n"
|
220
|
+
end.join
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
sig { returns(T.nilable(String)) }
|
225
|
+
def build_examples
|
226
|
+
return nil unless @examples
|
227
|
+
|
228
|
+
cmd_prefix = " {{command:#{CommandHelp._tool_name} #{_command_name}}}"
|
229
|
+
"{{bold:Examples:}}\n" + @examples.map do |command, explanation|
|
230
|
+
cmd = "#{cmd_prefix} #{command}"
|
231
|
+
exp = "{{italic:{{gray:# #{explanation}}}}}"
|
232
|
+
|
233
|
+
width = CLI::UI::ANSI.printing_width(CLI::UI.fmt("#{cmd} #{exp}"))
|
234
|
+
if width > CLI::UI::Terminal.width
|
235
|
+
" #{exp}\n#{cmd}"
|
236
|
+
else
|
237
|
+
"#{cmd} #{exp}"
|
238
|
+
end
|
239
|
+
end.join("\n\n")
|
240
|
+
end
|
241
|
+
|
242
|
+
sig { params(usage: String).void }
|
243
|
+
def usage(usage)
|
244
|
+
@usage ||= []
|
245
|
+
@usage << usage
|
246
|
+
end
|
247
|
+
|
248
|
+
sig { params(command: String, explanation: T.nilable(String)).void }
|
249
|
+
def example(command, explanation)
|
250
|
+
@examples ||= []
|
251
|
+
@examples << [command, explanation]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module Kit
|
6
|
+
class CommandRegistry
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
CommandOrProc = T.type_alias do
|
10
|
+
T.any(T.class_of(CLI::Kit::BaseCommand), T.proc.returns(T.class_of(CLI::Kit::BaseCommand)))
|
11
|
+
end
|
12
|
+
|
13
|
+
sig { returns(T::Hash[String, CommandOrProc]) }
|
14
|
+
attr_reader :commands
|
15
|
+
|
16
|
+
sig { returns(T::Hash[String, String]) }
|
17
|
+
attr_reader :aliases
|
18
|
+
|
19
|
+
module ContextualResolver
|
20
|
+
extend T::Sig
|
21
|
+
extend T::Helpers
|
22
|
+
interface!
|
23
|
+
|
24
|
+
sig { abstract.returns(T::Array[String]) }
|
25
|
+
def command_names; end
|
26
|
+
|
27
|
+
sig { abstract.returns(T::Hash[String, String]) }
|
28
|
+
def aliases; end
|
29
|
+
|
30
|
+
sig { abstract.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
|
31
|
+
def command_class(_name); end
|
32
|
+
end
|
33
|
+
|
34
|
+
module NullContextualResolver
|
35
|
+
extend T::Sig
|
36
|
+
extend ContextualResolver
|
37
|
+
|
38
|
+
sig { override.returns(T::Array[String]) }
|
39
|
+
def self.command_names
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { override.returns(T::Hash[String, String]) }
|
44
|
+
def self.aliases
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { override.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
|
49
|
+
def self.command_class(_name)
|
50
|
+
raise(CLI::Kit::Abort, 'Cannot be called on the NullContextualResolver since command_names is empty')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { params(default: String, contextual_resolver: ContextualResolver).void }
|
55
|
+
def initialize(default:, contextual_resolver: NullContextualResolver)
|
56
|
+
@commands = {}
|
57
|
+
@aliases = {}
|
58
|
+
@default = default
|
59
|
+
@contextual_resolver = contextual_resolver
|
60
|
+
end
|
61
|
+
|
62
|
+
sig { returns(T::Hash[String, T.class_of(CLI::Kit::BaseCommand)]) }
|
63
|
+
def resolved_commands
|
64
|
+
@commands.each_with_object({}) do |(k, v), a|
|
65
|
+
a[k] = resolve_class(v)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
sig { params(const: CommandOrProc, name: String).void }
|
70
|
+
def add(const, name)
|
71
|
+
commands[name] = const
|
72
|
+
end
|
73
|
+
|
74
|
+
sig { params(name: T.nilable(String)).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
|
75
|
+
def lookup_command(name)
|
76
|
+
name = @default if name.to_s.empty?
|
77
|
+
resolve_command(T.must(name))
|
78
|
+
end
|
79
|
+
|
80
|
+
sig { params(from: String, to: String).void }
|
81
|
+
def add_alias(from, to)
|
82
|
+
aliases[from] = to unless aliases[from]
|
83
|
+
end
|
84
|
+
|
85
|
+
sig { returns(T::Array[String]) }
|
86
|
+
def command_names
|
87
|
+
@contextual_resolver.command_names + commands.keys
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { params(name: String).returns(T::Boolean) }
|
91
|
+
def exist?(name)
|
92
|
+
!resolve_command(name).first.nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
sig { params(name: String).returns(String) }
|
98
|
+
def resolve_alias(name)
|
99
|
+
aliases[name] || @contextual_resolver.aliases.fetch(name, name)
|
100
|
+
end
|
101
|
+
|
102
|
+
sig { params(name: String).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
|
103
|
+
def resolve_command(name)
|
104
|
+
name = resolve_alias(name)
|
105
|
+
resolve_global_command(name) || \
|
106
|
+
resolve_contextual_command(name) || \
|
107
|
+
[nil, name]
|
108
|
+
end
|
109
|
+
|
110
|
+
sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
|
111
|
+
def resolve_global_command(name)
|
112
|
+
klass = resolve_class(commands.fetch(name, nil))
|
113
|
+
return nil unless klass
|
114
|
+
|
115
|
+
[klass, name]
|
116
|
+
rescue NameError
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
|
121
|
+
def resolve_contextual_command(name)
|
122
|
+
found = @contextual_resolver.command_names.include?(name)
|
123
|
+
return nil unless found
|
124
|
+
|
125
|
+
[@contextual_resolver.command_class(name), name]
|
126
|
+
end
|
127
|
+
|
128
|
+
sig { params(class_or_proc: T.nilable(CommandOrProc)).returns(T.nilable(T.class_of(CLI::Kit::BaseCommand))) }
|
129
|
+
def resolve_class(class_or_proc)
|
130
|
+
case class_or_proc
|
131
|
+
when nil
|
132
|
+
nil
|
133
|
+
when Proc
|
134
|
+
class_or_proc.call
|
135
|
+
else
|
136
|
+
class_or_proc
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module CLI
|
6
|
+
module Kit
|
7
|
+
class Config
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
XDG_CONFIG_HOME = 'XDG_CONFIG_HOME'
|
11
|
+
|
12
|
+
sig { params(tool_name: String).void }
|
13
|
+
def initialize(tool_name:)
|
14
|
+
@tool_name = tool_name
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the config corresponding to `name` from the config file
|
18
|
+
# `false` is returned if it doesn't exist
|
19
|
+
#
|
20
|
+
# #### Parameters
|
21
|
+
# `section` : the section of the config value you are looking for
|
22
|
+
# `name` : the name of the config value you are looking for
|
23
|
+
#
|
24
|
+
# #### Returns
|
25
|
+
# `value` : the value of the config variable (nil if none)
|
26
|
+
#
|
27
|
+
# #### Example Usage
|
28
|
+
# `config.get('name.of.config')`
|
29
|
+
#
|
30
|
+
sig { params(section: String, name: String, default: T.nilable(String)).returns(T.nilable(String)) }
|
31
|
+
def get(section, name, default: nil)
|
32
|
+
all_configs.dig("[#{section}]", name) || default
|
33
|
+
end
|
34
|
+
|
35
|
+
# Coalesce and enforce the value of a config to a boolean
|
36
|
+
sig { params(section: String, name: String, default: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
|
37
|
+
def get_bool(section, name, default: false)
|
38
|
+
case get(section, name)
|
39
|
+
when 'true'
|
40
|
+
true
|
41
|
+
when 'false'
|
42
|
+
false
|
43
|
+
when nil
|
44
|
+
default
|
45
|
+
else
|
46
|
+
raise CLI::Kit::Abort, "Invalid config: #{section}.#{name} is expected to be true or false"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sets the config value in the config file
|
51
|
+
#
|
52
|
+
# #### Parameters
|
53
|
+
# `section` : the section of the config you are setting
|
54
|
+
# `name` : the name of the config you are setting
|
55
|
+
# `value` : the value of the config you are setting
|
56
|
+
#
|
57
|
+
# #### Example Usage
|
58
|
+
# `config.set('section', 'name.of.config', 'value')`
|
59
|
+
#
|
60
|
+
sig { params(section: String, name: String, value: T.nilable(T.any(String, T::Boolean))).void }
|
61
|
+
def set(section, name, value)
|
62
|
+
all_configs["[#{section}]"] ||= {}
|
63
|
+
case value
|
64
|
+
when nil
|
65
|
+
T.must(all_configs["[#{section}]"]).delete(name)
|
66
|
+
else
|
67
|
+
T.must(all_configs["[#{section}]"])[name] = value.to_s
|
68
|
+
end
|
69
|
+
write_config
|
70
|
+
end
|
71
|
+
|
72
|
+
# Unsets a config value in the config file
|
73
|
+
#
|
74
|
+
# #### Parameters
|
75
|
+
# `section` : the section of the config you are deleting
|
76
|
+
# `name` : the name of the config you are deleting
|
77
|
+
#
|
78
|
+
# #### Example Usage
|
79
|
+
# `config.unset('section', 'name.of.config')`
|
80
|
+
#
|
81
|
+
sig { params(section: String, name: String).void }
|
82
|
+
def unset(section, name)
|
83
|
+
set(section, name, nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Gets the hash for the entire section
|
87
|
+
#
|
88
|
+
# #### Parameters
|
89
|
+
# `section` : the section of the config you are getting
|
90
|
+
#
|
91
|
+
# #### Example Usage
|
92
|
+
# `config.get_section('section')`
|
93
|
+
#
|
94
|
+
sig { params(section: String).returns(T::Hash[String, String]) }
|
95
|
+
def get_section(section)
|
96
|
+
(all_configs["[#{section}]"] || {}).dup
|
97
|
+
end
|
98
|
+
|
99
|
+
sig { returns(String) }
|
100
|
+
def to_s
|
101
|
+
ini.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
# The path on disk at which the configuration is stored:
|
105
|
+
# `$XDG_CONFIG_HOME/<toolname>/config`
|
106
|
+
# if ENV['XDG_CONFIG_HOME'] is not set, we default to ~/.config, e.g.:
|
107
|
+
# ~/.config/tool/config
|
108
|
+
#
|
109
|
+
sig { returns(String) }
|
110
|
+
def file
|
111
|
+
config_home = ENV.fetch(XDG_CONFIG_HOME, '~/.config')
|
112
|
+
File.expand_path(File.join(@tool_name, 'config'), config_home)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
sig { returns(T::Hash[String, T::Hash[String, String]]) }
|
118
|
+
def all_configs
|
119
|
+
ini.ini
|
120
|
+
end
|
121
|
+
|
122
|
+
sig { returns(CLI::Kit::Ini) }
|
123
|
+
def ini
|
124
|
+
@ini ||= CLI::Kit::Ini.new(file).tap(&:parse)
|
125
|
+
end
|
126
|
+
|
127
|
+
sig { void }
|
128
|
+
def write_config
|
129
|
+
all_configs.each do |section, sub_config|
|
130
|
+
all_configs.delete(section) if sub_config.empty?
|
131
|
+
end
|
132
|
+
FileUtils.mkdir_p(File.dirname(file))
|
133
|
+
File.write(file, to_s)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# typed: strong
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
class Exception
|
5
|
+
extend(T::Sig)
|
6
|
+
|
7
|
+
# You'd think instance variables @bug and @silent would work here. They
|
8
|
+
# don't. I'm not sure why. If you, the reader, want to take some time to
|
9
|
+
# figure it out, go ahead and refactor to that.
|
10
|
+
|
11
|
+
sig { returns(T::Boolean) }
|
12
|
+
def bug?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
sig { returns(T::Boolean) }
|
17
|
+
def silent?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { params(bug: T::Boolean).void }
|
22
|
+
def bug!(bug = true)
|
23
|
+
singleton_class.define_method(:bug?) { bug }
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { params(silent: T::Boolean).void }
|
27
|
+
def silent!(silent = true)
|
28
|
+
singleton_class.define_method(:silent?) { silent }
|
29
|
+
end
|
30
|
+
end
|