cli-kit 3.0.0.pre → 3.0.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/.rubocop.yml +21 -4
- data/Gemfile.lock +3 -3
- data/cli-kit.gemspec +15 -15
- data/exe/cli-kit +15 -0
- data/gen/lib/gen.rb +35 -0
- data/gen/lib/gen/commands.rb +18 -0
- data/gen/lib/gen/commands/help.rb +20 -0
- data/gen/lib/gen/commands/new.rb +21 -0
- data/gen/lib/gen/entry_point.rb +10 -0
- data/gen/lib/gen/generator.rb +163 -0
- data/gen/template/.gitignore +2 -0
- data/gen/template/Gemfile +4 -0
- data/gen/template/README.md +1 -0
- data/gen/template/bin/update-deps +94 -0
- data/gen/template/dev-gems.yml +3 -0
- data/gen/template/dev-vendor.yml +4 -0
- data/gen/template/exe/__app__-gems +17 -0
- data/gen/template/exe/__app__-vendor +18 -0
- data/gen/template/lib/__app__.rb +33 -0
- data/gen/template/lib/__app__/commands.rb +18 -0
- data/gen/template/lib/__app__/commands/example.rb +20 -0
- data/gen/template/lib/__app__/commands/help.rb +21 -0
- data/gen/template/lib/__app__/entry_point.rb +10 -0
- data/lib/cli/kit.rb +1 -0
- data/lib/cli/kit/autocall.rb +21 -0
- data/lib/cli/kit/base_command.rb +3 -3
- data/lib/cli/kit/command_registry.rb +22 -21
- data/lib/cli/kit/error_handler.rb +19 -13
- data/lib/cli/kit/executor.rb +28 -60
- data/lib/cli/kit/resolver.rb +42 -6
- data/lib/cli/kit/ruby_backports/enumerable.rb +1 -1
- data/lib/cli/kit/system.rb +0 -1
- data/lib/cli/kit/version.rb +1 -1
- metadata +31 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88690eeba1179ef8cb31ebd13b68d978e71f5c8a
|
4
|
+
data.tar.gz: f63da3dc52f120f759241232fb64953deb0e0b3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abd4591db97ad44a9ebdf3645181ad90b443ad70d3849b3f247cf577cc394b04638646d14ab1cc18273d05a3a55cb1cdb3022ce9052792b025a7498c6d94a309
|
7
|
+
data.tar.gz: 6c8571d319162adfeb0dd66c294fb225565c10e50fdcb70ab60dcd4bbd705131ec43916691c8ce160939348491ec453d5b1054a2504bc13594e76aecc20cdf01
|
data/.rubocop.yml
CHANGED
@@ -2,12 +2,17 @@ inherit_from:
|
|
2
2
|
- http://shopify.github.io/ruby-style-guide/rubocop.yml
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
Exclude:
|
6
|
-
|
7
|
-
|
5
|
+
Exclude: [ 'gen/template/**/*' ]
|
6
|
+
TargetRubyVersion: 2.3
|
7
|
+
|
8
|
+
Style/FrozenStringLiteralComment:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Shopify/RubocopComments:
|
12
|
+
Enabled: false
|
8
13
|
|
9
14
|
# This doesn't understand that <<~ doesn't exist in 2.0
|
10
|
-
|
15
|
+
Layout/IndentHeredoc:
|
11
16
|
Enabled: false
|
12
17
|
|
13
18
|
# This doesn't take into account retrying from an exception
|
@@ -21,3 +26,15 @@ Style/EmptyLiteral:
|
|
21
26
|
# allow the use of globals which makes sense in a CLI app like this
|
22
27
|
Style/GlobalVars:
|
23
28
|
Enabled: false
|
29
|
+
|
30
|
+
# allow using %r{} for regexes
|
31
|
+
Style/RegexpLiteral:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
# allow readable Dev::Util.begin formatting
|
35
|
+
Style/MultilineBlockChain:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
# allow using names to be more expressive
|
39
|
+
Performance/RedundantBlockCall:
|
40
|
+
Enabled: false
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cli-kit (
|
5
|
-
cli-ui (>= 1.
|
4
|
+
cli-kit (3.0.0)
|
5
|
+
cli-ui (>= 1.1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -11,7 +11,7 @@ GEM
|
|
11
11
|
ast (2.3.0)
|
12
12
|
builder (3.2.3)
|
13
13
|
byebug (9.0.6)
|
14
|
-
cli-ui (1.
|
14
|
+
cli-ui (1.1.0)
|
15
15
|
metaclass (0.0.4)
|
16
16
|
method_source (0.8.2)
|
17
17
|
minitest (5.10.2)
|
data/cli-kit.gemspec
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require 'cli/kit/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'cli-kit'
|
8
8
|
spec.version = CLI::Kit::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Burke Libbey', 'Julian Nadeau', 'Lisa Ugray']
|
10
|
+
spec.email = ['burke.libbey@shopify.com', 'julian.nadeau@shopify.com', 'lisa.ugray@shopify.com']
|
11
11
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
12
|
+
spec.summary = 'Terminal UI framework extensions'
|
13
|
+
spec.description = 'Terminal UI framework extensions'
|
14
|
+
spec.homepage = 'https://github.com/shopify/cli-kit'
|
15
|
+
spec.license = 'MIT'
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
18
|
f.match(%r{^(test|spec|features)/})
|
19
19
|
end
|
20
|
-
spec.bindir =
|
20
|
+
spec.bindir = 'exe'
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
-
spec.require_paths = [
|
22
|
+
spec.require_paths = ['lib']
|
23
23
|
|
24
|
-
spec.add_runtime_dependency
|
24
|
+
spec.add_runtime_dependency 'cli-ui', '>= 1.1.0'
|
25
25
|
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.15'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
29
29
|
end
|
data/exe/cli-kit
ADDED
@@ -0,0 +1,15 @@
|
|
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('gen/lib')
|
11
|
+
unshift_path.call('lib')
|
12
|
+
|
13
|
+
require 'gen'
|
14
|
+
|
15
|
+
exit(Gen::ErrorHandler.call { Gen::EntryPoint.call(ARGV) })
|
data/gen/lib/gen.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'cli/ui'
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
CLI::UI::StdoutRouter.enable
|
5
|
+
|
6
|
+
module Gen
|
7
|
+
extend CLI::Kit::Autocall
|
8
|
+
|
9
|
+
TOOL_NAME = 'cli-kit'
|
10
|
+
ROOT = File.expand_path('../../..', __FILE__)
|
11
|
+
LOG_FILE = '/tmp/cli-kit.log'
|
12
|
+
|
13
|
+
autoload(:Generator, 'gen/generator')
|
14
|
+
|
15
|
+
autoload(:EntryPoint, 'gen/entry_point')
|
16
|
+
autoload(:Commands, 'gen/commands')
|
17
|
+
|
18
|
+
autocall(:Config) { CLI::Kit::Config.new(tool_name: TOOL_NAME) }
|
19
|
+
autocall(:Command) { CLI::Kit::BaseCommand }
|
20
|
+
|
21
|
+
autocall(:Executor) { CLI::Kit::Executor.new(log_file: LOG_FILE) }
|
22
|
+
autocall(:Resolver) do
|
23
|
+
CLI::Kit::Resolver.new(
|
24
|
+
tool_name: TOOL_NAME,
|
25
|
+
command_registry: Gen::Commands::Registry
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
autocall(:ErrorHandler) do
|
30
|
+
CLI::Kit::ErrorHandler.new(
|
31
|
+
log_file: LOG_FILE,
|
32
|
+
exception_reporter: nil
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'gen'
|
2
|
+
|
3
|
+
module Gen
|
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 :Help, 'help', 'gen/commands/help'
|
16
|
+
register :New, 'new', 'gen/commands/new'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'gen'
|
2
|
+
|
3
|
+
module Gen
|
4
|
+
module Commands
|
5
|
+
class Help < Gen::Command
|
6
|
+
def call(_args, _name)
|
7
|
+
puts CLI::UI.fmt("{{bold:Available commands}}")
|
8
|
+
puts ""
|
9
|
+
|
10
|
+
Gen::Commands::Registry.resolved_commands.each do |name, klass|
|
11
|
+
puts CLI::UI.fmt("{{command:#{Gen::TOOL_NAME} #{name}}}")
|
12
|
+
if help = klass.help
|
13
|
+
puts CLI::UI.fmt(help)
|
14
|
+
end
|
15
|
+
puts ""
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'gen'
|
2
|
+
|
3
|
+
module Gen
|
4
|
+
module Commands
|
5
|
+
class New < Gen::Command
|
6
|
+
def call(args, _name)
|
7
|
+
unless args.size == 1
|
8
|
+
puts CLI::UI.fmt(self.class.help)
|
9
|
+
raise(CLI::Kit::AbortSilent)
|
10
|
+
end
|
11
|
+
project = args.first
|
12
|
+
|
13
|
+
Gen::Generator.run(project)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.help
|
17
|
+
"Generate a new cli-kit project.\nUsage: {{command:#{Gen::TOOL_NAME} new <name>}}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,163 @@
|
|
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' => false,
|
31
|
+
'bin/update-deps' => false,
|
32
|
+
'exe/__app__-gems' => 'exe/__app__',
|
33
|
+
'exe/__app__-vendor' => false,
|
34
|
+
'dev-gems.yml' => 'dev.yml',
|
35
|
+
'dev-vendor.yml' => false,
|
36
|
+
}.freeze
|
37
|
+
private_constant :BUNDLER_TRANSLATIONS
|
38
|
+
|
39
|
+
def initialize(project_name)
|
40
|
+
raise(
|
41
|
+
CLI::Kit::Abort,
|
42
|
+
"project name must match {{bold:#{VALID_PROJECT_NAME}}} (but can be changed later)"
|
43
|
+
) unless project_name =~ VALID_PROJECT_NAME
|
44
|
+
@project_name = project_name
|
45
|
+
@title_case_project_name = @project_name.sub(/^./, &:upcase)
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
vendor = ask_vendor?
|
50
|
+
create_project_dir
|
51
|
+
if vendor
|
52
|
+
copy_files(translations: VENDOR_TRANSLATIONS)
|
53
|
+
update_deps
|
54
|
+
else
|
55
|
+
copy_files(translations: BUNDLER_TRANSLATIONS)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def ask_vendor?
|
62
|
+
vendor = nil
|
63
|
+
CLI::UI::Frame.open('Configuration') do
|
64
|
+
q = 'How would you like the application to consume {{command:cli-kit}} and {{command:cli-ui}}?'
|
65
|
+
vendor = CLI::UI::Prompt.ask(q) do |c|
|
66
|
+
c.option('Vendor {{italic:(faster execution, more difficult to update deps)}}') { 'vendor' }
|
67
|
+
c.option('Bundler {{italic:(slower execution, easier dep management)}}') { 'bundler' }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
vendor == 'vendor'
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_project_dir
|
74
|
+
info(create: '')
|
75
|
+
FileUtils.mkdir(@project_name)
|
76
|
+
rescue Errno::EEXIST
|
77
|
+
error("directory already exists: #{@project_name}")
|
78
|
+
end
|
79
|
+
|
80
|
+
def copy_files(translations:)
|
81
|
+
each_template_file do |source_name|
|
82
|
+
target_name = translations.fetch(source_name, source_name)
|
83
|
+
next if target_name == false
|
84
|
+
target_name = apply_template_variables(target_name)
|
85
|
+
|
86
|
+
source = File.join(TEMPLATE_ROOT, source_name)
|
87
|
+
target = File.join(@project_name, target_name)
|
88
|
+
|
89
|
+
info(create: target_name)
|
90
|
+
|
91
|
+
if Dir.exist?(source)
|
92
|
+
FileUtils.mkdir(target)
|
93
|
+
else
|
94
|
+
content = apply_template_variables(File.read(source))
|
95
|
+
File.write(target, content)
|
96
|
+
end
|
97
|
+
File.chmod(File.stat(source).mode, target)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def update_deps
|
102
|
+
Dir.mktmpdir do |tmp|
|
103
|
+
clone(tmp, 'cli-ui')
|
104
|
+
clone(tmp, 'cli-kit')
|
105
|
+
info(run: 'bin/update-deps')
|
106
|
+
Dir.chdir(@project_name) do
|
107
|
+
system({ 'SOURCE_ROOT' => tmp }, 'bin/update-deps')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def clone(dir, repo)
|
113
|
+
info(clone: repo)
|
114
|
+
out, stat = Open3.capture2e('git', '-C', dir, 'clone', "https://github.com/shopify/#{repo}")
|
115
|
+
unless stat.success?
|
116
|
+
STDERR.puts(out)
|
117
|
+
error("git clone failed")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def each_template_file
|
122
|
+
return enum_for(:each_template_file) unless block_given?
|
123
|
+
|
124
|
+
root = Pathname.new(TEMPLATE_ROOT)
|
125
|
+
Dir.glob("#{TEMPLATE_ROOT}/**/*").each do |f|
|
126
|
+
el = Pathname.new(f)
|
127
|
+
yield(el.relative_path_from(root).to_s)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def apply_template_variables(s)
|
132
|
+
s
|
133
|
+
.gsub(/__app__/, @project_name)
|
134
|
+
.gsub(/__App__/, @title_case_project_name)
|
135
|
+
.gsub(/__cli-kit-version__/, cli_kit_version)
|
136
|
+
.gsub(/__cli-ui-version__/, cli_ui_version)
|
137
|
+
end
|
138
|
+
|
139
|
+
def cli_kit_version
|
140
|
+
require 'cli/kit/version'
|
141
|
+
CLI::Kit::VERSION.to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
def cli_ui_version
|
145
|
+
require 'cli/ui/version'
|
146
|
+
CLI::UI::VERSION.to_s
|
147
|
+
end
|
148
|
+
|
149
|
+
def info(create: nil, clone: nil, run: nil)
|
150
|
+
if clone
|
151
|
+
puts(CLI::UI.fmt("\t{{bold:{{yellow:clone}}\t#{clone}}}"))
|
152
|
+
elsif create
|
153
|
+
puts(CLI::UI.fmt("\t{{bold:{{blue:create}}\t#{create}}}"))
|
154
|
+
elsif run
|
155
|
+
puts(CLI::UI.fmt("\t{{bold:{{green:run}}\t#{run}}}"))
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def error(msg)
|
160
|
+
raise(CLI::Kit::Abort, msg)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# __app__
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby --disable-gems
|
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 {{bold_blue:#{path}}} for this script to succeed.\n" \
|
42
|
+
" Alternatively, you can set {{bold_blue:SOURCE_ROOT}} to a directory containing {{yellow:#{dep}}}.\n" \
|
43
|
+
" {{bold_blue:SOURCE_ROOT}} defaults to {{bold_blue:../}}."
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
head_sha = nil
|
48
|
+
dirty = false
|
49
|
+
|
50
|
+
Dir.chdir(path) do
|
51
|
+
_, _, stat = Open3.capture3('git fetch origin master')
|
52
|
+
bail("couldn't git fetch in dependency: {{yellow:#{dep}}}") unless stat.success?
|
53
|
+
|
54
|
+
head_sha, stat = Open3.capture2('git rev-parse HEAD')
|
55
|
+
bail("couldn't determine HEAD: {{yellow:#{dep}}}") unless stat.success?
|
56
|
+
head_sha.chomp!
|
57
|
+
|
58
|
+
fetch_head_sha, stat = Open3.capture2('git rev-parse FETCH_HEAD')
|
59
|
+
bail("couldn't determine FETCH_HEAD: {{yellow:#{dep}}}") unless stat.success?
|
60
|
+
fetch_head_sha.chomp!
|
61
|
+
|
62
|
+
git_status, stat = Open3.capture2('git status --porcelain')
|
63
|
+
bail("couldn't determine git status: {{yellow:#{dep}}}") unless stat.success?
|
64
|
+
|
65
|
+
if head_sha != fetch_head_sha
|
66
|
+
warn(
|
67
|
+
"Copying files from {{yellow:#{path}}} to satisfy dependency {{yellow:#{dep}}}.\n" \
|
68
|
+
" However, the repo at {{yellow:#{path}}} isn't up to date.\n" \
|
69
|
+
" The checked-out revision is {{yellow:#{head_sha[0..8]}}}, and "\
|
70
|
+
"{{yellow:origin/master}} is {{yellow:#{fetch_head_sha[0..8]}}}.\n" \
|
71
|
+
" Unless you know what you're doing, you should {{green:cd}} to that repo and {{green:git pull}}, then run this again."
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
unless git_status.chomp.empty?
|
76
|
+
dirty = true
|
77
|
+
warn("importing uncommitted changes from dependency: {{yellow:#{dep}}}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
depdir = File.expand_path("../../vendor/deps/#{dep}", __FILE__)
|
82
|
+
FileUtils.rm_rf(depdir)
|
83
|
+
FileUtils.mkdir_p(depdir)
|
84
|
+
dstlib = File.expand_path('lib', depdir)
|
85
|
+
srclib = File.expand_path('lib', path)
|
86
|
+
|
87
|
+
FileUtils.cp_r(srclib, dstlib)
|
88
|
+
|
89
|
+
rev = head_sha
|
90
|
+
rev << " (dirty)" if dirty
|
91
|
+
rev << "\n"
|
92
|
+
|
93
|
+
File.write("#{depdir}/REVISION", rev)
|
94
|
+
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,20 @@
|
|
1
|
+
require '__app__'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module __App__
|
5
|
+
module Commands
|
6
|
+
class Example < __App__::Command
|
7
|
+
def call(_args, _name)
|
8
|
+
puts 'neato'
|
9
|
+
|
10
|
+
if rand < 0.05
|
11
|
+
raise(CLI::Kit::Abort, "you got unlucky!")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.help
|
16
|
+
"A dummy command.\nUsage: {{command:#{__App__::TOOL_NAME} example}}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
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
|
data/lib/cli/kit.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'cli/kit'
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module Kit
|
5
|
+
module Autocall
|
6
|
+
def autocall(const, &block)
|
7
|
+
@autocalls ||= {}
|
8
|
+
@autocalls[const] = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def const_missing(const)
|
12
|
+
block = begin
|
13
|
+
@autocalls.fetch(const)
|
14
|
+
rescue KeyError
|
15
|
+
return super
|
16
|
+
end
|
17
|
+
const_set(const, block.call)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/cli/kit/base_command.rb
CHANGED
@@ -7,11 +7,11 @@ module CLI
|
|
7
7
|
true
|
8
8
|
end
|
9
9
|
|
10
|
-
def self.statsd_increment(
|
10
|
+
def self.statsd_increment(_metric, **_kwargs)
|
11
11
|
nil
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.statsd_time(
|
14
|
+
def self.statsd_time(_metric, **_kwargs)
|
15
15
|
yield
|
16
16
|
end
|
17
17
|
|
@@ -31,7 +31,7 @@ module CLI
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
def call(
|
34
|
+
def call(_args, _command_name)
|
35
35
|
raise NotImplementedError
|
36
36
|
end
|
37
37
|
|
@@ -19,11 +19,11 @@ module CLI
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def initialize(default:, contextual_resolver:
|
22
|
+
def initialize(default:, contextual_resolver: nil)
|
23
23
|
@commands = {}
|
24
24
|
@aliases = {}
|
25
25
|
@default = default
|
26
|
-
@contextual_resolver = contextual_resolver
|
26
|
+
@contextual_resolver = contextual_resolver || NullContextualResolver
|
27
27
|
end
|
28
28
|
|
29
29
|
def resolved_commands
|
@@ -45,47 +45,48 @@ module CLI
|
|
45
45
|
aliases[from] = to unless aliases[from]
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def command_names
|
49
|
+
@contextual_resolver.command_names + commands.keys
|
50
|
+
end
|
51
|
+
|
52
|
+
def exist?(name)
|
53
|
+
!resolve_command(name).first.nil?
|
52
54
|
end
|
53
55
|
|
56
|
+
private
|
57
|
+
|
54
58
|
def resolve_alias(name)
|
55
59
|
aliases[name] || @contextual_resolver.aliases.fetch(name, name)
|
56
60
|
end
|
57
61
|
|
58
|
-
def
|
62
|
+
def resolve_command(name)
|
59
63
|
name = resolve_alias(name)
|
60
|
-
|
61
|
-
|
64
|
+
resolve_global_command(name) || \
|
65
|
+
resolve_contextual_command(name) || \
|
66
|
+
[nil, name]
|
67
|
+
end
|
68
|
+
|
69
|
+
def resolve_global_command(name)
|
70
|
+
klass = resolve_class(commands.fetch(name, nil))
|
71
|
+
return nil unless klass
|
62
72
|
[klass, name]
|
63
73
|
rescue NameError
|
64
74
|
nil
|
65
75
|
end
|
66
76
|
|
67
77
|
def resolve_contextual_command(name)
|
68
|
-
name = resolve_alias(name)
|
69
78
|
found = @contextual_resolver.command_names.include?(name)
|
70
79
|
return nil unless found
|
71
80
|
[@contextual_resolver.command_class(name), name]
|
72
81
|
end
|
73
82
|
|
74
|
-
def command_names
|
75
|
-
@contextual_resolver.command_names + commands.keys
|
76
|
-
end
|
77
|
-
|
78
|
-
def exist?(name)
|
79
|
-
!resolve_command(name).first.nil?
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
|
84
83
|
def resolve_class(class_or_proc)
|
85
84
|
if class_or_proc.is_a?(Class)
|
86
85
|
class_or_proc
|
87
|
-
|
86
|
+
elsif class_or_proc.respond_to?(:call)
|
88
87
|
class_or_proc.call
|
88
|
+
else
|
89
|
+
class_or_proc
|
89
90
|
end
|
90
91
|
end
|
91
92
|
end
|
@@ -1,25 +1,34 @@
|
|
1
1
|
require 'cli/kit'
|
2
|
+
require 'English'
|
2
3
|
|
3
4
|
module CLI
|
4
5
|
module Kit
|
5
6
|
class ErrorHandler
|
6
|
-
def initialize(log_file
|
7
|
+
def initialize(log_file:, exception_reporter:)
|
7
8
|
@log_file = log_file
|
8
|
-
@exception_reporter_or_proc = exception_reporter
|
9
|
+
@exception_reporter_or_proc = exception_reporter || NullExceptionReporter
|
9
10
|
end
|
10
11
|
|
11
12
|
module NullExceptionReporter
|
12
|
-
def self.report(
|
13
|
+
def self.report(_exception, _logs)
|
13
14
|
nil
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
def call(&block)
|
19
|
+
install!
|
20
|
+
handle_abort(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
17
25
|
def install!
|
18
26
|
at_exit { handle_final_exception(@exception || $ERROR_INFO) }
|
19
27
|
end
|
20
28
|
|
21
29
|
def handle_abort
|
22
30
|
yield
|
31
|
+
CLI::Kit::EXIT_SUCCESS
|
23
32
|
rescue CLI::Kit::GenericAbort => e
|
24
33
|
is_bug = e.is_a?(CLI::Kit::Bug) || e.is_a?(CLI::Kit::BugSilent)
|
25
34
|
is_silent = e.is_a?(CLI::Kit::AbortSilent) || e.is_a?(CLI::Kit::BugSilent)
|
@@ -29,12 +38,10 @@ module CLI
|
|
29
38
|
|
30
39
|
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
31
40
|
rescue Interrupt
|
32
|
-
|
41
|
+
$stderr.puts(format_error_message("Interrupt"))
|
33
42
|
return CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
34
43
|
end
|
35
44
|
|
36
|
-
private
|
37
|
-
|
38
45
|
def handle_final_exception(error)
|
39
46
|
notify_with = nil
|
40
47
|
|
@@ -47,13 +54,13 @@ module CLI
|
|
47
54
|
unless skip.include?(error.message)
|
48
55
|
notify_with = error
|
49
56
|
end
|
50
|
-
when SystemExit
|
57
|
+
when SystemExit # "exit N" called
|
51
58
|
case error.status
|
52
|
-
when CLI::Kit::EXIT_SUCCESS
|
59
|
+
when CLI::Kit::EXIT_SUCCESS # submit nothing if it was `exit 0`
|
53
60
|
when CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
54
|
-
# if it was `exit 30`, translate the exit code to 1, and submit nothing
|
61
|
+
# if it was `exit 30`, translate the exit code to 1, and submit nothing.
|
55
62
|
# 30 is used to signal normal failures that are not indicative of bugs.
|
56
|
-
#
|
63
|
+
# However, users should see it presented as 1.
|
57
64
|
exit 1
|
58
65
|
else
|
59
66
|
# A weird termination status happened. `error.exception "message"` will maintain backtrace
|
@@ -70,7 +77,7 @@ module CLI
|
|
70
77
|
rescue => e
|
71
78
|
"(#{e.class}: #{e.message})"
|
72
79
|
end
|
73
|
-
|
80
|
+
exception_reporter.report(notify_with, logs)
|
74
81
|
end
|
75
82
|
end
|
76
83
|
|
@@ -86,9 +93,8 @@ module CLI
|
|
86
93
|
CLI::UI.fmt("{{red:#{msg}}}")
|
87
94
|
end
|
88
95
|
|
89
|
-
|
90
96
|
def print_error_message(e)
|
91
|
-
|
97
|
+
$stderr.puts(format_error_message(e.message))
|
92
98
|
end
|
93
99
|
end
|
94
100
|
end
|
data/lib/cli/kit/executor.rb
CHANGED
@@ -4,82 +4,50 @@ require 'English'
|
|
4
4
|
module CLI
|
5
5
|
module Kit
|
6
6
|
class Executor
|
7
|
-
def initialize(
|
8
|
-
tool_name:, command_registry:, error_handler:, log_file: nil
|
9
|
-
)
|
10
|
-
@tool_name = tool_name
|
11
|
-
@command_registry = command_registry
|
12
|
-
@error_handler = error_handler
|
7
|
+
def initialize(log_file:)
|
13
8
|
@log_file = log_file
|
14
9
|
end
|
15
10
|
|
11
|
+
def call(command, command_name, args)
|
12
|
+
with_traps { with_logging { command.call(args, command_name) } }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
16
17
|
def with_logging(&block)
|
17
18
|
return yield unless @log_file
|
18
19
|
CLI::UI.log_output_to(@log_file, &block)
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def trap_signals
|
26
|
-
trap('QUIT') do
|
27
|
-
z = caller
|
28
|
-
CLI::UI.raw do
|
29
|
-
STDERR.puts('SIGQUIT: quit')
|
30
|
-
STDERR.puts(z)
|
31
|
-
end
|
32
|
-
exit 1
|
33
|
-
end
|
34
|
-
trap('INFO') do
|
35
|
-
z = caller
|
36
|
-
CLI::UI.raw do
|
37
|
-
STDERR.puts('SIGINFO:')
|
38
|
-
STDERR.puts(z)
|
39
|
-
# Thread.list.map { |t| t.backtrace }
|
22
|
+
def with_traps
|
23
|
+
twrap('QUIT', method(:quit_handler)) do
|
24
|
+
twrap('INFO', method(:info_handler)) do
|
25
|
+
yield
|
40
26
|
end
|
41
27
|
end
|
42
28
|
end
|
43
29
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
command_not_found(command_name)
|
50
|
-
raise CLI::Kit::AbortSilent # Already output message
|
51
|
-
end
|
52
|
-
command.call(args, command_name)
|
53
|
-
CLI::Kit::EXIT_SUCCESS # unless an exception was raised
|
54
|
-
end
|
55
|
-
end
|
30
|
+
def twrap(signal, handler)
|
31
|
+
prev_handler = trap(signal, handler)
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
trap(signal, prev_handler)
|
56
35
|
end
|
57
36
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
37
|
+
def quit_handler(_sig)
|
38
|
+
z = caller
|
39
|
+
CLI::UI.raw do
|
40
|
+
$stderr.puts('SIGQUIT: quit')
|
41
|
+
$stderr.puts(z)
|
61
42
|
end
|
43
|
+
exit(CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG)
|
44
|
+
end
|
62
45
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# We don't want to match against any possible command
|
70
|
-
# so reject anything that is too far away
|
71
|
-
possible_matches.reject! do |possible_match|
|
72
|
-
CLI::Kit::Levenshtein.distance(possible_match, name) > 3
|
73
|
-
end
|
74
|
-
|
75
|
-
# If we have any matches left, tell the user
|
76
|
-
if possible_matches.any?
|
77
|
-
CLI::UI::Frame.open("{{bold:Did you mean?}}", timing: false, color: :blue) do
|
78
|
-
possible_matches.each do |possible_match|
|
79
|
-
STDERR.puts CLI::UI.fmt("{{command:#{@tool_name} #{possible_match}}}")
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
46
|
+
def info_handler(_sig)
|
47
|
+
z = caller
|
48
|
+
CLI::UI.raw do
|
49
|
+
$stderr.puts('SIGINFO:')
|
50
|
+
$stderr.puts(z)
|
83
51
|
end
|
84
52
|
end
|
85
53
|
end
|
data/lib/cli/kit/resolver.rb
CHANGED
@@ -3,21 +3,57 @@ require 'cli/kit'
|
|
3
3
|
module CLI
|
4
4
|
module Kit
|
5
5
|
class Resolver
|
6
|
-
def initialize(
|
6
|
+
def initialize(tool_name:, command_registry:)
|
7
|
+
@tool_name = tool_name
|
7
8
|
@command_registry = command_registry
|
8
|
-
@error_handler = error_handler
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(args)
|
12
12
|
args = args.dup
|
13
13
|
command_name = args.shift
|
14
14
|
|
15
|
-
@
|
16
|
-
|
17
|
-
|
15
|
+
command, resolved_name = @command_registry.lookup_command(command_name)
|
16
|
+
|
17
|
+
if command.nil?
|
18
|
+
command_not_found(command_name)
|
19
|
+
raise CLI::Kit::AbortSilent # Already output message
|
20
|
+
end
|
21
|
+
|
22
|
+
[command, resolved_name, args]
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def command_not_found(name)
|
28
|
+
CLI::UI::Frame.open("Command not found", color: :red, timing: false) do
|
29
|
+
$stderr.puts(CLI::UI.fmt("{{command:#{@tool_name} #{name}}} was not found"))
|
18
30
|
end
|
19
31
|
|
20
|
-
|
32
|
+
cmds = commands_and_aliases
|
33
|
+
if cmds.all? { |cmd| cmd.is_a?(String) }
|
34
|
+
possible_matches = cmds.min_by(2) do |cmd|
|
35
|
+
CLI::Kit::Levenshtein.distance(cmd, name)
|
36
|
+
end
|
37
|
+
|
38
|
+
# We don't want to match against any possible command
|
39
|
+
# so reject anything that is too far away
|
40
|
+
possible_matches.reject! do |possible_match|
|
41
|
+
CLI::Kit::Levenshtein.distance(possible_match, name) > 3
|
42
|
+
end
|
43
|
+
|
44
|
+
# If we have any matches left, tell the user
|
45
|
+
if possible_matches.any?
|
46
|
+
CLI::UI::Frame.open("{{bold:Did you mean?}}", timing: false, color: :blue) do
|
47
|
+
possible_matches.each do |possible_match|
|
48
|
+
$stderr.puts CLI::UI.fmt("{{command:#{@tool_name} #{possible_match}}}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def commands_and_aliases
|
56
|
+
@command_registry.command_names + @command_registry.aliases.keys
|
21
57
|
end
|
22
58
|
end
|
23
59
|
end
|
data/lib/cli/kit/system.rb
CHANGED
data/lib/cli/kit/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cli-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
- Julian Nadeau
|
9
|
+
- Lisa Ugray
|
9
10
|
autorequire:
|
10
11
|
bindir: exe
|
11
12
|
cert_chain: []
|
12
|
-
date: 2018-02-
|
13
|
+
date: 2018-02-27 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: cli-ui
|
@@ -17,14 +18,14 @@ dependencies:
|
|
17
18
|
requirements:
|
18
19
|
- - ">="
|
19
20
|
- !ruby/object:Gem::Version
|
20
|
-
version: 1.
|
21
|
+
version: 1.1.0
|
21
22
|
type: :runtime
|
22
23
|
prerelease: false
|
23
24
|
version_requirements: !ruby/object:Gem::Requirement
|
24
25
|
requirements:
|
25
26
|
- - ">="
|
26
27
|
- !ruby/object:Gem::Version
|
27
|
-
version: 1.
|
28
|
+
version: 1.1.0
|
28
29
|
- !ruby/object:Gem::Dependency
|
29
30
|
name: bundler
|
30
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,7 +72,9 @@ description: Terminal UI framework extensions
|
|
71
72
|
email:
|
72
73
|
- burke.libbey@shopify.com
|
73
74
|
- julian.nadeau@shopify.com
|
74
|
-
|
75
|
+
- lisa.ugray@shopify.com
|
76
|
+
executables:
|
77
|
+
- cli-kit
|
75
78
|
extensions: []
|
76
79
|
extra_rdoc_files: []
|
77
80
|
files:
|
@@ -86,7 +89,28 @@ files:
|
|
86
89
|
- bin/testunit
|
87
90
|
- cli-kit.gemspec
|
88
91
|
- dev.yml
|
92
|
+
- exe/cli-kit
|
93
|
+
- gen/lib/gen.rb
|
94
|
+
- gen/lib/gen/commands.rb
|
95
|
+
- gen/lib/gen/commands/help.rb
|
96
|
+
- gen/lib/gen/commands/new.rb
|
97
|
+
- gen/lib/gen/entry_point.rb
|
98
|
+
- gen/lib/gen/generator.rb
|
99
|
+
- gen/template/.gitignore
|
100
|
+
- gen/template/Gemfile
|
101
|
+
- gen/template/README.md
|
102
|
+
- gen/template/bin/update-deps
|
103
|
+
- gen/template/dev-gems.yml
|
104
|
+
- gen/template/dev-vendor.yml
|
105
|
+
- gen/template/exe/__app__-gems
|
106
|
+
- gen/template/exe/__app__-vendor
|
107
|
+
- gen/template/lib/__app__.rb
|
108
|
+
- gen/template/lib/__app__/commands.rb
|
109
|
+
- gen/template/lib/__app__/commands/example.rb
|
110
|
+
- gen/template/lib/__app__/commands/help.rb
|
111
|
+
- gen/template/lib/__app__/entry_point.rb
|
89
112
|
- lib/cli/kit.rb
|
113
|
+
- lib/cli/kit/autocall.rb
|
90
114
|
- lib/cli/kit/base_command.rb
|
91
115
|
- lib/cli/kit/command_registry.rb
|
92
116
|
- lib/cli/kit/config.rb
|
@@ -113,9 +137,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
137
|
version: '0'
|
114
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
139
|
requirements:
|
116
|
-
- - "
|
140
|
+
- - ">="
|
117
141
|
- !ruby/object:Gem::Version
|
118
|
-
version:
|
142
|
+
version: '0'
|
119
143
|
requirements: []
|
120
144
|
rubyforge_project:
|
121
145
|
rubygems_version: 2.6.14
|