cocoapods 0.37.2 → 0.38.0.beta.1

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -1
  3. data/lib/cocoapods.rb +0 -5
  4. data/lib/cocoapods/command.rb +3 -0
  5. data/lib/cocoapods/command/cache.rb +28 -0
  6. data/lib/cocoapods/command/cache/clean.rb +90 -0
  7. data/lib/cocoapods/command/cache/list.rb +69 -0
  8. data/lib/cocoapods/command/lib.rb +11 -4
  9. data/lib/cocoapods/command/list.rb +4 -4
  10. data/lib/cocoapods/command/outdated.rb +1 -10
  11. data/lib/cocoapods/command/project.rb +3 -2
  12. data/lib/cocoapods/command/spec.rb +0 -17
  13. data/lib/cocoapods/command/spec/cat.rb +1 -1
  14. data/lib/cocoapods/command/spec/create.rb +1 -0
  15. data/lib/cocoapods/command/spec/edit.rb +1 -1
  16. data/lib/cocoapods/command/spec/lint.rb +10 -4
  17. data/lib/cocoapods/config.rb +6 -0
  18. data/lib/cocoapods/downloader/cache.rb +48 -1
  19. data/lib/cocoapods/executable.rb +27 -6
  20. data/lib/cocoapods/gem_version.rb +1 -1
  21. data/lib/cocoapods/generator/copy_resources_script.rb +1 -0
  22. data/lib/cocoapods/generator/embed_frameworks_script.rb +23 -28
  23. data/lib/cocoapods/generator/header.rb +5 -1
  24. data/lib/cocoapods/generator/umbrella_header.rb +1 -1
  25. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +139 -33
  26. data/lib/cocoapods/generator/xcconfig/private_pod_xcconfig.rb +2 -2
  27. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +3 -3
  28. data/lib/cocoapods/installer.rb +64 -109
  29. data/lib/cocoapods/installer/analyzer.rb +167 -336
  30. data/lib/cocoapods/installer/analyzer/analysis_result.rb +46 -0
  31. data/lib/cocoapods/installer/analyzer/specs_state.rb +76 -0
  32. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +41 -0
  33. data/lib/cocoapods/installer/analyzer/target_inspector.rb +203 -0
  34. data/lib/cocoapods/installer/file_references_installer.rb +48 -13
  35. data/lib/cocoapods/installer/podfile_validator.rb +86 -0
  36. data/lib/cocoapods/installer/{hooks_context.rb → post_install_hooks_context.rb} +3 -3
  37. data/lib/cocoapods/installer/pre_install_hooks_context.rb +41 -0
  38. data/lib/cocoapods/installer/target_installer.rb +1 -7
  39. data/lib/cocoapods/installer/target_installer/aggregate_target_installer.rb +15 -17
  40. data/lib/cocoapods/installer/target_installer/pod_target_installer.rb +4 -4
  41. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +16 -16
  42. data/lib/cocoapods/sandbox/file_accessor.rb +20 -2
  43. data/lib/cocoapods/sandbox/path_list.rb +15 -13
  44. data/lib/cocoapods/sandbox/podspec_finder.rb +1 -0
  45. data/lib/cocoapods/sources_manager.rb +2 -0
  46. data/lib/cocoapods/target.rb +7 -37
  47. data/lib/cocoapods/target/aggregate_target.rb +25 -1
  48. data/lib/cocoapods/target/pod_target.rb +106 -10
  49. data/lib/cocoapods/user_interface.rb +26 -0
  50. data/lib/cocoapods/user_interface/error_report.rb +6 -0
  51. data/lib/cocoapods/validator.rb +22 -0
  52. metadata +21 -16
  53. data/lib/cocoapods/generator/target_environment_header.rb +0 -171
  54. data/lib/cocoapods/hooks/installer_representation.rb +0 -133
  55. data/lib/cocoapods/hooks/library_representation.rb +0 -93
  56. data/lib/cocoapods/hooks/pod_representation.rb +0 -70
