cli-kit 3.0.0.pre → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|