cocoapods-podgenerate 0.1.1 → 0.1.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: a9b3c14400566dae090f4ce380901a448e6aed75b5aab2a9b83e2629c043e547
4
- data.tar.gz: f8ce64ec3991bf97c28aac639a056cb566103cade356a2baf5d3fbac81083573
3
+ metadata.gz: 27602be6d9b287c0d9b46a5ce44325a4ab1ddfcb47e2b6f0c5d40c6ec59cb904
4
+ data.tar.gz: 39039a26b13a8504df307e15afe77bc439541baaa5a5d27cce7b39fa7f61fb87
5
5
  SHA512:
6
- metadata.gz: 2e524501b0080aab551e23973570c0057570c4a0ddf72ec20996c7a0ff0f7de623d2138edbf667e363d3fd9ad22bb40c91d17fd48091c365e1fcfa953e388a1f
7
- data.tar.gz: 7e2d6b08360a4c1d22ec27f0447634293b7d69f992ab13677829d73c997c00819c4fa99f04c346766b35e7541a25d313de80aba78c7a789c08ab1ba3531490c7
6
+ metadata.gz: 74077cdbefbb30767526f247b41f17d98ae02e43d644b03bdc8993fd40c1c7b799e4c4b48bb25a18e7b5a40146d0af9dae093161839eaf019ab9970631295f60
7
+ data.tar.gz: 0306e59218825aae0a218cd756ef04339c53f79c3a2ab69ed255d03b8c84c13900c2cd51f9314a2cb01c1cf8eb7c4eec14e06eada6230009ab0df4b2a68d9247
@@ -2,7 +2,7 @@
2
2
 
3
3
  # [cocoapods-podgenerate]
4
4
  # Performance profiler. Hooks into Pod::Installer to time each phase.
5
- # Output: per-phase wall-clock timing breakdown.
5
+ # Output: per-phase wall-clock timing breakdown with sub-step detail.
6
6
 
7
7
  module Pod
8
8
  module PodGenerate
@@ -23,16 +23,13 @@ module Pod
23
23
  def install
24
24
  return unless enabled?
25
25
  Pod::Installer.prepend(ProfilerHooks)
26
+ Pod::Installer.prepend(ProfilerSubSteps)
26
27
  end
27
28
 
28
29
  def record_phase(name, duration)
29
30
  @phase_timings << [name, duration]
30
31
  end
31
32
 
32
- def swap_or_default(phase_name)
33
- # Called from hooks: returns a timing helper or nil
34
- end
35
-
36
33
  def report
37
34
  return if @phase_timings.empty?
38
35
  total = @phase_timings.map(&:last).sum
@@ -43,9 +40,11 @@ module Pod
43
40
  end
44
41
  Pod::UI.puts " #{'─' * 50}"
45
42
  Pod::UI.puts " #{format('%-35s', 'TOTAL')} #{format('%.2f', total)}s"
43
+ @phase_timings.clear
46
44
  end
47
45
  end
48
46
 
47
+ # Top-level step hooks (v0.1.0)
49
48
  module ProfilerHooks
50
49
  def install!
51
50
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -88,6 +87,50 @@ module Pod
88
87
  Profiler.record_phase(' Integrate user project', elapsed)
89
88
  end
90
89
  end
90
+
91
+ # Sub-step timing hooks (v0.1.2)
92
+ module ProfilerSubSteps
93
+ def stage_sandbox(sandbox, pod_targets)
94
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
95
+ super
96
+ ensure
97
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
98
+ Profiler.record_phase(' Stage sandbox', elapsed) if elapsed > 0.01
99
+ end
100
+
101
+ def analyze_project_cache
102
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
103
+ result = super
104
+ ensure
105
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
106
+ Profiler.record_phase(' Analyze project cache', elapsed) if elapsed > 0.01
107
+ result
108
+ end
109
+
110
+ def create_and_save_projects(*args)
111
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
112
+ super
113
+ ensure
114
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
115
+ Profiler.record_phase(' Create and save projects', elapsed) if elapsed > 0.01
116
+ end
117
+
118
+ def update_project_cache(cache_analysis_result, target_installation_results)
119
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
120
+ super
121
+ ensure
122
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
123
+ Profiler.record_phase(' Update project cache', elapsed) if elapsed > 0.01
124
+ end
125
+
126
+ def write_lockfiles
127
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
128
+ super
129
+ ensure
130
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
131
+ Profiler.record_phase(' Write lockfiles', elapsed)
132
+ end
133
+ end
91
134
  end