@@ -0,0 +1,46 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ class AnalysisResult
5
+ # @return [SpecsState] the states of the Podfile specs.
6
+ #
7
+ attr_accessor :podfile_state
8
+
9
+ # @return [Hash{TargetDefinition => Array<Specification>}] the
10
+ # specifications grouped by target.
11
+ #
12
+ attr_accessor :specs_by_target
13
+
14
+ # @return [Array<Specification>] the specifications of the resolved
15
+ # version of Pods that should be installed.
16
+ #
17
+ attr_accessor :specifications
18
+
19
+ # @return [SpecsState] the states of the {Sandbox} respect the resolved
20
+ # specifications.
21
+ #
22
+ attr_accessor :sandbox_state
23
+
24
+ # @return [Array<Target>] The Podfile targets containing library
25
+ # dependencies.
26
+ #
27
+ attr_accessor :targets
28
+
29
+ # @return [Hash{TargetDefinition => Array<TargetInspectionResult>}] the
30
+ # results of inspecting the user targets
31
+ attr_accessor :target_inspections
32
+
33
+ # @return [Hash{String=>Symbol}] A hash representing all the user build
34
+ # configurations across all integration targets. Each key
35
+ # corresponds to the name of a configuration and its value to
36
+ # its type (`:debug` or `:release`).
37
+ #
38
+ def all_user_build_configurations
39
+ targets.reduce({}) do |result, target|
40
+ result.merge(target.user_build_configurations)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,76 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ # This class represents the state of a collection of Pods.
5
+ #
6
+ # @note The names of the pods stored by this class are always the **root**
7
+ # name of the specification.
8
+ #
9
+ # @note The motivation for this class is to ensure that the names of the
10
+ # subspecs are added instead of the name of the Pods.
11
+ #
12
+ class SpecsState
13
+ # Initialize a new instance
14
+ #
15
+ # @param [Hash{Symbol=>String}] pods_by_state
16
+ # The name of the pods grouped by their state
17
+ # (`:added`, `:removed`, `:changed` or `:unchanged`).
18
+ #
19
+ def initialize(pods_by_state = nil)
20
+ @added = []
21
+ @deleted = []
22
+ @changed = []
23
+ @unchanged = []
24
+
25
+ if pods_by_state
26
+ @added = pods_by_state[:added] || []
27
+ @deleted = pods_by_state[:removed] || []
28
+ @changed = pods_by_state[:changed] || []
29
+ @unchanged = pods_by_state[:unchanged] || []
30
+ end
31
+ end
32
+
33
+ # @return [Array<String>] the names of the pods that were added.
34
+ #
35
+ attr_accessor :added
36
+
37
+ # @return [Array<String>] the names of the pods that were changed.
38
+ #
39
+ attr_accessor :changed
40
+
41
+ # @return [Array<String>] the names of the pods that were deleted.
42
+ #
43
+ attr_accessor :deleted
44
+
45
+ # @return [Array<String>] the names of the pods that were unchanged.
46
+ #
47
+ attr_accessor :unchanged
48
+
49
+ # Displays the state of each pod.
50
+ #
51
+ # @return [void]
52
+ #
53
+ def print
54
+ added .sort.each { |pod| UI.message('A'.green + " #{pod}", '', 2) }
55
+ deleted .sort.each { |pod| UI.message('R'.red + " #{pod}", '', 2) }
56
+ changed .sort.each { |pod| UI.message('M'.yellow + " #{pod}", '', 2) }
57
+ unchanged.sort.each { |pod| UI.message('-' + " #{pod}", '', 2) }
58
+ end
59
+
60
+ # Adds the name of a Pod to the give state.
61
+ #
62
+ # @param [String] name
63
+ # the name of the Pod.
64
+ #
65
+ # @param [Symbol] state
66
+ # the state of the Pod.
67
+ #
68
+ # @return [void]
69
+ #
70
+ def add_name(name, state)
71
+ send(state) << name
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,41 @@
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_accessor :target_definition
9
+
10
+ # @return [Pathname] the path of the user project that the
11
+ # #target_definition should integrate
12
+ #
13
+ attr_accessor :project_path
14
+
15
+ # @return [Array<String>] the uuid of the user's targets
16
+ #
17
+ attr_accessor :project_target_uuids
18
+
19
+ # @return [Hash{String=>Symbol}] A hash representing the user build
20
+ # configurations where each key corresponds to the name of a
21
+ # configuration and its value to its type (`:debug` or
22
+ # `:release`).
23
+ #
24
+ attr_accessor :build_configurations
25
+
26
+ # @return [Platform] the platform of the user targets
27
+ #
28
+ attr_accessor :platform
29
+
30
+ # @return [Array<String>] the architectures used by user's targets
31
+ #
32
+ attr_accessor :archs
33
+
34
+ # @return [Bool] whether frameworks are recommended for the integration
35
+ # due to the presence of Swift source in the user's targets
36
+ #
37
+ attr_accessor :recommends_frameworks
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,203 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+ class TargetInspector
5
+ # @return [TargetDefinition] the target definition to inspect
6
+ #
7
+ attr_accessor :target_definition
8
+
9
+ # @return [Pathname] the root of the CocoaPods installation where the
10
+ # Podfile is located
11
+ attr_accessor :installation_root
12
+
13
+ # Initialize a new instance
14
+ #
15
+ # @param [TargetDefinition] target_definition
16
+ # @see #target_definition
17
+ #
18
+ # @param [Pathname] installation_root
19
+ # @see #installation_root
20
+ #
21
+ def initialize(target_definition, installation_root)
22
+ @target_definition = target_definition
23
+ @installation_root = installation_root
24
+ end
25
+
26
+ # Inspect the #target_definition
27
+ #
28
+ # @return [TargetInspectionResult]
29
+ #
30
+ def compute_results
31
+ project_path = compute_project_path
32
+ user_project = Xcodeproj::Project.open(project_path)
33
+ targets = compute_targets(user_project)
34
+
35
+ result = TargetInspectionResult.new
36
+ result.target_definition = target_definition
37
+ result.project_path = project_path
38
+ result.project_target_uuids = targets.map(&:uuid)
39
+ result.build_configurations = compute_build_configurations(targets)
40
+ result.platform = compute_platform(targets)
41
+ result.archs = compute_archs(targets)
42
+ result
43
+ end
44
+
45
+ #-----------------------------------------------------------------------#
46
+
47
+ private
48
+
49
+ # Returns the path of the user project that the #target_definition
50
+ # should integrate.
51
+ #
52
+ # @raise If the project is implicit and there are multiple projects.
53
+ #
54
+ # @raise If the path doesn't exits.
55
+ #
56
+ # @return [Pathname] the path of the user project.
57
+ #
58
+ def compute_project_path
59
+ if target_definition.user_project_path
60
+ path = installation_root + target_definition.user_project_path
61
+ path = "#{path}.xcodeproj" unless File.extname(path) == '.xcodeproj'
62
+ path = Pathname.new(path)
63
+ unless path.exist?
64
+ raise Informative, 'Unable to find the Xcode project ' \
65
+ "`#{path}` for the target `#{target_definition.label}`."
66
+ end
67
+ else
68
+ xcodeprojs = installation_root.children.select { |e| e.fnmatch('*.xcodeproj') }
69
+ if xcodeprojs.size == 1
70
+ path = xcodeprojs.first
71
+ else
72
+ raise Informative, 'Could not automatically select an Xcode project. ' \
73
+ "Specify one in your Podfile like so:\n\n" \
74
+ " xcodeproj 'path/to/Project.xcodeproj'\n"
75
+ end
76
+ end
77
+ path
78
+ end
79
+
80
+ # Returns a list of the targets from the project of #target_definition
81
+ # that needs to be integrated.
82
+ #
83
+ # @note The method first looks if there is a target specified with
84
+ # the `link_with` option of the {TargetDefinition}. Otherwise
85
+ # it looks for the target that has the same name of the target
86
+ # definition. Finally if no target was found the first
87
+ # encountered target is returned (it is assumed to be the one
88
+ # to integrate in simple projects).
89
+ #
90
+ # @param [Xcodeproj::Project] user_project
91
+ # the user project
92
+ #
93
+ # @return [Array<PBXNativeTarget>]
94
+ #
95
+ def compute_targets(user_project)
96
+ native_targets = user_project.native_targets
97
+ if link_with = target_definition.link_with
98
+ targets = native_targets.select { |t| link_with.include?(t.name) }
99
+ raise Informative, "Unable to find the targets named #{link_with.map { |x| "`#{x}`" }.to_sentence}" \
100
+ "to link with target definition `#{target_definition.name}`" if targets.empty?
101
+ elsif target_definition.link_with_first_target?
102
+ targets = [native_targets.first].compact
103
+ raise Informative, 'Unable to find a target' if targets.empty?
104
+ else
105
+ target = native_targets.find { |t| t.name == target_definition.name.to_s }
106
+ targets = [target].compact
107
+ raise Informative, "Unable to find a target named `#{target_definition.name}`" if targets.empty?
108
+ end
109
+ targets
110
+ end
111
+
112
+ # @param [Array<PBXNativeTarget] the user's targets of the project of
113
+ # #target_definition which needs to be integrated
114
+ #
115
+ # @return [Hash{String=>Symbol}] A hash representing the user build
116
+ # configurations where each key corresponds to the name of a
117
+ # configuration and its value to its type (`:debug` or `:release`).
118
+ #
119
+ def compute_build_configurations(user_targets)
120
+ if user_targets
121
+ user_targets.flat_map { |t| t.build_configurations.map(&:name) }.each_with_object({}) do |name, hash|
122
+ hash[name] = name == 'Debug' ? :debug : :release
123
+ end.merge(target_definition.build_configurations || {})
124
+ else
125
+ target_definition.build_configurations || {}
126
+ end
127
+ end
128
+
129
+ # @param [Array<PBXNativeTarget] the user's targets of the project of
130
+ # #target_definition which needs to be integrated
131
+ #
132
+ # @return [Platform] The platform of the user's targets
133
+ #
134
+ # @note This resolves to the lowest deployment target across the user
135
+ # targets.
136
+ #
137
+ # @todo Is assigning the platform to the target definition the best way
138
+ # to go?
139
+ #
140
+ def compute_platform(user_targets)
141
+ return target_definition.platform if target_definition.platform
142
+ name = nil
143
+ deployment_target = nil
144
+
145
+ user_targets.each do |target|
146
+ name ||= target.platform_name
147
+ raise Informative, 'Targets with different platforms' unless name == target.platform_name
148
+ if !deployment_target || deployment_target > Version.new(target.deployment_target)
149
+ deployment_target = Version.new(target.deployment_target)
150
+ end
151
+ end
152
+
153
+ target_definition.set_platform(name, deployment_target)
154
+ Platform.new(name, deployment_target)
155
+ end
156
+
157
+ # Computes the architectures relevant for the user's targets.
158
+ #
159
+ # @param [Array<PBXNativeTarget] the user's targets of the project of
160
+ # #target_definition which needs to be integrated
161
+ #
162
+ # @return [Array<String>]
163
+ #
164
+ def compute_archs(user_targets)
165
+ user_targets.flat_map do |target|
166
+ Array(target.common_resolved_build_setting('ARCHS'))
167
+ end.compact.uniq.sort
168
+ end
169
+
170
+ # Checks if any of the targets for the {TargetDefinition} computed before
171
+ # by #compute_user_project_targets is recommended to be build as a framework
172
+ # due the presence of Swift source code in any of the source build phases.
173
+ #
174
+ # @param [TargetDefinition] target_definition
175
+ # the target definition
176
+ #
177
+ # @param [Array<PBXNativeTarget>] native_targets
178
+ # the targets which are checked for presence of Swift source code
179
+ #
180
+ # @return [Boolean] Whether the user project targets to integrate into
181
+ # uses Swift
182
+ #
183
+ def compute_recommends_frameworks(target_definition, native_targets)
184
+ file_predicate = nil
185
+ file_predicate = proc do |file_ref|
186
+ if file_ref.respond_to?(:last_known_file_type)
187
+ file_ref.last_known_file_type == 'sourcecode.swift'
188
+ elsif file_ref.respond_to?(:files)
189
+ file_ref.files.any?(&file_predicate)
190
+ else
191
+ false
192
+ end
193
+ end
194
+ target_definition.platform.supports_dynamic_frameworks? || native_targets.any? do |target|
195
+ target.source_build_phase.files.any? do |build_file|
196
+ file_predicate.call(build_file.file_ref)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
@@ -8,9 +8,9 @@ module Pod
8
8
  #
