cocoapods-podgenerate 0.1.12 → 0.1.14

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: 4ff95024148a86a27ad23b6b884f1bfda2b1bac59e4c0274ac6b53dac16504fa
4
- data.tar.gz: 6a1fbb763cc83d3dd9245eaa2ae38877f4a4e784fef6651f6003e13b69ab0759
3
+ metadata.gz: 6a0fb718ed83348848126cbcb90a580683859fec7c0f9e82afefe69e58ab67cd
4
+ data.tar.gz: 6f26fbc0e1c1e842dbbbe0d97747d883939a583c9792f7d9988c779bb6236025
5
5
  SHA512:
6
- metadata.gz: 8b5840fbee3dac260a6673f870dfc7ce1bd1f57c47b71e055b9eee7bdbd1cb5361fe65c06702f9f4589fe3aae4475e31b9cc167c34708d49770c56aecacaa4ab
7
- data.tar.gz: a74db8fc1218a2ae364bb15bb200c8b51692515bffe57322295567d9e971680a59efa60f46ce380db1a9982ff545255ba049df9efa034bfd1f3d0f3811a25227
6
+ metadata.gz: b33b6753e7a3852c344b26b5f3c74e994e8e0eec5428f6749f775de1d1367fb79920d35bec4df8662cc80406155ffc05486e9f8ae5021ca61e88f92ca75df13a
7
+ data.tar.gz: a5dfb1691904f9f018660759adbc0de1d15e4865994f43f7174233812cabb8462b59cc515b33f4fbfbfdcc8936f8b99c684aac88943f2df797f4505d18687a94
@@ -13,14 +13,16 @@ module Pod
13
13
  DEFAULT_TIMEOUT = 120
14
14
 
15
15
  class << self
16
- # 计算适合当前机器的线程池大小
17
- # 使用 nproc - 1(为主线程留一个核心),最小 2,最大 16
18
- # @return [Integer] 推荐的线程池大小
19
- def pool_size
20
- [[Etc.nprocessors - 1, 2].max, 16].min
21
- rescue NameError
22
- 4
23
- end
16
+ # 计算适合当前机器的线程池大小
17
+ # 使用 nproc - 1(为主线程留一个核心),最小 2,最大 16
18
+ # 同时提供 pool_size 和 compute_pool_size 两个名称,供各 patch 文件统一使用。
19
+ # @return [Integer] 推荐的线程池大小
20
+ def pool_size
21
+ [[Etc.nprocessors - 1, 2].max, 16].min
22
+ rescue NameError
23
+ 4
24
+ end
25
+ alias compute_pool_size pool_size
24
26
  end
25
27
  end
26
28
  end
@@ -32,7 +32,6 @@
32
32
  # - lib/cocoapods/installer/project_cache/project_cache_analyzer.rb
33
33
 
34
34
  require 'concurrent'
35
- require 'etc'
36
35
 
37
36
  module Pod
38
37
  module PodGenerate
@@ -59,7 +58,7 @@ module Pod
59
58
  # target 标签到缓存键的映射
60
59
  def create_cache_key_mappings(target_by_label)
61
60
  UI.message '- Creating cache key mappings (parallel)' do
62
- pool_size = compute_pool_size
61
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
63
62
  pool = Concurrent::FixedThreadPool.new(pool_size)
64
63
  mutex = Mutex.new
65
64
  results = {}
@@ -115,12 +114,6 @@ module Pod
115
114
  end
116
115
  end
117
116
 
118
- # 计算线程池大小
119
- def compute_pool_size
120
- [[Etc.nprocessors - 1, 2].max, 16].min
121
- rescue NameError
122
- 4
123
- end
124
117
  end
125
118
  end
126
119
  end
@@ -38,7 +38,6 @@
38
38
  # - lib/cocoapods/installer/xcode/pods_project_generator.rb
39
39
 
40
40
  require 'concurrent'
41
- require 'etc'
42
41
 
43
42
  module Pod
44
43
  module PodGenerate
@@ -88,10 +87,25 @@ module Pod
88
87
  stage_sandbox(sandbox, pod_targets)
89
88
 
90
89
  cache_analysis_result = analyze_project_cache
