cocoapods 0.20.2 → 0.21.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,132 @@
1
+ module Pod
2
+ class Installer
3
+
4
+ # Creates the targets which aggregate the Pods libraries in the Pods
5
+ # project and the relative support files.
6
+ #
7
+ class AggregateTargetInstaller < TargetInstaller
8
+
9
+ # Creates the target in the Pods project and the relative support files.
10
+ #
11
+ # @return [void]
12
+ #
13
+ def install!
14
+ UI.message "- Installing target `#{library.name}` #{library.platform}" do
15
+ add_target
16
+ create_suport_files_group
17
+ create_xcconfig_file
18
+ create_target_environment_header
19
+ create_bridge_support_file
20
+ create_copy_resources_script
21
+ create_acknowledgements
22
+ create_dummy_source
23
+ end
24
+ end
25
+
26
+ #-----------------------------------------------------------------------#
27
+
28
+ private
29
+
30
+ # Generates the contents of the xcconfig file and saves it to disk.
31
+ #
32
+ # @note The `ALWAYS_SEARCH_USER_PATHS` flag is enabled to support
33
+ # libraries like `EmbedReader`.
34
+ #
35
+ # @return [void]
36
+ #
37
+ def create_xcconfig_file
38
+ path = library.xcconfig_path
39
+ UI.message "- Generating xcconfig file at #{UI.path(path)}" do
40
+ gen = Generator::AggregateXCConfig.new(library)
41
+ gen.save_as(path)
42
+ library.xcconfig = gen.xcconfig
43
+ xcconfig_file_ref = add_file_to_support_group(path)
44
+
45
+ target.build_configurations.each do |c|
46
+ c.base_configuration_reference = xcconfig_file_ref
47
+ end
48
+ end
49
+ end
50
+
51
+ # Generates a header which allows to inspect at compile time the installed
52
+ # pods and the installed specifications of a pod.
53
+ #
54
+ def create_target_environment_header
55
+ path = library.target_environment_header_path
56
+ UI.message "- Generating target environment header at #{UI.path(path)}" do
57
+ generator = Generator::TargetEnvironmentHeader.new(library.pod_targets.map { |l| l.specs }.flatten)
58
+ generator.save_as(path)
59
+ add_file_to_support_group(path)
60
+ end
61
+ end
62
+
63
+ # Generates the bridge support metadata if requested by the {Podfile}.
64
+ #
65
+ # @note The bridge support metadata is added to the resources of the
66
+ # library because it is needed for environments interpreted at
67
+ # runtime.
68
+ #
69
+ # @return [void]
70
+ #
71
+ def create_bridge_support_file
72
+ if target_definition.podfile.generate_bridge_support?
73
+ path = library.bridge_support_path
74
+ UI.message "- Generating BridgeSupport metadata at #{UI.path(path)}" do
75
+ headers = target.headers_build_phase.files.map { |bf| sandbox.root + bf.file_ref.path }
76
+ generator = Generator::BridgeSupport.new(headers)
77
+ generator.save_as(path)
78
+ add_file_to_support_group(path)
79
+ @bridge_support_file = path.relative_path_from(sandbox.root)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Creates a script that copies the resources to the bundle of the client
85
+ # target.
86
+ #
87
+ # @note The bridge support file needs to be created before the prefix
88
+ # header, otherwise it will not be added to the resources script.
89
+ #
90
+ # @return [void]
91
+ #
92
+ def create_copy_resources_script
93
+ path = library.copy_resources_script_path
94
+ UI.message "- Generating copy resources script at #{UI.path(path)}" do
95
+ file_accessors = library.pod_targets.map(&:file_accessors).flatten
96
+ resources = file_accessors.map { |accessor| accessor.resources.flatten.map {|res| project.relativize(res)} }.flatten
97
+ resources << bridge_support_file if bridge_support_file
98
+ generator = Generator::CopyResourcesScript.new(resources, library.platform)
99
+ generator.save_as(path)
100
+ add_file_to_support_group(path)
101
+ end
102
+ end
103
+
104
+ # Generates the acknowledgement files (markdown and plist) for the target.
105
+ #
106
+ # @return [void]
107
+ #
108
+ def create_acknowledgements
109
+ basepath = library.acknowledgements_basepath
110
+ Generator::Acknowledgements.generators.each do |generator_class|
111
+ path = generator_class.path_from_basepath(basepath)
112
+ UI.message "- Generating acknowledgements at #{UI.path(path)}" do
113
+ file_accessors = library.pod_targets.map(&:file_accessors).flatten
114
+ generator = generator_class.new(file_accessors)
115
+ generator.save_as(path)
116
+ add_file_to_support_group(path)
117
+ end
118
+ end
119
+ end
120
+
121
+ # @return [Pathname] the path of the bridge support file relative to the
122
+ # sandbox.
123
+ #
124
+ # @return [Nil] if no bridge support file was generated.
125
+ #
126
+ attr_reader :bridge_support_file
127
+
128
+ #-----------------------------------------------------------------------#
129
+
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,160 @@
1
+ module Pod
2
+ class Installer
3
+
4
+ # Creates the target for the Pods libraries in the Pods project and the
5
+ # relative support files.
6
+ #
7
+ class PodTargetInstaller < TargetInstaller
8
+
9
+ # Creates the target in the Pods project and the relative support files.
10
+ #
11
+ # @return [void]
12
+ #
13
+ def install!
14
+ UI.message "- Installing target `#{library.name}` #{library.platform}" do
15
+ add_target
16
+ add_files_to_build_phases
17
+ create_suport_files_group
18
+ create_xcconfig_file
19
+ create_prefix_header
20
+ create_dummy_source
21
+ end
22
+ end
23
+
24
+ #-----------------------------------------------------------------------#
25
+
26
+ private
27
+
28
+ # Adds the build files of the pods to the target and adds a reference to
29
+ # the frameworks of the Pods.
30
+ #
31
+ # @note The Frameworks are used only for presentation purposes as the
32
+ # xcconfig is the authoritative source about their information.
33
+ #
34
+ # @return [void]
35
+ #
36
+ def add_files_to_build_phases
37
+ UI.message "- Adding Build files" do
38
+ library.file_accessors.each do |file_accessor|
39
+ consumer = file_accessor.spec_consumer
40
+ flags = compiler_flags_for_consumer(consumer)
41
+ source_files = file_accessor.source_files
42
+ file_refs = source_files.map { |sf| project.file_reference(sf) }
43
+ target.add_file_references(file_refs, flags)
44
+
45
+ file_accessor.spec_consumer.frameworks.each do |framework|
46
+ project.add_system_framework(framework, target)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Generates the contents of the xcconfig file and saves it to disk.
53
+ #
54
+ # @note The `ALWAYS_SEARCH_USER_PATHS` flag is enabled to support
55
+ # libraries like `EmbedReader`.
56
+ #
57
+ # @return [void]
58
+ #
59
+ def create_xcconfig_file
60
+ path = library.xcconfig_path
61
+ UI.message "- Generating public xcconfig file at #{UI.path(path)}" do
62
+ gen = Generator::PublicPodXCConfig.new(library)
63
+ gen.save_as(path)
64
+ add_file_to_support_group(path)
65
+ end
66
+
67
+ path = library.xcconfig_private_path
68
+ UI.message "- Generating private xcconfig file at #{UI.path(path)}" do
69
+ gen = Generator::PrivatePodXCConfig.new(library)
70
+ gen.save_as(path)
71
+ xcconfig_file_ref = add_file_to_support_group(path)
72
+
73
+ target.build_configurations.each do |c|
74
+ c.base_configuration_reference = xcconfig_file_ref
75
+ end
76
+ end
77
+ end
78
+
79
+ # Creates a prefix header file which imports `UIKit` or `Cocoa` according
80
+ # to the platform of the target. This file also include any prefix header
81
+ # content reported by the specification of the pods.
82
+ #
83
+ # @return [void]
84
+ #
85
+ def create_prefix_header
86
+ path = library.prefix_header_path
87
+ UI.message "- Generating prefix header at #{UI.path(path)}" do
88
+ generator = Generator::PrefixHeader.new(library.file_accessors, library.platform)
89
+ generator.imports << library.target_environment_header_path.basename
90
+ generator.save_as(path)
91
+ add_file_to_support_group(path)
92
+
93
+ target.build_configurations.each do |c|
94
+ relative_path = path.relative_path_from(sandbox.root)
95
+ c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
96
+ end
97
+ end
98
+ end
99
+
100
+ ENABLE_OBJECT_USE_OBJC_FROM = {
101
+ :ios => Version.new('6'),
102
+ :osx => Version.new('10.8')
103
+ }
104
+
105
+ # Returns the compiler flags for the source files of the given specification.
106
+ #
107
+ # The following behavior is regarding the `OS_OBJECT_USE_OBJC` flag. When
108
+ # set to `0`, it will allow code to use `dispatch_release()` on >= iOS 6.0
109
+ # and OS X 10.8.
110
+ #
111
+ # * New libraries that do *not* require ARC don’t need to care about this
112
+ # issue at all.
113
+ #
114
+ # * New libraries that *do* require ARC _and_ have a deployment target of
115
+ # >= iOS 6.0 or OS X 10.8:
116
+ #
117
+ # These no longer use `dispatch_release()` and should *not* have the
118
+ # `OS_OBJECT_USE_OBJC` flag set to `0`.
119
+ #
120
+ # **Note:** this means that these libraries *have* to specify the
121
+ # deployment target in order to function well.
122
+ #
123
+ # * New libraries that *do* require ARC, but have a deployment target of
124
+ # < iOS 6.0 or OS X 10.8:
125
+ #
126
+ # These contain `dispatch_release()` calls and as such need the
127
+ # `OS_OBJECT_USE_OBJC` flag set to `1`.
128
+ #
129
+ # **Note:** libraries that do *not* specify a platform version are
130
+ # assumed to have a deployment target of < iOS 6.0 or OS X 10.8.
131
+ #
132
+ # For more information, see: http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
133
+ #
134
+ # @param [Specification::Consumer] consumer
135
+ # The consumer for the specification for which the compiler flags
136
+ # are needed.
137
+ #
138
+ # @return [String] The compiler flags.
139
+ #
140
+ def compiler_flags_for_consumer(consumer)
141
+ flags = consumer.compiler_flags.dup
142
+ if consumer.requires_arc
143
+ flags << '-fobjc-arc'
144
+ platform_name = consumer.platform_name
145
+ spec_deployment_target = consumer.spec.deployment_target(platform_name)
146
+ if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name]
147
+ flags << '-DOS_OBJECT_USE_OBJC=0'
148
+ end
149
+ end
150
+ if target_definition.inhibits_warnings_for_pod?(consumer.spec.root.name)
151
+ flags << '-w -Xanalyzer -analyzer-disable-checker'
152
+ end
153
+ flags * " "
154
+ end
155
+
156
+ #-----------------------------------------------------------------------#
157
+
158
+ end
159
+ end
160
+ end
@@ -35,9 +35,9 @@ module Pod
35
35
  #
