cli-kit 5.0.0 → 5.1.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/dependabot.yml +3 -0
- data/.github/workflows/ruby.yml +1 -19
- data/.rubocop.yml +17 -1
- data/.ruby-version +1 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +86 -86
- data/bin/tapioca +1 -2
- data/cli-kit.gemspec +8 -3
- data/dev.yml +7 -2
- data/examples/minimal/example.rb +9 -6
- data/gen/lib/gen/generator.rb +4 -4
- data/gen/lib/gen/help.rb +1 -1
- data/gen/template/dev-gems.yml +1 -1
- data/gen/template/dev-vendor.yml +1 -1
- data/lib/cli/kit/args/evaluation.rb +9 -20
- data/lib/cli/kit/command_help.rb +3 -3
- data/lib/cli/kit/command_registry.rb +4 -4
- data/lib/cli/kit/core_ext.rb +1 -1
- data/lib/cli/kit/error_handler.rb +2 -2
- data/lib/cli/kit/executor.rb +3 -2
- data/lib/cli/kit/opts.rb +11 -4
- data/lib/cli/kit/parse_args.rb +60 -0
- data/lib/cli/kit/sorbet_runtime_stub.rb +0 -2
- data/lib/cli/kit/support/test_helper.rb +4 -2
- data/lib/cli/kit/system.rb +9 -6
- data/lib/cli/kit/util.rb +2 -2
- data/lib/cli/kit/version.rb +1 -1
- data/lib/cli/kit.rb +1 -0
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d726194921593173c9e5ddc6825b4bb450b3b5b349be39801b0178668c3e94a
|
4
|
+
data.tar.gz: 3ab180c9b128bc0c6bdee63b68275273a12a938df484eb94e743f11ff81d28a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7677c4a9ccf218206b5b31f261507f66e12e7d8148be5857025979e282c8e524546015df0c6a612c818de297d6c93157fc15394592d0914eada8b5acd17469aa
|
7
|
+
data.tar.gz: 1a7882f6f3bb2a81dfa50c655c02fef3286badba79e4f5f6e384fc87a5d0953beba48b92eb83981c8124db91980c14d11c41a16d012b99eb3ef8151cc895fd86
|
data/.github/dependabot.yml
CHANGED
data/.github/workflows/ruby.yml
CHANGED
@@ -11,7 +11,6 @@ jobs:
|
|
11
11
|
- name: Set up Ruby
|
12
12
|
uses: ruby/setup-ruby@v1
|
13
13
|
with:
|
14
|
-
ruby-version: '2.7'
|
15
14
|
bundler-cache: true
|
16
15
|
- name: Check style
|
17
16
|
run: bundle exec rake style
|
@@ -23,7 +22,6 @@ jobs:
|
|
23
22
|
- name: Set up Ruby
|
24
23
|
uses: ruby/setup-ruby@v1
|
25
24
|
with:
|
26
|
-
ruby-version: '2.7'
|
27
25
|
bundler-cache: true
|
28
26
|
- name: Typecheck
|
29
27
|
run: bundle exec srb tc
|
@@ -32,25 +30,9 @@ jobs:
|
|
32
30
|
strategy:
|
33
31
|
matrix:
|
34
32
|
os: [macos-latest, ubuntu-latest]
|
35
|
-
ruby-version: ['2.
|
33
|
+
ruby-version: ['3.1', '3.2', '3.3', '3.4']
|
36
34
|
|
37
35
|
runs-on: ${{ matrix.os }}
|
38
|
-
steps:
|
39
|
-
- uses: actions/checkout@v2
|
40
|
-
- name: Set up Ruby
|
41
|
-
uses: ruby/setup-ruby@v1
|
42
|
-
with:
|
43
|
-
ruby-version: ${{ matrix.ruby-version }}
|
44
|
-
bundler-cache: true
|
45
|
-
- name: Run tests
|
46
|
-
run: bundle exec rake test
|
47
|
-
|
48
|
-
test-windows:
|
49
|
-
strategy:
|
50
|
-
matrix:
|
51
|
-
ruby-version: ['2.7', '3.0']
|
52
|
-
|
53
|
-
runs-on: windows-latest
|
54
36
|
env:
|
55
37
|
BUNDLE_WITHOUT: typecheck
|
56
38
|
steps:
|
data/.rubocop.yml
CHANGED
@@ -11,7 +11,7 @@ AllCops:
|
|
11
11
|
Exclude:
|
12
12
|
- gen/template/**/*
|
13
13
|
- vendor/**/*
|
14
|
-
|
14
|
+
- lib/cli/kit/levenshtein.rb # Vendored
|
15
15
|
NewCops: disable
|
16
16
|
|
17
17
|
Style/ClassAndModuleChildren:
|
@@ -51,3 +51,19 @@ Style/GlobalStdStream:
|
|
51
51
|
# Sometimes (often) explicit is good
|
52
52
|
Style/EmptyElse:
|
53
53
|
Enabled: false
|
54
|
+
|
55
|
+
# We make frequent use Open3 methods to run other programs. When passing long command lines, it's useful and informative
|
56
|
+
# to place the argument to an option on the same line as its option, eg:
|
57
|
+
# Open3.capture3(
|
58
|
+
# 'curl',
|
59
|
+
# '-H', 'X-Header: value',
|
60
|
+
# '-o', 'file.txt',
|
61
|
+
# '-L',
|
62
|
+
# 'https://example.com/',
|
63
|
+
# )
|
64
|
+
Layout/MultilineMethodArgumentLineBreaks:
|
65
|
+
Enabled: false
|
66
|
+
Layout/MultilineArrayLineBreaks:
|
67
|
+
Enabled: false
|
68
|
+
Layout/MultilineHashKeyLineBreaks:
|
69
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.4.3
|
data/Gemfile
CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :development, :test do
|
7
|
-
gem 'cli-ui'
|
7
|
+
gem 'cli-ui'
|
8
8
|
gem 'rubocop'
|
9
9
|
gem 'rubocop-rake'
|
10
10
|
gem 'rubocop-shopify'
|
@@ -20,7 +20,7 @@ group :typecheck do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
group :test do
|
23
|
-
gem 'mocha', '~> 2.0
|
23
|
+
gem 'mocha', '~> 2.4.0', require: false
|
24
24
|
gem 'minitest', '>= 5.0.0', require: false
|
25
25
|
gem 'minitest-reporters', require: false
|
26
26
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,118 +1,118 @@
|
|
1
|
-
GIT
|
2
|
-
remote: https://github.com/Shopify/cli-ui
|
3
|
-
revision: 0eefd57248f42ec163639884e77a071d82bfbda8
|
4
|
-
ref: 0eefd57248f42ec163639884e77a071d82bfbda8
|
5
|
-
specs:
|
6
|
-
cli-ui (1.5.1)
|
7
|
-
|
8
1
|
PATH
|
9
2
|
remote: .
|
10
3
|
specs:
|
11
|
-
cli-kit (
|
12
|
-
cli-ui (
|
4
|
+
cli-kit (5.1.0)
|
5
|
+
cli-ui (~> 2.4)
|
13
6
|
|
14
7
|
GEM
|
15
8
|
remote: https://rubygems.org/
|
16
9
|
specs:
|
17
10
|
ansi (1.5.0)
|
18
|
-
ast (2.4.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
11
|
+
ast (2.4.3)
|
12
|
+
benchmark (0.4.1)
|
13
|
+
builder (3.3.0)
|
14
|
+
byebug (12.0.0)
|
15
|
+
cli-ui (2.4.0)
|
16
|
+
docile (1.4.1)
|
17
|
+
erubi (1.13.1)
|
18
|
+
json (2.13.2)
|
19
|
+
language_server-protocol (3.17.0.5)
|
20
|
+
lint_roller (1.1.0)
|
21
|
+
logger (1.7.0)
|
22
|
+
method_source (1.1.0)
|
23
|
+
minitest (5.25.5)
|
24
|
+
minitest-reporters (1.7.1)
|
27
25
|
ansi
|
28
26
|
builder
|
29
27
|
minitest (>= 5.0)
|
30
28
|
ruby-progressbar
|
31
|
-
mocha (2.
|
29
|
+
mocha (2.4.5)
|
32
30
|
ruby2_keywords (>= 0.0.5)
|
33
31
|
netrc (0.11.0)
|
34
|
-
parallel (1.
|
35
|
-
parser (3.
|
32
|
+
parallel (1.27.0)
|
33
|
+
parser (3.3.9.0)
|
36
34
|
ast (~> 2.4.1)
|
35
|
+
racc
|
36
|
+
prism (1.4.0)
|
37
|
+
racc (1.8.1)
|
37
38
|
rainbow (3.1.1)
|
38
|
-
rake (13.0
|
39
|
-
rbi (0.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
regexp_parser (2.
|
45
|
-
rexml (3.
|
46
|
-
rubocop (1.
|
39
|
+
rake (13.3.0)
|
40
|
+
rbi (0.3.6)
|
41
|
+
prism (~> 1.0)
|
42
|
+
rbs (>= 3.4.4)
|
43
|
+
rbs (3.9.4)
|
44
|
+
logger
|
45
|
+
regexp_parser (2.10.0)
|
46
|
+
rexml (3.4.1)
|
47
|
+
rubocop (1.79.0)
|
47
48
|
json (~> 2.3)
|
49
|
+
language_server-protocol (~> 3.17.0.2)
|
50
|
+
lint_roller (~> 1.1.0)
|
48
51
|
parallel (~> 1.10)
|
49
|
-
parser (>= 3.
|
52
|
+
parser (>= 3.3.0.2)
|
50
53
|
rainbow (>= 2.2.2, < 4.0)
|
51
|
-
regexp_parser (>=
|
52
|
-
|
53
|
-
rubocop-ast (>= 1.23.0, < 2.0)
|
54
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
55
|
+
rubocop-ast (>= 1.46.0, < 2.0)
|
54
56
|
ruby-progressbar (~> 1.7)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
rubocop-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
57
|
+
tsort (>= 0.2.0)
|
58
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
59
|
+
rubocop-ast (1.46.0)
|
60
|
+
parser (>= 3.3.7.2)
|
61
|
+
prism (~> 1.4)
|
62
|
+
rubocop-rake (0.7.1)
|
63
|
+
lint_roller (~> 1.1)
|
64
|
+
rubocop (>= 1.72.1)
|
65
|
+
rubocop-shopify (2.17.1)
|
66
|
+
rubocop (~> 1.62)
|
67
|
+
rubocop-sorbet (0.10.5)
|
68
|
+
lint_roller
|
69
|
+
rubocop (>= 1.75.2)
|
70
|
+
ruby-progressbar (1.13.0)
|
65
71
|
ruby2_keywords (0.0.5)
|
66
|
-
simplecov (0.
|
72
|
+
simplecov (0.22.0)
|
67
73
|
docile (~> 1.1)
|
68
74
|
simplecov-html (~> 0.11)
|
69
75
|
simplecov_json_formatter (~> 0.1)
|
70
|
-
simplecov-html (0.
|
76
|
+
simplecov-html (0.13.2)
|
71
77
|
simplecov_json_formatter (0.1.4)
|
72
|
-
sorbet (0.5.
|
73
|
-
sorbet-static (= 0.5.
|
74
|
-
sorbet-runtime (0.5.
|
75
|
-
sorbet-static (0.5.
|
76
|
-
sorbet-static (0.5.
|
77
|
-
sorbet-static (0.5.
|
78
|
-
sorbet-static (0.5.
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
sorbet (
|
87
|
-
sorbet-runtime (= 0.5.10554)
|
88
|
-
spoom (1.1.12)
|
89
|
-
sorbet (>= 0.5.9204)
|
90
|
-
sorbet-runtime (>= 0.5.9204)
|
78
|
+
sorbet (0.5.12358)
|
79
|
+
sorbet-static (= 0.5.12358)
|
80
|
+
sorbet-runtime (0.5.12358)
|
81
|
+
sorbet-static (0.5.12358-aarch64-linux)
|
82
|
+
sorbet-static (0.5.12358-universal-darwin)
|
83
|
+
sorbet-static (0.5.12358-x86_64-linux)
|
84
|
+
sorbet-static-and-runtime (0.5.12358)
|
85
|
+
sorbet (= 0.5.12358)
|
86
|
+
sorbet-runtime (= 0.5.12358)
|
87
|
+
spoom (1.6.3)
|
88
|
+
erubi (>= 1.10.0)
|
89
|
+
prism (>= 0.28.0)
|
90
|
+
rbi (>= 0.3.3)
|
91
|
+
rexml (>= 3.2.6)
|
92
|
+
sorbet-static-and-runtime (>= 0.5.10187)
|
91
93
|
thor (>= 0.19.2)
|
92
|
-
tapioca (0.
|
93
|
-
|
94
|
+
tapioca (0.16.11)
|
95
|
+
benchmark
|
96
|
+
bundler (>= 2.2.25)
|
94
97
|
netrc (>= 0.11.0)
|
95
98
|
parallel (>= 1.21.0)
|
96
|
-
rbi (~> 0.
|
97
|
-
sorbet-static-and-runtime (>= 0.5.
|
98
|
-
spoom (
|
99
|
+
rbi (~> 0.2)
|
100
|
+
sorbet-static-and-runtime (>= 0.5.11087)
|
101
|
+
spoom (>= 1.2.0)
|
99
102
|
thor (>= 1.2.0)
|
100
103
|
yard-sorbet
|
101
|
-
thor (1.
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
yard (0.9.
|
108
|
-
|
109
|
-
|
110
|
-
sorbet-runtime (>= 0.5)
|
111
|
-
yard (>= 0.9)
|
104
|
+
thor (1.4.0)
|
105
|
+
tsort (0.2.0)
|
106
|
+
unicode-display_width (3.1.4)
|
107
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
108
|
+
unicode-emoji (4.0.4)
|
109
|
+
yard (0.9.37)
|
110
|
+
yard-sorbet (0.9.0)
|
111
|
+
sorbet-runtime
|
112
|
+
yard
|
112
113
|
|
113
114
|
PLATFORMS
|
114
|
-
|
115
|
-
ruby
|
115
|
+
aarch64-linux
|
116
116
|
universal-darwin
|
117
117
|
x86_64-linux
|
118
118
|
|
@@ -120,11 +120,11 @@ DEPENDENCIES
|
|
120
120
|
bundler (~> 2.1)
|
121
121
|
byebug
|
122
122
|
cli-kit!
|
123
|
-
cli-ui
|
123
|
+
cli-ui
|
124
124
|
method_source
|
125
125
|
minitest (>= 5.0.0)
|
126
126
|
minitest-reporters
|
127
|
-
mocha (~> 2.0
|
127
|
+
mocha (~> 2.4.0)
|
128
128
|
rake (~> 13.0)
|
129
129
|
rubocop
|
130
130
|
rubocop-rake
|
@@ -135,4 +135,4 @@ DEPENDENCIES
|
|
135
135
|
tapioca
|
136
136
|
|
137
137
|
BUNDLED WITH
|
138
|
-
2.
|
138
|
+
2.6.7
|
data/bin/tapioca
CHANGED
@@ -9,8 +9,7 @@
|
|
9
9
|
#
|
10
10
|
|
11
11
|
require 'pathname'
|
12
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
-
Pathname.new(__FILE__).realpath)
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
14
13
|
|
15
14
|
bundle_binstub = File.expand_path('../bundle', __FILE__)
|
16
15
|
|
data/cli-kit.gemspec
CHANGED
@@ -7,8 +7,11 @@ require 'cli/kit/version'
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = 'cli-kit'
|
9
9
|
spec.version = CLI::Kit::VERSION
|
10
|
-
spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray']
|
11
|
-
spec.email = [
|
10
|
+
spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray', 'Don Kelly']
|
11
|
+
spec.email = [
|
12
|
+
'burke.libbey@shopify.com', 'aaron.olson@shopify.com', 'lisa.ugray@shopify.com',
|
13
|
+
'don.kelly@shopify.com',
|
14
|
+
]
|
12
15
|
|
13
16
|
spec.summary = 'Terminal UI framework extensions'
|
14
17
|
spec.description = 'Terminal UI framework extensions'
|
@@ -22,7 +25,9 @@ Gem::Specification.new do |spec|
|
|
22
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
26
|
spec.require_paths = ['lib']
|
24
27
|
|
25
|
-
spec.add_runtime_dependency('cli-ui', '~> 2.
|
28
|
+
spec.add_runtime_dependency('cli-ui', '~> 2.4')
|
29
|
+
|
30
|
+
spec.required_ruby_version = '>= 3.0'
|
26
31
|
|
27
32
|
spec.add_development_dependency('bundler', '~> 2.1')
|
28
33
|
spec.add_development_dependency('minitest', '~> 5.0')
|
data/dev.yml
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
+
nix: true
|
2
|
+
|
1
3
|
up:
|
2
|
-
-
|
4
|
+
- packages:
|
3
5
|
- fswatch
|
4
|
-
- ruby
|
6
|
+
- ruby
|
5
7
|
- bundler
|
6
8
|
|
7
9
|
commands:
|
10
|
+
add-back-ruby:
|
11
|
+
run: bundle lock --add-platform ruby && git commit -a -m 'Add back ruby platform' && git push
|
12
|
+
aliases: [abr]
|
8
13
|
console: irb -I./lib -rcli/kit
|
9
14
|
check:
|
10
15
|
run: 'srb && rake style test'
|
data/examples/minimal/example.rb
CHANGED
@@ -9,12 +9,15 @@ CLI::UI::StdoutRouter.enable
|
|
9
9
|
include(CLI::Kit)
|
10
10
|
|
11
11
|
registry = CommandRegistry.new(default: 'hello')
|
12
|
-
registry.add(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
12
|
+
registry.add(
|
13
|
+
Class.new(BaseCommand) do
|
14
|
+
sig { params(_args: T::Array[String], _name: String).void }
|
15
|
+
def call(_args, _name)
|
16
|
+
puts 'hello, world!'
|
17
|
+
end
|
18
|
+
end,
|
19
|
+
'hello',
|
20
|
+
)
|
18
21
|
|
19
22
|
executor = Executor.new(log_file: '/tmp/example.log')
|
20
23
|
error_handler = ErrorHandler.new(log_file: '/tmp/example.log', exception_reporter: nil)
|
data/gen/lib/gen/generator.rb
CHANGED
@@ -149,10 +149,10 @@ module Gen
|
|
149
149
|
sig { params(s: String).returns(String) }
|
150
150
|
def apply_template_variables(s)
|
151
151
|
s
|
152
|
-
.gsub(
|
153
|
-
.gsub(
|
154
|
-
.gsub(
|
155
|
-
.gsub(
|
152
|
+
.gsub('__app__', @project_name)
|
153
|
+
.gsub('__App__', @title_case_project_name)
|
154
|
+
.gsub('__cli-kit-version__', cli_kit_version)
|
155
|
+
.gsub('__cli-ui-version__', cli_ui_version)
|
156
156
|
end
|
157
157
|
|
158
158
|
sig { returns(String) }
|
data/gen/lib/gen/help.rb
CHANGED
@@ -40,7 +40,7 @@ module Gen
|
|
40
40
|
max_len = cmds.map(&:first).map(&:length).max
|
41
41
|
|
42
42
|
cmds.each do |name, desc|
|
43
|
-
to.write(CLI::UI.fmt(" {{command:#{name.ljust(max_len)}}} #{desc}\n"))
|
43
|
+
to.write(CLI::UI.fmt(" {{command:#{name.ljust(T.must(max_len))}}} #{desc}\n"))
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
data/gen/template/dev-gems.yml
CHANGED
data/gen/template/dev-vendor.yml
CHANGED
@@ -151,7 +151,7 @@ module CLI
|
|
151
151
|
next unless opt.required?
|
152
152
|
|
153
153
|
node = @parse.detect do |node|
|
154
|
-
node.is_a?(Parser::Node::Option) && node.name == opt.name
|
154
|
+
node.is_a?(Parser::Node::Option) && node.name.to_sym == opt.name
|
155
155
|
end
|
156
156
|
if !node || T.cast(node, Parser::Node::Option).value.nil?
|
157
157
|
raise(MissingRequiredOption, opt.as_written_by_user)
|
@@ -199,26 +199,15 @@ module CLI
|
|
199
199
|
|
200
200
|
sig { params(opt: Definition::Option).returns(T.any(NilClass, String, T::Array[String])) }
|
201
201
|
def lookup_option(opt)
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
return(opt.multi? ? matches.map(&:value) : last.value)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
if opt.long
|
213
|
-
opts = T.cast(
|
214
|
-
parse.select { |node| node.is_a?(Parser::Node::LongOption) },
|
215
|
-
T::Array[Parser::Node::LongOption],
|
216
|
-
)
|
217
|
-
matches = opts.select { |node| node.name == opt.long }
|
218
|
-
if (last = matches.last)
|
219
|
-
return(opt.multi? ? matches.map(&:value) : last.value)
|
220
|
-
end
|
202
|
+
opts = T.cast(
|
203
|
+
parse.select { |node| node.is_a?(Parser::Node::ShortOption) || node.is_a?(Parser::Node::LongOption) },
|
204
|
+
T::Array[T.any(Parser::Node::ShortOption, Parser::Node::LongOption)],
|
205
|
+
)
|
206
|
+
matches = opts.select { |node| (opt.short && node.name == opt.short) || (opt.long && node.name == opt.long) }
|
207
|
+
if (last = matches.last)
|
208
|
+
return (opt.multi? ? matches.map(&:value) : last.value)
|
221
209
|
end
|
210
|
+
|
222
211
|
opt.default
|
223
212
|
end
|
224
213
|
|
data/lib/cli/kit/command_help.rb
CHANGED
@@ -135,7 +135,7 @@ module CLI
|
|
135
135
|
sig { returns(T.nilable(String)) }
|
136
136
|
def build_options
|
137
137
|
opts = opts_class
|
138
|
-
return
|
138
|
+
return unless opts
|
139
139
|
|
140
140
|
methods = []
|
141
141
|
loop do
|
@@ -149,7 +149,7 @@ module CLI
|
|
149
149
|
o = opts.new
|
150
150
|
o.define!(@defn)
|
151
151
|
|
152
|
-
return
|
152
|
+
return if @defn.options.empty? && @defn.flags.empty?
|
153
153
|
|
154
154
|
merged = T.let(@defn.options, T::Array[T.any(Args::Definition::Option, Args::Definition::Flag)])
|
155
155
|
merged += @defn.flags
|
@@ -238,7 +238,7 @@ module CLI
|
|
238
238
|
|
239
239
|
sig { returns(T.nilable(String)) }
|
240
240
|
def build_examples
|
241
|
-
return
|
241
|
+
return unless @examples
|
242
242
|
|
243
243
|
cmd_prefix = " {{command:#{CommandHelp._tool_name} #{_command_name}}}"
|
244
244
|
"{{bold:Examples:}}\n" + @examples.map do |command, explanation|
|
@@ -107,15 +107,15 @@ module CLI
|
|
107
107
|
sig { params(name: String).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
|
108
108
|
def resolve_command(name)
|
109
109
|
name = resolve_alias(name)
|
110
|
-
resolve_global_command(name) ||
|
111
|
-
resolve_contextual_command(name) ||
|
110
|
+
resolve_global_command(name) ||
|
111
|
+
resolve_contextual_command(name) ||
|
112
112
|
[nil, name]
|
113
113
|
end
|
114
114
|
|
115
115
|
sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
|
116
116
|
def resolve_global_command(name)
|
117
117
|
klass = resolve_class(commands.fetch(name, nil))
|
118
|
-
return
|
118
|
+
return unless klass
|
119
119
|
|
120
120
|
[klass, name]
|
121
121
|
rescue NameError
|
@@ -125,7 +125,7 @@ module CLI
|
|
125
125
|
sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
|
126
126
|
def resolve_contextual_command(name)
|
127
127
|
found = @contextual_resolver.command_names.include?(name)
|
128
|
-
return
|
128
|
+
return unless found
|
129
129
|
|
130
130
|
[@contextual_resolver.command_class(name), name]
|
131
131
|
end
|
data/lib/cli/kit/core_ext.rb
CHANGED
@@ -133,9 +133,9 @@ module CLI
|
|
133
133
|
sig { params(error: T.nilable(Exception)).returns(T.nilable(Exception)) }
|
134
134
|
def exception_for_submission(error)
|
135
135
|
# happens on normal non-error termination
|
136
|
-
return
|
136
|
+
return if error.nil?
|
137
137
|
|
138
|
-
return
|
138
|
+
return unless error.bug?
|
139
139
|
|
140
140
|
case error
|
141
141
|
when SignalException
|
data/lib/cli/kit/executor.rb
CHANGED
@@ -56,8 +56,9 @@ module CLI
|
|
56
56
|
end
|
57
57
|
|
58
58
|
sig do
|
59
|
-
type_parameters(:T)
|
60
|
-
block: T.proc.returns(T.type_parameter(:T)))
|
59
|
+
type_parameters(:T)
|
60
|
+
.params(signal: String, handler: Method, block: T.proc.returns(T.type_parameter(:T)))
|
61
|
+
.returns(T.type_parameter(:T))
|
61
62
|
end
|
62
63
|
def twrap(signal, handler, &block)
|
63
64
|
return yield unless Signal.list.key?(signal)
|
data/lib/cli/kit/opts.rb
CHANGED
@@ -180,17 +180,24 @@ module CLI
|
|
180
180
|
|
181
181
|
private
|
182
182
|
|
183
|
+
sig { params(label: T.nilable(String)).returns(T.nilable(Symbol)) }
|
184
|
+
def symbolize(label)
|
185
|
+
return if label.nil?
|
186
|
+
|
187
|
+
label.split('#').last&.to_sym
|
188
|
+
end
|
189
|
+
|
183
190
|
sig { returns(Symbol) }
|
184
191
|
def infer_name
|
185
192
|
to_skip = 1
|
186
|
-
Kernel.caller_locations
|
193
|
+
Kernel.caller_locations.each do |loc|
|
187
194
|
next if loc.path =~ /sorbet-runtime/
|
188
195
|
|
189
196
|
if to_skip > 0
|
190
197
|
to_skip -= 1
|
191
198
|
next
|
192
199
|
end
|
193
|
-
return
|
200
|
+
return T.must(symbolize(loc.label))
|
194
201
|
end
|
195
202
|
raise(ArgumentError, 'could not infer name')
|
196
203
|
end
|
@@ -218,7 +225,7 @@ module CLI
|
|
218
225
|
).returns(T.untyped)
|
219
226
|
end
|
220
227
|
def each_option(&block)
|
221
|
-
return
|
228
|
+
return enum_for(:each_option) unless block_given?
|
222
229
|
|
223
230
|
obj = assert_result!
|
224
231
|
obj.defn.options.each do |opt|
|
@@ -236,7 +243,7 @@ module CLI
|
|
236
243
|
).returns(T.untyped)
|
237
244
|
end
|
238
245
|
def each_flag(&block)
|
239
|
-
return
|
246
|
+
return enum_for(:each_flag) unless block_given?
|
240
247
|
|
241
248
|
obj = assert_result!
|
242
249
|
obj.defn.flags.each do |flag|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module Kit
|
5
|
+
module ParseArgs
|
6
|
+
# because sorbet type-checking takes the pedantic route that module doesn't include Kernel, therefore
|
7
|
+
# this is necessary (even tho it's ~probably fine~)
|
8
|
+
include Kernel
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
# T.untyped is used in two places. The interpretation of dynamic values from the provided `opts`
|
12
|
+
# and the resulting args[:opts] is pretty broad. There seems to be minimal value in expressing a
|
13
|
+
# tighter subset of T.untyped.
|
14
|
+
|
15
|
+
sig do
|
16
|
+
params(
|
17
|
+
args: T.any(Array, String),
|
18
|
+
opts_defn: T::Hash[Symbol, T::Array[T.untyped]],
|
19
|
+
).returns(T::Hash[Symbol, T.untyped])
|
20
|
+
end
|
21
|
+
def parse_args(args, opts_defn)
|
22
|
+
start_opts, parser_config = opts_defn.reduce([{}, []]) do |(ini, pcfg), (n, cfg)|
|
23
|
+
(vals, desc, short, klass) = cfg
|
24
|
+
(init_val, def_val) = Array(vals)
|
25
|
+
|
26
|
+
[
|
27
|
+
init_val.nil? ? ini : ini.merge(n => init_val),
|
28
|
+
pcfg + [[n, short, desc, def_val, klass]],
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
require('optparse')
|
33
|
+
|
34
|
+
acc_opts = {}
|
35
|
+
prsr = OptionParser.new do |opt_p|
|
36
|
+
parser_config.each do |(n, short, desc, def_val, klass)|
|
37
|
+
(_, mark) = short.split(' ')
|
38
|
+
long = "--#{n.to_s.tr("_", "-")}" + (mark.nil? ? '' : " #{mark}")
|
39
|
+
opt_args = klass.nil? ? [short, long, desc] : [short, long, klass, desc]
|
40
|
+
|
41
|
+
T.unsafe(opt_p).on(*opt_args) do |v|
|
42
|
+
acc_opts[n] = if acc_opts.key?(n)
|
43
|
+
Array(acc_opts[n]) + Array(v || def_val)
|
44
|
+
else
|
45
|
+
v || def_val
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
arg_v = (args.is_a?(Array) ? args : args.strip.split(/\s+/)).map(&:strip)
|
52
|
+
sub = prsr.parse(arg_v)
|
53
|
+
|
54
|
+
{ opts: start_opts.merge(acc_opts) }.tap do |a|
|
55
|
+
a[:sub] = sub if sub
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -94,10 +94,8 @@ module T
|
|
94
94
|
def log_info_handler=(value); end
|
95
95
|
def scalar_types; end
|
96
96
|
def scalar_types=(values); end
|
97
|
-
# rubocop:disable Naming/InclusiveLanguage
|
98
97
|
def sealed_violation_whitelist; end
|
99
98
|
def sealed_violation_whitelist=(sealed_violation_whitelist); end
|
100
|
-
# rubocop:enable Naming/InclusiveLanguage
|
101
99
|
def sig_builder_error_handler=(value); end
|
102
100
|
def sig_validation_error_handler(error, opts); end
|
103
101
|
def sig_validation_error_handler=(value); end
|
@@ -21,6 +21,8 @@ module CLI
|
|
21
21
|
def teardown
|
22
22
|
super
|
23
23
|
assert_all_commands_run
|
24
|
+
rescue Errno::EACCES
|
25
|
+
# this sometimes happens on windows builds - let's ignore it
|
24
26
|
end
|
25
27
|
|
26
28
|
module FakeConfig
|
@@ -223,7 +225,7 @@ module CLI
|
|
223
225
|
EOF
|
224
226
|
end
|
225
227
|
|
226
|
-
return
|
228
|
+
return if final_error.empty?
|
227
229
|
|
228
230
|
"\n" + final_error.join("\n") # Initial new line for formatting reasons
|
229
231
|
end
|
@@ -235,7 +237,7 @@ module CLI
|
|
235
237
|
|
236
238
|
if expected_cmd.nil?
|
237
239
|
@delegate_open3[a.join(' ')] = { unexpected: true }
|
238
|
-
return
|
240
|
+
return
|
239
241
|
end
|
240
242
|
|
241
243
|
expected_cmd[:run] = true
|
data/lib/cli/kit/system.rb
CHANGED
@@ -237,11 +237,15 @@ module CLI
|
|
237
237
|
|
238
238
|
previous_trailing = Hash.new('')
|
239
239
|
loop do
|
240
|
+
break if Process.wait(pid, Process::WNOHANG)
|
241
|
+
|
240
242
|
ios = [err_r, out_r].reject(&:closed?)
|
241
|
-
|
243
|
+
next if ios.empty?
|
244
|
+
|
245
|
+
readers, = IO.select(ios, [], [], 1)
|
246
|
+
next if readers.nil? # If IO.select times out we iterate again so we can check if the process has exited
|
242
247
|
|
243
|
-
readers
|
244
|
-
(readers || []).each do |io|
|
248
|
+
readers.each do |io|
|
245
249
|
data, trailing = split_partial_characters(io.readpartial(4096))
|
246
250
|
handlers[io].call(previous_trailing[io] + data)
|
247
251
|
previous_trailing[io] = trailing
|
@@ -250,7 +254,6 @@ module CLI
|
|
250
254
|
end
|
251
255
|
end
|
252
256
|
|
253
|
-
Process.wait(pid)
|
254
257
|
$CHILD_STATUS
|
255
258
|
end
|
256
259
|
|
@@ -297,7 +300,7 @@ module CLI
|
|
297
300
|
def os
|
298
301
|
return :mac if /darwin/.match(RUBY_PLATFORM)
|
299
302
|
return :linux if /linux/.match(RUBY_PLATFORM)
|
300
|
-
return :windows if /
|
303
|
+
return :windows if /mingw/.match(RUBY_PLATFORM)
|
301
304
|
|
302
305
|
raise "Could not determine OS from platform #{RUBY_PLATFORM}"
|
303
306
|
end
|
@@ -322,7 +325,7 @@ module CLI
|
|
322
325
|
.returns([String, T::Array[String]])
|
323
326
|
end
|
324
327
|
def apply_sudo(cmd, args, sudo)
|
325
|
-
return [cmd, args]
|
328
|
+
return [cmd, args] if !sudo || Process.uid.zero?
|
326
329
|
|
327
330
|
sudo_reason(sudo) if sudo.is_a?(String)
|
328
331
|
['sudo', args.unshift('-E', '-S', '-p', SUDO_PROMPT, '--', cmd)]
|
data/lib/cli/kit/util.rb
CHANGED
@@ -18,8 +18,8 @@ module CLI
|
|
18
18
|
# Converts a number to a human readable format on the SI scale
|
19
19
|
#
|
20
20
|
sig do
|
21
|
-
params(number: Numeric, unit: String, factor: Integer, precision: Integer,
|
22
|
-
|
21
|
+
params(number: Numeric, unit: String, factor: Integer, precision: Integer, space: T::Boolean)
|
22
|
+
.returns(String)
|
23
23
|
end
|
24
24
|
def to_si_scale(number, unit = '', factor: 1000, precision: 2, space: false)
|
25
25
|
raise ArgumentError, 'factor should only be 1000 or 1024' unless [1000, 1024].include?(factor)
|
data/lib/cli/kit/version.rb
CHANGED
data/lib/cli/kit.rb
CHANGED
@@ -23,6 +23,7 @@ module CLI
|
|
23
23
|
autoload :Levenshtein, 'cli/kit/levenshtein'
|
24
24
|
autoload :Logger, 'cli/kit/logger'
|
25
25
|
autoload :Opts, 'cli/kit/opts'
|
26
|
+
autoload :ParseArgs, 'cli/kit/parse_args'
|
26
27
|
autoload :Resolver, 'cli/kit/resolver'
|
27
28
|
autoload :Support, 'cli/kit/support'
|
28
29
|
autoload :System, 'cli/kit/system'
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cli-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
- Aaron Olson
|
9
9
|
- Lisa Ugray
|
10
|
-
|
10
|
+
- Don Kelly
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: cli-ui
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '2.
|
21
|
+
version: '2.4'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '2.
|
28
|
+
version: '2.4'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: bundler
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +73,7 @@ email:
|
|
73
73
|
- burke.libbey@shopify.com
|
74
74
|
- aaron.olson@shopify.com
|
75
75
|
- lisa.ugray@shopify.com
|
76
|
+
- don.kelly@shopify.com
|
76
77
|
executables:
|
77
78
|
- cli-kit
|
78
79
|
extensions: []
|
@@ -85,6 +86,7 @@ files:
|
|
85
86
|
- ".gitignore"
|
86
87
|
- ".rubocop.sorbet.yml"
|
87
88
|
- ".rubocop.yml"
|
89
|
+
- ".ruby-version"
|
88
90
|
- Gemfile
|
89
91
|
- Gemfile.lock
|
90
92
|
- LICENSE.txt
|
@@ -144,6 +146,7 @@ files:
|
|
144
146
|
- lib/cli/kit/levenshtein.rb
|
145
147
|
- lib/cli/kit/logger.rb
|
146
148
|
- lib/cli/kit/opts.rb
|
149
|
+
- lib/cli/kit/parse_args.rb
|
147
150
|
- lib/cli/kit/resolver.rb
|
148
151
|
- lib/cli/kit/sorbet_runtime_stub.rb
|
149
152
|
- lib/cli/kit/support.rb
|
@@ -155,7 +158,6 @@ homepage: https://github.com/shopify/cli-kit
|
|
155
158
|
licenses:
|
156
159
|
- MIT
|
157
160
|
metadata: {}
|
158
|
-
post_install_message:
|
159
161
|
rdoc_options: []
|
160
162
|
require_paths:
|
161
163
|
- lib
|
@@ -163,15 +165,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
165
|
requirements:
|
164
166
|
- - ">="
|
165
167
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
168
|
+
version: '3.0'
|
167
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
170
|
requirements:
|
169
171
|
- - ">="
|
170
172
|
- !ruby/object:Gem::Version
|
171
173
|
version: '0'
|
172
174
|
requirements: []
|
173
|
-
rubygems_version: 3.
|
174
|
-
signing_key:
|
175
|
+
rubygems_version: 3.6.7
|
175
176
|
specification_version: 4
|
176
177
|
summary: Terminal UI framework extensions
|
177
178
|
test_files: []
|