cocoapods-dykit 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pod/command.rb +2 -0
  3. data/lib/pod/command/dyinstall.rb +51 -0
  4. data/lib/pod/command/dyupdate.rb +106 -0
  5. data/lib/pod/command/fmwk.rb +4 -0
  6. data/lib/pod/command/lib/dylint.rb +1 -0
  7. data/lib/pod/gem_version.rb +1 -1
  8. data/lib/pod/installer.rb +715 -0
  9. data/lib/pod/installer/analyzer.rb +934 -0
  10. data/lib/pod/installer/analyzer/analysis_result.rb +57 -0
  11. data/lib/pod/installer/analyzer/locking_dependency_analyzer.rb +95 -0
  12. data/lib/pod/installer/analyzer/pod_variant.rb +68 -0
  13. data/lib/pod/installer/analyzer/pod_variant_set.rb +157 -0
  14. data/lib/pod/installer/analyzer/podfile_dependency_cache.rb +54 -0
  15. data/lib/pod/installer/analyzer/sandbox_analyzer.rb +251 -0
  16. data/lib/pod/installer/analyzer/specs_state.rb +84 -0
  17. data/lib/pod/installer/analyzer/target_inspection_result.rb +45 -0
  18. data/lib/pod/installer/analyzer/target_inspector.rb +254 -0
  19. data/lib/pod/installer/installation_options.rb +158 -0
  20. data/lib/pod/installer/pod_source_installer.rb +214 -0
  21. data/lib/pod/installer/pod_source_preparer.rb +77 -0
  22. data/lib/pod/installer/podfile_validator.rb +139 -0
  23. data/lib/pod/installer/post_install_hooks_context.rb +107 -0
  24. data/lib/pod/installer/pre_install_hooks_context.rb +42 -0
  25. data/lib/pod/installer/source_provider_hooks_context.rb +32 -0
  26. data/lib/pod/installer/user_project_integrator.rb +253 -0
  27. data/lib/pod/installer/user_project_integrator/target_integrator.rb +462 -0
  28. data/lib/pod/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  29. data/lib/pod/installer/xcode.rb +8 -0
  30. data/lib/pod/installer/xcode/pods_project_generator.rb +353 -0
  31. data/lib/pod/installer/xcode/pods_project_generator/aggregate_target_installer.rb +172 -0
  32. data/lib/pod/installer/xcode/pods_project_generator/file_references_installer.rb +367 -0
  33. data/lib/pod/installer/xcode/pods_project_generator/pod_target_installer.rb +718 -0
  34. data/lib/pod/installer/xcode/pods_project_generator/pod_target_integrator.rb +111 -0
  35. data/lib/pod/installer/xcode/pods_project_generator/target_installer.rb +265 -0
  36. data/lib/pod/installer/xcode/target_validator.rb +141 -0
  37. data/lib/pod/resolver.rb +632 -0
  38. metadata +34 -2
