pindo 5.18.6 → 5.18.9
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/command/android/autobuild.rb +15 -2
- data/lib/pindo/command/unity/autobuild.rb +1 -1
- data/lib/pindo/command/utils/gitconfig.rb +268 -0
- data/lib/pindo/command/utils.rb +1 -0
- data/lib/pindo/module/android/android_build_helper.rb +109 -69
- data/lib/pindo/module/android/android_project_helper.rb +88 -0
- data/lib/pindo/module/android/gradle_helper.rb +27 -2
- data/lib/pindo/module/android/keystore_helper.rb +99 -30
- data/lib/pindo/module/android/workflow_gradle_injector.rb +82 -6
- data/lib/pindo/module/task/model/git/git_commit_task.rb +6 -10
- data/lib/pindo/module/task/model/unity/unity_export_task.rb +14 -0
- data/lib/pindo/module/utils/git_hook_helper.rb +284 -0
- data/lib/pindo/options/groups/build_options.rb +0 -33
- data/lib/pindo/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3b74ddb66022968993f331b407f3a50a41d94a827e15e75f75dac1b8d5aadc1
|
|
4
|
+
data.tar.gz: '08c5e2e855359f4369e02cb6cab841d38e3344794a7d4e8f9b0f2695683d1da2'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6c1c36ddcf83fcff151bdd21e8e3104eec862b5c72aa15303a8fe3cae4f9be0dd36f37e2cee24d293e6ace76f895c72f057a18f12485c6d4a08905bb49350e21
|
|
7
|
+
data.tar.gz: 1f3a484ff340bd398d150960753bb541103aca2b5a8ba30e712733c029e209c9fdfcb7db6c2d80b7c1bb1e1c8202d3319600ab12d23c4cb928c3f55c2390e74c
|
|
@@ -96,7 +96,7 @@ module Pindo
|
|
|
96
96
|
# 定义此命令使用的参数项
|
|
97
97
|
def self.option_items
|
|
98
98
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
99
|
-
Pindo::Options::BuildOptions.select(:bundle_name, :release
|
|
99
|
+
Pindo::Options::BuildOptions.select(:bundle_name, :release),
|
|
100
100
|
Pindo::Options::JPSOptions.select(:conf, :upload, :media, :bind, :send),
|
|
101
101
|
Pindo::Options::UnityOptions.select(:skiplib, :skipyoo),
|
|
102
102
|
Pindo::Options::UnityOptions.select_with_defaults(skipmacro: true),
|
|
@@ -147,7 +147,7 @@ module Pindo
|
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
def run
|
|
150
|
-
pindo_project_dir =
|
|
150
|
+
pindo_project_dir = safe_pwd!
|
|
151
151
|
|
|
152
152
|
begin
|
|
153
153
|
# 加载 JPS 配置(缓存 project_name,并通过映射表解析 bundle_id)
|
|
@@ -182,6 +182,19 @@ module Pindo
|
|
|
182
182
|
|
|
183
183
|
private
|
|
184
184
|
|
|
185
|
+
# 有些场景下(例如用户删除了当前所在目录、或 shell 的 cwd 已失效),Dir.pwd 会抛 Errno::ENOENT。
|
|
186
|
+
# 这里做一次兜底:尝试切换到 ENV["PWD"](若可用),否则回退到 HOME,确保命令可继续执行并给出更可理解的行为。
|
|
187
|
+
def safe_pwd!
|
|
188
|
+
Dir.pwd
|
|
189
|
+
rescue Errno::ENOENT
|
|
190
|
+
fallback = ENV["PWD"]
|
|
191
|
+
fallback = nil unless fallback && File.directory?(fallback)
|
|
192
|
+
fallback ||= Dir.home
|
|
193
|
+
|
|
194
|
+
Dir.chdir(fallback)
|
|
195
|
+
Dir.pwd
|
|
196
|
+
end
|
|
197
|
+
|
|
185
198
|
# 解析 bundle_name(优先级:命令行参数 > JPSBuildConfig映射 > prepare_upload交互选择)
|
|
186
199
|
def resolve_bundle_name!
|
|
187
200
|
# 优先级 1:命令行 --bundle_name 参数
|
|
@@ -101,7 +101,7 @@ module Pindo
|
|
|
101
101
|
# 定义此命令使用的参数项
|
|
102
102
|
def self.option_items
|
|
103
103
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
104
|
-
Pindo::Options::BuildOptions.select(:bundleid, :bundle_name, :types, :release, :adhoc
|
|
104
|
+
Pindo::Options::BuildOptions.select(:bundleid, :bundle_name, :types, :release, :adhoc),
|
|
105
105
|
Pindo::Options::JPSOptions.select(:conf, :upload, :send, :media, :bind),
|
|
106
106
|
Pindo::Options::UnityOptions.select(:skiplib, :skipyoo, :kill_unity),
|
|
107
107
|
Pindo::Options::UnityOptions.select_with_defaults(skipmacro: true),
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'highline'
|
|
3
|
+
require 'pindo/base/git_handler'
|
|
4
|
+
require 'pindo/module/utils/git_hook_helper'
|
|
5
|
+
|
|
6
|
+
module Pindo
|
|
7
|
+
class Command
|
|
8
|
+
class Utils < Command
|
|
9
|
+
class Gitconfig < Utils
|
|
10
|
+
|
|
11
|
+
self.summary = '设置 pindo 全局 Git 配置与 commit 变更统计 hook'
|
|
12
|
+
|
|
13
|
+
self.description = <<-DESC
|
|
14
|
+
一次性配置本机全局 Git 环境,使所有 Git 仓库共享同一套 pindo 约定。
|
|
15
|
+
|
|
16
|
+
支持功能:
|
|
17
|
+
|
|
18
|
+
* 设置 Git 用户身份 (交互式):
|
|
19
|
+
- user.name 要求与飞书账号用户名一致,便于团队识别提交人
|
|
20
|
+
- user.email 要求与注册 gitee.com 等代码仓库的邮箱一致
|
|
21
|
+
- 已设置的值会显示当前值并询问是否修改,默认保留
|
|
22
|
+
|
|
23
|
+
* 设置全局 Git 配置:
|
|
24
|
+
- 禁止大小写: core.ignorecase = false
|
|
25
|
+
- 禁止自动 rebase: pull.rebase = false
|
|
26
|
+
- git 缓存内存大小: http.postBuffer = 157286400
|
|
27
|
+
|
|
28
|
+
* 自动安装并配置 git-lfs:
|
|
29
|
+
- 未检测到时通过 Homebrew 自动安装
|
|
30
|
+
- 运行 git lfs install --skip-repo 写全局 filter 配置
|
|
31
|
+
- 通过全局 hook (pre-push / post-checkout / post-commit /
|
|
32
|
+
post-merge) 让 git-lfs 全局生效,无需逐仓库 git lfs install
|
|
33
|
+
- 已知行为: 若仓库本地已有 git lfs install 生成的同名 hook,
|
|
34
|
+
LFS 会被调用两次(LFS 幂等无副作用,但 pre-push 会多一次
|
|
35
|
+
LFS 对象检查耗时; 这是为了保证自定义 hybrid hook 不被吞的
|
|
36
|
+
主动权衡)
|
|
37
|
+
|
|
38
|
+
* 安装全局 commit 变更统计 hook (通过 core.hooksPath):
|
|
39
|
+
- 目标目录: 自适应已有 core.hooksPath,默认 ~/.git-hooks/
|
|
40
|
+
- prepare-commit-msg: 完全接管,自动追加变更统计
|
|
41
|
+
- 27 个转发桩: 4 个 LFS-aware + 23 个纯转发(尊重 foreign 文件)
|
|
42
|
+
|
|
43
|
+
使用示例:
|
|
44
|
+
|
|
45
|
+
$ pindo utils gitconfig
|
|
46
|
+
|
|
47
|
+
撤销方式:
|
|
48
|
+
|
|
49
|
+
$ git config --global --unset core.hooksPath
|
|
50
|
+
$ git config --global --unset core.ignorecase
|
|
51
|
+
$ git config --global --unset pull.rebase
|
|
52
|
+
$ git config --global --unset http.postBuffer
|
|
53
|
+
$ git lfs uninstall --skip-repo
|
|
54
|
+
$ rm -rf ~/.git-hooks
|
|
55
|
+
DESC
|
|
56
|
+
|
|
57
|
+
self.arguments = []
|
|
58
|
+
|
|
59
|
+
# 需要统一设置的全局 Git 配置(按团队约定)
|
|
60
|
+
# value: 目标值 / desc: 中文含义(用于日志输出)
|
|
61
|
+
GLOBAL_CONFIGS = {
|
|
62
|
+
'core.ignorecase' => { value: 'false', desc: '禁止大小写' },
|
|
63
|
+
'pull.rebase' => { value: 'false', desc: '禁止自动rebase' },
|
|
64
|
+
'http.postBuffer' => { value: '157286400', desc: 'git缓存内存大小' },
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
def run
|
|
68
|
+
# --verbose 通过 ENV 向下传递到 GitHookHelper(helper 没有 CLAide 上下文)
|
|
69
|
+
ENV['PINDO_DEBUG'] ||= '1' if pindo_verbose?
|
|
70
|
+
|
|
71
|
+
if pindo_verbose?
|
|
72
|
+
puts ""
|
|
73
|
+
puts "==> pindo utils gitconfig:配置本机全局 Git 环境"
|
|
74
|
+
puts " 共 5 个步骤:用户身份 → Git 配置 → git-lfs 安装 → LFS filter → 全局 hook"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# 汇总 5 项全局 Git 配置,step [1/5] 和 [2/5] 处理完后统一打印
|
|
78
|
+
@final_configs = []
|
|
79
|
+
|
|
80
|
+
step_header(1, "设置 Git 用户身份 (user.name / user.email)")
|
|
81
|
+
setup_git_user_identity
|
|
82
|
+
|
|
83
|
+
step_header(2, "设置全局 Git 配置")
|
|
84
|
+
apply_global_git_configs
|
|
85
|
+
|
|
86
|
+
print_global_configs_summary
|
|
87
|
+
|
|
88
|
+
step_header(3, "检查并安装 git-lfs")
|
|
89
|
+
ensure_git_lfs_installed
|
|
90
|
+
|
|
91
|
+
step_header(4, "配置 git-lfs 全局 filter")
|
|
92
|
+
setup_git_lfs_filters
|
|
93
|
+
|
|
94
|
+
step_header(5, "安装全局 Git hook")
|
|
95
|
+
Pindo::GitHookHelper.share_instance.install_global_commit_stats_hook
|
|
96
|
+
|
|
97
|
+
puts "" if pindo_verbose?
|
|
98
|
+
Funlog.instance.fancyinfo_success("pindo utils gitconfig 全部完成 ✓")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# 打印 [1/5] + [2/5] 共 5 项全局 Git 配置的汇总
|
|
104
|
+
def print_global_configs_summary
|
|
105
|
+
puts ""
|
|
106
|
+
Funlog.instance.fancyinfo_start("全局 Git 配置汇总 (#{@final_configs.size} 项):")
|
|
107
|
+
@final_configs.each do |cfg|
|
|
108
|
+
line = " #{cfg[:desc]}:#{cfg[:key]} = #{cfg[:value]}"
|
|
109
|
+
line += "(#{cfg[:note]})" if cfg[:note]
|
|
110
|
+
if cfg[:status] == :updated
|
|
111
|
+
Funlog.instance.fancyinfo_update(line)
|
|
112
|
+
else
|
|
113
|
+
Funlog.instance.fancyinfo_success(line)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
puts ""
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# verbose 模式:--verbose 或 PINDO_DEBUG 环境变量
|
|
120
|
+
# 用 pindo_ 前缀避免与 CLAide 内部 verbose? 的方法可见性冲突
|
|
121
|
+
def pindo_verbose?
|
|
122
|
+
@verbose || !ENV['PINDO_DEBUG'].to_s.empty?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def step_header(n, title)
|
|
126
|
+
return unless pindo_verbose?
|
|
127
|
+
puts ""
|
|
128
|
+
puts "[#{n}/5] #{title}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def vstart(msg)
|
|
132
|
+
Funlog.instance.fancyinfo_start(msg) if pindo_verbose?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# 检测 git-lfs 是否已安装,未安装时通过 Homebrew 自动安装
|
|
136
|
+
def ensure_git_lfs_installed
|
|
137
|
+
vstart("检查 git-lfs 安装状态...")
|
|
138
|
+
if system('command -v git-lfs > /dev/null 2>&1')
|
|
139
|
+
lfs_version = `git-lfs version 2>/dev/null`.strip
|
|
140
|
+
Funlog.instance.fancyinfo_success("git-lfs 已安装 (#{lfs_version})")
|
|
141
|
+
return
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
Funlog.instance.fancyinfo_warning("未检测到 git-lfs,准备通过 Homebrew 自动安装")
|
|
145
|
+
unless system('command -v brew > /dev/null 2>&1')
|
|
146
|
+
Funlog.instance.fancyinfo_error("Homebrew 未安装,无法自动安装 git-lfs")
|
|
147
|
+
Funlog.instance.fancyinfo_error("请手动安装 git-lfs 后重试: https://git-lfs.com/")
|
|
148
|
+
raise Informative, "git-lfs not installed and brew unavailable"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# 显式关闭 brew auto-update + env hints
|
|
152
|
+
# auto-update 会触发 brew 仓库的 git fetch,在无交互式凭据的环境下
|
|
153
|
+
# (例如 CI、GIT_TERMINAL_PROMPT=0)会卡死或报错,与本次安装无关
|
|
154
|
+
brew_env = {
|
|
155
|
+
'HOMEBREW_NO_AUTO_UPDATE' => '1',
|
|
156
|
+
'HOMEBREW_NO_ENV_HINTS' => '1',
|
|
157
|
+
}
|
|
158
|
+
vstart("执行: HOMEBREW_NO_AUTO_UPDATE=1 brew install git-lfs")
|
|
159
|
+
unless system(brew_env, 'brew', 'install', 'git-lfs')
|
|
160
|
+
Funlog.instance.fancyinfo_error("brew install git-lfs 失败")
|
|
161
|
+
Funlog.instance.fancyinfo_error("请手动执行以上命令排查后重试")
|
|
162
|
+
raise Informative, "brew install git-lfs failed"
|
|
163
|
+
end
|
|
164
|
+
Funlog.instance.fancyinfo_success("git-lfs 已安装")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# 设置 git-lfs 全局 filter 配置(写入 ~/.gitconfig,不触碰任何仓库的 .git/hooks/)
|
|
168
|
+
def setup_git_lfs_filters
|
|
169
|
+
vstart("执行: git lfs install --skip-repo(写入 ~/.gitconfig 的 filter.lfs.* 配置)")
|
|
170
|
+
Pindo::GitHandler.git!(%w(lfs install --skip-repo))
|
|
171
|
+
Funlog.instance.fancyinfo_success("git-lfs filter 已配置")
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# 交互式设置 Git 用户身份 (user.name / user.email)
|
|
175
|
+
# - 已设置 → 显示当前值,询问是否修改(默认 N)
|
|
176
|
+
# - 未设置 → 强制提示,并明确告知命名要求
|
|
177
|
+
def setup_git_user_identity
|
|
178
|
+
ensure_git_user_field(
|
|
179
|
+
key: 'user.name',
|
|
180
|
+
label: 'Git 提交用户名',
|
|
181
|
+
hint: '请确保与飞书账号的用户名保持一致(便于团队识别提交人)',
|
|
182
|
+
prompt: '请输入 Git 提交用户名',
|
|
183
|
+
validator: ->(v) { !v.strip.empty? },
|
|
184
|
+
error_msg: '用户名不能为空'
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
ensure_git_user_field(
|
|
188
|
+
key: 'user.email',
|
|
189
|
+
label: 'Git 提交邮箱',
|
|
190
|
+
hint: '请确保与注册 gitee.com 等代码仓库使用的邮箱一致(否则提交可能无法关联到个人账号)',
|
|
191
|
+
prompt: '请输入 Git 提交邮箱',
|
|
192
|
+
validator: ->(v) { v.strip.match?(/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/) },
|
|
193
|
+
error_msg: '邮箱格式不合法,请输入形如 user@example.com 的地址'
|
|
194
|
+
)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def ensure_git_user_field(key:, label:, hint:, prompt:, validator:, error_msg:)
|
|
198
|
+
current = begin
|
|
199
|
+
Pindo::GitHandler.git!(%W(config --global --get #{key})).strip
|
|
200
|
+
rescue
|
|
201
|
+
''
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if !current.empty?
|
|
205
|
+
cli = HighLine.new
|
|
206
|
+
answer = cli.ask(" 当前#{label}是 #{current},是否修改?[y/N] ")
|
|
207
|
+
unless answer.to_s.strip.downcase.start_with?('y')
|
|
208
|
+
@final_configs << { desc: label, key: key, value: current, status: :kept }
|
|
209
|
+
return
|
|
210
|
+
end
|
|
211
|
+
else
|
|
212
|
+
Funlog.instance.fancyinfo_warning(" 当前#{label}未设置,需要设置")
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
puts ""
|
|
216
|
+
puts " ⚠ #{hint}"
|
|
217
|
+
puts ""
|
|
218
|
+
|
|
219
|
+
new_value = nil
|
|
220
|
+
cli = HighLine.new
|
|
221
|
+
loop do
|
|
222
|
+
new_value = cli.ask(" #{prompt}: ").to_s.strip
|
|
223
|
+
break if validator.call(new_value)
|
|
224
|
+
Funlog.instance.fancyinfo_warning(" #{error_msg}")
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
Pindo::GitHandler.git!(%W(config --global #{key} #{new_value}))
|
|
228
|
+
if current.empty?
|
|
229
|
+
@final_configs << { desc: label, key: key, value: new_value, status: :new, note: '新增' }
|
|
230
|
+
else
|
|
231
|
+
@final_configs << { desc: label, key: key, value: new_value, status: :updated, note: "更新: #{current} → #{new_value}" }
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def apply_global_git_configs
|
|
236
|
+
if pindo_verbose?
|
|
237
|
+
Funlog.instance.fancyinfo_start("即将设置 #{GLOBAL_CONFIGS.size} 项全局 Git 配置(直接覆盖策略):")
|
|
238
|
+
GLOBAL_CONFIGS.each do |key, cfg|
|
|
239
|
+
Funlog.instance.fancyinfo_start(" - #{cfg[:desc]}:#{key} → #{cfg[:value]}")
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
GLOBAL_CONFIGS.each { |key, cfg| ensure_global_config(key, cfg[:value], cfg[:desc]) }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def ensure_global_config(key, expected, desc)
|
|
246
|
+
current = begin
|
|
247
|
+
Pindo::GitHandler.git!(%W(config --global --get #{key})).strip
|
|
248
|
+
rescue
|
|
249
|
+
''
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
if current == expected
|
|
253
|
+
@final_configs << { desc: desc, key: key, value: expected, status: :kept }
|
|
254
|
+
elsif current.empty?
|
|
255
|
+
vstart(" #{desc}:#{key} 未设置,写入 #{expected}")
|
|
256
|
+
Pindo::GitHandler.git!(%W(config --global #{key} #{expected}))
|
|
257
|
+
@final_configs << { desc: desc, key: key, value: expected, status: :new, note: '新增' }
|
|
258
|
+
else
|
|
259
|
+
vstart(" #{desc}:#{key} 当前 #{current},覆盖为 #{expected}")
|
|
260
|
+
Pindo::GitHandler.git!(%W(config --global #{key} #{expected}))
|
|
261
|
+
@final_configs << { desc: desc, key: key, value: expected, status: :updated, note: "覆盖: #{current} → #{expected}" }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
data/lib/pindo/command/utils.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'pindo/command/utils/renewcert'
|
|
|
11
11
|
# require 'pindo/command/utils/copyconfig'
|
|
12
12
|
# require 'pindo/command/utils/allcopyconfig'
|
|
13
13
|
require 'pindo/command/utils/repoinit'
|
|
14
|
+
require 'pindo/command/utils/gitconfig'
|
|
14
15
|
# require 'pindo/command/utils/tag'
|
|
15
16
|
require 'pindo/command/utils/updateconfig'
|
|
16
17
|
require 'pindo/command/utils/fabric'
|
|
@@ -73,16 +73,21 @@ module Pindo
|
|
|
73
73
|
unless build_so_library(unity_dir)
|
|
74
74
|
raise RuntimeError, "编译 Unity 模块 SO 库失败"
|
|
75
75
|
end
|
|
76
|
-
copy_so_files(unity_dir, project_dir)
|
|
77
|
-
validate_unity_libs_state!(project_dir, stage: "导出后")
|
|
78
|
-
|
|
79
|
-
# SO 库拷贝完成后,重新配置主工程的 Java Home 和 Gradle 环境
|
|
80
|
-
puts "Unity SO库编译完成,切换到主工程编译环境"
|
|
81
|
-
Pindo::JavaEnvHelper.setup_java_home_from_project(project_dir, use_main: true)
|
|
82
|
-
Pindo::GradleHelper.check_gradle_with_project(project_dir, configure_main: true)
|
|
83
76
|
else
|
|
84
77
|
puts "未检测到 IL2CPP 目录,可能使用 Mono 后端,跳过 SO 库构建"
|
|
85
78
|
end
|
|
79
|
+
|
|
80
|
+
# 无论 IL2CPP 或 Mono,均需要将 Unity 导出工程的关键产物同步回主工程:
|
|
81
|
+
# - unityLibrary/libs(Java/Kotlin 库)
|
|
82
|
+
# - unityLibrary/src/main/assets(StreamingAssets 等资源)
|
|
83
|
+
# - unityLibrary/src/main/jniLibs(若存在)
|
|
84
|
+
copy_so_files(unity_dir, project_dir)
|
|
85
|
+
validate_unity_libs_state!(project_dir, stage: "导出后")
|
|
86
|
+
|
|
87
|
+
# 同步完成后,重新配置主工程的 Java Home 和 Gradle 环境
|
|
88
|
+
puts "Unity 产物同步完成,切换到主工程编译环境"
|
|
89
|
+
Pindo::JavaEnvHelper.setup_java_home_from_project(project_dir, use_main: true)
|
|
90
|
+
Pindo::GradleHelper.check_gradle_with_project(project_dir, configure_main: true)
|
|
86
91
|
else
|
|
87
92
|
puts "警告:Unity 作为 lib 的工程,但未找到 Unity 目录"
|
|
88
93
|
end
|
|
@@ -101,33 +106,81 @@ module Pindo
|
|
|
101
106
|
build_type = debug ? "debug" : "release"
|
|
102
107
|
raise "bundle_name 不能为空,Keystore 签名需要 Application ID" if bundle_name.nil? || bundle_name.empty?
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if workflow_name && !workflow_name.to_s.empty?
|
|
110
|
-
injector = Pindo::Android::WorkflowGradleInjector.new
|
|
111
|
-
ctx = injector.prepare!(
|
|
112
|
-
project_dir: project_dir,
|
|
113
|
-
workflow_name: workflow_name,
|
|
114
|
-
enable_pad: true
|
|
115
|
-
)
|
|
116
|
-
apk_path = nil
|
|
117
|
-
begin
|
|
118
|
-
apk_path = build_apk(project_dir, debug, workflow_build_type: ctx[:workflow_build_type])
|
|
119
|
-
ensure
|
|
120
|
-
injector.cleanup!(ctx)
|
|
109
|
+
apk_path = nil
|
|
110
|
+
begin
|
|
111
|
+
unless Pindo::KeystoreHelper.apply_keystore_config(project_dir, build_type, bundle_id: bundle_name)
|
|
112
|
+
raise RuntimeError, "Keystore 签名配置失败"
|
|
121
113
|
end
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
puts "✓ Android 签名配置成功"
|
|
115
|
+
|
|
116
|
+
if workflow_name && !workflow_name.to_s.empty?
|
|
117
|
+
pad_persist = pad_persist_enabled?
|
|
118
|
+
|
|
119
|
+
# 永久 PAD:每次构建前清理旧的 *_pack,并从当前导出产物重新生成
|
|
120
|
+
# 注意:PAD 会移动 unityLibrary/src/main/assets 下的目录到 *_pack;
|
|
121
|
+
# 因此要保证在此之前已经把 Unity/ 导出产物同步回主工程(Unity as lib 分支已同步)。
|
|
122
|
+
setup_play_asset_delivery_persistent(project_dir) if pad_persist
|
|
123
|
+
|
|
124
|
+
injector = Pindo::Android::WorkflowGradleInjector.new
|
|
125
|
+
ctx = injector.prepare!(
|
|
126
|
+
project_dir: project_dir,
|
|
127
|
+
workflow_name: workflow_name,
|
|
128
|
+
enable_pad: !pad_persist
|
|
129
|
+
)
|
|
130
|
+
begin
|
|
131
|
+
apk_path = build_apk(project_dir, debug, workflow_build_type: ctx[:workflow_build_type])
|
|
132
|
+
ensure
|
|
133
|
+
injector.cleanup!(ctx)
|
|
134
|
+
Pindo::Android::WorkflowGradleInjector.remove_project_pindo_tmp_dir!(project_dir)
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
# 兼容旧行为:仍会永久写入 PAD 相关变更(如需临时恢复,请传 workflow_name 走注入管线)
|
|
138
|
+
setup_play_asset_delivery(project_dir)
|
|
139
|
+
apk_path = build_apk(project_dir, debug)
|
|
140
|
+
end
|
|
141
|
+
ensure
|
|
142
|
+
# 安全优先:无论成功/失败,均清理本次下载/拷贝到工程 signing/ 的签名文件,并恢复本次改动的 Gradle 签名配置与进程 ENV。
|
|
143
|
+
# 说明:这会降低“失败后保留签名文件便于排查”的便利性,但可以显著降低泄露风险。
|
|
144
|
+
Pindo::KeystoreHelper.cleanup_managed_signing_paths!
|
|
145
|
+
Pindo::KeystoreHelper.restore_managed_signing_config!
|
|
146
|
+
Pindo::KeystoreHelper.cleanup_managed_signing_env!
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private def pad_persist_enabled?
|
|
151
|
+
# 默认开启永久 PAD(避免 workflow 注入管线在 cleanup 时删除 *_pack)
|
|
152
|
+
# 如需回到“临时 PAD(构建结束自动回滚)”,可显式设置:
|
|
153
|
+
# export PINDO_PAD_PERSIST=0
|
|
154
|
+
val = ENV.fetch("PINDO_PAD_PERSIST", nil)
|
|
155
|
+
return true if val.nil?
|
|
156
|
+
|
|
157
|
+
v = val.to_s.strip.downcase
|
|
158
|
+
return true if v.empty?
|
|
159
|
+
return false if %w[0 false no off].include?(v)
|
|
160
|
+
|
|
161
|
+
true
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# 永久 PAD:先清理旧的 *_pack,再从当前 assets 生成新的 pack
|
|
165
|
+
private def setup_play_asset_delivery_persistent(project_dir)
|
|
166
|
+
# 仅 Unity 导出工程才有 unityLibrary/src/main/assets
|
|
167
|
+
unity_assets = File.join(project_dir, "unityLibrary", "src", "main", "assets")
|
|
168
|
+
return unless File.directory?(unity_assets)
|
|
169
|
+
|
|
170
|
+
# 清理旧 pack:避免 assets 内容变化后残留旧 pack 目录导致重复/脏数据
|
|
171
|
+
Dir.glob(File.join(project_dir, "*_pack")).each do |dir|
|
|
172
|
+
next unless File.directory?(dir)
|
|
173
|
+
|
|
174
|
+
# 尽量只删除我们生成的模块:要求 build.gradle 存在且包含 asset-pack 插件
|
|
175
|
+
gradle = File.join(dir, "build.gradle")
|
|
176
|
+
next unless File.file?(gradle)
|
|
177
|
+
content = File.read(gradle)
|
|
178
|
+
next unless content.include?("com.android.asset-pack")
|
|
179
|
+
|
|
180
|
+
FileUtils.rm_rf(dir)
|
|
130
181
|
end
|
|
182
|
+
|
|
183
|
+
setup_play_asset_delivery(project_dir)
|
|
131
184
|
end
|
|
132
185
|
|
|
133
186
|
def build_apk(project_path, debug, workflow_build_type: nil)
|
|
@@ -142,13 +195,6 @@ module Pindo
|
|
|
142
195
|
main_module = Pindo::AndroidProjectHelper.get_main_module(project_path)
|
|
143
196
|
raise ArgumentError, "无法找到主模块" unless main_module
|
|
144
197
|
|
|
145
|
-
keystore_config = Pindo::KeystoreHelper.get_keystore_config_from_project(
|
|
146
|
-
project_path,
|
|
147
|
-
debug,
|
|
148
|
-
workflow_build_type: workflow_build_type
|
|
149
|
-
)
|
|
150
|
-
raise ArgumentError, "无法从 build.gradle 中获取 keystore 信息" unless keystore_config
|
|
151
|
-
|
|
152
198
|
build_tools = Pindo::AndroidProjectHelper.get_build_tools
|
|
153
199
|
unless build_tools
|
|
154
200
|
Funlog.error("无法继续构建:缺少必要的构建工具")
|
|
@@ -209,29 +255,27 @@ module Pindo
|
|
|
209
255
|
end
|
|
210
256
|
# --- END ---
|
|
211
257
|
|
|
212
|
-
# puts "解析 keystore 配置"
|
|
213
|
-
# 与 Gradle 对 storeFile 的生效顺序一致:常见写法为
|
|
214
|
-
# storeFile file(System.getenv("RELEASE_KEYSTORE_PATH") ?: "signing/gxdebug.jks")
|
|
215
|
-
# apply_keystore_config 已在当前进程设置 RELEASE_*,Gradle 打 AAB 时走 ENV 指向的真实 jks;
|
|
216
|
-
# get_keystore_config_from_project 若只解析到 ?: 右侧占位路径,会与 AAB 实际签名不一致且文件可能不存在。
|
|
217
|
-
# 故:当 RELEASE_KEYSTORE_PATH 展开后文件存在时,bundletool 必须使用同一套 RELEASE_*(非「失败回退」)。
|
|
218
258
|
kh = Pindo::KeystoreHelper
|
|
219
259
|
env_ks = ENV[kh::ENV_RELEASE_KEYSTORE_PATH]
|
|
220
260
|
env_ks_abs = env_ks && !env_ks.to_s.empty? ? File.expand_path(env_ks) : nil
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
261
|
+
# 签名信息只允许从环境变量读取,禁止从 build.gradle 解析值作为回退来源。
|
|
262
|
+
# 这样可以避免「环境变量缺失时悄悄退回到 Gradle 文本里的占位/历史明文」导致签名不一致。
|
|
263
|
+
ks = env_ks_abs
|
|
264
|
+
ks_pass = ENV.fetch(kh::ENV_RELEASE_KEYSTORE_PASSWORD, nil)
|
|
265
|
+
key_alias = ENV.fetch(kh::ENV_RELEASE_KEY_ALIAS, nil)
|
|
266
|
+
key_pass = ENV.fetch(kh::ENV_RELEASE_KEY_PASSWORD, nil)
|
|
267
|
+
|
|
268
|
+
missing_env = []
|
|
269
|
+
missing_env << kh::ENV_RELEASE_KEYSTORE_PATH if env_ks_abs.nil? || env_ks_abs.to_s.empty?
|
|
270
|
+
missing_env << kh::ENV_RELEASE_KEYSTORE_PASSWORD if ks_pass.to_s.empty?
|
|
271
|
+
missing_env << kh::ENV_RELEASE_KEY_ALIAS if key_alias.to_s.empty?
|
|
272
|
+
missing_env << kh::ENV_RELEASE_KEY_PASSWORD if key_pass.to_s.empty?
|
|
273
|
+
unless missing_env.empty?
|
|
274
|
+
raise RuntimeError, "缺少 Android release 签名所需环境变量:#{missing_env.join(', ')}"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
unless File.exist?(ks)
|
|
278
|
+
raise RuntimeError, "Keystore 文件不存在: #{ks}"
|
|
235
279
|
end
|
|
236
280
|
|
|
237
281
|
ks_display = ks && !ks.to_s.empty? ? File.expand_path(ks.to_s) : ks.to_s
|
|
@@ -239,7 +283,7 @@ module Pindo
|
|
|
239
283
|
# if workflow_build_type && !workflow_build_type.to_s.empty?
|
|
240
284
|
# puts "[bundletool] workflow buildType: #{workflow_build_type}"
|
|
241
285
|
# end
|
|
242
|
-
# puts "[bundletool] 签名来源:
|
|
286
|
+
# puts "[bundletool] 签名来源: RELEASE_* 环境变量(强制)"
|
|
243
287
|
# puts "[bundletool] keyAlias: #{key_alias.inspect}(口令不落日志)"
|
|
244
288
|
|
|
245
289
|
# 构建 APK
|
|
@@ -270,7 +314,7 @@ module Pindo
|
|
|
270
314
|
end
|
|
271
315
|
|
|
272
316
|
if ks.nil? || ks.to_s.empty?
|
|
273
|
-
raise RuntimeError, "Keystore
|
|
317
|
+
raise RuntimeError, "Keystore 路径为空:未从环境变量获取到 #{Pindo::KeystoreHelper::ENV_RELEASE_KEYSTORE_PATH}"
|
|
274
318
|
end
|
|
275
319
|
|
|
276
320
|
unless File.exist?(ks)
|
|
@@ -314,12 +358,9 @@ module Pindo
|
|
|
314
358
|
end
|
|
315
359
|
|
|
316
360
|
bundle_task = "#{prefix}#{task_name}"
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
puts ' 已跳过 Gradle clean(--skipclean)' if skip_clean
|
|
321
|
-
|
|
322
|
-
gradle_clean_resilient!(project_path) unless skip_clean
|
|
361
|
+
# 任意 bundle 变体(含 debug)均先 clean,避免 aabresguard 等任务因残留输出报「文件已存在」
|
|
362
|
+
puts ' AAB 构建前先执行 Gradle clean'
|
|
363
|
+
gradle_clean_resilient!(project_path)
|
|
323
364
|
|
|
324
365
|
cmd = "cd \"#{project_path}\" && ./gradlew --no-daemon #{bundle_task}"
|
|
325
366
|
system(cmd)
|
|
@@ -440,8 +481,7 @@ module Pindo
|
|
|
440
481
|
def validate_unity_libs_state!(android_root, stage:)
|
|
441
482
|
# 某些项目会将 unityLibrary 作为缓存/中间产物纳入仓库,但 libs 下的 .aar -> .srcaar
|
|
442
483
|
# 符号链接目标是由 EDM4U/导出过程生成,初次拉取代码时可能为断链。
|
|
443
|
-
#
|
|
444
|
-
return if Pindo::Options::GlobalOptionsState.instance[:skipvalidate]
|
|
484
|
+
# 这里必须严格失败,避免后续构建阶段才出现不可读/缺失依赖导致更难定位的问题
|
|
445
485
|
|
|
446
486
|
libs_dir = File.join(android_root, "unityLibrary", "libs")
|
|
447
487
|
return unless File.directory?(libs_dir)
|