92
135
  end
93
136
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # [cocoapods-podgenerate]
4
+ # Monkey-patches ProjectCacheAnalyzer to parallelize cache key computation.
5
+ #
6
+ # v0.1.2 Optimization:
7
+ # 1. Parallel MD5 cache key computation across all pod targets
8
+ #
9
+ # TargetCacheKey.from_pod_target computes MD5 checksums of build settings
10
+ # and collects resource dependencies per target. Each computation is fully
11
+ # independent and can run in parallel.
12
+ #
13
+ # Reference: CocoaPods — lib/cocoapods/installer/project_cache/project_cache_analyzer.rb
14
+
15
+ require 'concurrent'
16
+ require 'etc'
17
+
18
+ module Pod
19
+ module PodGenerate
20
+ module Patches
21
+ module CacheAnalyzerPatch
22
+ def self.apply
23
+ Pod::UI.message '[cocoapods-podgenerate] Applying CacheAnalyzerPatch (parallel cache key computation)'
24
+ Pod::Installer::ProjectCache::ProjectCacheAnalyzer.prepend(ParallelCacheKeyComputation)
25
+ end
26
+
27
+ module ParallelCacheKeyComputation
28
+ # Override create_cache_key_mappings to parallelize MD5 computation
29
+ # The original iterates target_by_label sequentially, computing cache keys.
30
+ # Since each target is independent, we use a thread pool.
31
+ def create_cache_key_mappings(target_by_label)
32
+ UI.message '- Creating cache key mappings (parallel)' do
33
+ pool_size = compute_pool_size
34
+ pool = Concurrent::FixedThreadPool.new(pool_size)
35
+ mutex = Mutex.new
36
+ results = {}
37
+
38
+ target_by_label.each do |label, target|
39
+ pool.post do
40
+ key = case target
41
+ when PodTarget
42
+ local = sandbox.local?(target.pod_name)
43
+ checkout_options = sandbox.checkout_sources[target.pod_name]
44
+ TargetCacheKey.from_pod_target(sandbox, target_by_label, target,
45
+ :is_local_pod => local,
46
+ :checkout_options => checkout_options)
47
+ when AggregateTarget
48
+ TargetCacheKey.from_aggregate_target(sandbox, target_by_label, target)
49
+ else
50
+ raise "[BUG] Unknown target type #{target}"
51
+ end
52
+ mutex.synchronize { results[label] = key }
53
+ rescue StandardError => e
54
+ mutex.synchronize do
55
+ Pod::UI.warn "[cocoapods-podgenerate] Cache key computation error: #{e.message}"
56
+ end
57
+ end
58
+ end
59
+
60
+ pool.shutdown
61
+ pool.wait_for_termination
62
+ results
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def compute_pool_size
69
+ [[Etc.nprocessors - 1, 2].max, 16].min
70
+ rescue NameError
71
+ 4
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -8,14 +8,21 @@
8
8
  # 2. Skip project generation entirely when nothing changed
9
9
  # 3. Parallelize PodTargetIntegrator integration
10
10
  #
11
+ # v0.1.2 Optimization:
12
+ # 4. Parallelize configure_schemes across projects
13
+ #
11
14
  # Reference: CocoaPods — lib/cocoapods/installer.rb
15
+ # lib/cocoapods/installer/xcode/pods_project_generator.rb
16
+
17
+ require 'concurrent'
18
+ require 'etc'
12
19
 
13
20
  module Pod
14
21
  module PodGenerate
15
22
  module Patches
16
23
  module InstallerPatch
17
24
  def self.apply
