cocoapods-podgenerate 0.1.4 → 0.1.8

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: b6d26a277c924f83166f71d24a5c4268faac627ec35aa125b7771ba4f962d035
4
- data.tar.gz: cf7d5a1740bcce3e2d9b55301ed07ae1a73a33083a1199e0027824eaf7c13e18
3
+ metadata.gz: fcab1469dbb21e1af1ff2024d9ba7f7761719a51c5e55c3b2bef9d36bf5ac991
4
+ data.tar.gz: 2bba05f649c9e47cf55974b53d894428fcdd252d8ae456c638f563704bbd769f
5
5
  SHA512:
6
- metadata.gz: 2bf8fcda7f3bd691211959324e96bc61fa74172675ff1c93a518727513299104108689d844059e446510d07bc7b1a52a229032bd7c3e1483502df83ebe15e8ae
7
- data.tar.gz: 50eae7e57d1883adf0dd706b1a67e31760670e088de0c2d45aeee22491243f44e6e00d8fd8ce592f1fe858e01c8d393bc69b62c98894e28b97efafea05a8683e
6
+ metadata.gz: 6d92ebe86345558f686219e98fcb9685c9955794d2dbdcc508832460966ff65b79203144c70738789499f2b9ab883ecea5f8f5eca051da40146892ad05587c36
7
+ data.tar.gz: efee76fa98a79f2088d641f0819bf659d4cae5182d31a5f7e7fa20af8a87c6dfb25c7d51750e27553e29b1956eab2590dd9a60c9a586152220108127273bbca5
@@ -242,41 +242,45 @@ module Pod
242
242
  # @param cache_key [String] 缓存键,写入文件头部供下次 load 验证
243
243
  # @param result [Hash{TargetDefinition => Array<Specification>}] Molinillo 解析结果
244
244
  def save_cached_result(cache_key, result)
245
- path = cache_path
245
+ begin
246
+ path = cache_path
246
247
 
247
- # 提取纯数据:从 Specification 对象中只取名称和版本号
248
- # Specification.root.name 返回 pod 的根名称(不含 subspec 后缀)
249
- # Specification.version.to_s 返回版本号字符串(如 "1.2.3")
250
- targets_data = {}
251
- result.each do |target_def, specs|
252
- pod_list = specs.map do |spec|
253
- {
254
- 'pod_name' => spec.root.name,
255
- 'version' => spec.version.to_s,
256
- }
248
+ # 提取纯数据:从 Specification 对象中只取名称和版本号
249
+ # 使用 respond_to? 安全检查确保 result 是预期的格式
250
+ targets_data = {}
251
+ if result.respond_to?(:each)
252
+ result.each do |target_def, specs|
253
+ next unless specs.respond_to?(:map)
254
+ pod_list = specs.map do |spec|
255
+ next unless spec.respond_to?(:root) && spec.root.respond_to?(:name) &&
256
+ spec.respond_to?(:version)
257
+ {
258
+ 'pod_name' => spec.root.name,
259
+ 'version' => spec.version.to_s,
260
+ }
261
+ end.compact
262
+ pod_list.uniq! { |entry| entry['pod_name'] }
263
+ target_name = target_def.respond_to?(:name) ? target_def.name : target_def.to_s
264
+ targets_data[target_name] = pod_list unless pod_list.empty?
265
+ end
257
266
  end
258
- # 去重:同一个 pod 的多个 subspec 共享相同的 root.name
259
- pod_list.uniq! { |entry| entry['pod_name'] }
260
- targets_data[target_def.name] = pod_list unless pod_list.empty?
261
- end
262
267
 
263
- # 组装缓存数据
264
- data = {
265
- 'cache_key' => cache_key,
266
- 'timestamp' => Time.now.to_s,
267
- 'cocoaPods_version' => Pod::VERSION,
268
- 'pod_count' => targets_data.values.flatten.size,
269
- 'targets' => targets_data,
270
- }
268
+ # 组装缓存数据
269
+ data = {
270
+ 'cache_key' => cache_key,
271
+ 'timestamp' => Time.now.to_s,
272
+ 'cocoaPods_version' => Pod::VERSION,
273
+ 'pod_count' => targets_data.values.flatten.size,
274
+ 'targets' => targets_data,
275
+ }
271
276
 