9
9
  attr_reader :sandbox
10
10
 
11
- # @return [Array<PodTarget>] The libraries of the installation.
11
+ # @return [Array<PodTarget>] The pod targets of the installation.
12
12
  #
13
- attr_reader :libraries
13
+ attr_reader :pod_targets
14
14
 
15
15
  # @return [Project] The Pods project.
16
16
  #
@@ -19,12 +19,12 @@ module Pod
19
19
  # Initialize a new instance
20
20
  #
21
21
  # @param [Sandbox] sandbox @see sandbox
22
- # @param [Array<PodTarget>] libraries @see libraries
23
- # @param [Project] libraries @see libraries
22
+ # @param [Array<PodTarget>] pod_targets @see pod_targets
23
+ # @param [Project] pods_project @see pod_project
24
24
  #
25
- def initialize(sandbox, libraries, pods_project)
25
+ def initialize(sandbox, pod_targets, pods_project)
26
26
  @sandbox = sandbox
27
- @libraries = libraries
27
+ @pod_targets = pod_targets
28
28
  @pods_project = pods_project
29
29
  end
30
30
 
@@ -113,18 +113,23 @@ module Pod
113
113
  #
114
114
  def link_headers
115
115
  UI.message '- Linking headers' do
116
- libraries.each do |library|
117
- library.file_accessors.each do |file_accessor|
116
+ pod_targets.each do |pod_target|
117
+ pod_target.file_accessors.each do |file_accessor|
118
+ framework_exp = /.framework\//
118
119
  headers_sandbox = Pathname.new(file_accessor.spec.root.name)
