pindo 5.13.1 → 5.13.3

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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/git_handler.rb +692 -0
  3. data/lib/pindo/command/android/autobuild.rb +2 -2
  4. data/lib/pindo/command/appstore/adhocbuild.rb +256 -311
  5. data/lib/pindo/command/appstore/autobuild.rb +203 -0
  6. data/lib/pindo/command/appstore/autoresign.rb +35 -17
  7. data/lib/pindo/command/appstore/bundleid.rb +120 -0
  8. data/lib/pindo/command/appstore/cert.rb +212 -0
  9. data/lib/pindo/command/appstore/configproj.rb +81 -0
  10. data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
  11. data/lib/pindo/command/appstore/iap.rb +788 -24
  12. data/lib/pindo/command/appstore/initconfig.rb +105 -0
  13. data/lib/pindo/command/appstore/itcapp.rb +95 -13
  14. data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
  15. data/lib/pindo/command/appstore/pem.rb +136 -0
  16. data/lib/pindo/command/appstore/pullconfig.rb +99 -0
  17. data/lib/pindo/command/appstore/quswark.rb +87 -0
  18. data/lib/pindo/command/appstore/quswauth.rb +67 -0
  19. data/lib/pindo/command/appstore/tag.rb +77 -0
  20. data/lib/pindo/command/appstore.rb +13 -1
  21. data/lib/pindo/command/env/quarkenv.rb +11 -13
  22. data/lib/pindo/command/env/swarkenv.rb +11 -16
  23. data/lib/pindo/command/ios/applovin.rb +24 -182
  24. data/lib/pindo/command/ios/autobuild.rb +64 -43
  25. data/lib/pindo/command/ios/autoresign.rb +34 -19
  26. data/lib/pindo/command/ios/build.rb +9 -6
  27. data/lib/pindo/command/ios/cert.rb +27 -20
  28. data/lib/pindo/command/ios/podupdate.rb +6 -37
  29. data/lib/pindo/command/jps/upload.rb +3 -3
  30. data/lib/pindo/command/unity/autobuild.rb +2 -2
  31. data/lib/pindo/command/utils/clearcert.rb +2 -17
  32. data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
  33. data/lib/pindo/command/utils/renewcert.rb +62 -38
  34. data/lib/pindo/command/utils/renewproj.rb +0 -3
  35. data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
  36. data/lib/pindo/command/utils.rb +2 -0
  37. data/lib/pindo/command/web/autobuild.rb +2 -2
  38. data/lib/pindo/command.rb +30 -3
  39. data/lib/pindo/config/build_info_manager.rb +176 -0
  40. data/lib/pindo/config/ios_config_parser.rb +404 -0
  41. data/lib/pindo/module/android/android_config_helper.rb +9 -5
  42. data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
  43. data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
  44. data/lib/pindo/module/build/build_helper.rb +12 -0
  45. data/lib/pindo/module/build/swark_helper.rb +116 -77
  46. data/lib/pindo/module/cert/cert_helper.rb +74 -0
  47. data/lib/pindo/module/cert/pem_helper.rb +72 -0
  48. data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +211 -6
  49. data/lib/pindo/module/pgyer/pgyerhelper.rb +13 -5
  50. data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
  51. data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
  52. data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
  53. data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
  54. data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
  55. data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
  56. data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
  57. data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
  58. data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +342 -0
  59. data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +341 -0
  60. data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +40 -59
  61. data/lib/pindo/module/task/model/build/ios_build_task.rb +23 -0
  62. data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
  63. data/lib/pindo/module/task/model/build_task.rb +15 -12
  64. data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
  65. data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
  66. data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
  67. data/lib/pindo/module/unity/unity_helper.rb +2 -1
  68. data/lib/pindo/module/xcode/applovin_xcode_helper.rb +271 -0
  69. data/lib/pindo/module/xcode/cocoapods_helper.rb +153 -0
  70. data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
  71. data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
  72. data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
  73. data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
  74. data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
  75. data/lib/pindo/options/core/global_options_state.rb +268 -0
  76. data/lib/pindo/options/core/option_configuration.rb +206 -0
  77. data/lib/pindo/options/core/option_initializer.rb +51 -0
  78. data/lib/pindo/options/core/option_item.rb +144 -0
  79. data/lib/pindo/options/core/option_value_parser.rb +54 -0
  80. data/lib/pindo/options/groups/build_options.rb +60 -0
  81. data/lib/pindo/options/groups/jps_options.rb +70 -0
  82. data/lib/pindo/options/groups/option_group.rb +73 -0
  83. data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
  84. data/lib/pindo/options/options.rb +14 -0
  85. data/lib/pindo/version.rb +1 -1
  86. metadata +51 -40
  87. data/lib/pindo/command/appstore/import.rb +0 -259
  88. data/lib/pindo/command/deploy/build.rb +0 -250
  89. data/lib/pindo/command/deploy/bundleid.rb +0 -259
  90. data/lib/pindo/command/deploy/cert.rb +0 -202
  91. data/lib/pindo/command/deploy/check.rb +0 -93
  92. data/lib/pindo/command/deploy/configproj.rb +0 -120
  93. data/lib/pindo/command/deploy/confusecode.rb +0 -262
  94. data/lib/pindo/command/deploy/confuseproj.rb +0 -122
  95. data/lib/pindo/command/deploy/iap.rb +0 -826
  96. data/lib/pindo/command/deploy/initconfig.rb +0 -138
  97. data/lib/pindo/command/deploy/itcapp.rb +0 -146
  98. data/lib/pindo/command/deploy/pem.rb +0 -55
  99. data/lib/pindo/command/deploy/pullconfig.rb +0 -56
  100. data/lib/pindo/command/deploy/pushconfig.rb +0 -93
  101. data/lib/pindo/command/deploy/quswark.rb +0 -156
  102. data/lib/pindo/command/deploy/quswauth.rb +0 -76
  103. data/lib/pindo/command/deploy/reportbug.rb +0 -145
  104. data/lib/pindo/command/deploy/resign.rb +0 -300
  105. data/lib/pindo/command/deploy/tag.rb +0 -108
  106. data/lib/pindo/command/deploy/uploadipa.rb +0 -73
  107. data/lib/pindo/command/deploy.rb +0 -42
  108. data/lib/pindo/command/dev/autobuild.rb +0 -117
  109. data/lib/pindo/command/dev/build.rb +0 -94
  110. data/lib/pindo/command/dev/debug.rb +0 -112
  111. data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
  112. data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
  113. data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
  114. data/lib/pindo/options/appconfigoptions.rb +0 -24
  115. data/lib/pindo/options/deployoptions.rb +0 -372
