cocoapods 0.35.0 → 0.36.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +185 -6
  3. data/README.md +1 -1
  4. data/lib/cocoapods.rb +4 -0
  5. data/lib/cocoapods/command.rb +2 -2
  6. data/lib/cocoapods/command/inter_process_communication.rb +1 -1
  7. data/lib/cocoapods/command/lib.rb +3 -0
  8. data/lib/cocoapods/command/list.rb +0 -35
  9. data/lib/cocoapods/command/search.rb +1 -2
  10. data/lib/cocoapods/command/spec.rb +6 -3
  11. data/lib/cocoapods/config.rb +1 -20
  12. data/lib/cocoapods/external_sources/abstract_external_source.rb +4 -0
  13. data/lib/cocoapods/gem_version.rb +1 -1
  14. data/lib/cocoapods/generator/embed_frameworks_script.rb +107 -0
  15. data/lib/cocoapods/generator/header.rb +13 -1
  16. data/lib/cocoapods/generator/info_plist_file.rb +84 -0
  17. data/lib/cocoapods/generator/module_map.rb +49 -0
  18. data/lib/cocoapods/generator/umbrella_header.rb +44 -0
  19. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +69 -23
  20. data/lib/cocoapods/generator/xcconfig/private_pod_xcconfig.rb +12 -0
  21. data/lib/cocoapods/generator/xcconfig/public_pod_xcconfig.rb +1 -9
  22. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +79 -1
  23. data/lib/cocoapods/hooks_manager.rb +75 -13
  24. data/lib/cocoapods/installer.rb +59 -2
  25. data/lib/cocoapods/installer/analyzer.rb +115 -38
  26. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +6 -1
  27. data/lib/cocoapods/installer/file_references_installer.rb +11 -5
  28. data/lib/cocoapods/installer/migrator.rb +9 -0
  29. data/lib/cocoapods/installer/target_installer.rb +89 -5
  30. data/lib/cocoapods/installer/target_installer/aggregate_target_installer.rb +49 -5
  31. data/lib/cocoapods/installer/target_installer/pod_target_installer.rb +57 -9
  32. data/lib/cocoapods/installer/user_project_integrator.rb +3 -2
  33. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +67 -6
  34. data/lib/cocoapods/project.rb +18 -2
  35. data/lib/cocoapods/resolver.rb +2 -2
  36. data/lib/cocoapods/sandbox/file_accessor.rb +23 -3
  37. data/lib/cocoapods/sandbox/headers_store.rb +4 -0
  38. data/lib/cocoapods/sources_manager.rb +5 -1
  39. data/lib/cocoapods/target.rb +117 -1
  40. data/lib/cocoapods/target/aggregate_target.rb +46 -4
  41. data/lib/cocoapods/target/pod_target.rb +39 -1
  42. data/lib/cocoapods/user_interface.rb +16 -21
  43. data/lib/cocoapods/user_interface/error_report.rb +2 -2
  44. data/lib/cocoapods/validator.rb +68 -23
  45. metadata +23 -19
@@ -12,8 +12,14 @@ module Pod
12
12
  UI.message "- Installing target `#{target.name}` #{target.platform}" do
13
13
  add_target
14
14
  create_support_files_dir
15
- create_suport_files_group
15
+ create_support_files_group
16
16
  create_xcconfig_file
17
+ if target.requires_frameworks?
18
+ create_info_plist_file
19
+ create_module_map
20
+ create_umbrella_header
21
+ create_embed_frameworks_script
22
+ end
17
23
  create_target_environment_header
18
24
  create_bridge_support_file
19
25
  create_copy_resources_script
@@ -26,12 +32,25 @@ module Pod
26
32
 
27
33
  private
28
34
 