36
36
  attr_reader :installation_root
37
37
 
38
- # @return [Library] the libraries generated by the installer.
38
+ # @return [Array<Target>] the targets represented in the Podfile.
39
39
  #
40
- attr_reader :libraries
40
+ attr_reader :targets
41
41
 
42
42
  # @param [Podfile] podfile @see #podfile
43
43
  # @param [Sandbox] sandbox @see #sandbox
@@ -46,11 +46,11 @@ module Pod
46
46
  #
47
47
  # @todo Too many initialization arguments
48
48
  #
49
- def initialize(podfile, sandbox, installation_root, libraries)
49
+ def initialize(podfile, sandbox, installation_root, targets)
50
50
  @podfile = podfile
51
51
  @sandbox = sandbox
52
52
  @installation_root = installation_root
53
- @libraries = libraries
53
+ @targets = targets
54
54
  end
55
55
 
56
56
  # Integrates the user projects associated with the {TargetDefinitions}
@@ -110,8 +110,8 @@ module Pod
110
110
  # @return [void]
111
111
  #
112
112
  def integrate_user_targets
113
- libraries_to_integrate.sort_by(&:name).each do |lib|
114
- TargetIntegrator.new(lib).integrate!
113
+ targets_to_integrate.sort_by(&:name).each do |target|
114
+ TargetIntegrator.new(target).integrate!
115
115
  end
