cocoapods-bb-PodAssistant 0.3.15.1 → 0.3.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76613430484281c489857dca49640b225d66d912b05c2feb488e0c7efab5bf30
4
- data.tar.gz: f310bc2ab0fac4f48a728a812fe487e26efe958b12a8042794e20512e2c6ce48
3
+ metadata.gz: 0356b0d9093281386d9cf59a6764965aced7e97d319e64b7efc7f087291f6140
4
+ data.tar.gz: 5b2af0ffd94d23af9654d1de3174ede20b7e53f97d00f3f95b7ca90f4410b571
5
5
  SHA512:
6
- metadata.gz: da38a902099ce6249365e29f537c39b20998670bfcd3271b561ad10789eaf148e131b1384608b7ade608a658ef9e4e26ab8055fef345d2dcefcbf1812684fa45
7
- data.tar.gz: d107c8364b31827bf08850e75248557a4fe24a0dd898f7d1ed4d25182fdac46eb0193fb7f27ff987246e757fd49f227654f7d6945f2bed5890efa8f421a20712
6
+ metadata.gz: 94e339e85bc22fbe2a0070ceef07848d897745c4e06b0f3fc66120946273ad229ca0d80962345d03b93370a106ea5079195db8a3b7d9d8a3623a35d83086686b
7
+ data.tar.gz: 5a42db8d7e28f3fc70ca02f950d6b2830a8a56f256b4953dd1cd7410f1b6d0cba74dcdd4b4c285269a502ec7a75a88938965067f246d1e168ccc2283afcbe576
@@ -1,3 +1,3 @@
1
1
  module CocoapodsBbPodassistant
2
- VERSION = "0.3.15.1"
2
+ VERSION = "0.3.15.2"
3
3
  end
@@ -6,9 +6,9 @@ require "timeout"
6
6
  module BBItools
7
7
  class DocCGenerator
8
8
  PODSPEC_REPO = "babybus-babybus-ios-specs-babybus-specs"
9
+ PODSPEC_REPO_URL = "https://git.babybus.co/babybus/ios/Specs/babybus-specs.git"
9
10
  DESTINATION = "generic/platform=iOS Simulator"
10
11
  CONFIGURATION = "Debug"
11
- KEYCHAIN_HOST = "git.babybus.co"
12
12
 
13
13
  def self.generate(options)
14
14
  new(options).run
@@ -26,7 +26,6 @@ module BBItools
26
26
  @output = options[:output]
27
27
  @logs = options[:logs]
28
28
  @derived_data = options[:derived_data]
29
- @lint_root = options[:lint_root]
30
29
  @hosting_base_path = options[:hosting_base_path]
31
30
  @subspec = options[:subspec]
32
31
  end
@@ -133,9 +132,9 @@ module BBItools
133
132
  derived_data_root = File.join(local_work_root, "DerivedData")
134
133
  FileUtils.mkdir_p(derived_data_root)
135
134
 
136
- lint_root = File.join(local_work_root, "Lint")
137
- FileUtils.mkdir_p(lint_root)
138
- lint_root_rel = lint_root
135
+ pod_install_root = File.join(local_work_root, "PodInstall")
136
+ FileUtils.rm_rf(pod_install_root)
137
+ FileUtils.mkdir_p(pod_install_root)
139
138
 
140
139
  # 最终生成的站点先放在本地
141
140
  local_site_output = File.join(local_work_root, "site_output")
@@ -207,80 +206,86 @@ module BBItools
207
206
  require_cmd!("git")
208
207
 
209
208
  # ---------------------------------------------------------
210
- # 4. 执行 Pod Lib Lint
209
+ # 4. 创建临时 Podfile + 最小 Xcode 工程,然后执行 pod install
211
210
  # ---------------------------------------------------------
212
- lint_log = File.join(logs_dir, "pod-lib-lint.log")
213
- lint_log_rel = rel_path(lint_log, base_dir: base_dir)
214
- lint_cmd = [
215
- "pod", "lib", "lint", podspec_basename,
216
- "--verbose", "--no-clean", "--skip-tests", "--skip-import-validation",
217
- "--use-modular-headers", "--use-static-frameworks",
218
- "--allow-warnings",
219
- "--sources=#{PODSPEC_REPO}"
220
- ]
221
-
222
- # 如果指定了 subspec,添加到 lint 命令
223
- lint_cmd << "--subspec=#{@subspec}" if @subspec
211
+ write_minimal_xcodeproj(File.join(pod_install_root, "App.xcodeproj"), deployment_target)
224
212
 
225
- File.open(status_md, "a") { |f| f.puts "- lint: #{lint_cmd.join(" ")}" }
213
+ pod_dep = @subspec ? "#{scheme}/#{@subspec}" : scheme
226
214
 
