pindo 5.18.12 → 5.18.17

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: 2f12654249c9833d657aadadbc44e7e7b749dbd590018855ddc196776dd21d85
4
- data.tar.gz: 0bc9ef08ddfaefeeca63cb52380eace72853a9201e1abd828e5100b5de12cba0
3
+ metadata.gz: 6c4f5555594146ac02e8057cc535c1233b2c81b5204e6807a021744e9eeafd8b
4
+ data.tar.gz: 1ad745131de6737f27c1c419253bf4dabc2c704cb2440f70ca7ad660d902b989
5
5
  SHA512:
6
- metadata.gz: 3a70f8ef90da1b660e40c0c1d84a56c2701fc541e8c932ac5facf224f3df59b4902cb45e5af246dfa492b311e3aa65d9cd9265d741fd2e514933a97c3dffe125
7
- data.tar.gz: 6b867becf5698dcfec5b87c4cf5cb302b3c3292a0abe8d5bd890f69e15dd00abb2c63de3d461d5ca9e2cc1cb953050a0bb37f1558c7b01de25793764dbea22c2
6
+ metadata.gz: 0c505ba3e2a3f0c7bb74e6f57e588eeca6ab50844104abb98c4f02e6e676e584069135841f0793c951a0cc47c218e0d4b791c116ac5bffb7cc76437df9947218
7
+ data.tar.gz: f0635784ade7e61a8b623238da8d60b04d221ceafb5312fea289063a065596db37aba8e6a67fe0210b4ece19e98d713d22fffd202805b4c530002f395265011c
@@ -110,19 +110,27 @@ module Pindo
110
110
 
111
111
  apk_path = nil
112
112
  begin
113
+ # PAD 必须在签名注入之前完成,保证:
114
+ # 1) Keystore 的 Gradle 快照登记时 launcher/build.gradle 已含 assetPacks;
115
+ # 2) restore_managed_signing_config! 构建结束后恢复的是"含 assetPacks、不含签名改动"的干净状态。
116
+ has_workflow = workflow_name && !workflow_name.to_s.empty?
117
+ pad_persist = pad_persist_enabled?
118
+
119
+ if has_workflow && pad_persist
120
+ # 永久 PAD:清理旧 *_pack 并从当前 assets 重建;无可拆分资源则仅幂等补写引用
121
+ setup_play_asset_delivery_persistent(project_dir)
122
+ elsif !has_workflow
123
+ # 兼容旧行为:非 workflow 场景仍在构建前做一次 PAD(永久写入)
124
+ setup_play_asset_delivery(project_dir)
125
+ end
126
+ # 注:has_workflow && !pad_persist(临时 PAD)由 injector.prepare!(enable_pad: true) 内部处理
127
+
113
128
  unless Pindo::KeystoreHelper.apply_keystore_config(project_dir, build_type, bundle_id: bundle_name)
114
129
  raise RuntimeError, "Keystore 签名配置失败"
115
130
  end
116
131
  puts "✓ Android 签名配置成功"
117
132
 
118
- if workflow_name && !workflow_name.to_s.empty?
119
- pad_persist = pad_persist_enabled?
120
-
121
- # 永久 PAD:每次构建前清理旧的 *_pack,并从当前导出产物重新生成
122
- # 注意:PAD 会移动 unityLibrary/src/main/assets 下的目录到 *_pack;
123
- # 因此要保证在此之前已经把 Unity/ 导出产物同步回主工程(Unity as lib 分支已同步)。
124
- setup_play_asset_delivery_persistent(project_dir) if pad_persist
125
-
133
+ if has_workflow
126
134
  injector = Pindo::Android::WorkflowGradleInjector.new