18
- Pod::UI.message '[cocoapods-podgenerate] Applying InstallerPatch v2'
25
+ Pod::UI.message '[cocoapods-podgenerate] Applying InstallerPatch v3'
19
26
  Pod::Installer.prepend(ForceIncrementalInstall)
20
27
  Pod::Installer::Xcode::PodsProjectGenerator.prepend(ParallelInstall)
21
28
  end
@@ -57,6 +64,74 @@ module Pod
57
64
  Pod::Installer::SandboxDirCleaner.new(sandbox, pod_targets, aggregate_targets).clean!
58
65
  update_project_cache(cache_analysis_result, target_installation_results)
59
66
  end
67
+
68
+ # ── Optimization 3+4: create_and_save_projects with parallel configure_schemes ──
69
+ def create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate,
70
+ build_configurations, project_object_version)
71
+ UI.section 'Generating Pods project' do
72
+ generator = create_generator(pod_targets_to_generate, aggregate_targets_to_generate,
73
+ build_configurations, project_object_version,
74
+ installation_options.generate_multiple_pod_projects)
75
+
76
+ pod_project_generation_result = generator.generate!
77
+ @target_installation_results = pod_project_generation_result.target_installation_results
78
+ @pods_project = pod_project_generation_result.project
79
+ @pod_target_subprojects = pod_project_generation_result.projects_by_pod_targets.keys
80
+ @generated_projects = ([pods_project] + pod_target_subprojects || []).compact
81
+ @generated_pod_targets = pod_targets_to_generate
82
+ @generated_aggregate_targets = aggregate_targets_to_generate || []
83
+ projects_by_pod_targets = pod_project_generation_result.projects_by_pod_targets
84
+
85
+ predictabilize_uuids(generated_projects) if installation_options.deterministic_uuids?
86
+ stabilize_target_uuids(generated_projects)
87
+
88
+ projects_writer = Pod::Installer::Xcode::PodsProjectWriter.new(sandbox, generated_projects,
89
+ target_installation_results.pod_target_installation_results,
90
+ installation_options)
91
+ projects_writer.write! do
92
+ run_podfile_post_install_hooks
93
+ end
94
+
95
+ # Parallel configure_schemes (each project is independent)
96
+ pods_project_pod_targets = pod_targets_to_generate - projects_by_pod_targets.values.flatten
97
+ all_projects_by_pod_targets = {}
98
+ if pods_project
99
+ all_projects_by_pod_targets[pods_project] = pods_project_pod_targets
100
+ end
101
+ all_projects_by_pod_targets.merge!(projects_by_pod_targets) if projects_by_pod_targets
102
+
103
+ if all_projects_by_pod_targets.size > 1
104
+ parallel_configure_schemes(all_projects_by_pod_targets, generator, pod_project_generation_result)
105
+ else
106
+ all_projects_by_pod_targets.each do |project, pts|
107
+ generator.configure_schemes(project, pts, pod_project_generation_result)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def parallel_configure_schemes(projects_by_pod_targets, generator, generation_result)
116
+ pool_size = [[Etc.nprocessors - 1, 2].max, 16].min
117
+ Pod::UI.message "- Configuring schemes across #{projects_by_pod_targets.size} projects (pool: #{pool_size})"
118
+
119
+ pool = Concurrent::FixedThreadPool.new(pool_size)
120
+ projects_by_pod_targets.each do |project, pts|
121
+ pool.post do
122
+ generator.configure_schemes(project, pts, generation_result)
123
+ rescue StandardError => e
124
+ Pod::UI.warn "[cocoapods-podgenerate] Scheme configuration error: #{e.message}"
125
+ end
126
+ end
127
+ pool.shutdown
128
+ pool.wait_for_termination
129
+ rescue NameError
130
+ # Fallback: sequential
131
+ projects_by_pod_targets.each do |project, pts|
132
+ generator.configure_schemes(project, pts, generation_result)
133
+ end
134
+ end
60
135
  end
61
136
 
