shopify-cli 1.0.5 → 1.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/CHANGELOG.md +4 -0
- data/bin/load_shopify.rb +3 -1
- data/bin/shopify +2 -0
- data/ext/shopify-cli/extconf.rb +40 -20
- data/lib/project_types/node/commands/create.rb +4 -4
- data/lib/project_types/node/commands/deploy/heroku.rb +6 -1
- data/lib/project_types/node/commands/generate/billing.rb +6 -5
- data/lib/project_types/node/commands/generate/page.rb +8 -5
- data/lib/project_types/node/commands/generate/webhook.rb +4 -1
- data/lib/project_types/node/messages/messages.rb +1 -0
- data/lib/project_types/rails/commands/create.rb +52 -4
- data/lib/project_types/rails/commands/generate.rb +1 -0
- data/lib/project_types/rails/commands/generate/webhook.rb +3 -2
- data/lib/project_types/rails/commands/serve.rb +6 -2
- data/lib/project_types/rails/gem.rb +61 -6
- data/lib/project_types/rails/messages/messages.rb +27 -11
- data/lib/project_types/script/config/extension_points.yml +3 -3
- data/lib/project_types/script/forms/create.rb +1 -1
- data/lib/rubygems_plugin.rb +18 -10
- data/lib/shopify-cli/admin_api/populate_resource_command.rb +1 -1
- data/lib/shopify-cli/commands/connect.rb +1 -1
- data/lib/shopify-cli/commands/system.rb +9 -8
- data/lib/shopify-cli/context.rb +28 -0
- data/lib/shopify-cli/heroku.rb +18 -2
- data/lib/shopify-cli/js_deps.rb +2 -2
- data/lib/shopify-cli/js_system.rb +2 -2
- data/lib/shopify-cli/process_supervision.rb +52 -15
- data/lib/shopify-cli/project.rb +14 -6
- data/lib/shopify-cli/tunnel.rb +10 -4
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +6 -2
- data/shopify-cli.gemspec +4 -1
- data/vendor/deps/cli-kit/REVISION +1 -1
- data/vendor/deps/cli-kit/lib/cli/kit.rb +1 -1
- data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +2 -2
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +12 -6
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +9 -11
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +8 -2
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +7 -7
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +48 -17
- data/vendor/deps/cli-ui/REVISION +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui.rb +5 -4
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +9 -3
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -2
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +13 -5
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +29 -2
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +21 -10
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +11 -2
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -3
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +6 -8
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +2 -0
- data/vendor/gen/lib/gen.rb +39 -0
- data/vendor/gen/lib/gen/commands.rb +18 -0
- data/vendor/gen/lib/gen/commands/help.rb +20 -0
- data/vendor/gen/lib/gen/commands/new.rb +21 -0
- data/vendor/gen/lib/gen/entry_point.rb +10 -0
- data/vendor/gen/lib/gen/generator.rb +165 -0
- data/vendor/gen/template/.gitignore +2 -0
- data/vendor/gen/template/Gemfile +10 -0
- data/vendor/gen/template/README.md +1 -0
- data/vendor/gen/template/bin/testunit +23 -0
- data/vendor/gen/template/bin/update-deps +97 -0
- data/vendor/gen/template/dev-gems.yml +3 -0
- data/vendor/gen/template/dev-vendor.yml +4 -0
- data/vendor/gen/template/exe/__app__-gems +17 -0
- data/vendor/gen/template/exe/__app__-vendor +18 -0
- data/vendor/gen/template/lib/__app__.rb +33 -0
- data/vendor/gen/template/lib/__app__/commands.rb +18 -0
- data/vendor/gen/template/lib/__app__/commands/example.rb +19 -0
- data/vendor/gen/template/lib/__app__/commands/help.rb +21 -0
- data/vendor/gen/template/lib/__app__/entry_point.rb +10 -0
- data/vendor/gen/template/test/example_test.rb +17 -0
- data/vendor/gen/template/test/test_helper.rb +22 -0
- metadata +25 -4
- data/Vagrantfile +0 -17
- data/lib/project_types/script/forms/script_form.rb +0 -69
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'gen'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'open3'
|
4
|
+
require 'pathname'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
module Gen
|
8
|
+
class Generator
|
9
|
+
def self.run(project_name)
|
10
|
+
new(project_name).run
|
11
|
+
end
|
12
|
+
|
13
|
+
TEMPLATE_ROOT = File.expand_path('gen/template', Gen::ROOT)
|
14
|
+
|
15
|
+
VALID_PROJECT_NAME = /\A[a-z][a-z0-9]*\z/
|
16
|
+
private_constant :VALID_PROJECT_NAME
|
17
|
+
|
18
|
+
# false -> delete file
|
19
|
+
# string -> rename file before applying template substitutions
|
20
|
+
VENDOR_TRANSLATIONS = {
|
21
|
+
'Gemfile' => false,
|
22
|
+
'exe/__app__-gems' => false,
|
23
|
+
'exe/__app__-vendor' => 'exe/__app__',
|
24
|
+
'dev-gems.yml' => false,
|
25
|
+
'dev-vendor.yml' => 'dev.yml',
|
26
|
+
}.freeze
|
27
|
+
private_constant :VENDOR_TRANSLATIONS
|
28
|
+
|
29
|
+
BUNDLER_TRANSLATIONS = {
|
30
|
+
'bin/update-deps' => false,
|
31
|
+
'exe/__app__-gems' => 'exe/__app__',
|
32
|
+
'exe/__app__-vendor' => false,
|
33
|
+
'dev-gems.yml' => 'dev.yml',
|
34
|
+
'dev-vendor.yml' => false,
|
35
|
+
}.freeze
|
36
|
+
private_constant :BUNDLER_TRANSLATIONS
|
37
|
+
|
38
|
+
def initialize(project_name)
|
39
|
+
raise(
|
40
|
+
CLI::Kit::Abort,
|
41
|
+
"project name must match {{bold:#{VALID_PROJECT_NAME}}} (but can be changed later)"
|
42
|
+
) unless project_name =~ VALID_PROJECT_NAME
|
43
|
+
@project_name = project_name
|
44
|
+
@title_case_project_name = @project_name.sub(/^./, &:upcase)
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
vendor = ask_vendor?
|
49
|
+
create_project_dir
|
50
|
+
if vendor
|
51
|
+
copy_files(translations: VENDOR_TRANSLATIONS)
|
52
|
+
update_deps
|
53
|
+
else
|
54
|
+
copy_files(translations: BUNDLER_TRANSLATIONS)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def ask_vendor?
|
61
|
+
return 'vendor' if ENV['DEPS'] == 'vendor'
|
62
|
+
return 'bundler' if ENV['DEPS'] == 'bundler'
|
63
|
+
|
64
|
+
vendor = nil
|
65
|
+
CLI::UI::Frame.open('Configuration') do
|
66
|
+
q = 'How would you like the application to consume {{command:cli-kit}} and {{command:cli-ui}}?'
|
67
|
+
vendor = CLI::UI::Prompt.ask(q) do |c|
|
68
|
+
c.option('Vendor {{italic:(faster execution, more difficult to update deps)}}') { 'vendor' }
|
69
|
+
c.option('Bundler {{italic:(slower execution, easier dep management)}}') { 'bundler' }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
vendor == 'vendor'
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_project_dir
|
76
|
+
info(create: '')
|
77
|
+
FileUtils.mkdir(@project_name)
|
78
|
+
rescue Errno::EEXIST
|
79
|
+
error("directory already exists: #{@project_name}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def copy_files(translations:)
|
83
|
+
each_template_file do |source_name|
|
84
|
+
target_name = translations.fetch(source_name, source_name)
|
85
|
+
next if target_name == false
|
86
|
+
target_name = apply_template_variables(target_name)
|
87
|
+
|
88
|
+
source = File.join(TEMPLATE_ROOT, source_name)
|
89
|
+
target = File.join(@project_name, target_name)
|
90
|
+
|
91
|
+
info(create: target_name)
|
92
|
+
|
93
|
+
if Dir.exist?(source)
|
94
|
+
FileUtils.mkdir(target)
|
95
|
+
else
|
96
|
+
content = apply_template_variables(File.read(source))
|
97
|
+
File.write(target, content)
|
98
|
+
end
|
99
|
+
File.chmod(File.stat(source).mode, target)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def update_deps
|
104
|
+
Dir.mktmpdir do |tmp|
|
105
|
+
clone(tmp, 'cli-ui')
|
106
|
+
clone(tmp, 'cli-kit')
|
107
|
+
info(run: 'bin/update-deps')
|
108
|
+
Dir.chdir(@project_name) do
|
109
|
+
system({ 'SOURCE_ROOT' => tmp }, 'bin/update-deps')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def clone(dir, repo)
|
115
|
+
info(clone: repo)
|
116
|
+
out, stat = Open3.capture2e('git', '-C', dir, 'clone', "https://github.com/shopify/#{repo}")
|
117
|
+
unless stat.success?
|
118
|
+
STDERR.puts(out)
|
119
|
+
error("git clone failed")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def each_template_file
|
124
|
+
return enum_for(:each_template_file) unless block_given?
|
125
|
+
|
126
|
+
root = Pathname.new(TEMPLATE_ROOT)
|
127
|
+
Dir.glob("#{TEMPLATE_ROOT}/**/*").each do |f|
|
128
|
+
el = Pathname.new(f)
|
129
|
+
yield(el.relative_path_from(root).to_s)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def apply_template_variables(s)
|
134
|
+
s
|
135
|
+
.gsub(/__app__/, @project_name)
|
136
|
+
.gsub(/__App__/, @title_case_project_name)
|
137
|
+
.gsub(/__cli-kit-version__/, cli_kit_version)
|
138
|
+
.gsub(/__cli-ui-version__/, cli_ui_version)
|
139
|
+
end
|
140
|
+
|
141
|
+
def cli_kit_version
|
142
|
+
require 'cli/kit/version'
|
143
|
+
CLI::Kit::VERSION.to_s
|
144
|
+
end
|
145
|
+
|
146
|
+
def cli_ui_version
|
147
|
+
require 'cli/ui/version'
|
148
|
+
CLI::UI::VERSION.to_s
|
149
|
+
end
|
150
|
+
|
151
|
+
def info(create: nil, clone: nil, run: nil)
|
152
|
+
if clone
|
153
|
+
puts(CLI::UI.fmt("\t{{bold:{{yellow:clone}}\t#{clone}}}"))
|
154
|
+
elsif create
|
155
|
+
puts(CLI::UI.fmt("\t{{bold:{{blue:create}}\t#{create}}}"))
|
156
|
+
elsif run
|
157
|
+
puts(CLI::UI.fmt("\t{{bold:{{green:run}}\t#{run}}}"))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def error(msg)
|
162
|
+
raise(CLI::Kit::Abort, msg)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'cli-kit', '~> __cli-kit-version__'
|
4
|
+
gem 'cli-ui', '~> __cli-ui-version__'
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
gem 'mocha', '~> 1.5.0', require: false
|
8
|
+
gem 'minitest', '>= 5.0.0', require: false
|
9
|
+
gem 'minitest-reporters', require: false
|
10
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# __app__
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
root = File.expand_path('../..', __FILE__)
|
7
|
+
TEST_ROOT = root + '/test'
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift(TEST_ROOT)
|
10
|
+
|
11
|
+
def test_files
|
12
|
+
Dir.glob(TEST_ROOT + "/**/*_test.rb")
|
13
|
+
end
|
14
|
+
|
15
|
+
if ARGV.empty?
|
16
|
+
test_files.each { |f| require(f) }
|
17
|
+
exit 0
|
18
|
+
end
|
19
|
+
|
20
|
+
# A list of files is presumed to be specified
|
21
|
+
ARGV.each do |a|
|
22
|
+
require a.sub(%r{^test/}, '')
|
23
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../../vendor/deps/cli-ui/lib", __FILE__))
|
4
|
+
require 'open3'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
def fmt(tag, msg)
|
8
|
+
# Not really CLI::UI.fmt compatible: no nesting support, for example.
|
9
|
+
# While we could pull in CLI::UI here, it makes it more difficult to
|
10
|
+
# bootstrap a new project and to fix a broken vendor.
|
11
|
+
fmt_msg = msg
|
12
|
+
.gsub(/{{yellow:(.*?)}}/, "\x1b[33m\\1\x1b[31m")
|
13
|
+
.gsub(/{{green:(.*?)}}/, "\x1b[32m\\1\x1b[31m")
|
14
|
+
.gsub(/{{blue:(.*?)}}/, "\x1b[34m\\1\x1b[31m")
|
15
|
+
.gsub(/{{bold_blue:(.*?)}}/, "\x1b[1;34m\\1\x1b[0;31m")
|
16
|
+
.gsub(/{{bold_green:(.*?)}}/, "\x1b[1;32m\\1\x1b[0;31m")
|
17
|
+
"\x1b[1;31m[#{tag}] \x1b[0;31m#{fmt_msg}\x1b[0m"
|
18
|
+
end
|
19
|
+
|
20
|
+
def bail(msg)
|
21
|
+
STDERR.puts(fmt("ERROR", msg))
|
22
|
+
exit(1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def warn(msg)
|
26
|
+
STDERR.puts(fmt("WARNING", msg))
|
27
|
+
end
|
28
|
+
|
29
|
+
def source_path
|
30
|
+
File.expand_path(ENV.fetch('SOURCE_ROOT', File.expand_path('../../..', __FILE__)))
|
31
|
+
end
|
32
|
+
|
33
|
+
deps = %w(cli-ui cli-kit)
|
34
|
+
|
35
|
+
deps.each do |dep|
|
36
|
+
path = File.expand_path(dep, source_path)
|
37
|
+
|
38
|
+
unless Dir.exist?(path)
|
39
|
+
bail(
|
40
|
+
"dependency is not checked out: {{yellow:#{dep}}}.\n" \
|
41
|
+
" This repo {{bold_blue:(github.com/shopify/#{dep})}} must be cloned at" \
|
42
|
+
" {{bold_blue:#{path}}} for this script to succeed.\n" \
|
43
|
+
" Currently, SOURCE_ROOT is set to {{bold_blue:#{source_path}}}.\n" \
|
44
|
+
" Alternatively, you can set {{bold_blue:SOURCE_ROOT}} to a directory containing {{yellow:#{dep}}}.\n" \
|
45
|
+
" {{bold_blue:SOURCE_ROOT}} defaults to {{bold_blue:../}}."
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
head_sha = nil
|
50
|
+
dirty = false
|
51
|
+
|
52
|
+
Dir.chdir(path) do
|
53
|
+
_, _, stat = Open3.capture3('git fetch origin master')
|
54
|
+
bail("couldn't git fetch in dependency: {{yellow:#{dep}}}") unless stat.success?
|
55
|
+
|
56
|
+
head_sha, stat = Open3.capture2('git rev-parse HEAD')
|
57
|
+
bail("couldn't determine HEAD: {{yellow:#{dep}}}") unless stat.success?
|
58
|
+
head_sha.chomp!
|
59
|
+
|
60
|
+
fetch_head_sha, stat = Open3.capture2('git rev-parse FETCH_HEAD')
|
61
|
+
bail("couldn't determine FETCH_HEAD: {{yellow:#{dep}}}") unless stat.success?
|
62
|
+
fetch_head_sha.chomp!
|
63
|
+
|
64
|
+
git_status, stat = Open3.capture2('git status --porcelain')
|
65
|
+
bail("couldn't determine git status: {{yellow:#{dep}}}") unless stat.success?
|
66
|
+
|
67
|
+
if head_sha != fetch_head_sha
|
68
|
+
warn(
|
69
|
+
"Copying files from {{yellow:#{path}}} to satisfy dependency {{yellow:#{dep}}}.\n" \
|
70
|
+
" However, the repo at {{yellow:#{path}}} isn't up to date.\n" \
|
71
|
+
" The checked-out revision is {{yellow:#{head_sha[0..8]}}}, and "\
|
72
|
+
"{{yellow:origin/master}} is {{yellow:#{fetch_head_sha[0..8]}}}.\n" \
|
73
|
+
" Unless you know what you're doing, you should {{green:cd}} to that" \
|
74
|
+
" repo and {{green:git pull}}, then run this again."
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
unless git_status.chomp.empty?
|
79
|
+
dirty = true
|
80
|
+
warn("importing uncommitted changes from dependency: {{yellow:#{dep}}}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
depdir = File.expand_path("../../vendor/deps/#{dep}", __FILE__)
|
85
|
+
FileUtils.rm_rf(depdir)
|
86
|
+
FileUtils.mkdir_p(depdir)
|
87
|
+
dstlib = File.expand_path('lib', depdir)
|
88
|
+
srclib = File.expand_path('lib', path)
|
89
|
+
|
90
|
+
FileUtils.cp_r(srclib, dstlib)
|
91
|
+
|
92
|
+
rev = head_sha
|
93
|
+
rev << " (dirty)" if dirty
|
94
|
+
rev << "\n"
|
95
|
+
|
96
|
+
File.write("#{depdir}/REVISION", rev)
|
97
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
Encoding.default_external = Encoding::UTF_8
|
4
|
+
Encoding.default_internal = Encoding::UTF_8
|
5
|
+
|
6
|
+
unshift_path = ->(path) {
|
7
|
+
p = File.expand_path("../../#{path}", __FILE__)
|
8
|
+
$LOAD_PATH.unshift(p) unless $LOAD_PATH.include?(p)
|
9
|
+
}
|
10
|
+
unshift_path.call('lib')
|
11
|
+
|
12
|
+
require 'bundler/setup'
|
13
|
+
require '__app__'
|
14
|
+
|
15
|
+
exit(__App__::ErrorHandler.call do
|
16
|
+
__App__::EntryPoint.call(ARGV.dup)
|
17
|
+
end)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby --disable-gems
|
2
|
+
|
3
|
+
Encoding.default_external = Encoding::UTF_8
|
4
|
+
Encoding.default_internal = Encoding::UTF_8
|
5
|
+
|
6
|
+
unshift_path = ->(path) {
|
7
|
+
p = File.expand_path("../../#{path}", __FILE__)
|
8
|
+
$LOAD_PATH.unshift(p) unless $LOAD_PATH.include?(p)
|
9
|
+
}
|
10
|
+
unshift_path.call('vendor/deps/cli-ui/lib')
|
11
|
+
unshift_path.call('vendor/deps/cli-kit/lib')
|
12
|
+
unshift_path.call('lib')
|
13
|
+
|
14
|
+
require '__app__'
|
15
|
+
|
16
|
+
exit(__App__::ErrorHandler.call do
|
17
|
+
__App__::EntryPoint.call(ARGV.dup)
|
18
|
+
end)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'cli/ui'
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
CLI::UI::StdoutRouter.enable
|
5
|
+
|
6
|
+
module __App__
|
7
|
+
extend CLI::Kit::Autocall
|
8
|
+
|
9
|
+
TOOL_NAME = '__app__'
|
10
|
+
ROOT = File.expand_path('../..', __FILE__)
|
11
|
+
LOG_FILE = '/tmp/__app__.log'
|
12
|
+
|
13
|
+
autoload(:EntryPoint, '__app__/entry_point')
|
14
|
+
autoload(:Commands, '__app__/commands')
|
15
|
+
|
16
|
+
autocall(:Config) { CLI::Kit::Config.new(tool_name: TOOL_NAME) }
|
17
|
+
autocall(:Command) { CLI::Kit::BaseCommand }
|
18
|
+
|
19
|
+
autocall(:Executor) { CLI::Kit::Executor.new(log_file: LOG_FILE) }
|
20
|
+
autocall(:Resolver) do
|
21
|
+
CLI::Kit::Resolver.new(
|
22
|
+
tool_name: TOOL_NAME,
|
23
|
+
command_registry: __App__::Commands::Registry
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
autocall(:ErrorHandler) do
|
28
|
+
CLI::Kit::ErrorHandler.new(
|
29
|
+
log_file: LOG_FILE,
|
30
|
+
exception_reporter: nil
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require '__app__'
|
2
|
+
|
3
|
+
module __App__
|
4
|
+
module Commands
|
5
|
+
Registry = CLI::Kit::CommandRegistry.new(
|
6
|
+
default: 'help',
|
7
|
+
contextual_resolver: nil
|
8
|
+
)
|
9
|
+
|
10
|
+
def self.register(const, cmd, path)
|
11
|
+
autoload(const, path)
|
12
|
+
Registry.add(->() { const_get(const) }, cmd)
|
13
|
+
end
|
14
|
+
|
15
|
+
register :Example, 'example', '__app__/commands/example'
|
16
|
+
register :Help, 'help', '__app__/commands/help'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require '__app__'
|
2
|
+
|
3
|
+
module __App__
|
4
|
+
module Commands
|
5
|
+
class Example < __App__::Command
|
6
|
+
def call(_args, _name)
|
7
|
+
puts 'neato'
|
8
|
+
|
9
|
+
if rand < 0.05
|
10
|
+
raise(CLI::Kit::Abort, "you got unlucky!")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.help
|
15
|
+
"A dummy command.\nUsage: {{command:#{__App__::TOOL_NAME} example}}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require '__app__'
|
2
|
+
|
3
|
+
module __App__
|
4
|
+
module Commands
|
5
|
+
class Help < __App__::Command
|
6
|
+
def call(args, _name)
|
7
|
+
puts CLI::UI.fmt("{{bold:Available commands}}")
|
8
|
+
puts ""
|
9
|
+
|
10
|
+
__App__::Commands::Registry.resolved_commands.each do |name, klass|
|
11
|
+
next if name == 'help'
|
12
|
+
puts CLI::UI.fmt("{{command:#{__App__::TOOL_NAME} #{name}}}")
|
13
|
+
if help = klass.help
|
14
|
+
puts CLI::UI.fmt(help)
|
15
|
+
end
|
16
|
+
puts ""
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|