272
- # 原子写入:先写临时文件,成功后再 rename
273
- tmp_path = "#{path}.tmp"
274
- File.write(tmp_path, YAML.dump(data))
275
- File.rename(tmp_path, path)
276
- rescue StandardError => e
277
- # 缓存保存失败不应中断 pod install 主流程
278
- # 最坏情况:下次运行时缓存 MISS → 正常 Molinillo 解析
279
- Pod::UI.warn "[cocoapods-podgenerate] 保存解析缓存失败: #{e.message}"
277
+ # 原子写入:先写临时文件,成功后再 rename
278
+ tmp_path = "#{path}.tmp"
279
+ File.write(tmp_path, YAML.dump(data))
280
+ File.rename(tmp_path, path)
281
+ rescue StandardError => e
282
+ Pod::UI.warn "[cocoapods-podgenerate] 保存解析缓存失败: #{e.message}"
283
+ end
280
284
  end
281
285
  end
282
286
  end
@@ -22,7 +22,10 @@
22
22
  # v0.1.4 修复:
23
23
  # - C2: 快速跳过路径设置缺失的 @pods_project/@pod_target_subprojects/@generated_projects
24
24
  # 并确保 run_podfile_post_install_hooks 被调用(即使在跳过路径上)
25
- # - H1: 跳过路径不再传入空 InstallationResults,而是保留上次的 @target_installation_results
25
+ # - H1: 跳过路径不再调用 update_project_cache(@target_installation_results 在跳过路径
26
+ # 上始终为 nil,回退到空 InstallationResults 会清除 metadata_cache 导致下次全量重建)
27
+ # - L3: parallel_configure_schemes 用 defined?(Concurrent::FixedThreadPool) 替代
28
+ # 宽泛的 rescue NameError(NameError 可能吞掉无关的未定义常量/变量错误)
26
29
  # - M1: wait_for_termination 使用 ThreadPool::DEFAULT_TIMEOUT
27
30
  # - M3: integrate_targets 改用 Concurrent::FixedThreadPool(限制并发数,避免 200 线程)
28
31
  #
@@ -94,9 +97,12 @@ module Pod
94
97
  # C2 修复: 初始化所有实例变量(避免下游代码获得 nil)
95
98
  @generated_aggregate_targets = aggregate_targets
96
99
  @generated_pod_targets = []
97
- @pods_project = nil
100
+ # 修复: 创建空项目替代 nil,避免 post-install hooks 中
101
+ # installer.pods_project 返回 nil 导致 .targets 等调用崩溃
102
+ # (例如 Flutter podhelper.rb 访问 pods_project.targets)
103
+ @pods_project = Pod::Project.new(sandbox.project_path)
98
104
  @pod_target_subprojects = []
99
- @generated_projects = []
105
+ @generated_projects = [@pods_project]
100
106
 
101
107
  # C2 修复: 确保 post-install hooks 被调用
102
108
  run_podfile_post_install_hooks
@@ -104,10 +110,13 @@ module Pod
104
110
  # 清理沙盒中残留的文件
105
111
  Pod::Installer::SandboxDirCleaner.new(sandbox, pod_targets, aggregate_targets).clean!
106
112
 
107
- # H1 修复: 使用上次的安装结果(而非空结果)更新缓存
108
- prev_results = @target_installation_results ||
109
- Pod::Installer::Xcode::PodsProjectGenerator::InstallationResults.new({}, {})
110
- update_project_cache(cache_analysis_result, prev_results)
113
+ # H1 修复: 当没有目标需要生成时,跳过 update_project_cache 调用
114
+ # @target_installation_results 仅在 create_and_save_projects 内设置,
115
+ # 在跳过路径上始终为 nil,回退到空 InstallationResults.new({}, {})
116
+ # 会导致 metadata_cache 中所有 pod target 的安装结果被清除,
117
+ # 下次运行时触发全量重建(cache 损坏)。
118
+ # 跳过路径的正确行为:不更新任何缓存,因为没有任何变化,
119
+ # 已有的缓存状态仍然有效。
111
120
  return