116
116
  end
117
117
 
@@ -128,7 +128,7 @@ module Pod
128
128
  #
129
129
  def warn_about_empty_podfile
130
130
  if podfile.target_definitions.values.all?{ |td| td.empty? }
131
- UI.warn "[!] The Podfile does not contain any dependency."
131
+ UI.warn "[!] The Podfile does not contain any dependencies."
132
132
  end
133
133
  end
134
134
 
@@ -163,14 +163,14 @@ module Pod
163
163
  # @note Empty target definitions are ignored.
164
164
  #
165
165
  def user_project_paths
166
- libraries.map do |lib|
167
- lib.user_project_path
166
+ targets.map do |target|
167
+ target.user_project_path
168
168
  end.compact.uniq
169
169
  end
170
170
 
171
171
 
172
- def libraries_to_integrate
173
- libraries.reject { |lib| lib.target_definition.empty? }
172
+ def targets_to_integrate
173
+ targets.reject { |target| target.target_definition.empty? }
174
174
  end
175
175
 
176
176
  #-----------------------------------------------------------------------#
@@ -9,14 +9,14 @@ module Pod
9
9
  #
10
10
  class TargetIntegrator
11
11
 
12
- # @return [Library] the library that should be integrated.
12
+ # @return [Target] the target that should be integrated.
13
13
  #
