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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/LICENSE.md +9 -0
- data/README.md +131 -0
- data/VERSION +1 -0
- data/lib/cocoapods/command/gen.rb +118 -0
- data/lib/cocoapods/generate.rb +10 -0
- data/lib/cocoapods/generate/configuration.rb +342 -0
- data/lib/cocoapods/generate/installer.rb +347 -0
- data/lib/cocoapods/generate/podfile_generator.rb +378 -0
- data/lib/cocoapods_plugin.rb +7 -0
- metadata +108 -0
@@ -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
|