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
@@ -89,6 +89,7 @@ module Pod
89
89
  prepare
90
90
  resolve_dependencies
91
91
  download_dependencies
92
+ determine_dependency_product_types
92
93
  generate_pods_project
93
94
  integrate_user_project if config.integrate_targets?
94
95
  perform_post_install_actions
@@ -97,6 +98,7 @@ module Pod
97
98
  def prepare
98
99
  UI.message 'Preparing' do
99
100
  sandbox.prepare
101
+ ensure_plugins_are_installed!
100
102
  Migrator.migrate(sandbox)
101
103
  end
102
104
  end
@@ -310,6 +312,21 @@ module Pod
310
312
  @pod_installers.each(&:clean!)
311
313
  end
312
314
 
315
+ # Determines if the dependencies need to be built as dynamic frameworks or
316
+ # if they can be built as static libraries by checking for the Swift source
317
+ # presence. Therefore it is important that the file accessors of the
318
+ # #pod_targets are created.
319
+ #
320
+ # @return [void]
321
+ #
322
+ def determine_dependency_product_types
323
+ aggregate_targets.each do |aggregate_target|
324
+ aggregate_target.pod_targets.each do |pod_target|
325
+ pod_target.host_requires_frameworks = aggregate_target.requires_frameworks?
326
+ end
327
+ end
328
+ end
329
+
313
330
  # Performs any post-installation actions
314
331
  #
315
332
  # @return [void]
@@ -323,7 +340,23 @@ module Pod
323
340
  #
324
341
  def run_plugins_post_install_hooks
325
342
  context = HooksContext.generate(sandbox, aggregate_targets)
326
- HooksManager.run(:post_install, context)
343
+ HooksManager.run(:post_install, context, podfile.plugins)
344
+ end
345
+
346
+ # Ensures that all plugins specified in the {#podfile} are loaded.
347
+ #
348
+ # @return [void]
349
+ #
350
+ def ensure_plugins_are_installed!
351
+ require 'claide/command/plugin_manager'
352
+
353
+ loaded_plugins = Command::PluginManager.specifications.map(&:name)
354
+
355
+ podfile.plugins.keys.each do |plugin|
356
+ unless loaded_plugins.include? plugin
357
+ raise Informative, "Your Podfile requires that the plugin `#{plugin}` be installed. Please install it and try installation again."
358
+ end
359
+ end
327
360
  end
328
361
 
329
362
  # Prints a warning for any pods that are deprecated
@@ -418,16 +451,32 @@ module Pod
418
451
  pod_targets.sort_by(&:name).each do |pod_target|
419
452
  pod_target.file_accessors.each do |file_accessor|
420
453
  file_accessor.spec_consumer.frameworks.each do |framework|
421
- pod_target.native_target.add_system_framework(framework)
454
+ if pod_target.should_build?
455
+ pod_target.native_target.add_system_framework(framework)
456
+ end
422
457
  end
423
458
  end
424
459
  end
425
460
  end
426
461
  end
427
462
 
463
+ # Adds a target dependency for each pod spec to each aggregate target and
464
+ # links the pod targets among each other.
465
+ #
466
+ # @return [void]
467
+ #
428
468
  def set_target_dependencies
469
+ frameworks_group = pods_project.frameworks_group
429
470
  aggregate_targets.each do |aggregate_target|
430
471
  aggregate_target.pod_targets.each do |pod_target|
472
+ unless pod_target.should_build?
473
+ pod_target.resource_bundle_targets.each do |resource_bundle_target|
474
+ aggregate_target.native_target.add_dependency(resource_bundle_target)
475
+ end
476
+
477
+ next
478
+ end
479
+
431
480
  aggregate_target.native_target.add_dependency(pod_target.native_target)
432
481
  pod_target.dependencies.each do |dep|
433
482
 
@@ -437,7 +486,15 @@ module Pod
437
486
  unless pod_dependency_target
438
487
  puts "[BUG] DEP: #{dep}"
439
488
  end
489
+
490
+ next unless pod_dependency_target.should_build?
440
491
  pod_target.native_target.add_dependency(pod_dependency_target.native_target)