91
- ptg = cache_analysis_result.pod_targets_to_generate
92
- atg = cache_analysis_result.aggregate_targets_to_generate
90
+ ptg = cache_analysis_result.pod_targets_to_generate || []
91
+ atg = cache_analysis_result.aggregate_targets_to_generate || []
92
+
93
+ # ── 本地开发 pod 文件级变更检测 ──
94
+ # CocoaPods 的 TargetCacheKey 使用 spec attributes_hash(如
95
+ # source_files 的 glob 模式字符串)做哈希,不检查 glob 展开后的
96
+ # 实际文件列表。当本地开发 pod(:path)中源文件有增删时,
97
+ # glob 模式不变 → cache key 不变 → ptg 为空 → "No changes" 跳过。
98
+ # 解决方法:为每个开发 pod 计算当前源文件列表的 SHA256,
99
+ # 与上次运行的清单比较,有差异时强制加入 ptg。
100
+ unless sandbox.development_pods.empty?
101
+ dev_changed = detect_dev_pod_file_changes
102
+ unless dev_changed.empty?
103
+ Pod::UI.puts "[cocoapods-podgenerate] Dev pod files changed: #{dev_changed.map(&:pod_name).join(', ')} — forcing regeneration"
104
+ ptg = (ptg + dev_changed).uniq
105
+ end
106
+ end
93
107
 
94
- if ptg.empty? && (atg.nil? || atg.empty?)
108
+ if ptg.empty? && atg.empty?
95
109
  Pod::UI.puts "[cocoapods-podgenerate] No changes — skipping project generation"
96
110
 
97
111
  # C2 修复: 初始化所有实例变量(避免下游代码获得 nil)
@@ -162,7 +176,7 @@ module Pod
162
176
  # 创建空项目降级,避免 post-install hook 中 nil.targets 崩溃
163
177
  # 参考:v0.1.11 — undefined method 'targets' for nil
164
178
  unless @pods_project
165
- Pod::UI.message '[cocoapods-podgenerate] pods_project is nil — creating empty fallback'
179
+ Pod::UI.warn "[cocoapods-podgenerate] pods_project is nil from PodsProjectGenerator — creating empty fallback. This may indicate a CocoaPods internal error or an incompatible version."
166
180
  @pods_project = Pod::Project.new(sandbox.project_path)
167
181
  end
168
182
  @pod_target_subprojects = pod_project_generation_result.projects_by_pod_targets.keys
@@ -275,7 +289,7 @@ module Pod
275
289
  # 每个 scheme 文件是独立的 .xcscheme,存储在不同 xcodeproj 的
276
290
  # xcuserdata 目录中。每个 project 完全独立 → 无锁并行。
277
291
  def parallel_configure_schemes(projects_by_pod_targets, generator, generation_result)
278
- pool_size = [[Etc.nprocessors - 1, 2].max, 16].min
292
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
279
293
  Pod::UI.message "- Configuring schemes across #{projects_by_pod_targets.size} projects (pool: #{pool_size})"
280
294
 
281
295
  # L3 修复: defined? 精确检查类可用性,替代 rescue NameError
@@ -301,6 +315,92 @@ module Pod
301
315
  pool.kill
302
316
  end
303
317
  end
318
+
319
+ # ── 本地开发 pod 文件级变更检测 ──
320
+ #
321
+ # CocoaPods 的 TargetCacheKey 使用 pod_target.root_spec.attributes_hash
322
+ # 作为缓存键的一部分。attributes_hash 中包含 source_files 等 glob 模式
323
+ # 字符串(如 "lib/**/*.rb"),而不是实际展开后的文件列表。
324
+ # 当本地开发 pod 的源文件在文件系统层面发生增删时,glob 模式不变,
325
+ # 缓存键也就不会变化,导致 "No changes — skipping project generation"
326
+ # 漏掉文件级变更。
327
+ #
328
+ # 解决方法:为每个开发 pod 维护一个 SHA256 清单文件,记录其 source_files
329
+ # glob 展开后的实际文件列表的哈希值。每次 pod install 时重新计算并比较。
330
+ # 清单存储在 Pods/.cocoapods-podgenerate-devpod-manifest.yaml 中。
331
+ DEV_POD_FILE_MANIFEST = '.cocoapods-podgenerate-devpod-manifest.yaml'
332
+
333
+ # 检测开发 pod 中源文件是否有增删
334
+ # 返回需要重新生成的 PodTarget 数组
335
+ def detect_dev_pod_file_changes
336
+ dev_pods = sandbox.development_pods
337
+ return [] if dev_pods.empty?
338
+
339
+ manifest_path = File.join(sandbox.root.to_s, DEV_POD_FILE_MANIFEST)
340
+
341
+ # 读取上次记录的 hash 值
342
+ previous = {}
343
+ if File.exist?(manifest_path)
344
+ begin
345
+ data = YAML.safe_load(File.read(manifest_path))
346
+ previous = data if data.is_a?(Hash)
347
+ rescue => e
348
+ Pod::UI.warn "[cocoapods-podgenerate] Failed to read dev pod manifest: #{e.message}"
349
+ end
350
+ end
351
+
352
+ current = {}
353
+ changed = []
354
+
355
+ pod_targets.each do |pt|
356
+ name = pt.pod_name
357
+ next unless dev_pods.key?(name)
358
+
359
+ current[name] = compute_dev_pod_file_digest(pt)
360
+ if previous[name] != current[name]
361
+ changed << pt
362
+ end
363
+ end
364
+
365
+ # 持久化当前清单
366
+ begin
367
+ File.write(manifest_path, YAML.dump(current))
368
+ rescue => e
369
+ Pod::UI.warn "[cocoapods-podgenerate] Failed to write dev pod manifest: #{e.message}"
370
+ end
371
+
372
+ changed
373
+ end
374
+
375
+ # 计算开发 pod 当前源文件列表的 SHA256
376
+ # 使用 podspec 中的 source_files/headers glob 模式,
377
+ # 在文件系统层面展开后对相对路径排序做哈希。
378
+ # @return [String] 十六进制 SHA256(空文件列表则是空字符串哈希)
379
+ def compute_dev_pod_file_digest(pod_target)
380
+ pod_name = pod_target.pod_name
381
+ pod_dir = sandbox.pod_dir(pod_name)
382
+ return '' unless pod_dir && File.directory?(pod_dir)
383
+
384
+ pod_dir_str = pod_dir.to_s
385
+ files = []
386
+
387
+ pod_target.spec_consumers.each do |consumer|
388
+ patterns = []
389
+ patterns.concat(Array(consumer.source_files))
390
+ patterns.concat(Array(consumer.public_header_files))
391
+ patterns.concat(Array(consumer.private_header_files))
392
+
393
+ patterns.each do |pattern|
394
+ full_pattern = File.join(pod_dir_str, pattern)
395
+ Dir.glob(full_pattern).each do |f|
396
+ next unless File.file?(f)
397
+ files << f.sub("#{pod_dir_str}/", '')
398
+ end
399
+ end
400
+ end
401
+
402
+ Digest::SHA256.hexdigest(files.uniq.sort.join("\n"))
403
+ end
304
404
  end