35
+ # Ensure that vendored static frameworks and libraries are not linked
36
+ # twice to the aggregate target, which shares the xcconfig of the user
37
+ # target.
38
+ #
39
+ def custom_build_settings
40
+ settings = {
41
+ 'OTHER_LDFLAGS' => '',
42
+ 'OTHER_LIBTOOLFLAGS' => '',
43
+ 'PODS_ROOT' => '$(SRCROOT)',
44
+ }
45
+ super.merge(settings)
46
+ end
47
+
29
48
  # Creates the group that holds the references to the support files
30
49
  # generated by this installer.
31
50
  #
32
51
  # @return [void]
33
52
  #
34
- def create_suport_files_group
53
+ def create_support_files_group
35
54
  parent = project.support_files_group
36
55
  name = target.name
37
56
  dir = target.support_files_dir
@@ -92,9 +111,12 @@ module Pod
92
111
  #
93
112
  def create_copy_resources_script
94
113
  path = target.copy_resources_script_path
95
- file_accessors = target.pod_targets.map(&:file_accessors).flatten
96
- resource_paths = file_accessors.map { |accessor| accessor.resources.flatten.map { |res| res.relative_path_from(project.path.dirname) } }.flatten
97
- resource_bundles = file_accessors.map { |accessor| accessor.resource_bundles.keys.map { |name| "${BUILT_PRODUCTS_DIR}/#{name}.bundle" } }.flatten
114
+ library_targets = target.pod_targets.reject do |pod_target|
115
+ pod_target.should_build? && pod_target.requires_frameworks?
116
+ end
117
+ file_accessors = library_targets.flat_map(&:file_accessors)
118
+ resource_paths = file_accessors.flat_map { |accessor| accessor.resources.flat_map { |res| res.relative_path_from(project.path.dirname) } }
119
+ resource_bundles = file_accessors.flat_map { |accessor| accessor.resource_bundles.keys.map { |name| "${BUILT_PRODUCTS_DIR}/#{name}.bundle" } }
98
120
  resources = []
99
121
  resources.concat(resource_paths)
100
122
  resources.concat(resource_bundles)
@@ -104,6 +126,28 @@ module Pod
104
126
  add_file_to_support_group(path)
105
127
  end
106
128
 
129
+ # Creates a script that embeds the frameworks to the bundle of the client
130
+ # target.
131
+ #
132
+ # @note We can't use Xcode default copy bundle resource phase, because
133
+ # we need to ensure that we only copy the resources, which are
134
+ # relevant for the current build configuration.
135
+ #
136
+ # @return [void]
137
+ #
138
+ def create_embed_frameworks_script
139
+ path = target.embed_frameworks_script_path
140
+ frameworks_by_config = {}
141
+ target.user_build_configurations.keys.each do |config|
142
+ frameworks_by_config[config] = target.pod_targets.select do |pod_target|
143
+ pod_target.include_in_build_config?(config) && pod_target.should_build?
144
+ end.map(&:product_name)
145
+ end
146
+ generator = Generator::EmbedFrameworksScript.new(target_definition, frameworks_by_config)
147
+ generator.save_as(path)
148
+ add_file_to_support_group(path)
149
+ end
150
+
107
151
  # Generates the acknowledgement files (markdown and plist) for the target.
108
152
  #
109
153
  # @return [void]
@@ -9,12 +9,24 @@ module Pod
9
9
  # @return [void]
10
10
  #
11
11
  def install!
12
+ unless target.should_build?
13
+ add_resources_bundle_targets
14
+ return
15
+ end
16
+
12
17
  UI.message "- Installing target `#{target.name}` #{target.platform}" do
13
18
  add_target
14
19
  create_support_files_dir
15
- add_files_to_build_phases
16
20
  add_resources_bundle_targets
21
+ add_files_to_build_phases
17
22
  create_xcconfig_file
23
+ if target.requires_frameworks?
24
+ create_info_plist_file
25
+ create_module_map
26
+ create_umbrella_header do |generator|
27
+ generator.imports += target.file_accessors.flat_map(&:public_headers).map(&:basename)
28
+ end
29
+ end
18
30
  create_prefix_header