227
- log "执行 lint: #{podspec_basename}#{ @subspec ? " (subspec: #{@subspec})" : "" }(cwd=#{rel_path(podspec_dir_abs, base_dir: base_dir)}"
228
- lint_env = {
229
- "HOME" => real_home,
230
- "TMPDIR" => lint_root
231
- }
215
+ # Symbol graph 输出目录(swiftc -emit-symbol-graph 直接写这里,不经过 clang -extract-api
216
+ symbol_graph_out = File.join(pod_install_root, "symbol-graphs")
217
+ FileUtils.mkdir_p(symbol_graph_out)
232
218
 
233
- if ENV["BB_DOCC_ALLOW_PROMPT"] != "1"
234
- lint_env["GIT_TERMINAL_PROMPT"] = "0"
235
- end
219
+ pod_install_podfile = <<~PODFILE
220
+ platform :ios, '#{deployment_target}'
221
+ inhibit_all_warnings!
222
+ use_frameworks! :linkage => :static
236
223
 
237
- lint_exit = run_to_file(lint_cmd, cwd: podspec_dir_abs, env: lint_env, log_path: lint_log)
224
+ source '#{PODSPEC_REPO_URL}'
238
225
 
239
- File.open(status_md, "a") do |f|
240
- if lint_exit.zero?
241
- f.puts "- lint: 成功"
242
- else
243
- f.puts "- lint: 失败(exit=#{lint_exit})"
226
+ target 'App' do
227
+ pod '#{pod_dep}', :path => '#{podspec_dir_abs}'
244
228
  end
245
- f.puts
246
- f.puts "**pod lib lint 日志(尾部)**"
247
- f.puts "```"
248
- tail_lines(lint_log, 200).each { |line| f.puts line }
249
- f.puts "```"
250
- end
251
229
 
252
- # ---------------------------------------------------------
253
- # 5. Lint 失败处理 (软失败)
254
- # ---------------------------------------------------------
255
- unless lint_exit.zero?
256
- log "⚠️ Lint 失败 (exit=#{lint_exit}),尝试继续执行 docbuild..."
257
- log "失败日志: #{lint_log_rel}"
258
-
259
- # 打印关键错误信息
260
- puts "[docc] -------- pod lib lint 日志(尾部 200 行)--------"
261
- puts tail_lines(lint_log, 200).join("\n")
262
-
263
- # 检查是否是 Git 认证问题
264
- if safe_read_text(lint_log).include?("Authentication failed for 'https://#{KEYCHAIN_HOST}/")
265
- puts "[docc] 提示: 检测到 git clone 认证失败(#{KEYCHAIN_HOST})"
230
+ post_install do |installer|
231
+ installer.pods_project.targets.each do |target|
232
+ target.build_configurations.each do |config|
233
+ config.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'] = 'YES'
234
+ # 所有 target 都禁用 clang -extract-api(docbuild 会强制开它,我们不用 docbuild)
235
+ config.build_settings['BUILD_DOCUMENTATION_DURING_EACH_BUILD'] = 'NO'
236
+ next unless target.name == '#{scheme}'
237
+ # 只对主 Pod 注入 -emit-symbol-graph,让 swiftc 在编译时直接输出 symbol graph
238
+ # BUILD_DOCUMENTATION_DURING_EACH_BUILD=YES 更精准,不触发 clang -extract-api
239
+ config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -emit-symbol-graph -emit-symbol-graph-dir #{symbol_graph_out}'
240
+ end
241
+ end
266
242
  end
267
-
268
- # 注意:这里不 return,继续尝试寻找 workspace
243
+ PODFILE
244
+
245
+ File.write(File.join(pod_install_root, "Podfile"), pod_install_podfile)
246
+
247
+ pod_install_log = File.join(logs_dir, "pod-install.log")
248
+ pod_install_cmd = ["pod", "install", "--no-repo-update"]
249
+
250
+ File.open(status_md, "a") { |f| f.puts "- pod_install: #{pod_install_cmd.join(" ")}" }
251
+
252
+ log "执行 pod install: #{pod_dep} (cwd=#{rel_path(pod_install_root, base_dir: base_dir)})"
253
+ pod_install_env = { "HOME" => real_home }
254
+ pod_install_env["GIT_TERMINAL_PROMPT"] = "0" if ENV["BB_DOCC_ALLOW_PROMPT"].to_s.strip != "1"
255
+
256
+ pod_install_exit = run_to_file(pod_install_cmd, cwd: pod_install_root, env: pod_install_env, log_path: pod_install_log)
257
+
258
+ unless pod_install_exit.zero?
259
+ File.open(status_md, "a") do |f|
260
+ f.puts "- pod_install: 失败(exit=#{pod_install_exit})"
261
+ f.puts
262
+ f.puts "**pod install 日志(尾部)**"
263
+ f.puts "```"
264
+ tail_lines(pod_install_log, 200).each { |line| f.puts line }
265
+ f.puts "```"
266
+ end
267
+ puts "[docc] -------- pod install 日志(尾部 200 行)--------"
268
+ puts tail_lines(pod_install_log, 200).join("\n")
269
+ fail!("pod install 失败 (exit=#{pod_install_exit})")
269
270
  end
270
271
 
272
+ File.open(status_md, "a") { |f| f.puts "- pod_install: 成功" }
273
+
274
+ # pod install 后,清理依赖 Pod 中多余的 .docc 目录
275
+ # xcodebuild docbuild 要求每个 target 只能有一个 .docc catalog
276
+ cleaned_docc = remove_extra_docc_catalogs(File.join(pod_install_root, "Pods"))
277
+ File.open(status_md, "a") { |f| f.puts "- cleaned_extra_docc_catalogs: #{cleaned_docc.join(', ')}" } if cleaned_docc.any?
278
+
271
279
  # ---------------------------------------------------------
272
- # 6. 查找 Workspace 并执行 DocBuild
280
+ # 5. 查找 Workspace 并执行 DocBuild
273
281
  # ---------------------------------------------------------
274
- workspace_path_abs = find_workspace_from_lint_log(lint_log, lint_root)
275
-
276
- if workspace_path_abs.to_s.strip.empty?
277
- fail!("未找到 *.xcworkspace(lint_root=#{lint_root_rel}),无法继续")
278
- end
279
-
280
- workspace_path_rel = rel_path(workspace_path_abs.to_s, base_dir: base_dir)
282
+ workspace_path_abs = Dir.glob(File.join(pod_install_root, "*.xcworkspace")).first.to_s
283
+ fail!("未找到 *.xcworkspace(pod_install_root=#{pod_install_root})") if workspace_path_abs.strip.empty?
284
+
285
+ workspace_path_rel = rel_path(workspace_path_abs, base_dir: base_dir)
281
286
  fail!("workspace 不存在: #{workspace_path_rel}") unless File.directory?(workspace_path_abs)
282
287
 
283
- validation_dir_abs = File.dirname(workspace_path_abs)
288
+ validation_dir_abs = pod_install_root
284
289
  File.open(status_md, "a") do |f|
285
290
  f.puts "- validation_dir: #{rel_path(validation_dir_abs, base_dir: base_dir)}"
286
291
  f.puts "- workspace: #{workspace_path_rel}"
@@ -314,20 +319,19 @@ module BBItools
314
319
  FileUtils.mkdir_p(derived_dir)
315
320
  derived_dir_rel = rel_path(derived_dir, base_dir: base_dir)
316
321
 
317
- docbuild_log = File.join(logs_dir, "xcodebuild-docbuild.log")
322
+ build_log = File.join(logs_dir, "xcodebuild-build.log")
318
323
 
319
- workspace_for_docbuild = rel_path(workspace_path_abs, base_dir: podspec_dir_abs)
320
- derived_dir_for_docbuild = rel_path(derived_dir, base_dir: podspec_dir_abs)
321
-
322
- # DocBuild Command
323
- docbuild_cmd = [
324
- "xcodebuild", "docbuild",
325
- "-workspace", workspace_for_docbuild,
326
- "-scheme", scheme, # 通常 Subspec 的 Scheme 还是主 Pod 名
324
+ # 使用 xcodebuild build(非 docbuild)
325
+ # docbuild 会在命令行层面强制对所有 target 开启 ExtractAPI,无视项目里的 BUILD_DOCUMENTATION_DURING_EACH_BUILD=NO
326
+ # build 只对项目里明确设置了 YES 的 target(主 Pod)执行 ExtractAPI,依赖不受影响
327
+ build_cmd = [
328
+ "xcodebuild", "build",
329
+ "-workspace", workspace_path_abs,
330
+ "-scheme", scheme,
327
331
  "-destination", DESTINATION,
328
332
  "-configuration", CONFIGURATION,
329
- "-derivedDataPath", derived_dir_for_docbuild,
330
- "ENABLE_USER_SCRIPT_SANDBOXING=NO" # 尝试解决 Swift Macro 权限问题
333
+ "-derivedDataPath", derived_dir,
334
+ "ENABLE_USER_SCRIPT_SANDBOXING=NO"
331
335
  ]
332
336
 
333
337
  docc_catalog_abs = resolve_docc_catalog_abs(podspec_dir_abs, scheme)
@@ -336,45 +340,55 @@ module BBItools
336
340
  from_sources = path_inside_dir?(docc_catalog_abs, File.join(podspec_dir_abs, "Sources"))
337
341
  File.open(status_md, "a") do |f|
338
342
  f.puts "- docc_catalog: #{docc_catalog_rel_for_status}"
339
- if from_sources
340
- f.puts "- docc_catalog_source: sources(auto, 未依赖 podspec DOCC_CATALOGS)"
341
- else
342
- f.puts "- docc_catalog_source: root(auto)"
343
- end
343
+ f.puts "- docc_catalog_source: #{from_sources ? 'sources' : 'root'}"
344
344
  end
345
- docbuild_cmd << "DOCC_CATALOGS=#{docc_catalog_abs}"
346
345
  else
347
346
  File.open(status_md, "a") { |f| f.puts "- docc_catalog: 未找到(将使用工程默认配置)" }
348
347
  end
349
348
 
350
349
  if deployment_target && !deployment_target.strip.empty?
351
- docbuild_cmd << "IPHONEOS_DEPLOYMENT_TARGET=#{deployment_target}"
352
- docbuild_cmd << "SWIFT_VERSION=5.0"
350
+ build_cmd << "IPHONEOS_DEPLOYMENT_TARGET=#{deployment_target}"
351
+ build_cmd << "SWIFT_VERSION=5.0"
353
352
  end
354
- docbuild_cmd += ["CODE_SIGNING_ALLOWED=NO", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGN_IDENTITY="]
353
+ build_cmd += ["CODE_SIGNING_ALLOWED=NO", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGN_IDENTITY="]
354
+
355
+ build_cmd_report = build_cmd.map { |arg| arg == workspace_path_abs ? workspace_path_rel : (arg == derived_dir ? derived_dir_rel : arg) }
356
+ File.open(status_md, "a") { |f| f.puts "- build: #{build_cmd_report.join(" ")}" }
355
357
 
356
- docbuild_cmd_report = docbuild_cmd.dup
357
- docbuild_cmd_report[docbuild_cmd_report.index(workspace_for_docbuild) || 0] = workspace_path_rel
358
- docbuild_cmd_report[docbuild_cmd_report.index(derived_dir_for_docbuild) || 0] = derived_dir_rel
359
- File.open(status_md, "a") { |f| f.puts "- docbuild: #{docbuild_cmd_report.join(" ")}" }
358
+ log "执行 build (ExtractAPI 仅对 #{scheme}): #{component_name}"
359
+ build_exit = run_to_file(build_cmd, cwd: pod_install_root, env: { "HOME" => real_home }, log_path: build_log)
360
360
 
361
- log "执行 docbuild: #{scheme} (target: #{component_name})"
362
- docbuild_exit = run_to_file(docbuild_cmd, cwd: podspec_dir_abs, env: { "HOME" => real_home }, log_path: docbuild_log)
361
+ # 自动检测 arm64 模拟器不兼容问题(预编译 SDK 无 arm64 simulator slice)
362
+ # 失败后检查日志,有 "unsupported Swift architecture" 时排除 arm64 重试
363
+ if !build_exit.zero? && safe_read_text(build_log).include?("unsupported Swift architecture")
364
+ log "⚠️ 检测到依赖 SDK 不支持 arm64 模拟器,自动切换 x86_64 重试 (EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64)..."
365
+ File.open(status_md, "a") { |f| f.puts "- build_retry: excluded arm64 for simulator" }
363
366
 
364
- unless docbuild_exit.zero?
367
+ build_log_retry = File.join(logs_dir, "xcodebuild-build-x86_64.log")
368
+ build_cmd_retry = build_cmd + ["EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64"]
369
+
370
+ build_exit = run_to_file(build_cmd_retry, cwd: pod_install_root, env: { "HOME" => real_home }, log_path: build_log_retry)
371
+ build_log = build_log_retry
372
+ end
373
+
374
+ unless build_exit.zero?
365
375
  File.open(status_md, "a") do |f|
366
- f.puts "- docbuild: 失败(exit=#{docbuild_exit})"
376
+ f.puts "- build: 失败(exit=#{build_exit})"
367
377
  f.puts
368
378
  f.puts "**xcodebuild 日志(尾部)**"
369
379
  f.puts "```"
370
- tail_lines(docbuild_log, 200).each { |line| f.puts line }
380
+ tail_lines(build_log, 200).each { |line| f.puts line }
371
381
  f.puts "```"
372
382
  end
373
- fail!("docbuild 失败")
383
+ puts "[docc] -------- build 日志(尾部 200 行)--------"
384
+ puts tail_lines(build_log, 200).join("\n")
385
+ fail!("build 失败")
374
386
  end
375
387
 
376
- File.open(status_md, "a") { |f| f.puts "- docbuild: 成功" }
388
+ File.open(status_md, "a") { |f| f.puts "- build: 成功" }
377
389
 
390
+ # xcodebuild build + BUILD_DOCUMENTATION_DURING_EACH_BUILD=YES 会直接生成 .doccarchive
391
+ # 先尝试找现成的 archive
378
392
  archives = []
379
393
  Find.find(derived_dir) do |p|
380
394
  next unless File.directory?(p)
@@ -390,43 +404,58 @@ module BBItools
390
404
  .reverse
391
405
  .find { |p| File.basename(p) == "#{scheme}.doccarchive" } || archives.max_by { |p| File.mtime(p) }
392
406
 
393
- fail!("未找到 .doccarchive(derivedData=#{derived_dir_rel})") if doccarchive_path.to_s.strip.empty?
407
+ # 若 build 没直接产出 .doccarchive,则找 symbol-graph 目录手动跑 xcrun docc convert
408
+ if doccarchive_path.to_s.strip.empty?
409
+ log "build 未直接生成 .doccarchive,尝试手动 docc convert..."
394
410
 
395
- want_tutorials = false
396
- if docc_catalog_abs && File.directory?(docc_catalog_abs)
397
- has_tutorial = Dir.glob(File.join(docc_catalog_abs, "**", "*.tutorial")).any?
398
- want_tutorials = has_tutorial
399
- end
411
+ # 优先使用 -emit-symbol-graph-dir 指定的目录(swiftc 直接写入)
412
+ symbol_graph_dir = nil
413
+ if Dir.glob(File.join(symbol_graph_out, "*.symbols.json")).any?
414
+ symbol_graph_dir = symbol_graph_out
415
+ log "使用 swiftc -emit-symbol-graph 输出: #{symbol_graph_dir}"
416
+ end
400
417
 
401
- if want_tutorials
402
- has_in_archive = File.directory?(File.join(doccarchive_path, "tutorials")) || File.directory?(File.join(doccarchive_path, "data", "tutorials"))
403
- unless has_in_archive
404
- symbol_graph_dir = Dir.glob(File.join(derived_dir, "Build", "Intermediates.noindex", "**", "#{scheme}.build", "symbol-graph")).sort.first
405
- fail!("未找到 symbol-graph 目录,无法按官方 docc convert 生成教程") if symbol_graph_dir.to_s.strip.empty?
406
-
407
- manual_archive_dir = File.join(derived_data_root, ".manual_doccarchive", component_name, "#{scheme}.doccarchive")
408
- FileUtils.rm_rf(manual_archive_dir)
409
- FileUtils.mkdir_p(File.dirname(manual_archive_dir))
410
-
411
- manual_log = File.join(logs_dir, "docc-convert-manual.log")
412
- manual_diag = File.join(logs_dir, "docc-convert-manual-diagnostics.json")
413
-
414
- manual_cmd = [
415
- "xcrun", "docc", "convert", docc_catalog_abs,
416
- "--emit-lmdb-index",
417
- "--fallback-display-name", scheme,
418
- "--fallback-bundle-identifier", "org.cocoapods.#{scheme}",
419
- "--output-dir", manual_archive_dir,
420
- "--additional-symbol-graph-dir", symbol_graph_dir,
421
- "--ide-console-output",
422
- "--diagnostics-file", manual_diag
423
- ]
424
-
425
- manual_exit = run_to_file(manual_cmd, cwd: podspec_dir_abs, env: { "HOME" => real_home }, log_path: manual_log)
426
- fail!("docc convert 失败(exit=#{manual_exit})") unless manual_exit.zero? && File.directory?(manual_archive_dir)
427
-
428
- doccarchive_path = manual_archive_dir
418
+ # 备用:Xcode 中间目录(BUILD_DOCUMENTATION_DURING_EACH_BUILD=YES 生成的路径)
419
+ if symbol_graph_dir.to_s.strip.empty?
420
+ symbol_graph_dir = Dir.glob(
421
+ File.join(derived_dir, "Build", "Intermediates.noindex", "**", "#{scheme}.build", "symbol-graph")
422
+ ).sort.first
429
423
  end
424
+
425
+ fail!("未找到 symbol-graph 文件(#{symbol_graph_out} 和 #{scheme}.build/symbol-graph 均为空):确认 pod 有 Swift 源码且 OTHER_SWIFT_FLAGS 已生效") if symbol_graph_dir.to_s.strip.empty?
426
+
427
+ manual_archive_dir = File.join(derived_data_root, ".manual_doccarchive", component_name, "#{scheme}.doccarchive")
428
+ FileUtils.rm_rf(manual_archive_dir)
429
+ FileUtils.mkdir_p(File.dirname(manual_archive_dir))
430
+
431
+ docc_convert_log = File.join(logs_dir, "docc-convert.log")
432
+ docc_convert_diag = File.join(logs_dir, "docc-convert-diagnostics.json")
433
+
434
+ docc_convert_cmd = [
435
+ "xcrun", "docc", "convert",
436
+ "--emit-lmdb-index",
437
+ "--fallback-display-name", scheme,
438
+ "--fallback-bundle-identifier", "org.cocoapods.#{scheme}",
439
+ "--fallback-bundle-version", spec_version.to_s.strip.empty? ? "1.0" : spec_version,
440
+ "--output-dir", manual_archive_dir,
441
+ "--additional-symbol-graph-dir", symbol_graph_dir,
442
+ "--ide-console-output",
443
+ "--diagnostics-file", docc_convert_diag
444
+ ]
445
+ docc_convert_cmd.insert(3, docc_catalog_abs) if docc_catalog_abs
446
+
447
+ log "执行 docc convert: #{scheme}"
448
+ File.open(status_md, "a") { |f| f.puts "- docc_convert: #{docc_convert_cmd.join(" ")}" }
449
+
450
+ docc_convert_exit = run_to_file(docc_convert_cmd, cwd: pod_install_root, env: { "HOME" => real_home }, log_path: docc_convert_log)
451
+
452
+ unless docc_convert_exit.zero? && File.directory?(manual_archive_dir)
453
+ puts "[docc] -------- docc-convert 日志(尾部 100 行)--------"
454
+ puts tail_lines(docc_convert_log, 100).join("\n")
455
+ fail!("docc convert 失败(exit=#{docc_convert_exit})")
456
+ end
457
+
458
+ doccarchive_path = manual_archive_dir
430
459
  end
431
460
 
432
461
  doccarchive_rel = rel_path(doccarchive_path, base_dir: base_dir)
@@ -437,23 +466,19 @@ module BBItools
437
466
 
438
467
  export_log = File.join(logs_dir, "docc-transform.log")
439
468
 
440
- doccarchive_for_export = rel_path(doccarchive_path, base_dir: podspec_dir_abs)
441
469
  export_staging_dir = File.join(derived_data_root, ".docc-site", scheme)
442
470
  FileUtils.rm_rf(export_staging_dir)
443
471
  FileUtils.mkdir_p(export_staging_dir)
444
- site_out_for_export = rel_path(export_staging_dir, base_dir: podspec_dir_abs)
445
-
446
- # Export Command
472
+
473
+ # Export Command (使用绝对路径)
447
474
  export_cmd = [
448
475
  "xcrun", "docc", "process-archive", "transform-for-static-hosting",
449
- doccarchive_for_export,
450
- "--output-path", site_out_for_export,
451
- "--hosting-base-path", hosting_base_path # 关键参数
476
+ doccarchive_path,
477
+ "--output-path", export_staging_dir,
478
+ "--hosting-base-path", hosting_base_path
452
479
  ]
453
480
 
454
- export_cmd_report = export_cmd.dup
455
- export_cmd_report[export_cmd_report.index(doccarchive_for_export) || 0] = doccarchive_rel
456
- export_cmd_report[export_cmd_report.index(site_out_for_export) || 0] = rel_path(site_out, base_dir: base_dir)
481
+ export_cmd_report = export_cmd.map { |arg| arg == doccarchive_path ? doccarchive_rel : (arg == export_staging_dir ? rel_path(site_out, base_dir: base_dir) : arg) }
457
482
  File.open(status_md, "a") { |f| f.puts "- export: #{export_cmd_report.join(" ")}" }
458
483
 
459
484
  log "导出静态站点: #{component_dir_rel} (hosting-base-path: #{hosting_base_path})"
@@ -470,7 +495,7 @@ module BBItools
470
495
 
471
496
  File.open(status_md, "a") { |f| f.puts "- docc_html_dir: #{docc_html_dir.empty? ? '(builtin)' : docc_html_dir}" }
472
497
 
473
- export_exit = run_to_file(export_cmd, cwd: podspec_dir_abs, env: export_env, log_path: export_log)
498
+ export_exit = run_to_file(export_cmd, cwd: pod_install_root, env: export_env, log_path: export_log)
474
499
  unless export_exit.zero?
475
500
  warn tail_lines(export_log, 200).join("\n")
476
501
  fail!("docc 导出失败")
@@ -582,6 +607,201 @@ module BBItools
582
607
  exit 1
583
608
  end
584
609
 
610
+ # 扫描 pods_dir 下每个 Pod,找出拥有多个 .docc catalog 的 target
611
+ # 保留与 Pod 名同名的那个(或第一个),删除其余的,同时从 Pods.xcodeproj/project.pbxproj 移除对应引用
612
+ def remove_extra_docc_catalogs(pods_dir)
613
+ removed = []
614
+ return removed unless File.directory?(pods_dir)
615
+
616
+ pbxproj_path = File.join(pods_dir, "Pods.xcodeproj", "project.pbxproj")
617
+
618
+ Dir.children(pods_dir).each do |pod_name|
619
+ pod_path = File.join(pods_dir, pod_name)
620
+ next unless File.directory?(pod_path)
621
+ next if pod_name.start_with?(".")
622
+
623
+ docc_dirs = []
624
+ Find.find(pod_path) do |p|
625
+ if File.directory?(p) && p.end_with?(".docc")
626
+ docc_dirs << p
627
+ Find.prune
628
+ end
629
+ end
630
+
631
+ next if docc_dirs.size <= 1
632
+
633
+ # 优先保留与 Pod 名同名的 catalog,否则保留第一个
634
+ preferred = docc_dirs.find { |p| File.basename(p, ".docc").casecmp(pod_name).zero? }
635
+ preferred ||= docc_dirs.first
636
+
637
+ docc_dirs.each do |d|
638
+ next if d == preferred
639
+ log "🗑 删除多余 .docc catalog: #{d}"
640
+ FileUtils.rm_rf(d)
641
+ # pbxproj 里仍有文件引用,xcodebuild 会从项目文件读 catalog 列表,必须一并清理
642
+ remove_docc_from_pbxproj(pbxproj_path, File.basename(d)) if File.file?(pbxproj_path)
643
+ removed << d
644
+ end
645
+ end
646
+
647
+ removed
648
+ rescue StandardError => e
649
+ log "⚠️ remove_extra_docc_catalogs 异常: #{e.message}"
650
+ []
651
+ end
652
+
653
+ # 从 project.pbxproj 中删除对指定 .docc catalog 的所有引用
654
+ # 通过 GUID 匹配,移除 PBXFileReference / PBXBuildFile / group children / build phase files 各行
655
+ def remove_docc_from_pbxproj(pbxproj_path, docc_basename)
656
+ text = safe_read_text(pbxproj_path)
657
+ return if text.empty?
658
+
659
+ # 找 PBXFileReference GUID
660
+ file_ref_guids = []
661
+ text.scan(/(\h{32})\s+\/\*\s+#{Regexp.escape(docc_basename)}\s+\*\/\s*=\s*\{isa\s*=\s*PBXFileReference/) do
662
+ file_ref_guids << $1
663
+ end
664
+ return if file_ref_guids.empty?
665
+
666
+ # 找引用这些 fileRef 的 PBXBuildFile GUID
667
+ build_file_guids = []
668
+ file_ref_guids.each do |ref_guid|
669
+ text.scan(/(\h{32})\s+\/\*[^*]*\*\/\s*=\s*\{isa\s*=\s*PBXBuildFile;\s*fileRef\s*=\s*#{ref_guid}/) do
670
+ build_file_guids << $1
671
+ end
672
+ end
673
+
674
+ all_guids = (file_ref_guids + build_file_guids).uniq
675
+
676
+ # 删除所有包含这些 GUID 的行(覆盖 definition / children / files 引用)
677
+ new_text = text.lines.reject { |line| all_guids.any? { |guid| line.include?(guid) } }.join
678
+ File.write(pbxproj_path, new_text) unless new_text == text
679
+ rescue StandardError => e
680
+ log "⚠️ remove_docc_from_pbxproj 异常: #{e.message}"
681
+ end
682
+
683
+ def write_minimal_xcodeproj(xcodeproj_dir, deployment_target)
684
+ FileUtils.mkdir_p(xcodeproj_dir)
685
+ pbxproj = <<~PBXPROJ
686
+ // !$*UTF8*$!
687
+ {
688
+ archiveVersion = 1;
689
+ classes = {
690
+ };
691
+ objectVersion = 56;
692
+ objects = {
693
+ /* Begin PBXFileReference section */
694
+ 00000001 /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
695
+ /* End PBXFileReference section */
696
+
697
+ /* Begin PBXGroup section */
698
+ 00000002 = {
699
+ isa = PBXGroup;
700
+ children = (
701
+ 00000003,
702
+ );
703
+ sourceTree = "<group>";
704
+ };
705
+ 00000003 /* Products */ = {
706
+ isa = PBXGroup;
707
+ children = (
708
+ 00000001,
709
+ );
710
+ name = Products;
711
+ sourceTree = "<group>";
712
+ };
713
+ /* End PBXGroup section */
714
+
715
+ /* Begin PBXNativeTarget section */
716
+ 00000004 /* App */ = {
717
+ isa = PBXNativeTarget;
718
+ buildConfigurationList = 00000005;
719
+ buildPhases = ();
720
+ buildRules = ();
721
+ dependencies = ();
722
+ name = App;
723
+ productName = App;
724
+ productReference = 00000001;
725
+ productType = "com.apple.product-type.application";
726
+ };
727
+ /* End PBXNativeTarget section */
728
+
729
+ /* Begin PBXProject section */
730
+ 00000006 /* Project object */ = {
731
+ isa = PBXProject;
732
+ buildConfigurationList = 00000007;
733
+ compatibilityVersion = "Xcode 14.0";
734
+ developmentRegion = en;
735
+ hasScannedForEncodings = 0;
736
+ knownRegions = (en, Base);
737
+ mainGroup = 00000002;
738
+ productRefGroup = 00000003;
739
+ projectDirPath = "";
740
+ projectRoot = "";
741
+ targets = (00000004);
742
+ };
743
+ /* End PBXProject section */
744
+
745
+ /* Begin XCBuildConfiguration section */
746
+ 00000008 /* Debug */ = {
747
+ isa = XCBuildConfiguration;
748
+ buildSettings = {
749
+ ALWAYS_SEARCH_USER_PATHS = NO;
750
+ IPHONEOS_DEPLOYMENT_TARGET = #{deployment_target};
751
+ SDKROOT = iphoneos;
752
+ };
753
+ name = Debug;
754
+ };
755
+ 00000009 /* Release */ = {
756
+ isa = XCBuildConfiguration;
757
+ buildSettings = {
758
+ ALWAYS_SEARCH_USER_PATHS = NO;
759
+ IPHONEOS_DEPLOYMENT_TARGET = #{deployment_target};
760
+ SDKROOT = iphoneos;
761
+ };
762
+ name = Release;
763
+ };
764
+ 0000000A /* Debug */ = {
765
+ isa = XCBuildConfiguration;
766
+ buildSettings = {
767
+ INFOPLIST_FILE = "";
768
+ PRODUCT_BUNDLE_IDENTIFIER = org.example.App;
769
+ PRODUCT_NAME = App;
770
+ };
771
+ name = Debug;
772
+ };
773
+ 0000000B /* Release */ = {
774
+ isa = XCBuildConfiguration;
775
+ buildSettings = {
776
+ INFOPLIST_FILE = "";
777
+ PRODUCT_BUNDLE_IDENTIFIER = org.example.App;
778
+ PRODUCT_NAME = App;
779
+ };
780
+ name = Release;
781
+ };
782
+ /* End XCBuildConfiguration section */
783
+
784
+ /* Begin XCConfigurationList section */
785
+ 00000005 = {
786
+ isa = XCConfigurationList;
787
+ buildConfigurations = (0000000A, 0000000B);
788
+ defaultConfigurationIsVisible = 0;
789
+ defaultConfigurationName = Release;
790
+ };
791
+ 00000007 = {
792
+ isa = XCConfigurationList;
793
+ buildConfigurations = (00000008, 00000009);
794
+ defaultConfigurationIsVisible = 0;
795
+ defaultConfigurationName = Release;
796
+ };
797
+ /* End XCConfigurationList section */
798
+ };
799
+ rootObject = 00000006 /* Project object */;
800
+ }
801
+ PBXPROJ
802
+ File.write(File.join(xcodeproj_dir, "project.pbxproj"), pbxproj)
803
+ end
804
+
585
805
  def abs_path(path, base_dir:)
586
806
  return "" if path.nil? || path.empty?
587
807
  return File.expand_path(path) if path.start_with?("/")
@@ -968,38 +1188,6 @@ module BBItools
968
1188
  push_exit
969
1189
  end
970
1190
 
971
- def find_workspace_from_lint_log(lint_log, lint_root)
972
- workspace_path = nil
973
-
974
- File.foreach(lint_log, encoding: "UTF-8", invalid: :replace, undef: :replace, replace: "?") do |line|
975
- if (m = line.match(/Pods workspace available at `([^`]+)`/))
976
- workspace_path = m[1].to_s.strip
977
- elsif (m = line.match(%r{(/[^ ]+App\.xcworkspace)}))
978
- workspace_path = m[1].to_s.strip
979
- end
980
- end
981
-
982
- if workspace_path && File.directory?(workspace_path)
983
- return workspace_path
984
- end
985
-
986
- candidates = []
987
- root = File.expand_path(lint_root)
988
- root_depth = root.split(File::SEPARATOR).length
989
-
990
- Find.find(root) do |p|
991
- if File.directory?(p) && p.end_with?(".xcworkspace")
992
- depth = p.split(File::SEPARATOR).length - root_depth
993
- candidates << p if depth <= 4
994
- Find.prune
995
- end
996
- end
997
-
998
- candidates
999
- .select { |p| File.directory?(p) }
1000
- .max_by { |p| File.mtime(p) }
1001
- end
1002
-
1003
1191
  def bump_deployment_targets_in_validation_dir(validation_dir, min_target)
1004
1192
  min_v = parse_version(min_target)
1005
1193
  pattern = /(IPHONEOS_DEPLOYMENT_TARGET\s*=\s*)([0-9]+(?:\.[0-9]+)?)(\s*;?)/
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-bb-PodAssistant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.15.1
4
+ version: 0.3.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - humin