62
137
  # ── Optimization 3: Parallelize PodTargetIntegrator ──
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ # [cocoapods-podgenerate]
4
+ # Monkey-patches MultiPodsProjectGenerator to parallelize pod target installation.
5
+ #
6
+ # v0.1.2 Optimization:
7
+ # 1. Parallel install_all_pod_targets — each pod target's install is independent I/O
8
+ #
9
+ # Architecture:
10
+ # Instead of overriding create_pods_project (which has Ruby constant resolution issues
11
+ # in prepended modules for PodsProjectGenerator's inner classes), we keep the original
12
+ # project creation + file references sequential, and only parallelize the pod target
13
+ # installation step which is the heaviest I/O operation.
14
+ #
15
+ # Reference: CocoaPods — lib/cocoapods/installer/xcode/multi_pods_project_generator.rb
16
+ # lib/cocoapods/installer/xcode/pods_project_generator.rb
17
+
18
+ require 'concurrent'
19
+ require 'etc'
20
+
21
+ module Pod
22
+ module PodGenerate
23
+ module Patches
24
+ module MultiProjectGeneratorPatch
25
+ def self.apply
26
+ Pod::UI.message '[cocoapods-podgenerate] Applying MultiProjectGeneratorPatch (parallel pod target install)'
27
+ Pod::Installer::Xcode::MultiPodsProjectGenerator.prepend(ParallelMultiProjectGenerator)
28
+ end
29
+
30
+ module ParallelMultiProjectGenerator
31
+ # ── Optimization: Parallel install_all_pod_targets ──
32
+ # Each project has independent pod targets (different xcodeproj directories),
33
+ # so PodTargetInstaller operations can run concurrently without locking.
34
+ def install_all_pod_targets(projects_by_pod_targets)
35
+ UI.message '- Installing Pod Targets (parallel)' do
36
+ pool_size = compute_pool_size
37
+ mutex = Mutex.new
38
+ all_results = {}
39
+
40
+ pool = Concurrent::FixedThreadPool.new(pool_size)
41
+ projects_by_pod_targets.each do |project, pts|
42
+ pool.post do
43
+ target_results = install_pod_targets(project, pts)
44
+ mutex.synchronize { all_results.merge!(target_results) }
45
+ rescue StandardError => e
46
+ mutex.synchronize do
47
+ Pod::UI.warn "[cocoapods-podgenerate] Pod target install: #{e.message}"
48
+ end
49
+ end
50
+ end
51
+
52
+ pool.shutdown
53
+ pool.wait_for_termination
54
+ all_results
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def compute_pool_size
61
+ [[Etc.nprocessors - 1, 2].max, 16].min
62
+ rescue NameError
63
+ 4
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -7,14 +7,21 @@
7
7
  # 1. SHA256 digest — skip sort+save for unchanged projects
8
8
  # 2. Parallel save — multiple xcodeproj files saved in threads
9
9
  #
10
+ # v0.1.2 Optimizations:
11
+ # 3. Parallel cleanup_projects — empty group removal across projects
12
+ # 4. Parallel recreate_user_schemes — scheme file creation across projects
13
+ #
10
14
  # Reference: CocoaPods — lib/cocoapods/installer/xcode/pods_project_generator/pods_project_writer.rb
11
15
 
16
+ require 'concurrent'
17
+ require 'etc'
18
+
12
19
  module Pod
13
20
  module PodGenerate
14
21
  module Patches
15
22
  module ProjectWriterPatch
16
23
  def self.apply
17
- Pod::UI.message '[cocoapods-podgenerate] Applying ProjectWriterPatch v2 (incremental + parallel save)'
24
+ Pod::UI.message '[cocoapods-podgenerate] Applying ProjectWriterPatch v3 (incremental + parallel save + parallel write steps)'
18
25
  Pod::Installer::Xcode::PodsProjectWriter.prepend(IncrementalAndParallelSave)
19
26
  end
20
27
 
@@ -27,7 +34,20 @@ module Pod
27
34
  compute_initial_digests
28
35
  end
29
36
 