492
+
493
+ if pod_target.requires_frameworks?
494
+ product_ref = frameworks_group.files.find { |f| f.path == pod_dependency_target.product_name } ||
495
+ frameworks_group.new_product_ref_for_target(pod_dependency_target.product_basename, pod_dependency_target.product_type)
496
+ pod_target.native_target.frameworks_build_phase.add_file_reference(product_ref)
497
+ end
441
498
  end
442
499
  end
443
500
  end
@@ -180,47 +180,92 @@ module Pod
180
180
  def generate_targets
181
181
  targets = []
182
182
  result.specs_by_target.each do |target_definition, specs|
183
- target = AggregateTarget.new(target_definition, sandbox)
184
- targets << target
185
-
186
- if config.integrate_targets?
187
- project_path = compute_user_project_path(target_definition)
188
- user_project = Xcodeproj::Project.open(project_path)
189
- native_targets = compute_user_project_targets(target_definition, user_project)
190
-
191
- target.user_project_path = project_path
192
- target.client_root = project_path.dirname
193
- target.user_target_uuids = native_targets.map(&:uuid)
194
- target.user_build_configurations = compute_user_build_configurations(target_definition, native_targets)
195
- target.archs = @archs_by_target_def[target_definition]
196
- else
197
- target.client_root = config.installation_root
198
- target.user_target_uuids = []
199
- target.user_build_configurations = target_definition.build_configurations || {}
200
- if target_definition.platform.name == :osx
201
- target.archs = '$(ARCHS_STANDARD_64_BIT)'
202
- end
183
+ targets << generate_target(target_definition, specs)
184
+ end
185
+ targets
186
+ end
187
+
188
+ # Setup the aggregate target for a single user target
189
+ #
190
+ # @param [TargetDefinition] target_definition
191
+ # the target definition for the user target.
192
+ #
193
+ # @param [Array<Specification>] specs
194
+ # the specifications that need to be installed grouped by the
195
+ # given target definition.
196
+ #
197
+ # @return [AggregateTarget]
198
+ #
199
+ def generate_target(target_definition, specs)
200
+ target = AggregateTarget.new(target_definition, sandbox)
201
+ target.host_requires_frameworks |= target_definition.uses_frameworks?
202
+
203
+ if config.integrate_targets?
204
+ project_path = compute_user_project_path(target_definition)
205
+ user_project = Xcodeproj::Project.open(project_path)
206
+ native_targets = compute_user_project_targets(target_definition, user_project)
207
+
208
+ target.user_project_path = project_path
209
+ target.client_root = project_path.dirname
210
+ target.user_target_uuids = native_targets.map(&:uuid)
211
+ target.user_build_configurations = compute_user_build_configurations(target_definition, native_targets)
212
+ target.archs = @archs_by_target_def[target_definition]
213
+ else
214
+ target.client_root = config.installation_root
215
+ target.user_target_uuids = []
216
+ target.user_build_configurations = target_definition.build_configurations || { 'Release' => :release, 'Debug' => :debug }
217
+ if target_definition.platform.name == :osx
218
+ target.archs = '$(ARCHS_STANDARD_64_BIT)'
203
219
  end
220
+ end
204
221
 
205
- grouped_specs = specs.map do |spec|
206
- specs.select { |s| s.root == spec.root }
207
- end.uniq
222
+ target.pod_targets = generate_pod_targets(target, specs)
208
223
 
