xcocoapods 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6303 -0
  3. data/LICENSE +28 -0
  4. data/README.md +80 -0
  5. data/bin/pod +56 -0
  6. data/bin/sandbox-pod +168 -0
  7. data/lib/cocoapods.rb +73 -0
  8. data/lib/cocoapods/command.rb +175 -0
  9. data/lib/cocoapods/command/cache.rb +28 -0
  10. data/lib/cocoapods/command/cache/clean.rb +90 -0
  11. data/lib/cocoapods/command/cache/list.rb +69 -0
  12. data/lib/cocoapods/command/env.rb +66 -0
  13. data/lib/cocoapods/command/init.rb +128 -0
  14. data/lib/cocoapods/command/install.rb +45 -0
  15. data/lib/cocoapods/command/ipc.rb +19 -0
  16. data/lib/cocoapods/command/ipc/list.rb +40 -0
  17. data/lib/cocoapods/command/ipc/podfile.rb +31 -0
  18. data/lib/cocoapods/command/ipc/podfile_json.rb +30 -0
  19. data/lib/cocoapods/command/ipc/repl.rb +51 -0
  20. data/lib/cocoapods/command/ipc/spec.rb +29 -0
  21. data/lib/cocoapods/command/ipc/update_search_index.rb +24 -0
  22. data/lib/cocoapods/command/lib.rb +11 -0
  23. data/lib/cocoapods/command/lib/create.rb +105 -0
  24. data/lib/cocoapods/command/lib/lint.rb +121 -0
  25. data/lib/cocoapods/command/list.rb +39 -0
  26. data/lib/cocoapods/command/options/project_directory.rb +36 -0
  27. data/lib/cocoapods/command/options/repo_update.rb +34 -0
  28. data/lib/cocoapods/command/outdated.rb +140 -0
  29. data/lib/cocoapods/command/repo.rb +29 -0
  30. data/lib/cocoapods/command/repo/add.rb +103 -0
  31. data/lib/cocoapods/command/repo/lint.rb +82 -0
  32. data/lib/cocoapods/command/repo/list.rb +93 -0
  33. data/lib/cocoapods/command/repo/push.rb +281 -0
  34. data/lib/cocoapods/command/repo/remove.rb +36 -0
  35. data/lib/cocoapods/command/repo/update.rb +28 -0
  36. data/lib/cocoapods/command/setup.rb +103 -0
  37. data/lib/cocoapods/command/spec.rb +112 -0
  38. data/lib/cocoapods/command/spec/cat.rb +51 -0
  39. data/lib/cocoapods/command/spec/create.rb +283 -0
  40. data/lib/cocoapods/command/spec/edit.rb +87 -0
  41. data/lib/cocoapods/command/spec/env_spec.rb +53 -0
  42. data/lib/cocoapods/command/spec/lint.rb +137 -0
  43. data/lib/cocoapods/command/spec/which.rb +43 -0
  44. data/lib/cocoapods/command/update.rb +101 -0
  45. data/lib/cocoapods/config.rb +347 -0
  46. data/lib/cocoapods/core_overrides.rb +1 -0
  47. data/lib/cocoapods/downloader.rb +190 -0
  48. data/lib/cocoapods/downloader/cache.rb +233 -0
  49. data/lib/cocoapods/downloader/request.rb +86 -0
  50. data/lib/cocoapods/downloader/response.rb +16 -0
  51. data/lib/cocoapods/executable.rb +222 -0
  52. data/lib/cocoapods/external_sources.rb +57 -0
  53. data/lib/cocoapods/external_sources/abstract_external_source.rb +205 -0
  54. data/lib/cocoapods/external_sources/downloader_source.rb +30 -0
  55. data/lib/cocoapods/external_sources/path_source.rb +55 -0
  56. data/lib/cocoapods/external_sources/podspec_source.rb +54 -0
  57. data/lib/cocoapods/gem_version.rb +5 -0
  58. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  59. data/lib/cocoapods/generator/acknowledgements/markdown.rb +44 -0
  60. data/lib/cocoapods/generator/acknowledgements/plist.rb +94 -0
  61. data/lib/cocoapods/generator/app_target_helper.rb +244 -0
  62. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  63. data/lib/cocoapods/generator/constant.rb +19 -0
  64. data/lib/cocoapods/generator/copy_resources_script.rb +230 -0
  65. data/lib/cocoapods/generator/dummy_source.rb +31 -0
  66. data/lib/cocoapods/generator/embed_frameworks_script.rb +215 -0
  67. data/lib/cocoapods/generator/header.rb +103 -0
  68. data/lib/cocoapods/generator/info_plist_file.rb +116 -0
  69. data/lib/cocoapods/generator/module_map.rb +99 -0
  70. data/lib/cocoapods/generator/prefix_header.rb +60 -0
  71. data/lib/cocoapods/generator/umbrella_header.rb +46 -0
  72. data/lib/cocoapods/hooks_manager.rb +132 -0
  73. data/lib/cocoapods/installer.rb +703 -0
  74. data/lib/cocoapods/installer/analyzer.rb +972 -0
  75. data/lib/cocoapods/installer/analyzer/analysis_result.rb +87 -0
  76. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +98 -0
  77. data/lib/cocoapods/installer/analyzer/pod_variant.rb +67 -0
  78. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +157 -0
  79. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  80. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +240 -0
  81. data/lib/cocoapods/installer/analyzer/specs_state.rb +84 -0
  82. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +53 -0
  83. data/lib/cocoapods/installer/analyzer/target_inspector.rb +260 -0
  84. data/lib/cocoapods/installer/installation_options.rb +158 -0
  85. data/lib/cocoapods/installer/pod_source_installer.rb +202 -0
  86. data/lib/cocoapods/installer/pod_source_preparer.rb +77 -0
  87. data/lib/cocoapods/installer/podfile_validator.rb +139 -0
  88. data/lib/cocoapods/installer/post_install_hooks_context.rb +132 -0
  89. data/lib/cocoapods/installer/pre_install_hooks_context.rb +51 -0
  90. data/lib/cocoapods/installer/source_provider_hooks_context.rb +34 -0
  91. data/lib/cocoapods/installer/user_project_integrator.rb +250 -0
  92. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +463 -0
  93. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  94. data/lib/cocoapods/installer/xcode.rb +8 -0
  95. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +416 -0
  96. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +181 -0
  97. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +84 -0
  98. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +334 -0
  99. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +777 -0
  100. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +116 -0
  101. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +86 -0
  102. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +256 -0
  103. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +68 -0
  104. data/lib/cocoapods/installer/xcode/target_validator.rb +147 -0
  105. data/lib/cocoapods/open-uri.rb +33 -0
  106. data/lib/cocoapods/project.rb +414 -0
  107. data/lib/cocoapods/resolver.rb +585 -0
  108. data/lib/cocoapods/resolver/lazy_specification.rb +79 -0
  109. data/lib/cocoapods/sandbox.rb +404 -0
  110. data/lib/cocoapods/sandbox/file_accessor.rb +444 -0
  111. data/lib/cocoapods/sandbox/headers_store.rb +146 -0
  112. data/lib/cocoapods/sandbox/path_list.rb +220 -0
  113. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +85 -0
  114. data/lib/cocoapods/sandbox/podspec_finder.rb +23 -0
  115. data/lib/cocoapods/sources_manager.rb +157 -0
  116. data/lib/cocoapods/target.rb +261 -0
  117. data/lib/cocoapods/target/aggregate_target.rb +338 -0
  118. data/lib/cocoapods/target/build_settings.rb +1075 -0
  119. data/lib/cocoapods/target/pod_target.rb +559 -0
  120. data/lib/cocoapods/user_interface.rb +459 -0
  121. data/lib/cocoapods/user_interface/error_report.rb +187 -0
  122. data/lib/cocoapods/user_interface/inspector_reporter.rb +109 -0
  123. data/lib/cocoapods/validator.rb +981 -0
  124. metadata +533 -0