119
- library.build_headers.add_search_path(headers_sandbox, library.platform)
120
- sandbox.public_headers.add_search_path(headers_sandbox, library.platform)
120
+ pod_target.build_headers.add_search_path(headers_sandbox, pod_target.platform)
121
+ sandbox.public_headers.add_search_path(headers_sandbox, pod_target.platform)
121
122
 
122
123
  header_mappings(headers_sandbox, file_accessor, file_accessor.headers).each do |namespaced_path, files|
123
- library.build_headers.add_files(namespaced_path, files, library.platform)
124
+ pod_target.build_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp }, pod_target.platform)
124
125
  end
125
126
 
126
127
  header_mappings(headers_sandbox, file_accessor, file_accessor.public_headers).each do |namespaced_path, files|
127
- sandbox.public_headers.add_files(namespaced_path, files, library.platform)
128
+ sandbox.public_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp }, pod_target.platform)
129
+ end
130
+
131
+ vendored_frameworks_header_mappings(headers_sandbox, file_accessor).each do |namespaced_path, files|
132
+ sandbox.public_headers.add_files(namespaced_path, files, pod_target.platform)
128
133
  end
129
134
  end
130
135
  end
@@ -141,7 +146,7 @@ module Pod
141
146
  # specs platform combinations.
142
147
  #