209
- grouped_specs.each do |pod_specs|
210
- pod_target = PodTarget.new(pod_specs, target_definition, sandbox)
211
- if config.integrate_targets?
212
- pod_target.user_build_configurations = target.user_build_configurations
213
- pod_target.archs = @archs_by_target_def[target_definition]
214
- else
215
- pod_target.user_build_configurations = {}
216
- if target_definition.platform.name == :osx
217
- pod_target.archs = '$(ARCHS_STANDARD_64_BIT)'
218
- end
219
- end
220
- target.pod_targets << pod_target
224
+ target
225
+ end
226
+
227
+ # Setup the pod targets for an aggregate target. Group specs and subspecs
228
+ # by their root to create a {PodTarget} for each spec.
229
+ #
230
+ # @param [AggregateTarget] target
231
+ # the aggregate target
232
+ #
233
+ # @param [Array<Specification>] specs
234
+ # the specifications that need to be installed.
235
+ #
236
+ # @return [Array<PodTarget>]
237
+ #
238
+ def generate_pod_targets(target, specs)
239
+ grouped_specs = specs.group_by(&:root).values.uniq
240
+ grouped_specs.map do |pod_specs|
241
+ generate_pod_target(target, pod_specs)
242
+ end
243
+ end
244
+
245
+ # Create a target for each spec group and add it to the aggregate target
246
+ #
247
+ # @param [AggregateTarget] target
248
+ # the aggregate target
249
+ #
250
+ # @param [Array<Specification>] specs
251
+ # the specifications of an equal root.
252
+ #
253
+ # @return [PodTarget]
254
+ #
255
+ def generate_pod_target(target, pod_specs)
256
+ pod_target = PodTarget.new(pod_specs, target.target_definition, sandbox)
257
+
258
+ if config.integrate_targets?
259
+ pod_target.user_build_configurations = target.user_build_configurations
260
+ pod_target.archs = @archs_by_target_def[target.target_definition]
261
+ else
262
+ pod_target.user_build_configurations = {}
263
+ if target.platform.name == :osx
264
+ pod_target.archs = '$(ARCHS_STANDARD_64_BIT)'
221
265
  end
222
266
  end
223
- targets
267
+
268
+ pod_target
224
269
  end
225
270
 
226
271
  # Generates dependencies that require the specific version of the Pods
@@ -331,6 +376,8 @@ module Pod
331
376
  pods_to_fetch = result.podfile_state.added + result.podfile_state.changed
332
377
  if update_mode == :selected
333
378
  pods_to_fetch += update[:pods]
379
+ elsif update_mode == :all
380
+ pods_to_fetch += result.podfile_state.unchanged + result.podfile_state.deleted
334
381
  end
335
382
  pods_to_fetch
336
383
  end
@@ -462,9 +509,8 @@ module Pod
462
509
  raise Informative, 'Unable to find the Xcode project ' \
463
510
  "`#{path}` for the target `#{target_definition.label}`."
464
511
  end
465
-
466
512
  else
467
- xcodeprojs = Pathname.glob(config.installation_root + '*.xcodeproj')
513
+ xcodeprojs = config.installation_root.children.select { |e| e.fnmatch('*.xcodeproj') }
468
514
  if xcodeprojs.size == 1
469
515
  path = xcodeprojs.first
470
516
  else
@@ -514,6 +560,37 @@ module Pod
514
560
  end
515
561
  end
516
562
 
563
+ # Checks if any of the targets for the {TargetDefinition} computed before
564
+ # by #compute_user_project_targets require to be build as a framework due
565
+ # the presence of Swift source code in any of the source build phases.
566
+ #
567
+ # @param [TargetDefinition] target_definition
568
+ # the target definition
569
+ #
570
+ # @param [Array<PBXNativeTarget>] native_targets
571
+ # the targets which are checked for presence of Swift source code
572
+ #
573
+ # @return [Boolean] Whether the user project targets to integrate into
574
+ # uses Swift
575
+ #
576
+ def compute_user_project_targets_require_framework(target_definition, native_targets)
577
+ file_predicate = nil
578
+ file_predicate = proc do |file_ref|
579
+ if file_ref.respond_to?(:last_known_file_type)
580
+ file_ref.last_known_file_type == 'sourcecode.swift'
581
+ elsif file_ref.respond_to?(:files)
582
+ file_ref.files.any?(&file_predicate)
583
+ else
584
+ false
585
+ end
586
+ end
587
+ target_definition.platform.supports_dynamic_frameworks? || native_targets.any? do |target|
588
+ target.source_build_phase.files.any? do |build_file|
589
+ file_predicate.call(build_file.file_ref)
590
+ end
591
+ end
592
+ end
593
+
517
594
  # @return [Hash{String=>Symbol}] A hash representing the user build
518
595
  # configurations where each key corresponds to the name of a
519
596
  # configuration and its value to its type (`:debug` or `:release`).
