cli-kit 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.github/dependabot.yml +10 -0
- data/.github/probots.yml +2 -0
- data/.github/workflows/ruby.yml +32 -0
- data/.rubocop.yml +13 -15
- data/Gemfile +3 -2
- data/Gemfile.lock +35 -30
- data/README.md +102 -4
- data/Rakefile +27 -0
- data/TODO.md +5 -0
- data/bin/console +3 -3
- data/bin/test_gen +31 -0
- data/bin/testunit +2 -2
- data/cli-kit.gemspec +8 -7
- data/dev.yml +1 -1
- 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/lib/gen/commands/help.rb +4 -4
- data/gen/lib/gen/generator.rb +12 -10
- data/gen/lib/gen.rb +5 -1
- data/gen/template/Gemfile +6 -0
- data/gen/template/bin/testunit +23 -0
- data/gen/template/bin/update-deps +2 -1
- data/gen/template/lib/__app__/commands/example.rb +0 -1
- data/gen/template/test/example_test.rb +17 -0
- data/gen/template/test/test_helper.rb +22 -0
- data/lib/cli/kit/base_command.rb +14 -8
- data/lib/cli/kit/command_registry.rb +1 -1
- data/lib/cli/kit/config.rb +39 -4
- data/lib/cli/kit/error_handler.rb +56 -36
- data/lib/cli/kit/executor.rb +39 -10
- data/lib/cli/kit/ini.rb +16 -7
- data/lib/cli/kit/logger.rb +82 -0
- data/lib/cli/kit/resolver.rb +2 -2
- data/lib/cli/kit/support/test_helper.rb +244 -0
- data/lib/cli/kit/support.rb +9 -0
- data/lib/cli/kit/system.rb +61 -22
- data/lib/cli/kit/util.rb +189 -0
- data/lib/cli/kit/version.rb +1 -1
- data/lib/cli/kit.rb +4 -1
- metadata +36 -20
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 523252459712e507c4579e244e6330eb3e8a5d8c71334d4e41553903ab651cd6
|
4
|
+
data.tar.gz: 459cb0a684e2890718d0cffdd74cd8540bd91a1995dfe1db593df9a189da20d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8579924711573ce6338b52dc44c47ad40c12f925bbd6f3ad6cee5be9f44b2b4f315e6d272adc309788b0418ee6806567660f0386d7e91d9d09a524beeb0a4a1f
|
7
|
+
data.tar.gz: b5507292ba97fd6f13b83b6426e81e4500e0ef1480387164c936164b7593bf7daac98e39cbb835362f198c39e562f2d12adf92384365a9c99a7f0ed42c158a45
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
@Shopify/dev-infra
|
data/.github/probots.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
style:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- name: Set up Ruby
|
11
|
+
uses: ruby/setup-ruby@v1
|
12
|
+
with:
|
13
|
+
ruby-version: '2.7'
|
14
|
+
bundler-cache: true
|
15
|
+
- name: Check style
|
16
|
+
run: bundle exec rake style
|
17
|
+
test:
|
18
|
+
strategy:
|
19
|
+
matrix:
|
20
|
+
os: [macos-latest, ubuntu-latest, windows-latest]
|
21
|
+
ruby-version: ['2.6', '2.7']
|
22
|
+
|
23
|
+
runs-on: ${{ matrix.os }}
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true
|
31
|
+
- name: Run tests
|
32
|
+
run: bundle exec rake test
|
data/.rubocop.yml
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
-
|
2
|
-
-
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-shopify: rubocop-cli.yml
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
Exclude:
|
6
|
-
|
5
|
+
Exclude:
|
6
|
+
- gen/template/**/*
|
7
|
+
- vendor/**/*
|
8
|
+
TargetRubyVersion: 2.5
|
7
9
|
|
8
|
-
Style/
|
9
|
-
|
10
|
-
|
11
|
-
Shopify/RubocopComments:
|
12
|
-
Enabled: false
|
10
|
+
Style/ClassAndModuleChildren:
|
11
|
+
Exclude:
|
12
|
+
- lib/cli/kit/support/test_helper.rb
|
13
13
|
|
14
|
-
|
15
|
-
Layout/IndentHeredoc:
|
14
|
+
Style/FrozenStringLiteralComment:
|
16
15
|
Enabled: false
|
17
16
|
|
18
17
|
# This doesn't take into account retrying from an exception
|
19
|
-
Lint/
|
18
|
+
Lint/SuppressedException:
|
20
19
|
Enabled: false
|
21
20
|
|
22
21
|
# allow String.new to create mutable strings
|
@@ -35,6 +34,5 @@ Style/RegexpLiteral:
|
|
35
34
|
Style/MultilineBlockChain:
|
36
35
|
Enabled: false
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
Enabled: false
|
37
|
+
Style/StringLiterals:
|
38
|
+
EnforcedStyle: single_quotes
|
data/Gemfile
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# NOTE: These are development-only dependencies
|
2
|
-
source
|
2
|
+
source 'https://rubygems.org'
|
3
3
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :development, :test do
|
7
7
|
gem 'rubocop'
|
8
|
+
gem 'rubocop-shopify'
|
8
9
|
gem 'byebug'
|
9
10
|
gem 'method_source'
|
10
11
|
end
|
11
12
|
|
12
13
|
group :test do
|
13
|
-
gem 'mocha', require: false
|
14
|
+
gem 'mocha', '~> 1.13.0', require: false
|
14
15
|
gem 'minitest', '>= 5.0.0', require: false
|
15
16
|
gem 'minitest-reporters', require: false
|
16
17
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,57 +1,62 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cli-kit (
|
5
|
-
cli-ui (>= 1.1.
|
4
|
+
cli-kit (4.0.0)
|
5
|
+
cli-ui (>= 1.1.4)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ansi (1.5.0)
|
11
|
-
ast (2.
|
12
|
-
builder (3.2.
|
13
|
-
byebug (
|
14
|
-
cli-ui (1.1
|
15
|
-
|
16
|
-
|
17
|
-
minitest (
|
18
|
-
minitest-reporters (1.1.14)
|
11
|
+
ast (2.4.2)
|
12
|
+
builder (3.2.4)
|
13
|
+
byebug (11.1.3)
|
14
|
+
cli-ui (1.5.1)
|
15
|
+
method_source (1.0.0)
|
16
|
+
minitest (5.14.4)
|
17
|
+
minitest-reporters (1.4.3)
|
19
18
|
ansi
|
20
19
|
builder
|
21
20
|
minitest (>= 5.0)
|
22
21
|
ruby-progressbar
|
23
|
-
mocha (1.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
rubocop (0.49.1)
|
22
|
+
mocha (1.13.0)
|
23
|
+
parallel (1.21.0)
|
24
|
+
parser (3.0.2.0)
|
25
|
+
ast (~> 2.4.1)
|
26
|
+
rainbow (3.0.0)
|
27
|
+
rake (13.0.6)
|
28
|
+
regexp_parser (2.1.1)
|
29
|
+
rexml (3.2.5)
|
30
|
+
rubocop (1.22.3)
|
33
31
|
parallel (~> 1.10)
|
34
|
-
parser (>=
|
35
|
-
|
36
|
-
|
32
|
+
parser (>= 3.0.0.0)
|
33
|
+
rainbow (>= 2.2.2, < 4.0)
|
34
|
+
regexp_parser (>= 1.8, < 3.0)
|
35
|
+
rexml
|
36
|
+
rubocop-ast (>= 1.12.0, < 2.0)
|
37
37
|
ruby-progressbar (~> 1.7)
|
38
|
-
unicode-display_width (
|
39
|
-
|
40
|
-
|
38
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
39
|
+
rubocop-ast (1.12.0)
|
40
|
+
parser (>= 3.0.1.1)
|
41
|
+
rubocop-shopify (2.3.0)
|
42
|
+
rubocop (~> 1.22)
|
43
|
+
ruby-progressbar (1.11.0)
|
44
|
+
unicode-display_width (2.1.0)
|
41
45
|
|
42
46
|
PLATFORMS
|
43
47
|
ruby
|
44
48
|
|
45
49
|
DEPENDENCIES
|
46
|
-
bundler (~> 1
|
50
|
+
bundler (~> 2.1)
|
47
51
|
byebug
|
48
52
|
cli-kit!
|
49
53
|
method_source
|
50
54
|
minitest (>= 5.0.0)
|
51
55
|
minitest-reporters
|
52
|
-
mocha
|
53
|
-
rake (~>
|
56
|
+
mocha (~> 1.13.0)
|
57
|
+
rake (~> 13.0)
|
54
58
|
rubocop
|
59
|
+
rubocop-shopify
|
55
60
|
|
56
61
|
BUNDLED WITH
|
57
|
-
|
62
|
+
2.2.24
|
data/README.md
CHANGED
@@ -11,8 +11,106 @@
|
|
11
11
|
to build a number of internal developer tools, along with
|
12
12
|
[cli-ui](https://github.com/shopify/cli-ui).
|
13
13
|
|
14
|
-
##
|
14
|
+
## Getting Started
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
To begin creating your first `cli-kit` application, run:
|
17
|
+
```bash
|
18
|
+
gem install cli-kit
|
19
|
+
cli-kit new myproject
|
20
|
+
```
|
21
|
+
|
22
|
+
Where `myproject` is the name of the application you wish to create. Then, you will be prompted to
|
23
|
+
select how the project consumes `cli-kit` and `cli-ui`. The available options are:
|
24
|
+
- Vendor (faster execution, more difficult to update dependencies)
|
25
|
+
- Bundler (slower execution, easier dependency management)
|
26
|
+
|
27
|
+
You're now ready to write your very first `cli-kit` application!
|
28
|
+
|
29
|
+
## How do `cli-kit` Applications Work?
|
30
|
+
|
31
|
+
The executable for your `cli-kit` app is stored in the "exe" directory. To execute the app, simply
|
32
|
+
run:
|
33
|
+
```bash
|
34
|
+
./exe/myproject
|
35
|
+
```
|
36
|
+
|
37
|
+
### Folder Structure
|
38
|
+
* `/exe/` - Location of the executables for your application.
|
39
|
+
* `/lib/` - Location of the resources for your app (modules, classes, helpers, etc).
|
40
|
+
* `myproject.rb` - This file is the starting point for where to look for all other files. It
|
41
|
+
configures autoload and autocall for the app.
|
42
|
+
* `myproject/` - Stores the various commands/entry points.
|
43
|
+
* `entry_point.rb` - This is the file that is first called from the executable. It handles
|
44
|
+
loading and commands.
|
45
|
+
* `commands.rb` - Registers the various commands that your application is able to handle.
|
46
|
+
* `commands/` - Stores Ruby files for each command (help, new, add, etc).
|
47
|
+
|
48
|
+
## Adding a New Command to your App
|
49
|
+
|
50
|
+
### Registering the Command
|
51
|
+
|
52
|
+
Let's say that you'd like your program to be able to handle a specific task, and you'd like to
|
53
|
+
_register_ a new handler for the command for that task, like `myproject add` to add 2 numbers, like
|
54
|
+
in a calculator app.
|
55
|
+
To do this, open `/lib/myproject/commands.rb`. Then, add a new line into the module, like this:
|
56
|
+
```ruby
|
57
|
+
register :Add, 'add', 'myproject/commands/add'
|
58
|
+
```
|
59
|
+
|
60
|
+
The format for this is `register :<CommandClass>, '<command-at-cli>', '<path/to/command.rb>'`
|
61
|
+
|
62
|
+
### Creating the Command Action
|
63
|
+
|
64
|
+
The action for a specific command is stored in its own Ruby file, in the `/lib/myproject/commands/`
|
65
|
+
directory. Here is an example of the `add` command in our previous to-do app example:
|
66
|
+
```ruby
|
67
|
+
require 'myproject'
|
68
|
+
|
69
|
+
module Myproject
|
70
|
+
module Commands
|
71
|
+
class Add < Myproject::Command
|
72
|
+
def call(args, _name)
|
73
|
+
# command action goes here
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.help
|
77
|
+
# help or instructions go here
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
```
|
84
|
+
|
85
|
+
The `call(args, _name)` method is what actually runs when the `myproject add` command is executed.
|
86
|
+
|
87
|
+
- **Note:** The `args` parameter represents all the arguments the user has specified.
|
88
|
+
|
89
|
+
Let's say that you are trying to compute the sum of 2 numbers that the user has specified as
|
90
|
+
arguments. For example:
|
91
|
+
```ruby
|
92
|
+
def call(args, _name)
|
93
|
+
sum = args.map(&:to_i).inject(&:+)
|
94
|
+
puts sum
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
### Getting Help
|
99
|
+
|
100
|
+
Above, you'll notice that we also have a `self.help` method. This method is what runs when the user
|
101
|
+
has incorrectly used the command, or has requested help. For example:
|
102
|
+
```ruby
|
103
|
+
def self.help
|
104
|
+
"Print the sum of 2 numbers.\nUsage: {{command:#{Myproject::TOOL_NAME} add}} 5 7"
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
## User Interfaces
|
109
|
+
|
110
|
+
`cli-kit` also features `cli-ui`, another gem from us here at Shopify, which allows for the use of
|
111
|
+
powerful command-line user interface elements. For more details on how to use `cli-ui`, visit the
|
112
|
+
[`cli-ui`](https://github.com/Shopify/cli-ui) repo.
|
113
|
+
|
114
|
+
## Examples
|
115
|
+
|
116
|
+
- [A Simple To-Do App](https://github.com/Shopify/cli-kit-example)
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
|
6
|
+
TEST_ROOT = File.expand_path('../test', __FILE__)
|
7
|
+
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.libs += ['test']
|
10
|
+
t.test_files = FileList[File.join(TEST_ROOT, '**', '*_test.rb')]
|
11
|
+
t.verbose = false
|
12
|
+
t.warning = false
|
13
|
+
end
|
14
|
+
|
15
|
+
RuboCop::RakeTask.new(:style) do |t|
|
16
|
+
t.options = ['--display-cop-names']
|
17
|
+
end
|
18
|
+
|
19
|
+
task :test_gen_bundler do
|
20
|
+
sh 'DEPS=bundler bin/test_gen'
|
21
|
+
end
|
22
|
+
|
23
|
+
task :test_gen_vendor do
|
24
|
+
sh 'DEPS=vendor bin/test_gen'
|
25
|
+
end
|
26
|
+
|
27
|
+
task(default: [:test, :style, :test_gen_bundler, :test_gen_vendor])
|
data/TODO.md
ADDED
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'cli/kit'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "cli/kit"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
data/bin/test_gen
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -euo pipefail
|
3
|
+
|
4
|
+
# Make sure we're in the cli kit directory
|
5
|
+
CURR_DIR=$(dirname "$0")
|
6
|
+
cd $CURR_DIR
|
7
|
+
cd ../
|
8
|
+
|
9
|
+
# Clean up
|
10
|
+
function finish {
|
11
|
+
cd $CURR_DIR
|
12
|
+
cd ../../
|
13
|
+
rm -rf myapp
|
14
|
+
}
|
15
|
+
trap finish EXIT
|
16
|
+
|
17
|
+
# Generate app and move up a level to be at the same level as cli-kit
|
18
|
+
bundle exec ruby exe/cli-kit new myapp
|
19
|
+
mv myapp ../
|
20
|
+
cd ../myapp
|
21
|
+
|
22
|
+
# Test
|
23
|
+
if [[ $DEPS == 'bundler' ]]; then
|
24
|
+
bundle install
|
25
|
+
fi
|
26
|
+
bin/testunit
|
27
|
+
|
28
|
+
if [[ $DEPS == 'vendor' ]]; then
|
29
|
+
git clone https://github.com/Shopify/cli-ui.git ../cli-ui
|
30
|
+
bin/update-deps
|
31
|
+
fi
|
data/bin/testunit
CHANGED
@@ -9,12 +9,12 @@ CLI_TEST_ROOT = root + '/test'
|
|
9
9
|
$LOAD_PATH.unshift(CLI_TEST_ROOT)
|
10
10
|
|
11
11
|
def test_files
|
12
|
-
Dir.glob(CLI_TEST_ROOT +
|
12
|
+
Dir.glob(CLI_TEST_ROOT + '/**/*_test.rb')
|
13
13
|
end
|
14
14
|
|
15
15
|
if ARGV.empty?
|
16
16
|
test_files.each { |f| require(f) }
|
17
|
-
exit
|
17
|
+
exit(0)
|
18
18
|
end
|
19
19
|
|
20
20
|
# A list of files is presumed to be specified
|
data/cli-kit.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'cli/kit/version'
|
@@ -6,24 +7,24 @@ require 'cli/kit/version'
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
8
|
spec.name = 'cli-kit'
|
8
9
|
spec.version = CLI::Kit::VERSION
|
9
|
-
spec.authors = ['Burke Libbey', '
|
10
|
-
spec.email = ['burke.libbey@shopify.com', '
|
10
|
+
spec.authors = ['Burke Libbey', 'Aaron Olson', 'Lisa Ugray']
|
11
|
+
spec.email = ['burke.libbey@shopify.com', 'aaron.olson@shopify.com', 'lisa.ugray@shopify.com']
|
11
12
|
|
12
13
|
spec.summary = 'Terminal UI framework extensions'
|
13
14
|
spec.description = 'Terminal UI framework extensions'
|
14
15
|
spec.homepage = 'https://github.com/shopify/cli-kit'
|
15
16
|
spec.license = 'MIT'
|
16
17
|
|
17
|
-
spec.files =
|
18
|
+
spec.files = %x(git ls-files -z).split("\x0").reject do |f|
|
18
19
|
f.match(%r{^(test|spec|features)/})
|
19
20
|
end
|
20
21
|
spec.bindir = 'exe'
|
21
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
23
|
spec.require_paths = ['lib']
|
23
24
|
|
24
|
-
spec.add_runtime_dependency
|
25
|
+
spec.add_runtime_dependency('cli-ui', '>= 1.1.4')
|
25
26
|
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
27
|
+
spec.add_development_dependency('bundler', '~> 2.1')
|
28
|
+
spec.add_development_dependency('minitest', '~> 5.0')
|
29
|
+
spec.add_development_dependency('rake', '~> 13.0')
|
29
30
|
end
|
data/dev.yml
CHANGED
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
|
@@ -4,15 +4,15 @@ module Gen
|
|
4
4
|
module Commands
|
5
5
|
class Help < Gen::Command
|
6
6
|
def call(_args, _name)
|
7
|
-
puts CLI::UI.fmt(
|
8
|
-
puts
|
7
|
+
puts CLI::UI.fmt('{{bold:Available commands}}')
|
8
|
+
puts ''
|
9
9
|
|
10
10
|
Gen::Commands::Registry.resolved_commands.each do |name, klass|
|
11
11
|
puts CLI::UI.fmt("{{command:#{Gen::TOOL_NAME} #{name}}}")
|
12
|
-
if help = klass.help
|
12
|
+
if klass.respond_to?(:help) && (help = klass.help)
|
13
13
|
puts CLI::UI.fmt(help)
|
14
14
|
end
|
15
|
-
puts
|
15
|
+
puts ''
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/gen/lib/gen/generator.rb
CHANGED
@@ -18,21 +18,20 @@ module Gen
|
|
18
18
|
# false -> delete file
|
19
19
|
# string -> rename file before applying template substitutions
|
20
20
|
VENDOR_TRANSLATIONS = {
|
21
|
-
'Gemfile'
|
22
|
-
'exe/__app__-gems'
|
21
|
+
'Gemfile' => false,
|
22
|
+
'exe/__app__-gems' => false,
|
23
23
|
'exe/__app__-vendor' => 'exe/__app__',
|
24
|
-
'dev-gems.yml'
|
25
|
-
'dev-vendor.yml'
|
24
|
+
'dev-gems.yml' => false,
|
25
|
+
'dev-vendor.yml' => 'dev.yml',
|
26
26
|
}.freeze
|
27
27
|
private_constant :VENDOR_TRANSLATIONS
|
28
28
|
|
29
29
|
BUNDLER_TRANSLATIONS = {
|
30
|
-
'bin'
|
31
|
-
'
|
32
|
-
'exe/__app__-gems' => 'exe/__app__',
|
30
|
+
'bin/update-deps' => false,
|
31
|
+
'exe/__app__-gems' => 'exe/__app__',
|
33
32
|
'exe/__app__-vendor' => false,
|
34
|
-
'dev-gems.yml'
|
35
|
-
'dev-vendor.yml'
|
33
|
+
'dev-gems.yml' => 'dev.yml',
|
34
|
+
'dev-vendor.yml' => false,
|
36
35
|
}.freeze
|
37
36
|
private_constant :BUNDLER_TRANSLATIONS
|
38
37
|
|
@@ -59,6 +58,9 @@ module Gen
|
|
59
58
|
private
|
60
59
|
|
61
60
|
def ask_vendor?
|
61
|
+
return true if ENV['DEPS'] == 'vendor'
|
62
|
+
return false if ENV['DEPS'] == 'bundler'
|
63
|
+
|
62
64
|
vendor = nil
|
63
65
|
CLI::UI::Frame.open('Configuration') do
|
64
66
|
q = 'How would you like the application to consume {{command:cli-kit}} and {{command:cli-ui}}?'
|
@@ -114,7 +116,7 @@ module Gen
|
|
114
116
|
out, stat = Open3.capture2e('git', '-C', dir, 'clone', "https://github.com/shopify/#{repo}")
|
115
117
|
unless stat.success?
|
116
118
|
STDERR.puts(out)
|
117
|
-
error(
|
119
|
+
error('git clone failed')
|
118
120
|
end
|
119
121
|
end
|
120
122
|
|