30
- # ── Optimization: SHA256 skip + parallel save ──
37
+ # ── Optimizations 3+4+2: Parallel write! with parallel cleanup + schemes + save ──
38
+ def write!
39
+ # Parallel cleanup (each project is independent)
40
+ parallel_cleanup_projects(@projects)
41
+
42
+ # Parallel recreate_user_schemes (each project is independent)
43
+ parallel_recreate_user_schemes(@projects)
44
+
45
+ yield if block_given?
46
+
47
+ save_projects(@projects)
48
+ end
49
+
50
+ # ── Optimization 1: SHA256 skip + parallel save ──
31
51
  def save_projects(projects)
32
52
  # Filter: skip projects whose pbxproj is unchanged
33
53
  to_save = projects.select do |project|
@@ -68,6 +88,87 @@ module Pod
68
88
 
69
89
  private
70
90
 
91
+ # ── Optimization 3: Parallel cleanup_projects ──
92
+
93
+ def parallel_cleanup_projects(projects)
94
+ pool_size = compute_pool_size
95
+ Pod::UI.message "- Cleaning up #{projects.size} projects (pool: #{pool_size})"
96
+
97
+ pool = Concurrent::FixedThreadPool.new(pool_size)
98
+ projects.each do |project|
99
+ pool.post do
100
+ cleanup_single_project(project)
101
+ rescue StandardError => e
102
+ Pod::UI.warn "[cocoapods-podgenerate] Cleanup error: #{e.message}"
103
+ end
104
+ end
105
+ pool.shutdown
106
+ pool.wait_for_termination
107
+ rescue NameError
108
+ cleanup_projects(projects)
109
+ end
110
+
111
+ def cleanup_single_project(project)
112
+ [project.pods, project.support_files_group,
113
+ project.development_pods, project.dependencies_group].each do |group|
114
+ group.remove_from_project if group.respond_to?(:empty?) && group.empty?
115
+ end
116
+ end
117
+
118
+ # ── Optimization 4: Parallel recreate_user_schemes ──
119
+
120
+ def parallel_recreate_user_schemes(projects)
121
+ library_product_types = [:framework, :dynamic_library, :static_library]
122
+
123
+ # Pre-build results_by_native_target once (shared read-only cache)
124
+ results_by_native_target = build_native_target_cache
125
+
126
+ pool_size = compute_pool_size
127
+ Pod::UI.message "- Recreating user schemes for #{projects.size} projects (pool: #{pool_size})"
128
+
129
+ pool = Concurrent::FixedThreadPool.new(pool_size)
130
+ projects.each do |project|
131
+ pool.post do
132
+ project.recreate_user_schemes(false) do |scheme, target|
133
+ next unless target.respond_to?(:symbol_type)
134
+ next unless library_product_types.include?(target.symbol_type)
135
+ installation_result = results_by_native_target[target]
136
+ next unless installation_result
137
+ installation_result.test_native_targets.each do |test_native_target|
138
+ scheme.add_test_target(test_native_target)
139
+ end
140
+ end
141
+ rescue StandardError => e
142
+ Pod::UI.warn "[cocoapods-podgenerate] Scheme recreation error: #{e.message}"
143
+ end
144
+ end
145
+ pool.shutdown
146
+ pool.wait_for_termination
147
+ rescue NameError
148
+ # Fallback: sequential
149
+ projects.each do |project|
150
+ project.recreate_user_schemes(false) do |scheme, target|
151
+ next unless target.respond_to?(:symbol_type)
152
+ next unless library_product_types.include?(target.symbol_type)
153
+ installation_result = results_by_native_target[target]
154
+ next unless installation_result
155
+ installation_result.test_native_targets.each do |test_native_target|
156
+ scheme.add_test_target(test_native_target)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def build_native_target_cache
163
+ cache = {}
164
+ @pod_target_installation_results.each do |_, result|
165
+ cache[result.native_target] = result if result.respond_to?(:native_target)
166
+ end
167
+ cache
168
+ end
169
+
170
+ # ── Digest helpers (from v0.1.1) ──
171
+
71
172
  def compute_initial_digests
72
173
  @projects.each do |project|
73
174
  update_digest(project)
@@ -115,6 +216,12 @@ module Pod
115
216
  rescue StandardError
116
217
  nil
117
218
  end