@@ -32,8 +32,13 @@ module Pod
32
32
  add_to_dependency_graph(pod, [], dependency_graph)
33
33
  end
34
34
 
35
+ pods_to_update = pods_to_update.flat_map do |u|
36
+ root_name = Specification.root_name(u)
37
+ dependency_graph.vertices.keys.select { |n| Specification.root_name(n) == root_name }
38
+ end
39
+
35
40
  pods_to_update.each do |u|
36
- dependency_graph.detach_vertex_named(u) if dependency_graph.vertex_named(u)
41
+ dependency_graph.detach_vertex_named(u)
37
42
  end
38
43
  end
39
44
 
@@ -67,7 +67,7 @@ module Pod
67
67
  #
68
68
  def add_source_files_references
69
69
  UI.message '- Adding source files to Pods project' do
70
- add_file_accessors_paths_to_pods_group(:source_files)
70
+ add_file_accessors_paths_to_pods_group(:source_files, nil, true)
71
71
  end
72
72
  end
73
73
 
@@ -100,8 +100,8 @@ module Pod
100
100
  #
101
101
  def add_resources
102
102
  UI.message '- Adding resources to Pods project' do
103
- add_file_accessors_paths_to_pods_group(:resources, :resources)
104
- add_file_accessors_paths_to_pods_group(:resource_bundle_files, :resources)
103
+ add_file_accessors_paths_to_pods_group(:resources, :resources, true)
104
+ add_file_accessors_paths_to_pods_group(:resource_bundle_files, :resources, true)
105
105
  end
106
106
  end
107
107
 
@@ -152,14 +152,20 @@ module Pod
152
152
  # @param [Symbol] group_key
153
153
  # The key of the group of the Pods project.
154
154
  #
155
+ # @param [Bool] reflect_file_system_structure_for_development
156
+ # Wether organizing the a local pod's files in subgroups inside
157
+ # the pod's group is allowed.
158
+ #
155
159
  # @return [void]
156
160
  #
157
- def add_file_accessors_paths_to_pods_group(file_accessor_key, group_key = nil)
161
+ def add_file_accessors_paths_to_pods_group(file_accessor_key, group_key = nil, reflect_file_system_structure_for_development = false)
158
162
  file_accessors.each do |file_accessor|
163
+ pod_name = file_accessor.spec.name
164
+ local = sandbox.local?(pod_name)
159
165
  paths = file_accessor.send(file_accessor_key)
160
166
  paths.each do |path|
161
167
  group = pods_project.group_for_spec(file_accessor.spec.name, group_key)
162
- pods_project.add_file_reference(path, group)
168
+ pods_project.add_file_reference(path, group, local && reflect_file_system_structure_for_development)
163
169
  end
164
170
  end
165
171
  end
@@ -13,6 +13,7 @@ module Pod
13
13
  def migrate(sandbox)
14
14
  if sandbox.manifest
15
15
  migrate_to_0_34(sandbox) if installation_minor?('0.34', sandbox)
16
+ migrate_to_0_36(sandbox) if installation_minor?('0.36', sandbox)
16
17
  end
17
18
  end
18
19
 
@@ -46,6 +47,14 @@ module Pod
46
47
  delete(Pathname(File.join(ENV['HOME'], 'Library/Caches/CocoaPods/Git')))
47
48
  end
48
49
 
50
+ # Migrates from CocoaPods versions prior to 0.36.
51
+ #
52
+ def migrate_to_0_36(sandbox)
53
+ UI.message('Migrating to CocoaPods 0.36') do
54
+ move(sandbox.root + 'Headers/Build', sandbox.root + 'Headers/Private')
55
+ end
56
+ end
57
+
49
58
  # @!group Private helpers
50
59
 
51
60
  def installation_minor?(target_version, sandbox)
@@ -36,25 +36,47 @@ module Pod
36
36
  # @return [void]
37
37
  #
38
38
  def add_target
39
+ product_type = target.product_type
39
40
  name = target.label
40
41
  platform = target.platform.name
41
42
  deployment_target = target.platform.deployment_target.to_s
