lhj-tools 0.1.5 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lhj/action/sh_helper.rb +138 -0
- data/lib/lhj/command/config/info.rb +47 -0
- data/lib/lhj/command/config.rb +11 -0
- data/lib/lhj/command/file_path.rb +20 -0
- data/lib/lhj/command/head_import.rb +19 -3
- data/lib/lhj/command/http.rb +14 -0
- data/lib/lhj/command/init.rb +4 -4
- data/lib/lhj/command/local/fetch.rb +1 -1
- data/lib/lhj/command/local/filter.rb +1 -1
- data/lib/lhj/command/local/local.rb +1 -1
- data/lib/lhj/command/local/local_upload.rb +1 -1
- data/lib/lhj/command/local/micro_service.rb +1 -1
- data/lib/lhj/command/oss/del.rb +18 -5
- data/lib/lhj/command/oss/list.rb +1 -1
- data/lib/lhj/command/oss/upload.rb +7 -3
- data/lib/lhj/command/refactor_rename.rb +1 -1
- data/lib/lhj/command/rename_image.rb +1 -1
- data/lib/lhj/command/sync_pod_repo.rb +149 -0
- data/lib/lhj/command/trans.rb +1 -1
- data/lib/lhj/command/yapi.rb +15 -14
- data/lib/lhj/command.rb +25 -6
- data/lib/lhj/tools/version.rb +1 -1
- data/lib/lhj/tools.rb +1 -0
- data/lib/lhj/tree/hash_walker.rb +1 -1
- data/lib/lhj/tree/path_walker.rb +1 -2
- data/lib/lhj/tree/tree.rb +5 -5
- data/lib/lhj/ui/errors/lhj_common_error.rb +19 -0
- data/lib/lhj/ui/errors/lhj_crash.rb +11 -0
- data/lib/lhj/ui/errors/lhj_error.rb +25 -0
- data/lib/lhj/ui/errors/lhj_exception.rb +19 -0
- data/lib/lhj/ui/errors/lhj_shell_error.rb +11 -0
- data/lib/lhj/ui/errors.rb +1 -0
- data/lib/lhj/ui/implementations/shell.rb +148 -0
- data/lib/lhj/ui/interface.rb +205 -0
- data/lib/lhj/ui/ui.rb +26 -0
- metadata +51 -2
data/lib/lhj/command/yapi.rb
CHANGED
@@ -5,6 +5,7 @@ require 'yaml'
|
|
5
5
|
|
6
6
|
module Lhj
|
7
7
|
class Command
|
8
|
+
# generate model from yapi
|
8
9
|
class Yapi < Command
|
9
10
|
self.summary = '通过yapi接口生成请求'
|
10
11
|
self.description = '更新 ~/.lhj/yapi.yml 文件配置后执行`lhj api`生成接口模型'
|
@@ -34,7 +35,7 @@ module Lhj
|
|
34
35
|
super
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
+
def handle
|
38
39
|
load_config
|
39
40
|
fetch_model
|
40
41
|
print_methods
|
@@ -49,13 +50,13 @@ module Lhj
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def puts_h(str)
|
52
|
-
puts str
|
53
|
+
puts str.magenta
|
53
54
|
@h_file_array ||= []
|
54
55
|
@h_file_array << str
|
55
56
|
end
|
56
57
|
|
57
58
|
def puts_m(str)
|
58
|
-
puts str
|
59
|
+
puts str.blue
|
59
60
|
@m_file_array ||= []
|
60
61
|
@m_file_array << str
|
61
62
|
end
|
@@ -65,9 +66,9 @@ module Lhj
|
|
65
66
|
file_name = gen_model_name('')
|
66
67
|
h_file = File.join('.', "#{file_name}.h")
|
67
68
|
m_file = File.join('.', "#{file_name}.m")
|
68
|
-
File.write(h_file, @h_file_array.join("\n")) if @h_file_array.count
|
69
|
-
File.write(m_file, @m_file_array.join("\n")) if @m_file_array.count
|
70
|
-
puts "\n\n生成文件成功!所在路径:\n#{File.expand_path(h_file)} \n#{File.expand_path(m_file)}"
|
69
|
+
File.write(h_file, @h_file_array.join("\n")) if @h_file_array.count.positive?
|
70
|
+
File.write(m_file, @m_file_array.join("\n")) if @m_file_array.count.positive?
|
71
|
+
puts "\n\n生成文件成功!所在路径:\n#{File.expand_path(h_file)} \n#{File.expand_path(m_file)}".green
|
71
72
|
end
|
72
73
|
|
73
74
|
def url_str
|
@@ -78,7 +79,7 @@ module Lhj
|
|
78
79
|
yml = File.join(Lhj::Config.instance.home_dir, 'yapi.yml')
|
79
80
|
config = YAML.load_file(yml)
|
80
81
|
config.each do |k, v|
|
81
|
-
@http_headers << "#{k}=#{v}" if
|
82
|
+
@http_headers << "#{k}=#{v}" if k.eql?('__wpkreporterwid_') || k.eql?('_yapi_token') || k.eql?('_yapi_uid')
|
82
83
|
end
|
83
84
|
@http_url = config['url']
|
84
85
|
@config_id = config['id']
|
@@ -107,27 +108,27 @@ module Lhj
|
|
107
108
|
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
108
109
|
http.request(req)
|
109
110
|
end
|
110
|
-
puts res.body
|
111
|
+
puts res.body unless res.body['errcode'].to_i.zero?
|
111
112
|
JSON.parse(res.body)
|
112
113
|
end
|
113
114
|
|
114
115
|
def fetch_model
|
115
116
|
res_json = req_model
|
116
117
|
begin
|
117
|
-
puts "\n<===============打印返回数据模型-Begin=====================>\n"
|
118
|
+
puts "\n<===============打印返回数据模型-Begin=====================>\n".green
|
118
119
|
fetch_res_boy(res_json)
|
119
120
|
print_models
|
120
121
|
print_models_implementation
|
121
|
-
puts "\n<===============打印返回数据模型-End=====================>\n"
|
122
|
+
puts "\n<===============打印返回数据模型-End=====================>\n".green
|
122
123
|
end
|
123
124
|
begin
|
124
|
-
puts "\n<===============打印请求模型-Begin=====================>\n"
|
125
|
+
puts "\n<===============打印请求模型-Begin=====================>\n".green
|
125
126
|
@models = []
|
126
127
|
@model_names = []
|
127
128
|
fetch_req_body(res_json)
|
128
129
|
print_models
|
129
130
|
print_models_implementation
|
130
|
-
puts "\n<===============打印请求模型-End=====================>\n"
|
131
|
+
puts "\n<===============打印请求模型-End=====================>\n".green
|
131
132
|
end
|
132
133
|
end
|
133
134
|
|
@@ -221,7 +222,7 @@ module Lhj
|
|
221
222
|
@models.each do |model|
|
222
223
|
puts_m "@implementation #{model[:name]}"
|
223
224
|
str = model[:properties].filter { |p| p[:type].eql?('array') && !p[:type_name].eql?('NSString') }.map { |p| "@\"#{p[:key]}\": #{p[:type_name]}.class" }.join(', ')
|
224
|
-
if str && str.length
|
225
|
+
if str && str.length.positive?
|
225
226
|
puts_m '+(NSDictionary *)modelContainerPropertyGenericClass {'
|
226
227
|
puts_m " return @{#{str}};"
|
227
228
|
puts_m '}'
|
@@ -268,7 +269,7 @@ module Lhj
|
|
268
269
|
end
|
269
270
|
|
270
271
|
def print_methods
|
271
|
-
puts "\n<===============方法调用=====================>\n"
|
272
|
+
puts "\n<===============方法调用=====================>\n".green
|
272
273
|
puts_m '/**'
|
273
274
|
puts_m " * #{@data_json['title']} -- #{@data_json['username']}"
|
274
275
|
puts_m ' */'
|
data/lib/lhj/command.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'claide'
|
2
2
|
require "tty-spinner"
|
3
|
+
require 'lhj/action/sh_helper'
|
4
|
+
require 'lhj/ui/ui'
|
3
5
|
|
4
6
|
module Lhj
|
5
7
|
# command plugin
|
6
8
|
class Command < CLAide::Command
|
7
9
|
require 'lhj/command/init'
|
10
|
+
require 'lhj/command/config'
|
8
11
|
require 'lhj/command/head_import'
|
9
12
|
require 'lhj/command/refactor_rename'
|
10
13
|
require 'lhj/command/local/fetch'
|
@@ -20,20 +23,36 @@ module Lhj
|
|
20
23
|
require 'lhj/command/rename_image'
|
21
24
|
require 'lhj/command/trans'
|
22
25
|
require 'lhj/command/yapi'
|
26
|
+
require 'lhj/command/file_path'
|
27
|
+
require 'lhj/command/http'
|
28
|
+
require 'lhj/command/sync_pod_repo'
|
23
29
|
|
24
30
|
self.abstract_command = true
|
25
31
|
self.command = 'lhj'
|
26
32
|
|
27
|
-
def spinner
|
28
|
-
@spinner ||= TTY::Spinner.new('[:spinner]正在处理...', format: :dots)
|
29
|
-
end
|
30
|
-
|
31
33
|
def auto_spin
|
32
|
-
|
34
|
+
puts "开始处理...\n".green
|
35
|
+
# @spinner.auto_spin
|
33
36
|
end
|
34
37
|
|
35
38
|
def stop
|
36
|
-
|
39
|
+
puts '处理完成'.green
|
40
|
+
# @spinner.success('Done!')
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(argv)
|
44
|
+
super(argv)
|
45
|
+
@spinner = TTY::Spinner.new('...', output: $stdout, format: :dots, clear: true)
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
auto_spin
|
50
|
+
handle
|
51
|
+
stop
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle
|
55
|
+
raise 'A subclass should override the `Lhj::Command#run` method'
|
37
56
|
end
|
38
57
|
|
39
58
|
end
|
data/lib/lhj/tools/version.rb
CHANGED
data/lib/lhj/tools.rb
CHANGED
data/lib/lhj/tree/hash_walker.rb
CHANGED
data/lib/lhj/tree/path_walker.rb
CHANGED
data/lib/lhj/tree/tree.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
require_relative 'node'
|
4
|
+
require_relative 'directory_renderer'
|
5
|
+
require_relative 'number_renderer'
|
6
|
+
require_relative 'hash_walker'
|
7
|
+
require_relative 'path_walker'
|
8
8
|
|
9
9
|
module Lhj
|
10
10
|
class Tree
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'lhj_exception'
|
2
|
+
|
3
|
+
module Lhj
|
4
|
+
class Interface
|
5
|
+
# Super class for exception types that we do not want to record
|
6
|
+
# explicitly as crashes or user errors
|
7
|
+
class LhjCommonException < LhjException; end
|
8
|
+
|
9
|
+
# Raised when there is a build failure in xcodebuild
|
10
|
+
class LhjBuildFailure < LhjCommonException; end
|
11
|
+
|
12
|
+
# Raised when a test fails when being run by tools such as scan or snapshot
|
13
|
+
class LhjTestFailure < LhjCommonException; end
|
14
|
+
|
15
|
+
# Raise this type of exception when a failure caused by a third party
|
16
|
+
# dependency (i.e. xcodebuild, gradle, slather) happens.
|
17
|
+
class LhjDependencyCausedException < LhjCommonException; end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'lhj_exception'
|
2
|
+
|
3
|
+
module Lhj
|
4
|
+
class Interface
|
5
|
+
class LhjError < LhjException
|
6
|
+
attr_reader :show_github_issues
|
7
|
+
attr_reader :error_info
|
8
|
+
|
9
|
+
def initialize(show_github_issues: false, error_info: nil)
|
10
|
+
@show_github_issues = show_github_issues
|
11
|
+
@error_info = error_info
|
12
|
+
end
|
13
|
+
|
14
|
+
def prefix
|
15
|
+
'[USER_ERROR]'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Exception
|
22
|
+
# def fastlane_should_report_metrics?
|
23
|
+
# return false
|
24
|
+
# end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Lhj
|
2
|
+
class Interface
|
3
|
+
class LhjException < StandardError
|
4
|
+
def prefix
|
5
|
+
'[LHJ_EXCEPTION]'
|
6
|
+
end
|
7
|
+
|
8
|
+
def caused_by_calling_ui_method?(method_name: nil)
|
9
|
+
return false if backtrace.nil? || backtrace[0].nil? || method_name.nil?
|
10
|
+
first_frame = backtrace[0]
|
11
|
+
if first_frame.include?(method_name) && first_frame.include?('interface.rb')
|
12
|
+
true
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + "/errors/*.rb"].each { |f| require_relative f }
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require_relative '../interface'
|
2
|
+
|
3
|
+
module Lhj
|
4
|
+
# Shell is the terminal output of things
|
5
|
+
# For documentation for each of the methods open `interface.rb`
|
6
|
+
class Shell < Interface
|
7
|
+
|
8
|
+
def log
|
9
|
+
return @log if @log
|
10
|
+
|
11
|
+
$stdout.sync = true
|
12
|
+
|
13
|
+
# if !ENV.key?('DEBUG')
|
14
|
+
# $stdout.puts("Logging disabled while running tests. Force them by setting the DEBUG environment variable")
|
15
|
+
# @log ||= Logger.new(nil) # don't show any logs when running tests
|
16
|
+
# else
|
17
|
+
@log ||= Logger.new($stdout)
|
18
|
+
# end
|
19
|
+
|
20
|
+
@log.formatter = proc do |severity, datetime, progname, msg|
|
21
|
+
"#{format_string(datetime, severity)}#{msg}\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
@log
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_string(datetime = Time.now, severity = "")
|
28
|
+
return "[#{datetime.strftime('%H:%M:%S')}]: "
|
29
|
+
end
|
30
|
+
|
31
|
+
#####################################################
|
32
|
+
# @!group Messaging: show text to the user
|
33
|
+
#####################################################
|
34
|
+
|
35
|
+
def error(message)
|
36
|
+
log.error(message.to_s.red)
|
37
|
+
end
|
38
|
+
|
39
|
+
def important(message)
|
40
|
+
log.warn(message.to_s.yellow)
|
41
|
+
end
|
42
|
+
|
43
|
+
def success(message)
|
44
|
+
log.info(message.to_s.green)
|
45
|
+
end
|
46
|
+
|
47
|
+
def message(message)
|
48
|
+
log.info(message.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def deprecated(message)
|
52
|
+
log.error(message.to_s.deprecated)
|
53
|
+
end
|
54
|
+
|
55
|
+
def command(message)
|
56
|
+
log.info("$ #{message}".cyan)
|
57
|
+
end
|
58
|
+
|
59
|
+
def command_output(message)
|
60
|
+
actual = (encode_as_utf_8_if_possible(message).split("\r").last || "") # as clearing the line will remove the `>` and the time stamp
|
61
|
+
actual.split("\n").each do |msg|
|
62
|
+
prefix = msg.include?("▸") ? "" : "▸ "
|
63
|
+
log.info(prefix + "" + msg.magenta)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def verbose(message)
|
68
|
+
log.debug(message.to_s)
|
69
|
+
end
|
70
|
+
|
71
|
+
def header(message)
|
72
|
+
success(message)
|
73
|
+
end
|
74
|
+
|
75
|
+
def content_error(content, error_line)
|
76
|
+
error_line = error_line.to_i
|
77
|
+
return unless error_line > 0
|
78
|
+
|
79
|
+
contents = content.split(/\r?\n/).map(&:chomp)
|
80
|
+
|
81
|
+
start_line = error_line - 2 < 1 ? 1 : error_line - 2
|
82
|
+
end_line = error_line + 2 < contents.length ? error_line + 2 : contents.length
|
83
|
+
|
84
|
+
Range.new(start_line, end_line).each do |line|
|
85
|
+
str = line == error_line ? " => " : " "
|
86
|
+
str << line.to_s.rjust(Math.log10(end_line) + 1)
|
87
|
+
str << ":\t#{contents[line - 1]}"
|
88
|
+
error(str)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#####################################################
|
93
|
+
# @!group Errors: Inputs
|
94
|
+
#####################################################
|
95
|
+
|
96
|
+
def interactive?
|
97
|
+
interactive = true
|
98
|
+
interactive = false if $stdout.isatty == false
|
99
|
+
interactive = false if Helper.ci?
|
100
|
+
return interactive
|
101
|
+
end
|
102
|
+
|
103
|
+
def input(message)
|
104
|
+
verify_interactive!(message)
|
105
|
+
ask("#{format_string}#{message.to_s.yellow}").to_s.strip
|
106
|
+
end
|
107
|
+
|
108
|
+
def confirm(message)
|
109
|
+
verify_interactive!(message)
|
110
|
+
agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
|
111
|
+
end
|
112
|
+
|
113
|
+
def select(message, options)
|
114
|
+
verify_interactive!(message)
|
115
|
+
|
116
|
+
important(message)
|
117
|
+
choose(*options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def password(message)
|
121
|
+
verify_interactive!(message)
|
122
|
+
|
123
|
+
ask("#{format_string}#{message.to_s.yellow}") do |q|
|
124
|
+
q.whitespace = :chomp
|
125
|
+
q.echo = "*"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def encode_as_utf_8_if_possible(message)
|
132
|
+
return message if message.valid_encoding?
|
133
|
+
|
134
|
+
# genstrings outputs UTF-16, so we should try to use this encoding if it turns out to be valid
|
135
|
+
test_message = message.dup
|
136
|
+
return message.encode(Encoding::UTF_8, Encoding::UTF_16) if test_message.force_encoding(Encoding::UTF_16).valid_encoding?
|
137
|
+
|
138
|
+
# replace any invalid with empty string
|
139
|
+
message.encode(Encoding::UTF_8, invalid: :replace)
|
140
|
+
end
|
141
|
+
|
142
|
+
def verify_interactive!(message)
|
143
|
+
return if interactive?
|
144
|
+
important(message)
|
145
|
+
crash!("Could not retrieve response as fastlane runs in non-interactive mode")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require_relative 'errors'
|
2
|
+
|
3
|
+
module Lhj
|
4
|
+
# Abstract super class
|
5
|
+
class Interface
|
6
|
+
#####################################################
|
7
|
+
# @!group Messaging: show text to the user
|
8
|
+
#####################################################
|
9
|
+
|
10
|
+
# Level Error: Can be used to show additional error
|
11
|
+
# information before actually raising an exception
|
12
|
+
# or can be used to just show an error from which
|
13
|
+
# fastlane can recover (much magic)
|
14
|
+
#
|
15
|
+
# By default those messages are shown in red
|
16
|
+
def error(_message)
|
17
|
+
not_implemented(__method__)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Level Important: Can be used to show warnings to the user
|
21
|
+
# not necessarily negative, but something the user should
|
22
|
+
# be aware of.
|
23
|
+
#
|
24
|
+
# By default those messages are shown in yellow
|
25
|
+
def important(_message)
|
26
|
+
not_implemented(__method__)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Level Success: Show that something was successful
|
30
|
+
#
|
31
|
+
# By default those messages are shown in green
|
32
|
+
def success(_message)
|
33
|
+
not_implemented(__method__)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Level Message: Show a neutral message to the user
|
37
|
+
#
|
38
|
+
# By default those messages shown in white/black
|
39
|
+
def message(_message)
|
40
|
+
not_implemented(__method__)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Level Deprecated: Show that a particular function is deprecated
|
44
|
+
#
|
45
|
+
# By default those messages shown in strong blue
|
46
|
+
def deprecated(_message)
|
47
|
+
not_implemented(__method__)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Level Command: Print out a terminal command that is being
|
51
|
+
# executed.
|
52
|
+
#
|
53
|
+
# By default those messages shown in cyan
|
54
|
+
def command(_message)
|
55
|
+
not_implemented(__method__)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Level Command Output: Print the output of a command with
|
59
|
+
# this method
|
60
|
+
#
|
61
|
+
# By default those messages shown in magenta
|
62
|
+
def command_output(_message)
|
63
|
+
not_implemented(__method__)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Level Verbose: Print out additional information for the
|
67
|
+
# users that are interested. Will only be printed when
|
68
|
+
# FastlaneCore::Globals.verbose? = true
|
69
|
+
#
|
70
|
+
# By default those messages are shown in white
|
71
|
+
def verbose(_message)
|
72
|
+
not_implemented(__method__)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Print a header = a text in a box
|
76
|
+
# use this if this message is really important
|
77
|
+
def header(_message)
|
78
|
+
not_implemented(__method__)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Print lines of content around specific line where
|
82
|
+
# failed to parse.
|
83
|
+
#
|
84
|
+
# This message will be shown as error
|
85
|
+
def content_error(content, error_line)
|
86
|
+
not_implemented(__method__)
|
87
|
+
end
|
88
|
+
|
89
|
+
#####################################################
|
90
|
+
# @!group Errors: Inputs
|
91
|
+
#####################################################
|
92
|
+
|
93
|
+
# Is is possible to ask the user questions?
|
94
|
+
def interactive?
|
95
|
+
not_implemented(__method__)
|
96
|
+
end
|
97
|
+
|
98
|
+
# get a standard text input (single line)
|
99
|
+
def input(_message)
|
100
|
+
not_implemented(__method__)
|
101
|
+
end
|
102
|
+
|
103
|
+
# A simple yes or no question
|
104
|
+
def confirm(_message)
|
105
|
+
not_implemented(__method__)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Let the user select one out of x items
|
109
|
+
# return value is the value of the option the user chose
|
110
|
+
def select(_message, _options)
|
111
|
+
not_implemented(__method__)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Password input for the user, text field shouldn't show
|
115
|
+
# plain text
|
116
|
+
def password(_message)
|
117
|
+
not_implemented(__method__)
|
118
|
+
end
|
119
|
+
|
120
|
+
#####################################################
|
121
|
+
# @!group Abort helper methods
|
122
|
+
#####################################################
|
123
|
+
|
124
|
+
# Pass an exception to this method to exit the program
|
125
|
+
# using the given exception
|
126
|
+
# Use this method instead of user_error! if this error is
|
127
|
+
# unexpected, e.g. an invalid server response that shouldn't happen
|
128
|
+
def crash!(exception)
|
129
|
+
raise LhjCrash.new, exception.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
# Use this method to exit the program because of an user error
|
133
|
+
# e.g. app doesn't exist on the given Developer Account
|
134
|
+
# or invalid user credentials
|
135
|
+
# or scan tests fail
|
136
|
+
# This will show the error message, but doesn't show the full
|
137
|
+
# stack trace
|
138
|
+
# Basically this should be used when you actively catch the error
|
139
|
+
# and want to show a nice error message to the user
|
140
|
+
def user_error!(error_message, options = {})
|
141
|
+
raise LhjError.new(show_github_issues: options[:show_github_issues], error_info: options[:error_info]), error_message.to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
# Use this method to exit the program because of a shell command
|
145
|
+
# failure -- the command returned a non-zero response. This does
|
146
|
+
# not specify the nature of the error. The error might be from a
|
147
|
+
# programming error, a user error, or an expected error because
|
148
|
+
# the user of the Fastfile doesn't have their environment set up
|
149
|
+
# properly. Because of this, when these errors occur, it means
|
150
|
+
# that the caller of the shell command did not adequate error
|
151
|
+
# handling and the caller error handling should be improved.
|
152
|
+
def shell_error!(error_message, options = {})
|
153
|
+
raise LhjShellError.new(options), error_message.to_s
|
154
|
+
end
|
155
|
+
|
156
|
+
# Use this method to exit the program because of a build failure
|
157
|
+
# that's caused by the source code of the user. Example for this
|
158
|
+
# is that gym will fail when the code doesn't compile or because
|
159
|
+
# settings for the project are incorrect.
|
160
|
+
# By using this method we'll have more accurate results about
|
161
|
+
# fastlane failures
|
162
|
+
def build_failure!(error_message, options = {})
|
163
|
+
raise LhjBuildFailure.new(options), error_message.to_s
|
164
|
+
end
|
165
|
+
|
166
|
+
# Use this method to exit the program because of a test failure
|
167
|
+
# that's caused by the source code of the user. Example for this
|
168
|
+
# is that scan will fail when the tests fail.
|
169
|
+
# By using this method we'll have more accurate results about
|
170
|
+
# fastlane failures
|
171
|
+
def test_failure!(error_message)
|
172
|
+
raise LhjTestFailure.new, error_message
|
173
|
+
end
|
174
|
+
|
175
|
+
# Use this method to exit the program because of terminal state
|
176
|
+
# that is neither the fault of fastlane, nor a problem with the
|
177
|
+
# user's input. Using this method instead of user_error! will
|
178
|
+
# avoid tracking this outcome as a fastlane failure.
|
179
|
+
#
|
180
|
+
# e.g. tests ran successfully, but no screenshots were found
|
181
|
+
#
|
182
|
+
# This will show the message, but hide the full stack trace.
|
183
|
+
def abort_with_message!(message)
|
184
|
+
raise LhjCommonException.new, message
|
185
|
+
end
|
186
|
+
|
187
|
+
#####################################################
|
188
|
+
# @!group Helpers
|
189
|
+
#####################################################
|
190
|
+
def not_implemented(method_name)
|
191
|
+
require_relative 'ui'
|
192
|
+
UI.user_error!("Current UI '#{self}' doesn't support method '#{method_name}'")
|
193
|
+
end
|
194
|
+
|
195
|
+
def to_s
|
196
|
+
self.class.name.split('::').last
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class String
|
202
|
+
def deprecated
|
203
|
+
self.bold.blue
|
204
|
+
end
|
205
|
+
end
|
data/lib/lhj/ui/ui.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Lhj
|
2
|
+
class UI
|
3
|
+
class << self
|
4
|
+
attr_accessor(:ui_object)
|
5
|
+
|
6
|
+
def ui_object
|
7
|
+
require_relative 'implementations/shell'
|
8
|
+
@ui_object ||= Shell.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method_sym, *args, &_block)
|
12
|
+
# not using `responds` because we don't care about methods like .to_s and so on
|
13
|
+
require_relative 'interface'
|
14
|
+
interface_methods = Lhj::Interface.instance_methods - Object.instance_methods
|
15
|
+
UI.user_error!("Unknown method '#{method_sym}', supported #{interface_methods}") unless interface_methods.include?(method_sym)
|
16
|
+
|
17
|
+
self.ui_object.send(method_sym, *args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Import all available implementations
|
24
|
+
Dir[File.dirname(__FILE__) + '/implementations/*.rb'].each do |file|
|
25
|
+
require_relative file
|
26
|
+
end
|