19
31
  create_dummy_source
20
32
  end
@@ -36,20 +48,41 @@ module Pod
36
48
  target.file_accessors.each do |file_accessor|
37
49
  consumer = file_accessor.spec_consumer
38
50
 
51
+ headers = file_accessor.headers
52
+ public_headers = file_accessor.public_headers
39
53
  other_source_files = file_accessor.source_files.select { |sf| sf.extname == '.d' }
40
54
 
41
55
  {
42
56
  true => file_accessor.arc_source_files,
43
57
  false => file_accessor.non_arc_source_files,
44
58
  }.each do |arc, files|
45
- files = files - other_source_files
59
+ files = files - headers - other_source_files
46
60
  flags = compiler_flags_for_consumer(consumer, arc)
47
61
  regular_file_refs = files.map { |sf| project.reference_for_path(sf) }
48
62
  native_target.add_file_references(regular_file_refs, flags)
49
63
  end
50
64
 
65
+ header_file_refs = headers.map { |sf| project.reference_for_path(sf) }
66
+ native_target.add_file_references(header_file_refs) do |build_file|
67
+ # Set added headers as public if needed
68
+ if target.requires_frameworks?
69
+ if public_headers.include?(build_file.file_ref.real_path)
70
+ build_file.settings ||= {}
71
+ build_file.settings['ATTRIBUTES'] = ['Public']
72
+ end
73
+ end
74
+ end
75
+
51
76
  other_file_refs = other_source_files.map { |sf| project.reference_for_path(sf) }
52
77
  native_target.add_file_references(other_file_refs, nil)
78
+
79
+ next unless target.requires_frameworks?
80
+
81
+ resource_refs = file_accessor.resources.flatten.map do |res|
82
+ project.reference_for_path(res)
83
+ end
84
+
85
+ native_target.add_resources(resource_refs)
53
86
  end
54
87
  end
55
88
 
@@ -63,20 +96,35 @@ module Pod
63
96
  def add_resources_bundle_targets
64
97
  target.file_accessors.each do |file_accessor|
65
98
  file_accessor.resource_bundles.each do |bundle_name, paths|
66
- # Add a dependency on an existing Resource Bundle target if possible
67
- if bundle_target = project.targets.find { |target| target.name == bundle_name }
68
- native_target.add_dependency(bundle_target)
69
- next
70
- end
71
99
  file_references = paths.map { |sf| project.reference_for_path(sf) }
72
- bundle_target = project.new_resources_bundle(bundle_name, file_accessor.spec_consumer.platform_name)
100
+ label = target.resources_bundle_target_label(bundle_name)
101
+ bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
102
+ bundle_target.product_reference.tap do |bundle_product|
103
+ bundle_file_name = "#{bundle_name}.bundle"
104
+ bundle_product.name = bundle_file_name
105
+ bundle_product.path = bundle_file_name
106
+ end
73
107
  bundle_target.add_resources(file_references)
74
108
 
75
109
  target.user_build_configurations.each do |bc_name, type|
76
110
  bundle_target.add_build_configuration(bc_name, type)
77
111
  end
78
112
 
79
- native_target.add_dependency(bundle_target)
113
+ target.resource_bundle_targets << bundle_target
114
+
115
+ if target.should_build?
116
+ native_target.add_dependency(bundle_target)
117
+ if target.requires_frameworks?
118
+ native_target.add_resources([bundle_target.product_reference])
119
+ end
120
+ end
121
+
122
+ bundle_target.build_configurations.each do |c|
123
+ c.build_settings['PRODUCT_NAME'] = bundle_name
124
+ if target.requires_frameworks?
125
+ c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir
126
+ end
127
+ end
80
128
  end
81
129
  end
82
130
  end
@@ -132,7 +132,8 @@ module Pod
132
132
  end
133
133
  end
134
134
 