127
135
  ctx = injector.prepare!(
128
136
  project_dir: project_dir,
@@ -136,8 +144,6 @@ module Pindo
136
144
  Pindo::Android::WorkflowGradleInjector.remove_project_pindo_tmp_dir!(project_dir)
137
145
  end
138
146
  else
139
- # 兼容旧行为:仍会永久写入 PAD 相关变更(如需临时恢复,请传 workflow_name 走注入管线)
140
- setup_play_asset_delivery(project_dir)
141
147
  apk_path = build_apk(project_dir, debug)
142
148
  end
143
149
  ensure
@@ -163,17 +169,43 @@ module Pindo
163
169
  true
164
170
  end
165
171
 
166
- # 永久 PAD:先清理旧的 *_pack,再从当前 assets 生成新的 pack
172
+ # 永久 PAD:仅当 assets 中存在可拆分资源时,才清理旧 *_pack 并重新生成;
173
+ # 若无可拆分资源但工程已有 *_pack 模块,则幂等补写 settings.gradle / launcher/build.gradle 的引用,
174
+ # 避免 Unity 重新导出覆盖 launcher/build.gradle 导致 assetPacks 丢失。
167
175
  private def setup_play_asset_delivery_persistent(project_dir)
168
- # 仅 Unity 导出工程才有 unityLibrary/src/main/assets
169
176
  unity_assets = File.join(project_dir, "unityLibrary", "src", "main", "assets")
170
177
  return unless File.directory?(unity_assets)
171
178
 
172
- # 清理旧 pack:避免 assets 内容变化后残留旧 pack 目录导致重复/脏数据
179
+ splittable = Dir.glob(File.join(unity_assets, "*")).select { |p| File.directory?(p) }
180
+ splittable.reject! { |p| File.basename(p).downcase == "bin" }
181
+ splittable.reject! { |p| Dir.glob(File.join(p, "*")).empty? }
182
+
183
+ if splittable.empty?
184
+ existing_packs = Dir.glob(File.join(project_dir, "*_pack")).select do |dir|
185
+ next false unless File.directory?(dir)
186
+
187
+ gradle = File.join(dir, "build.gradle")
188
+ next false unless File.file?(gradle)
189
+
190
+ File.read(gradle).include?("com.android.asset-pack")
191
+ end
192
+
193
+ if existing_packs.empty?
194
+ puts "unityLibrary assets 下无可拆分资源,且工程无 *_pack 模块,跳过 PAD"
195
+ return
196
+ end
197
+
198
+ pack_module_refs = existing_packs.map { |dir| ":#{File.basename(dir)}" }
199
+ puts "unityLibrary assets 下无可拆分资源,复用已有 *_pack 模块:#{pack_module_refs.join(', ')}"
200
+ GradleHelper.update_settings_gradle(project_dir, pack_module_refs)
201
+ GradleHelper.update_launcher_build_gradle(project_dir, pack_module_refs)
202
+ return
203
+ end
204
+
205
+ # 有新资源可拆分,先清理旧 pack 再重建,避免残留脏数据
173
206
  Dir.glob(File.join(project_dir, "*_pack")).each do |dir|
174
207
  next unless File.directory?(dir)
175
208
 
176
- # 尽量只删除我们生成的模块:要求 build.gradle 存在且包含 asset-pack 插件
177
209
  gradle = File.join(dir, "build.gradle")
178
210
  next unless File.file?(gradle)
179
211
  content = File.read(gradle)
@@ -529,7 +561,30 @@ module Pindo
529
561
  asset_subdirs = Dir.glob(File.join(assets_path, "*")).select { |path| File.directory?(path) }
530
562
 
531
563
  if asset_subdirs.empty?
532
- puts "未找到 assets 下的子目录,跳过 Play Asset Delivery 设置"
564
+ # 重要:assets 为空并不代表不需要 PAD。
565
+ # 很多工程会在首次分包后把资源移动到 *_pack,从而 assets 留空;
566
+ # 此时仍需要确保 settings.gradle / launcher/build.gradle 中的 include/assetPacks 引用存在,
567
+ # 否则会出现 `assetPacks = [":yoo_pack"]` 未写入/被外部基线覆盖的问题。
568
+ existing_pack_modules = Dir.glob(File.join(project_dir, "*_pack")).filter_map do |dir|
569
+ next unless File.directory?(dir)
570
+
571
+ gradle = File.join(dir, "build.gradle")
572
+ next unless File.file?(gradle)
573
+
574
+ content = File.read(gradle)
575
+ next unless content.include?("com.android.asset-pack")
576
+
577
+ ":#{File.basename(dir)}"
578
+ end.uniq
579
+
580
+ if existing_pack_modules.any?
581
+ puts "assets 下无可拆分资源,检测到已存在的 Asset Pack 模块,将确保工程引用完整..."
582
+ GradleHelper.update_settings_gradle(project_dir, existing_pack_modules)
583
+ GradleHelper.update_launcher_build_gradle(project_dir, existing_pack_modules)
584
+ puts "✓ 已同步现存 Asset Pack 引用:#{existing_pack_modules.join(', ')}"
585
+ else
586
+ puts "未找到 assets 下的子目录,且工程中不存在 *_pack 模块,跳过 Play Asset Delivery 设置"
587
+ end
533
588
  return
534
589
  end
535
590
 
@@ -646,13 +646,24 @@ module Pindo
646
646
  return
647
647
  end
648
648
 
649
+ pack_modules = Array(pack_modules).compact.map(&:to_s).reject(&:empty?).uniq
650
+ if pack_modules.empty?
651
+ puts "✓ 未检测到需要写入的 Asset Pack 模块,跳过更新 launcher/build.gradle"
652
+ return
653
+ end
654
+
649
655
  content = File.read(launcher_build_gradle_path)
650
656
  original_content = content.dup
651
657
 
652
658
  # 检查是否已有 assetPacks 配置
653
659
  if content.match(/assetPacks\s*=\s*\[/)
654
- # 更新现有的 assetPacks 配置
655
- content.gsub!(/assetPacks\s*=\s*\[[^\]]*\]/, "assetPacks = #{pack_modules.inspect}")
660
+ # 合并现有的 assetPacks 配置(不要覆盖用户已有项)
661
+ content.gsub!(/assetPacks\s*=\s*\[([^\]]*)\]/m) do
662
+ raw_items = Regexp.last_match(1).to_s
663
+ existing = raw_items.scan(/["']([^"']+)["']/).flatten.map(&:to_s).reject(&:empty?)
664
+ merged = (existing + pack_modules).uniq
665
+ "assetPacks = #{merged.inspect}"
666
+ end
656
667
  else