305
405
 
306
406
  # ── 优化 3: 并行化 PodTargetIntegrator(修复 M3)──
@@ -338,7 +438,7 @@ module Pod
338
438
  end
339
439
 
340
440
  # 多 target: 使用线程池并行集成(M3 修复)
341
- pool_size = [[Etc.nprocessors - 1, 2].max, 16].min
441
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
342
442
  pool = Concurrent::FixedThreadPool.new(pool_size)
343
443
 
344
444
  pods_to_integrate.each do |result|
@@ -25,7 +25,6 @@
25
25
  # - lib/cocoapods/installer/xcode/pods_project_generator.rb
26
26
 
27
27
  require 'concurrent'
28
- require 'etc'
29
28
 
30
29
  module Pod
31
30
  module PodGenerate
@@ -53,7 +52,7 @@ module Pod
53
52
  # pod target 名称到安装结果的映射
54
53
  def install_all_pod_targets(projects_by_pod_targets)
55
54
  UI.message '- Installing Pod Targets (parallel)' do
56
- pool_size = compute_pool_size
55
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
57
56
  mutex = Mutex.new
58
57
  all_results = {}
59
58
  errors = [] # v0.1.4: 收集错误而不是静默吞掉
@@ -90,14 +89,6 @@ module Pod
90
89
 
91
90
  private
92
91
 
93
- # 计算适合当前机器的线程池大小
94
- # 使用 CPU 核心数 - 1(为主线程留一个),最小 2,最大 16
95
- # @return [Integer]
96
- def compute_pool_size
97
- [[Etc.nprocessors - 1, 2].max, 16].min
98
- rescue NameError
99
- 4 # Etc 不可用时的安全回退
100
- end
101
92
  end
102
93
  end
103
94
  end
@@ -33,7 +33,6 @@
33
33
 
34
34
  require 'digest'
35
35
  require 'concurrent'
36
- require 'etc'
37
36
 
38
37
  module Pod
39
38
  module PodGenerate
@@ -142,7 +141,7 @@ module Pod
142
141
  # 每个 project 独立,使用 Concurrent::FixedThreadPool 并行执行。
143
142
  # 如果 concurrent-ruby 不可用(NameError),回退到串行处理。
144
143
  def parallel_cleanup_projects(projects)
145
- pool_size = compute_pool_size
144
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
146
145
  Pod::UI.message "- Cleaning up #{projects.size} projects (pool: #{pool_size})"
147
146
 
148
147
  pool = begin
@@ -187,7 +186,7 @@ module Pod
187
186
  # 预构建 native target → InstallationResult 的查找缓存(只读、线程安全)
188
187
  results_by_native_target = build_native_target_cache
189
188
 
190
- pool_size = compute_pool_size
189
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
191
190
  Pod::UI.message "- Recreating user schemes for #{projects.size} projects (pool: #{pool_size})"
192
191
 
193
192
  pool = begin
@@ -292,12 +291,6 @@ module Pod
292
291
  nil
293
292
  end
294
293
 
