cli-kit 5.1.0 → 5.3.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/.github/release.yml +20 -0
- data/.github/workflows/release.yml +52 -0
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.sorbet.yml +1 -0
- data/.rubocop.yml +2 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +23 -24
- data/Rakefile +0 -1
- data/bin/testunit +0 -1
- data/cli-kit.gemspec +2 -1
- data/examples/minimal/example.rb +1 -1
- data/examples/single-file/example.rb +4 -3
- data/gen/lib/gen/commands/help.rb +1 -3
- data/gen/lib/gen/commands/new.rb +2 -6
- data/gen/lib/gen/commands.rb +1 -7
- data/gen/lib/gen/entry_point.rb +1 -5
- data/gen/lib/gen/generator.rb +15 -19
- data/gen/lib/gen/help.rb +3 -7
- data/lib/cli/kit/args/definition.rb +37 -95
- data/lib/cli/kit/args/evaluation.rb +40 -59
- data/lib/cli/kit/args/parser/node.rb +19 -23
- data/lib/cli/kit/args/parser.rb +12 -16
- data/lib/cli/kit/args/tokenizer.rb +15 -18
- data/lib/cli/kit/base_command.rb +4 -8
- data/lib/cli/kit/command_help.rb +24 -27
- data/lib/cli/kit/command_registry.rb +40 -36
- data/lib/cli/kit/config.rb +210 -17
- data/lib/cli/kit/core_ext.rb +118 -8
- data/lib/cli/kit/error_handler.rb +49 -39
- data/lib/cli/kit/executor.rb +7 -16
- data/lib/cli/kit/ini.rb +8 -12
- data/lib/cli/kit/levenshtein.rb +7 -5
- data/lib/cli/kit/logger.rb +8 -10
- data/lib/cli/kit/opts.rb +26 -86
- data/lib/cli/kit/parse_args.rb +5 -10
- data/lib/cli/kit/resolver.rb +4 -6
- data/lib/cli/kit/support/test_helper.rb +10 -5
- data/lib/cli/kit/system.rb +25 -114
- data/lib/cli/kit/util.rb +15 -31
- data/lib/cli/kit/version.rb +1 -1
- data/lib/cli/kit.rb +19 -36
- metadata +18 -3
- data/lib/cli/kit/sorbet_runtime_stub.rb +0 -154
data/lib/cli/kit/system.rb
CHANGED
|
@@ -9,8 +9,6 @@ module CLI
|
|
|
9
9
|
module System
|
|
10
10
|
SUDO_PROMPT = CLI::UI.fmt('{{info:(sudo)}} Password: ')
|
|
11
11
|
class << self
|
|
12
|
-
extend T::Sig
|
|
13
|
-
|
|
14
12
|
# Ask for sudo access with a message explaning the need for it
|
|
15
13
|
# Will make subsequent commands capable of running with sudo for a period of time
|
|
16
14
|
#
|
|
@@ -20,7 +18,7 @@ module CLI
|
|
|
20
18
|
# #### Usage
|
|
21
19
|
# `ctx.sudo_reason("We need to do a thing")`
|
|
22
20
|
#
|
|
23
|
-
|
|
21
|
+
#: (String msg) -> void
|
|
24
22
|
def sudo_reason(msg)
|
|
25
23
|
# See if sudo has a cached password
|
|
26
24
|
%x(env SUDO_ASKPASS=/usr/bin/false sudo -A true > /dev/null 2>&1)
|
|
@@ -48,16 +46,7 @@ module CLI
|
|
|
48
46
|
# #### Usage
|
|
49
47
|
# `out, stat = CLI::Kit::System.capture2('ls', 'a_folder')`
|
|
50
48
|
#
|
|
51
|
-
|
|
52
|
-
params(
|
|
53
|
-
cmd: String,
|
|
54
|
-
args: String,
|
|
55
|
-
sudo: T.any(T::Boolean, String),
|
|
56
|
-
env: T::Hash[String, T.nilable(String)],
|
|
57
|
-
kwargs: T.untyped,
|
|
58
|
-
)
|
|
59
|
-
.returns([String, Process::Status])
|
|
60
|
-
end
|
|
49
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
|
|
61
50
|
def capture2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
62
51
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2)
|
|
63
52
|
end
|
|
@@ -79,16 +68,7 @@ module CLI
|
|
|
79
68
|
# #### Usage
|
|
80
69
|
# `out_and_err, stat = CLI::Kit::System.capture2e('ls', 'a_folder')`
|
|
81
70
|
#
|
|
82
|
-
|
|
83
|
-
params(
|
|
84
|
-
cmd: String,
|
|
85
|
-
args: String,
|
|
86
|
-
sudo: T.any(T::Boolean, String),
|
|
87
|
-
env: T::Hash[String, T.nilable(String)],
|
|
88
|
-
kwargs: T.untyped,
|
|
89
|
-
)
|
|
90
|
-
.returns([String, Process::Status])
|
|
91
|
-
end
|
|
71
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
|
|
92
72
|
def capture2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
93
73
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2e)
|
|
94
74
|
end
|
|
@@ -111,70 +91,22 @@ module CLI
|
|
|
111
91
|
# #### Usage
|
|
112
92
|
# `out, err, stat = CLI::Kit::System.capture3('ls', 'a_folder')`
|
|
113
93
|
#
|
|
114
|
-
|
|
115
|
-
params(
|
|
116
|
-
cmd: String,
|
|
117
|
-
args: String,
|
|
118
|
-
sudo: T.any(T::Boolean, String),
|
|
119
|
-
env: T::Hash[String, T.nilable(String)],
|
|
120
|
-
kwargs: T.untyped,
|
|
121
|
-
)
|
|
122
|
-
.returns([String, String, Process::Status])
|
|
123
|
-
end
|
|
94
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, String, Process::Status]
|
|
124
95
|
def capture3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
|
|
125
96
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture3)
|
|
126
97
|
end
|
|
127
98
|
|
|
128
|
-
|
|
129
|
-
params(
|
|
130
|
-
cmd: String,
|
|
131
|
-
args: String,
|
|
132
|
-
sudo: T.any(T::Boolean, String),
|
|
133
|
-
env: T::Hash[String, T.nilable(String)],
|
|
134
|
-
kwargs: T.untyped,
|
|
135
|
-
block: T.nilable(
|
|
136
|
-
T.proc.params(stdin: IO, stdout: IO, wait_thr: Process::Waiter)
|
|
137
|
-
.returns([IO, IO, Process::Waiter]),
|
|
138
|
-
),
|
|
139
|
-
)
|
|
140
|
-
.returns([IO, IO, Process::Waiter])
|
|
141
|
-
end
|
|
99
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
|
|
142
100
|
def popen2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
143
101
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2, &block)
|
|
144
102
|
end
|
|
145
103
|
|
|
146
|
-
|
|
147
|
-
params(
|
|
148
|
-
cmd: String,
|
|
149
|
-
args: String,
|
|
150
|
-
sudo: T.any(T::Boolean, String),
|
|
151
|
-
env: T::Hash[String, T.nilable(String)],
|
|
152
|
-
kwargs: T.untyped,
|
|
153
|
-
block: T.nilable(
|
|
154
|
-
T.proc.params(stdin: IO, stdout: IO, wait_thr: Process::Waiter)
|
|
155
|
-
.returns([IO, IO, Process::Waiter]),
|
|
156
|
-
),
|
|
157
|
-
)
|
|
158
|
-
.returns([IO, IO, Process::Waiter])
|
|
159
|
-
end
|
|
104
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
|
|
160
105
|
def popen2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
161
106
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2e, &block)
|
|
162
107
|
end
|
|
163
108
|
|
|
164
|
-
|
|
165
|
-
params(
|
|
166
|
-
cmd: String,
|
|
167
|
-
args: String,
|
|
168
|
-
sudo: T.any(T::Boolean, String),
|
|
169
|
-
env: T::Hash[String, T.nilable(String)],
|
|
170
|
-
kwargs: T.untyped,
|
|
171
|
-
block: T.nilable(
|
|
172
|
-
T.proc.params(stdin: IO, stdout: IO, stderr: IO, wait_thr: Process::Waiter)
|
|
173
|
-
.returns([IO, IO, IO, Process::Waiter]),
|
|
174
|
-
),
|
|
175
|
-
)
|
|
176
|
-
.returns([IO, IO, IO, Process::Waiter])
|
|
177
|
-
end
|
|
109
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, IO stderr, Process::Waiter wait_thr) -> [IO, IO, IO, Process::Waiter] } -> [IO, IO, IO, Process::Waiter]
|
|
178
110
|
def popen3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
|
|
179
111
|
delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen3, &block)
|
|
180
112
|
end
|
|
@@ -194,18 +126,7 @@ module CLI
|
|
|
194
126
|
# #### Usage
|
|
195
127
|
# `stat = CLI::Kit::System.system('ls', 'a_folder')`
|
|
196
128
|
#
|
|
197
|
-
|
|
198
|
-
params(
|
|
199
|
-
cmd: String,
|
|
200
|
-
args: String,
|
|
201
|
-
sudo: T.any(T::Boolean, String),
|
|
202
|
-
env: T::Hash[String, T.nilable(String)],
|
|
203
|
-
stdin: T.nilable(T.any(IO, String, Integer, Symbol)),
|
|
204
|
-
kwargs: T.untyped,
|
|
205
|
-
block: T.nilable(T.proc.params(out: String, err: String).void),
|
|
206
|
-
)
|
|
207
|
-
.returns(Process::Status)
|
|
208
|
-
end
|
|
129
|
+
#: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], ?stdin: (IO | String | Integer | Symbol)?, **untyped kwargs) ?{ (String out, String err) -> void } -> Process::Status
|
|
209
130
|
def system(cmd, *args, sudo: false, env: ENV.to_h, stdin: nil, **kwargs, &block)
|
|
210
131
|
cmd, args = apply_sudo(cmd, args, sudo)
|
|
211
132
|
|
|
@@ -219,7 +140,8 @@ module CLI
|
|
|
219
140
|
STDIN
|
|
220
141
|
end
|
|
221
142
|
cmd, args = resolve_path(cmd, args, env)
|
|
222
|
-
|
|
143
|
+
process = Process #: as untyped
|
|
144
|
+
pid = process.spawn(env, cmd, *args, 0 => in_stream, :out => out_w, :err => err_w, **kwargs)
|
|
223
145
|
out_w.close
|
|
224
146
|
err_w.close
|
|
225
147
|
|
|
@@ -260,15 +182,16 @@ module CLI
|
|
|
260
182
|
# Split off trailing partial UTF-8 Characters. UTF-8 Multibyte characters start with a 11xxxxxx byte that tells
|
|
261
183
|
# how many following bytes are part of this character, followed by some number of 10xxxxxx bytes. This simple
|
|
262
184
|
# algorithm will split off a whole trailing multi-byte character.
|
|
263
|
-
|
|
185
|
+
#: (String data) -> [String, String]
|
|
264
186
|
def split_partial_characters(data)
|
|
265
|
-
last_byte =
|
|
187
|
+
last_byte = data.getbyte(-1) #: as !nil
|
|
266
188
|
return [data, ''] if (last_byte & 0b1000_0000).zero?
|
|
267
189
|
|
|
268
190
|
# UTF-8 is up to 4 characters per rune, so we could never want to trim more than that, and we want to avoid
|
|
269
191
|
# allocating an array for the whole of data with bytes
|
|
270
192
|
min_bound = -[4, data.bytesize].min
|
|
271
|
-
|
|
193
|
+
fb = data.byteslice(min_bound..-1) #: as !nil
|
|
194
|
+
final_bytes = fb.bytes
|
|
272
195
|
partial_character_sub_index = final_bytes.rindex { |byte| byte & 0b1100_0000 == 0b1100_0000 }
|
|
273
196
|
|
|
274
197
|
# Bail out for non UTF-8
|
|
@@ -293,10 +216,13 @@ module CLI
|
|
|
293
216
|
|
|
294
217
|
partial_character_index = min_bound + partial_character_sub_index
|
|
295
218
|
|
|
296
|
-
[
|
|
219
|
+
[
|
|
220
|
+
data.byteslice(0...partial_character_index), #: as !nil
|
|
221
|
+
data.byteslice(partial_character_index..-1), #: as !nil
|
|
222
|
+
]
|
|
297
223
|
end
|
|
298
224
|
|
|
299
|
-
|
|
225
|
+
#: -> Symbol
|
|
300
226
|
def os
|
|
301
227
|
return :mac if /darwin/.match(RUBY_PLATFORM)
|
|
302
228
|
return :linux if /linux/.match(RUBY_PLATFORM)
|
|
@@ -305,7 +231,7 @@ module CLI
|
|
|
305
231
|
raise "Could not determine OS from platform #{RUBY_PLATFORM}"
|
|
306
232
|
end
|
|
307
233
|
|
|
308
|
-
|
|
234
|
+
#: (String cmd, Hash[String, String?] env) -> String?
|
|
309
235
|
def which(cmd, env)
|
|
310
236
|
exts = os == :windows ? (env['PATHEXT'] || 'exe').split(';') : ['']
|
|
311
237
|
(env['PATH'] || '').split(File::PATH_SEPARATOR).each do |path|
|
|
@@ -320,10 +246,7 @@ module CLI
|
|
|
320
246
|
|
|
321
247
|
private
|
|
322
248
|
|
|
323
|
-
|
|
324
|
-
params(cmd: String, args: T::Array[String], sudo: T.any(T::Boolean, String))
|
|
325
|
-
.returns([String, T::Array[String]])
|
|
326
|
-
end
|
|
249
|
+
#: (String cmd, Array[String] args, (String | bool) sudo) -> [String, Array[String]]
|
|
327
250
|
def apply_sudo(cmd, args, sudo)
|
|
328
251
|
return [cmd, args] if !sudo || Process.uid.zero?
|
|
329
252
|
|
|
@@ -331,21 +254,12 @@ module CLI
|
|
|
331
254
|
['sudo', args.unshift('-E', '-S', '-p', SUDO_PROMPT, '--', cmd)]
|
|
332
255
|
end
|
|
333
256
|
|
|
334
|
-
|
|
335
|
-
params(
|
|
336
|
-
cmd: String,
|
|
337
|
-
args: T::Array[String],
|
|
338
|
-
kwargs: T::Hash[Symbol, T.untyped],
|
|
339
|
-
sudo: T.any(T::Boolean, String),
|
|
340
|
-
env: T::Hash[String, T.nilable(String)],
|
|
341
|
-
method: Symbol,
|
|
342
|
-
block: T.untyped,
|
|
343
|
-
).returns(T.untyped)
|
|
344
|
-
end
|
|
257
|
+
#: (String cmd, Array[String] args, Hash[Symbol, untyped] kwargs, ?sudo: (String | bool), ?env: Hash[String, String?], ?method: Symbol) ?{ (?) -> untyped } -> untyped
|
|
345
258
|
def delegate_open3(cmd, args, kwargs, sudo: raise, env: raise, method: raise, &block)
|
|
346
259
|
cmd, args = apply_sudo(cmd, args, sudo)
|
|
347
260
|
cmd, args = resolve_path(cmd, args, env)
|
|
348
|
-
|
|
261
|
+
open3 = Open3 #: as untyped
|
|
262
|
+
open3.send(method, env, cmd, *args, **kwargs, &block)
|
|
349
263
|
rescue Errno::EINTR
|
|
350
264
|
raise(Errno::EINTR, "command interrupted: #{cmd} #{args.join(" ")}")
|
|
351
265
|
end
|
|
@@ -359,10 +273,7 @@ module CLI
|
|
|
359
273
|
# project.
|
|
360
274
|
#
|
|
361
275
|
# See https://github.com/Shopify/dev/pull/625 for more details.
|
|
362
|
-
|
|
363
|
-
params(cmd: String, args: T::Array[String], env: T::Hash[String, T.nilable(String)])
|
|
364
|
-
.returns([String, T::Array[String]])
|
|
365
|
-
end
|
|
276
|
+
#: (String cmd, Array[String] args, Hash[String, String?] env) -> [String, Array[String]]
|
|
366
277
|
def resolve_path(cmd, args, env)
|
|
367
278
|
# If only one argument was provided, make sure it's interpreted by a shell.
|
|
368
279
|
if args.empty?
|
data/lib/cli/kit/util.rb
CHANGED
|
@@ -6,21 +6,17 @@ module CLI
|
|
|
6
6
|
module Kit
|
|
7
7
|
module Util
|
|
8
8
|
class << self
|
|
9
|
-
extend T::Sig
|
|
10
9
|
#
|
|
11
10
|
# Converts an integer representing bytes into a human readable format
|
|
12
11
|
#
|
|
13
|
-
|
|
12
|
+
#: (Integer bytes, ?precision: Integer, ?space: bool) -> String
|
|
14
13
|
def to_filesize(bytes, precision: 2, space: false)
|
|
15
14
|
to_si_scale(bytes, 'B', precision: precision, space: space, factor: 1024)
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
# Converts a number to a human readable format on the SI scale
|
|
19
18
|
#
|
|
20
|
-
|
|
21
|
-
params(number: Numeric, unit: String, factor: Integer, precision: Integer, space: T::Boolean)
|
|
22
|
-
.returns(String)
|
|
23
|
-
end
|
|
19
|
+
#: (Numeric number, ?String unit, ?factor: Integer, ?precision: Integer, ?space: bool) -> String
|
|
24
20
|
def to_si_scale(number, unit = '', factor: 1000, precision: 2, space: false)
|
|
25
21
|
raise ArgumentError, 'factor should only be 1000 or 1024' unless [1000, 1024].include?(factor)
|
|
26
22
|
|
|
@@ -37,11 +33,11 @@ module CLI
|
|
|
37
33
|
if number < 1
|
|
38
34
|
index = [-scale - 1, small_scale.length].min
|
|
39
35
|
scale = -(index + 1)
|
|
40
|
-
prefix =
|
|
36
|
+
prefix = small_scale[index] #: as !nil
|
|
41
37
|
else
|
|
42
38
|
index = [scale - 1, big_scale.length].min
|
|
43
39
|
scale = index + 1
|
|
44
|
-
prefix =
|
|
40
|
+
prefix = big_scale[index] #: as !nil
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
|
|
@@ -62,10 +58,7 @@ module CLI
|
|
|
62
58
|
# Dir.chdir, when invoked in block form, complains when we call chdir
|
|
63
59
|
# again recursively. There's no apparent good reason for this, so we
|
|
64
60
|
# simply implement our own block form of Dir.chdir here.
|
|
65
|
-
|
|
66
|
-
type_parameters(:T).params(dir: String, block: T.proc.returns(T.type_parameter(:T)))
|
|
67
|
-
.returns(T.type_parameter(:T))
|
|
68
|
-
end
|
|
61
|
+
#: [T] (String dir) { -> T } -> T
|
|
69
62
|
def with_dir(dir, &block)
|
|
70
63
|
prev = Dir.pwd
|
|
71
64
|
begin
|
|
@@ -85,44 +78,35 @@ module CLI
|
|
|
85
78
|
# end.retry_after(ExpectedError) do
|
|
86
79
|
# costly_prep()
|
|
87
80
|
# end
|
|
88
|
-
|
|
89
|
-
type_parameters(:T).params(block_that_might_raise: T.proc.returns(T.type_parameter(:T)))
|
|
90
|
-
.returns(Retrier[T.type_parameter(:T)])
|
|
91
|
-
end
|
|
81
|
+
#: [T] { -> T } -> Retrier[T]
|
|
92
82
|
def begin(&block_that_might_raise)
|
|
93
83
|
Retrier.new(block_that_might_raise)
|
|
94
84
|
end
|
|
95
85
|
end
|
|
96
86
|
|
|
87
|
+
#: [BlockReturnType]
|
|
97
88
|
class Retrier
|
|
98
|
-
|
|
99
|
-
extend T::Generic
|
|
100
|
-
|
|
101
|
-
BlockReturnType = type_member
|
|
102
|
-
|
|
103
|
-
sig { params(block_that_might_raise: T.proc.returns(BlockReturnType)).void }
|
|
89
|
+
#: (^-> BlockReturnType block_that_might_raise) -> void
|
|
104
90
|
def initialize(block_that_might_raise)
|
|
105
91
|
@block_that_might_raise = block_that_might_raise
|
|
106
92
|
end
|
|
107
93
|
|
|
108
|
-
|
|
109
|
-
params(
|
|
110
|
-
exception: T.class_of(Exception),
|
|
111
|
-
retries: Integer,
|
|
112
|
-
before_retry: T.nilable(T.proc.params(e: Exception).void),
|
|
113
|
-
).returns(BlockReturnType)
|
|
114
|
-
end
|
|
94
|
+
#: (?singleton(Exception) exception, ?retries: Integer) ?{ (Exception e) -> void } -> BlockReturnType
|
|
115
95
|
def retry_after(exception = StandardError, retries: 1, &before_retry)
|
|
116
96
|
@block_that_might_raise.call
|
|
117
97
|
rescue exception => e
|
|
118
98
|
raise if (retries -= 1) < 0
|
|
119
99
|
|
|
120
100
|
if before_retry
|
|
101
|
+
# rubocop:disable Style/IdenticalConditionalBranches
|
|
121
102
|
if before_retry.arity == 0
|
|
122
|
-
|
|
103
|
+
prc = before_retry #: as ^() -> void
|
|
104
|
+
prc.call
|
|
123
105
|
else
|
|
124
|
-
|
|
106
|
+
prc = before_retry #: as ^(Exception) -> void
|
|
107
|
+
prc.call(e)
|
|
125
108
|
end
|
|
109
|
+
# rubocop:enable Style/IdenticalConditionalBranches
|
|
126
110
|
end
|
|
127
111
|
retry
|
|
128
112
|
end
|
data/lib/cli/kit/version.rb
CHANGED
data/lib/cli/kit.rb
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
|
|
3
3
|
require 'cli/ui'
|
|
4
|
-
|
|
5
|
-
unless defined?(T)
|
|
6
|
-
require('cli/kit/sorbet_runtime_stub')
|
|
7
|
-
end
|
|
8
|
-
|
|
9
4
|
require 'cli/kit/core_ext'
|
|
10
5
|
|
|
11
6
|
module CLI
|
|
12
7
|
module Kit
|
|
13
|
-
extend T::Sig
|
|
14
|
-
|
|
15
8
|
autoload :Args, 'cli/kit/args'
|
|
16
9
|
autoload :BaseCommand, 'cli/kit/base_command'
|
|
17
10
|
autoload :CommandRegistry, 'cli/kit/command_registry'
|
|
@@ -33,6 +26,9 @@ module CLI
|
|
|
33
26
|
EXIT_BUG = 1
|
|
34
27
|
EXIT_SUCCESS = 0
|
|
35
28
|
|
|
29
|
+
UNTYPED_NIL = nil #: untyped
|
|
30
|
+
private_constant(:UNTYPED_NIL)
|
|
31
|
+
|
|
36
32
|
# Abort, Bug, AbortSilent, and BugSilent are four ways of immediately bailing
|
|
37
33
|
# on command-line execution when an unrecoverable error occurs.
|
|
38
34
|
#
|
|
@@ -76,9 +72,7 @@ module CLI
|
|
|
76
72
|
GenericAbort = Class.new(Exception) # rubocop:disable Lint/InheritException
|
|
77
73
|
|
|
78
74
|
class Abort < GenericAbort # bug:false; silent: false
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
sig { returns(T::Boolean) }
|
|
75
|
+
#: -> bool
|
|
82
76
|
def bug?
|
|
83
77
|
false
|
|
84
78
|
end
|
|
@@ -88,31 +82,25 @@ module CLI
|
|
|
88
82
|
end
|
|
89
83
|
|
|
90
84
|
class BugSilent < GenericAbort # bug:true; silent:true
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
sig { returns(T::Boolean) }
|
|
85
|
+
#: -> bool
|
|
94
86
|
def silent?
|
|
95
87
|
true
|
|
96
88
|
end
|
|
97
89
|
end
|
|
98
90
|
|
|
99
91
|
class AbortSilent < GenericAbort # bug:false; silent:true
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
sig { returns(T::Boolean) }
|
|
92
|
+
#: -> bool
|
|
103
93
|
def bug?
|
|
104
94
|
false
|
|
105
95
|
end
|
|
106
96
|
|
|
107
|
-
|
|
97
|
+
#: -> bool
|
|
108
98
|
def silent?
|
|
109
99
|
true
|
|
110
100
|
end
|
|
111
101
|
end
|
|
112
102
|
|
|
113
103
|
class << self
|
|
114
|
-
extend T::Sig
|
|
115
|
-
|
|
116
104
|
# Mirrors the API of Kernel#raise, but with the addition of a few new
|
|
117
105
|
# optional keyword arguments. `bug` and `silent` attach metadata to the
|
|
118
106
|
# exception being raised, which is interpreted later in the ErrorHandler to
|
|
@@ -121,35 +109,30 @@ module CLI
|
|
|
121
109
|
# `depth` is used to trim leading elements of the backtrace. If you wrap
|
|
122
110
|
# this method in your own wrapper, you'll want to pass `depth: 2`, for
|
|
123
111
|
# example.
|
|
124
|
-
|
|
125
|
-
params(
|
|
126
|
-
exception: T.any(Class, String, Exception),
|
|
127
|
-
string: T.untyped,
|
|
128
|
-
array: T.nilable(T::Array[String]),
|
|
129
|
-
cause: T.nilable(Exception),
|
|
130
|
-
bug: T.nilable(T::Boolean),
|
|
131
|
-
silent: T.nilable(T::Boolean),
|
|
132
|
-
depth: Integer,
|
|
133
|
-
).returns(T.noreturn)
|
|
134
|
-
end
|
|
112
|
+
#: (?(Class | String | Exception) exception, ?untyped string, ?Array[String]? array, ?cause: Exception?, ?bug: bool?, ?silent: bool?, ?fault: Exception::Fault?, ?depth: Integer) -> bot
|
|
135
113
|
def raise(
|
|
136
114
|
# default arguments
|
|
137
|
-
exception =
|
|
115
|
+
exception = UNTYPED_NIL,
|
|
116
|
+
string = UNTYPED_NIL,
|
|
117
|
+
array = UNTYPED_NIL,
|
|
118
|
+
cause: $ERROR_INFO,
|
|
138
119
|
# new arguments
|
|
139
|
-
bug: nil, silent: nil, depth: 1
|
|
120
|
+
bug: nil, silent: nil, fault: nil, depth: 1
|
|
140
121
|
)
|
|
122
|
+
k = Kernel #: as untyped
|
|
141
123
|
if array
|
|
142
|
-
|
|
124
|
+
k.raise(exception, string, array, cause: cause)
|
|
143
125
|
elsif string
|
|
144
|
-
|
|
126
|
+
k.raise(exception, string, Kernel.caller(depth), cause: cause)
|
|
145
127
|
elsif exception.is_a?(String)
|
|
146
|
-
|
|
128
|
+
k.raise(RuntimeError, exception, Kernel.caller(depth), cause: cause)
|
|
147
129
|
else
|
|
148
|
-
|
|
130
|
+
k.raise(exception, exception.message, Kernel.caller(depth), cause: cause)
|
|
149
131
|
end
|
|
150
132
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
151
133
|
e.bug!(bug) unless bug.nil?
|
|
152
134
|
e.silent!(silent) unless silent.nil?
|
|
135
|
+
e.fault!(fault) if fault
|
|
153
136
|
Kernel.raise(e, cause: cause)
|
|
154
137
|
end
|
|
155
138
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cli-kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Burke Libbey
|
|
@@ -26,6 +26,20 @@ dependencies:
|
|
|
26
26
|
- - "~>"
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
28
|
version: '2.4'
|
|
29
|
+
- !ruby/object:Gem::Dependency
|
|
30
|
+
name: logger
|
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
|
32
|
+
requirements:
|
|
33
|
+
- - "~>"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '1.7'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - "~>"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '1.7'
|
|
29
43
|
- !ruby/object:Gem::Dependency
|
|
30
44
|
name: bundler
|
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -81,7 +95,9 @@ extra_rdoc_files: []
|
|
|
81
95
|
files:
|
|
82
96
|
- ".github/CODEOWNERS"
|
|
83
97
|
- ".github/dependabot.yml"
|
|
98
|
+
- ".github/release.yml"
|
|
84
99
|
- ".github/workflows/cla.yml"
|
|
100
|
+
- ".github/workflows/release.yml"
|
|
85
101
|
- ".github/workflows/ruby.yml"
|
|
86
102
|
- ".gitignore"
|
|
87
103
|
- ".rubocop.sorbet.yml"
|
|
@@ -148,7 +164,6 @@ files:
|
|
|
148
164
|
- lib/cli/kit/opts.rb
|
|
149
165
|
- lib/cli/kit/parse_args.rb
|
|
150
166
|
- lib/cli/kit/resolver.rb
|
|
151
|
-
- lib/cli/kit/sorbet_runtime_stub.rb
|
|
152
167
|
- lib/cli/kit/support.rb
|
|
153
168
|
- lib/cli/kit/support/test_helper.rb
|
|
154
169
|
- lib/cli/kit/system.rb
|
|
@@ -165,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
165
180
|
requirements:
|
|
166
181
|
- - ">="
|
|
167
182
|
- !ruby/object:Gem::Version
|
|
168
|
-
version: '3.
|
|
183
|
+
version: '3.2'
|
|
169
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
185
|
requirements:
|
|
171
186
|
- - ">="
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# typed: ignore
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module T
|
|
5
|
-
class << self
|
|
6
|
-
def absurd(value); end
|
|
7
|
-
def all(type_a, type_b, *types); end
|
|
8
|
-
def any(type_a, type_b, *types); end
|
|
9
|
-
def attached_class; end
|
|
10
|
-
def class_of(klass); end
|
|
11
|
-
def enum(values); end
|
|
12
|
-
def nilable(type); end
|
|
13
|
-
def noreturn; end
|
|
14
|
-
def self_type; end
|
|
15
|
-
def type_alias(type = nil, &_blk); end
|
|
16
|
-
def type_parameter(name); end
|
|
17
|
-
def untyped; end
|
|
18
|
-
|
|
19
|
-
def assert_type!(value, _type, _checked: true)
|
|
20
|
-
value
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def cast(value, _type, _checked: true)
|
|
24
|
-
value
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def let(value, _type, _checked: true)
|
|
28
|
-
value
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def must(arg, _msg = nil)
|
|
32
|
-
arg
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def proc
|
|
36
|
-
T::Proc.new
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def reveal_type(value)
|
|
40
|
-
value
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def unsafe(value)
|
|
44
|
-
value
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
module Sig
|
|
49
|
-
def sig(arg0 = nil, &blk); end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
module Helpers
|
|
53
|
-
def abstract!; end
|
|
54
|
-
def interface!; end
|
|
55
|
-
def final!; end
|
|
56
|
-
def sealed!; end
|
|
57
|
-
def mixes_in_class_methods(mod); end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
module Generic
|
|
61
|
-
include(T::Helpers)
|
|
62
|
-
|
|
63
|
-
def type_parameters(*params); end
|
|
64
|
-
def type_member(variance = :invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
|
65
|
-
def type_template(variance = :invariant, fixed: nil, lower: nil, upper: BasicObject); end
|
|
66
|
-
|
|
67
|
-
def [](*types)
|
|
68
|
-
self
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
module Array
|
|
73
|
-
class << self
|
|
74
|
-
def [](type); end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
Boolean = Object.new.freeze
|
|
79
|
-
|
|
80
|
-
module Configuration
|
|
81
|
-
class << self
|
|
82
|
-
def call_validation_error_handler(signature, opts); end
|
|
83
|
-
def call_validation_error_handler=(value); end
|
|
84
|
-
def default_checked_level=(default_checked_level); end
|
|
85
|
-
def enable_checking_for_sigs_marked_checked_tests; end
|
|
86
|
-
def enable_final_checks_on_hooks; end
|
|
87
|
-
def enable_legacy_t_enum_migration_mode; end
|
|
88
|
-
def reset_final_checks_on_hooks; end
|
|
89
|
-
def hard_assert_handler(str, extra); end
|
|
90
|
-
def hard_assert_handler=(value); end
|
|
91
|
-
def inline_type_error_handler(error); end
|
|
92
|
-
def inline_type_error_handler=(value); end
|
|
93
|
-
def log_info_handler(str, extra); end
|
|
94
|
-
def log_info_handler=(value); end
|
|
95
|
-
def scalar_types; end
|
|
96
|
-
def scalar_types=(values); end
|
|
97
|
-
def sealed_violation_whitelist; end
|
|
98
|
-
def sealed_violation_whitelist=(sealed_violation_whitelist); end
|
|
99
|
-
def sig_builder_error_handler=(value); end
|
|
100
|
-
def sig_validation_error_handler(error, opts); end
|
|
101
|
-
def sig_validation_error_handler=(value); end
|
|
102
|
-
def soft_assert_handler(str, extra); end
|
|
103
|
-
def soft_assert_handler=(value); end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
module Enumerable
|
|
108
|
-
class << self
|
|
109
|
-
def [](type); end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
module Enumerator
|
|
114
|
-
class << self
|
|
115
|
-
def [](type); end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
module Hash
|
|
120
|
-
class << self
|
|
121
|
-
def [](keys, values); end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
class Proc
|
|
126
|
-
def bind(*_)
|
|
127
|
-
self
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def params(*_param)
|
|
131
|
-
self
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def void
|
|
135
|
-
self
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def returns(_type)
|
|
139
|
-
self
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
module Range
|
|
144
|
-
class << self
|
|
145
|
-
def [](type); end
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
module Set
|
|
150
|
-
class << self
|
|
151
|
-
def [](type); end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|