cocoapods-tt 0.0.1

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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. metadata +193 -0
@@ -0,0 +1,1044 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'fileutils'
3
+ require 'cocoapods/podfile'
4
+
5
+ module Pod
6
+ # The Installer is responsible of taking a Podfile and transform it in the
7
+ # Pods libraries. It also integrates the user project so the Pods
8
+ # libraries can be used out of the box.
9
+ #
10
+ # The Installer is capable of doing incremental updates to an existing Pod
11
+ # installation.
12
+ #
13
+ # The Installer gets the information that it needs mainly from 3 files:
14
+ #
15
+ # - Podfile: The specification written by the user that contains
16
+ # information about targets and Pods.
17
+ # - Podfile.lock: Contains information about the pods that were previously
18
+ # installed and in concert with the Podfile provides information about
19
+ # which specific version of a Pod should be installed. This file is
20
+ # ignored in update mode.
21
+ # - Manifest.lock: A file contained in the Pods folder that keeps track of
22
+ # the pods installed in the local machine. This files is used once the
23
+ # exact versions of the Pods has been computed to detect if that version
24
+ # is already installed. This file is not intended to be kept under source
25
+ # control and is a copy of the Podfile.lock.
26
+ #
27
+ # The Installer is designed to work in environments where the Podfile folder
28
+ # is under source control and environments where it is not. The rest of the
29
+ # files, like the user project and the workspace are assumed to be under
30
+ # source control.
31
+ #
32
+ class Installer
33
+ autoload :Analyzer, 'cocoapods/installer/analyzer'
34
+ autoload :InstallationOptions, 'cocoapods/installer/installation_options'
35
+ autoload :PostInstallHooksContext, 'cocoapods/installer/post_install_hooks_context'
36
+ autoload :PreInstallHooksContext, 'cocoapods/installer/pre_install_hooks_context'
37
+ autoload :BaseInstallHooksContext, 'cocoapods/installer/base_install_hooks_context'
38
+ autoload :PostIntegrateHooksContext, 'cocoapods/installer/post_integrate_hooks_context'
39
+ autoload :PreIntegrateHooksContext, 'cocoapods/installer/pre_integrate_hooks_context'
40
+ autoload :SourceProviderHooksContext, 'cocoapods/installer/source_provider_hooks_context'
41
+ autoload :PodfileValidator, 'cocoapods/installer/podfile_validator'
42
+ autoload :PodSourceInstaller, 'cocoapods/installer/pod_source_installer'
43
+ autoload :PodSourcePreparer, 'cocoapods/installer/pod_source_preparer'
44
+ autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
45
+ autoload :Xcode, 'cocoapods/installer/xcode'
46
+ autoload :SandboxHeaderPathsInstaller, 'cocoapods/installer/sandbox_header_paths_installer'
47
+ autoload :SandboxDirCleaner, 'cocoapods/installer/sandbox_dir_cleaner'
48
+ autoload :ProjectCache, 'cocoapods/installer/project_cache/project_cache'
49
+ autoload :TargetUUIDGenerator, 'cocoapods/installer/target_uuid_generator'
50
+
51
+ include Config::Mixin
52
+
53
+ MASTER_SPECS_REPO_GIT_URL = 'https://github.com/CocoaPods/Specs.git'.freeze
54
+
55
+ # @return [Sandbox] The sandbox where the Pods should be installed.
56
+ #
57
+ attr_reader :sandbox
58
+
59
+ # @return [Podfile] The Podfile specification that contains the information
60
+ # of the Pods that should be installed.
61
+ #
62
+ attr_reader :podfile
63
+
64
+ # @return [Lockfile] The Lockfile that stores the information about the
65
+ # Pods previously installed on any machine.
66
+ #
67
+ attr_reader :lockfile
68
+
69
+ # Initialize a new instance
70
+ #
71
+ # @param [Sandbox] sandbox @see #sandbox
72
+ # @param [Podfile] podfile @see #podfile
73
+ # @param [Lockfile] lockfile @see #lockfile
74
+ #
75
+ def initialize(sandbox, podfile, lockfile = nil)
76
+ @sandbox = sandbox || raise(ArgumentError, 'Missing required argument `sandbox`')
77
+ @podfile = podfile || raise(ArgumentError, 'Missing required argument `podfile`')
78
+ @lockfile = lockfile
79
+
80
+ @use_default_plugins = true
81
+ @has_dependencies = true
82
+ @pod_installers = []
83
+ end
84
+
85
+ # @return [Hash, Boolean, nil] Pods that have been requested to be
86
+ # updated or true if all Pods should be updated.
87
+ # If all Pods should been updated the contents of the Lockfile are
88
+ # not taken into account for deciding what Pods to install.
89
+ #
90
+ attr_accessor :update
91
+
92
+ # @return [Boolean] Whether it has dependencies. Defaults to true.
93
+ #
94
+ attr_accessor :has_dependencies
95
+ alias_method :has_dependencies?, :has_dependencies
96
+
97
+ # @return [Boolean] Whether the spec repos should be updated.
98
+ #
99
+ attr_accessor :repo_update
100
+ alias_method :repo_update?, :repo_update
101
+
102
+ # @return [Boolean] Whether default plugins should be used during
103
+ # installation. Defaults to true.
104
+ #
105
+ attr_accessor :use_default_plugins
106
+ alias_method :use_default_plugins?, :use_default_plugins
107
+
108
+ # @return [Boolean] Whether installation should verify that there are no
109
+ # Podfile or Lockfile changes. Defaults to false.
110
+ #
111
+ attr_accessor :deployment
112
+ alias_method :deployment?, :deployment
113
+
114
+ # @return [Boolean] Whether installation should ignore the contents of the project cache
115
+ # when incremental installation is enabled.
116
+ #
117
+ attr_accessor :clean_install
118
+ alias_method :clean_install?, :clean_install
119
+
120
+ #-------------------------------------------------------------------------#
121
+
122
+ private
123
+
124
+ # @return [Array<PodSourceInstaller>] the pod installers created
125
+ # while installing pod targets
126
+ #
127
+ attr_reader :pod_installers
128
+
129
+ # @return [ProjectInstallationCache] The installation cache stored in Pods/.project_cache/installation_cache
130
+ #
131
+ attr_reader :installation_cache
132
+
133
+ # @return [ProjectMetadataCache] The metadata cache stored in Pods/.project_cache/metadata_cache
134
+ #
135
+ attr_reader :metadata_cache
136
+
137
+ # @return [ProjectCacheVersion] The version of the project cache stored in Pods/.project_cache/version
138
+ #
139
+ attr_reader :project_cache_version
140
+
141
+ #-------------------------------------------------------------------------#
142
+
143
+ public
144
+
145
+ # Installs the Pods.
146
+ #
147
+ # The installation process is mostly linear with a few minor complications
148
+ # to keep in mind:
149
+ #
150
+ # - The stored podspecs need to be cleaned before the resolution step
151
+ # otherwise the sandbox might return an old podspec and not download
152
+ # the new one from an external source.
153
+ # - The resolver might trigger the download of Pods from external sources
154
+ # necessary to retrieve their podspec (unless it is instructed not to
155
+ # do it).
156
+ #
157
+ # @return [void]
158
+ #
159
+ def install!
160
+ prepare
161
+ resolve_dependencies
162
+ download_dependencies
163
+ validate_targets
164
+ if installation_options.skip_pods_project_generation?
165
+ show_skip_pods_project_generation_message
166
+ else
167
+ integrate
168
+ end
169
+ write_lockfiles
170
+ perform_post_install_actions
171
+ end
172
+
173
+ def show_skip_pods_project_generation_message
174
+ UI.section 'Skipping Pods Project Creation'
175
+ UI.section 'Skipping User Project Integration'
176
+ end
177
+
178
+ def integrate
179
+ run_podfile_pre_integrate_hooks
180
+ generate_pods_project
181
+ if installation_options.integrate_targets?
182
+ integrate_user_project
183
+ else
184
+ UI.section 'Skipping User Project Integration'
185
+ end
186
+ end
187
+
188
+ def analyze_project_cache
189
+ user_projects = aggregate_targets.map(&:user_project).compact.uniq
190
+ object_version = user_projects.min_by { |p| p.object_version.to_i }.object_version.to_i unless user_projects.empty?
191
+
192
+ if !installation_options.incremental_installation
193
+ # Run entire installation.
194
+ ProjectCache::ProjectCacheAnalysisResult.new(pod_targets, aggregate_targets, {},
195
+ analysis_result.all_user_build_configurations, object_version)
196
+ else
197
+ UI.message 'Analyzing Project Cache' do
198
+ @installation_cache = ProjectCache::ProjectInstallationCache.from_file(sandbox, sandbox.project_installation_cache_path)
199
+ @metadata_cache = ProjectCache::ProjectMetadataCache.from_file(sandbox, sandbox.project_metadata_cache_path)
200
+ @project_cache_version = ProjectCache::ProjectCacheVersion.from_file(sandbox.project_version_cache_path)
201
+
202
+ force_clean_install = clean_install || project_cache_version.version != Version.create(VersionMetadata.project_cache_version)
203
+ cache_result = ProjectCache::ProjectCacheAnalyzer.new(sandbox, installation_cache, analysis_result.all_user_build_configurations,
204
+ object_version, plugins, pod_targets, aggregate_targets, installation_options.to_h, :clean_install => force_clean_install).analyze
205
+ aggregate_targets_to_generate = cache_result.aggregate_targets_to_generate || []
206
+ pod_targets_to_generate = cache_result.pod_targets_to_generate
207
+ (aggregate_targets_to_generate + pod_targets_to_generate).each do |target|
208
+ UI.message "- Regenerating #{target.label}"
209
+ end
210
+ cache_result
211
+ end
212
+ end
213
+ end
214
+
215
+ def prepare
216
+ # Raise if pwd is inside Pods
217
+ if Dir.pwd.start_with?(sandbox.root.to_path)
218
+ message = 'Command should be run from a directory outside Pods directory.'
219
+ message << "\n\n\tCurrent directory is #{UI.path(Pathname.pwd)}\n"
220
+ raise Informative, message
221
+ end
222
+ UI.message 'Preparing' do
223
+ deintegrate_if_different_major_version
224
+ sandbox.prepare
225
+ ensure_plugins_are_installed!
226
+ run_plugins_pre_install_hooks
227
+ end
228
+ end
229
+
230
+ # @return [Analyzer] The analyzer used to resolve dependencies
231
+ #
232
+ def resolve_dependencies
233
+ plugin_sources = run_source_provider_hooks
234
+ analyzer = create_analyzer(plugin_sources)
235
+
236
+ UI.section 'Updating local specs repositories' do
237
+ analyzer.update_repositories
238
+ end if repo_update?
239
+
240
+ UI.section 'Analyzing dependencies' do
241
+ analyze(analyzer)
242
+ validate_build_configurations
243
+ end
244
+
245
+ UI.section 'Verifying no changes' do
246
+ verify_no_podfile_changes!
247
+ verify_no_lockfile_changes!
248
+ end if deployment?
249
+
250
+ analyzer
251
+ end
252
+
253
+ def download_dependencies
254
+ UI.section 'Downloading dependencies' do
255
+ install_pod_sources
256
+ run_podfile_pre_install_hooks
257
+ clean_pod_sources
258
+ end
259
+ end
260
+
261
+ # Stages the sandbox after analysis.
262
+ #
263
+ # @param [Sandbox] sandbox
264
+ # The sandbox to stage.
265
+ #
266
+ # @param [Array<PodTarget>] pod_targets
267
+ # The list of all pod targets.
268
+ #
269
+ # @return [void]
270
+ #
271
+ def stage_sandbox(sandbox, pod_targets)
272
+ SandboxHeaderPathsInstaller.new(sandbox, pod_targets).install!
273
+ end
274
+
275
+ #-------------------------------------------------------------------------#
276
+
277
+ # @!group Pods Project Generation
278
+
279
+ private
280
+
281
+ def create_generator(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version, generate_multiple_pod_projects = false)
282
+ if generate_multiple_pod_projects
283
+ Xcode::MultiPodsProjectGenerator.new(sandbox, aggregate_targets_to_generate, pod_targets_to_generate,
284
+ build_configurations, installation_options, config, project_object_version, metadata_cache)
285
+ else
286
+ Xcode::SinglePodsProjectGenerator.new(sandbox, aggregate_targets_to_generate, pod_targets_to_generate, build_configurations, installation_options, config, project_object_version)
287
+ end
288
+ end
289
+
290
+ # Generates the Xcode project(s) that go inside the `Pods/` directory.
291
+ #
292
+ def generate_pods_project
293
+ stage_sandbox(sandbox, pod_targets)
294
+
295
+ cache_analysis_result = analyze_project_cache
296
+ pod_targets_to_generate = cache_analysis_result.pod_targets_to_generate
297
+ aggregate_targets_to_generate = cache_analysis_result.aggregate_targets_to_generate
298
+
299
+ clean_sandbox(pod_targets_to_generate)
300
+
301
+ create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate,
302
+ cache_analysis_result.build_configurations, cache_analysis_result.project_object_version)
303
+ SandboxDirCleaner.new(sandbox, pod_targets, aggregate_targets).clean!
304
+
305
+ update_project_cache(cache_analysis_result, target_installation_results)
306
+ end
307
+
308
+ def create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version)
309
+ UI.section 'Generating Pods project' do
310
+ generator = create_generator(pod_targets_to_generate, aggregate_targets_to_generate,
311
+ build_configurations, project_object_version,
312
+ installation_options.generate_multiple_pod_projects)
313
+
314
+ pod_project_generation_result = generator.generate!
315
+ @target_installation_results = pod_project_generation_result.target_installation_results
316
+ @pods_project = pod_project_generation_result.project
317
+ # The `pod_target_subprojects` is used for backwards compatibility so that consumers can iterate over
318
+ # all pod targets across projects without needing to open each one.
319
+ @pod_target_subprojects = pod_project_generation_result.projects_by_pod_targets.keys
320
+ @generated_projects = ([pods_project] + pod_target_subprojects || []).compact
321
+ @generated_pod_targets = pod_targets_to_generate
322
+ @generated_aggregate_targets = aggregate_targets_to_generate || []
323
+ projects_by_pod_targets = pod_project_generation_result.projects_by_pod_targets
324
+
325
+ predictabilize_uuids(generated_projects) if installation_options.deterministic_uuids?
326
+ stabilize_target_uuids(generated_projects)
327
+
328
+ projects_writer = Xcode::PodsProjectWriter.new(sandbox, generated_projects,
329
+ target_installation_results.pod_target_installation_results, installation_options)
330
+ projects_writer.write! do
331
+ run_podfile_post_install_hooks
332
+ end
333
+
334
+ pods_project_pod_targets = pod_targets_to_generate - projects_by_pod_targets.values.flatten
335
+ all_projects_by_pod_targets = {}
336
+ pods_project_by_targets = { pods_project => pods_project_pod_targets } if pods_project
337
+ all_projects_by_pod_targets.merge!(pods_project_by_targets) if pods_project_by_targets
338
+ all_projects_by_pod_targets.merge!(projects_by_pod_targets) if projects_by_pod_targets
339
+ all_projects_by_pod_targets.each do |project, pod_targets|
340
+ generator.configure_schemes(project, pod_targets, pod_project_generation_result)
341
+ end
342
+ end
343
+ end
344
+
345
+ def predictabilize_uuids(projects)
346
+ UI.message('- Generating deterministic UUIDs') { Xcodeproj::Project.predictabilize_uuids(projects) }
347
+ end
348
+
349
+ def stabilize_target_uuids(projects)
350
+ UI.message('- Stabilizing target UUIDs') { TargetUUIDGenerator.new(projects).generate! }
351
+ end
352
+
353
+ #-------------------------------------------------------------------------#
354
+
355
+ public
356
+
357
+ # @!group Installation results
358
+
359
+ # @return [Analyzer::AnalysisResult] the result of the analysis performed during installation
360
+ #
361
+ attr_reader :analysis_result
362
+
363
+ # @return [Array<Hash{String, TargetInstallationResult}>] the installation results produced by the pods project
364
+ # generator
365
+ #
366
+ attr_reader :target_installation_results
367
+
368
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
369
+ #
370
+ attr_reader :pods_project
371
+
372
+ # @return [Array<Pod::Project>] the subprojects nested under pods_project.
373
+ #
374
+ attr_reader :pod_target_subprojects
375
+
376
+ # @return [Array<AggregateTarget>] The model representations of an
377
+ # aggregation of pod targets generated for a target definition
378
+ # in the Podfile as result of the analyzer.
379
+ #
380
+ attr_reader :aggregate_targets
381
+
382
+ # @return [Array<PodTarget>] The model representations of pod targets
383
+ # generated as result of the analyzer.
384
+ #
385
+ attr_reader :pod_targets
386
+
387
+ # @return [Array<Project>] The list of projects generated from the installation.
388
+ #
389
+ attr_reader :generated_projects
390
+
391
+ # @return [Array<PodTarget>] The list of pod targets that were generated from the installation.
392
+ #
393
+ attr_reader :generated_pod_targets
394
+
395
+ # @return [Array<AggregateTarget>] The list of aggregate targets that were generated from the installation.
396
+ #
397
+ attr_reader :generated_aggregate_targets
398
+
399
+ # @return [Array<Specification>] The specifications that were installed.
400
+ #
401
+ attr_accessor :installed_specs
402
+
403
+ #-------------------------------------------------------------------------#
404
+
405
+ private
406
+
407
+ # @!group Installation steps
408
+
409
+ # Performs the analysis.
410
+ #
411
+ # @param [Analyzer] analyzer the analyzer to use for analysis
412
+ #
413
+ # @return [void]
414
+ #
415
+ def analyze(analyzer = create_analyzer)
416
+ @analysis_result = analyzer.analyze
417
+ @aggregate_targets = @analysis_result.targets
418
+ @pod_targets = @analysis_result.pod_targets
419
+ end
420
+
421
+ def create_analyzer(plugin_sources = nil)
422
+ Analyzer.new(sandbox, podfile, lockfile, plugin_sources, has_dependencies?, update)
423
+ end
424
+
425
+ # Ensures that the white-listed build configurations are known to prevent
426
+ # silent typos.
427
+ #
428
+ # @raise If an unknown user configuration is found.
429
+ #
430
+ def validate_build_configurations
431
+ whitelisted_configs = pod_targets.
432
+ flat_map(&:target_definitions).
433
+ flat_map(&:all_whitelisted_configurations).
434
+ map(&:downcase).
435
+ uniq
436
+ all_user_configurations = analysis_result.all_user_build_configurations.keys.map(&:downcase)
437
+
438
+ remainder = whitelisted_configs - all_user_configurations
439
+ unless remainder.empty?
440
+ raise Informative,
441
+ "Unknown #{'configuration'.pluralize(remainder.size)} whitelisted: #{remainder.sort.to_sentence}. " \
442
+ "CocoaPods found #{all_user_configurations.sort.to_sentence}, did you mean one of these?"
443
+ end
444
+ end
445
+
446
+ # @return [void] In this step we clean all the header folders for pod targets that will be
447
+ # regenerated from scratch and cleanup any pods that have been removed.
448
+ #
449
+ def clean_sandbox(pod_targets)
450
+ pod_targets.each do |pod_target|
451
+ pod_target.build_headers.implode_path!(pod_target.headers_sandbox)
452
+ sandbox.public_headers.implode_path!(pod_target.headers_sandbox)
453
+ end
454
+
455
+ unless sandbox_state.deleted.empty?
456
+ title_options = { :verbose_prefix => '-> '.red }
457
+ sandbox_state.deleted.each do |pod_name|
458
+ UI.titled_section("Removing #{pod_name}".red, title_options) do
459
+ sandbox.clean_pod(pod_name)
460
+ end
461
+ end
462
+ end
463
+ end
464
+
465
+ # @raise [Informative] If there are any Podfile changes
466
+ #
467
+ def verify_no_podfile_changes!
468
+ return unless analysis_result.podfile_needs_install?
469
+
470
+ changed_state = analysis_result.podfile_state.to_s(:states => %i(added deleted changed))
471
+ raise Informative, "There were changes to the podfile in deployment mode:\n#{changed_state}"
472
+ end
473
+
474
+ # @raise [Informative] If there are any Lockfile changes
475
+ #
476
+ def verify_no_lockfile_changes!
477
+ new_lockfile = generate_lockfile
478
+ return if new_lockfile == lockfile
479
+
480
+ return unless diff = Xcodeproj::Differ.hash_diff(lockfile.to_hash, new_lockfile.to_hash, :key_1 => 'Old Lockfile', :key_2 => 'New Lockfile')
481
+ pretty_diff = YAMLHelper.convert_hash(diff, Lockfile::HASH_KEY_ORDER, "\n\n")
482
+ pretty_diff.gsub!(':diff:', 'diff:'.yellow)
483
+
484
+ raise Informative, "There were changes to the lockfile in deployment mode:\n#{pretty_diff}"
485
+ end
486
+
487
+ # Downloads, installs the documentation and cleans the sources of the Pods
488
+ # which need to be installed.
489
+ #
490
+ # @return [void]
491
+ #
492
+ def install_pod_sources
493
+ @installed_specs = []
494
+ pods_to_install = sandbox_state.added | sandbox_state.changed
495
+ title_options = { :verbose_prefix => '-> '.green }
496
+ root_specs.sort_by(&:name).each do |spec|
497
+ if pods_to_install.include?(spec.name)
498
+ if sandbox_state.changed.include?(spec.name) && sandbox.manifest
499
+ current_version = spec.version
500
+ previous_version = sandbox.manifest.version(spec.name)
501
+ has_changed_version = current_version != previous_version
502
+ current_repo = analysis_result.specs_by_source.detect { |key, values| break key if values.map(&:name).include?(spec.name) }
503
+ current_repo &&= (Pod::TrunkSource::TRUNK_REPO_NAME if current_repo.name == Pod::TrunkSource::TRUNK_REPO_NAME) || current_repo.url || current_repo.name
504
+ previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
505
+ has_changed_repo = !previous_spec_repo.nil? && current_repo && !current_repo.casecmp(previous_spec_repo).zero?
506
+ title = "Installing #{spec.name} #{spec.version}"
507
+ title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if has_changed_version && has_changed_repo
508
+ title << " (was #{previous_version})" if has_changed_version && !has_changed_repo
509
+ title << " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if !has_changed_version && has_changed_repo
510
+ else
511
+ title = "Installing #{spec}"
512
+ end
513
+ UI.titled_section(title.green, title_options) do
514
+ install_source_of_pod(spec.name)
515
+ end
516
+ else
517
+ UI.section("Using #{spec}", title_options[:verbose_prefix]) do
518
+ create_pod_installer(spec.name)
519
+ end
520
+ end
521
+ end
522
+ end
523
+
524
+ def create_pod_installer(pod_name)
525
+ specs_by_platform = specs_for_pod(pod_name)
526
+
527
+ if specs_by_platform.empty?
528
+ requiring_targets = pod_targets.select { |pt| pt.recursive_dependent_targets.any? { |dt| dt.pod_name == pod_name } }
529
+ message = "Could not install '#{pod_name}' pod"
530
+ message += ", dependended upon by #{requiring_targets.to_sentence}" unless requiring_targets.empty?
531
+ message += '. There is either no platform to build for, or no target to build.'
532
+ raise StandardError, message
533
+ end
534
+
535
+ pod_installer = PodSourceInstaller.new(sandbox, podfile, specs_by_platform, :can_cache => installation_options.clean?)
536
+ pod_installers << pod_installer
537
+ pod_installer
538
+ end
539
+
540
+ # The specifications matching the specified pod name
541
+ #
542
+ # @param [String] pod_name the name of the pod
543
+ #
544
+ # @return [Hash{Platform => Array<Specification>}] the specifications grouped by platform
545
+ #
546
+ def specs_for_pod(pod_name)
547
+ pod_targets.each_with_object({}) do |pod_target, hash|
548
+ if pod_target.root_spec.name == pod_name
549
+ hash[pod_target.platform] ||= []
550
+ hash[pod_target.platform].concat(pod_target.specs)
551
+ end
552
+ end
553
+ end
554
+
555
+ # Install the Pods. If the resolver indicated that a Pod should be
556
+ # installed and it exits, it is removed and then reinstalled. In any case if
557
+ # the Pod doesn't exits it is installed.
558
+ #
559
+ # @return [void]
560
+ #
561
+ def install_source_of_pod(pod_name)
562
+ pod_installer = create_pod_installer(pod_name)
563
+ pod_installer.install!
564
+ @installed_specs.concat(pod_installer.specs_by_platform.values.flatten.uniq)
565
+ end
566
+
567
+ # Cleans the sources of the Pods if the config instructs to do so.
568
+ #
569
+ #
570
+ def clean_pod_sources
571
+ return unless installation_options.clean?
572
+ return if installed_specs.empty?
573
+ pod_installers.each(&:clean!)
574
+ end
575
+
576
+ # Unlocks the sources of the Pods.
577
+ #
578
+ def unlock_pod_sources
579
+ pod_installers.each do |installer|
580
+ pod_target = pod_targets.find { |target| target.pod_name == installer.name }
581
+ installer.unlock_files!(pod_target.file_accessors)
582
+ end
583
+ end
584
+
585
+ # Locks the sources of the Pods if the config instructs to do so.
586
+ #
587
+ def lock_pod_sources
588
+ return unless installation_options.lock_pod_sources?
589
+ pod_installers.each do |installer|
590
+ pod_target = pod_targets.find { |target| target.pod_name == installer.name }
591
+ installer.lock_files!(pod_target.file_accessors)
592
+ end
593
+ end
594
+
595
+ def validate_targets
596
+ validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets, installation_options)
597
+ validator.validate!
598
+ end
599
+
600
+ # Runs the registered callbacks for the plugins pre install hooks.
601
+ #
602
+ # @return [void]
603
+ #
604
+ def run_plugins_pre_install_hooks
605
+ context = PreInstallHooksContext.generate(sandbox, podfile, lockfile)
606
+ HooksManager.run(:pre_install, context, plugins)
607
+ end
608
+
609
+ # Performs any post-installation actions
610
+ #
611
+ # @return [void]
612
+ #
613
+ def perform_post_install_actions
614
+ run_plugins_post_install_hooks
615
+ warn_for_deprecations
616
+ warn_for_installed_script_phases
617
+ warn_for_removing_git_master_specs_repo
618
+ print_post_install_message
619
+ end
620
+
621
+ def print_post_install_message
622
+ podfile_dependencies = analysis_result.podfile_dependency_cache.podfile_dependencies.size
623
+ pods_installed = root_specs.size
624
+ title_options = { :verbose_prefix => '-> '.green }
625
+ UI.titled_section('Pod installation complete! ' \
626
+ "There #{podfile_dependencies == 1 ? 'is' : 'are'} #{podfile_dependencies} " \
627
+ "#{'dependency'.pluralize(podfile_dependencies)} from the Podfile " \
628
+ "and #{pods_installed} total #{'pod'.pluralize(pods_installed)} installed.".green,
629
+ title_options)
630
+ end
631
+
632
+ # Runs the registered callbacks for the plugins pre integrate hooks.
633
+ #
634
+ def run_plugins_pre_integrate_hooks
635
+ if any_plugin_pre_integrate_hooks?
636
+ context = PreIntegrateHooksContext.generate(sandbox, pods_project, aggregate_targets)
637
+ HooksManager.run(:pre_integrate, context, plugins)
638
+ end
639
+ end
640
+
641
+ # Runs the registered callbacks for the plugins post install hooks.
642
+ #
643
+ def run_plugins_post_install_hooks
644
+ # This short-circuits because unlocking pod sources is expensive
645
+ if any_plugin_post_install_hooks?
646
+ unlock_pod_sources
647
+
648
+ context = PostInstallHooksContext.generate(sandbox, pods_project, aggregate_targets)
649
+ HooksManager.run(:post_install, context, plugins)
650
+ end
651
+
652
+ lock_pod_sources
653
+ end
654
+
655
+ # Runs the registered callbacks for the plugins post integrate hooks.
656
+ #
657
+ def run_plugins_post_integrate_hooks
658
+ if any_plugin_post_integrate_hooks?
659
+ context = PostIntegrateHooksContext.generate(sandbox, pods_project, aggregate_targets)
660
+ HooksManager.run(:post_integrate, context, plugins)
661
+ end
662
+ end
663
+
664
+ # @return [Boolean] whether there are any plugin pre-integrate hooks to run
665
+ #
666
+ def any_plugin_pre_integrate_hooks?
667
+ HooksManager.hooks_to_run(:pre_integrate, plugins).any?
668
+ end
669
+
670
+ # @return [Boolean] whether there are any plugin post-install hooks to run
671
+ #
672
+ def any_plugin_post_install_hooks?
673
+ HooksManager.hooks_to_run(:post_install, plugins).any?
674
+ end
675
+
676
+ # @return [Boolean] whether there are any plugin post-integrate hooks to run
677
+ #
678
+ def any_plugin_post_integrate_hooks?
679
+ HooksManager.hooks_to_run(:post_integrate, plugins).any?
680
+ end
681
+
682
+ # Runs the registered callbacks for the source provider plugin hooks.
683
+ #
684
+ # @return [Array<Pod::Source>] the plugin sources
685
+ #
686
+ def run_source_provider_hooks
687
+ context = SourceProviderHooksContext.generate
688
+ HooksManager.run(:source_provider, context, plugins)
689
+ context.sources
690
+ end
691
+
692
+ # Run the deintegrator against all projects in the installation root if the
693
+ # current CocoaPods major version part is different than the one in the
694
+ # lockfile.
695
+ #
696
+ # @return [void]
697
+ #
698
+ def deintegrate_if_different_major_version
699
+ return unless lockfile
700
+ return if lockfile.cocoapods_version.major == Version.create(VERSION).major
701
+ UI.section('Re-creating CocoaPods due to major version update.') do
702
+ projects = Pathname.glob(config.installation_root + '*.xcodeproj').map { |path| Xcodeproj::Project.open(path) }
703
+ deintegrator = Deintegrator.new
704
+ projects.each do |project|
705
+ config.with_changes(:silent => true) { deintegrator.deintegrate_project(project) }
706
+ project.save if project.dirty?
707
+ end
708
+ end
709
+ end
710
+
711
+ # Ensures that all plugins specified in the {#podfile} are loaded.
712
+ #
713
+ # @return [void]
714
+ #
715
+ def ensure_plugins_are_installed!
716
+ require 'claide/command/plugin_manager'
717
+
718
+ loaded_plugins = Command::PluginManager.specifications.map(&:name)
719
+
720
+ podfile.plugins.keys.each do |plugin|
721
+ unless loaded_plugins.include? plugin
722
+ raise Informative, "Your Podfile requires that the plugin `#{plugin}` be installed. Please install it and try installation again."
723
+ end
724
+ end
725
+ end
726
+
727
+ DEFAULT_PLUGINS = {}
728
+
729
+ # Returns the plugins that should be run, as indicated by the default
730
+ # plugins and the podfile's plugins
731
+ #
732
+ # @return [Hash<String, Hash>] The plugins to be used
733
+ #
734
+ def plugins
735
+ if use_default_plugins?
736
+ DEFAULT_PLUGINS.merge(podfile.plugins)
737
+ else
738
+ podfile.plugins
739
+ end
740
+ end
741
+
742
+ # Prints a warning for any pods that are deprecated
743
+ #
744
+ # @return [void]
745
+ #
746
+ def warn_for_deprecations
747
+ deprecated_pods = root_specs.select do |spec|
748
+ spec.deprecated || spec.deprecated_in_favor_of
749
+ end
750
+ deprecated_pods.each do |spec|
751
+ if spec.deprecated_in_favor_of
752
+ UI.warn "#{spec.name} has been deprecated in " \
753
+ "favor of #{spec.deprecated_in_favor_of}"
754
+ else
755
+ UI.warn "#{spec.name} has been deprecated"
756
+ end
757
+ end
758
+ end
759
+
760
+ # Prints a warning for any pods that included script phases
761
+ #
762
+ # @return [void]
763
+ #
764
+ def warn_for_installed_script_phases
765
+ pods_to_install = sandbox_state.added | sandbox_state.changed
766
+ pod_targets.group_by(&:pod_name).each do |name, pod_targets|
767
+ if pods_to_install.include?(name) && !sandbox.local?(name)
768
+ script_phase_count = pod_targets.inject(0) { |sum, target| sum + target.script_phases.count }
769
+ unless script_phase_count.zero?
770
+ UI.warn "#{name} has added #{script_phase_count} #{'script phase'.pluralize(script_phase_count)}. " \
771
+ 'Please inspect before executing a build. See `https://guides.cocoapods.org/syntax/podspec.html#script_phases` for more information.'
772
+ end
773
+ end
774
+ end
775
+ end
776
+
777
+ # Prints a warning if the project is not explicitly using the git based master specs repo.
778
+ #
779
+ # Helps users to delete the git based master specs repo from the repos directory which reduces `--repo-update`
780
+ # speed and hopefully reduces Github workload.
781
+ #
782
+ # @return [void]
783
+ #
784
+ def warn_for_removing_git_master_specs_repo
785
+ return unless installation_options.warn_for_unused_master_specs_repo?
786
+ plugin_sources = run_source_provider_hooks
787
+ all_sources = podfile.sources + plugin_sources.map(&:url)
788
+ master_source = all_sources.find { |source| source == MASTER_SPECS_REPO_GIT_URL }
789
+ master_repo = config.sources_manager.all.find { |s| s.url == MASTER_SPECS_REPO_GIT_URL }
790
+ if master_source.nil? && !master_repo.nil?
791
+ UI.warn 'Your project does not explicitly specify the CocoaPods master specs repo. Since CDN is now used as the' \
792
+ ' default, you may safely remove it from your repos directory via `pod repo remove master`. To suppress this warning' \
793
+ ' please add `warn_for_unused_master_specs_repo => false` to your Podfile.'
794
+ end
795
+ end
796
+
797
+ # @return [Lockfile] The lockfile to write to disk.
798
+ #
799
+ def generate_lockfile
800
+ external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
801
+ checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
802
+ Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
803
+ end
804
+
805
+ # Writes the Podfile and the lock files.
806
+ #
807
+ # @return [void]
808
+ #
809
+ def write_lockfiles
810
+ @lockfile = generate_lockfile
811
+
812
+ UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
813
+ # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the
814
+ # contents of the file are the same.
815
+ @lockfile.write_to_disk(config.lockfile_path)
816
+ end
817
+
818
+ UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do
819
+ # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the
820
+ # contents of the file are the same.
821
+ @lockfile.write_to_disk(sandbox.manifest_path)
822
+ end
823
+ end
824
+
825
+ # @param [ProjectCacheAnalysisResult] cache_analysis_result
826
+ # The cache analysis result for the current installation.
827
+ #
828
+ # @param [Hash{String => TargetInstallationResult}] target_installation_results
829
+ # The installation results for pod targets installed.
830
+ #
831
+ def update_project_cache(cache_analysis_result, target_installation_results)
832
+ return unless installation_cache || metadata_cache
833
+ installation_cache.update_cache_key_by_target_label!(cache_analysis_result.cache_key_by_target_label)
834
+ installation_cache.update_project_object_version!(cache_analysis_result.project_object_version)
835
+ installation_cache.update_build_configurations!(cache_analysis_result.build_configurations)
836
+ installation_cache.update_podfile_plugins!(plugins)
837
+ installation_cache.update_installation_options!(installation_options.to_h)
838
+ installation_cache.save_as(sandbox.project_installation_cache_path)
839
+
840
+ metadata_cache.update_metadata!(target_installation_results.pod_target_installation_results || {},
841
+ target_installation_results.aggregate_target_installation_results || {})
842
+ metadata_cache.save_as(sandbox.project_metadata_cache_path)
843
+
844
+ cache_version = ProjectCache::ProjectCacheVersion.new(VersionMetadata.project_cache_version)
845
+ cache_version.save_as(sandbox.project_version_cache_path)
846
+ end
847
+
848
+ # Integrates the user projects adding the dependencies on the CocoaPods
849
+ # libraries, setting them up to use the xcconfigs and performing other
850
+ # actions. This step is also responsible of creating the workspace if
851
+ # needed.
852
+ #
853
+ # @return [void]
854
+ #
855
+ def integrate_user_project
856
+ UI.section "Integrating client #{'project'.pluralize(aggregate_targets.map(&:user_project_path).uniq.count)}" do
857
+ installation_root = config.installation_root
858
+ integrator = UserProjectIntegrator.new(podfile, sandbox, installation_root, aggregate_targets, generated_aggregate_targets,
859
+ :use_input_output_paths => !installation_options.disable_input_output_paths?)
860
+ integrator.integrate!
861
+ run_podfile_post_integrate_hooks
862
+ end
863
+ end
864
+
865
+ #-------------------------------------------------------------------------#
866
+
867
+ private
868
+
869
+ # @!group Hooks
870
+
871
+ # Runs the pre install hooks of the installed specs and of the Podfile.
872
+ #
873
+ # @return [void]
874
+ #
875
+ def run_podfile_pre_install_hooks
876
+ UI.message '- Running pre install hooks' do
877
+ executed = run_podfile_pre_install_hook
878
+ UI.message '- Podfile' if executed
879
+ end
880
+ end
881
+
882
+ # Runs the pre install hook of the Podfile
883
+ #
884
+ # @raise Raises an informative if the hooks raises.
885
+ #
886
+ # @return [Boolean] Whether the hook was run.
887
+ #
888
+ def run_podfile_pre_install_hook
889
+ podfile.pre_install!(self)
890
+ rescue => e
891
+ raise Informative, 'An error occurred while processing the pre-install ' \
892
+ 'hook of the Podfile.' \
893
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
894
+ end
895
+
896
+ # Runs the post integrate hooks of the installed specs and of the Podfile.
897
+ #
898
+ # @note Post integrate hooks run _after_ saving of project, so that they
899
+ # can alter it after it is written to the disk.
900
+ #
901
+ # @return [void]
902
+ #
903
+ def run_podfile_pre_integrate_hooks
904
+ UI.message '- Running pre integrate hooks' do
905
+ executed = run_podfile_pre_integrate_hook
906
+ UI.message '- Podfile' if executed
907
+ end
908
+ end
909
+
910
+ # Runs the pre integrate hook of the Podfile.
911
+ #
912
+ # @raise Raises an informative if the hooks raises.
913
+ #
914
+ # @return [Boolean] Whether the hook was run.
915
+ #
916
+ def run_podfile_pre_integrate_hook
917
+ podfile.pre_integrate!(self)
918
+ rescue => e
919
+ raise Informative, 'An error occurred while processing the pre-integrate ' \
920
+ 'hook of the Podfile.' \
921
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
922
+ end
923
+
924
+ # Runs the post install hooks of the installed specs and of the Podfile.
925
+ #
926
+ # @note Post install hooks run _before_ saving of project, so that they
927
+ # can alter it before it is written to the disk.
928
+ #
929
+ # @return [void]
930
+ #
931
+ def run_podfile_post_install_hooks
932
+ UI.message '- Running post install hooks' do
933
+ executed = run_podfile_post_install_hook
934
+ UI.message '- Podfile' if executed
935
+ end
936
+ end
937
+
938
+ # Runs the post install hook of the Podfile
939
+ #
940
+ # @raise Raises an informative if the hooks raises.
941
+ #
942
+ # @return [Boolean] Whether the hook was run.
943
+ #
944
+ def run_podfile_post_install_hook
945
+ podfile.post_install!(self)
946
+ rescue => e
947
+ raise Informative, 'An error occurred while processing the post-install ' \
948
+ 'hook of the Podfile.' \
949
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
950
+ end
951
+
952
+ # Runs the post integrate hooks of the installed specs and of the Podfile.
953
+ #
954
+ # @note Post integrate hooks run _after_ saving of project, so that they
955
+ # can alter it after it is written to the disk.
956
+ #
957
+ # @return [void]
958
+ #
959
+ def run_podfile_post_integrate_hooks
960
+ UI.message '- Running post integrate hooks' do
961
+ executed = run_podfile_post_integrate_hook
962
+ UI.message '- Podfile' if executed
963
+ end
964
+ end
965
+
966
+ # Runs the post integrate hook of the Podfile.
967
+ #
968
+ # @raise Raises an informative if the hooks raises.
969
+ #
970
+ # @return [Boolean] Whether the hook was run.
971
+ #
972
+ def run_podfile_post_integrate_hook
973
+ podfile.post_integrate!(self)
974
+ rescue => e
975
+ raise Informative, 'An error occurred while processing the post-integrate ' \
976
+ 'hook of the Podfile.' \
977
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
978
+ end
979
+ #-------------------------------------------------------------------------#
980
+
981
+ public
982
+
983
+ # @param [Array<PodTarget>] targets
984
+ #
985
+ # @return [Array<PodTarget>] The targets of the development pods generated by
986
+ # the installation process. This can be used as a convenience method for external scripts.
987
+ #
988
+ def development_pod_targets(targets = pod_targets)
989
+ targets.select do |pod_target|
990
+ sandbox.local?(pod_target.pod_name)
991
+ end
992
+ end
993
+
994
+ #-------------------------------------------------------------------------#
995
+
996
+ private
997
+
998
+ # @!group Private helpers
999
+
1000
+ # @return [Array<Specification>] All the root specifications of the
1001
+ # installation.
1002
+ #
1003
+ def root_specs
1004
+ analysis_result.specifications.map(&:root).uniq
1005
+ end
1006
+
1007
+ # @return [SpecsState] The state of the sandbox returned by the analyzer.
1008
+ #
1009
+ def sandbox_state
1010
+ analysis_result.sandbox_state
1011
+ end
1012
+
1013
+ # @return [InstallationOptions] the installation options to use during install
1014
+ #
1015
+ def installation_options
1016
+ podfile.installation_options
1017
+ end
1018
+
1019
+ #-------------------------------------------------------------------------#
1020
+
1021
+ public
1022
+
1023
+ # @!group Convenience Methods
1024
+
1025
+ def self.targets_from_sandbox(sandbox, podfile, lockfile)
1026
+ raise Informative, 'You must run `pod install` to be able to generate target information' unless lockfile
1027
+
1028
+ new(sandbox, podfile, lockfile).instance_exec do
1029
+ plugin_sources = run_source_provider_hooks
1030
+ analyzer = create_analyzer(plugin_sources)
1031
+ analyze(analyzer)
1032
+ if analysis_result.podfile_needs_install?
1033
+ raise Pod::Informative, 'The Podfile has changed, you must run `pod install`'
1034
+ elsif analysis_result.sandbox_needs_install?
1035
+ raise Pod::Informative, 'The `Pods` directory is out-of-date, you must run `pod install`'
1036
+ end
1037
+
1038
+ aggregate_targets
1039
+ end
1040
+ end
1041
+
1042
+ #-------------------------------------------------------------------------#
1043
+ end
1044
+ end