135
- INHERITED_FLAGS = ['$(inherited)', '${inherited}']
135
+ IGNORED_KEYS = %w(CODE_SIGN_IDENTITY).freeze
136
+ INHERITED_FLAGS = %w($(inherited) ${inherited}).freeze
136
137
 
137
138
  # Checks whether the settings of the CocoaPods generated xcconfig are
138
139
  # overridden by the build configuration of a target and prints a
@@ -144,7 +145,7 @@ module Pod
144
145
  user_target.build_configurations.each do |config|
145
146
  xcconfig = aggregate_target.xcconfigs[config.name]
146
147
  if xcconfig
147
- xcconfig.to_hash.keys.each do |key|
148
+ (xcconfig.to_hash.keys - IGNORED_KEYS).each do |key|
148
149
  target_values = config.build_settings[key]
149
150
  if target_values &&
150
151
  !INHERITED_FLAGS.any? { |flag| target_values.include?(flag) }
@@ -31,8 +31,10 @@ module Pod
31
31
  project_is_dirty = [
32
32
  XCConfigIntegrator.integrate(target, native_targets),
33
33
  update_to_cocoapods_0_34,
34
+ remove_embed_frameworks_script_phases,
34
35
  unless native_targets_to_integrate.empty?
35
36
  add_pods_library
37
+ add_embed_frameworks_script_phase if target.requires_frameworks?
36
38
  add_copy_resources_script_phase
37
39
  add_check_manifest_lock_script_phase
38
40
  true
@@ -91,9 +93,9 @@ module Pod
91
93
  changes
92
94
  end
93
95
 
94
- # Adds spec libraries to the frameworks build phase of the
96
+ # Adds spec product reference to the frameworks build phase of the
95
97
  # {TargetDefinition} integration libraries. Adds a file reference to
96
- # the library of the {TargetDefinition} and adds it to the frameworks
98
+ # the frameworks group of the project and adds it to the frameworks
97
99
  # build phase of the targets.
98
100
  #
99
101
  # @return [void]
@@ -101,12 +103,71 @@ module Pod
101
103
  def add_pods_library
102
104
  frameworks = user_project.frameworks_group
103
105
  native_targets_to_integrate.each do |native_target|
104
- library = frameworks.files.select { |f| f.path == target.product_name }.first ||
105
- frameworks.new_product_ref_for_target(target.name, :static_library)
106
- unless native_target.frameworks_build_phase.files_references.include?(library)
107
- native_target.frameworks_build_phase.add_file_reference(library)
106
+ build_phase = native_target.frameworks_build_phase
107
+
108
+ # Find and delete possible reference for the other product type
109
+ old_product_name = target.requires_frameworks? ? target.static_library_name : target.framework_name
110
+ old_product_ref = frameworks.files.find { |f| f.path == old_product_name }
111
+ if old_product_ref.present?
112
+ UI.message("Removing old Pod product reference #{old_product_name} from project.")
113
+ build_phase.remove_file_reference(old_product_ref)
114
+ frameworks.remove_reference(old_product_ref)
115
+ end
116
+
117
+ # Find or create and add a reference for the current product type
118
+ target_basename = target.product_basename
119
+ new_product_ref = frameworks.files.find { |f| f.path == target.product_name } ||
120
+ frameworks.new_product_ref_for_target(target_basename, target.product_type)
121
+ build_file = build_phase.build_file(new_product_ref) ||
122
+ build_phase.add_file_reference(new_product_ref)
123
+ if target.requires_frameworks?
124
+ # Weak link the aggregate target's product, because as it contains
125
+ # no symbols, it isn't copied into the app bundle. dyld will so
126
+ # never try to find the missing executable at runtime.
127
+ build_file.settings ||= {}
128
+ build_file.settings['ATTRIBUTES'] = ['Weak']
129
+ end
130
+ end
131
+ end
132
+
133
+ # Find or create a 'Embed Pods Frameworks' Copy Files Build Phase
134
+ #
135
+ # @return [void]
136
+ #
137
+ def add_embed_frameworks_script_phase
138
+ phase_name = 'Embed Pods Frameworks'
139
+ native_targets_to_integrate.each do |native_target|
140
+ embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name == phase_name }
141
+ unless embed_build_phase.present?
142
+ UI.message("Adding Build Phase '#{phase_name}' to project.")
143
+ embed_build_phase = native_target.new_shell_script_build_phase(phase_name)
108
144
  end