@@ -0,0 +1,341 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'yaml'
4
+
5
+ module Pindo
6
+ # Xcode Swark/Quark 辅助工具类
7
+ # 用于配置和运行 Quark 和 Swark 开发环境
8
+ class XcodeSwarkHelper
9
+
10
+ # 配置 Quark 开发环境
11
+ # @param pindo_dir [String] Pindo 工作目录
12
+ # @param quark_git_url [String] Quark Git 仓库 URL
13
+ # @return [Boolean] 是否配置成功
14
+ def self.setup_quark_env(pindo_dir:, quark_git_url:)
15
+ require 'pindo/base/git_handler'
16
+ require_relative '../../base/funlog'
17
+
18
+ begin
19
+ # 确保 pindo 目录存在
20
+ FileUtils.mkdir_p(pindo_dir) unless File.exist?(pindo_dir)
21
+
22
+ Funlog.instance.fancyinfo_start("正在配置 Quark 开发环境...")
23
+
24
+ # 获取仓库名称
25
+ reponame = get_repo_base_name(repo_url: quark_git_url)
26
+
27
+ # 克隆或更新 Quark 仓库
28
+ quark_path = Pindo::GitHandler.getcode_to_dir(
29
+ reponame: reponame,
30
+ remote_url: quark_git_url,
31
+ path: pindo_dir,
32
+ new_branch: nil
33
+ )
34
+
35
+ # 执行 quark-install
36
+ install_command = File.join(quark_path, 'quark-install')
37
+ if File.exist?(install_command)
38
+ Funlog.instance.fancyinfo("执行 quark-install...")
39
+ system "/bin/chmod 777 #{install_command}"
40
+ system install_command
41
+ else
42
+ Funlog.instance.fancyinfo_warning("未找到 quark-install 文件: #{install_command}")
43
+ end
44
+
45
+ # 执行 quark-upgrade
46
+ upgrade_command = File.join(quark_path, 'quark-upgrade')
47
+ if File.exist?(upgrade_command)
48
+ Funlog.instance.fancyinfo("执行 quark-upgrade...")
49
+ system "/bin/chmod 777 #{upgrade_command}"
50
+ system upgrade_command
51
+ else
52
+ Funlog.instance.fancyinfo_warning("未找到 quark-upgrade 文件: #{upgrade_command}")
53
+ end
54
+
55
+ Funlog.instance.fancyinfo_success("Quark 开发环境配置完成!")
56
+ return true
57
+
58
+ rescue StandardError => e
59
+ Funlog.instance.fancyinfo_error("配置 Quark 环境失败: #{e.message}")
60
+ puts e.backtrace
61
+ return false
62
+ end
63
+ end
64
+
65
+ # 配置 Swark 开发环境
66
+ # @param pindo_dir [String] Pindo 工作目录
67
+ # @param swark_git_url [String] Swark Git 仓库 URL
68
+ # @return [Boolean] 是否配置成功
69
+ def self.setup_swark_env(pindo_dir:, swark_git_url:)
70
+ require 'pindo/base/git_handler'
71
+ require_relative '../../base/funlog'
72
+
73
+ begin
74
+ # 确保 swark 目录存在
75
+ swark_dir = File.expand_path(pindo_dir)
76
+ FileUtils.mkdir_p(swark_dir) unless File.exist?(swark_dir)
77
+
78
+ Funlog.instance.fancyinfo_start("正在配置 Swark 开发环境...")
79
+
80
+ # 获取仓库名称
81
+ reponame = get_repo_base_name(repo_url: swark_git_url)
82
+
83
+ # 克隆或更新 Swark 仓库(强制使用 swark-toolchain-lite 作为目录名)
84
+ swark_path = Pindo::GitHandler.getcode_to_dir(
85
+ reponame: 'swark-toolchain-lite',
86
+ remote_url: swark_git_url,
87
+ path: swark_dir,
88
+ new_branch: nil
89
+ )
90
+
91
+ # 执行 install
92
+ install_command = File.join(swark_path, 'install')
93
+ if File.exist?(install_command)
94
+ Funlog.instance.fancyinfo("执行 swark install...")
95
+ system "/bin/chmod 777 #{install_command}"
96
+ system install_command
97
+ else
98
+ Funlog.instance.fancyinfo_warning("未找到 install 文件: #{install_command}")
99
+ end
100
+
101
+ # 执行 swark-upgrade
102
+ swark_exe_dir = File.expand_path("~")
103
+ upgrade_command = File.join(swark_exe_dir, 'swark-toolchain/tools/swark-upgrade')
104
+ if File.exist?(upgrade_command)
105
+ Funlog.instance.fancyinfo("执行 swark-upgrade...")
106
+ puts "升级命令: #{upgrade_command}"
107
+ system "/bin/chmod 777 #{upgrade_command}"
108
+ system upgrade_command
109
+ else
110
+ Funlog.instance.fancyinfo_warning("未找到 swark-upgrade 文件: #{upgrade_command}")
111
+ end
112
+
113
+ Funlog.instance.fancyinfo_success("Swark 开发环境配置完成!")
114
+ return true
115
+
116
+ rescue StandardError => e
117
+ Funlog.instance.fancyinfo_error("配置 Swark 环境失败: #{e.message}")
118
+ puts e.backtrace
119
+ return false
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ # 从 Git URL 中提取仓库基础名称
126
+ # @param repo_url [String] Git 仓库 URL
127
+ # @return [String] 仓库基础名称
128
+ def self.get_repo_base_name(repo_url:)
129
+ return nil if repo_url.nil? || repo_url.empty?
130
+
131
+ # 移除 .git 后缀
132
+ base_name = repo_url.sub(/\.git$/, '')
133
+
134
+ # 提取最后一个路径部分
135
+ base_name = base_name.split('/').last
136
+
137
+ base_name
138
+ end
139
+
140
+ # 运行 Swark 配置
141
+ # @param project_dir [String] 项目目录
142
+ # @param config_json [Hash] 配置 JSON 数据
143
+ # @param build_type [String] 构建类型 (dev/adhoc/release)
144
+ # @return [Boolean] 是否成功
145
+ def self.swark_run(project_dir:, config_json:, build_type: 'release')
146
+ require_relative '../../base/funlog'
147
+
148
+ begin
149
+ Funlog.instance.fancyinfo_start("正在配置 Swark 环境...")
150
+
151
+ # 1. 设置 Swark 环境
152
+ require 'pindo/config/pindoconfig'
153
+ pindo_dir = Pindo::Pindoconfig.instance.pindo_dir
154
+ swark_git_url = Pindo::Pindoconfig.instance.deploy_swark_giturl
155
+ setup_swark_env(pindo_dir: pindo_dir, swark_git_url: swark_git_url)
156
+
157
+ # 2. 运行 Swark 授权
158
+ bundle_id = config_json['app_info']['app_identifier'] if config_json && config_json['app_info']
159
+ if bundle_id && !bundle_id.empty?
160
+ swark_authorize_run(bundle_id: bundle_id)
161
+ end
162
+
163
+ # 3. 创建 Swark.host.yaml 配置文件
164
+ swark_host_name = File.join(project_dir, "Swark.host.yaml")
165
+ host_json = {}
166
+ host_json["remote"] = {}
167
+ host_json["remote"]["test"] = ""
168
+
169
+ # 获取 host URL
170
+ host_url = ""
171
+ if config_json && config_json['app_setting']
172
+ if config_json['app_setting']['app_client_url']
173
+ host_url = File.join(config_json['app_setting']['app_client_url'], 'api/v3/init')
174
+ elsif config_json['app_setting']['kGUKeyAppClientHost']
175
+ host_url = File.join(config_json['app_setting']['kGUKeyAppClientHost'], 'api/v3/init')
176
+ end
177
+ end
178
+
179
+ host_json["remote"]["pre"] = host_url
180
+ host_json["remote"]["prod"] = host_url
181
+
182
+ # 设置 embed 名称
183
+ embed_name = "vdisk.dat"
184
+ category_name = "VMDemo"
185
+ if config_json['project_info'] && config_json['project_info']['project_name']
186
+ category_name = config_json['project_info']['project_name']
187
+ category_name = category_name.gsub(/ /, '').gsub(/\'/, '')
188
+ embed_name = category_name + ".dat"
189
+ end
190
+ host_json["embed"] = embed_name
191
+
192
+ # 写入 YAML 文件
193
+ File.open(swark_host_name, "w") do |file|
194
+ YAML.dump(host_json, file)
195
+ end
196
+
197
+ # 4. 运行 swark host 命令
198
+ # dev 使用 pre 模式,其他使用 prod 模式
199
+ swark_mode = (build_type == 'dev') ? 'pre' : 'prod'
200
+ command = "swark host #{swark_mode}"
201
+
202
+ Funlog.instance.fancyinfo("执行命令: #{command}")
203
+ system command
204
+
205
+ Funlog.instance.fancyinfo_success("Swark 配置完成!")
206
+ return true
207
+
208
+ rescue StandardError => e
209
+ Funlog.instance.fancyinfo_error("Swark 配置失败: #{e.message}")
210
+ puts e.backtrace
211
+ return false
212
+ end
213
+ end
214
+
215
+ # 运行 Quark 配置
216
+ # @param project_dir [String] 项目目录
217
+ # @param config_json [Hash] 配置 JSON 数据
218
+ # @param build_type [String] 构建类型 (dev/adhoc/release)
219
+ # @return [Boolean] 是否成功
220
+ def self.quark_run(project_dir:, config_json:, build_type: 'release')
221
+ require_relative '../../base/funlog'
222
+
223
+ begin
224
+ Funlog.instance.fancyinfo_start("正在配置 Quark 环境...")
225
+
226
+ # 1. 设置 Quark 环境
227
+ require 'pindo/config/pindoconfig'
228
+ pindo_dir = Pindo::Pindoconfig.instance.pindo_dir
229
+ quark_git_url = Pindo::Pindoconfig.instance.deploy_quark_giturl
230
+ setup_quark_env(pindo_dir: pindo_dir, quark_git_url: quark_git_url)
231
+
232
+ # 2. 运行 quark host 命令
233
+ # dev 使用 test 模式,其他使用 prod 模式
234
+ quark_mode = (build_type == 'dev') ? 'test' : 'prod'
235
+ command = "quark host #{quark_mode}"
236
+
237
+ Funlog.instance.fancyinfo("执行命令: #{command}")
238
+ system command
239
+
240
+ # 3. 修改 Quark.lock 文件
241
+ quark_json_file = File.join(project_dir, "QuarkData/Quark.lock")
242
+ unless File.exist?(quark_json_file)
243
+ Funlog.instance.fancyinfo_warning("未找到 Quark.lock 文件: #{quark_json_file}")
244
+ return false
245
+ end
246
+
247
+ quark_json = JSON.parse(File.read(quark_json_file))
248
+
249
+ # 设置 remote URL
250
+ if config_json && config_json['app_setting'] && config_json['app_setting']['app_client_url']
251
+ quark_json['remote'] = File.join(config_json['app_setting']['app_client_url'], 'api/init')
252
+ end
253
+
254
+ # 设置 embed 和 category 名称
255
+ embed_name = "Meety.dat"
256
+ category_name = "PodsDummy"
257
+ if config_json['project_info'] && config_json['project_info']['project_name']
258
+ category_name = config_json['project_info']['project_name']
259
+ category_name = category_name.gsub(/ /, '').gsub(/\'/, '')
260
+ embed_name = category_name + ".dat"
261
+ end
262
+
263
+ quark_json['embed'] = embed_name
264
+ quark_json['category'] = category_name
265
+ quark_json['env'] = quark_mode
266
+
267
+ # 写入文件
268
+ File.open(quark_json_file, "w") do |file|
269
+ file.write(JSON.pretty_generate(quark_json))
270
+ end
271
+
272
+ Funlog.instance.fancyinfo_success("Quark 配置完成!")
273
+ return true
274
+
275
+ rescue StandardError => e
276
+ Funlog.instance.fancyinfo_error("Quark 配置失败: #{e.message}")
277
+ puts e.backtrace
278
+ return false
279
+ end
280
+ end
281
+
282
+ # 运行 Swark 授权
283
+ # @param bundle_id [String] Bundle ID
284
+ # @return [Boolean] 是否成功
285
+ def self.swark_authorize_run(bundle_id:)
286
+ require_relative '../../base/funlog'
287
+ require 'pindo/base/git_handler'
288
+ require 'pindo/config/pindoconfig'
289
+
290
+ begin
291
+ Funlog.instance.fancyinfo_start("正在执行 Swark 授权...")
292
+
293
+ pindo_dir = Pindo::Pindoconfig.instance.pindo_dir
294
+ app_config_dir = File.join(File.expand_path(pindo_dir), bundle_id)
295
+ swark_authorize_file = File.join(app_config_dir, "swark_authorize.json")
296
+
297
+ unless File.exist?(swark_authorize_file)
298
+ Funlog.instance.fancyinfo_warning("未找到 swark_authorize.json 文件: #{swark_authorize_file}")
299
+ return false
300
+ end
301
+
302
+ swark_authorize_json = JSON.parse(File.read(swark_authorize_file))
303
+
304
+ # 检查是否已经授权
305
+ if swark_authorize_json && swark_authorize_json['swark_authorize_status']
306
+ Funlog.instance.fancyinfo("Swark 已经授权过了")
307
+ return true
308
+ end
309
+
310
+ # 执行授权命令
311
+ command = "swark authorize "
312
+ command += swark_authorize_json["swark_authorize_teamid"] + "." + swark_authorize_json["swark_authorize_bundleid"]
313
+
314
+ Funlog.instance.fancyinfo("执行命令: #{command}")
315
+ puts
316
+ puts
317
+ puts command
318
+ puts
319
+ system command
320
+
321
+ # 更新授权状态
322
+ swark_authorize_json['swark_authorize_status'] = true
323
+ File.open(swark_authorize_file, "w") do |f|
324
+ f.write(JSON.pretty_generate(swark_authorize_json))
325
+ end
326
+
327
+ # 提交到配置仓库
328
+ Pindo::GitHandler.git_addpush_repo(path: app_config_dir, message: "swark authorize success !!!")
329
+
330
+ Funlog.instance.fancyinfo_success("Swark 授权完成!")
331
+ return true
332
+
333
+ rescue StandardError => e
334
+ Funlog.instance.fancyinfo_error("Swark 授权失败: #{e.message}")
335
+ puts e.backtrace
336
+ return false
337
+ end
338
+ end
339
+
340
+ end
341
+ end
@@ -0,0 +1,268 @@
1
+ require 'singleton'
2
+ require 'json'
3
+ require 'fileutils'
4
+
5
+ module Pindo
6
+ module Options
7
+ # 全局参数状态管理器(单例,简化版)
8
+ # 职责:
9
+ # 1. 管理当前命令的参数状态
10
+ # 2. 管理文件缓存的加载、保存和应用
11
+ class GlobalOptionsState
12
+ include Singleton
13
+
14
+ def initialize
15
+ # 运行时状态(内存)
16
+ @current_command = nil # 当前命令名称
17
+ @current_options = nil # 当前参数配置对象
18
+ @current_directory = nil # 当前项目目录
19
+ @cache_enabled = false # 是否启用缓存
20
+
21
+ # 缓存状态(文件)
22
+ @cache_data = {} # 缓存数据:{ 项目目录 => { 命令 => 参数Hash } }
23
+ @cache_loaded = false # 是否已加载缓存文件
24
+
25
+ # 调试
26
+ @verbose = ENV['PINDO_VERBOSE'] == '1'
27
+
28
+ ensure_cache_dir
29
+ end
30
+
31
+ # ==================== 运行时状态管理 ====================
32
+
33
+ # 准备缓存(在创建 OptionConfiguration 之前调用)
34
+ # @param command_name [String] 命令名称
35
+ # @param directory [String] 项目目录
36
+ def prepare_cache(command_name, directory)
37
+ @current_command = command_name
38
+ @current_directory = directory
39
+ load_cache_from_file
40
+ end
41
+
42
+ # 加载缓存的参数值(带用户确认)
43
+ # @return [Hash] 缓存的参数值
44
+ def load_cached_values
45
+ return {} unless @current_directory && @current_command
46
+
47
+ cached_params = @cache_data.dig(@current_directory.to_sym, @current_command.to_sym)
48
+
49
+ # 没有缓存数据,直接返回空Hash
50
+ unless cached_params && cached_params.is_a?(Hash) && cached_params.any?
51
+ log_verbose("没有找到缓存参数: #{@current_directory} / #{@current_command}")
52
+ return {}
53
+ end
54
+
55
+ # 检查环境变量是否强制使用缓存
56
+ force_build = ENV['PINDO_FORCE_BUILD']
57
+
58
+ if force_build && !force_build.empty?
59
+ # 自动使用缓存
60
+ puts "\n检测到 PINDO_FORCE_BUILD 环境变量,自动使用缓存的参数"
61
+ log_verbose("加载缓存参数: #{cached_params.inspect}")
62
+ return cached_params
63
+ end
64
+
65
+ # 显示缓存的参数
66
+ display_cached_params(cached_params)
67
+
68
+ # 询问用户是否使用缓存
69
+ require 'highline/import'
70
+ cli = HighLine.new
71
+ confirm = cli.agree("\n是否使用以上缓存的参数? (y/n) ")
72
+
73
+ if confirm
74
+ puts "使用缓存的参数\n"
75
+ log_verbose("加载缓存参数: #{cached_params.inspect}")
76
+ cached_params
77
+ else
78
+ puts "清除缓存,使用新参数\n"
79
+ # 清除当前命令的缓存
80
+ clear_current_cache
81
+ {}
82
+ end
83
+ end
84
+
85
+ # 显示缓存的参数
86
+ def display_cached_params(cached_params)
87
+ # 根据命令名显示友好的描述
88
+ group_desc = case @current_command
89
+ when 'ios:autobuild'
90
+ 'iOS 构建'
91
+ when 'and:autobuild', 'android:autobuild'
92
+ 'Android 构建'
93
+ when 'web:autobuild'
94
+ 'Web 构建'
95
+ else
96
+ @current_command
97
+ end
98
+
99
+ puts "\n检测到之前的参数 (#{group_desc}):"
100
+ puts "────────────────────────────────────────"
101
+
102
+ cached_params.each do |key, value|
103
+ # 跳过内部字段
104
+ next if key.to_s.start_with?('__')
105
+ next if value.nil?
106
+
107
+ # 格式化显示参数
108
+ key_name = format_param_name(key)
109
+ puts " #{key_name}: #{value}"
110
+ end
111
+
112
+ puts "────────────────────────────────────────"
113
+ end
114
+
115
+ # 格式化参数名称
116
+ def format_param_name(key)
117
+ case key.to_s
118
+ when 'bundleid', 'bundle_id'
119
+ 'Bundle ID'
120
+ when 'build_type'
121
+ '构建类型'
122
+ when 'upload'
123
+ '上传JPS'
124
+ when 'send'
125
+ '发送通知'
126
+ when 'proj', 'project_name'
127
+ '项目名称'
128
+ when 'scheme'
129
+ 'Scheme'
130
+ else
131
+ key.to_s
132
+ end
133
+ end
134
+
135
+ # 清除当前命令的缓存
136
+ def clear_current_cache
137
+ return unless @current_directory && @current_command
138
+
139
+ if @cache_data[@current_directory.to_sym]
140
+ @cache_data[@current_directory.to_sym].delete(@current_command.to_sym)
141
+
142
+ # 如果项目目录下没有其他命令缓存了,删除整个项目目录
143
+ if @cache_data[@current_directory.to_sym].empty?
144
+ @cache_data.delete(@current_directory.to_sym)
145
+ end
146
+
147
+ # 立即保存到文件
148
+ save_cache_to_file_immediate
149
+ end
150
+ end
151
+
152
+ # 设置当前命令上下文
153
+ # @param command_name [String] 命令名称(如 "ios:autobuild")
154
+ # @param options [OptionConfiguration] 参数配置对象
155
+ # @param directory [String] 项目目录
156
+ # @param enable_cache [Boolean] 是否启用缓存
157
+ def set_command(command_name, options, directory: nil, enable_cache: false)
158
+ @current_command = command_name
159
+ @current_options = options
160
+ @current_directory = directory || Dir.pwd
161
+ @cache_enabled = enable_cache
162
+
163
+ log_verbose("设置命令: #{command_name}")
164
+ log_verbose("项目目录: #{@current_directory}")
165
+ log_verbose("缓存启用: #{@cache_enabled}")
166
+ end
167
+
168
+ # 清除当前命令状态
169
+ def clear
170
+ # 如果启用了缓存,保存当前参数
171
+ save_cache_to_file if @cache_enabled && @current_options
172
+
173
+ @current_command = nil
174
+ @current_options = nil
175
+ @current_directory = nil
176
+ @cache_enabled = false
177
+ end
178
+
179
+ # 访问当前参数值
180
+ # @param key [Symbol] 参数键名
181
+ # @return [Any] 参数值
182
+ def [](key)
183
+ @current_options ? @current_options[key] : nil
184
+ end
185
+
186
+ # 设置当前参数值
187
+ # @param key [Symbol] 参数键名
188
+ # @param value [Any] 参数值
189
+ def []=(key, value)
190
+ @current_options[key] = value if @current_options
191
+ end
192
+
193
+ # ==================== 文件缓存管理 ====================
194
+
195
+ # 缓存文件路径
196
+ def cache_file_path
197
+ File.join(cache_dir, 'options_cache.json')
198
+ end
199
+
200
+ # 缓存目录
201
+ def cache_dir
202
+ File.join(Dir.home, '.pindo', 'cache')
203
+ end
204
+
205
+ # 确保缓存目录存在
206
+ def ensure_cache_dir
207
+ FileUtils.mkdir_p(cache_dir) unless Dir.exist?(cache_dir)
208
+ end
209
+
210
+ # 从文件加载缓存
211
+ def load_cache_from_file
212
+ return if @cache_loaded
213
+
214
+ if File.exist?(cache_file_path)
215
+ begin
216
+ content = File.read(cache_file_path)
217
+ @cache_data = JSON.parse(content, symbolize_names: true)
218
+ log_verbose("加载缓存文件: #{cache_file_path}")
219
+ log_verbose("缓存内容: #{@cache_data.inspect}")
220
+ rescue StandardError => e
221
+ log_verbose("加载缓存文件失败: #{e.message}")
222
+ @cache_data = {}
223
+ end
224
+ else
225
+ log_verbose("缓存文件不存在: #{cache_file_path}")
226
+ end
227
+
228
+ @cache_loaded = true
229
+ end
230
+
231
+ # 保存当前参数到缓存文件
232
+ def save_cache_to_file
233
+ return unless @current_directory && @current_command && @current_options
234
+
235
+ # 确保缓存数据结构存在
236
+ @cache_data[@current_directory.to_sym] ||= {}
237
+
238
+ # 提取当前参数值(排除 nil 值)
239
+ current_params = {}
240
+ @current_options.instance_variable_get(:@values).each do |key, value|
241
+ current_params[key] = value unless value.nil?
242
+ end
243
+
244
+ # 保存到缓存
245
+ @cache_data[@current_directory.to_sym][@current_command.to_sym] = current_params
246
+
247
+ # 写入文件
248
+ save_cache_to_file_immediate
249
+ end
250
+
251
+ # 立即保存缓存数据到文件(内部方法)
252
+ def save_cache_to_file_immediate
253
+ begin
254
+ File.write(cache_file_path, JSON.pretty_generate(@cache_data))
255
+ log_verbose("保存缓存文件: #{cache_file_path}")
256
+ rescue StandardError => e
257
+ log_verbose("保存缓存文件失败: #{e.message}")
258
+ end
259
+ end
260
+
261
+ # ==================== 调试日志 ====================
262
+
263
+ def log_verbose(message)
264
+ puts "[GlobalOptionsState] #{message}" if @verbose
265
+ end
266
+ end
267
+ end
268
+ end