pindo 5.1.4 → 5.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5eda913afe12b6e589a0ac3981040fe27b575045a488afb373f1825e548fb53d
4
- data.tar.gz: 660bfab7bec17ed41564c2d925d7fb7014754e421a2db9cc5cf77369a0b41db3
3
+ metadata.gz: eeb5144aeaf56d2e5bafd3484f8217e9e4ce46a54485eb9b2b5d454cfe3c34fe
4
+ data.tar.gz: abf8c96e71101c513b825593aa6627e5252770a31d144afe6803bec6b030cda0
5
5
  SHA512:
6
- metadata.gz: b3712e5cc54bae69dd86d022f1ba73c6e8a1848beb4c09d420e4dd94ce5b9a9d5b96a88acc723525bfb4b3fa3b0bf1ecfa6b7c0567ea6f08fbfd4392c8e554fd
7
- data.tar.gz: 4c8cc257d0ccc1fc5cc475421ab805d98f159a645c88feb81ca8559ebe519fe57ae83f63e152cb1ef46ea057ed325b0f0a671f1caa29e426e9a1f01c04872988
6
+ metadata.gz: 7b01b26770891a88284b6e2c63ed10f9fc22cb13f17038a648655ea856eb6fc9eaf3392032faf991662e2d2ac1c20a3ebe59aa439a339150c8d96f5a0fceda53
7
+ data.tar.gz: 0ddad442cb9c1973230a91931f3d38f4ed6089aab55c65f07661d600ccc9f91dba7950a70ac3ed144af1a7f1f71a80ef5a52c9eaa50301d81f7914efd763d53a
@@ -88,7 +88,7 @@ module Pindo
88
88
 
89
89
  build_helper = Pindo::BuildHelper.share_instance
90
90
  if @args_upload_flag
91
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
91
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
92
92
  if is_need_add_tag
93
93
  Pindo::Command::Dev::Tag::run(tag_action_parms)
94
94
  end
@@ -108,7 +108,7 @@ module Pindo
108
108
  pindo_project_dir = Dir.pwd
109
109
  build_helper = Pindo::BuildHelper.share_instance
110
110
  if @args_upload_flag
111
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
111
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
112
112
  if is_need_add_tag
113
113
  Pindo::Command::Dev::Tag::run(tag_action_parms)
114
114
  end
@@ -214,12 +214,15 @@ module Pindo
214
214
  info_plist_dict = Xcodeproj::Plist.read_from_path(info_plist_path)
215
215
  info_plist_dict["CFBundleURLTypes"] = info_plist_dict["CFBundleURLTypes"] || []
216
216
  # info_plist_dict["CFBundleURLTypes"] 中不存在CFBundleURLName为bundleid的item
217
- if !bundleid_scheme_name.nil? || bundleid_scheme_name.empty? || !info_plist_dict["CFBundleURLTypes"].any? { |item| item["CFBundleURLName"] == bundleid_scheme_name }
217
+ #bundle id去除. 特殊字符串,保留全小写
218
+ bundleid_scheme_valeu = bundleid_scheme_name.gsub(/[^\w\s]/, '').downcase
219
+
220
+ if !bundleid_scheme_name.nil? || bundleid_scheme_name.empty? || !info_plist_dict["CFBundleURLTypes"].any? { |item| item["CFBundleURLName"] == bundleid_scheme_valeu }
218
221
  item0 = {}
219
222
  item0["CFBundleTypeRole"] = "Editor"
220
- item0["CFBundleURLName"] = bundleid_scheme_name
223
+ item0["CFBundleURLName"] = bundleid_scheme_valeu
221
224
  item0["CFBundleURLSchemes"] = []
222
- item0["CFBundleURLSchemes"] << bundleid_scheme_name
225
+ item0["CFBundleURLSchemes"] << bundleid_scheme_valeu
223
226
  info_plist_dict["CFBundleURLTypes"] << item0
224
227
  end
225
228
  Xcodeproj::Plist.write_to_path(info_plist_dict, info_plist_path)
@@ -108,6 +108,7 @@ module Pindo
108
108
  build_helper = Pindo::BuildHelper.share_instance
109
109
 
110
110
  Dir.chdir(current_project_dir)
111
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(current_project_dir)
111
112
  if is_need_add_tag
112
113
  Pindo::Command::Dev::Tag::run(tag_action_parms)
113
114
  end
