cocoapods-dykit 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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