cli-kit 3.1.0 → 3.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 +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.github/probots.yml +2 -0
- data/Gemfile.lock +3 -3
- data/TODO.md +5 -0
- data/cli-kit.gemspec +2 -2
- data/examples/README.md +21 -0
- data/examples/minimal/example.rb +22 -0
- data/examples/single-file/example.rb +71 -0
- data/examples/todo-list/README.md +1 -0
- data/gen/template/lib/__app__/commands/example.rb +0 -1
- data/lib/cli/kit/base_command.rb +4 -3
- data/lib/cli/kit/config.rb +4 -4
- data/lib/cli/kit/error_handler.rb +10 -1
- data/lib/cli/kit/executor.rb +8 -2
- data/lib/cli/kit/ini.rb +7 -3
- data/lib/cli/kit/support/test_helper.rb +18 -0
- data/lib/cli/kit/system.rb +6 -2
- data/lib/cli/kit/version.rb +1 -1
- metadata +12 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a1c78454dde57819601c7ef40040c02943b72ea2f3831718a2a4362731c2cf9a
|
4
|
+
data.tar.gz: 6e4e1adcdd54eb38d419b2d2d936ec03a05190cf72baaabd1002e1407dfdcf49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f57fe58683a342a39957fd19cedc79641583456100e7e63b71e4e395b0fc705938ccaa1574bc36d975dda6f6b5c7fcbf28406972432abcf3ac890bb1334e2715
|
7
|
+
data.tar.gz: 5f1f0bf80809f7ff4ae97ab4cd0871ceaef6b4c4967b06fdcae5ccb1c869524c351c1a2acf7cab83cd2416ce37766033b5c63d6ff2480fd660067d74dcc51f8f
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
@Shopify/dev-infra
|
data/.github/probots.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cli-kit (3.
|
4
|
+
cli-kit (3.3.0)
|
5
5
|
cli-ui (>= 1.1.4)
|
6
6
|
|
7
7
|
GEM
|
@@ -11,7 +11,7 @@ GEM
|
|
11
11
|
ast (2.4.0)
|
12
12
|
builder (3.2.3)
|
13
13
|
byebug (9.0.6)
|
14
|
-
cli-ui (1.
|
14
|
+
cli-ui (1.2.3)
|
15
15
|
metaclass (0.0.4)
|
16
16
|
method_source (0.8.2)
|
17
17
|
minitest (5.10.2)
|
@@ -53,4 +53,4 @@ DEPENDENCIES
|
|
53
53
|
rubocop (~> 0.56.0)
|
54
54
|
|
55
55
|
BUNDLED WITH
|
56
|
-
1.
|
56
|
+
1.17.3
|
data/TODO.md
ADDED
data/cli-kit.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'cli/kit/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'cli-kit'
|
8
8
|
spec.version = CLI::Kit::VERSION
|
9
|
-
spec.authors = ['Burke Libbey', '
|
10
|
-
spec.email = ['burke.libbey@shopify.com', '
|
9
|
+
spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray']
|
10
|
+
spec.email = ['burke.libbey@shopify.com', 'aaron.olson@shopify.com', 'lisa.ugray@shopify.com']
|
11
11
|
|
12
12
|
spec.summary = 'Terminal UI framework extensions'
|
13
13
|
spec.description = 'Terminal UI framework extensions'
|
data/examples/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Examples
|
2
|
+
|
3
|
+
**Note: If you're looking to bootstrap a new app, consider running `cli-kit new` instead of
|
4
|
+
copy/pasting one of these.**
|
5
|
+
|
6
|
+
## Full Example
|
7
|
+
|
8
|
+
The full example lives in its own repository at https://github.com/Shopify/cli-kit-example.
|
9
|
+
This is quite similar to the output of `cli-kit new`, but fleshed out a little bit more with
|
10
|
+
a couple of commands.
|
11
|
+
|
12
|
+
## Single-File starting point
|
13
|
+
|
14
|
+
Maybe it appeals to you to start from a single file and grow, rather than generating framework.
|
15
|
+
Check out the [`examples/single-file`](single-file) example.
|
16
|
+
|
17
|
+
## Minimal example
|
18
|
+
|
19
|
+
This example demonstrates the core of what `cli-kit` does very simply, but in general, shouldn't be
|
20
|
+
used for anything other than quick hacks. It leaves out a few best practices that help CLI apps
|
21
|
+
scale gracefully. Find it at [`examples/minimal`](minimal).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cli/ui'
|
4
|
+
require 'cli/kit'
|
5
|
+
|
6
|
+
CLI::UI::StdoutRouter.enable
|
7
|
+
|
8
|
+
include CLI::Kit
|
9
|
+
|
10
|
+
registry = CommandRegistry.new(default: 'hello', contextual_resolver: nil)
|
11
|
+
registry.add(Class.new(BaseCommand) do
|
12
|
+
def call(_args, _name)
|
13
|
+
puts "hello, world!"
|
14
|
+
end
|
15
|
+
end, 'hello')
|
16
|
+
|
17
|
+
executor = Executor.new(log_file: '/tmp/example.log')
|
18
|
+
error_handler = ErrorHandler.new(log_file: '/tmp/example.log', exception_reporter: nil)
|
19
|
+
resolver = Resolver.new(tool_name: 'example', command_registry: registry)
|
20
|
+
entry_point = ->(args) { executor.call(*resolver.call(args)) }
|
21
|
+
|
22
|
+
exit(error_handler.call { entry_point.call(ARGV.dup) }) if __FILE__ == $PROGRAM_NAME
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cli/ui'
|
4
|
+
require 'cli/kit'
|
5
|
+
|
6
|
+
CLI::UI::StdoutRouter.enable
|
7
|
+
|
8
|
+
module Example
|
9
|
+
extend CLI::Kit::Autocall
|
10
|
+
|
11
|
+
TOOL_NAME = 'example'
|
12
|
+
ROOT = File.expand_path('../..', __FILE__)
|
13
|
+
LOG_FILE = '/tmp/example.log'
|
14
|
+
|
15
|
+
module Commands
|
16
|
+
extend CLI::Kit::Autocall
|
17
|
+
|
18
|
+
Registry = CLI::Kit::CommandRegistry.new(
|
19
|
+
default: 'hello',
|
20
|
+
contextual_resolver: nil
|
21
|
+
)
|
22
|
+
|
23
|
+
def self.register(const, cmd, path = nil, &block)
|
24
|
+
path ? autoload(const, path) : autocall(const, &block)
|
25
|
+
Registry.add(->() { const_get(const) }, cmd)
|
26
|
+
end
|
27
|
+
|
28
|
+
# register(:Hello, 'hello', 'a/b/hello')
|
29
|
+
|
30
|
+
register(:Hello, 'hello') do
|
31
|
+
Class.new(Example::Command) do
|
32
|
+
def call(_args, _name)
|
33
|
+
puts "hello, world!"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
autocall(:EntryPoint) do
|
40
|
+
Module.new do
|
41
|
+
def self.call(args)
|
42
|
+
cmd, command_name, args = Example::Resolver.call(args)
|
43
|
+
Example::Executor.call(cmd, command_name, args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
autocall(:Config) { CLI::Kit::Config.new(tool_name: TOOL_NAME) }
|
49
|
+
autocall(:Command) { CLI::Kit::BaseCommand }
|
50
|
+
|
51
|
+
autocall(:Executor) { CLI::Kit::Executor.new(log_file: LOG_FILE) }
|
52
|
+
autocall(:Resolver) do
|
53
|
+
CLI::Kit::Resolver.new(
|
54
|
+
tool_name: TOOL_NAME,
|
55
|
+
command_registry: Example::Commands::Registry
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
autocall(:ErrorHandler) do
|
60
|
+
CLI::Kit::ErrorHandler.new(
|
61
|
+
log_file: LOG_FILE,
|
62
|
+
exception_reporter: nil
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
if __FILE__ == $PROGRAM_NAME
|
68
|
+
exit(Example::ErrorHandler.call do
|
69
|
+
Example::EntryPoint.call(ARGV.dup)
|
70
|
+
end)
|
71
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Full example at https://github.com/Shopify/cli-kit-example
|
data/lib/cli/kit/base_command.rb
CHANGED
@@ -17,21 +17,22 @@ module CLI
|
|
17
17
|
|
18
18
|
def self.call(args, command_name)
|
19
19
|
cmd = new
|
20
|
-
stats_tags = cmd.stats_tags(args)
|
20
|
+
stats_tags = cmd.stats_tags(args, command_name)
|
21
21
|
begin
|
22
22
|
statsd_increment("cli.command.invoked", tags: stats_tags)
|
23
23
|
statsd_time("cli.command.time", tags: stats_tags) do
|
24
24
|
cmd.call(args, command_name)
|
25
25
|
end
|
26
26
|
statsd_increment("cli.command.success", tags: stats_tags)
|
27
|
-
rescue => e
|
27
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
28
28
|
statsd_increment("cli.command.exception", tags: stats_tags + ["exception:#{e.class}"])
|
29
29
|
raise e
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def stats_tags(args)
|
33
|
+
def stats_tags(args, command_name)
|
34
34
|
tags = ["task:#{self.class}"]
|
35
|
+
tags << "command:#{command_name}" if command_name
|
35
36
|
tags << "subcommand:#{args.first}" if args&.first && has_subcommands?
|
36
37
|
tags
|
37
38
|
end
|
data/lib/cli/kit/config.rb
CHANGED
@@ -23,13 +23,13 @@ module CLI
|
|
23
23
|
# #### Example Usage
|
24
24
|
# `config.get('name.of.config')`
|
25
25
|
#
|
26
|
-
def get(section, name)
|
27
|
-
all_configs.dig("[#{section}]", name) ||
|
26
|
+
def get(section, name, default: false)
|
27
|
+
all_configs.dig("[#{section}]", name) || default
|
28
28
|
end
|
29
29
|
|
30
30
|
# Coalesce and enforce the value of a config to a boolean
|
31
|
-
def get_bool(section, name)
|
32
|
-
case get(section, name).to_s
|
31
|
+
def get_bool(section, name, default: false)
|
32
|
+
case get(section, name, default: default).to_s
|
33
33
|
when "true"
|
34
34
|
true
|
35
35
|
when "false"
|
@@ -4,9 +4,10 @@ require 'English'
|
|
4
4
|
module CLI
|
5
5
|
module Kit
|
6
6
|
class ErrorHandler
|
7
|
-
def initialize(log_file:, exception_reporter:)
|
7
|
+
def initialize(log_file:, exception_reporter:, tool_name: nil)
|
8
8
|
@log_file = log_file
|
9
9
|
@exception_reporter_or_proc = exception_reporter || NullExceptionReporter
|
10
|
+
@tool_name = tool_name
|
10
11
|
end
|
11
12
|
|
12
13
|
module NullExceptionReporter
|
@@ -84,6 +85,14 @@ module CLI
|
|
84
85
|
rescue Interrupt
|
85
86
|
$stderr.puts(format_error_message("Interrupt"))
|
86
87
|
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
88
|
+
rescue Errno::ENOSPC
|
89
|
+
message = if @tool_name
|
90
|
+
"Your disk is full - {{command:#{@tool_name}}} requires free space to operate"
|
91
|
+
else
|
92
|
+
"Your disk is full - free space is required to operate"
|
93
|
+
end
|
94
|
+
$stderr.puts(format_error_message(message))
|
95
|
+
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
87
96
|
end
|
88
97
|
|
89
98
|
def exception_reporter
|
data/lib/cli/kit/executor.rb
CHANGED
@@ -16,8 +16,14 @@ module CLI
|
|
16
16
|
begin
|
17
17
|
command.call(args, command_name)
|
18
18
|
rescue => e
|
19
|
-
|
20
|
-
|
19
|
+
begin
|
20
|
+
$stderr.puts "This command ran with ID: #{id}"
|
21
|
+
$stderr.puts "Please include this information in any issues/report along with relevant logs"
|
22
|
+
rescue SystemCallError
|
23
|
+
# Outputting to stderr is best-effort. Avoid raising another error when outputting debug info so that
|
24
|
+
# we can detect and log the original error, which may even be the source of this error.
|
25
|
+
nil
|
26
|
+
end
|
21
27
|
raise e
|
22
28
|
end
|
23
29
|
end
|
data/lib/cli/kit/ini.rb
CHANGED
@@ -15,8 +15,12 @@ module CLI
|
|
15
15
|
class Ini
|
16
16
|
attr_accessor :ini
|
17
17
|
|
18
|
-
def initialize(path = nil, default_section: nil, convert_types: true)
|
19
|
-
@config =
|
18
|
+
def initialize(path = nil, config: nil, default_section: nil, convert_types: true)
|
19
|
+
@config = if path && File.exist?(path)
|
20
|
+
File.readlines(path)
|
21
|
+
elsif config
|
22
|
+
config.lines
|
23
|
+
end
|
20
24
|
@ini = {}
|
21
25
|
@current_key = nil
|
22
26
|
@default_section = default_section
|
@@ -39,7 +43,7 @@ module CLI
|
|
39
43
|
|
40
44
|
# Otherwise set the values
|
41
45
|
else
|
42
|
-
k, v = l.split('=').map(&:strip)
|
46
|
+
k, v = l.split('=', 2).map(&:strip)
|
43
47
|
set_val(k, v)
|
44
48
|
end
|
45
49
|
end
|
@@ -19,6 +19,24 @@ module CLI
|
|
19
19
|
assert_all_commands_run
|
20
20
|
end
|
21
21
|
|
22
|
+
module FakeConfig
|
23
|
+
require 'tmpdir'
|
24
|
+
require 'fileutils'
|
25
|
+
|
26
|
+
def setup
|
27
|
+
super
|
28
|
+
@tmpdir = Dir.mktmpdir
|
29
|
+
@prev_xdg = ENV['XDG_CONFIG_HOME']
|
30
|
+
ENV['XDG_CONFIG_HOME'] = @tmpdir
|
31
|
+
end
|
32
|
+
|
33
|
+
def teardown
|
34
|
+
FileUtils.rm_rf(@tmpdir)
|
35
|
+
ENV['XDG_CONFIG_HOME'] = @prev_xdg
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
22
40
|
class FakeSuccess
|
23
41
|
def initialize(success)
|
24
42
|
@success = success
|
data/lib/cli/kit/system.rb
CHANGED
@@ -191,9 +191,13 @@ module CLI
|
|
191
191
|
# If only one argument was provided, make sure it's interpreted by a shell.
|
192
192
|
return ["true ; " + a[0]] if a.size == 1
|
193
193
|
return a if a.first.include?('/')
|
194
|
-
|
195
|
-
|
194
|
+
|
195
|
+
paths = env.fetch('PATH', '').split(':')
|
196
|
+
item = paths.detect do |f|
|
197
|
+
command_path = "#{f}/#{a.first}"
|
198
|
+
File.executable?(command_path) && File.file?(command_path)
|
196
199
|
end
|
200
|
+
|
197
201
|
a[0] = "#{item}/#{a.first}" if item
|
198
202
|
a
|
199
203
|
end
|
data/lib/cli/kit/version.rb
CHANGED
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: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
|
-
-
|
8
|
+
- Aaron Olson
|
9
9
|
- Lisa Ugray
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2019-06-13 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: cli-ui
|
@@ -71,13 +71,15 @@ dependencies:
|
|
71
71
|
description: Terminal UI framework extensions
|
72
72
|
email:
|
73
73
|
- burke.libbey@shopify.com
|
74
|
-
-
|
74
|
+
- aaron.olson@shopify.com
|
75
75
|
- lisa.ugray@shopify.com
|
76
76
|
executables:
|
77
77
|
- cli-kit
|
78
78
|
extensions: []
|
79
79
|
extra_rdoc_files: []
|
80
80
|
files:
|
81
|
+
- ".github/CODEOWNERS"
|
82
|
+
- ".github/probots.yml"
|
81
83
|
- ".gitignore"
|
82
84
|
- ".rubocop.yml"
|
83
85
|
- ".travis.yml"
|
@@ -86,11 +88,16 @@ files:
|
|
86
88
|
- LICENSE.txt
|
87
89
|
- README.md
|
88
90
|
- Rakefile
|
91
|
+
- TODO.md
|
89
92
|
- bin/console
|
90
93
|
- bin/test_gen
|
91
94
|
- bin/testunit
|
92
95
|
- cli-kit.gemspec
|
93
96
|
- dev.yml
|
97
|
+
- examples/README.md
|
98
|
+
- examples/minimal/example.rb
|
99
|
+
- examples/single-file/example.rb
|
100
|
+
- examples/todo-list/README.md
|
94
101
|
- exe/cli-kit
|
95
102
|
- gen/lib/gen.rb
|
96
103
|
- gen/lib/gen/commands.rb
|
@@ -150,8 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
157
|
- !ruby/object:Gem::Version
|
151
158
|
version: '0'
|
152
159
|
requirements: []
|
153
|
-
|
154
|
-
rubygems_version: 2.6.14
|
160
|
+
rubygems_version: 3.0.2
|
155
161
|
signing_key:
|
156
162
|
specification_version: 4
|
157
163
|
summary: Terminal UI framework extensions
|