14
- attr_reader :library
14
+ attr_reader :target
15
15
 
16
- # @param [Library] library @see #target_definition
16
+ # @param [Target] target @see #target_definition
17
17
  #
18
- def initialize(library)
19
- @library = library
18
+ def initialize(target)
19
+ @target = target
20
20
  end
21
21
 
22
22
  # Integrates the user project targets. Only the targets that do **not**
@@ -26,7 +26,7 @@ module Pod
26
26
  # @return [void]
27
27
  #
28
28
  def integrate!
29
- return if targets.empty?
29
+ return if native_targets.empty?
30
30
  UI.section(integration_message) do
31
31
  add_xcconfig_base_configuration
32
32
  add_pods_library
@@ -36,46 +36,50 @@ module Pod
36
36
  end
37
37
  end
38
38
 
39
- # @return [Array<PBXNativeTarget>] the list of targets that the Pods
40
- # lib that need to be integrated.
39
+ # @return [Array<PBXNativeTarget>] the user targets for integration.
41
40
  #
42
- # @note A target is considered integrated if it already references
43
- #
44
- def targets
45
- unless @targets
46
- target_uuids = library.user_target_uuids
47
- targets = target_uuids.map do |uuid|
48
- target = user_project.objects_by_uuid[uuid]
49
- unless target
41
+ def native_targets
42
+ unless @native_targets
43
+ target_uuids = target.user_target_uuids
44
+ native_targets = target_uuids.map do |uuid|
45
+ native_target = user_project.objects_by_uuid[uuid]
46
+ unless native_target
50
47
  raise Informative, "[Bug] Unable to find the target with " \
51
- "the `#{uuid}` UUID for the `#{library}` library"
48
+ "the `#{uuid}` UUID for the `#{target}` integration library"
52
49
  end
53
- target
50
+ native_target
54
51
  end
