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.
- checksums.yaml +7 -0
- data/lib/cocoapods-tt/command/native/install.rb +56 -0
- data/lib/cocoapods-tt/command/native/update.rb +157 -0
- data/lib/cocoapods-tt/command/tt/make.rb +92 -0
- data/lib/cocoapods-tt/command/tt.rb +115 -0
- data/lib/cocoapods-tt/command.rb +1 -0
- data/lib/cocoapods-tt/gem_version.rb +3 -0
- data/lib/cocoapods-tt/native/command.rb +185 -0
- data/lib/cocoapods-tt/native/config.rb +366 -0
- data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
- data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
- data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
- data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
- data/lib/cocoapods-tt/native/downloader.rb +192 -0
- data/lib/cocoapods-tt/native/executable.rb +247 -0
- data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
- data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
- data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
- data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
- data/lib/cocoapods-tt/native/external_sources.rb +57 -0
- data/lib/cocoapods-tt/native/gem_version.rb +5 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
- data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
- data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
- data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
- data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
- data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
- data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
- data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
- data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
- data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
- data/lib/cocoapods-tt/native/generator/header.rb +103 -0
- data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
- data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
- data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
- data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
- data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
- data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
- data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
- data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
- data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
- data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
- data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
- data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
- data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
- data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
- data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
- data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
- data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
- data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
- data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
- data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
- data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
- data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
- data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
- data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
- data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
- data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
- data/lib/cocoapods-tt/native/installer.rb +1044 -0
- data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
- data/lib/cocoapods-tt/native/open-uri.rb +33 -0
- data/lib/cocoapods-tt/native/podfile.rb +13 -0
- data/lib/cocoapods-tt/native/project.rb +544 -0
- data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
- data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
- data/lib/cocoapods-tt/native/resolver.rb +600 -0
- data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
- data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
- data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
- data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
- data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
- data/lib/cocoapods-tt/native/sandbox.rb +470 -0
- data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
- data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
- data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
- data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
- data/lib/cocoapods-tt/native/target.rb +378 -0
- data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
- data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
- data/lib/cocoapods-tt/native/user_interface.rb +463 -0
- data/lib/cocoapods-tt/native/validator.rb +1170 -0
- data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
- data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
- data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
- data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
- data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
- data/lib/cocoapods-tt/native/xcode.rb +7 -0
- data/lib/cocoapods-tt.rb +1 -0
- data/lib/cocoapods_plugin.rb +17 -0
- 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
|