112
121
  end
113
122
 
@@ -154,6 +163,16 @@ module Pod
154
163
  projects_writer = Pod::Installer::Xcode::PodsProjectWriter.new(sandbox, generated_projects,
155
164
  target_installation_results.pod_target_installation_results,
156
165
  installation_options)
166
+
167
+ # 解析跨项目依赖:当 generate_multiple_pod_projects 启用后,
168
+ # 主项目的 aggregate target 通过 PBXContainerItemProxy 引用子项目的 pod target。
169
+ # Xcodeproj 无法解析这些跨项目引用,PBXTargetDependency#target 返回 nil。
170
+ # 这会导致递归遍历依赖链的工具(如 Flutter podhelper.rb 的
171
+ # depends_on_flutter)在访问 nil.target 时崩溃。
172
+ # 解决方法:在 post-install hooks 运行前,将子项目 target 的引用
173
+ # 直接挂载到主项目的 PBXTargetDependency.target 上。
174
+ resolve_cross_project_dependencies
175
+
157
176
  projects_writer.write! do
158
177
  run_podfile_post_install_hooks
159
178
  end
@@ -178,40 +197,86 @@ module Pod
178
197
 
179
198
  private
180
199
 
181
- # 并行配置所有项目的 scheme 文件
200
+ # 解析跨项目 target 依赖关系
201
+ #
202
+ # generate_multiple_pod_projects 启用时,每个 pod target 位于独立的
203
+ # .xcodeproj 子项目中。主项目(Pods.xcodeproj)中的 aggregate target
204
+ # 通过 PBXTargetDependency + PBXContainerItemProxy 引用子项目中的目标。
205
+ # Xcodeproj 在读取主项目时不会自动加载子项目,因此
206
+ # PBXTargetDependency#target 对于跨项目引用返回 nil。
207
+ #
208
+ # 在 post-install hooks 执行前,将子项目中实际的 target 对象关联到
209
+ # 主项目的 PBXTargetDependency.target 上,使得依赖链遍历可以正常工作。
210
+ # 这对于 Flutter podhelper.rb 的 depends_on_flutter 递归函数尤为重要。
211
+ def resolve_cross_project_dependencies
212
+ return unless @pods_project && @pod_target_subprojects
213
+ return if @pod_target_subprojects.empty?
214
+
215
+ # 构建 UUID → target 查找表(从所有子项目中)
216
+ remote_targets = {}
217
+ @pod_target_subprojects.each do |sub_project|
218
+ sub_project.targets.each do |target|
219
+ remote_targets[target.uuid] = target
220
+ end
221
+ end
222
+
223
+ return if remote_targets.empty?
224
+
225
+ resolved = 0
226
+ # 遍历主项目中所有 target 的依赖
227
+ @pods_project.targets.each do |target|
228
+ target.dependencies.each do |dependency|
229
+ # 已解析的(同一项目内)跳过
230
+ next if dependency.target
231
+ # 无 proxy 引用说明不是跨项目依赖,也跳过
232
+ next unless dependency.target_proxy
233
+
234
+ remote_uuid = dependency.target_proxy.remote_global_id_string
235
+ next unless remote_uuid
236
+
237
+ remote_target = remote_targets[remote_uuid]
238
+ next unless remote_target
239
+
240
+ dependency.target = remote_target
241
+ resolved += 1
242
+ end
243
+ end
244
+
245
+ return unless resolved > 0
246
+
247
+ Pod::UI.message "[cocoapods-podgenerate] Resolved #{resolved} cross-project target dependencies"
248
+ end
249
+
250
+ # ── 并行配置 scheme ──
182
251
  #
183
252
  # 每个 scheme 文件是独立的 .xcscheme,存储在不同 xcodeproj 的
184
253
  # xcuserdata 目录中。每个 project 完全独立 → 无锁并行。
185
- #
186
- # v0.1.4: rescue 范围缩小到只包裹 Concurrent::FixedThreadPool 创建
187
254
  def parallel_configure_schemes(projects_by_pod_targets, generator, generation_result)