55
- non_integrated = targets.reject do |target|
56
- target.frameworks_build_phase.files.any? do |build_file|
52
+ non_integrated = native_targets.reject do |native_target|
53
+ native_target.frameworks_build_phase.files.any? do |build_file|
57
54
  file_ref = build_file.file_ref
58
55
  file_ref &&
59
56
  file_ref.isa == 'PBXFileReference' &&
60
- file_ref.display_name == library.product_name
57
+ file_ref.display_name == target.product_name
61
58
  end
62
59
  end
63
- @targets = non_integrated
60
+ @native_targets = non_integrated
64
61
  end
65
- @targets
62
+ @native_targets
66
63
  end
67
64
 
68
65
  # Read the project from the disk to ensure that it is up to date as
69
66
  # other TargetIntegrators might have modified it.
70
67
  #
71
68
  def user_project
72
- @user_project ||= Xcodeproj::Project.new(library.user_project_path)
69
+ @user_project ||= Xcodeproj::Project.new(target.user_project_path)
70
+ end
71
+
72
+ # Read the pods project from the disk to ensure that it is up to date as
73
+ # other TargetIntegrators might have modified it.
74
+ #
75
+ def pods_project
76
+ @pods_project ||= Xcodeproj::Project.new(target.sandbox.project_path)
73
77
  end
74
78
 
75
79
  # @return [String] a string representation suitable for debugging.
76
80
  #
77
81
  def inspect
78
- "#<#{self.class} for target `#{target_definition.label}'>"
82
+ "#<#{self.class} for target `#{target.label}'>"
79
83
  end
80
84
 
81
85
  #---------------------------------------------------------------------#
@@ -84,6 +88,12 @@ module Pod
84
88
 
85
89
  private
86
90
 
91
+ # @return [Specification::Consumer] the consumer for the specifications.
92
+ #
93
+ def spec_consumers
94
+ @spec_consumers ||= target.pod_targets.map(&:file_accessors).flatten.map(&:spec_consumer)
95
+ end
96
+
87
97
  # Adds the `xcconfig` configurations files generated for the current
88
98
  # {TargetDefinition} to the build configurations of the targets that
89
99
  # should be integrated.
@@ -98,25 +108,31 @@ module Pod
98
108
  # @return [void]
99
109
  #
100
110
  def add_xcconfig_base_configuration
101
- xcconfig = user_project.new_file(library.xcconfig_relative_path)
102
- targets.each do |target|
103
- check_overridden_build_settings(library.xcconfig, target)
104
- target.build_configurations.each do |config|
111
+ xcconfig = user_project.files.select { |f| f.path == target.xcconfig_relative_path }.first ||
112
+ user_project.new_file(target.xcconfig_relative_path)
113
+ native_targets.each do |native_target|
114
+ check_overridden_build_settings(target.xcconfig, native_target)
115
+ native_target.build_configurations.each do |config|
105
116
  config.base_configuration_reference = xcconfig
106
117
  end
107
118
  end
108
119
  end
109
120
 
110
- # Adds a file reference to the library of the {TargetDefinition} and
111
- # adds it to the frameworks build phase of the targets.
121
+ # Adds spec libraries to the frameworks build phase of the
122
+ # {TargetDefinition} integration libraries. Adds a file reference to
123
+ # the library of the {TargetDefinition} and adds it to the frameworks
124
+ # build phase of the targets.
112
125
  #
113
126
  # @return [void]
114
127
  #
115
128
  def add_pods_library
116
129
  frameworks = user_project.frameworks_group
117
- pods_library = frameworks.new_static_library(library.label)
118
- targets.each do |target|
119
- target.frameworks_build_phase.add_file_reference(pods_library)
130
+ native_targets.each do |native_target|
131
+ library = frameworks.files.select { |f| f.path == target.product_name }.first ||
132
+ frameworks.new_static_library(target.name)
133
+ unless native_target.frameworks_build_phase.files_references.include?(library)
134
+ native_target.frameworks_build_phase.add_file_reference(library)
135
+ end
120
136
  end