@@ -0,0 +1,240 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ # Analyze the sandbox to detect which Pods should be removed, and which
5
+ # ones should be reinstalled.
6
+ #
7
+ # The logic is the following:
8
+ #
9
+ # Added
10
+ # - If not present in the sandbox lockfile.
11
+ # - The directory of the Pod doesn't exits.
12
+ #
13
+ # Changed
14
+ # - The version of the Pod changed.
15
+ # - The SHA of the specification file changed.
16
+ # - The specific installed (sub)specs of the same Pod changed.
17
+ # - The specification is from an external source and the
18
+ # installation process is in update mode.
19
+ # - The directory of the Pod is empty.
20
+ # - The Pod has been pre-downloaded.
21
+ #
22
+ # Removed
23
+ # - If a specification is present in the lockfile but not in the resolved
24
+ # specs.
25
+ #
26
+ # Unchanged
27
+ # - If none of the above conditions match.
28
+ #
29
+ class SandboxAnalyzer
30
+ # @return [Sandbox] The sandbox to analyze.
31
+ #
32
+ attr_reader :sandbox
33
+
34
+ # @return [Array<Specifications>] The specifications returned by the
35
+ # resolver.
36
+ #
37
+ attr_reader :specs
38
+
39
+ # @return [Bool] Whether the installation is performed in update mode.
40
+ #
41
+ attr_reader :update_mode
42
+
43
+ alias_method :update_mode?, :update_mode
44
+
45
+ # Init a new SandboxAnalyzer
46
+ #
47
+ # @param [Sandbox] sandbox @see sandbox
48
+ # @param [Array<Specifications>] specs @see specs
49
+ # @param [Bool] update_mode @see update_mode
50
+ #
51
+ def initialize(sandbox, specs, update_mode)
52
+ @sandbox = sandbox
53
+ @specs = specs
54
+ @update_mode = update_mode
55
+ end
56
+
57
+ # Performs the analysis to the detect the state of the sandbox respect
58
+ # to the resolved specifications.
59
+ #
60
+ # @return [void]
61
+ #
62
+ def analyze
63
+ state = SpecsState.new
64
+ if sandbox_manifest
65
+ all_names = (resolved_pods + sandbox_pods).uniq.sort
66
+ all_names.sort.each do |name|
67
+ state.add_name(name, pod_state(name))
68
+ end
69
+ else
70
+ state.added.merge(resolved_pods)
71
+ end
72
+ state
73
+ end
74
+
75
+ #---------------------------------------------------------------------#
76
+
77
+ private
78
+
79
+ # @!group Pod state
80
+
81
+ # Returns the state of the Pod with the given name.
82
+ #
83
+ # @param [String] pod
84
+ # the name of the Pod.
85
+ #
86
+ # @return [Symbol] The state
87
+ #
88
+ def pod_state(pod)
89
+ return :added if pod_added?(pod)
90
+ return :deleted if pod_deleted?(pod)
91
+ return :changed if pod_changed?(pod)
92
+ :unchanged
93
+ end
94
+
95
+ # Returns whether the Pod with the given name should be installed.
96
+ #
97
+ # @note A Pod whose folder doesn't exists is considered added.
98
+ #
99
+ # @param [String] pod
100
+ # the name of the Pod.
101
+ #
102
+ # @return [Bool] Whether the Pod is added.
103
+ #
104
+ def pod_added?(pod)
105
+ return true if resolved_pods.include?(pod) && !sandbox_pods.include?(pod)
106
+ return true if !folder_exist?(pod) && !sandbox.local?(pod)
107
+ false
108
+ end
109
+
110
+ # Returns whether the Pod with the given name should be removed from
111
+ # the installation.
112
+ #
113
+ # @param [String] pod
114
+ # the name of the Pod.
115
+ #
116
+ # @return [Bool] Whether the Pod is deleted.
117
+ #
118
+ def pod_deleted?(pod)
119
+ return true if !resolved_pods.include?(pod) && sandbox_pods.include?(pod)
120
+ false
121
+ end
122
+
123
+ # Returns whether the Pod with the given name should be considered
124
+ # changed and thus should be reinstalled.
125
+ #
126
+ # @note In update mode, as there is no way to know if a remote source
127
+ # hash changed the Pods from external
128
+ # sources are always marked as changed.
129
+ #
130
+ # @note A Pod whose folder is empty is considered changed.
131
+ #
132
+ # @param [String] pod
133
+ # the name of the Pod.
134
+ #
135
+ # @return [Bool] Whether the Pod is changed.
136
+ #
137
+ def pod_changed?(pod)
138
+ spec = root_spec(pod)
139
+ return true if spec.version != sandbox_version(pod)
140
+ return true if spec.checksum != sandbox_checksum(pod)
141
+ return true if resolved_spec_names(pod) != sandbox_spec_names(pod)
142
+ return true if sandbox.predownloaded?(pod)
143
+ return true if folder_empty?(pod)
144
+ false
145
+ end
146
+
147
+ #---------------------------------------------------------------------#
148
+
149
+ private
150
+
151
+ # @!group Private helpers
152
+
153
+ # @return [Lockfile] The manifest to use for the sandbox.
154
+ #
155
+ def sandbox_manifest
156
+ sandbox.manifest
157
+ end
158
+
159
+ #--------------------------------------#
160
+
161
+ # @return [Array<String>] The name of the resolved Pods.
162
+ #
163
+ def resolved_pods
164
+ specs.map { |spec| spec.root.name }.uniq
165
+ end
166
+
167
+ # @return [Array<String>] The name of the Pods stored in the sandbox
168
+ # manifest.
169
+ #
170
+ def sandbox_pods
171
+ sandbox_manifest.pod_names.map { |name| Specification.root_name(name) }.uniq
172
+ end
173
+
174
+ # @return [Array<String>] The name of the resolved specifications
175
+ # (includes subspecs).
176
+ #
177
+ # @param [String] pod
178
+ # the name of the Pod.
179
+ #
180
+ def resolved_spec_names(pod)
181
+ specs.select { |s| s.root.name == pod }.map(&:name).uniq.sort
182
+ end
183
+
184
+ # @return [Array<String>] The name of the specifications stored in the
185
+ # sandbox manifest (includes subspecs).
186
+ #
187
+ # @param [String] pod
188
+ # the name of the Pod.
189
+ #
190
+ def sandbox_spec_names(pod)
191
+ sandbox_manifest.pod_names.select { |name| Specification.root_name(name) == pod }.uniq.sort
192
+ end
193
+
194
+ # @return [Specification] The root specification for the Pod with the
195
+ # given name.
196
+ #
197
+ # @param [String] pod
198
+ # the name of the Pod.
199
+ #
200
+ def root_spec(pod)
201
+ specs.find { |s| s.root.name == pod }.root
202
+ end
203
+
204
+ #--------------------------------------#
205
+
206
+ # @return [Version] The version of Pod with the given name stored in
207
+ # the sandbox.
208
+ #
209
+ # @param [String] pod
210
+ # the name of the Pod.
211
+ #
212
+ def sandbox_version(pod)
213
+ sandbox_manifest.version(pod)
214
+ end
215
+
216
+ # @return [String] The checksum of the specification of the Pod with
217
+ # the given name stored in the sandbox.
218
+ #
219
+ # @param [String] pod
220
+ # the name of the Pod.
221
+ #
222
+ def sandbox_checksum(pod)
223
+ sandbox_manifest.checksum(pod)
224
+ end
225
+
226
+ #--------------------------------------#
227
+
228
+ def folder_exist?(pod)
229
+ sandbox.pod_dir(pod).exist?
230
+ end
231
+
232
+ def folder_empty?(pod)
233
+ Dir.glob(sandbox.pod_dir(pod) + '*').empty?
234
+ end
235
+
236
+ #---------------------------------------------------------------------#
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,84 @@
1
+ require 'set'
2
+
3
+ module Pod
4
+ class Installer
5
+ class Analyzer
6
+ # This class represents the state of a collection of Pods.
7
+ #
8
+ # @note The names of the pods stored by this class are always the **root**
9
+ # name of the specification.
10
+ #
11
+ # @note The motivation for this class is to ensure that the names of the
12
+ # subspecs are added instead of the name of the Pods.
13
+ #
14
+ class SpecsState
15
+ # @return [Set<String>] the names of the pods that were added.
16
+ #
17
+ attr_reader :added
18
+
19
+ # @return [Set<String>] the names of the pods that were changed.
20
+ #
21
+ attr_reader :changed
22
+
23
+ # @return [Set<String>] the names of the pods that were deleted.
24
+ #
25
+ attr_reader :deleted
26
+
27
+ # @return [Set<String>] the names of the pods that were unchanged.
28
+ #
29
+ attr_reader :unchanged
30
+
31
+ # Initialize a new instance
32
+ #
33
+ # @param [Hash{Symbol=>String}] pods_by_state
34
+ # The name of the pods grouped by their state
35
+ # (`:added`, `:removed`, `:changed` or `:unchanged`).
36
+ #
37
+ def initialize(pods_by_state = nil)
38
+ @added = Set.new
39
+ @deleted = Set.new
40
+ @changed = Set.new
41
+ @unchanged = Set.new
42
+
43
+ if pods_by_state
44
+ {
45
+ :added => :added,
46
+ :changed => :changed,
47
+ :removed => :deleted,
48
+ :unchanged => :unchanged,
49
+ }.each do |state, spec_state|
50
+ Array(pods_by_state[state]).each do |name|
51
+ add_name(name, spec_state)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ # Displays the state of each pod.
58
+ #
59
+ # @return [void]
60
+ #
61
+ def print
62
+ added .sort.each { |pod| UI.message('A'.green + " #{pod}", '', 2) }
63
+ deleted .sort.each { |pod| UI.message('R'.red + " #{pod}", '', 2) }
64
+ changed .sort.each { |pod| UI.message('M'.yellow + " #{pod}", '', 2) }
65
+ unchanged.sort.each { |pod| UI.message('-' + " #{pod}", '', 2) }
66
+ end
67
+
68
+ # Adds the name of a Pod to the give state.
69
+ #
70
+ # @param [String] name
71
+ # the name of the Pod.
72
+ #
73
+ # @param [Symbol] state
74
+ # the state of the Pod.
75
+ #
76
+ # @return [void]
77
+ #
78
+ def add_name(name, state)
79
+ send(state) << Specification.root_name(name)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,53 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ class TargetInspectionResult
5
+ # @return [TargetDefinition] the target definition, whose project was
6
+ # inspected
7
+ #
8
+ attr_reader :target_definition
9
+
10
+ # @return [Xcodeproj::Project] the user's Xcode project
11
+ #
12
+ attr_reader :project
13
+
14
+ # @return [Array<String>] the uuid of the user's targets
15
+ #
16
+ attr_reader :project_target_uuids
17
+
18
+ # @return [Hash{String=>Symbol}] A hash representing the user build
19
+ # configurations where each key corresponds to the name of a
20
+ # configuration and its value to its type (`:debug` or
21
+ # `:release`).
22
+ #
23
+ attr_reader :build_configurations
24
+
25
+ # @return [Platform] the platform of the user targets
26
+ #
27
+ attr_reader :platform
28
+
29
+ # @return [Array<String>] the architectures used by user's targets
30
+ #
31
+ attr_reader :archs
32
+
33
+ # Initialize a new instance
34
+ #
35
+ # @param [TargetDefinition] target_definition @see #target_definition
36
+ # @param [Xcodeproj::Project] project @see #project
37
+ # @param [Array<String>] project_target_uuids @see #project_target_uuids
38
+ # @param [Hash{String=>Symbol}] build_configurations @see #build_configurations
39
+ # @param [Platform] platform @see #platform
40
+ # @param [Array<String>] archs @see #archs
41
+ #
42
+ def initialize(target_definition, project, project_target_uuids, build_configurations, platform, archs)
43
+ @target_definition = target_definition
44
+ @project = project
45
+ @project_target_uuids = project_target_uuids
46
+ @build_configurations = build_configurations
47
+ @platform = platform
48
+ @archs = archs
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,260 @@
1
+ require 'active_support/core_ext/array/conversions'
2
+
3
+ module Pod
4
+ class Installer
5
+ class Analyzer
6
+ class TargetInspector
7
+ PLATFORM_INFO_URL = 'https://guides.cocoapods.org/syntax/podfile.html#platform'.freeze
8
+
9
+ # @return [TargetDefinition] the target definition to inspect
10
+ #
11
+ attr_reader :target_definition
12
+
13
+ # @return [Pathname] the root of the CocoaPods installation where the
14
+ # Podfile is located
15
+ #
16
+ attr_reader :installation_root
17
+
18
+ # Initialize a new instance
19
+ #
20
+ # @param [TargetDefinition] target_definition
21
+ # @see #target_definition
22
+ #
23
+ # @param [Pathname] installation_root
24
+ # @see #installation_root
25
+ #
26
+ def initialize(target_definition, installation_root)
27
+ @target_definition = target_definition
28
+ @installation_root = installation_root
29
+ end
30
+
31
+ # Inspect the #target_definition
32
+ #
33
+ # @raise If no `user_project` is set
34
+ #
35
+ # @return [TargetInspectionResult] the result of the inspection of the target definition within the user project
36
+ #
37
+ def compute_results(user_project)
38
+ raise ArgumentError, 'Cannot compute results without a user project set' unless user_project
39
+
40
+ targets = compute_targets(user_project)
41
+ project_target_uuids = targets.map(&:uuid)
42
+ build_configurations = compute_build_configurations(targets)
43
+ platform = compute_platform(targets)
44
+ archs = compute_archs(targets)
45
+ swift_version = compute_swift_version_from_targets(targets)
46
+
47
+ result = TargetInspectionResult.new(target_definition, user_project, project_target_uuids,
48
+ build_configurations, platform, archs)
49
+ result.target_definition.swift_version = swift_version
50
+ result
51
+ end
52
+
53
+ # Returns the path of the user project that the #target_definition
54
+ # should integrate.
55
+ #
56
+ # @raise If the project is implicit and there are multiple projects.
57
+ #
58
+ # @raise If the path doesn't exits.
59
+ #
60
+ # @return [Pathname] the path of the user project.
61
+ #
62
+ def compute_project_path
63
+ if target_definition.user_project_path
64
+ path = installation_root + target_definition.user_project_path
65
+ path = "#{path}.xcodeproj" unless File.extname(path) == '.xcodeproj'
66
+ path = Pathname.new(path)
67
+ unless path.exist?
68
+ raise Informative, 'Unable to find the Xcode project ' \
69
+ "`#{path}` for the target `#{target_definition.label}`."
70
+ end
71
+ else
72
+ xcodeprojs = installation_root.children.select { |e| e.fnmatch('*.xcodeproj') }
73
+ if xcodeprojs.size == 1
74
+ path = xcodeprojs.first
75
+ else
76
+ raise Informative, 'Could not automatically select an Xcode project. ' \
77
+ "Specify one in your Podfile like so:\n\n" \
78
+ " project 'path/to/Project.xcodeproj'\n"
79
+ end
80
+ end
81
+ path
82
+ end
83
+
84
+ #-----------------------------------------------------------------------#
85
+
86
+ private
87
+
88
+ # Returns a list of the targets from the project of #target_definition
89
+ # that needs to be integrated.
90
+ #
91
+ # @note The method first looks if there is a target specified with
92
+ # the `link_with` option of the {TargetDefinition}. Otherwise
93
+ # it looks for the target that has the same name of the target
94
+ # definition. Finally if no target was found the first
95
+ # encountered target is returned (it is assumed to be the one
96
+ # to integrate in simple projects).
97
+ #
98
+ # @param [Xcodeproj::Project] user_project
99
+ # the user project
100
+ #
101
+ # @return [Array<PBXNativeTarget>]
102
+ #
103
+ def compute_targets(user_project)
104
+ native_targets = user_project.native_targets
105
+ target = native_targets.find { |t| t.name == target_definition.name.to_s }
106
+ unless target
107
+ found = native_targets.map { |t| "`#{t.name}`" }.to_sentence
108
+ raise Informative, "Unable to find a target named `#{target_definition.name}`, did find #{found}."
109
+ end
110
+ [target]
111
+ end
112
+
113
+ # @param [Array<PBXNativeTarget] user_targets the user's targets of the project of
114
+ # #target_definition which needs to be integrated
115
+ #
116
+ # @return [Hash{String=>Symbol}] A hash representing the user build
117
+ # configurations where each key corresponds to the name of a
118
+ # configuration and its value to its type (`:debug` or `:release`).
119
+ #
120
+ def compute_build_configurations(user_targets)
121
+ if user_targets
122
+ user_targets.flat_map { |t| t.build_configurations.map(&:name) }.each_with_object({}) do |name, hash|
123
+ hash[name] = name == 'Debug' ? :debug : :release
124
+ end.merge(target_definition.build_configurations || {})
125
+ else
126
+ target_definition.build_configurations || {}
127
+ end
128
+ end
129
+
130
+ # @param [Array<PBXNativeTarget] user_targets the user's targets of the project of
131
+ # #target_definition which needs to be integrated
132
+ #
133
+ # @return [Platform] The platform of the user's targets
134
+ #
135
+ # @note This resolves to the lowest deployment target across the user
136
+ # targets.
137
+ #
138
+ # @todo Is assigning the platform to the target definition the best way
139
+ # to go?
140
+ #
141
+ def compute_platform(user_targets)
142
+ return target_definition.platform if target_definition.platform
143
+ name = nil
144
+ deployment_target = nil
145
+
146
+ user_targets.each do |target|
147
+ name ||= target.platform_name
148
+ raise Informative, 'Targets with different platforms' unless name == target.platform_name
149
+ if !deployment_target || deployment_target > Version.new(target.deployment_target)
150
+ deployment_target = Version.new(target.deployment_target)
151
+ end
152
+ end
153
+
154
+ unless name
155
+ raise Informative,
156
+ "Unable to determine the platform for the `#{target_definition.name}` target."
157
+ end
158
+
159
+ UI.warn "Automatically assigning platform `#{name}` with version `#{deployment_target}` " \
160
+ "on target `#{target_definition.name}` because no platform was specified. " \
161
+ "Please specify a platform for this target in your Podfile. See `#{PLATFORM_INFO_URL}`."
162
+
163
+ target_definition.set_platform(name, deployment_target)
164
+ Platform.new(name, deployment_target)
165
+ end
166
+
167
+ # Computes the architectures relevant for the user's targets.
168
+ #
169
+ # @param [Array<PBXNativeTarget] user_targets the user's targets of the project of
170
+ # #target_definition which needs to be integrated
171
+ #
172
+ # @return [Array<String>]
173
+ #
174
+ def compute_archs(user_targets)
175
+ user_targets.flat_map do |target|
176
+ Array(target.common_resolved_build_setting('ARCHS'))
177
+ end.compact.uniq.sort
178
+ end
179
+
180
+ # Checks if any of the targets for the {TargetDefinition} computed before
181
+ # by #compute_user_project_targets is recommended to be build as a framework
182
+ # due the presence of Swift source code in any of the source build phases.
183
+ #
184
+ # @param [TargetDefinition] target_definition
185
+ # the target definition
186
+ #
187
+ # @param [Array<PBXNativeTarget>] native_targets
188
+ # the targets which are checked for presence of Swift source code
189
+ #
190
+ # @return [Boolean] Whether the user project targets to integrate into
191
+ # uses Swift
192
+ #
193
+ def compute_recommends_frameworks(target_definition, native_targets)
194
+ file_predicate = nil
195
+ file_predicate = proc do |file_ref|
196
+ if file_ref.respond_to?(:last_known_file_type)
197
+ file_ref.last_known_file_type == 'sourcecode.swift'
198
+ elsif file_ref.respond_to?(:files)
199
+ file_ref.files.any?(&file_predicate)
200
+ else
201
+ false
202
+ end
203
+ end
204
+ target_definition.platform.supports_dynamic_frameworks? || native_targets.any? do |target|
205
+ target.source_build_phase.files.any? do |build_file|
206
+ file_predicate.call(build_file.file_ref)
207
+ end
208
+ end
209
+ end
210
+
211
+ # Compute the Swift version for the target build configurations. If more
212
+ # than one Swift version is defined for a given target, then it will raise.
213
+ #
214
+ # @param [Array<PBXNativeTarget>] targets
215
+ # the targets that are checked for Swift versions.
216
+ #
217
+ # @return [String] the targets Swift version or nil
218
+ #
219
+ def compute_swift_version_from_targets(targets)
220
+ versions_to_targets = targets.inject({}) do |memo, target|
221
+ # User project may have an xcconfig that specifies the `SWIFT_VERSION`. We first check if that is true and
222
+ # that the xcconfig file actually exists. After the first integration the xcconfig set is most probably
223
+ # the one that was generated from CocoaPods. See https://github.com/CocoaPods/CocoaPods/issues/7731 for
224
+ # more details.
225
+ resolve_against_xcconfig = target.build_configuration_list.build_configurations.all? do |bc|
226
+ !bc.base_configuration_reference.nil? && File.exist?(bc.base_configuration_reference.real_path)
227
+ end
228
+ versions = target.resolved_build_setting('SWIFT_VERSION', resolve_against_xcconfig).values
229
+ versions.each do |version|
230
+ memo[version] = [] if memo[version].nil?
231
+ memo[version] << target.name unless memo[version].include? target.name
232
+ end
233
+ memo
234
+ end
235
+
236
+ case versions_to_targets.count
237
+ when 0
238
+ nil
239
+ when 1
240
+ versions_to_targets.keys.first
241
+ else
242
+ target_version_pairs = versions_to_targets.map do |version_names, target_names|
243
+ target_names.map { |target_name| [target_name, version_names] }
244
+ end
245
+
246
+ sorted_pairs = target_version_pairs.flat_map { |i| i }.sort_by do |target_name, version_name|
247
+ "#{target_name} #{version_name}"
248
+ end
249
+
250
+ formatted_output = sorted_pairs.map do |target, version_name|
251
+ "#{target}: Swift #{version_name}"
252
+ end.join("\n")
253
+
254
+ raise Informative, "There may only be up to 1 unique SWIFT_VERSION per target. Found target(s) with multiple Swift versions:\n#{formatted_output}"
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end