@@ -0,0 +1,111 @@
1
+ module Pod
2
+ class DyInstaller
3
+ class Xcode
4
+ class PodsProjectGenerator
5
+ # This class is responsible for integrating a pod target. This includes integrating
6
+ # the test targets included by each pod target.
7
+ #
8
+ class PodTargetIntegrator
9
+ # @return [PodTarget] the target that should be integrated.
10
+ #
11
+ attr_reader :target
12
+
13
+ # Init a new PodTargetIntegrator.
14
+ #
15
+ # @param [PodTarget] target @see #target
16
+ #
17
+ def initialize(target)
18
+ @target = target
19
+ end
20
+
21
+ # Integrates the pod target.
22
+ #
23
+ # @return [void]
24
+ #
25
+ def integrate!
26
+ UI.section(integration_message) do
27
+ target.test_specs_by_native_target.each do |native_target, test_specs|
28
+ add_embed_frameworks_script_phase(native_target)
29
+ add_copy_resources_script_phase(native_target)
30
+ UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(test_specs), native_target)
31
+ end
32
+ specs = target.non_test_specs
33
+ UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(specs), target.native_target)
34
+ end
35
+ end
36
+
37
+ # @return [String] a string representation suitable for debugging.
38
+ #
39
+ def inspect
40
+ "#<#{self.class} for target `#{target.label}'>"
41
+ end
42
+
43
+ private
44
+
45
+ # @!group Integration steps
46
+ #---------------------------------------------------------------------#
47
+
48
+ # Find or create a 'Copy Pods Resources' build phase
49
+ #
50
+ # @return [void]
51
+ #
52
+ def add_copy_resources_script_phase(native_target)
53
+ test_type = target.test_type_for_product_type(native_target.symbol_type)
54
+ script_path = "${PODS_ROOT}/#{target.copy_resources_script_path_for_test_type(test_type).relative_path_from(target.sandbox.root)}"
55
+ resource_paths = target.all_dependent_targets.flat_map do |dependent_target|
56
+ include_test_spec_paths = dependent_target == target
57
+ dependent_target.resource_paths(include_test_spec_paths)
58
+ end
59
+ input_paths = []
60
+ output_paths = []
61
+ unless resource_paths.empty?
62
+ resource_paths_flattened = resource_paths.flatten.uniq
63
+ input_paths = [script_path, *resource_paths_flattened]
64
+ output_paths = UserProjectIntegrator::TargetIntegrator.resource_output_paths(resource_paths_flattened)
65
+ end
66
+ UserProjectIntegrator::TargetIntegrator.validate_input_output_path_limit(input_paths, output_paths)
67
+ UserProjectIntegrator::TargetIntegrator.create_or_update_copy_resources_script_phase_to_target(native_target, script_path, input_paths, output_paths)
68
+ end
69
+
70
+ # Find or create a 'Embed Pods Frameworks' Copy Files Build Phase
71
+ #
72
+ # @return [void]
73
+ #
74
+ def add_embed_frameworks_script_phase(native_target)
75
+ test_type = target.test_type_for_product_type(native_target.symbol_type)
76
+ script_path = "${PODS_ROOT}/#{target.embed_frameworks_script_path_for_test_type(test_type).relative_path_from(target.sandbox.root)}"
77
+ all_dependent_targets = target.all_dependent_targets
78
+ framework_paths = all_dependent_targets.flat_map do |dependent_target|
79
+ include_test_spec_paths = dependent_target == target
80
+ dependent_target.framework_paths(include_test_spec_paths)
81
+ end
82
+ input_paths = []
83
+ output_paths = []
84
+ unless framework_paths.empty?
85
+ input_paths = [script_path, *framework_paths.flat_map { |fw| [fw[:input_path], fw[:dsym_input_path]] }.compact]
86
+ output_paths = framework_paths.flat_map { |fw| [fw[:output_path], fw[:dsym_output_path]] }.compact
87
+ end
88
+ UserProjectIntegrator::TargetIntegrator.validate_input_output_path_limit(input_paths, output_paths)
89
+ UserProjectIntegrator::TargetIntegrator.create_or_update_embed_frameworks_script_phase_to_target(native_target, script_path, input_paths, output_paths)
90
+ end
91
+
92
+ # @return [String] the message that should be displayed for the target
93
+ # integration.
94
+ #
95
+ def integration_message
96
+ "Integrating target `#{target.name}`"
97
+ end
98
+
99
+ # @param [Array<Specification] specs
100
+ # the specs to return script phrases from.
101
+ #
102
+ # @return [Array<Hash<Symbol=>String>] an array of all combined script phases from the specs.
103
+ #
104
+ def script_phases_for_specs(specs)
105
+ specs.flat_map { |spec| spec.consumer(target.platform).script_phases }
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,265 @@
1
+ module Pod
2
+ class DyInstaller
3
+ class Xcode
4
+ class PodsProjectGenerator
5
+ # Controller class responsible of creating and configuring the static
6
+ # library target in Pods project. It also creates the support file needed
7
+ # by the target.
8
+ #
9
+ class TargetInstaller
10
+ # @return [Sandbox] sandbox
11
+ # The sandbox where the support files should be generated.
12
+ #
13
+ attr_reader :sandbox
14
+
15
+ # @return [Target] target
16
+ # The library whose target needs to be generated.
17
+ #
18
+ attr_reader :target
19
+
20
+ # Initialize a new instance
21
+ #
22
+ # @param [Sandbox] sandbox @see sandbox
23
+ # @param [Target] target @see target
24
+ #
25
+ def initialize(sandbox, target)
26
+ @sandbox = sandbox
27
+ @target = target
28
+ end
29
+
30
+ private
31
+
32
+ #-----------------------------------------------------------------------#
33
+
34
+ # @!group Installation steps
35
+
36
+ # Adds the target for the library to the Pods project with the
37
+ # appropriate build configurations.
38
+ #
39
+ # @note The `PODS_HEADERS_SEARCH_PATHS` overrides the xcconfig.
40
+ #
41
+ # @return [void]
42
+ #
43
+ def add_target
44
+ product_type = target.product_type
45
+ name = target.label
46
+ platform = target.platform.name
47
+ language = target.uses_swift? ? :swift : :objc
48
+ @native_target = project.new_target(product_type, name, platform, deployment_target, nil, language)
49
+
50
+ product_name = target.product_name
51
+ product = @native_target.product_reference
52
+ product.name = product_name
53
+
54
+ target.user_build_configurations.each do |bc_name, type|
55
+ @native_target.add_build_configuration(bc_name, type)
56
+ end
57
+
58
+ @native_target.build_configurations.each do |configuration|
59
+ configuration.build_settings.merge!(custom_build_settings)
60
+ end
61
+
62
+ target.native_target = @native_target
63
+ end
64
+
65
+ # @return [String] The deployment target.
66
+ #
67
+ def deployment_target
68
+ target.platform.deployment_target.to_s
69
+ end
70
+
71
+ # Returns the customized build settings which are overridden in the build
72
+ # settings of the user target.
73
+ #
74
+ # @return [Hash{String => String}]
75
+ #
76
+ def custom_build_settings
77
+ settings = {}
78
+
79
+ unless target.archs.empty?
80
+ settings['ARCHS'] = target.archs
81
+ end
82
+
83
+ if target.requires_frameworks?
84
+ if target.static_framework?
85
+ settings['MACH_O_TYPE'] = 'staticlib'
86
+ end
87
+ else
88
+ settings.merge!('OTHER_LDFLAGS' => '', 'OTHER_LIBTOOLFLAGS' => '')
89
+ end
90
+
91
+ settings
92
+ end
93
+
94
+ # @param [Generator] generator
95
+ # the generator to use for generating the content.
96
+ #
97
+ # @param [Pathname] path
98
+ # the pathname to save the content into.
99
+ #
100
+ # Saves the content the provided path unless the path exists and the contents are exactly the same.
101
+ #
102
+ # @return [Void]
103
+ #
104
+ def update_changed_file(generator, path)
105
+ path.dirname.mkpath
106
+ if path.exist?
107
+ generator.save_as(support_files_temp_dir)
108
+ unless FileUtils.identical?(support_files_temp_dir, path)
109
+ FileUtils.mv(support_files_temp_dir, path)
110
+ end
111
+ else
112
+ generator.save_as(path)
113
+ end
114
+ clean_support_files_temp_dir if support_files_temp_dir.exist?
115
+ end
116
+
117
+ # Creates the directory where to store the support files of the target.
118
+ #
119
+ def create_support_files_dir
120
+ target.support_files_dir.mkpath
121
+ end
122
+
123
+ # Remove temp file whose store .prefix/config/dummy file.
124
+ #
125
+ def clean_support_files_temp_dir
126
+ support_files_temp_dir.rmtree
127
+ end
128
+
129
+ # @return [String] The temp file path to store temporary files.
130
+ #
131
+ def support_files_temp_dir
132
+ sandbox.target_support_files_dir('generated_files_tmp')
133
+ end
134
+
135
+ # Creates the Info.plist file which sets public framework attributes
136
+ #
137
+ # @param [Pathname] path
138
+ # the path to save the generated Info.plist file.
139
+ #
140
+ # @param [PBXNativeTarget] native_target
141
+ # the native target to link the generated Info.plist file into.
142
+ #
143
+ # @param [Version] version
144
+ # the version to use for when generating this Info.plist file.
145
+ #
146
+ # @param [Platform] platform
147
+ # the platform to use for when generating this Info.plist file.
148
+ #
149
+ # @param [Symbol] bundle_package_type
150
+ # the CFBundlePackageType of the target this Info.plist file is for.
151
+ #
152
+ # @return [void]
153
+ #
154
+ def create_info_plist_file(path, native_target, version, platform, bundle_package_type = :fmwk)
155
+ UI.message "- Generating Info.plist file at #{UI.path(path)}" do
156
+ generator = Generator::InfoPlistFile.new(version, platform, bundle_package_type)
157
+ update_changed_file(generator, path)
158
+ add_file_to_support_group(path)
159
+
160
+ native_target.build_configurations.each do |c|
161
+ relative_path = path.relative_path_from(sandbox.root)
162
+ c.build_settings['INFOPLIST_FILE'] = relative_path.to_s
163
+ end
164
+ end
165
+ end
166
+
167
+ # Creates the module map file which ensures that the umbrella header is
168
+ # recognized with a customized path
169
+ #
170
+ # @return [void]
171
+ #
172
+ def create_module_map
173
+ path = target.module_map_path
174
+ UI.message "- Generating module map file at #{UI.path(path)}" do
175
+ generator = Generator::ModuleMap.new(target)
176
+ yield generator if block_given?
177
+ update_changed_file(generator, path)
178
+ add_file_to_support_group(path)
179
+
180
+ native_target.build_configurations.each do |c|
181
+ relative_path = path.relative_path_from(sandbox.root)
182
+ c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
183
+ end
184
+ end
185
+ end
186
+
187
+ # Generates a header which ensures that all header files are exported
188
+ # in the module map
189
+ #
190
+ # @yield_param [Generator::UmbrellaHeader]
191
+ # yielded once to configure the imports
192
+ #
193
+ def create_umbrella_header
194
+ path = target.umbrella_header_path
195
+ UI.message "- Generating umbrella header at #{UI.path(path)}" do
196
+ generator = Generator::UmbrellaHeader.new(target)
197
+ yield generator if block_given?
198
+ update_changed_file(generator, path)
199
+
200
+ # Add the file to the support group and the native target,
201
+ # so it will been added to the header build phase
202
+ file_ref = add_file_to_support_group(path)
203
+ native_target.add_file_references([file_ref])
204
+
205
+ acl = target.requires_frameworks? ? 'Public' : 'Project'
206
+ build_file = native_target.headers_build_phase.build_file(file_ref)
207
+ build_file.settings ||= {}
208
+ build_file.settings['ATTRIBUTES'] = [acl]
209
+ end
210
+ end
211
+
212
+ # Generates a dummy source file for each target so libraries that contain
213
+ # only categories build.
214
+ #
215
+ # @return [void]
216
+ #
217
+ def create_dummy_source
218
+ path = target.dummy_source_path
219
+ generator = Generator::DummySource.new(target.label)
220
+ update_changed_file(generator, path)
221
+ file_reference = add_file_to_support_group(path)
222
+ native_target.source_build_phase.add_file_reference(file_reference)
223
+ end
224
+
225
+ # @return [PBXNativeTarget] the target generated by the installation
226
+ # process.
227
+ #
228
+ # @note Generated by the {#add_target} step.
229
+ #
230
+ attr_reader :native_target
231
+
232
+ private
233
+
234
+ #-----------------------------------------------------------------------#
235
+
236
+ # @!group Private helpers.
237
+
238
+ # @return [Project] the Pods project of the sandbox.
239
+ #
240
+ def project
241
+ sandbox.project
242
+ end
243
+
244
+ # @return [PBXGroup] the group where the file references to the support
245
+ # files should be stored.
246
+ #
247
+ attr_reader :support_files_group
248
+
249
+ # Adds a reference to the given file in the support group of this target.
250
+ #
251
+ # @param [Pathname] path
252
+ # The path of the file to which the reference should be added.
253
+ #
254
+ # @return [PBXFileReference] the file reference of the added file.
255
+ #
256
+ def add_file_to_support_group(path)
257
+ support_files_group.new_file(path)
258
+ end
259
+
260
+ #-----------------------------------------------------------------------#
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,141 @@
1
+ module Pod
2
+ class DyInstaller
3
+ class Xcode
4
+ # The {Xcode::TargetValidator} ensures that the pod and aggregate target
5
+ # configuration is valid for installation.
6
+ #
7
+ class TargetValidator
8
+ # @return [Array<AggregateTarget>] The aggregate targets that should be
9
+ # validated.
10
+ #
11
+ attr_reader :aggregate_targets
12
+
13
+ # @return [Array<PodTarget>] The pod targets that should be validated.
14
+ #
15
+ attr_reader :pod_targets
16
+
17
+ # Create a new TargetValidator with aggregate and pod targets to
18
+ # validate.
19
+ #
20
+ # @param [Array<AggregateTarget>] aggregate_targets
21
+ # The aggregate targets to validate.
22
+ #
23
+ # @param [Array<PodTarget>] pod_targets
24
+ # The pod targets to validate.
25
+ #
26
+ def initialize(aggregate_targets, pod_targets)
27
+ @aggregate_targets = aggregate_targets
28
+ @pod_targets = pod_targets
29
+ end
30
+
31
+ # Perform the validation steps for the provided aggregate and pod
32
+ # targets.
33
+ #
34
+ def validate!
35
+ verify_no_duplicate_framework_and_library_names
36
+ verify_no_static_framework_transitive_dependencies
37
+ verify_no_pods_used_with_multiple_swift_versions
38
+ verify_swift_pods_have_module_dependencies
39
+ end
40
+
41
+ private
42
+
43
+ def verify_no_duplicate_framework_and_library_names
44
+ aggregate_targets.each do |aggregate_target|
45
+ aggregate_target.user_build_configurations.keys.each do |config|
46
+ pod_targets = aggregate_target.pod_targets_for_build_configuration(config)
47
+ file_accessors = pod_targets.flat_map(&:file_accessors)
48
+
49
+ frameworks = file_accessors.flat_map(&:vendored_frameworks).uniq.map(&:basename)
50
+ frameworks += pod_targets.select { |pt| pt.should_build? && pt.requires_frameworks? }.map(&:product_module_name).uniq
51
+ verify_no_duplicate_names(frameworks, aggregate_target.label, 'frameworks')
52
+
53
+ libraries = file_accessors.flat_map(&:vendored_libraries).uniq.map(&:basename)
54
+ libraries += pod_targets.select { |pt| pt.should_build? && !pt.requires_frameworks? }.map(&:product_name)
55
+ verify_no_duplicate_names(libraries, aggregate_target.label, 'libraries')
56
+ end
57
+ end
58
+ end
59
+
60
+ def verify_no_duplicate_names(names, label, type)
61
+ duplicates = names.map { |n| n.to_s.downcase }.group_by { |f| f }.select { |_, v| v.size > 1 }.keys
62
+
63
+ unless duplicates.empty?
64
+ raise Informative, "The '#{label}' target has " \
65
+ "#{type} with conflicting names: #{duplicates.to_sentence}."
66
+ end
67
+ end
68
+
69
+ def verify_no_static_framework_transitive_dependencies
70
+ aggregate_targets.each do |aggregate_target|
71
+ next unless aggregate_target.requires_frameworks?
72
+
73
+ aggregate_target.user_build_configurations.keys.each do |config|
74
+ dynamic_pod_targets = aggregate_target.pod_targets_for_build_configuration(config).reject(&:static_framework?)
75
+
76
+ dependencies = dynamic_pod_targets.select(&:should_build?).flat_map(&:dependencies)
77
+ depended_upon_targets = dynamic_pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? }
78
+
79
+ static_libs = depended_upon_targets.flat_map(&:file_accessors).flat_map(&:vendored_static_artifacts)
80
+ unless static_libs.empty?
81
+ raise Informative, "The '#{aggregate_target.label}' target has " \
82
+ "transitive dependencies that include static binaries: (#{static_libs.to_sentence})"
83
+ end
84
+
85
+ static_framework_deps = dynamic_pod_targets.select(&:should_build?).flat_map(&:recursive_dependent_targets).select(&:static_framework?)
86
+ unless static_framework_deps.empty?
87
+ raise Informative, "The '#{aggregate_target.label}' target has " \
88
+ "transitive dependencies that include static frameworks: (#{static_framework_deps.flat_map(&:name).to_sentence})"
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def verify_no_pods_used_with_multiple_swift_versions
95
+ error_message_for_target = lambda do |target|
96
+ "#{target.name} (Swift #{target.swift_version})"
97
+ end
98
+ swift_pod_targets = pod_targets.select(&:uses_swift?)
99
+ error_messages = swift_pod_targets.map do |pod_target|
100
+ next unless pod_target.spec_swift_version.nil?
101
+ swift_target_definitions = pod_target.target_definitions.reject { |target| target.swift_version.blank? }
102
+ next if swift_target_definitions.empty? || swift_target_definitions.uniq(&:swift_version).count == 1
103
+ target_errors = swift_target_definitions.map(&error_message_for_target).join(', ')
104
+ "- #{pod_target.name} required by #{target_errors}"
105
+ end.compact
106
+
107
+ unless error_messages.empty?
108
+ raise Informative, 'The following pods are integrated into targets ' \
109
+ "that do not have the same Swift version:\n\n#{error_messages.join("\n")}"
110
+ end
111
+ end
112
+
113
+ def verify_swift_pods_have_module_dependencies
114
+ error_messages = []
115
+ pod_targets.each do |pod_target|
116
+ next unless pod_target.uses_swift?
117
+
118
+ non_module_dependencies = []
119
+ pod_target.dependent_targets.each do |dependent_target|
120
+ next if !dependent_target.should_build? || dependent_target.defines_module?
121
+ non_module_dependencies << dependent_target.name
122
+ end
123
+
124
+ next if non_module_dependencies.empty?
125
+
126
+ error_messages << "The Swift pod `#{pod_target.name}` depends upon #{non_module_dependencies.map { |d| "`#{d}`" }.to_sentence}, " \
127
+ 'which do not define modules. ' \
128
+ 'To opt into those targets generating module maps '\
129
+ '(which is necessary to import them from Swift when building as static libraries), ' \
130
+ 'you may set `use_modular_headers!` globally in your Podfile, '\
131
+ 'or specify `:modular_headers => true` for particular dependencies.'
132
+ end
133
+ return if error_messages.empty?
134
+
135
+ raise Informative, 'The following Swift pods cannot yet be integrated '\
136
+ "as static libraries:\n\n#{error_messages.join("\n\n")}"
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end