42
- @native_target = project.new_target(:static_library, name, platform, deployment_target)
43
+ @native_target = project.new_target(product_type, name, platform, deployment_target)
44
+
45
+ product_name = target.product_name
46
+ product = @native_target.product_reference
47
+ product.name = product_name
48
+ product.path = product_name
43
49
 
44
50
  target.user_build_configurations.each do |bc_name, type|
45
51
  configuration = @native_target.add_build_configuration(bc_name, type)
46
52
  end
47
53
 
48
- settings = { 'OTHER_LDFLAGS' => '', 'OTHER_LIBTOOLFLAGS' => '' }
54
+ @native_target.build_configurations.each do |configuration|
55
+ configuration.build_settings.merge!(custom_build_settings)
56
+ end
57
+
58
+ target.native_target = @native_target
59
+ end
60
+
61
+ # Returns the customized build settings which are overridden in the build
62
+ # settings of the user target.
63
+ #
64
+ # @return [Hash{String => String}]
65
+ #
66
+ def custom_build_settings
67
+ settings = {}
68
+
49
69
  if target.archs
50
70
  settings['ARCHS'] = target.archs
51
71
  end
52
72
 
53
- @native_target.build_configurations.each do |configuration|
54
- configuration.build_settings.merge!(settings)
73
+ if target.requires_frameworks?
74
+ settings['PRODUCT_NAME'] = target.product_module_name
75
+ else
76
+ settings.merge!('OTHER_LDFLAGS' => '', 'OTHER_LIBTOOLFLAGS' => '')
55
77
  end
56
78
 
57
- target.native_target = @native_target
79
+ settings
58
80
  end
59
81
 
60
82
  # Creates the directory where to store the support files of the target.
@@ -63,6 +85,68 @@ module Pod
63
85
  target.support_files_dir.mkdir
64
86
  end
65
87
 
88
+ # Creates the Info.plist file which sets public framework attributes
89
+ #
90
+ # @return [void]
91
+ #
92
+ def create_info_plist_file
93
+ path = target.info_plist_path
94
+ UI.message "- Generating Info.plist file at #{UI.path(path)}" do
95
+ generator = Generator::InfoPlistFile.new(target)
96
+ generator.save_as(path)
97
+ add_file_to_support_group(path)
98
+
99
+ native_target.build_configurations.each do |c|
100
+ relative_path = path.relative_path_from(sandbox.root)
101
+ c.build_settings['INFOPLIST_FILE'] = relative_path.to_s
102
+ end
103
+ end
104
+ end
105
+
106
+ # Creates the module map file which ensures that the umbrella header is
107
+ # recognized with a customized path
108
+ #
109
+ # @return [void]
110
+ #
111
+ def create_module_map
112
+ path = target.module_map_path
113
+ UI.message "- Generating module map file at #{UI.path(path)}" do
114
+ generator = Generator::ModuleMap.new(target)
115
+ generator.save_as(path)
116
+ add_file_to_support_group(path)
117
+
118
+ native_target.build_configurations.each do |c|
119
+ relative_path = path.relative_path_from(sandbox.root)
120
+ c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
121
+ end
122
+ end
123
+ end
124
+
125
+ # Generates a header which ensures that all header files are exported
126
+ # in the module map
127
+ #
128
+ # @yield_param [Generator::UmbrellaHeader]
129
+ # yielded once to configure the imports
130
+ #
131
+ def create_umbrella_header
132
+ path = target.umbrella_header_path
133
+ UI.message "- Generating umbrella header at #{UI.path(path)}" do
134
+ generator = Generator::UmbrellaHeader.new(target)
135
+ yield generator if block_given?
136
+ generator.save_as(path)
137
+
138
+ # Add the file to the support group and the native target,
139
+ # so it will been added to the header build phase
140
+ file_ref = add_file_to_support_group(path)
141
+ native_target.add_file_references([file_ref])
142
+
143
+ # Make the umbrella header public
144
+ build_file = native_target.headers_build_phase.build_file(file_ref)
145
+ build_file.settings ||= {}
146
+ build_file.settings['ATTRIBUTES'] = ['Public']
147
+ end
148
+ end
149
+
66
150
  # Generates a dummy source file for each target so libraries that contain
67
151
  # only categories build.
68
152
  #