657
668
  # 在 android 块中添加 assetPacks 配置
658
669
  android_block_pattern = /(android\s*\{)/
@@ -98,6 +98,16 @@ module Pindo
98
98
  if enable_pad
99
99
  pad_backup!(context)
100
100
  run_pad!(context)
101
+
102
+ # 临时 PAD 默认会在 cleanup! 中恢复备份并删除 created_dirs(即 *_pack),以实现回滚。
103
+ # 但某些工程会在构建结束后用“基线文件/外部备份”覆盖当前 build.gradle,
104
+ # 若该基线不包含 assetPacks/include,会导致引用丢失。
105
+ #
106
+ # 当显式开启 PINDO_PAD_KEEP_REFS=1 时:
107
+ # - 将 PAD 写入后的 settings.gradle / launcher/build.gradle 同步进备份快照,
108
+ # 以确保 cleanup! 恢复后仍保留 assetPacks/include;
109
+ # - 同时 cleanup! 将跳过删除 created_dirs,保留 *_pack 目录,保持工程可 sync。
110
+ sync_pad_refs_to_backups!(context) if pad_keep_refs_enabled?
101
111
  end
102
112
 
103
113
  # 2) 注入 buildType/signingConfig(对所有 Android modules)
@@ -242,15 +252,26 @@ module Pindo
242
252
  backups.each do |item|
243
253
  path = File.join(project_dir, item.fetch("path"))
244
254
  backup_path = File.join(project_dir, item.fetch("backup_path"))
245
- next unless File.file?(backup_path)
246
255
 
247
- FileUtils.mkdir_p(File.dirname(path))
248
- bin_copy(backup_path, path)
256
+ if item["type"] == "dir"
257
+ next unless File.directory?(backup_path)
258
+ FileUtils.rm_rf(path) if File.exist?(path)
259
+ FileUtils.mkdir_p(File.dirname(path))
260
+ FileUtils.cp_r(backup_path, path)
261
+ else
262
+ next unless File.file?(backup_path)
263
+ FileUtils.mkdir_p(File.dirname(path))
264
+ bin_copy(backup_path, path)
265
+ end
249
266
  end
250
267
 
251
- (data["created_dirs"] || []).each do |rel|
252
- abs = File.join(project_dir, rel)
253
- FileUtils.rm_rf(abs) if abs.start_with?(project_dir.to_s)
268
+ # 临时 PAD 默认会清理 created_dirs(通常是 *_pack)。
269
+ # 若显式开启 PINDO_PAD_KEEP_REFS=1,则保留 pack 目录与引用,避免构建结束后被外部基线覆盖而丢引用。
270
+ unless ENV.fetch("PINDO_PAD_KEEP_REFS", "").to_s.strip.downcase.match?(/\A(1|true|yes|on)\z/)
271
+ (data["created_dirs"] || []).each do |rel|
272
+ abs = File.join(project_dir, rel)
273
+ FileUtils.rm_rf(abs) if abs.start_with?(project_dir.to_s)
274
+ end
254
275
  end
255
276
  end
256
277
 
@@ -529,7 +550,6 @@ module Pindo
529
550
  def groovy_signing_config_entry(workflow_name:, workflow_build_type:, signing_config_name:)
530
551
  lines = []
531
552
  lines << "// #{MARK_BEGIN}"
532
- lines << "// workflowName=#{workflow_name.inspect}"
533
553
  lines << "#{signing_config_name} {"
534
554
  lines << " def signingEnvVars = #{RELEASE_SIGNING_ENV_VARS.inspect}"
535
555
  lines << " def hasCompleteReleaseSigningEnv = signingEnvVars.every { System.getenv(it) }"
@@ -553,7 +573,6 @@ module Pindo
553
573
  def kts_signing_config_entry(workflow_name:, workflow_build_type:, signing_config_name:)
554
574
  lines = []
555
575
  lines << "// #{MARK_BEGIN}"
556
- lines << "// workflowName=#{workflow_name.inspect}"
557
576
  lines << "create(\"#{signing_config_name}\") {"
558
577
  lines << " val signingEnvVars = listOf("
559
578
  RELEASE_SIGNING_ENV_VARS.each_with_index do |v, idx|
@@ -582,7 +601,6 @@ module Pindo
582
601
  def groovy_build_type_entry(workflow_name:, workflow_build_type:, signing_config_name:, is_main_module:)
583
602
  lines = []
584
603
  lines << "// #{MARK_BEGIN}"
585
- lines << "// workflowName=#{workflow_name.inspect}"
586
604
  lines << "#{workflow_build_type} {"
587
605
  lines << " minifyEnabled false"
588
606
  if is_main_module
@@ -597,7 +615,6 @@ module Pindo
597
615
  def kts_build_type_entry(workflow_name:, workflow_build_type:, signing_config_name:, is_main_module:)
598
616
  lines = []
599
617
  lines << "// #{MARK_BEGIN}"
600
- lines << "// workflowName=#{workflow_name.inspect}"
601
618
  lines << "create(\"#{workflow_build_type}\") {"
602
619
  lines << " isMinifyEnabled = false"
603
620
  if is_main_module
@@ -743,7 +760,7 @@ module Pindo
743
760
  end.join
744
761
  end
745
762
 
746
- def backup_file!(context, abs_path)
763
+ def backup_file!(context, abs_path, force: false)
747
764
  project_dir = context[:project_dir]
748
765
  return unless abs_path && File.file?(abs_path)
749
766
  return unless abs_path.start_with?(project_dir.to_s)
@@ -751,7 +768,10 @@ module Pindo
751
768
  rel = abs_path.delete_prefix("#{project_dir}/")
752
769
 
753
770
  # 已备份过就跳过
754
- return if context[:backups].any? { |b| b["path"] == rel && b["type"] == "file" }
771
+ if (existing = context[:backups].find { |b| b["path"] == rel && b["type"] == "file" })
772
+ return unless force
773
+ context[:backups].delete(existing)
774
+ end
755
775
 
756
776
  backup_path = File.join(context[:backup_dir], rel)
757
777
  FileUtils.mkdir_p(File.dirname(backup_path))
@@ -765,6 +785,22 @@ module Pindo
765
785
  }