295
- # 计算线程池大小
296
- def compute_pool_size
297
- [[Etc.nprocessors - 1, 2].max, 16].min
298
- rescue NameError
299
- 4
300
- end
301
294
  end
302
295
  end
303
296
  end
@@ -15,7 +15,6 @@
15
15
  # - lib/cocoapods/installer/user_project_integrator.rb
16
16
 
17
17
  require 'concurrent'
18
- require 'etc'
19
18
 
20
19
  module Pod
21
20
  module PodGenerate
@@ -83,7 +82,8 @@ module Pod
83
82
  projects = projects.uniq
84
83
 
85
84
  if projects.size <= 1
86
- projects.each do |project|
85
+ project = projects.first
86
+ if project
87
87
  if project.dirty?
88
88
  project.save
89
89
  else
@@ -133,7 +133,7 @@ module Pod
133
133
  return
134
134
  end
135
135
 
136
- pool_size = compute_pool_size
136
+ pool_size = Pod::PodGenerate::Parallel::ThreadPool.compute_pool_size
137
137
  Pod::UI.message "- Checking xcconfig overrides for #{targets.size} targets (pool: #{pool_size})"
138
138
  pool = Concurrent::FixedThreadPool.new(pool_size)
139
139
  targets.each do |aggregate_target|
@@ -187,11 +187,6 @@ module Pod
187
187
  end
188
188
  end
189
189
 
190
- def compute_pool_size
191
- [[Etc.nprocessors - 1, 2].max, 16].min
192
- rescue NameError
193
- 4
194
- end
195
190
  end
196
191
  end
197
192
  end
@@ -23,7 +23,6 @@ require 'cocoapods-podgenerate/patches/user_integrator_patch'
23
23
  require 'cocoapods-podgenerate/patches/multi_project_generator_patch'
24
24
  require 'cocoapods-podgenerate/patches/cache_analyzer_patch'
25
25
  require 'cocoapods-podgenerate/parallel/thread_pool'
26
- require 'cocoapods-podgenerate/parallel/batch_processor'
27
26
  require 'cocoapods-podgenerate/benchmark/profiler'
28
27
 
29
28
  module Pod
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.12
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - PodGenerate Team
@@ -90,7 +90,6 @@ files:
90
90
  - lib/cocoapods-podgenerate/benchmark/profiler.rb
91
91
  - lib/cocoapods-podgenerate/command.rb
92
92
  - lib/cocoapods-podgenerate/hooks.rb
93
- - lib/cocoapods-podgenerate/parallel/batch_processor.rb
94
93
  - lib/cocoapods-podgenerate/parallel/thread_pool.rb
95
94
  - lib/cocoapods-podgenerate/patches/analyzer_patch.rb
96
95
  - lib/cocoapods-podgenerate/patches/cache_analyzer_patch.rb
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # [cocoapods-podgenerate]
4
- # 批处理器 — 将工作项在线程池中并行分配处理。
5
- #
6
- # 用于将需要并行化的批量任务分配到 Concurrent::FixedThreadPool,
7
- # 保持结果的输入顺序(通过索引数组)。
8
- #
9
- # v0.1.4 改进:
10
- # - wait_for_termination 添加超时(120s)防止死锁
11
- # - 移除未使用的 batch_size 和 completed 变量
12
-
13
- require 'concurrent'
14
- require_relative 'thread_pool'
15
-
16
- module Pod
17
- module PodGenerate
18
- module Parallel
19
- module BatchProcessor
20
- # 在线程池中并行处理项目,保持结果的输入顺序
21
- #
22
- # @param items [Array] 要处理的项目列表
23
- # @param pool [Concurrent::FixedThreadPool] 线程池实例
24
- # @yield [item] 处理每个项目的代码块
25
- # @return [Array] 结果列表,顺序与输入相同(nil 表示处理失败的项目)
26
- def self.process(items, pool:, &block)
27
- return [] if items.empty?
28
-
29
- results = Array.new(items.size)
30
- mutex = Mutex.new
31
-
32
- items.each_with_index do |item, idx|
33
- pool.post do
34
- result = block.call(item)
35
- mutex.synchronize { results[idx] = result }
36
- rescue StandardError => e
37
- Pod::UI.warn "[cocoapods-podgenerate] BatchProcessor error on item #{idx}: #{e.message}"
38
- end
39
- end
40
-
41
- # v0.1.4: 带超时的等待
42
- pool.shutdown
43
- unless pool.wait_for_termination(Pod::PodGenerate::Parallel::ThreadPool::DEFAULT_TIMEOUT)
44
- Pod::UI.warn '[cocoapods-podgenerate] BatchProcessor timed out after 120s'
45
- pool.kill
46
- end
47
-
48
- results
49
- end
50
- end
51
- end
52
- end
53
- end