219
+
220
+ def compute_pool_size
221
+ [[Etc.nprocessors - 1, 2].max, 16].min
222
+ rescue NameError
223
+ 4
224
+ end
118
225
  end
119
226
  end
120
227
  end
@@ -4,39 +4,43 @@
4
4
  # Monkey-patches UserProjectIntegrator to parallelize and optimize the
5
5
  # "Integrating client project" step (step 4 of pod install).
6
6
  #
7
- # For projects with many user targets / aggregate targets, the integration
8
- # step runs serially. This patch:
7
+ # v0.1.1:
9
8
  # 1. Parallelizes integrate_user_targets using threads
10
9
  # 2. Parallelizes save_projects using threads
11
- # 3. Caches user_project references to avoid redundant project parsing
10
+ #
11
+ # v0.1.2:
12
+ # 3. Parallelizes warn_about_xcconfig_overrides using threads
12
13
  #
13
14
  # Reference: CocoaPods source
14
15
  # - lib/cocoapods/installer/user_project_integrator.rb
15
- # - lib/cocoapods/installer/user_project_integrator/target_integrator.rb
16
+
17
+ require 'concurrent'
18
+ require 'etc'
16
19
 
17
20
  module Pod
18
21
  module PodGenerate
19
22
  module Patches
20
23
  module UserIntegratorPatch
24
+ IGNORED_KEYS = %w(CODE_SIGN_IDENTITY).freeze
25
+ INHERITED_FLAGS = %w($(inherited) ${inherited}).freeze
26
+
21
27
  def self.apply
22
- Pod::UI.message '[cocoapods-podgenerate] Applying UserIntegratorPatch (parallel client integration)'
28
+ Pod::UI.message '[cocoapods-podgenerate] Applying UserIntegratorPatch v2 (parallel client integration + xcconfig warnings)'
23
29
  Pod::Installer::UserProjectIntegrator.prepend(ParallelIntegration)
24
30
  end
25
31
 
26
32
  module ParallelIntegration
27
- # Override integrate_user_targets to use parallel execution
33
+ # ── Optimization 1: Parallel integrate_user_targets ──
28
34
  def integrate_user_targets
29
35
  target_integrators = targets_to_integrate.sort_by(&:name).map do |target|
30
36
  Pod::Installer::UserProjectIntegrator::TargetIntegrator.new(target, :use_input_output_paths => use_input_output_paths?)
31
37
  end
32
38
 
33
39
  if target_integrators.size <= 1
34
- # Single target — no need for threads
35
40
  target_integrators.each(&:integrate!)
36
41
  return
37
42
  end
38
43
 
39
- # Multiple targets — integrate in parallel
40
44
  Pod::UI.message "- Integrating #{target_integrators.size} targets in parallel"
41
45
  threads = target_integrators.map do |integrator|
42
46
  Thread.new do
@@ -50,7 +54,7 @@ module Pod
50
54
  threads.each(&:join)
51
55
  end
52
56
 
53
- # Override save_projects to use parallel saving
57
+ # ── Optimization 2: Parallel save_projects ──
54
58
  def save_projects(projects)
55
59
  projects = projects.uniq
56
60
 
@@ -65,7 +69,6 @@ module Pod
65
69
  return
66
70
  end
67
71
 
68
- # Save multiple projects in parallel
69
72
  Pod::UI.message "- Saving #{projects.size} user projects in parallel"
70
73
  mutex = Mutex.new
71
74
  threads = projects.map do |project|
@@ -85,6 +88,58 @@ module Pod
85
88
  end
86
89
  threads.each(&:join)
87
90
  end