145
+ script_path = target.embed_frameworks_script_relative_path
146
+ embed_build_phase.shell_script = %("#{script_path}"\n)
147
+ embed_build_phase.show_env_vars_in_log = '0'
148
+ end
149
+ end
150
+
151
+ # Delete 'Embed Pods Frameworks' Build Phases, if they exist
152
+ # and are not needed anymore due to not integrating the
153
+ # dependencies by frameworks.
154
+ #
155
+ # @return [Bool] whether any changes to the project were made.
156
+ #
157
+ def remove_embed_frameworks_script_phases
158
+ return false if target.requires_frameworks?
159
+
160
+ phase_name = 'Embed Pods Frameworks'
161
+ result = false
162
+
163
+ native_targets.each do |native_target|
164
+ embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name == phase_name }
165
+ next unless embed_build_phase.present?
166
+ native_target.build_phases.delete(embed_build_phase)
167
+ result = true
109
168
  end
169
+
170
+ result
110
171
  end
111
172
 
112
173
  # Adds a shell script build phase responsible to copy the resources
@@ -59,6 +59,7 @@ module Pod
59
59
 
60
60
  parent_group = development ? development_pods : pods
61
61
  source_tree = absolute ? :absolute : :group
62
+
62
63
  group = parent_group.new_group(pod_name, path, source_tree)
63
64
  group
64
65
  end
@@ -144,13 +145,28 @@ module Pod
144
145
  # @param [PBXGroup] group
145
146
  # The group for the new file reference.
146
147
  #
148
+ # @param [Bool] reflect_file_system_structure
149
+ # Wether group structure should reflect the file system structure.
150
+ # If yes, where needed, intermediate groups are created, similar to
151
+ # how mkdir -p operates.
152
+ #
147
153
  # @return [PBXFileReference] The new file reference.
148
154
  #
149
- def add_file_reference(absolute_path, group)
150
- unless Pathname.new(absolute_path).absolute?
155
+ def add_file_reference(absolute_path, group, reflect_file_system_structure = false)
156
+ file_path_name = Pathname.new(absolute_path)
157
+ unless file_path_name.absolute?
151
158
  raise ArgumentError, "Paths must be absolute #{absolute_path}"
152
159
  end
153
160
 
161
+ if reflect_file_system_structure
162
+ relative_path = file_path_name.relative_path_from(group.real_path)
163
+ relative_dir = relative_path.dirname
164
+ relative_dir.each_filename do|name|
165
+ next if name == '.'
166
+ group = group[name] || group.new_group(name, name)
167
+ end
168
+ end
169
+
154
170
  if ref = reference_for_path(absolute_path)
155
171
  ref
156
172
  else
@@ -50,7 +50,7 @@ module Pod
50
50
  # definition.
51
51
  #
52
52
  def resolve
53
- dependencies = @podfile.target_definition_list.map(&:dependencies).flatten
53
+ dependencies = podfile.target_definition_list.map(&:dependencies).flatten
54
54
  @cached_sets = {}
55
55
  @activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
56
56
  specs_by_target
@@ -78,7 +78,6 @@ module Pod
78
78
  uniq.
79
79
  sort_by(&:name).
80
80
  each do |spec|
81
- validate_platform(spec, target)
82
81
  sandbox.store_head_pod(spec.name) if spec.version.head?
83
82
  end
84
83
  end
