shopify-cli 1.0.2 → 1.1.1
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/.travis.yml +3 -2
- data/CHANGELOG.md +20 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -13
- data/bin/load_shopify.rb +3 -1
- data/bin/shopify +2 -0
- data/docs/Gemfile.lock +23 -13
- data/docs/getting-started/index.md +3 -2
- data/docs/getting-started/install/index.md +55 -9
- data/docs/getting-started/uninstall/index.md +1 -1
- data/docs/getting-started/upgrade/index.md +8 -4
- data/ext/shopify-cli/extconf.rb +40 -20
- data/lib/project_types/extension/cli.rb +1 -1
- data/lib/project_types/extension/commands/build.rb +1 -1
- data/lib/project_types/extension/models/type.rb +1 -0
- data/lib/project_types/extension/tasks/create_extension.rb +1 -1
- data/lib/project_types/extension/tasks/get_app.rb +1 -1
- data/lib/project_types/extension/tasks/update_draft.rb +1 -1
- 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 +7 -5
- data/lib/project_types/node/commands/generate/page.rb +9 -5
- data/lib/project_types/node/commands/generate/webhook.rb +5 -1
- data/lib/project_types/node/messages/messages.rb +1 -0
- data/lib/project_types/rails/cli.rb +0 -1
- 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/cli.rb +2 -3
- data/lib/project_types/script/commands/create.rb +5 -9
- data/lib/project_types/script/commands/disable.rb +4 -15
- data/lib/project_types/script/commands/enable.rb +37 -13
- data/lib/project_types/script/commands/push.rb +8 -13
- data/lib/project_types/script/config/extension_points.yml +9 -3
- data/lib/project_types/script/errors.rb +8 -0
- data/lib/project_types/script/forms/create.rb +1 -1
- data/lib/project_types/script/layers/application/create_script.rb +7 -6
- data/lib/project_types/script/layers/application/disable_script.rb +9 -7
- data/lib/project_types/script/layers/application/enable_script.rb +11 -9
- data/lib/project_types/script/layers/application/push_script.rb +6 -4
- data/lib/project_types/script/layers/domain/errors.rb +2 -0
- data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +2 -2
- data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/errors.rb +2 -0
- data/lib/project_types/script/layers/infrastructure/script_service.rb +8 -2
- data/lib/project_types/script/messages/messages.rb +25 -31
- data/lib/project_types/script/script_project.rb +6 -2
- data/lib/project_types/script/templates/ts/as-pect.config.js +6 -0
- data/lib/project_types/script/ui/error_handler.rb +8 -0
- data/lib/project_types/script/ui/printing_spinner.rb +75 -0
- data/lib/rubygems_plugin.rb +18 -10
- data/lib/shopify-cli/admin_api/populate_resource_command.rb +1 -1
- data/lib/shopify-cli/admin_api/schema.rb +20 -18
- data/lib/shopify-cli/command.rb +14 -11
- data/lib/shopify-cli/commands.rb +1 -0
- data/lib/shopify-cli/commands/config.rb +44 -0
- data/lib/shopify-cli/commands/connect.rb +8 -69
- data/lib/shopify-cli/commands/create.rb +2 -2
- data/lib/shopify-cli/commands/help.rb +1 -1
- data/lib/shopify-cli/commands/system.rb +22 -13
- data/lib/shopify-cli/context.rb +28 -0
- data/lib/shopify-cli/core.rb +0 -1
- data/lib/shopify-cli/core/entry_point.rb +1 -1
- data/lib/shopify-cli/core/executor.rb +3 -5
- data/lib/shopify-cli/core/monorail.rb +1 -1
- data/lib/shopify-cli/db.rb +1 -1
- data/lib/shopify-cli/feature.rb +97 -0
- data/lib/shopify-cli/heroku.rb +21 -5
- data/lib/shopify-cli/js_deps.rb +2 -2
- data/lib/shopify-cli/js_system.rb +2 -2
- data/lib/shopify-cli/messages/messages.rb +40 -12
- data/lib/shopify-cli/partners_api/organizations.rb +7 -7
- data/lib/shopify-cli/process_supervision.rb +60 -21
- data/lib/shopify-cli/project.rb +14 -6
- data/lib/shopify-cli/project_type.rb +5 -7
- data/lib/shopify-cli/sub_command.rb +1 -0
- data/lib/shopify-cli/task.rb +2 -2
- data/lib/shopify-cli/tasks.rb +11 -4
- data/lib/shopify-cli/tasks/ensure_env.rb +72 -16
- data/lib/shopify-cli/tasks/update_dashboard_urls.rb +4 -3
- data/lib/shopify-cli/tunnel.rb +53 -14
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +36 -9
- 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 +28 -6
- data/Vagrantfile +0 -17
- data/lib/project_types/script/forms/enable.rb +0 -24
- data/lib/project_types/script/forms/push.rb +0 -19
- data/lib/project_types/script/forms/script_form.rb +0 -66
|
@@ -28,16 +28,17 @@ module ShopifyCli
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def construct_redirect_urls(urls, new_url, callback_url)
|
|
31
|
-
urls.map do |url|
|
|
31
|
+
new_urls = urls.map do |url|
|
|
32
32
|
if (match = url.match(NGROK_REGEX))
|
|
33
33
|
"#{new_url}#{match[2]}"
|
|
34
34
|
else
|
|
35
35
|
url
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
|
-
if
|
|
39
|
-
|
|
38
|
+
if new_urls.grep(/#{new_url}#{callback_url}/).empty?
|
|
39
|
+
new_urls.push("#{new_url}#{callback_url}")
|
|
40
40
|
end
|
|
41
|
+
new_urls.uniq
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
end
|
data/lib/shopify-cli/tunnel.rb
CHANGED
|
@@ -21,6 +21,7 @@ module ShopifyCli
|
|
|
21
21
|
DOWNLOAD_URLS = {
|
|
22
22
|
mac: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip',
|
|
23
23
|
linux: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip',
|
|
24
|
+
windows: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip',
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
NGROK_TUNNELS_URI = URI.parse('http://localhost:4040/api/tunnels')
|
|
@@ -62,14 +63,19 @@ module ShopifyCli
|
|
|
62
63
|
#
|
|
63
64
|
def start(ctx, port: PORT)
|
|
64
65
|
install(ctx)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
ctx.puts(ctx.message('core.tunnel.start_with_account', log.url, log.account))
|
|
66
|
+
url, account, seconds_remaining = start_ngrok(ctx, port)
|
|
67
|
+
if account
|
|
68
|
+
ctx.puts(ctx.message('core.tunnel.start_with_account', url, account))
|
|
69
69
|
else
|
|
70
|
-
|
|
70
|
+
if seconds_remaining <= 0
|
|
71
|
+
ctx.puts(ctx.message('core.tunnel.timed_out'))
|
|
72
|
+
url, _account, seconds_remaining = restart_ngrok(ctx, port)
|
|
73
|
+
end
|
|
74
|
+
ctx.puts(ctx.message('core.tunnel.start', url))
|
|
75
|
+
ctx.puts(ctx.message('core.tunnel.will_timeout', seconds_to_hm(seconds_remaining)))
|
|
76
|
+
ctx.puts(ctx.message('core.tunnel.signup_suggestion', ShopifyCli::TOOL_NAME))
|
|
71
77
|
end
|
|
72
|
-
|
|
78
|
+
url
|
|
73
79
|
end
|
|
74
80
|
|
|
75
81
|
##
|
|
@@ -83,7 +89,7 @@ module ShopifyCli
|
|
|
83
89
|
#
|
|
84
90
|
def auth(ctx, token)
|
|
85
91
|
install(ctx)
|
|
86
|
-
ctx.system(File.join(ShopifyCli
|
|
92
|
+
ctx.system(File.join(ShopifyCli.cache_dir, 'ngrok'), 'authtoken', token)
|
|
87
93
|
end
|
|
88
94
|
|
|
89
95
|
##
|
|
@@ -117,14 +123,21 @@ module ShopifyCli
|
|
|
117
123
|
private
|
|
118
124
|
|
|
119
125
|
def install(ctx)
|
|
120
|
-
return if File.exist?(File.join(ShopifyCli
|
|
126
|
+
return if File.exist?(File.join(ShopifyCli.cache_dir, ctx.windows? ? 'ngrok.exe' : 'ngrok'))
|
|
127
|
+
check_prereq_command(ctx, 'curl')
|
|
128
|
+
check_prereq_command(ctx, ctx.linux? ? 'unzip' : 'tar')
|
|
121
129
|
spinner = CLI::UI::SpinGroup.new
|
|
122
130
|
spinner.add('Installing ngrok...') do
|
|
123
|
-
zip_dest = File.join(ShopifyCli
|
|
131
|
+
zip_dest = File.join(ShopifyCli.cache_dir, 'ngrok.zip')
|
|
124
132
|
unless File.exist?(zip_dest)
|
|
125
|
-
ctx.system('curl', '-o', zip_dest, DOWNLOAD_URLS[ctx.os], chdir: ShopifyCli
|
|
133
|
+
ctx.system('curl', '-o', zip_dest, DOWNLOAD_URLS[ctx.os], chdir: ShopifyCli.cache_dir)
|
|
134
|
+
end
|
|
135
|
+
args = if ctx.linux?
|
|
136
|
+
%W(unzip -u #{zip_dest})
|
|
137
|
+
else
|
|
138
|
+
%W(tar -xf #{zip_dest})
|
|
126
139
|
end
|
|
127
|
-
ctx.system(
|
|
140
|
+
ctx.system(*args, chdir: ShopifyCli.cache_dir)
|
|
128
141
|
ctx.rm(zip_dest)
|
|
129
142
|
end
|
|
130
143
|
spinner.wait
|
|
@@ -138,13 +151,37 @@ module ShopifyCli
|
|
|
138
151
|
end
|
|
139
152
|
|
|
140
153
|
def ngrok_command(port)
|
|
141
|
-
"
|
|
154
|
+
"\"#{File.join(ShopifyCli.cache_dir, 'ngrok')}\" http -inspect=false -log=stdout -log-level=debug #{port}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def seconds_to_hm(seconds)
|
|
158
|
+
format("%d hours %d minutes", seconds / 3600, seconds / 60 % 60)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def start_ngrok(ctx, port)
|
|
162
|
+
process = ShopifyCli::ProcessSupervision.start(:ngrok, ngrok_command(port))
|
|
163
|
+
log = fetch_url(ctx, process.log_path)
|
|
164
|
+
seconds_remaining = (process.time.to_i + log.timeout) - Time.now.to_i
|
|
165
|
+
[log.url, log.account, seconds_remaining]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def restart_ngrok(ctx, port)
|
|
169
|
+
unless ShopifyCli::ProcessSupervision.stop(:ngrok)
|
|
170
|
+
ctx.abort(ctx.message('core.tunnel.error.stop'))
|
|
171
|
+
end
|
|
172
|
+
start_ngrok(ctx, port)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def check_prereq_command(ctx, command)
|
|
176
|
+
cmd_path = ctx.which(command)
|
|
177
|
+
ctx.abort(ctx.message('core.tunnel.error.prereq_command_required', command)) if cmd_path.nil?
|
|
178
|
+
ctx.done(ctx.message('core.tunnel.prereq_command_location', command, cmd_path))
|
|
142
179
|
end
|
|
143
180
|
|
|
144
181
|
class LogParser # :nodoc:
|
|
145
182
|
TIMEOUT = 10
|
|
146
183
|
|
|
147
|
-
attr_reader :url, :account
|
|
184
|
+
attr_reader :url, :account, :timeout
|
|
148
185
|
|
|
149
186
|
def initialize(log_path)
|
|
150
187
|
@log_path = log_path
|
|
@@ -173,7 +210,9 @@ module ShopifyCli
|
|
|
173
210
|
end
|
|
174
211
|
|
|
175
212
|
def parse_account
|
|
176
|
-
|
|
213
|
+
account, timeout, _ = @log.match(/AccountName:([\w\s\d@._\-]*) SessionDuration:([\d]+) PlanName/)&.captures
|
|
214
|
+
@account = account&.empty? ? nil : account
|
|
215
|
+
@timeout = timeout&.empty? ? 0 : timeout.to_i
|
|
177
216
|
end
|
|
178
217
|
|
|
179
218
|
def error
|
data/lib/shopify-cli/version.rb
CHANGED
data/lib/shopify_cli.rb
CHANGED
|
@@ -44,10 +44,6 @@ module ShopifyCli
|
|
|
44
44
|
ROOT = File.expand_path('../..', __FILE__)
|
|
45
45
|
PROJECT_TYPES_DIR = File.join(ROOT, 'lib', 'project_types')
|
|
46
46
|
TEMP_DIR = File.join(ROOT, '.tmp')
|
|
47
|
-
CACHE_DIR = File.join(File.expand_path(ENV.fetch('XDG_CACHE_HOME', '~/.cache')), TOOL_NAME)
|
|
48
|
-
TOOL_CONFIG_PATH = File.join(File.expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config')), TOOL_NAME)
|
|
49
|
-
LOG_FILE = File.join(TOOL_CONFIG_PATH, 'logs', 'log.log')
|
|
50
|
-
DEBUG_LOG_FILE = File.join(TOOL_CONFIG_PATH, 'logs', 'debug.log')
|
|
51
47
|
|
|
52
48
|
# programmer emoji if default install location, else wrench emoji
|
|
53
49
|
EMOJI = ROOT == '/opt/shopify' ? "\u{1f469}\u{200d}\u{1f4bb}" : "\u{1f527}"
|
|
@@ -82,7 +78,7 @@ module ShopifyCli
|
|
|
82
78
|
# ShopifyCli::Config
|
|
83
79
|
autocall(:Config) { CLI::Kit::Config.new(tool_name: TOOL_NAME) }
|
|
84
80
|
# ShopifyCli::Logger
|
|
85
|
-
autocall(:Logger) { CLI::Kit::Logger.new(debug_log_file:
|
|
81
|
+
autocall(:Logger) { CLI::Kit::Logger.new(debug_log_file: ShopifyCli.debug_log_file) }
|
|
86
82
|
# ShopifyCli::Resolver
|
|
87
83
|
autocall(:Resolver) do
|
|
88
84
|
ShopifyCli::Core::HelpResolver.new(
|
|
@@ -93,7 +89,7 @@ module ShopifyCli
|
|
|
93
89
|
# ShopifyCli::ErrorHandler
|
|
94
90
|
autocall(:ErrorHandler) do
|
|
95
91
|
CLI::Kit::ErrorHandler.new(
|
|
96
|
-
log_file: ShopifyCli
|
|
92
|
+
log_file: ShopifyCli.log_file,
|
|
97
93
|
exception_reporter: nil,
|
|
98
94
|
)
|
|
99
95
|
end
|
|
@@ -105,6 +101,7 @@ module ShopifyCli
|
|
|
105
101
|
autoload :Context, 'shopify-cli/context'
|
|
106
102
|
autoload :Core, 'shopify-cli/core'
|
|
107
103
|
autoload :DB, 'shopify-cli/db'
|
|
104
|
+
autoload :Feature, 'shopify-cli/feature'
|
|
108
105
|
autoload :Form, 'shopify-cli/form'
|
|
109
106
|
autoload :Git, 'shopify-cli/git'
|
|
110
107
|
autoload :Helpers, 'shopify-cli/helpers'
|
|
@@ -126,7 +123,37 @@ module ShopifyCli
|
|
|
126
123
|
|
|
127
124
|
require 'shopify-cli/messages/messages'
|
|
128
125
|
Context.load_messages(ShopifyCli::Messages::MESSAGES)
|
|
129
|
-
end
|
|
130
126
|
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
def self.cache_dir
|
|
128
|
+
cache_dir = if ENV.key?('RUNNING_SHOPIFY_CLI_TESTS')
|
|
129
|
+
TEMP_DIR
|
|
130
|
+
elsif ENV['LOCALAPPDATA'].nil?
|
|
131
|
+
File.join(File.expand_path(ENV.fetch('XDG_CACHE_HOME', '~/.cache')), TOOL_NAME)
|
|
132
|
+
else
|
|
133
|
+
File.join(File.expand_path(ENV['LOCALAPPDATA']), TOOL_NAME)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Make sure the cache dir always exists
|
|
137
|
+
@cache_dir_exists ||= FileUtils.mkdir_p(cache_dir)
|
|
138
|
+
|
|
139
|
+
cache_dir
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def self.tool_config_path
|
|
143
|
+
if ENV.key?('RUNNING_SHOPIFY_CLI_TESTS')
|
|
144
|
+
TEMP_DIR
|
|
145
|
+
elsif ENV['APPDATA'].nil?
|
|
146
|
+
File.join(File.expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config')), TOOL_NAME)
|
|
147
|
+
else
|
|
148
|
+
File.join(File.expand_path(ENV['APPDATA']), TOOL_NAME)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.log_file
|
|
153
|
+
File.join(tool_config_path, 'logs', 'log.log')
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.debug_log_file
|
|
157
|
+
File.join(tool_config_path, 'logs', 'debug.log')
|
|
158
|
+
end
|
|
159
|
+
end
|
data/shopify-cli.gemspec
CHANGED
|
@@ -26,7 +26,10 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
# Specify which files should be added to the gem when it is released.
|
|
27
27
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
28
28
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
29
|
-
%x(git ls-files -z).split("\x0").reject
|
|
29
|
+
%x(git ls-files -z).split("\x0").reject do |f|
|
|
30
|
+
f.match(%r{^(test|spec|features|packaging)/}) ||
|
|
31
|
+
f.match(%r{^bin/(update-deps|shopify.bat)$})
|
|
32
|
+
end
|
|
30
33
|
end
|
|
31
34
|
spec.bindir = "bin"
|
|
32
35
|
spec.require_paths = ["lib", "vendor"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1013aa5c5664e7034ca3f02fd2e0513361b07e95 (dirty)
|
|
@@ -51,7 +51,7 @@ module CLI
|
|
|
51
51
|
# 1. rescue Abort or Bug
|
|
52
52
|
# 2. Print a contextualized error message
|
|
53
53
|
# 3. Re-raise AbortSilent or BugSilent respectively.
|
|
54
|
-
GenericAbort = Class.new(Exception)
|
|
54
|
+
GenericAbort = Class.new(Exception) # rubocop:disable Lint/InheritException
|
|
55
55
|
Abort = Class.new(GenericAbort)
|
|
56
56
|
Bug = Class.new(GenericAbort)
|
|
57
57
|
BugSilent = Class.new(GenericAbort)
|
|
@@ -22,11 +22,11 @@ module CLI
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def handle_exception(error)
|
|
25
|
-
if notify_with = exception_for_submission(error)
|
|
25
|
+
if (notify_with = exception_for_submission(error))
|
|
26
26
|
logs = begin
|
|
27
27
|
File.read(@log_file)
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
rescue => e
|
|
29
|
+
"(#{e.class}: #{e.message})"
|
|
30
30
|
end
|
|
31
31
|
exception_reporter.report(notify_with, logs)
|
|
32
32
|
end
|
|
@@ -56,7 +56,7 @@ module CLI
|
|
|
56
56
|
# if it was `exit 30`, translate the exit code to 1, and submit nothing.
|
|
57
57
|
# 30 is used to signal normal failures that are not indicative of bugs.
|
|
58
58
|
# However, users should see it presented as 1.
|
|
59
|
-
exit
|
|
59
|
+
exit(1)
|
|
60
60
|
else
|
|
61
61
|
# A weird termination status happened. `error.exception "message"` will maintain backtrace
|
|
62
62
|
# but allow us to set a message
|
|
@@ -83,7 +83,7 @@ module CLI
|
|
|
83
83
|
|
|
84
84
|
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
|
85
85
|
rescue Interrupt
|
|
86
|
-
|
|
86
|
+
stderr_puts_message('Interrupt')
|
|
87
87
|
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
|
88
88
|
rescue Errno::ENOSPC
|
|
89
89
|
message = if @tool_name
|
|
@@ -91,10 +91,16 @@ module CLI
|
|
|
91
91
|
else
|
|
92
92
|
"Your disk is full - free space is required to operate"
|
|
93
93
|
end
|
|
94
|
-
|
|
94
|
+
stderr_puts_message(message)
|
|
95
95
|
CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
def stderr_puts_message(message)
|
|
99
|
+
$stderr.puts(format_error_message(message))
|
|
100
|
+
rescue Errno::EPIPE
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
98
104
|
def exception_reporter
|
|
99
105
|
if @exception_reporter_or_proc.respond_to?(:report)
|
|
100
106
|
@exception_reporter_or_proc
|
|
@@ -13,19 +13,17 @@ module CLI
|
|
|
13
13
|
def call(command, command_name, args)
|
|
14
14
|
with_traps do
|
|
15
15
|
with_logging do |id|
|
|
16
|
+
command.call(args, command_name)
|
|
17
|
+
rescue => e
|
|
16
18
|
begin
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Outputting to stderr is best-effort. Avoid raising another error when outputting debug info so that
|
|
24
|
-
# we can detect and log the original error, which may even be the source of this error.
|
|
25
|
-
nil
|
|
26
|
-
end
|
|
27
|
-
raise e
|
|
19
|
+
$stderr.puts "This command ran with ID: #{id}"
|
|
20
|
+
$stderr.puts "Please include this information in any issues/report along with relevant logs"
|
|
21
|
+
rescue SystemCallError
|
|
22
|
+
# Outputting to stderr is best-effort. Avoid raising another error when outputting debug info so that
|
|
23
|
+
# we can detect and log the original error, which may even be the source of this error.
|
|
24
|
+
nil
|
|
28
25
|
end
|
|
26
|
+
raise e
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
end
|
|
@@ -10,9 +10,10 @@ module CLI
|
|
|
10
10
|
# Constructor for CLI::Kit::Logger
|
|
11
11
|
#
|
|
12
12
|
# @param debug_log_file [String] path to the file where debug logs should be stored
|
|
13
|
-
def initialize(debug_log_file:)
|
|
13
|
+
def initialize(debug_log_file:, env_debug_name: 'DEBUG')
|
|
14
14
|
FileUtils.mkpath(File.dirname(debug_log_file))
|
|
15
15
|
@debug_logger = ::Logger.new(debug_log_file, MAX_NUM_LOGS, MAX_LOG_SIZE)
|
|
16
|
+
@env_debug_name = env_debug_name
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# Functionally equivalent to Logger#info
|
|
@@ -60,7 +61,7 @@ module CLI
|
|
|
60
61
|
#
|
|
61
62
|
# @param msg [String] the message to log
|
|
62
63
|
def debug(msg)
|
|
63
|
-
$stdout.puts CLI::UI.fmt(msg) if
|
|
64
|
+
$stdout.puts CLI::UI.fmt(msg) if is_debug?
|
|
64
65
|
@debug_logger.debug(format_debug(msg))
|
|
65
66
|
end
|
|
66
67
|
|
|
@@ -71,6 +72,11 @@ module CLI
|
|
|
71
72
|
return msg unless CLI::UI::StdoutRouter.current_id
|
|
72
73
|
"[#{CLI::UI::StdoutRouter.current_id[:id]}] #{msg}"
|
|
73
74
|
end
|
|
75
|
+
|
|
76
|
+
def is_debug?
|
|
77
|
+
val = ENV[@env_debug_name]
|
|
78
|
+
val && val != '0' && val != ''
|
|
79
|
+
end
|
|
74
80
|
end
|
|
75
81
|
end
|
|
76
82
|
end
|
|
@@ -10,7 +10,7 @@ module CLI
|
|
|
10
10
|
def assert_all_commands_run(should_raise: true)
|
|
11
11
|
errors = CLI::Kit::System.error_message
|
|
12
12
|
CLI::Kit::System.reset!
|
|
13
|
-
assert
|
|
13
|
+
assert(false, errors) if should_raise && !errors.nil?
|
|
14
14
|
errors
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -196,22 +196,22 @@ module CLI
|
|
|
196
196
|
|
|
197
197
|
unless errors[:unexpected].empty?
|
|
198
198
|
final_error << CLI::UI.fmt(<<~EOF)
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
{{bold:Unexpected command invocations:}}
|
|
200
|
+
{{command:#{errors[:unexpected].join("\n")}}}
|
|
201
201
|
EOF
|
|
202
202
|
end
|
|
203
203
|
|
|
204
204
|
unless errors[:not_run].empty?
|
|
205
205
|
final_error << CLI::UI.fmt(<<~EOF)
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
{{bold:Expected commands were not run:}}
|
|
207
|
+
{{command:#{errors[:not_run].join("\n")}}}
|
|
208
208
|
EOF
|
|
209
209
|
end
|
|
210
210
|
|
|
211
211
|
unless errors[:other].empty?
|
|
212
212
|
final_error << CLI::UI.fmt(<<~EOF)
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
{{bold:Commands were not run as expected:}}
|
|
214
|
+
#{errors[:other].map { |cmd, msg| "{{command:#{cmd}}}\n#{msg}" }.join("\n\n")}
|
|
215
215
|
EOF
|
|
216
216
|
end
|
|
217
217
|
|
|
@@ -19,7 +19,7 @@ module CLI
|
|
|
19
19
|
#
|
|
20
20
|
def sudo_reason(msg)
|
|
21
21
|
# See if sudo has a cached password
|
|
22
|
-
|
|
22
|
+
%x(env SUDO_ASKPASS=/usr/bin/false sudo -A true)
|
|
23
23
|
return if $CHILD_STATUS.success?
|
|
24
24
|
CLI::UI.with_frame_color(:blue) do
|
|
25
25
|
puts(CLI::UI.fmt("{{i}} #{msg}"))
|
|
@@ -90,6 +90,18 @@ module CLI
|
|
|
90
90
|
delegate_open3(*a, sudo: sudo, env: env, method: :capture3, **kwargs)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
def popen2(*a, sudo: false, env: ENV, **kwargs, &block)
|
|
94
|
+
delegate_open3(*a, sudo: sudo, env: env, method: :popen2, **kwargs, &block)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def popen2e(*a, sudo: false, env: ENV, **kwargs)
|
|
98
|
+
delegate_open3(*a, sudo: sudo, env: env, method: :popen2e, **kwargs, &block)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def popen3(*a, sudo: false, env: ENV, **kwargs)
|
|
102
|
+
delegate_open3(*a, sudo: sudo, env: env, method: :popen3, **kwargs, &block)
|
|
103
|
+
end
|
|
104
|
+
|
|
93
105
|
# Execute a command in the user's environment
|
|
94
106
|
# Outputs result of the command without capturing it
|
|
95
107
|
#
|
|
@@ -130,13 +142,11 @@ module CLI
|
|
|
130
142
|
|
|
131
143
|
readers, = IO.select(ios)
|
|
132
144
|
readers.each do |io|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
io.close
|
|
139
|
-
end
|
|
145
|
+
data, trailing = split_partial_characters(io.readpartial(4096))
|
|
146
|
+
handlers[io].call(previous_trailing[io] + data)
|
|
147
|
+
previous_trailing[io] = trailing
|
|
148
|
+
rescue IOError
|
|
149
|
+
io.close
|
|
140
150
|
end
|
|
141
151
|
end
|
|
142
152
|
|
|
@@ -163,6 +173,14 @@ module CLI
|
|
|
163
173
|
[data.byteslice(0...partial_character_index), data.byteslice(partial_character_index..-1)]
|
|
164
174
|
end
|
|
165
175
|
|
|
176
|
+
def os
|
|
177
|
+
return :mac if /darwin/.match(RUBY_PLATFORM)
|
|
178
|
+
return :linux if /linux/.match(RUBY_PLATFORM)
|
|
179
|
+
return :windows if /mingw32/.match(RUBY_PLATFORM)
|
|
180
|
+
|
|
181
|
+
raise "Could not determine OS from platform #{RUBY_PLATFORM}"
|
|
182
|
+
end
|
|
183
|
+
|
|
166
184
|
private
|
|
167
185
|
|
|
168
186
|
def apply_sudo(*a, sudo)
|
|
@@ -171,9 +189,9 @@ module CLI
|
|
|
171
189
|
a
|
|
172
190
|
end
|
|
173
191
|
|
|
174
|
-
def delegate_open3(*a, sudo: raise, env: raise, method: raise, **kwargs)
|
|
192
|
+
def delegate_open3(*a, sudo: raise, env: raise, method: raise, **kwargs, &block)
|
|
175
193
|
a = apply_sudo(*a, sudo)
|
|
176
|
-
Open3.send(method, env, *resolve_path(a, env), **kwargs)
|
|
194
|
+
Open3.send(method, env, *resolve_path(a, env), **kwargs, &block)
|
|
177
195
|
rescue Errno::EINTR
|
|
178
196
|
raise(Errno::EINTR, "command interrupted: #{a.join(' ')}")
|
|
179
197
|
end
|
|
@@ -189,17 +207,30 @@ module CLI
|
|
|
189
207
|
# See https://github.com/Shopify/dev/pull/625 for more details.
|
|
190
208
|
def resolve_path(a, env)
|
|
191
209
|
# If only one argument was provided, make sure it's interpreted by a shell.
|
|
192
|
-
|
|
210
|
+
if a.size == 1
|
|
211
|
+
if os == :windows
|
|
212
|
+
return ["break && " + a[0]]
|
|
213
|
+
else
|
|
214
|
+
return ["true ; " + a[0]]
|
|
215
|
+
end
|
|
216
|
+
end
|
|
193
217
|
return a if a.first.include?('/')
|
|
194
218
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
219
|
+
item = which(a.first, env)
|
|
220
|
+
a[0] = item if item
|
|
221
|
+
a
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def which(cmd, env)
|
|
225
|
+
exts = os == :windows ? env.fetch('PATHEXT').split(';') : ['']
|
|
226
|
+
env.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |path|
|
|
227
|
+
exts.each do |ext|
|
|
228
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
|
229
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
|
230
|
+
end
|
|
199
231
|
end
|
|
200
232
|
|
|
201
|
-
|
|
202
|
-
a
|
|
233
|
+
nil
|
|
203
234
|
end
|
|
204
235
|
end
|
|
205
236
|
end
|