91
+
92
+ # ── Optimization 3: Parallel warn_about_xcconfig_overrides ──
93
+ # Overrides the original method by prepend — called automatically from integrate!
94
+ def warn_about_xcconfig_overrides
95
+ targets = targets_to_integrate
96
+ return if targets.empty?
97
+
98
+ if targets.size <= 1
99
+ warn_single_target(targets.first)
100
+ return
101
+ end
102
+
103
+ pool_size = compute_pool_size
104
+ Pod::UI.message "- Checking xcconfig overrides for #{targets.size} targets (pool: #{pool_size})"
105
+ pool = Concurrent::FixedThreadPool.new(pool_size)
106
+ targets.each do |aggregate_target|
107
+ pool.post do
108
+ warn_single_target(aggregate_target)
109
+ rescue StandardError => e
110
+ Pod::UI.warn "[cocoapods-podgenerate] Xcconfig warning error: #{e.message}"
111
+ end
112
+ end
113
+ pool.shutdown
114
+ pool.wait_for_termination
115
+ rescue NameError
116
+ targets.each { |t| warn_single_target(t) }
117
+ end
118
+
119
+ private
120
+
121
+ def warn_single_target(aggregate_target)
122
+ aggregate_target.user_targets.each do |user_target|
123
+ user_target.build_configurations.each do |config|
124
+ xcconfig = aggregate_target.xcconfigs[config.name]
125
+ next unless xcconfig
126
+
127
+ (xcconfig.to_hash.keys - UserIntegratorPatch::IGNORED_KEYS).each do |key|
128
+ target_values = config.build_settings[key]
129
+ if target_values &&
130
+ !UserIntegratorPatch::INHERITED_FLAGS.any? { |flag| target_values.include?(flag) }
131
+ print_override_warning(aggregate_target, user_target, config, key)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ def compute_pool_size
139
+ [[Etc.nprocessors - 1, 2].max, 16].min
140
+ rescue NameError
141
+ 4
142
+ end
88
143
  end
89
144
  end
90
145
  end
@@ -5,6 +5,8 @@ require 'cocoapods-podgenerate/patches/project_patch'
5
5
  require 'cocoapods-podgenerate/patches/project_writer_patch'
6
6
  require 'cocoapods-podgenerate/patches/analyzer_patch'
7
7
  require 'cocoapods-podgenerate/patches/user_integrator_patch'
8
+ require 'cocoapods-podgenerate/patches/multi_project_generator_patch'
9
+ require 'cocoapods-podgenerate/patches/cache_analyzer_patch'
8
10
  require 'cocoapods-podgenerate/parallel/thread_pool'
9
11
  require 'cocoapods-podgenerate/parallel/batch_processor'
10
12
  require 'cocoapods-podgenerate/benchmark/profiler'
@@ -18,6 +20,8 @@ module Pod
18
20
  Pod::PodGenerate::Patches::ProjectWriterPatch.apply
19
21
  Pod::PodGenerate::Patches::AnalyzerPatch.apply
20
22
  Pod::PodGenerate::Patches::UserIntegratorPatch.apply
23
+ Pod::PodGenerate::Patches::MultiProjectGeneratorPatch.apply
24
+ Pod::PodGenerate::Patches::CacheAnalyzerPatch.apply
21
25
 
22
26
  # Install hook for profiler
23
27
  Pod::PodGenerate::Benchmark::Profiler.install
@@ -28,8 +32,6 @@ module Pod
28
32
  end
29
33
 
30
34
  # Auto-activate when loaded via `plugin` directive in Podfile
31
- # The :pre_install hook is set up by hooks.rb, but we also support
32
- # direct `plugin` activation which defers to when CocoaPods is loaded.
33
35
  if defined?(Pod::HooksManager)
34
36
  Pod::PodGenerate.activate
35
37
  else
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.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - PodGenerate Team
@@ -93,7 +93,9 @@ files:
93
93
  - lib/cocoapods-podgenerate/parallel/batch_processor.rb
94
94
  - lib/cocoapods-podgenerate/parallel/thread_pool.rb
95
95
  - lib/cocoapods-podgenerate/patches/analyzer_patch.rb
96
+ - lib/cocoapods-podgenerate/patches/cache_analyzer_patch.rb
96
97
  - lib/cocoapods-podgenerate/patches/installer_patch.rb
98
+ - lib/cocoapods-podgenerate/patches/multi_project_generator_patch.rb
97
99
  - lib/cocoapods-podgenerate/patches/project_patch.rb
98
100
  - lib/cocoapods-podgenerate/patches/project_writer_patch.rb
99
101
  - lib/cocoapods-podgenerate/patches/user_integrator_patch.rb