766
786
  end
767
787
 
788
+ def pad_keep_refs_enabled?
789
+ ENV.fetch("PINDO_PAD_KEEP_REFS", "").to_s.strip.downcase.match?(/\A(1|true|yes|on)\z/)
790
+ end
791
+
792
+ def sync_pad_refs_to_backups!(context)
793
+ project_dir = context[:project_dir]
794
+
795
+ settings = find_settings_gradle(project_dir)
796
+ backup_file!(context, settings, force: true) if settings
797
+
798
+ launcher_groovy = File.join(project_dir, "launcher", "build.gradle")
799
+ launcher_kts = File.join(project_dir, "launcher", "build.gradle.kts")
800
+ backup_file!(context, launcher_kts, force: true) if File.file?(launcher_kts)
801
+ backup_file!(context, launcher_groovy, force: true) if File.file?(launcher_groovy)
802
+ end
803
+
768
804
  def self.bin_copy(src, dst)
769
805
  File.open(src, "rb") do |r|
770
806
  File.open(dst, "wb") do |w|
@@ -107,8 +107,22 @@ module Pindo
107
107
  if @process_type == Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
108
108
  coding_branch = get_current_branch_name
109
109
  @build_number, @commit_hash = git_repo_helper.get_build_number_from_commit(project_dir: root_dir)