188
255
  pool_size = [[Etc.nprocessors - 1, 2].max, 16].min
189
256
  Pod::UI.message "- Configuring schemes across #{projects_by_pod_targets.size} projects (pool: #{pool_size})"
190
257
 
191
- pool = begin
192
- Concurrent::FixedThreadPool.new(pool_size)
193
- rescue NameError
194
- nil # concurrent-ruby 不可用,回退到串行
195
- end
196
-
197
- if pool
258
+ # L3 修复: defined? 精确检查类可用性,替代 rescue NameError
259
+ unless defined?(Concurrent::FixedThreadPool)
260
+ # 回退到顺序执行(concurrent-ruby 中的 FixedThreadPool 不可用)
198
261
  projects_by_pod_targets.each do |project, pts|
199
- pool.post do
200
- generator.configure_schemes(project, pts, generation_result)
201
- rescue StandardError => e
202
- Pod::UI.warn "[cocoapods-podgenerate] Scheme configuration error: #{e.message}"
203
- end
204
- end
205
- pool.shutdown
206
- unless pool.wait_for_termination(Pod::PodGenerate::Parallel::ThreadPool::DEFAULT_TIMEOUT)
207
- Pod::UI.warn '[cocoapods-podgenerate] Scheme configuration timed out'
208
- pool.kill
262
+ generator.configure_schemes(project, pts, generation_result)
209
263
  end
210
- else
211
- projects_by_pod_targets.each do |project, pts|
264
+ return
265
+ end
266
+
267
+ pool = Concurrent::FixedThreadPool.new(pool_size)
268
+ projects_by_pod_targets.each do |project, pts|
269
+ pool.post do
212
270
  generator.configure_schemes(project, pts, generation_result)
271
+ rescue StandardError => e
272
+ Pod::UI.warn "[cocoapods-podgenerate] Scheme configuration error: #{e.message}"
213
273
  end
214
274
  end
275
+ pool.shutdown
276
+ unless pool.wait_for_termination(Pod::PodGenerate::Parallel::ThreadPool::DEFAULT_TIMEOUT)
277
+ Pod::UI.warn '[cocoapods-podgenerate] Scheme configuration timed out'
278
+ pool.kill
279
+ end
215
280
  end
216
281
  end
217
282
 
@@ -141,9 +141,11 @@ module Pod
141
141
 
142
142
  if pool
143
143
  projects.each do |project|
144
- pool.post { cleanup_single_project(project) }
145
- rescue StandardError => e
146
- Pod::UI.warn "[cocoapods-podgenerate] Cleanup error: #{e.message}"
144
+ pool.post do
145
+ cleanup_single_project(project)
146
+ rescue StandardError => e
147
+ Pod::UI.warn "[cocoapods-podgenerate] Cleanup error: #{e.message}"
148
+ end
147
149
  end
148
150
  pool.shutdown
149
151
  pool.wait_for_termination(Pod::PodGenerate::Parallel::ThreadPool::DEFAULT_TIMEOUT) || pool.kill
@@ -186,9 +188,9 @@ module Pod
186
188
  projects.each do |project|
187
189
  pool.post do
188
190
  recreate_schemes_for_project(project, library_product_types, results_by_native_target)
191
+ rescue StandardError => e
192
+ Pod::UI.warn "[cocoapods-podgenerate] Scheme recreation error: #{e.message}"
189
193
  end
190
- rescue StandardError => e
191
- Pod::UI.warn "[cocoapods-podgenerate] Scheme recreation error: #{e.message}"
192
194
  end
193
195
  pool.shutdown
194
196
  pool.wait_for_termination(Pod::PodGenerate::Parallel::ThreadPool::DEFAULT_TIMEOUT) || pool.kill
@@ -64,6 +64,8 @@ module Pod
64
64
  threads = groups.map do |project, integrators|
65
65
  Thread.new do
66
66
  integrators.each(&:integrate!)
67
+ rescue StandardError => e
68
+ Pod::UI.warn "[cocoapods-podgenerate] Integrate error for #{project.path}: #{e.message}"
67
69
  end
68
70
  end
69
71
  threads.each(&:join)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-podgenerate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - PodGenerate Team