121
137
  end
122
138
 
@@ -127,9 +143,11 @@ module Pod
127
143
  # @return [void]
128
144
  #
129
145
  def add_copy_resources_script_phase
130
- targets.each do |target|
131
- phase = target.new_shell_script_build_phase('Copy Pods Resources')
132
- path = library.copy_resources_script_relative_path
146
+ phase_name = "Copy Pods Resources"
147
+ native_targets.each do |native_target|
148
+ phase = native_target.shell_script_build_phases.select { |bp| bp.name == phase_name }.first ||
149
+ native_target.new_shell_script_build_phase(phase_name)
150
+ path = target.copy_resources_script_relative_path
133
151
  phase.shell_script = %{"#{path}"\n}
134
152
  end
135
153
  end
@@ -144,10 +162,12 @@ module Pod
144
162
  # @return [void]
145
163
  #
146
164
  def add_check_manifest_lock_script_phase
147
- targets.each do |target|
148
- phase = target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
149
- target.build_phases.unshift(phase)
150
- phase.name = 'Check Pods Manifest.lock'
165
+ phase_name = 'Check Pods Manifest.lock'
166
+ native_targets.each do |native_target|
167
+ next if native_target.shell_script_build_phases.any? { |phase| phase.name == phase_name }
168
+ phase = native_target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
169
+ native_target.build_phases.unshift(phase)
170
+ phase.name = phase_name
151
171
  phase.shell_script = <<-EOS.strip_heredoc
152
172
  diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
153
173
  if [[ $? != 0 ]] ; then
@@ -165,7 +185,7 @@ module Pod
165
185
  # @return [void]
166
186
  #
167
187
  def save_user_project
168
- user_project.save_as(library.user_project_path)
188
+ user_project.save_as(target.user_project_path)
169
189
  end
170
190
 
171
191
  #---------------------------------------------------------------------#
@@ -179,11 +199,11 @@ module Pod
179
199
  #
180
200
  # @return [void]
181
201
  #
182
- def check_overridden_build_settings(xcconfig, target)
202
+ def check_overridden_build_settings(xcconfig, native_target)
183
203
  return unless xcconfig
184
204
 
185
205
  configs_by_overridden_key = {}
186
- target.build_configurations.each do |config|
206
+ native_target.build_configurations.each do |config|
187
207
  xcconfig.attributes.keys.each do |key|
188
208
  target_value = config.build_settings[key]
189
209
 
@@ -194,13 +214,13 @@ module Pod
194
214
  end
195
215
 
196
216
  configs_by_overridden_key.each do |key, config_names|
197
- name = "#{target.name} [#{config_names.join(' - ')}]"
217
+ name = "#{native_target.name} [#{config_names.join(' - ')}]"
198
218
  actions = [
199
219
  "Use the `$(inherited)` flag, or",
200
220
  "Remove the build settings from the target."
201
221
  ]
202
222
  UI.warn("The target `#{name}` overrides the `#{key}` build " \
203
- "setting defined in `#{library.xcconfig_relative_path}'.",
223
+ "setting defined in `#{target.xcconfig_relative_path}'.",
204
224
  actions)
205
225
  end
206
226
  end
@@ -210,10 +230,10 @@ module Pod
210
230
  # integration.
211
231
  #
212
232
  def integration_message
213
- "Integrating `#{library.product_name}` into " \
214
- "#{'target'.pluralize(targets.size)} " \
215
- "`#{targets.map(&:name).to_sentence}` " \
216
- "of project #{UI.path library.user_project_path}."
233
+ "Integrating Pod #{'target'.pluralize(target.pod_targets.size)} " \
234
+ "`#{target.pod_targets.map(&:name).to_sentence}` " \
235
+ "into aggregate target #{target.name} " \
236
+ "of project #{UI.path target.user_project_path}."
217
237
  end
218
238
 
219
239
  #---------------------------------------------------------------------#