110
- @build_version = "0.0.0"
110
+
111
+ # 版本号仍按正常优先级计算,仅"不打 tag / 不升版本",避免硬编码 0.0.0 污染 build.gradle 与下游上传参数
112
+ if @fixed_version && !@fixed_version.empty?
113
+ @build_version = @fixed_version
114
+ else
115
+ @build_version = git_repo_helper.calculate_build_version(
116
+ project_dir: root_dir,
117
+ tag_prefix: @tag_pre,
118
+ create_tag_type: Pindo::CreateTagType::NONE,
119
+ version_increase_type: @ver_inc
120
+ )
121
+ end
122
+
123
+ commit_short = @commit_hash ? @commit_hash[0..7] : "unknown"
111
124
  Funlog.instance.fancyinfo_warning("skip_without_tag 模式:跳过分支合并和 tag 创建")
125
+ Funlog.instance.fancyinfo_success("Version: #{@build_version}, Build: #{@build_number}, Commit: #{commit_short}")
112
126
 
113
127
  # 显示 commit 信息后直接返回
114
128
  display_all_repos_commit_info(root_dir)
@@ -224,41 +224,29 @@ module Pindo
224
224
  end
225
225
  end
226
226
 
227
- # 获取Build号(从commit hash转换而来)
227
+ # 获取Build号(基于 git 提交总数,单调递增)
228
+ # 对标 fastlane number_of_commits:versionCode = git rev-list --count HEAD
228
229
  # @param project_dir [String] 项目目录路径
229
- # @return [Integer, String] 返回 build_number commit_hash
230
- # - build_number: Build号(commit hash前6位16进制转10进制)
231
- # - commit_hash: 完整的commit hash(40位)
230
+ # @return [Array(Integer, String)] build_number 和完整 commit_hash
231
+ # - build_number: 当前 HEAD 的 commit 总数(最小为 1)
232
+ # - commit_hash: 完整的 commit hash(40位)
232
233
  def get_build_number_from_commit(project_dir: nil)
233
234
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?
234
235
 
235
- # 获取git根目录
236
236
  git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: project_dir)
237
- return 1, nil unless git_root
238
-
239
- begin
240
- # 获取当前HEAD的完整commit hash
241
- full_commit_hash = Pindo::GitHandler.git!(%W(-C #{git_root} rev-parse HEAD)).strip
242
-
243
- # 取前6位计算build_number
244
- short_hash = full_commit_hash[0..5]
237
+ raise Pindo::Informative, "非 Git 仓库,无法计算 versionCode: #{project_dir}" unless git_root
245
238
 
246
- # 将16进制转换为10进制
247
- build_number = short_hash.to_i(16)
248
-
249
- # 确保在Android versionCode安全范围内(最大值为2^31-1)
250
- max_value = 2**31 - 1
251
- build_number = build_number % max_value if build_number > max_value
239
+ # shallow clone 下 rev-list --count 结果不完整,必须先 unshallow
240
+ shallow = Pindo::GitHandler.git!(%W(-C #{git_root} rev-parse --is-shallow-repository)).strip
241
+ if shallow == "true"
242
+ raise Pindo::Informative, "shallow clone 无法计算 versionCode,请执行 git fetch --unshallow 后重试"
243
+ end
252
244
 
253
- # 确保build_number不为0
254
- build_number = 1 if build_number == 0
245
+ count = Pindo::GitHandler.git!(%W(-C #{git_root} rev-list --count HEAD)).strip.to_i
246
+ full_commit_hash = Pindo::GitHandler.git!(%W(-C #{git_root} rev-parse HEAD)).strip
255
247
 
256
- return build_number, full_commit_hash
257
- rescue StandardError => e
258
- Funlog.instance.fancyinfo_error("获取commit hash失败: #{e.message}")
259
- # 如果获取失败,返回基于时间戳的默认值
260
- return Time.now.to_i % 1000000 + 1, nil
261
- end
248
+ build_number = count < 1 ? 1 : count
249
+ [build_number, full_commit_hash]
262
250
  end
263
251
 
264
252
 
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.18.12"
9
+ VERSION = "5.18.17"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pindo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.18.12
4
+ version: 5.18.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -526,7 +526,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
526
526
  - !ruby/object:Gem::Version
527
527
  version: 3.0.0
528
528
  requirements: []
529
- rubygems_version: 4.0.3
529
+ rubygems_version: 3.6.9
530
530
  specification_version: 4
531
531
  summary: easy work
532
532
  test_files: []