@@ -78,7 +78,7 @@ module Pindo
78
78
  end
79
79
  build_helper = Pindo::BuildHelper.share_instance
80
80
  if @args_upload_flag
81
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
81
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
82
82
  if is_need_add_tag
83
83
  Pindo::Command::Dev::Tag::run(tag_action_parms)
84
84
  end
@@ -78,9 +78,9 @@ module Pindo
78
78
 
79
79
  if @args_upload_flag
80
80
  build_helper = Pindo::BuildHelper.share_instance
81
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
81
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
82
82
  if is_need_add_tag
83
- Pindo::Command::Dev::Tag::run(tag_action_parms)
83
+ Pindo::Command::Dev::Tag::run(tag_action_parms)
84
84
  end
85
85
  end
86
86
 
@@ -88,7 +88,7 @@ module Pindo
88
88
 
89
89
  build_helper = Pindo::BuildHelper.share_instance
90
90
  if @args_upload_flag
91
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
91
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
92
92
  if is_need_add_tag
93
93
  Pindo::Command::Dev::Tag::run(tag_action_parms)
94
94
  end
@@ -87,9 +87,9 @@ module Pindo
87
87
 
88
88
  if @args_upload_flag
89
89
  build_helper = Pindo::BuildHelper.share_instance
90
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
90
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
91
91
  if is_need_add_tag
92
- Pindo::Command::Dev::Tag::run(tag_action_parms)
92
+ Pindo::Command::Dev::Tag::run(tag_action_parms)
93
93
  end
94
94
  end
95
95
 
@@ -110,9 +110,9 @@ module Pindo
110
110
  build_helper = Pindo::BuildHelper.share_instance
111
111
 
112
112
  if @args_upload_flag
113
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir)
113
+ is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(pindo_project_dir, auto_mode: true)
114
114
  if is_need_add_tag
115
- Pindo::Command::Dev::Tag::run(tag_action_parms)
115
+ Pindo::Command::Dev::Tag::run(tag_action_parms)
116
116
  end
117
117
  end
118
118
 
@@ -43,15 +43,43 @@ module Pindo
43
43
  raise RuntimeError, "找不到 AAB 文件: #{paths[:bundle]}"
44
44
  end
45
45
 
46
- puts "解析 keystore 配置"
46
+ # --- AAB 包体积检测 ---
47
+ aab_size = File.size(paths[:bundle])
48
+ aab_size_mb = (aab_size.to_f / 1024 / 1024).round(2)
49
+ base_size = 0
50
+ base_size_mb = 0
51
+ base_percent = 0
52
+ base_limit_bytes = 194615705 # 185MB
53
+ base_limit_mb = 185
54
+ begin
55
+ # 用 unzip -v 统计 base/ 文件夹压缩体积
56
+ unzip_out = `unzip -v "#{paths[:bundle]}"`
57
+ base_lines = unzip_out.lines.select { |l| l.include?(" base/") }
58
+ base_size = base_lines.map { |l| l.split[2].to_i }.sum
59
+ base_size_mb = (base_size.to_f / 1024 / 1024).round(2)
60
+ base_percent = aab_size > 0 ? ((base_size.to_f * 100) / aab_size).round(2) : 0
61
+ rescue => e
62
+ puts "\e[31mAAB base 文件夹体积检测失败: #{e.message}\e[0m"
63
+ end
64
+ puts "\e[36mAAB 包体积: #{aab_size_mb} MB\e[0m"
65
+ puts "\e[36mbase 文件夹压缩体积: #{base_size_mb} MB (占比 #{base_percent}%)\e[0m"
66
+ if base_size > base_limit_bytes
67
+ puts "\e[41;97m警告: base 文件夹已超出 Google Play 限制(#{base_limit_mb}MB),请优化资源或分包!\e[0m"
68
+ puts "\e[31mAAB 包体积不符合 Google Play 提交标准,需要缩减包体积才能提交!!!\e[0m"
69
+ else
70
+ puts "\e[32mAAB 包体积符合 Google Play 提交标准,可以正常提交\e[0m"
71
+ end
72
+ # --- END ---
73
+
74
+ # puts "解析 keystore 配置"
47
75
  ks = keystore_config[:store_file]
48
- puts "读取 keystore path = #{ks}"
76
+ # puts "读取 keystore path = #{ks}"
49
77
  ks_pass = keystore_config[:store_password]
