cocoapods-generate-minlison 1.5.0

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.
@@ -0,0 +1,347 @@
1
+ module Pod
2
+ module Generate
3
+ # Responsible for creating a workspace for a single specification,
4
+ # given a configuration and a generated podfile.
5
+ #
6
+ class Installer
7
+ # @return [Configuration]
8
+ # the configuration to use when installing
9
+ #
10
+ attr_reader :configuration
11
+
12
+ # @return [Specification]
13
+ # the spec whose workspace is being created
14
+ #
15
+ attr_reader :spec
16
+
17
+ # @return [Podfile]
18
+ # the podfile to install
19
+ #
20
+ attr_reader :podfile
21
+
22
+ def initialize(configuration, spec, podfile)
23
+ @configuration = configuration
24
+ @spec = spec
25
+ @podfile = podfile
26
+ end
27
+
28
+ # @return [Pathname]
29
+ # The directory that pods will be installed into
30
+ #
31
+ def install_directory
32
+ @install_directory ||= podfile.defined_in_file.dirname
33
+ end
34
+
35
+ # Installs the {podfile} into the {install_directory}
36
+ #
37
+ # @return [void]
38
+ #
39
+ def install!
40
+ UI.title "Generating #{spec.name} in #{UI.path install_directory}" do
41
+ clean! if configuration.clean?
42
+ install_directory.mkpath
43
+
44
+ UI.message 'Creating stub application' do
45
+ create_app_project
46
+ end
47
+
48
+ UI.message 'Writing Podfile' do
49
+ podfile.defined_in_file.open('w') { |f| f << podfile.to_yaml }
50
+ end
51
+
52
+ installer = nil
53
+ UI.section 'Installing...' do
54
+ configuration.pod_config.with_changes(installation_root: install_directory, podfile: podfile, lockfile: configuration.lockfile, sandbox: nil, sandbox_root: install_directory, podfile_path: podfile.defined_in_file, silent: !configuration.pod_config.verbose?, verbose: false, lockfile_path: nil) do
55
+ installer = ::Pod::Installer.new(configuration.pod_config.sandbox, podfile, configuration.lockfile)
56
+ installer.use_default_plugins = configuration.use_default_plugins
57
+ installer.install!
58
+ end
59
+ end
60
+
61
+ UI.section 'Performing post-installation steps' do
62
+ perform_post_install_steps(open_app_project, installer)
63
+ end
64
+
65
+ print_post_install_message
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ # Removes the {install_directory}
72
+ #
73
+ # @return [void]
74
+ #
75
+ def clean!
76
+ UI.message 'Cleaning gen install directory' do
77
+ FileUtils.rm_rf install_directory
78
+ end
79
+ end
80
+
81
+ def open_app_project(recreate: false)
82
+ app_project_path = install_directory.join("#{spec.name}.xcodeproj")
83
+ if !recreate && app_project_path.exist?
84
+ Xcodeproj::Project.open(app_project_path)
85
+ else
86
+ Xcodeproj::Project.new(app_project_path)
87
+ end
88
+ end
89
+
90
+ # Creates an app project that CocoaPods will integrate into
91
+ #
92
+ # @return [Xcodeproj::Project]
93
+ #
94
+ def create_app_project
95
+ app_project = open_app_project(recreate: true)
96
+
97
+ spec.available_platforms.map do |platform|
98
+ consumer = spec.consumer(platform)
99
+ target_name = "App-#{Platform.string_name(consumer.platform_name)}"
100
+ native_app_target = Pod::Generator::AppTargetHelper.add_app_target(app_project, consumer.platform_name, deployment_target(consumer), target_name)
101
+ # Temporarily set Swift version to pass validator checks for pods which do not specify Swift version.
102
+ # It will then be re-set again within #perform_post_install_steps.
103
+ Pod::Generator::AppTargetHelper.add_swift_version(native_app_target, Pod::Validator::DEFAULT_SWIFT_VERSION)
104
+ native_app_target
105
+ end
106
+ .tap do
107
+ app_project.recreate_user_schemes do |scheme, target|
108
+ installation_result = installation_result_from_target(target)
109
+ next unless installation_result
110
+ installation_result.test_native_targets.each do |test_native_target|
111
+ scheme.add_test_target(test_native_target)
112
+ end
113
+ end
114
+ end
115
+ .each do |target|
116
+ Xcodeproj::XCScheme.share_scheme(app_project.path, target.name)
117
+ end
118
+
119
+ app_project.save
120
+ end
121
+
122
+ def deployment_target(consumer)
123
+ deployment_target = consumer.spec.deployment_target(consumer.platform_name)
124
+ if consumer.platform_name == :ios && configuration.use_frameworks?
125
+ minimum = Version.new('8.0')
126
+ deployment_target = [Version.new(deployment_target), minimum].max.to_s
127
+ end
128
+ deployment_target
129
+ end
130
+
131
+ def perform_post_install_steps(app_project, installer)
132
+ app_project.native_targets.each do |native_app_target|
133
+ remove_script_phase_from_target(native_app_target, 'Check Pods Manifest.lock')
134
+
135
+ pod_target = installer.pod_targets.find { |pt| pt.platform.name == native_app_target.platform_name && pt.pod_name == spec.name }
136
+ raise "unable to find a pod target for #{native_app_target} / #{spec}" unless pod_target
137
+
138
+ if (app_host_source_dir = configuration.app_host_source_dir)
139
+ relative_app_host_source_dir = app_host_source_dir.relative_path_from(installer.sandbox.root)
140
+ groups = {}
141
+
142
+ app_host_source_dir.find do |file|
143
+ relative_path = file.relative_path_from(app_host_source_dir)
144
+
145
+ if file.directory?
146
+ groups[relative_path] =
147
+ if (base_group = groups[relative_path.dirname])
148
+ basename = relative_path.basename
149
+ base_group.new_group(basename.to_s, basename)
150
+ else
151
+ app_project.new_group(native_app_target.name, relative_app_host_source_dir)
152
+ end
153
+
154
+ next
155
+ elsif file.to_s.end_with?('-Bridging-Header.h')
156
+ native_app_target.build_configurations.each do |bc|
157
+ if (old_bridging_header = bc.build_settings['SWIFT_OBJC_BRIDGING_HEADER'])
158
+ raise Informative, "Conflicting Swift ObjC bridging headers specified, got #{old_bridging_header} and #{relative_path}. Only one `-Bridging-Header.h` file may be specified in the app host source dir."
159
+ end
160
+
161
+ bc.build_settings['SWIFT_OBJC_BRIDGING_HEADER'] = relative_path.to_s
162
+ end
163
+ end
164
+
165
+ group = groups[relative_path.dirname]
166
+ source_file_ref = group.new_file(file.basename)
167
+ native_app_target.add_file_references([source_file_ref])
168
+ end
169
+ elsif Pod::Generator::AppTargetHelper.method(:add_app_project_import).arity == -5 # CocoaPods >= 1.6
170
+ Pod::Generator::AppTargetHelper.add_app_project_import(app_project, native_app_target, pod_target, pod_target.platform.name, native_app_target.name)
171
+ else
172
+ Pod::Generator::AppTargetHelper.add_app_project_import(app_project, native_app_target, pod_target, pod_target.platform.name, pod_target.requires_frameworks?, native_app_target.name)
173
+ end
174
+
175
+ # Set `PRODUCT_BUNDLE_IDENTIFIER`
176
+ native_app_target.build_configurations.each do |bc|
177
+ bc.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods-generate.${PRODUCT_NAME:rfc1034identifier}'
178
+ end
179
+
180
+ case native_app_target.platform_name
181
+ when :ios
182
+ make_ios_app_launchable(installer, app_project, native_app_target)
183
+ end
184
+
185
+ Pod::Generator::AppTargetHelper.add_swift_version(native_app_target, pod_target.swift_version) unless pod_target.swift_version.blank?
186
+ if installer.pod_targets.any? { |pt| pt.spec_consumers.any? { |c| c.frameworks.include?('XCTest') } }
187
+ Pod::Generator::AppTargetHelper.add_xctest_search_paths(native_app_target)
188
+ end
189
+
190
+ # Share the pods xcscheme only if it exists. For pre-built vendored pods there is no xcscheme generated.
191
+ if installer.respond_to?(:generated_projects) # CocoaPods 1.7.0
192
+ installer.generated_projects.each do |project|
193
+ Xcodeproj::XCScheme.share_scheme(project.path, pod_target.label) if File.exist?(project.path + pod_target.label)
194
+ end
195
+ elsif File.exist?(installer.pods_project.path + pod_target.label)
196
+ Xcodeproj::XCScheme.share_scheme(installer.pods_project.path, pod_target.label)
197
+ end
198
+
199
+ add_test_spec_schemes_to_app_scheme(installer, app_project)
200
+ end
201
+
202
+ app_project.save
203
+ end
204
+
205
+ def installation_result_from_target(target)
206
+ return unless target.respond_to?(:symbol_type)
207
+ library_product_types = %i[framework dynamic_library static_library]
208
+ return unless library_product_types.include? target.symbol_type
209
+
210
+ results_by_native_target[target]
211
+ end
212
+
213
+ def remove_script_phase_from_target(native_target, script_phase_name)
214
+ script_phase = native_target.shell_script_build_phases.find { |bp| bp.name && bp.name.end_with?(script_phase_name) }
215
+ return unless script_phase.present?
216
+ native_target.build_phases.delete(script_phase)
217
+ end
218
+
219
+ def add_test_spec_schemes_to_app_scheme(installer, app_project)
220
+ test_native_targets =
221
+ if installer.respond_to?(:target_installation_results) # CocoaPods >= 1.6
222
+ installer
223
+ .target_installation_results
224
+ .pod_target_installation_results
225
+ .values
226
+ .flatten(1)
227
+ .select { |installation_result| installation_result.target.pod_name == spec.root.name }
228
+ else
229
+ installer
230
+ .pod_targets
231
+ .select { |pod_target| pod_target.pod_name == spec.root.name }
232
+ end
233
+ .flat_map(&:test_native_targets)
234
+ .group_by(&:platform_name)
235
+
236
+ Xcodeproj::Plist.write_to_path(
237
+ { 'IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded' => false },
238
+ app_project.path.sub_ext('.xcworkspace').join('xcshareddata').tap(&:mkpath).join('WorkspaceSettings.xcsettings')
239
+ )
240
+
241
+ test_native_targets.each do |platform_name, test_targets|
242
+ app_scheme_path = Xcodeproj::XCScheme.shared_data_dir(app_project.path).join("App-#{Platform.string_name(platform_name)}.xcscheme")
243
+ raise "Missing app scheme for #{platform_name}: #{app_scheme_path.inspect}" unless app_scheme_path.file?
244
+
245
+ app_scheme = Xcodeproj::XCScheme.new(app_scheme_path)
246
+ test_action = app_scheme.test_action
247
+ existing_test_targets = test_action.testables.flat_map(&:buildable_references).map(&:target_name)
248
+
249
+ test_targets.sort_by(&:name).each do |target|
250
+ next if existing_test_targets.include?(target.name)
251
+
252
+ testable = Xcodeproj::XCScheme::TestAction::TestableReference.new(target)
253
+ testable.buildable_references.each do |buildable|
254
+ buildable.xml_element.attributes['ReferencedContainer'] = 'container:Pods.xcodeproj'
255
+ end
256
+ test_action.add_testable(testable)
257
+ end
258
+
259
+ app_scheme.save!
260
+ end
261
+ end
262
+
263
+ def make_ios_app_launchable(installer, app_project, native_app_target)
264
+ platform_name = Platform.string_name(native_app_target.platform_name)
265
+ generated_source_dir = installer.sandbox.root.join('App', platform_name).tap(&:mkpath)
266
+
267
+ # Add `LaunchScreen.storyboard`
268
+ launch_storyboard = generated_source_dir.join('LaunchScreen.storyboard')
269
+ launch_storyboard.write <<-XML.strip_heredoc
270
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
271
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
272
+ <dependencies>
273
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
274
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
275
+ </dependencies>
276
+ <scenes>
277
+ <!--View Controller-->
278
+ <scene sceneID="EHf-IW-A2E">
279
+ <objects>
280
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
281
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
282
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
283
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
284
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
285
+ </view>
286
+ </viewController>
287
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
288
+ </objects>
289
+ <point key="canvasLocation" x="53" y="375"/>
290
+ </scene>
291
+ </scenes>
292
+ </document>
293
+ XML
294
+
295
+ # Add & wire `Info.plist`
296
+ info_plist_contents = {
297
+ 'CFBundleDevelopmentRegion' => '$(DEVELOPMENT_LANGUAGE)',
298
+ 'CFBundleExecutable' => '$(EXECUTABLE_NAME)',
299
+ 'CFBundleIdentifier' => '$(PRODUCT_BUNDLE_IDENTIFIER)',
300
+ 'CFBundleInfoDictionaryVersion' => '6.0',
301
+ 'CFBundleName' => '$(PRODUCT_NAME)',
302
+ 'CFBundlePackageType' => 'APPL',
303
+ 'CFBundleShortVersionString' => '1.0',
304
+ 'CFBundleVersion' => '1',
305
+ 'LSRequiresIPhoneOS' => true,
306
+ 'UILaunchStoryboardName' => 'LaunchScreen',
307
+ 'UIRequiredDeviceCapabilities' => [
308
+ 'armv7'
309
+ ],
310
+ 'UISupportedInterfaceOrientations' => %w[
311
+ UIInterfaceOrientationPortrait
312
+ UIInterfaceOrientationLandscapeLeft
313
+ UIInterfaceOrientationLandscapeRight
314
+ ],
315
+ 'UISupportedInterfaceOrientations~ipad' => %w[
316
+ UIInterfaceOrientationPortrait
317
+ UIInterfaceOrientationPortraitUpsideDown
318
+ UIInterfaceOrientationLandscapeLeft
319
+ UIInterfaceOrientationLandscapeRight
320
+ ]
321
+ }
322
+ info_plist_path = generated_source_dir.join('Info.plist')
323
+ Xcodeproj::Plist.write_to_path(info_plist_contents, info_plist_path)
324
+
325
+ native_app_target.build_configurations.each do |bc|
326
+ bc.build_settings['INFOPLIST_FILE'] = "${SRCROOT}/App/#{platform_name}/Info.plist"
327
+ end
328
+
329
+ group = app_project.main_group.find_subpath("App-#{platform_name}", true)
330
+ group.new_file(info_plist_path)
331
+ native_app_target.resources_build_phase.add_file_reference group.new_file(launch_storyboard)
332
+ end
333
+
334
+ def print_post_install_message
335
+ workspace_path = install_directory.join(podfile.workspace_path)
336
+
337
+ if configuration.auto_open?
338
+ configuration.pod_config.with_changes(verbose: true) do
339
+ Executable.execute_command 'open', [workspace_path]
340
+ end
341
+ else
342
+ UI.info "Open #{UI.path workspace_path} to work on #{spec.name}"
343
+ end
344
+ end
345
+ end
346
+ end
347
+ end
@@ -0,0 +1,378 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pod
4
+ module Generate
5
+ # Generates podfiles for pod specifications given a configuration.
6
+ #
7
+ class PodfileGenerator
8
+ # @return [Configuration]
9
+ # the configuration used when generating podfiles
10
+ #
11
+ attr_reader :configuration
12
+
13
+ def initialize(configuration)
14
+ @configuration = configuration
15
+ end
16
+
17
+ # @return [Hash<Specification, Podfile>]
18
+ # a hash of specifications to generated podfiles
19
+ #
20
+ def podfiles_by_spec
21
+ Hash[configuration.podspecs.map do |spec|
22
+ [spec, podfile_for_spec(spec)]
23
+ end]
24
+ end
25
+
26
+ # @return [Podfile] a podfile suitable for installing the given spec
27
+ #
28
+ # @param [Specification] spec
29
+ #
30
+ def podfile_for_spec(spec)
31
+ generator = self
32
+ dir = configuration.gen_dir_for_pod(spec.name)
33
+
34
+ Pod::Podfile.new do
35
+ project "#{spec.name}.xcodeproj"
36
+ workspace "#{spec.name}.xcworkspace"
37
+
38
+ plugin 'cocoapods-generate'
39
+
40
+ install! 'cocoapods', generator.installation_options
41
+
42
+ generator.podfile_plugins.each do |name, options|
43
+ plugin(*[name, options].compact)
44
+ end
45
+
46
+ use_frameworks!(generator.configuration.use_frameworks?)
47
+
48
+ if (supported_swift_versions = generator.supported_swift_versions)
49
+ supports_swift_versions(supported_swift_versions)
50
+ end
51
+
52
+ # Explicitly set sources
53
+ generator.configuration.sources.each do |source_url|
54
+ source(source_url)
55
+ end
56
+
57
+ self.defined_in_file = dir.join('CocoaPods.podfile.yaml')
58
+
59
+ test_specs = spec.recursive_subspecs.select(&:test_specification?)
60
+ app_specs = if spec.respond_to?(:app_specification?)
61
+ spec.recursive_subspecs.select(&:app_specification?)
62
+ else
63
+ []
64
+ end
65
+
66
+ # Stick all of the transitive dependencies in an abstract target.
67
+ # This allows us to force CocoaPods to use the versions / sources / external sources
68
+ # that we want.
69
+ # By using an abstract target,
70
+ abstract_target 'Transitive Dependencies' do
71
+ pods_for_transitive_dependencies = [spec.name]
72
+ .concat(test_specs.map(&:name))
73
+ .concat(test_specs.flat_map { |ts| ts.dependencies.flat_map(&:name) })
74
+ .concat(app_specs.map(&:name))
75
+ .concat(app_specs.flat_map { |as| as.dependencies.flat_map(&:name) })
76
+
77
+ dependencies = generator
78
+ .transitive_dependencies_by_pod
79
+ .values_at(*pods_for_transitive_dependencies)
80
+ .compact
81
+ .flatten(1)
82
+ .uniq
83
+ .sort_by(&:name)
84
+ .reject { |d| d.root_name == spec.root.name }
85
+
86
+ dependencies.each do |dependency|
87
+ pod_args = generator.pod_args_for_dependency(self, dependency)
88
+ pod(*pod_args)
89
+ end
90
+ end
91
+
92
+ # Add platform-specific concrete targets that inherit the
93
+ # `pod` declaration for the local pod.
94
+ spec.available_platforms.map(&:string_name).sort.each do |platform_name|
95
+ target "App-#{platform_name}" do
96
+ current_target_definition.swift_version = generator.swift_version if generator.swift_version
97
+ end
98
+ end
99
+
100
+ # this block has to come _before_ inhibit_all_warnings! / use_modular_headers!,
101
+ # and the local `pod` declaration
102
+ current_target_definition.instance_exec do
103
+ transitive_dependencies = children.find { |c| c.name == 'Transitive Dependencies' }
104
+
105
+ %w[use_modular_headers inhibit_warnings].each do |key|
106
+ value = transitive_dependencies.send(:internal_hash).delete(key)
107
+ next if value.blank?
108
+ set_hash_value(key, value)
109
+ end
110
+ end
111
+
112
+ inhibit_all_warnings! if generator.inhibit_all_warnings?
113
+ use_modular_headers! if generator.use_modular_headers?
114
+
115
+ # This is the pod declaration for the local pod,
116
+ # it will be inherited by the concrete target definitions below
117
+ pod_options = generator.dependency_compilation_kwargs(spec.name)
118
+ pod_options[:path] = spec.defined_in_file.relative_path_from(dir).to_s
119
+ { testspecs: test_specs, appspecs: app_specs }.each do |key, specs|
120
+ pod_options[key] = specs.map { |s| s.name.sub(%r{^#{Regexp.escape spec.root.name}/}, '') }.sort unless specs.empty?
121
+ end
122
+
123
+ pod spec.name, **pod_options
124
+
125
+ # Implement local-sources option to set up dependencies to podspecs in the local filesystem.
126
+ next if generator.configuration.local_sources.empty?
127
+ generator.transitive_local_dependencies(spec, generator.configuration.local_sources).each do |dependency, podspec_file|
128
+ pod_options = generator.dependency_compilation_kwargs(dependency.name)
129
+ pod_options[:path] = if podspec_file[0] == '/' # absolute path
130
+ podspec_file
131
+ else
132
+ '../../' + podspec_file
133
+ end
134
+ pod dependency.name, **pod_options
135
+ end
136
+ end
137
+ end
138
+ def recursive_subspecs_dependencies(spec)
139
+ dependencies = []
140
+ spec.recursive_subspecs.each do |subspec|
141
+ subspec.dependencies.each do |depency|
142
+ if ! "#{depency}".include? "#{spec.name}"
143
+ dependencies << depency
144
+ end
145
+ end
146
+ end
147
+ return dependencies
148
+ end
149
+ def transitive_local_dependencies(spec, paths)
150
+ dependencies = recursive_subspecs_dependencies(spec)
151
+ return_list = []
152
+ dependencies.each do |dependency|
153
+ found_podspec_file = nil
154
+ name = dependency.name.split('/')[0]
155
+ paths.each do |path|
156
+ podspec_file = path + '/' + name + '.podspec'
157
+ next unless File.file?(podspec_file)
158
+ found_podspec_file = podspec_file
159
+ break
160
+ end
161
+ next unless found_podspec_file
162
+ return_list << [dependency, found_podspec_file]
163
+ dep_spec = Pod::Specification.from_file(found_podspec_file)
164
+ dep_spec.dependencies.each do |d_dep|
165
+ dependencies << d_dep unless dependencies.include? d_dep
166
+ end
167
+ end
168
+ return_list
169
+ end
170
+
171
+ # @return [Boolean]
172
+ # whether all warnings should be inhibited
173
+ #
174
+ def inhibit_all_warnings?
175
+ return false unless configuration.use_podfile?
176
+ target_definition_list.all? do |target_definition|
177
+ target_definition.send(:inhibit_warnings_hash)['all']
178
+ end
179
+ end
180
+
181
+ # @return [Boolean]
182
+ # whether all pods should use modular headers
183
+ #
184
+ def use_modular_headers?
185
+ if configuration.use_podfile? && configuration.use_modular_headers?
186
+ raise Informative, 'Conflicting `use_modular_headers` option. Cannot specify both `--use-modular-headers` and `--use-podfile`.'
187
+ end
188
+
189
+ if configuration.use_podfile?
190
+ target_definition_list.all? do |target_definition|
191
+ target_definition.use_modular_headers_hash['all']
192
+ end
193
+ else
194
+ configuration.use_modular_headers?
195
+ end
196
+ end
197
+
198
+ # @return [Hash]
199
+ # a hash with "compilation"-related dependency options for the `pod` DSL method
200
+ #
201
+ # @param [String] pod_name
202
+ #
203
+ def dependency_compilation_kwargs(pod_name)
204
+ options = {}
205
+ options[:inhibit_warnings] = inhibit_warnings?(pod_name) if inhibit_warnings?(pod_name) != inhibit_all_warnings?
206
+ options[:modular_headers] = modular_headers?(pod_name) if modular_headers?(pod_name) != use_modular_headers?
207
+ options
208
+ end
209
+
210
+ # @return [Hash<String,Array<Dependency>>]
211
+ # the transitive dependency objects dependency upon by each pod
212
+ #
213
+ def transitive_dependencies_by_pod
214
+ return {} unless configuration.use_lockfile?
215
+ @transitive_dependencies_by_pod ||= begin
216
+ lda = ::Pod::Installer::Analyzer::LockingDependencyAnalyzer
217
+ dependency_graph = Molinillo::DependencyGraph.new
218
+ configuration.lockfile.dependencies.each do |dependency|
219
+ dependency_graph.add_vertex(dependency.name, dependency, true)
220
+ end
221
+ add_to_dependency_graph = if lda.method(:add_to_dependency_graph).parameters.size == 4 # CocoaPods < 1.6.0
222
+ ->(pod) { lda.add_to_dependency_graph(pod, [], dependency_graph, []) }
223
+ else
224
+ ->(pod) { lda.add_to_dependency_graph(pod, [], dependency_graph, [], Set.new) }
225
+ end
226
+ configuration.lockfile.internal_data['PODS'].each(&add_to_dependency_graph)
227
+
228
+ transitive_dependencies_by_pod = Hash.new { |hash, key| hash[key] = [] }
229
+ dependency_graph.each do |v|
230
+ transitive_dependencies_by_pod[v.name].concat v.recursive_successors.map(&:payload) << v.payload
231
+ end
232
+
233
+ transitive_dependencies_by_pod.each_value(&:uniq!)
234
+ transitive_dependencies_by_pod
235
+ end
236
+ end
237
+
238
+ # @return [Hash<String,Array<Dependency>>]
239
+ # dependencies in the podfile grouped by root name
240
+ #
241
+ def podfile_dependencies
242
+ return {} unless configuration.use_podfile?
243
+ @podfile_dependencies ||= configuration.podfile.dependencies.group_by(&:root_name).tap { |h| h.default = [] }
244
+ end
245
+
246
+ # @return [Hash<String,String>]
247
+ # versions in the lockfile keyed by pod name
248
+ #
249
+ def lockfile_versions
250
+ return {} unless configuration.use_lockfile_versions?
251
+ @lockfile_versions ||= Hash[configuration.lockfile.pod_names.map { |name| [name, "= #{configuration.lockfile.version(name)}"] }]
252
+ end
253
+
254
+ # @return [Hash<String,Array<Dependency>>]
255
+ # returns the arguments that should be passed to the Podfile DSL's
256
+ # `pod` method for the given podfile and dependency
257
+ #
258
+ # @param [Podfile] podfile
259
+ #
260
+ # @param [Dependency] dependency
261
+ #
262
+ def pod_args_for_dependency(podfile, dependency)
263
+ dependency = podfile_dependencies[dependency.root_name]
264
+ .map { |dep| dep.dup.tap { |d| d.name = dependency.name } }
265
+ .push(dependency)
266
+ .reduce(&:merge)
267
+
268
+ options = dependency_compilation_kwargs(dependency.name)
269
+ options[:source] = dependency.podspec_repo if dependency.podspec_repo
270
+ options.update(dependency.external_source) if dependency.external_source
271
+ %i[path podspec].each do |key|
272
+ next unless (path = options[key])
273
+ options[key] = Pathname(path)
274
+ .expand_path(configuration.podfile.defined_in_file.dirname)
275
+ .relative_path_from(podfile.defined_in_file.dirname)
276
+ .to_s
277
+ end
278
+ args = [dependency.name]
279
+ if dependency.external_source.nil?
280
+ requirements = dependency.requirement.as_list
281
+ if (version = lockfile_versions[dependency.name])
282
+ requirements << version
283
+ end
284
+ args.concat requirements.uniq
285
+ end
286
+ args << options unless options.empty?
287
+ args
288
+ end
289
+
290
+ def swift_version
291
+ @swift_version ||= target_definition_list.map(&:swift_version).compact.max
292
+ end
293
+
294
+ def supported_swift_versions
295
+ return unless configuration.use_podfile?
296
+ return if target_definition_list.empty?
297
+ return unless target_definition_list.first.respond_to?(:swift_version_requirements)
298
+ target_definition_list.reduce(nil) do |supported_swift_versions, target_definition|
299
+ target_swift_versions = target_definition.swift_version_requirements
300
+ next supported_swift_versions unless target_swift_versions
301
+ Array(target_swift_versions) | Array(supported_swift_versions)
302
+ end
303
+ end
304
+
305
+ def installation_options
306
+ installation_options = {
307
+ deterministic_uuids: configuration.deterministic_uuids?,
308
+ share_schemes_for_development_pods: configuration.share_schemes_for_development_pods?,
309
+ warn_for_multiple_pod_sources: configuration.warn_for_multiple_pod_sources?
310
+ }
311
+
312
+ if Pod::Installer::InstallationOptions.all_options.include?('generate_multiple_pod_projects')
313
+ installation_options[:generate_multiple_pod_projects] = configuration.generate_multiple_pod_projects?
314
+ end
315
+
316
+ if Pod::Installer::InstallationOptions.all_options.include?('incremental_installation')
317
+ installation_options[:incremental_installation] = configuration.incremental_installation?
318
+ end
319
+
320
+ installation_options
321
+ end
322
+
323
+ def podfile_plugins
324
+ configuration.podfile_plugins.merge('cocoapods-disable-podfile-validations' => { 'no_abstract_only_pods' => true }) do |_key, old_value, new_value|
325
+ old_value.merge(new_value)
326
+ end
327
+ end
328
+
329
+ private
330
+
331
+ # @return [Array<Podfile::TargetDefinition>]
332
+ # a list of all target definitions to consider from the podfile
333
+ #
334
+ def target_definition_list
335
+ return [] unless configuration.use_podfile?
336
+ @target_definition_list ||= begin
337
+ list = configuration.podfile.target_definition_list
338
+ list.reject!(&:abstract?) unless list.all?(&:abstract?)
339
+ list
340
+ end
341
+ end
342
+
343
+ # @return [Boolean]
344
+ # whether warnings should be inhibited for the given pod
345
+ #
346
+ # @param [String] pod_name
347
+ #
348
+ def inhibit_warnings?(pod_name)
349
+ return false unless configuration.use_podfile?
350
+ target_definitions_for_pod(pod_name).all? do |target_definition|
351
+ target_definition.inhibits_warnings_for_pod?(pod_name)
352
+ end
353
+ end
354
+
355
+ # @return [Boolean]
356
+ # whether modular headers should be enabled for the given pod
357
+ #
358
+ # @param [String] pod_name
359
+ #
360
+ def modular_headers?(pod_name)
361
+ return true if configuration.use_modular_headers?
362
+ return false unless configuration.use_podfile?
363
+ target_definitions_for_pod(pod_name).all? do |target_definition|
364
+ target_definition.build_pod_as_module?(pod_name)
365
+ end
366
+ end
367
+
368
+ # @return [Podfile::TargetDefinition]
369
+ #
370
+ # @param [String] pod_name
371
+ #
372
+ def target_definitions_for_pod(pod_name)
373
+ target_definitions = target_definition_list.reject { |td| td.dependencies.none? { |d| d.name == pod_name } }
374
+ target_definitions.empty? ? target_definition_list : target_definitions
375
+ end
376
+ end
377
+ end
378
+ end