143
148
  def file_accessors
144
- @file_accessors ||= libraries.map(&:file_accessors).flatten.compact
149
+ @file_accessors ||= pod_targets.map(&:file_accessors).flatten.compact
145
150
  end
146
151
 
147
152
  # Adds file references to the list of the paths returned by the file
@@ -208,6 +213,36 @@ module Pod
208
213
  mappings
209
214
  end
210
215
 
216
+ # Computes the destination sub-directory in the sandbox for headers
217
+ # from inside vendored frameworks.
218
+ #
219
+ # @param [Pathname] headers_sandbox
220
+ # The sandbox where the header links should be stored for this
221
+ # Pod.
222
+ #
223
+ # @param [Sandbox::FileAccessor] file_accessor
224
+ # The consumer file accessor for which the headers need to be
225
+ # linked.
226
+ #
227
+ def vendored_frameworks_header_mappings(headers_sandbox, file_accessor)
228
+ mappings = {}
229
+ file_accessor.vendored_frameworks.each do |framework|
230
+ headers_dir = Sandbox::FileAccessor.vendored_frameworks_headers_dir(framework)
231
+ headers = Sandbox::FileAccessor.vendored_frameworks_headers(framework)
232
+ framework_name = framework.basename(framework.extname)
233
+ dir = headers_sandbox + framework_name
234
+ headers.each do |header|
235
+ # the relative path of framework headers should be kept,
236
+ # not flattened like is done for most public headers.
237
+ relative_path = header.relative_path_from(headers_dir)
238
+ sub_dir = dir + relative_path.dirname
239
+ mappings[sub_dir] ||= []
240
+ mappings[sub_dir] << header
241
+ end
242
+ end
243
+ mappings
244
+ end
245
+
211
246
  #-----------------------------------------------------------------------#
212
247
  end
213
248
  end