@@ -408,6 +407,7 @@ module Pod
408
407
  # dependencies for `target`.
409
408
  #
410
409
  def valid_dependencies_for_target_from_node(target, node)
410
+ validate_platform(node.payload, target)
411
411
  dependency_nodes = node.outgoing_edges.select do |edge|
412
412
  edge_is_valid_for_target?(edge, target)
413
413
  end.map(&:destination)
@@ -12,7 +12,7 @@ module Pod
12
12
  GLOB_PATTERNS = {
13
13
  :readme => 'readme{*,.*}'.freeze,
14
14
  :license => 'licen{c,s}e{*,.*}'.freeze,
15
- :source_files => '*.{h,hpp,hh,m,mm,c,cpp}'.freeze,
15
+ :source_files => '*.{h,hpp,hh,m,mm,c,cpp,swift}'.freeze,
16
16
  :public_header_files => "*{#{HEADER_EXTENSIONS.join(',')}}".freeze,
17
17
  }.freeze
18
18
 
@@ -113,8 +113,8 @@ module Pod
113
113
  # @return [Array<Pathname>] the public headers of the specification.
114
114
  #
115
115
  def public_headers(include_frameworks = false)
116
- public_headers = paths_for_attribute(:public_header_files)
117
- private_headers = paths_for_attribute(:private_header_files)
116
+ public_headers = public_header_files
117
+ private_headers = private_header_files
118
118
  if public_headers.nil? || public_headers.empty?
119
119
  header_files = headers
120
120
  else
@@ -210,6 +210,26 @@ module Pod
210
210
 
211
211
  private
212
212
 
213
+ # @!group Private paths
214
+
215
+ # @return [Array<Pathname>] The paths of the user-specified public header
216
+ # files.
217
+ #
218
+ def public_header_files
219
+ paths_for_attribute(:public_header_files)
220
+ end
221
+
222
+ # @return [Array<Pathname>] The paths of the user-specified public header
223
+ # files.
224
+ #
225
+ def private_header_files
226
+ paths_for_attribute(:private_header_files)
227
+ end
228
+
229
+ #-----------------------------------------------------------------------#
230
+
231
+ private
232
+
213
233
  # @!group Private helpers
214
234
 
215
235
  # Returns the list of the paths founds in the file system for the
@@ -26,6 +26,10 @@ module Pod
26
26
  @search_paths = []
27
27
  end
28
28
 
29
+ # @param [Platform] platform
30
+ # the platform for which the header search paths should be
31
+ # returned
32
+ #
29
33
  # @return [Array<String>] All the search paths of the header directory in
30
34
  # xcconfig format. The paths are specified relative to the pods
31
35
  # root with the `${PODS_ROOT}` variable.
@@ -9,6 +9,7 @@ module Pod
9
9
  # known Pods.
10
10
  #
11
11
  def aggregate
12
+ return Source::Aggregate.new([]) unless config.repos_dir.exist?
12
13
  dirs = config.repos_dir.children.select(&:directory?)
13
14
  Source::Aggregate.new(dirs)
14
15
  end
@@ -60,6 +61,7 @@ module Pod
60
61
  # installation of CocoaPods.
61
62
  #
62
63
  def all
64
+ return [] unless config.repos_dir.exist?
63
65
  dirs = config.repos_dir.children.select(&:directory?)
64
66
  dirs.map { |repo| Source.new(repo) }
65
67
  end
@@ -393,7 +395,9 @@ module Pod
393
395
  #
394
396
  def source_with_url(url)
395
397
  url = url.downcase.gsub(/.git$/, '')
396
- aggregate.sources.find { |s| s.url.downcase.gsub(/.git$/, '') == url }
398
+ aggregate.sources.find do |source|
399
+ source.url && source.url.downcase.gsub(/.git$/, '') == url
400
+ end
397
401
  end
398
402
 
399
403
  # Returns a suitable repository name for `url`.