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 +4 -4
- data/lib/cocoapods-podgenerate/patches/analyzer_patch.rb +35 -31
- data/lib/cocoapods-podgenerate/patches/installer_patch.rb +94 -29
- data/lib/cocoapods-podgenerate/patches/project_writer_patch.rb +7 -5
- data/lib/cocoapods-podgenerate/patches/user_integrator_patch.rb +2 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fcab1469dbb21e1af1ff2024d9ba7f7761719a51c5e55c3b2bef9d36bf5ac991
|
|
4
|
+
data.tar.gz: 2bba05f649c9e47cf55974b53d894428fcdd252d8ae456c638f563704bbd769f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
245
|
+
begin
|
|
246
|
+
path = cache_path
|
|
246
247
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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
|
-
|
|
211
|
-
|
|
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
|
|
145
|
-
|
|
146
|
-
|
|
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)
|