pindo 5.13.1 → 5.13.2
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/lib/pindo/base/git_handler.rb +692 -0
- data/lib/pindo/command/android/autobuild.rb +2 -2
- data/lib/pindo/command/appstore/adhocbuild.rb +258 -311
- data/lib/pindo/command/appstore/autobuild.rb +203 -0
- data/lib/pindo/command/appstore/autoresign.rb +35 -17
- data/lib/pindo/command/appstore/bundleid.rb +120 -0
- data/lib/pindo/command/appstore/cert.rb +212 -0
- data/lib/pindo/command/appstore/configproj.rb +81 -0
- data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
- data/lib/pindo/command/appstore/iap.rb +788 -24
- data/lib/pindo/command/appstore/initconfig.rb +105 -0
- data/lib/pindo/command/appstore/itcapp.rb +95 -13
- data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
- data/lib/pindo/command/appstore/pem.rb +136 -0
- data/lib/pindo/command/appstore/pullconfig.rb +99 -0
- data/lib/pindo/command/appstore/quswark.rb +87 -0
- data/lib/pindo/command/appstore/quswauth.rb +67 -0
- data/lib/pindo/command/appstore/tag.rb +77 -0
- data/lib/pindo/command/appstore.rb +13 -1
- data/lib/pindo/command/env/quarkenv.rb +11 -13
- data/lib/pindo/command/env/swarkenv.rb +11 -16
- data/lib/pindo/command/ios/autobuild.rb +64 -43
- data/lib/pindo/command/ios/autoresign.rb +34 -19
- data/lib/pindo/command/ios/build.rb +9 -6
- data/lib/pindo/command/ios/cert.rb +27 -20
- data/lib/pindo/command/jps/upload.rb +3 -3
- data/lib/pindo/command/unity/autobuild.rb +2 -2
- data/lib/pindo/command/utils/clearcert.rb +2 -17
- data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
- data/lib/pindo/command/utils/renewcert.rb +62 -38
- data/lib/pindo/command/utils/renewproj.rb +0 -3
- data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
- data/lib/pindo/command/utils.rb +2 -0
- data/lib/pindo/command/web/autobuild.rb +2 -2
- data/lib/pindo/command.rb +30 -3
- data/lib/pindo/config/build_info_manager.rb +176 -0
- data/lib/pindo/config/ios_config_parser.rb +404 -0
- data/lib/pindo/module/android/android_config_helper.rb +9 -5
- data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
- data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
- data/lib/pindo/module/build/build_helper.rb +12 -0
- data/lib/pindo/module/build/swark_helper.rb +116 -77
- data/lib/pindo/module/cert/cert_helper.rb +74 -0
- data/lib/pindo/module/cert/pem_helper.rb +72 -0
- data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +208 -6
- data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
- data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
- data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
- data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
- data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
- data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +197 -0
- data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +367 -0
- data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +37 -27
- data/lib/pindo/module/task/model/build/ios_build_task.rb +13 -0
- data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
- data/lib/pindo/module/task/model/build_task.rb +15 -12
- data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
- data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
- data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
- data/lib/pindo/module/unity/unity_helper.rb +2 -1
- data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
- data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
- data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
- data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
- data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
- data/lib/pindo/options/core/global_options_state.rb +268 -0
- data/lib/pindo/options/core/option_configuration.rb +206 -0
- data/lib/pindo/options/core/option_initializer.rb +51 -0
- data/lib/pindo/options/core/option_item.rb +144 -0
- data/lib/pindo/options/core/option_value_parser.rb +54 -0
- data/lib/pindo/options/groups/build_options.rb +60 -0
- data/lib/pindo/options/groups/jps_options.rb +70 -0
- data/lib/pindo/options/groups/option_group.rb +73 -0
- data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
- data/lib/pindo/options/options.rb +14 -0
- data/lib/pindo/version.rb +1 -1
- metadata +49 -40
- data/lib/pindo/command/appstore/import.rb +0 -259
- data/lib/pindo/command/deploy/build.rb +0 -250
- data/lib/pindo/command/deploy/bundleid.rb +0 -259
- data/lib/pindo/command/deploy/cert.rb +0 -202
- data/lib/pindo/command/deploy/check.rb +0 -93
- data/lib/pindo/command/deploy/configproj.rb +0 -120
- data/lib/pindo/command/deploy/confusecode.rb +0 -262
- data/lib/pindo/command/deploy/confuseproj.rb +0 -122
- data/lib/pindo/command/deploy/iap.rb +0 -826
- data/lib/pindo/command/deploy/initconfig.rb +0 -138
- data/lib/pindo/command/deploy/itcapp.rb +0 -146
- data/lib/pindo/command/deploy/pem.rb +0 -55
- data/lib/pindo/command/deploy/pullconfig.rb +0 -56
- data/lib/pindo/command/deploy/pushconfig.rb +0 -93
- data/lib/pindo/command/deploy/quswark.rb +0 -156
- data/lib/pindo/command/deploy/quswauth.rb +0 -76
- data/lib/pindo/command/deploy/reportbug.rb +0 -145
- data/lib/pindo/command/deploy/resign.rb +0 -300
- data/lib/pindo/command/deploy/tag.rb +0 -108
- data/lib/pindo/command/deploy/uploadipa.rb +0 -73
- data/lib/pindo/command/deploy.rb +0 -42
- data/lib/pindo/command/dev/autobuild.rb +0 -117
- data/lib/pindo/command/dev/build.rb +0 -94
- data/lib/pindo/command/dev/debug.rb +0 -112
- data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
- data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
- data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
- data/lib/pindo/options/appconfigoptions.rb +0 -24
- data/lib/pindo/options/deployoptions.rb +0 -372
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
require 'pindo/options/core/option_item'
|
|
2
|
+
|
|
3
|
+
module Pindo
|
|
4
|
+
module Options
|
|
5
|
+
# 参数配置管理器(简化版)
|
|
6
|
+
# 负责管理参数值的生命周期:默认值、类型转换、验证
|
|
7
|
+
class OptionConfiguration
|
|
8
|
+
|
|
9
|
+
# 初始化
|
|
10
|
+
# @param available_options [Array<OptionItem>] 可用参数列表
|
|
11
|
+
# @param raw_values [Hash] 原始参数值
|
|
12
|
+
# @param command_instance [Object, nil] 命令实例(用于 value_block)
|
|
13
|
+
def initialize(available_options, raw_values = {}, command_instance: nil)
|
|
14
|
+
@available_options = available_options
|
|
15
|
+
@raw_values = raw_values
|
|
16
|
+
@command_instance = command_instance
|
|
17
|
+
@values = {}
|
|
18
|
+
@options_map = build_options_map
|
|
19
|
+
|
|
20
|
+
# 执行参数处理流程
|
|
21
|
+
process_all_options
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# 获取参数值(支持符号和字符串)
|
|
25
|
+
# @param key [Symbol, String] 参数键名
|
|
26
|
+
# @return [Object] 参数值
|
|
27
|
+
def [](key)
|
|
28
|
+
key = normalize_key(key)
|
|
29
|
+
@values[key]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 设置参数值
|
|
33
|
+
# @param key [Symbol, String] 参数键名
|
|
34
|
+
# @param value [Object] 参数值
|
|
35
|
+
def []=(key, value)
|
|
36
|
+
key = normalize_key(key)
|
|
37
|
+
option_item = @options_map[key]
|
|
38
|
+
|
|
39
|
+
if option_item
|
|
40
|
+
@values[key] = option_item.auto_convert_value(value)
|
|
41
|
+
option_item.valid?(@values[key])
|
|
42
|
+
else
|
|
43
|
+
@values[key] = value
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# 获取所有参数值
|
|
48
|
+
# @return [Hash] 所有参数值
|
|
49
|
+
def to_hash
|
|
50
|
+
@values.dup
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# 检查参数是否存在
|
|
54
|
+
# @param key [Symbol, String] 参数键名
|
|
55
|
+
# @return [Boolean]
|
|
56
|
+
def key?(key)
|
|
57
|
+
@values.key?(normalize_key(key))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# 获取所有参数键
|
|
61
|
+
# @return [Array<Symbol>]
|
|
62
|
+
def keys
|
|
63
|
+
@values.keys
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# 遍历所有参数
|
|
67
|
+
# @yield [key, value] 参数键值对
|
|
68
|
+
def each(&block)
|
|
69
|
+
@values.each(&block)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# 构建参数映射表(支持别名)
|
|
75
|
+
# @return [Hash{Symbol => OptionItem}]
|
|
76
|
+
def build_options_map
|
|
77
|
+
map = {}
|
|
78
|
+
@available_options.each do |item|
|
|
79
|
+
# 主键
|
|
80
|
+
map[item.key] = item
|
|
81
|
+
# 别名
|
|
82
|
+
item.aliases.each do |alias_name|
|
|
83
|
+
map[alias_name] = item
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
map
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# 参数处理主流程
|
|
90
|
+
def process_all_options
|
|
91
|
+
# 1. 应用默认值
|
|
92
|
+
apply_defaults
|
|
93
|
+
|
|
94
|
+
# 2. 应用原始值(命令行参数和环境变量)
|
|
95
|
+
apply_raw_values
|
|
96
|
+
|
|
97
|
+
# 3. 应用 value_block(交互式获取值)
|
|
98
|
+
apply_value_blocks
|
|
99
|
+
|
|
100
|
+
# 4. 类型转换
|
|
101
|
+
convert_types
|
|
102
|
+
|
|
103
|
+
# 5. 验证必填参数
|
|
104
|
+
validate_required
|
|
105
|
+
|
|
106
|
+
# 6. 自定义验证
|
|
107
|
+
validate_custom
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 应用默认值
|
|
111
|
+
def apply_defaults
|
|
112
|
+
@available_options.each do |item|
|
|
113
|
+
@values[item.key] = item.default_value if item.default_value
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# 应用原始值(映射别名到主键)
|
|
118
|
+
def apply_raw_values
|
|
119
|
+
@raw_values.each do |key, value|
|
|
120
|
+
normalized_key = normalize_key(key)
|
|
121
|
+
option_item = @options_map[normalized_key]
|
|
122
|
+
|
|
123
|
+
if option_item
|
|
124
|
+
# 使用主键存储
|
|
125
|
+
@values[option_item.key] = value
|
|
126
|
+
else
|
|
127
|
+
# 未知参数,仍然保存(可能是其他用途)
|
|
128
|
+
@values[normalized_key] = value
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# 应用 value_block(交互式获取值)
|
|
134
|
+
# 优先级:命令行参数 > 缓存(已在 raw_values) > value_block > 默认值
|
|
135
|
+
def apply_value_blocks
|
|
136
|
+
@available_options.each do |item|
|
|
137
|
+
# 只有当参数没有值时,才调用 value_block
|
|
138
|
+
next if @values.key?(item.key) && !@values[item.key].nil?
|
|
139
|
+
next unless item.value_block
|
|
140
|
+
|
|
141
|
+
begin
|
|
142
|
+
# 调用 value_block 获取值
|
|
143
|
+
# 如果 value_block 接受参数,则传入命令实例
|
|
144
|
+
value = if item.value_block.arity > 0
|
|
145
|
+
item.value_block.call(@command_instance)
|
|
146
|
+
else
|
|
147
|
+
item.value_block.call
|
|
148
|
+
end
|
|
149
|
+
@values[item.key] = value unless value.nil?
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
# value_block 执行失败,记录错误但不中断流程
|
|
152
|
+
puts "[OptionConfiguration] value_block 执行失败 (#{item.key}): #{e.message}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# 类型转换
|
|
158
|
+
def convert_types
|
|
159
|
+
@available_options.each do |item|
|
|
160
|
+
next unless @values.key?(item.key)
|
|
161
|
+
|
|
162
|
+
begin
|
|
163
|
+
converted_value = item.auto_convert_value(@values[item.key])
|
|
164
|
+
@values[item.key] = converted_value
|
|
165
|
+
rescue StandardError => e
|
|
166
|
+
raise ArgumentError, "参数 '#{item.key}' 类型转换失败: #{e.message}"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# 验证必填参数
|
|
172
|
+
def validate_required
|
|
173
|
+
@available_options.each do |item|
|
|
174
|
+
next if item.optional
|
|
175
|
+
|
|
176
|
+
# 检查参数是否存在且不为 nil
|
|
177
|
+
unless @values.key?(item.key) && !@values[item.key].nil?
|
|
178
|
+
raise ArgumentError, "参数 '#{item.key}' 是必填的"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# 自定义验证(verify_block)
|
|
184
|
+
def validate_custom
|
|
185
|
+
@available_options.each do |item|
|
|
186
|
+
next unless item.verify_block
|
|
187
|
+
next unless @values.key?(item.key)
|
|
188
|
+
|
|
189
|
+
value = @values[item.key]
|
|
190
|
+
begin
|
|
191
|
+
item.verify_block.call(value)
|
|
192
|
+
rescue StandardError => e
|
|
193
|
+
raise ArgumentError, "参数 '#{item.key}' 验证失败: #{e.message}"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# 标准化键名(转为 Symbol)
|
|
199
|
+
# @param key [Symbol, String] 键名
|
|
200
|
+
# @return [Symbol]
|
|
201
|
+
def normalize_key(key)
|
|
202
|
+
key.to_sym
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'pindo/options/core/option_value_parser'
|
|
2
|
+
require 'pindo/options/core/option_configuration'
|
|
3
|
+
require 'pindo/options/core/global_options_state'
|
|
4
|
+
|
|
5
|
+
module Pindo
|
|
6
|
+
module Options
|
|
7
|
+
# 参数初始化器
|
|
8
|
+
# 提供统一的参数初始化流程:解析 → 配置 → 注册
|
|
9
|
+
module OptionInitializer
|
|
10
|
+
# 初始化命令参数
|
|
11
|
+
#
|
|
12
|
+
# @param command_instance [Object] 命令实例
|
|
13
|
+
# @param argv [CLAide::ARGV] 命令行参数
|
|
14
|
+
# @param option_items [Array<OptionItem>] 参数项列表
|
|
15
|
+
# @param command_name [String] 命令名称
|
|
16
|
+
# @param directory [String, nil] 工作目录(默认:当前目录)
|
|
17
|
+
# @param enable_cache [Boolean] 是否启用缓存(默认:false)
|
|
18
|
+
# @return [OptionConfiguration] 参数配置对象
|
|
19
|
+
def self.initialize(command_instance, argv, option_items, command_name, directory: nil, enable_cache: false)
|
|
20
|
+
# 1. 解析参数值(从命令行和环境变量)
|
|
21
|
+
raw_values = OptionValueParser.parse(argv, option_items)
|
|
22
|
+
|
|
23
|
+
# 2. 如果启用缓存,合并缓存值到 raw_values
|
|
24
|
+
if enable_cache
|
|
25
|
+
state = GlobalOptionsState.instance
|
|
26
|
+
state.prepare_cache(command_name, directory || Dir.pwd)
|
|
27
|
+
cached_values = state.load_cached_values
|
|
28
|
+
|
|
29
|
+
# 缓存值优先级:命令行参数 > 缓存 > 默认值
|
|
30
|
+
# 只有在命令行未提供的参数才使用缓存
|
|
31
|
+
cached_values.each do |key, value|
|
|
32
|
+
raw_values[key] = value unless raw_values.key?(key)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# 3. 创建参数配置(自动处理验证等,传入命令实例用于 value_block)
|
|
37
|
+
options = OptionConfiguration.new(option_items, raw_values, command_instance: command_instance)
|
|
38
|
+
|
|
39
|
+
# 4. 设置全局状态
|
|
40
|
+
GlobalOptionsState.instance.set_command(
|
|
41
|
+
command_name,
|
|
42
|
+
options,
|
|
43
|
+
directory: directory || Dir.pwd,
|
|
44
|
+
enable_cache: enable_cache
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
options
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Pindo
|
|
2
|
+
module Options
|
|
3
|
+
# OptionItem 类定义单个参数的所有属性和行为(简化版)
|
|
4
|
+
class OptionItem
|
|
5
|
+
|
|
6
|
+
# 核心属性
|
|
7
|
+
attr_accessor :key # Symbol: 参数键名
|
|
8
|
+
attr_accessor :description # String: 参数描述
|
|
9
|
+
attr_accessor :type # Class: 数据类型 (String/Integer/Boolean)
|
|
10
|
+
attr_accessor :env_name # String: 环境变量名
|
|
11
|
+
attr_accessor :aliases # Array<Symbol>: 参数别名
|
|
12
|
+
attr_accessor :default_value # Any: 默认值
|
|
13
|
+
attr_accessor :optional # Boolean: 是否可选(默认为 true)
|
|
14
|
+
attr_accessor :verify_block # Proc: 自定义验证逻辑
|
|
15
|
+
attr_accessor :value_block # Proc: 获取参数值的 block(交互式输入)
|
|
16
|
+
attr_accessor :example # String: 使用示例
|
|
17
|
+
|
|
18
|
+
# Boolean 类型标记
|
|
19
|
+
Boolean = :boolean
|
|
20
|
+
|
|
21
|
+
# 初始化方法
|
|
22
|
+
# @param key [Symbol] 参数键名(必填)
|
|
23
|
+
# @param options [Hash] 其他配置选项
|
|
24
|
+
def initialize(key:, **options)
|
|
25
|
+
raise ArgumentError, "key must be a Symbol" unless key.is_a?(Symbol)
|
|
26
|
+
|
|
27
|
+
@key = key
|
|
28
|
+
@description = options[:description] || options[:desc] || ""
|
|
29
|
+
@type = options[:type] || String
|
|
30
|
+
@env_name = options[:env_name]
|
|
31
|
+
@aliases = options[:aliases] || []
|
|
32
|
+
@default_value = options[:default_value] || options[:default]
|
|
33
|
+
@optional = options.fetch(:optional, true)
|
|
34
|
+
@verify_block = options[:verify_block]
|
|
35
|
+
@value_block = options[:value_block]
|
|
36
|
+
@example = options[:example]
|
|
37
|
+
|
|
38
|
+
validate_type!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# 判断是否是 Boolean 类型
|
|
42
|
+
def boolean?
|
|
43
|
+
@type == Boolean || @type == :boolean
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# 从环境变量读取值
|
|
47
|
+
# @return [String, nil] 环境变量的值
|
|
48
|
+
def fetch_env_value
|
|
49
|
+
return nil unless @env_name
|
|
50
|
+
value = ENV[@env_name]
|
|
51
|
+
value if value && !value.empty?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# 自动类型转换
|
|
55
|
+
# @param value [Any] 原始值
|
|
56
|
+
# @return [Any] 转换后的值
|
|
57
|
+
def auto_convert_value(value)
|
|
58
|
+
return nil if value.nil?
|
|
59
|
+
|
|
60
|
+
case @type
|
|
61
|
+
when Boolean, :boolean
|
|
62
|
+
# Boolean 转换
|
|
63
|
+
if value.is_a?(String)
|
|
64
|
+
return true if value.downcase == 'true' || value == '1'
|
|
65
|
+
return false if value.downcase == 'false' || value == '0'
|
|
66
|
+
end
|
|
67
|
+
!!value
|
|
68
|
+
when Integer
|
|
69
|
+
value.to_i
|
|
70
|
+
else
|
|
71
|
+
# String 或其他类型
|
|
72
|
+
value.to_s
|
|
73
|
+
end
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
raise ArgumentError, "参数 '#{@key}' 类型转换失败: #{e.message}"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# 验证参数值
|
|
79
|
+
# @param value [Any] 要验证的值
|
|
80
|
+
# @return [Boolean] 验证是否通过
|
|
81
|
+
def valid?(value)
|
|
82
|
+
return true unless @verify_block
|
|
83
|
+
|
|
84
|
+
begin
|
|
85
|
+
@verify_block.call(value)
|
|
86
|
+
true
|
|
87
|
+
rescue StandardError => e
|
|
88
|
+
raise ArgumentError, "参数 '#{@key}' 验证失败: #{e.message}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# 转换为 CLAide 选项格式(用于 --help 输出)
|
|
93
|
+
# @return [Array] CLAide 选项格式 [option_string, description]
|
|
94
|
+
def to_claide_option
|
|
95
|
+
option_string = build_option_string
|
|
96
|
+
description_text = build_description_text
|
|
97
|
+
|
|
98
|
+
[option_string, description_text]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# 验证类型是否合法
|
|
104
|
+
def validate_type!
|
|
105
|
+
valid_types = [String, Integer, Boolean, :boolean]
|
|
106
|
+
unless valid_types.include?(@type)
|
|
107
|
+
raise ArgumentError, "Invalid type: #{@type}. Valid types: #{valid_types.join(', ')}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# 构建选项字符串(--key[=VALUE] 格式)
|
|
112
|
+
def build_option_string
|
|
113
|
+
# 只显示主选项,不显示别名(避免输出过长导致换行)
|
|
114
|
+
if boolean?
|
|
115
|
+
"--#{@key}"
|
|
116
|
+
else
|
|
117
|
+
type_hint = type_to_hint
|
|
118
|
+
"--#{@key}=#{type_hint}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# 构建描述文本(描述 + 环境变量)
|
|
123
|
+
def build_description_text
|
|
124
|
+
if @env_name
|
|
125
|
+
"#{@description} (环境变量: #{@env_name})"
|
|
126
|
+
else
|
|
127
|
+
@description
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# 类型转换为提示字符串
|
|
132
|
+
def type_to_hint
|
|
133
|
+
case @type
|
|
134
|
+
when String
|
|
135
|
+
'VALUE'
|
|
136
|
+
when Integer
|
|
137
|
+
'NUMBER'
|
|
138
|
+
else
|
|
139
|
+
'VALUE'
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'pindo/options/core/option_item'
|
|
2
|
+
|
|
3
|
+
module Pindo
|
|
4
|
+
module Options
|
|
5
|
+
# 参数值解析器
|
|
6
|
+
# 负责从 CLAide::ARGV 和环境变量中提取参数的原始值
|
|
7
|
+
class OptionValueParser
|
|
8
|
+
|
|
9
|
+
# 解析参数值
|
|
10
|
+
# @param argv [CLAide::ARGV] CLAide 的参数对象
|
|
11
|
+
# @param option_items [Array<OptionItem>] 参数定义列表
|
|
12
|
+
# @return [Hash] 原始参数值 Hash { key: raw_value }
|
|
13
|
+
def self.parse(argv, option_items)
|
|
14
|
+
values = {}
|
|
15
|
+
|
|
16
|
+
option_items.each do |item|
|
|
17
|
+
# 1. 从 argv 提取值(优先级最高)
|
|
18
|
+
raw_value = extract_from_argv(argv, item)
|
|
19
|
+
|
|
20
|
+
# 2. 如果 argv 没有,尝试从环境变量读取
|
|
21
|
+
if raw_value.nil?
|
|
22
|
+
raw_value = item.fetch_env_value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# 3. 存储值(可能是 nil)
|
|
26
|
+
values[item.key] = raw_value unless raw_value.nil?
|
|
27
|
+
|
|
28
|
+
# 4. 处理别名(别名指向同一个值)
|
|
29
|
+
item.aliases.each do |alias_name|
|
|
30
|
+
values[alias_name] = raw_value unless raw_value.nil?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
values
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
# 从 argv 提取参数值
|
|
40
|
+
# @param argv [CLAide::ARGV] CLAide 参数对象
|
|
41
|
+
# @param item [OptionItem] 参数定义
|
|
42
|
+
# @return [Object, nil] 提取的值
|
|
43
|
+
def self.extract_from_argv(argv, item)
|
|
44
|
+
if item.boolean?
|
|
45
|
+
# Boolean 类型:使用 flag?
|
|
46
|
+
argv.flag?(item.key.to_s, nil)
|
|
47
|
+
else
|
|
48
|
+
# 其他类型:使用 option
|
|
49
|
+
argv.option(item.key.to_s, nil)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'pindo/options/core/option_item'
|
|
2
|
+
require 'pindo/options/groups/option_group'
|
|
3
|
+
|
|
4
|
+
module Pindo
|
|
5
|
+
module Options
|
|
6
|
+
# 通用构建参数组
|
|
7
|
+
# 定义跨平台(iOS/Android)的构建参数
|
|
8
|
+
module BuildOptions
|
|
9
|
+
extend OptionGroup
|
|
10
|
+
|
|
11
|
+
def self.all_options
|
|
12
|
+
|
|
13
|
+
@all_options ||= {
|
|
14
|
+
|
|
15
|
+
bundleid: OptionItem.new(
|
|
16
|
+
key: :bundleid,
|
|
17
|
+
description: '指定打包的 Bundle ID',
|
|
18
|
+
type: String,
|
|
19
|
+
env_name: 'PINDO_BUNDLE_ID',
|
|
20
|
+
aliases: [:bundle_id, :package_name, :bundle_name],
|
|
21
|
+
optional: true,
|
|
22
|
+
verify_block: proc do |value|
|
|
23
|
+
# 支持 iOS 格式 (com.example.app) 和 Android 格式 (com.example.app)
|
|
24
|
+
# iOS 可以包含大写字母、连字符和通配符(*)
|
|
25
|
+
unless value =~ /^[a-zA-Z0-9\-\.\*]+$/
|
|
26
|
+
raise "Bundle ID/Package Name 格式错误: #{value},应该类似 com.example.app 或 com.example.*"
|
|
27
|
+
end
|
|
28
|
+
end,
|
|
29
|
+
example: 'pindo ios autobuild --bundleid=com.example.app'
|
|
30
|
+
),
|
|
31
|
+
|
|
32
|
+
build_type: OptionItem.new(
|
|
33
|
+
key: :build_type,
|
|
34
|
+
description: '指定构建类型(dev/adhoc/release)',
|
|
35
|
+
type: String,
|
|
36
|
+
env_name: 'PINDO_BUILD_TYPE',
|
|
37
|
+
default_value: 'dev',
|
|
38
|
+
optional: true,
|
|
39
|
+
verify_block: proc do |value|
|
|
40
|
+
valid_types = ['dev', 'adhoc', 'release']
|
|
41
|
+
unless valid_types.include?(value.to_s.downcase)
|
|
42
|
+
raise "构建类型错误: #{value},必须是 dev、adhoc 或 release 之一"
|
|
43
|
+
end
|
|
44
|
+
end,
|
|
45
|
+
example: 'pindo ios autobuild --build_type=release'
|
|
46
|
+
),
|
|
47
|
+
|
|
48
|
+
scheme: OptionItem.new(
|
|
49
|
+
key: :scheme,
|
|
50
|
+
description: '指定构建 Scheme',
|
|
51
|
+
type: String,
|
|
52
|
+
env_name: 'PINDO_SCHEME',
|
|
53
|
+
optional: true,
|
|
54
|
+
example: 'pindo ios autobuild --scheme=MyAppScheme'
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'pindo/options/core/option_item'
|
|
2
|
+
require 'pindo/options/groups/option_group'
|
|
3
|
+
|
|
4
|
+
module Pindo
|
|
5
|
+
module Options
|
|
6
|
+
# JPS 平台参数组
|
|
7
|
+
# 定义 JPS 测试平台特有的参数
|
|
8
|
+
module JPSOptions
|
|
9
|
+
extend OptionGroup
|
|
10
|
+
|
|
11
|
+
def self.all_options
|
|
12
|
+
@all_options ||= {
|
|
13
|
+
proj: OptionItem.new(
|
|
14
|
+
key: :proj,
|
|
15
|
+
description: '指定上传到测试平台的项目名称',
|
|
16
|
+
type: String,
|
|
17
|
+
env_name: 'PINDO_PROJECT_NAME',
|
|
18
|
+
optional: true,
|
|
19
|
+
example: 'pindo ios autobuild --proj="My App"'
|
|
20
|
+
),
|
|
21
|
+
|
|
22
|
+
upload: OptionItem.new(
|
|
23
|
+
key: :upload,
|
|
24
|
+
description: '编译后上传到测试平台(上传成功后自动发送给自己)',
|
|
25
|
+
type: OptionItem::Boolean,
|
|
26
|
+
env_name: 'PINDO_UPLOAD',
|
|
27
|
+
optional: true,
|
|
28
|
+
example: 'pindo ios autobuild --upload'
|
|
29
|
+
),
|
|
30
|
+
|
|
31
|
+
send: OptionItem.new(
|
|
32
|
+
key: :send,
|
|
33
|
+
description: '发送通知到测试群组(同时也会发送给自己)',
|
|
34
|
+
type: OptionItem::Boolean,
|
|
35
|
+
env_name: 'PINDO_SEND',
|
|
36
|
+
optional: true,
|
|
37
|
+
example: 'pindo ios autobuild --send'
|
|
38
|
+
),
|
|
39
|
+
desc: OptionItem.new(
|
|
40
|
+
key: :desc,
|
|
41
|
+
description: '指定上传的备注信息',
|
|
42
|
+
type: String,
|
|
43
|
+
env_name: 'PINDO_UPLOAD_DESC',
|
|
44
|
+
aliases: [:description],
|
|
45
|
+
optional: true,
|
|
46
|
+
example: 'pindo jps upload --desc="版本说明"'
|
|
47
|
+
),
|
|
48
|
+
|
|
49
|
+
resign: OptionItem.new(
|
|
50
|
+
key: :resign,
|
|
51
|
+
description: '上传后是否重签名',
|
|
52
|
+
type: OptionItem::Boolean,
|
|
53
|
+
env_name: 'PINDO_RESIGN',
|
|
54
|
+
optional: true,
|
|
55
|
+
example: 'pindo jps upload --resign'
|
|
56
|
+
),
|
|
57
|
+
|
|
58
|
+
certid: OptionItem.new(
|
|
59
|
+
key: :certid,
|
|
60
|
+
description: '设置重签名的Bundle ID',
|
|
61
|
+
type: String,
|
|
62
|
+
env_name: 'PINDO_CERT_ID',
|
|
63
|
+
optional: true,
|
|
64
|
+
example: 'pindo jps resign --certid=com.test.bundleid'
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'pindo/options/core/option_item'
|
|
2
|
+
|
|
3
|
+
module Pindo
|
|
4
|
+
module Options
|
|
5
|
+
# 参数组工具模块
|
|
6
|
+
# 提供参数组的定义、筛选和合并功能
|
|
7
|
+
# 合并了原 OptionGroupBase 和 OptionRegistry 的功能
|
|
8
|
+
module OptionGroup
|
|
9
|
+
|
|
10
|
+
# ==================== 实例方法(供参数组使用) ====================
|
|
11
|
+
|
|
12
|
+
# 选择指定的参数
|
|
13
|
+
# @param keys [Array<Symbol>] 要选择的参数键名
|
|
14
|
+
# @return [Array<OptionItem>] 选中的参数列表
|
|
15
|
+
def select(*keys)
|
|
16
|
+
keys = keys.flatten.map(&:to_sym)
|
|
17
|
+
all_options_hash = all_options
|
|
18
|
+
|
|
19
|
+
selected = keys.map do |key|
|
|
20
|
+
option = all_options_hash[key]
|
|
21
|
+
if option.nil?
|
|
22
|
+
raise ArgumentError, "参数组 #{self.name} 中不存在参数: #{key}"
|
|
23
|
+
end
|
|
24
|
+
option
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
selected
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# 排除指定的参数,返回剩余参数
|
|
31
|
+
# @param keys [Array<Symbol>] 要排除的参数键名
|
|
32
|
+
# @return [Array<OptionItem>] 剩余的参数列表
|
|
33
|
+
def except(*keys)
|
|
34
|
+
keys = keys.flatten.map(&:to_sym)
|
|
35
|
+
all_options_hash = all_options
|
|
36
|
+
|
|
37
|
+
all_options_hash.reject { |k, v| keys.include?(k) }.values
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 获取所有参数(返回数组)
|
|
41
|
+
# @return [Array<OptionItem>] 所有参数列表
|
|
42
|
+
def all
|
|
43
|
+
all_options.values
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# 子类必须实现此方法
|
|
47
|
+
# @return [Hash{Symbol => OptionItem}] 所有参数的 Hash
|
|
48
|
+
def all_options
|
|
49
|
+
raise NotImplementedError, "子类必须实现 all_options 方法"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# ==================== 类方法(合并参数组) ====================
|
|
53
|
+
|
|
54
|
+
# 合并多个参数组
|
|
55
|
+
# @param option_groups [Array<Array<OptionItem>>] 参数组列表
|
|
56
|
+
# @return [Array<OptionItem>] 合并后的参数列表(去重)
|
|
57
|
+
def self.merge(*option_groups)
|
|
58
|
+
merged_map = {}
|
|
59
|
+
|
|
60
|
+
option_groups.flatten.compact.each do |item|
|
|
61
|
+
unless item.is_a?(OptionItem)
|
|
62
|
+
raise ArgumentError, "Expected OptionItem, got #{item.class}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# 如果键已存在,后面的覆盖前面的
|
|
66
|
+
merged_map[item.key] = item
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
merged_map.values
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|