50
- puts "读取 keystore pass = #{ks_pass}"
78
+ # puts "读取 keystore pass = #{ks_pass}"
51
79
  key_alias = keystore_config[:key_alias]
52
- puts "读取 key alias = #{key_alias}"
80
+ # puts "读取 key alias = #{key_alias}"
53
81
  key_pass = keystore_config[:key_password]
54
- puts "读取 key pass = #{key_pass}"
82
+ # puts "读取 key pass = #{key_pass}"
55
83
 
56
84
  # 构建 APK
57
85
  bundletool_cmd = [
@@ -67,17 +67,34 @@ module Pindo
67
67
 
68
68
  def get_main_module(project_path)
69
69
  settings_gradle_path = File.join(project_path, "settings.gradle")
70
- return nil unless File.exist?(settings_gradle_path)
70
+ settings_gradle_kts_path = File.join(project_path, "settings.gradle.kts")
71
+
72
+ # 优先使用 settings.gradle.kts,如果不存在则使用 settings.gradle
73
+ if File.exist?(settings_gradle_kts_path)
74
+ settings_gradle_path = settings_gradle_kts_path
75
+ elsif !File.exist?(settings_gradle_path)
76
+ return nil
77
+ end
71
78
 
72
79
  content = File.read(settings_gradle_path)
73
- modules = content.scan(/include\s+['"]([^'"]+)['"]/).flatten
80
+ # 兼容 include ':app' 和 include(":app")
81
+ modules = content.scan(/include\s*\(?\s*['\"]?([:\w\-]+)['\"]?\s*\)?/).flatten
74
82
 
75
83
  main_module = modules.find do |m|
76
84
  module_name = m.split(':').last
77
85
  gradle_path = File.join(project_path, module_name, "build.gradle")
86
+ gradle_kts_path = File.join(project_path, module_name, "build.gradle.kts")
87
+
88
+ # 优先使用 build.gradle.kts,如果不存在则使用 build.gradle
89
+ if File.exist?(gradle_kts_path)
90
+ gradle_path = gradle_kts_path
91
+ end
92
+
78
93
  if File.exist?(gradle_path)
79
- File.read(gradle_path).include?("apply plugin: 'com.android.application'") ||
80
- File.read(gradle_path).include?("id 'com.android.application'")
94
+ gradle_content = File.read(gradle_path)
95
+ gradle_content.include?("apply plugin: 'com.android.application") ||
96
+ gradle_content.include?("id 'com.android.application") ||
97
+ (gradle_content.include?("plugins {") && gradle_content.include?("com.android.application"))
81
98
  end
82
99
  end
83
100
  return nil unless main_module
@@ -90,153 +107,225 @@ module Pindo
90
107
  main_module = get_main_module(project_path)
91
108
  return nil unless main_module
92
109
 
93
- gradle_path = File.join(main_module, "build.gradle")
94
- return nil unless File.exist?(gradle_path)
110
+ gradle_kts_path = File.join(main_module, "build.gradle.kts")
111
+ gradle_path = File.join(main_module, "build.gradle")
112
+
113
+ if File.exist?(gradle_kts_path)
114
+ puts "KTS 项目,读取 #{File.basename(gradle_kts_path)} 文件"
115
+ get_keystore_config_kts(gradle_kts_path, project_path, debug)
116
+ elsif File.exist?(gradle_path)
117
+ puts "Groovy 项目,读取 #{File.basename(gradle_path)} 文件"
118
+ get_keystore_config_groovy(gradle_path, project_path, debug)
119
+ else
120
+ puts "未找到 build.gradle 或 build.gradle.kts 文件"
121
+ nil
122
+ end
123
+ end
124
+
125
+ # 处理 Kotlin DSL (build.gradle.kts)
126
+ def get_keystore_config_kts(gradle_kts_path, project_path, debug)
127
+ content = File.read(gradle_kts_path)
128
+ puts "读取 #{File.basename(gradle_kts_path)} 文件"
129
+ signing_configs_block = extract_signing_configs_kts(content)
130
+ # puts "==== signingConfigs block ===="
131
+ # puts signing_configs_block
132
+ # puts "==============================" if signing_configs_block
133
+ return nil unless signing_configs_block
134
+
135
+ config_type = debug ? 'debug' : 'release'
136
+ config_block = extract_config_block_kts(signing_configs_block, config_type)
137
+ # puts "==== config_block ===="
138
+ # puts config_block
139
+ # puts "=====================" if config_block
140
+ return nil unless config_block
141
+
142
+ config_block = remove_kts_comments(config_block)
143
+ ext_values = get_ext_values(project_path)
144
+ store_file, store_password, key_alias, key_password = extract_keystore_fields_kts(config_block, ext_values)
145
+ store_file = fix_store_file_path(store_file, project_path)
146
+ keystore_config = {
147
+ store_file: store_file,
148
+ store_password: store_password,
149
+ key_alias: key_alias,
150
+ key_password: key_password
151
+ }
152
+ if keystore_config.values.any?(&:nil?)
153
+ puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
154
+ end
155
+ keystore_config
156
+ end
95
157
 
158
+ # 处理 Groovy DSL (build.gradle)
159
+ def get_keystore_config_groovy(gradle_path, project_path, debug)
96
160
  content = File.read(gradle_path)
161
+ puts "读取 #{File.basename(gradle_path)} 文件"
162
+ signing_configs_block = extract_signing_configs_groovy(content)
163
+ # puts "==== signingConfigs block ===="
164
+ # puts signing_configs_block
165
+ # puts "==============================" if signing_configs_block
166
+ return nil unless signing_configs_block
97
167
 
98
- # 直接读取整个文件内容,不使用正则表达式截取 android
99
- puts "读取 build.gradle 文件"
168
+ config_type = debug ? 'debug' : 'release'
169
+ config_block = extract_config_block_groovy(signing_configs_block, config_type)
170
+ # puts "==== config_block ===="
171
+ # puts config_block
172
+ # puts "=====================" if config_block
173
+ return nil unless config_block
174
+
175
+ config_block = remove_groovy_comments(config_block)
176
+ ext_values = get_ext_values(project_path)
177
+ store_file, store_password, key_alias, key_password = extract_keystore_fields_groovy(config_block, ext_values)
178
+ store_file = fix_store_file_path(store_file, project_path)
179
+ keystore_config = {
180
+ store_file: store_file,
181
+ store_password: store_password,
182
+ key_alias: key_alias,
183
+ key_password: key_password
184
+ }
185
+ if keystore_config.values.any?(&:nil?)
186
+ puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
187
+ end
188
+ keystore_config
189
+ end
100
190
 
101
- # 查找 signingConfigs 块的开始和结束位置
102
- signing_configs_start = content.index(/signingConfigs\s*\{/)
103
- return nil unless signing_configs_start
191
+ # --- 工具方法 ---
192
+ def extract_signing_configs_kts(content)
193
+ # 提取 signingConfigs { ... },支持多层嵌套
194
+ match = content.match(/signingConfigs\s*\{([\s\S]*?)^\}/m)
195
+ match ? match[1] : nil
196
+ end
104
197
 
105
- # 从开始位置查找匹配的闭合大括号
106
- open_braces = 0
107
- signing_configs_end = nil
198
+ def extract_signing_configs_groovy(content)
199
+ # 提取 signingConfigs { ... },支持多层嵌套
200
+ match = content.match(/signingConfigs\s*\{([\s\S]*?)^\}/m)
201
+ match ? match[1] : nil
202
+ end
108
203
 
109
- content[signing_configs_start..-1].each_char.with_index do |char, i|
110
- if char == '{'
111
- open_braces += 1
112
- elsif char == '}'
113
- open_braces -= 1
114
- if open_braces == 0
115
- signing_configs_end = signing_configs_start + i
204
+ def extract_config_block_kts(signing_configs_block, config_type)
205
+ # 支持 create("xxx") { ... }
206
+ all_blocks = signing_configs_block.scan(/create\(["']?([A-Za-z0-9_]+)["']?\)\s*\{([\s\S]*?)^\s*\}/m)
207
+ # 优先 release/debug/Android_Sign/自定义名
208
+ priority_names = [config_type, "Android_Sign", "release", "debug"]
209
+ config_block = nil
210
+ priority_names.each do |name|
211
+ block = all_blocks.find { |n, b| n == name && b.include?("storeFile") }
212
+ if block
213
+ config_block = block[1]
214
+ break
215
+ end
216
+ end
217
+ # 没找到就取第一个有 storeFile 的块
218
+ if config_block.nil?
219
+ all_blocks.each do |name, block|
220
+ if block.include?("storeFile")
221
+ config_block = block
116
222
  break
117
223
  end
118
224
  end
119
225
  end
226
+ config_block
227
+ end
120
228
 
121
- return nil unless signing_configs_end
122
-
123
- # 提取完整的 signingConfigs 块
124
- signing_configs_block = content[signing_configs_start..signing_configs_end]
125
-
126
-
127
- # 查找配置名称,如 Android_Sign
128
- config_name_match = signing_configs_block.match(/signingConfigs\s*\{\s*(\w+)\s*\{/)
129
- config_name = config_name_match ? config_name_match[1] : nil
130
- return nil unless config_name
131
-
132
- # 检查 buildTypes 中使用的签名配置
133
- config_type = debug ? 'debug' : 'release'
134
- build_type_match = content.match(/buildTypes\s*\{.*?#{config_type}\s*\{(.*?)}/m)
135
- if build_type_match && build_type_match[1] =~ /signingConfig\s+signingConfigs\.(\w+)/
136
- config_name = $1
229
+ def extract_config_block_groovy(signing_configs_block, config_type)
230
+ # 支持 xxx { ... }
231
+ all_blocks = signing_configs_block.scan(/([A-Za-z0-9_]+)\s*\{([\s\S]*?)^\s*\}/m)
232
+ priority_names = [config_type, "Android_Sign", "release", "debug"]
233
+ config_block = nil
234
+ priority_names.each do |name|
235
+ block = all_blocks.find { |n, b| n == name && b.include?("storeFile") }
236
+ if block
237
+ config_block = block[1]
238
+ break
239
+ end
137
240
  end
138
-
139
- # 提取特定配置块的内容
140
- config_start = signing_configs_block.index(/#{config_name}\s*\{/)
141
- return nil unless config_start
142
-
143
- # 从配置开始位置查找匹配的闭合大括号
144
- open_braces = 0
145
- config_end = nil
146
-
147
- signing_configs_block[config_start..-1].each_char.with_index do |char, i|
148
- if char == '{'
149
- open_braces += 1
150
- elsif char == '}'
151
- open_braces -= 1
152
- if open_braces == 0
153
- config_end = config_start + i
241
+ if config_block.nil?
242
+ all_blocks.each do |name, block|
243
+ if block.include?("storeFile")
244
+ config_block = block
154
245
  break
155
246
  end
156
247
  end
157
248
  end
249
+ config_block
250
+ end
158
251
 
159
- return nil unless config_end
160
-
161
- # 提取完整的配置块
162
- config_block = signing_configs_block[config_start..config_end]
163
-
164
- puts "解析 signing config:"
165
- puts "=" * 50
166
- puts config_block
167
- puts "=" * 50
168
-
169
- # 从配置块中提取各项参数
170
- store_file_match = config_block.match(/storeFile\s+file\(["']?\${([^}]+)}["']?\)/m)
171
- store_password_match = config_block.match(/storePassword\s+["']?\${([^}]+)}["']?/m)
172
- key_alias_match = config_block.match(/keyAlias\s+["']?\${([^}]+)}["']?/m)
173
- key_password_match = config_block.match(/keyPassword\s+["']?\${([^}]+)}["']?/m)
174
-
175
- # 如果使用了外部变量,尝试从 ext_signing.gradle 或其他配置文件中获取实际值
176
- if store_file_match || store_password_match || key_alias_match || key_password_match
177
- ext_values = get_ext_values(project_path)
178
- puts "尝试从 ext values 中获取"
179
-
180
- # 获取 store_file 并处理 $rootDir 路径
181
- store_file = store_file_match ? ext_values[store_file_match[1]] : nil
182
- if store_file && store_file.include?('$rootDir')
183
- # 替换 $rootDir 为项目根目录的绝对路径
184
- # 查找项目根目录(包含settings.gradle的目录)
185
- root_dir = project_path
186
- while root_dir && !File.exist?(File.join(root_dir, "settings.gradle"))
187
- parent_dir = File.dirname(root_dir)
188
- # 防止无限循环
189
- break if parent_dir == root_dir
190
- root_dir = parent_dir
191
- end
252
+ def remove_kts_comments(block)
253
+ # 去除 // 注释
254
+ block.lines.reject { |line| line.strip.start_with?("//") }.join
255
+ end
192
256
 
193
- store_file = store_file.gsub('$rootDir', root_dir)
194
- puts "处理后的 store_file 路径: #{store_file}"
195
- end
257
+ def remove_groovy_comments(block)
258
+ # 去除 // /* ... */ 注释
259
+ block = block.gsub(/\/\*[\s\S]*?\*\//, "")
260
+ block.lines.reject { |line| line.strip.start_with?("//") }.join
261
+ end
196
262
 
197
- keystore_config = {
198
- store_file: store_file,
199
- store_password: store_password_match ? ext_values[store_password_match[1]] : nil,
200
- key_alias: key_alias_match ? ext_values[key_alias_match[1]] : nil,
201
- key_password: key_password_match ? ext_values[key_password_match[1]] : nil
202
- }
263
+ # 通用字段递归解析
264
+ def extract_keystore_fields_common(fields, ext_values)
265
+ fields.map { |val| extract_var_or_value(val, ext_values) }
266
+ end
203
267
 
204
- # 确保所有值都不为 nil
205
- if keystore_config.values.any?(&:nil?)
206
- puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
207
- end
268
+ def extract_keystore_fields_groovy(config_block, ext_values)
269
+ # 只处理 groovy 语法
270
+ store_file = config_block[/storeFile\s+file\(["']?([^\)"']+)["']?\)/, 1]
271
+ store_password = config_block[/storePassword\s+["']?([^\)"']+)["']?/, 1]
272
+ key_alias = config_block[/keyAlias\s+["']?([^\)"']+)["']?/, 1]
273
+ key_password = config_block[/keyPassword\s+["']?([^\)"']+)["']?/, 1]
274
+ extract_keystore_fields_common([store_file, store_password, key_alias, key_password], ext_values)
275
+ end
208
276
 
209
- return keystore_config
277
+ def extract_keystore_fields_kts(config_block, ext_values)
278
+ # 只处理 kts 语法
279
+ store_file = config_block[/storeFile\s*=\s*file\(["']?([^\)"']+)["']?\)/, 1] ||
280
+ config_block[/storeFile\s*=\s*rootProject\.file\(["']?([^\)"']+)["']?\)/, 1]
281
+ store_password = config_block[/storePassword\s*=\s*["']?([^\)"']+)["']?/, 1]
282
+ key_alias = config_block[/keyAlias\s*=\s*["']?([^\)"']+)["']?/, 1]
283
+ key_password = config_block[/keyPassword\s*=\s*["']?([^\)"']+)["']?/, 1]
284
+ extract_keystore_fields_common([store_file, store_password, key_alias, key_password], ext_values)
285
+ end
286
+
287
+ def extract_var_or_value(val, ext_values, depth=0)
288
+ return nil if val.nil? || val.empty? || depth > 5
289
+ # 匹配 ${KEY}、$KEY、"${KEY}"、'${KEY}'
290
+ if val =~ /^\$\{?([A-Za-z0-9_]+)\}?$/
291
+ key = $1
292
+ v = ext_values[key]
293
+ v ? extract_var_or_value(v, ext_values, depth+1) : nil
294
+ elsif val =~ /^"?\$\{([A-Za-z0-9_]+)\}"?$/
295
+ key = $1
296
+ v = ext_values[key]
297
+ v ? extract_var_or_value(v, ext_values, depth+1) : nil
210
298
  else
211
- # 直接从配置块中提取硬编码的值
212
- store_file = config_block.match(/storeFile\s+file\(['"]([^'"]+)['"]\)/m)&.[](1)
213
- store_password = config_block.match(/storePassword\s+['"]([^'"]+)['"]/m)&.[](1)
214
- key_alias = config_block.match(/keyAlias\s+['"]([^'"]+)['"]/m)&.[](1)
215
- key_password = config_block.match(/keyPassword\s+['"]([^'"]+)['"]/m)&.[](1)
216
-
217
- keystore_config = {
218
- store_file: store_file,
219
- store_password: store_password,
220
- key_alias: key_alias,
221
- key_password: key_password
222
- }
223
-
224
- # 确保所有值都不为 nil
225
- if keystore_config.values.any?(&:nil?)
226
- puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
227
- end
299
+ val
300
+ end
301
+ end
228
302
 
229
- return keystore_config
303
+ def resolve_var(val, ext_values, depth=0)
304
+ return val if val.nil? || depth > 5
305
+ if ext_values[val]
306
+ resolve_var(ext_values[val], ext_values, depth+1)
307
+ else
308
+ val
230
309
  end
231
310
  end
232
311
 
312
+ def fix_store_file_path(store_file, project_path)
313
+ return nil if store_file.nil? || store_file.empty?
314
+ # 兼容 $rootDir、${rootDir}、project.rootDir、rootProject.file
315
+ store_file = store_file.gsub(/^\$?\{?rootDir\}?\/?/, project_path + "/")
316
+ store_file = store_file.gsub(/^project\.rootDir\/?/, project_path + "/")
317
+ store_file = store_file.gsub(/^rootProject\.file\(['"](.+?)['"]\)/, project_path + '/\\1')
318
+ store_file = File.expand_path(store_file, project_path) unless File.exist?(store_file)
319
+ store_file
320
+ end
321
+
233
322
  # 新增方法:从 ext 配置文件中获取变量值
234
323
  def get_ext_values(project_path)
235
324
  ext_values = {}
236
325
 
237
- # 查找可能的 ext 配置文件
238
326
  ext_files = [
239
327
  File.join(project_path, "buildScripts/cfg/ext_signing.gradle"),
328
+ File.join(project_path, "buildScripts/cfg/ext_signing.gradle.kts"),
240
329
  File.join(project_path, "gradle.properties"),
241
330
  File.join(project_path, "local.properties")
242
331
  ]
@@ -246,13 +335,18 @@ module Pindo
246
335
 
247
336
  content = File.read(file_path)
248
337
 
249
- # 解析 ext.KEY = "VALUE" 格式
338
+ # 支持 ext.KEY = "VALUE"
250
339
  content.scan(/ext\.(\w+)\s*=\s*["']([^"']+)["']/m).each do |key, value|
251
340
  ext_values[key] = value
252
341
  end
253
342
 
254
- # 解析 KEY=VALUE 格式
255
- content.scan(/^(\w+)\s*=\s*["']?([^"'\n]+)["']?/m).each do |key, value|
343
+ # 支持 ext["KEY"] = "VALUE"
344
+ content.scan(/ext\[\s*["'](\w+)["']\s*\]\s*=\s*["']([^"']+)["']/m).each do |key, value|
345
+ ext_values[key] = value
346
+ end
347
+
348
+ # 支持 KEY = "VALUE"
349
+ content.scan(/^(\w+)\s*=\s*["']([^"']+)["']/m).each do |key, value|
256
350
  ext_values[key] = value
257
351
  end
258
352
  end
@@ -265,9 +359,14 @@ module Pindo
265
359
  unity_library_path = File.join(project_path, "unityLibrary")
266
360
  return false unless File.directory?(unity_library_path)
267
361
 
268
- # 检查 unityLibrary 的 build.gradle 是否存在
362
+ # 检查 unityLibrary 的 build.gradle 或 build.gradle.kts 是否存在
269
363
  unity_gradle_path = File.join(unity_library_path, "build.gradle")
270
- return false unless File.exist?(unity_gradle_path)
364
+ unity_gradle_kts_path = File.join(unity_library_path, "build.gradle.kts")
365
+ if File.exist?(unity_gradle_kts_path)
366
+ unity_gradle_path = unity_gradle_kts_path
367
+ elsif !File.exist?(unity_gradle_path)
368
+ return false
369
+ end
271
370
 
272
371
  # 检查 build.gradle 中是否包含 Unity 特有的配置
273
372
  content = File.read(unity_gradle_path)
@@ -153,13 +153,13 @@ module Pindo
153
153
  keystore_config = get_keystore_config(project_path, debug)
154
154
 
155
155
  ks = keystore_config[:store_file]
156
- puts "读取 keystore path = #{ks}"
156
+ # puts "读取 keystore path = #{ks}"
157
157
  ks_pass = keystore_config[:store_password]
158
- puts "读取 keystore pass = #{ks_pass}"
158
+ # puts "读取 keystore pass = #{ks_pass}"
159
159
  key_alias = keystore_config[:key_alias]
160
- puts "读取 key alias = #{key_alias}"
160
+ # puts "读取 key alias = #{key_alias}"
161
161
  key_pass = keystore_config[:key_password]
162
- puts "读取 key pass = #{key_pass}"
162
+ # puts "读取 key pass = #{key_pass}"
163
163
  end
164
164
 
165
165
  private
@@ -28,8 +28,17 @@ module Pindo
28
28
  end
29
29
 
30
30
  def update_build_gradle(project_path)
31
- # 更新build.gradle
31
+ # 更新build.gradle 或 build.gradle.kts
32
32
  build_gradle_path = File.join(project_path, "build.gradle")
33
+ build_gradle_kts_path = File.join(project_path, "build.gradle.kts")
34
+
35
+ # 优先使用 build.gradle.kts,如果不存在则使用 build.gradle
36
+ if File.exist?(build_gradle_kts_path)
37
+ build_gradle_path = build_gradle_kts_path
38
+ elsif !File.exist?(build_gradle_path)
39
+ return
40
+ end
41
+
33
42
  content = File.read(build_gradle_path)
34
43
  content.gsub!("classpath 'com.android.tools.build:gradle:4.0.1'",
35
44
  "classpath 'com.android.tools.build:gradle:4.2.2'")
@@ -124,7 +124,7 @@ module Pindo
124
124
  end
125
125
 
126
126
 
127
- def check_is_need_add_tag?(project_path)
127
+ def check_is_need_add_tag?(project_path, auto_mode: false)
128
128
  tag_action_parms = nil
129
129
  is_need_add_tag = false
130
130
 
@@ -133,36 +133,43 @@ module Pindo
133
133
  latest_tag = get_latest_version_tag(project_dir: current_git_root_path)
134
134
 
135
135
  unless is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
136
- cli = HighLine.new
137
- menu_options = {
138
- "新增版本号,打新Tag" => -> {
139
- tag_action_parms = []
140
- :new_tag
141
- },
142
- "将上次的Tag删除重新打Tag" => -> {
143
- tag_action_parms = []
144
- tag_action_parms << "--retag"
145
- :recreate_tag
146
- },
147
- "不需要Tag继续编译且上传,手动修改上传备注" => -> {
148
- puts ""
149
- :continue_without_tag
150
- },
151
- "终止退出编译" => -> {
152
- raise Informative, "终止退出编译!"
153
- :exit
136
+ if auto_mode || !$stdin.tty?
137
+ # 在自动化模式或没有交互式终端时,默认选择新增版本号打新Tag
138
+ puts "检测到当前代码没有打Tag,在自动模式下将自动新增版本号并打新Tag"
139
+ tag_action_parms = []
140
+ is_need_add_tag = false
141
+ else
142
+ cli = HighLine.new
143
+ menu_options = {
144
+ "新增版本号,打新Tag" => -> {
145
+ tag_action_parms = []
146
+ :new_tag
147
+ },
148
+ "将上次的Tag删除重新打Tag" => -> {
149
+ tag_action_parms = []
150
+ tag_action_parms << "--retag"
151
+ :recreate_tag
152
+ },
153
+ "不需要Tag继续编译且上传,手动修改上传备注" => -> {
154
+ puts ""
155
+ :continue_without_tag
156
+ },
157
+ "终止退出编译" => -> {
158
+ raise Informative, "终止退出编译!"
159
+ :exit
160
+ }
154
161
  }
155
- }
156
162
 
157
- result = cli.choose do |menu|
158
- menu.header = "当前代码并没有打Tag,上传的Changelog需要Tag"
159
- menu.prompt = "请选中打Tag的方式, 请输入选项(1/2/3...):"
160
- menu_options.each do |option, action|
161
- menu.choice(option) { action.call }
163
+ result = cli.choose do |menu|
164
+ menu.header = "当前代码并没有打Tag,上传的Changelog需要Tag"
165
+ menu.prompt = "请选中打Tag的方式, 请输入选项(1/2/3...):"
166
+ menu_options.each do |option, action|
167
+ menu.choice(option) { action.call }
168
+ end
162
169
  end
163
- end
164
170
 
165
- is_need_add_tag = !tag_action_parms.nil?
171
+ is_need_add_tag = !tag_action_parms.nil?
172
+ end
166
173
  end
167
174
  end
168
175
 
data/lib/pindo/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Pindo
2
2
 
3
- VERSION = "5.1.4"
3
+ VERSION = "5.1.6"
4
4
 
5
5
  class VersionCheck
6
6
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pindo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.4
4
+ version: 5.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-06-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: claide
@@ -453,7 +453,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
453
453
  - !ruby/object:Gem::Version
454
454
  version: '0'
455
455
  requirements: []
456
- rubygems_version: 3.6.3
456
+ rubygems_version: 3.6.9
457
457
  specification_version: 3
458
458
  summary: easy work
459
459
  test_files: []