cli-kit 3.1.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 283b38ecb21fd3caac8399447f06f5bccff261af
4
- data.tar.gz: fe47b61139d7df53eca531693ba385c44a0c6455
2
+ SHA256:
3
+ metadata.gz: a1c78454dde57819601c7ef40040c02943b72ea2f3831718a2a4362731c2cf9a
4
+ data.tar.gz: 6e4e1adcdd54eb38d419b2d2d936ec03a05190cf72baaabd1002e1407dfdcf49
5
5
  SHA512:
6
- metadata.gz: 6f8723304b346c20418debde33e203bc3794ae0defc4e34308a7c2fbf5364fb22c41f7b7e800bbe5f2fb76a0ac90ca37e980c5ec641c71b3deb19d277d029b19
7
- data.tar.gz: 6f08ef957f6f63b6fe108b6b6e118b5f887a9050ae8aed548445d8b77ff8ec47ff5a488f881b3e95e3682c30ba7098196876096a5cd70fd7fe312dd74292928c
6
+ metadata.gz: f57fe58683a342a39957fd19cedc79641583456100e7e63b71e4e395b0fc705938ccaa1574bc36d975dda6f6b5c7fcbf28406972432abcf3ac890bb1334e2715
7
+ data.tar.gz: 5f1f0bf80809f7ff4ae97ab4cd0871ceaef6b4c4967b06fdcae5ccb1c869524c351c1a2acf7cab83cd2416ce37766033b5c63d6ff2480fd660067d74dcc51f8f
@@ -0,0 +1 @@
1
+ @Shopify/dev-infra
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cli-kit (3.1.0)
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.1.4)
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.16.1
56
+ 1.17.3
data/TODO.md ADDED
@@ -0,0 +1,5 @@
1
+ * Build a help system
2
+ * Build a tabular data formatter
3
+ * Suppress colour by default when printing to non-TTY
4
+ * Do frames in a way that works on BK when running on BK
5
+
@@ -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', 'Julian Nadeau', 'Lisa Ugray']
10
- spec.email = ['burke.libbey@shopify.com', 'julian.nadeau@shopify.com', 'lisa.ugray@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'
@@ -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
@@ -1,5 +1,4 @@
1
1
  require '__app__'
2
- require 'json'
3
2
 
4
3
  module __App__
5
4
  module Commands
@@ -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
@@ -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) || false
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
@@ -16,8 +16,14 @@ module CLI
16
16
  begin
17
17
  command.call(args, command_name)
18
18
  rescue => e
19
- $stderr.puts "This command ran with ID: #{id}"
20
- $stderr.puts "Please include this information in any issues/report along with relevant logs"
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
@@ -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 = File.readlines(path) if path && File.exist?(path)
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
@@ -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
- item = env.fetch('PATH', '').split(':').detect do |f|
195
- File.exist?("#{f}/#{a.first}")
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
@@ -1,5 +1,5 @@
1
1
  module CLI
2
2
  module Kit
3
- VERSION = "3.1.0"
3
+ VERSION = "3.3.0"
4
4
  end
5
5
  end
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.1.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
- - Julian Nadeau
8
+ - Aaron Olson
9
9
  - Lisa Ugray
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2018-07-27 00:00:00.000000000 Z
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
- - julian.nadeau@shopify.com
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
- rubyforge_project:
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