cocoapods 1.5.2 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +365 -1
  3. data/bin/pod +1 -1
  4. data/lib/cocoapods/command/cache/clean.rb +1 -1
  5. data/lib/cocoapods/command/init.rb +4 -2
  6. data/lib/cocoapods/command/install.rb +7 -0
  7. data/lib/cocoapods/command/lib/lint.rb +8 -1
  8. data/lib/cocoapods/command/outdated.rb +4 -9
  9. data/lib/cocoapods/command/repo/add.rb +1 -1
  10. data/lib/cocoapods/command/repo/list.rb +1 -1
  11. data/lib/cocoapods/command/repo/push.rb +17 -12
  12. data/lib/cocoapods/command/repo/remove.rb +1 -1
  13. data/lib/cocoapods/command/repo/update.rb +1 -1
  14. data/lib/cocoapods/command/setup.rb +1 -1
  15. data/lib/cocoapods/command/spec/create.rb +39 -39
  16. data/lib/cocoapods/command/spec/lint.rb +8 -1
  17. data/lib/cocoapods/command.rb +3 -1
  18. data/lib/cocoapods/config.rb +13 -2
  19. data/lib/cocoapods/downloader/cache.rb +1 -1
  20. data/lib/cocoapods/executable.rb +3 -3
  21. data/lib/cocoapods/external_sources/abstract_external_source.rb +23 -13
  22. data/lib/cocoapods/external_sources.rb +7 -4
  23. data/lib/cocoapods/gem_version.rb +1 -1
  24. data/lib/cocoapods/generator/acknowledgements/markdown.rb +6 -0
  25. data/lib/cocoapods/generator/acknowledgements/plist.rb +13 -2
  26. data/lib/cocoapods/generator/app_target_helper.rb +141 -17
  27. data/lib/cocoapods/generator/copy_resources_script.rb +14 -3
  28. data/lib/cocoapods/generator/dummy_source.rb +14 -5
  29. data/lib/cocoapods/generator/embed_frameworks_script.rb +37 -20
  30. data/lib/cocoapods/generator/header.rb +1 -1
  31. data/lib/cocoapods/generator/info_plist_file.rb +12 -4
  32. data/lib/cocoapods/generator/prefix_header.rb +2 -2
  33. data/lib/cocoapods/hooks_manager.rb +28 -17
  34. data/lib/cocoapods/installer/analyzer/analysis_result.rb +52 -22
  35. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +14 -6
  36. data/lib/cocoapods/installer/analyzer/pod_variant.rb +4 -5
  37. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +3 -14
  38. data/lib/cocoapods/installer/analyzer/specs_state.rb +28 -4
  39. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +27 -14
  40. data/lib/cocoapods/installer/analyzer/target_inspector.rb +17 -11
  41. data/lib/cocoapods/installer/analyzer.rb +391 -284
  42. data/lib/cocoapods/installer/installation_options.rb +2 -0
  43. data/lib/cocoapods/installer/pod_source_installer.rb +31 -43
  44. data/lib/cocoapods/installer/post_install_hooks_context.rb +72 -47
  45. data/lib/cocoapods/installer/pre_install_hooks_context.rb +22 -13
  46. data/lib/cocoapods/installer/source_provider_hooks_context.rb +3 -1
  47. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +44 -11
  48. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +69 -29
  49. data/lib/cocoapods/installer/user_project_integrator.rb +6 -4
  50. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +25 -16
  51. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +104 -0
  52. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +23 -50
  53. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +296 -177
  54. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +51 -33
  55. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +93 -0
  56. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +62 -69
  57. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +72 -0
  58. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +130 -122
  59. data/lib/cocoapods/installer/xcode/target_validator.rb +15 -9
  60. data/lib/cocoapods/installer.rb +140 -63
  61. data/lib/cocoapods/project.rb +16 -14
  62. data/lib/cocoapods/resolver/resolver_specification.rb +41 -0
  63. data/lib/cocoapods/resolver.rb +79 -98
  64. data/lib/cocoapods/sandbox/file_accessor.rb +11 -6
  65. data/lib/cocoapods/sandbox/headers_store.rb +9 -8
  66. data/lib/cocoapods/sandbox/path_list.rb +5 -8
  67. data/lib/cocoapods/sandbox.rb +31 -43
  68. data/lib/cocoapods/sources_manager.rb +1 -1
  69. data/lib/cocoapods/target/aggregate_target.rb +143 -85
  70. data/lib/cocoapods/target/build_settings.rb +1124 -0
  71. data/lib/cocoapods/target/framework_paths.rb +36 -0
  72. data/lib/cocoapods/target/pod_target.rb +198 -295
  73. data/lib/cocoapods/target.rb +92 -37
  74. data/lib/cocoapods/user_interface.rb +5 -0
  75. data/lib/cocoapods/validator.rb +149 -44
  76. data/lib/cocoapods.rb +0 -1
  77. metadata +31 -23
  78. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +0 -260
  79. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +0 -87
  80. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +0 -558
  81. data/lib/cocoapods/generator/xcconfig.rb +0 -13
@@ -1,5 +1,4 @@
1
1
  require 'molinillo'
2
- require 'cocoapods/resolver/lazy_specification'
3
2
 
4
3
  module Pod
5
4
  class NoSpecFoundError < Informative
@@ -12,43 +11,8 @@ module Pod
12
11
  # by target for a given Podfile.
13
12
  #
14
13
  class Resolver
15
- # A small container that wraps a resolved specification for a given target definition. Additional metadata
16
- # is included here such as if the specification is only used by tests.
17
- #
18
- class ResolverSpecification
19
- # @return [Specification] the specification that was resolved
20
- #
21
- attr_reader :spec
22
-
23
- # @return [Source] the spec repo source the specification came from
24
- #
25
- attr_reader :source
26
-
27
- # @return [Bool] whether this resolved specification is only used by tests.
28
- #
29
- attr_reader :used_by_tests_only
30
- alias used_by_tests_only? used_by_tests_only
31
-
32
- def initialize(spec, used_by_tests_only, source)
33
- @spec = spec
34
- @used_by_tests_only = used_by_tests_only
35
- @source = source
36
- end
37
-
38
- def name
39
- spec.name
40
- end
41
-
42
- def root
43
- spec.root
44
- end
45
-
46
- def ==(other)
47
- self.class == other &&
48
- spec == other.spec &&
49
- used_by_tests_only == other.test_only
50
- end
51
- end
14
+ require 'cocoapods/resolver/lazy_specification'
15
+ require 'cocoapods/resolver/resolver_specification'
52
16
 
53
17
  include Pod::Installer::InstallationOptions::Mixin
54
18
 
@@ -97,7 +61,11 @@ module Pod
97
61
  @specs_updated = specs_updated
98
62
  @podfile_dependency_cache = podfile_dependency_cache
99
63
  @platforms_by_dependency = Hash.new { |h, k| h[k] = [] }
64
+
100
65
  @cached_sets = {}
66
+ @podfile_requirements_by_root_name = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).each_value { |a| a.map!(&:requirement) }
67
+ @search = {}
68
+ @validated_platforms = Set.new
101
69
  end
102
70
 
103
71
  #-------------------------------------------------------------------------#
@@ -133,19 +101,16 @@ module Pod
133
101
  #
134
102
  def resolver_specs_by_target
135
103
  @resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
136
- dependencies = {}
137
104
  @podfile_dependency_cache.target_definition_list.each do |target|
138
- specs = @podfile_dependency_cache.target_definition_dependencies(target).flat_map do |dep|
139
- name = dep.name
140
- node = @activated.vertex_named(name)
141
- (valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] }
142
- end
105
+ # can't use vertex.root? since that considers _all_ targets
106
+ explicit_dependencies = @podfile_dependency_cache.target_definition_dependencies(target).map(&:name).to_set
107
+ vertices = valid_dependencies_for_target(target)
143
108
 
144
- resolver_specs_by_target[target] = specs.
145
- group_by(&:first).
146
- map do |vertex, spec_test_only_tuples|
147
- test_only = spec_test_only_tuples.all? { |tuple| tuple[1] }
109
+ resolver_specs_by_target[target] = vertices.
110
+ map do |vertex|
148
111
  payload = vertex.payload
112
+ test_only = (!explicit_dependencies.include?(vertex.name) || payload.test_specification?) &&
113
+ (vertex.recursive_predecessors & vertices).all? { |v| !explicit_dependencies.include?(v.name) || v.payload.test_specification? }
149
114
  spec_source = payload.respond_to?(:spec_source) && payload.spec_source
150
115
  ResolverSpecification.new(payload, test_only, spec_source)
151
116
  end.
@@ -170,11 +135,11 @@ module Pod
170
135
  # @param [Dependency] dependency the dependency that is being searched for.
171
136
  #
172
137
  def search_for(dependency)
173
- @search ||= {}
174
138
  @search[dependency] ||= begin
175
139
  locked_requirement = requirement_for_locked_pod_named(dependency.name)
176
- additional_requirements = Array(locked_requirement)
177
- specifications_for_dependency(dependency, additional_requirements)
140
+ podfile_deps = Array(@podfile_requirements_by_root_name[dependency.root_name])
141
+ podfile_deps << locked_requirement if locked_requirement
142
+ specifications_for_dependency(dependency, podfile_deps)
178
143
  end
179
144
  @search[dependency].dup
180
145
  end
@@ -235,31 +200,29 @@ module Pod
235
200
  def requirement_satisfied_by?(requirement, activated, spec)
236
201
  version = spec.version
237
202
  return false unless requirement.requirement.satisfied_by?(version)
238
- shared_possibility_versions, prerelease_requirement = possibility_versions_for_root_name(requirement, activated)
239
- return false if !shared_possibility_versions.empty? && !shared_possibility_versions.include?(version)
240
- return false if version.prerelease? && !prerelease_requirement
203
+ return false unless valid_possibility_version_for_root_name?(requirement, activated, spec)
241
204
  return false unless spec_is_platform_compatible?(activated, requirement, spec)
242
205
  true
243
206
  end
244
207
 
245
- def possibility_versions_for_root_name(requirement, activated)
246
- prerelease_requirement = requirement.prerelease? || requirement.external_source
247
- existing = activated.vertices.values.flat_map do |vertex|
208
+ def valid_possibility_version_for_root_name?(requirement, activated, spec)
209
+ return true if prerelease_requirement = requirement.prerelease? || requirement.external_source || !spec.version.prerelease?
210
+
211
+ activated.each do |vertex|
248
212
  next unless vertex.payload
249
213
  next unless Specification.root_name(vertex.name) == requirement.root_name
250
214
 
251
215
  prerelease_requirement ||= vertex.requirements.any? { |r| r.prerelease? || r.external_source }
252
216
 
253
- if vertex.payload.respond_to?(:possibilities)
254
- vertex.payload.possibilities.map(&:version)
255
- else
256
- vertex.payload.version
217
+ if vertex.payload.respond_to?(:version)
218
+ return true if vertex.payload.version == spec.version
219
+ break
257
220
  end
258
- end.compact
221
+ end
259
222
 
260
- [existing, prerelease_requirement]
223
+ prerelease_requirement
261
224
  end
262
- private :possibility_versions_for_root_name
225
+ private :valid_possibility_version_for_root_name?
263
226
 
264
227
  # Sort dependencies so that the ones that are easiest to resolve are first.
265
228
  # Easiest to resolve is (usually) defined by:
@@ -386,7 +349,7 @@ module Pod
386
349
  #
387
350
  def find_cached_set(dependency)
388
351
  name = dependency.root_name
389
- unless cached_sets[name]
352
+ cached_sets[name] ||= begin
390
353
  if dependency.external_source
391
354
  spec = sandbox.specification(name)
392
355
  unless spec
@@ -397,12 +360,13 @@ module Pod
397
360
  else
398
361
  set = create_set_from_sources(dependency)
399
362
  end
400
- cached_sets[name] = set
363
+
401
364
  unless set
402
365
  raise Molinillo::NoSuchDependencyError.new(dependency) # rubocop:disable Style/RaiseArgs
403
366
  end
367
+
368
+ set
404
369
  end
405
- cached_sets[name]
406
370
  end
407
371
 
408
372
  # @return [Requirement, Nil]
@@ -431,8 +395,11 @@ module Pod
431
395
  # @return [Source::Aggregate] The aggregate of the {#sources}.
432
396
  #
433
397
  def aggregate_for_dependency(dependency)
398
+ sources_manager = Config.instance.sources_manager
434
399
  if dependency && dependency.podspec_repo
435
- return Config.instance.sources_manager.aggregate_for_dependency(dependency)
400
+ sources_manager.aggregate_for_dependency(dependency)
401
+ elsif (locked_vertex = @locked_dependencies.vertex_named(dependency.name)) && (locked_dependency = locked_vertex.payload) && locked_dependency.podspec_repo
402
+ sources_manager.aggregate_for_dependency(locked_dependency)
436
403
  else
437
404
  @aggregate ||= Source::Aggregate.new(sources)
438
405
  end
@@ -446,6 +413,7 @@ module Pod
446
413
  #
447
414
  def validate_platform(spec, target)
448
415
  return unless target_platform = target.platform
416
+ return unless @validated_platforms.add?([spec.object_id, target_platform])
449
417
  unless spec.available_platforms.any? { |p| target_platform.to_sym == p.to_sym }
450
418
  raise Informative, "The platform of the target `#{target.name}` " \
451
419
  "(#{target.platform}) is not compatible with `#{spec}`, which does " \
@@ -455,11 +423,6 @@ module Pod
455
423
 
456
424
  # Handles errors that come out of a {Molinillo::Resolver}.
457
425
  #
458
- # @todo The check for version conflicts coming from the {Lockfile}
459
- # requiring a pre-release version can be deleted for version 1.0,
460
- # as it is a migration step for Lockfiles coming from CocoaPods
461
- # versions before `0.35.0`.
462
- #
463
426
  # @return [void]
464
427
  #
465
428
  # @param [Molinillo::ResolverError] error
@@ -475,16 +438,7 @@ module Pod
475
438
  :version_for_spec => lambda(&:version),
476
439
  :additional_message_for_conflict => lambda do |o, name, conflict|
477
440
  local_pod_parent = conflict.requirement_trees.flatten.reverse.find(&:local?)
478
- lockfile_reqs = conflict.requirements[name_for_locking_dependency_source]
479
- if lockfile_reqs && lockfile_reqs.last && lockfile_reqs.last.prerelease? && !conflict.existing
480
- o << "\nDue to the previous naïve CocoaPods resolver, " \
481
- "you were using a pre-release version of `#{name}`, " \
482
- 'without explicitly asking for a pre-release version, which now leads to a conflict. ' \
483
- 'Please decide to either use that pre-release version by adding the ' \
484
- 'version requirement to your Podfile ' \
485
- "(e.g. `pod '#{name}', '#{lockfile_reqs.map(&:requirement).join("', '")}'`) " \
486
- "or revert to a stable version by running `pod update #{name}`."
487
- elsif local_pod_parent && !specifications_for_dependency(conflict.requirement).empty? && !conflict.possibility && conflict.locked_requirement
441
+ if local_pod_parent && !specifications_for_dependency(conflict.requirement).empty? && !conflict.possibility && conflict.locked_requirement
488
442
  # Conflict was caused by a requirement from a local dependency.
489
443
  # Tell user to use `pod update`.
490
444
  o << "\nIt seems like you've changed the constraints of dependency `#{name}` " \
@@ -528,6 +482,17 @@ module Pod
528
482
  end
529
483
  end,
530
484
  )
485
+ when Molinillo::NoSuchDependencyError
486
+ message += <<-EOS
487
+
488
+
489
+ You have either:
490
+ * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
491
+ * mistyped the name or version.
492
+ * not added the source repo that hosts the Podspec to your Podfile.
493
+
494
+ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
495
+ EOS
531
496
  end
532
497
  raise type.new(message).tap { |e| e.set_backtrace(error.backtrace) }
533
498
  end
@@ -543,8 +508,12 @@ module Pod
543
508
  #
544
509
  # @return [Bool]
545
510
  def spec_is_platform_compatible?(dependency_graph, dependency, spec)
511
+ # This is safe since a pod will only be in locked dependencies if we're
512
+ # using the same exact version
513
+ return true if locked_dependencies.vertex_named(spec.name)
514
+
546
515
  vertex = dependency_graph.vertex_named(dependency.name)
547
- predecessors = vertex.recursive_predecessors.select(&:root)
516
+ predecessors = vertex.recursive_predecessors.select(&:root?)
548
517
  predecessors << vertex if vertex.root?
549
518
  platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }.uniq
550
519
 
@@ -566,32 +535,44 @@ module Pod
566
535
  # An array of target-appropriate nodes whose `payload`s are
567
536
  # dependencies for `target`.
568
537
  #
569
- def valid_dependencies_for_target_from_node(target, dependencies, node)
570
- dependencies[[node.name, target.platform]] ||= begin
571
- validate_platform(node.payload, target)
572
- dependency_nodes = []
573
- node.outgoing_edges.each do |edge|
574
- next unless edge_is_valid_for_target_platform?(edge, target.platform)
575
- dependency_nodes << edge.destination
576
- end
538
+ def valid_dependencies_for_target(target)
539
+ dependencies = Set.new
540
+ @podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
541
+ node = @activated.vertex_named(dep.name)
542
+ add_valid_dependencies_from_node(node, target, dependencies)
543
+ end
544
+ dependencies
545
+ end
577
546
 
578
- dependency_nodes.flat_map do |item|
579
- valid_dependencies_for_target_from_node(target, dependencies, item)
580
- end.concat dependency_nodes
547
+ def add_valid_dependencies_from_node(node, target, dependencies)
548
+ return unless dependencies.add?(node)
549
+ validate_platform(node.payload, target)
550
+ node.outgoing_edges.each do |edge|
551
+ next unless edge_is_valid_for_target_platform?(edge, target.platform)
552
+ add_valid_dependencies_from_node(edge.destination, target, dependencies)
581
553
  end
582
554
  end
583
555
 
556
+ EdgeAndPlatform = Struct.new(:edge, :target_platform)
557
+ private_constant :EdgeAndPlatform
558
+
584
559
  # Whether the given `edge` should be followed to find dependencies for the
585
560
  # given `target_platform`.
586
561
  #
587
562
  # @return [Bool]
588
563
  #
589
564
  def edge_is_valid_for_target_platform?(edge, target_platform)
590
- requirement_name = edge.requirement.name
565
+ @edge_validity ||= Hash.new do |hash, edge_and_platform|
566
+ e = edge_and_platform.edge
567
+ platform = edge_and_platform.target_platform
568
+ requirement_name = e.requirement.name
591
569
 
592
- edge.origin.payload.all_dependencies(target_platform).any? do |dep|
593
- dep.name == requirement_name
570
+ hash[edge_and_platform] = e.origin.payload.all_dependencies(platform).any? do |dep|
571
+ dep.name == requirement_name
572
+ end
594
573
  end
574
+
575
+ @edge_validity[EdgeAndPlatform.new(edge, target_platform)]
595
576
  end
596
577
  end
597
578
  end
@@ -1,4 +1,4 @@
1
- autoload :MachO, 'macho'
1
+ require 'macho'
2
2
 
3
3
  module Pod
4
4
  class Sandbox
@@ -33,8 +33,8 @@ module Pod
33
33
 
34
34
  # Initialize a new instance
35
35
  #
36
- # @param [Sandbox::PathList, Pathname] path_list @see path_list
37
- # @param [Specification::Consumer] spec_consumer @see spec_consumer
36
+ # @param [Sandbox::PathList, Pathname] path_list @see #path_list
37
+ # @param [Specification::Consumer] spec_consumer @see #spec_consumer
38
38
  #
39
39
  def initialize(path_list, spec_consumer)
40
40
  if path_list.is_a?(PathList)
@@ -106,6 +106,13 @@ module Pod
106
106
  source_files - arc_source_files
107
107
  end
108
108
 
109
+ # @return [Array<Pathname] the source files that do not match any of the
110
+ # recognized file extensions
111
+ def other_source_files
112
+ extensions = SOURCE_FILE_EXTENSIONS
113
+ source_files.reject { |f| extensions.include?(f.extname) }
114
+ end
115
+
109
116
  # @return [Array<Pathname>] the headers of the specification.
110
117
  #
111
118
  def headers
@@ -413,9 +420,7 @@ module Pod
413
420
  #
414
421
  def expanded_paths(patterns, options = {})
415
422
  return [] if patterns.empty?
416
- result = []
417
- result << path_list.glob(patterns, options)
418
- result.flatten.compact.uniq
423
+ path_list.glob(patterns, options).flatten.compact.uniq
419
424
  end
420
425
 
421
426
  # @param [Pathname] binary
@@ -16,7 +16,7 @@ module Pod
16
16
  #
17
17
  attr_reader :sandbox
18
18
 
19
- # @param [Sandbox] @see sandbox
19
+ # @param [Sandbox] @see #sandbox
20
20
  #
21
21
  # @param [String] relative_path
22
22
  # the relative path to the sandbox root and hence to the Pods
@@ -54,7 +54,7 @@ module Pod
54
54
  return @search_paths_cache[key] if @search_paths_cache.key?(key)
55
55
  search_paths = @search_paths.select do |entry|
56
56
  matches_platform = entry[:platform] == platform.name
57
- matches_target = target_name.nil? || (entry[:path].basename.to_s == target_name)
57
+ matches_target = target_name.nil? || (File.basename(entry[:path]) == target_name)
58
58
  matches_platform && matches_target
59
59
  end
60
60
  headers_dir = root.relative_path_from(sandbox.root).dirname
@@ -63,7 +63,7 @@ module Pod
63
63
  paths << "${PODS_ROOT}/#{headers_dir}/#{@relative_path}" if !use_modular_headers || @visibility_scope == :public
64
64
  paths << "${PODS_ROOT}/#{headers_dir}/#{entry[:path]}" if !use_modular_headers || @visibility_scope == :private
65
65
  paths
66
- end.uniq
66
+ end.tap(&:uniq!).freeze
67
67
  end
68
68
 
69
69
  # Removes the directory as it is regenerated from scratch during each
@@ -96,8 +96,9 @@ module Pod
96
96
  # @return [Array<Pathname>]
97
97
  #
98
98
  def add_files(namespace, relative_header_paths)
99
+ root.join(namespace).mkpath unless relative_header_paths.empty?
99
100
  relative_header_paths.map do |relative_header_path|
100
- add_file(namespace, relative_header_path)
101
+ add_file(namespace, relative_header_path, :mkdir => false)
101
102
  end
102
103
  end
103
104
 
@@ -115,9 +116,9 @@ module Pod
115
116
  #
116
117
  # @return [Pathname]
117
118
  #
118
- def add_file(namespace, relative_header_path)
119
+ def add_file(namespace, relative_header_path, mkdir: true)
119
120
  namespaced_path = root + namespace
120
- namespaced_path.mkpath unless File.exist?(namespaced_path)
121
+ namespaced_path.mkpath if mkdir
121
122
 
122
123
  absolute_source = (sandbox.root + relative_header_path)
123
124
  source = absolute_source.relative_path_from(namespaced_path)
@@ -128,7 +129,7 @@ module Pod
128
129
  # Adds an header search path to the sandbox.
129
130
  #
130
131
  # @param [Pathname] path
131
- # the path tho add.
132
+ # the path to add.
132
133
  #
133
134
  # @param [String] platform
134
135
  # the platform the search path applies to
@@ -136,7 +137,7 @@ module Pod
136
137
  # @return [void]
137
138
  #
138
139
  def add_search_path(path, platform)
139
- @search_paths << { :platform => platform.name, :path => (Pathname.new(@relative_path) + path) }
140
+ @search_paths << { :platform => platform.name, :path => File.join(@relative_path, path) }
140
141
  end
141
142
 
142
143
  #-----------------------------------------------------------------------#
@@ -16,11 +16,11 @@ module Pod
16
16
  # @return [Pathname] The root of the list whose files and directories
17
17
  # are used to perform the matching operations.
18
18
  #
19
- attr_accessor :root
19
+ attr_reader :root
20
20
 
21
21
  # Initialize a new instance
22
22
  #
23
- # @param [Pathname] root The root of the PathList.
23
+ # @param [Pathname] root @see #root
24
24
  #
25
25
  def initialize(root)
26
26
  root_dir = ActiveSupport::Multibyte::Unicode.normalize(root.to_s)
@@ -88,7 +88,8 @@ module Pod
88
88
  # @return [Array<Pathname>]
89
89
  #
90
90
  def glob(patterns, options = {})
91
- relative_glob(patterns, options).map { |p| root.join(p) }
91
+ cache_key = options.merge(:patterns => patterns)
92
+ @glob_cache[cache_key] ||= relative_glob(patterns, options).map { |p| root.join(p) }
92
93
  end
93
94
 
94
95
  # The list of relative paths that are case insensitively matched by a
@@ -115,10 +116,6 @@ module Pod
115
116
  def relative_glob(patterns, options = {})
116
117
  return [] if patterns.empty?
117
118
 
118
- cache_key = options.merge(:patterns => patterns)
119
- cached_value = @glob_cache[cache_key]
120
- return cached_value if cached_value
121
-
122
119
  dir_pattern = options[:dir_pattern]
123
120
  exclude_patterns = options[:exclude_patterns]
124
121
  include_dirs = options[:include_dirs]
@@ -155,7 +152,7 @@ module Pod
155
152
  exclude_options = { :dir_pattern => '**/*', :include_dirs => include_dirs }
156
153
  list -= relative_glob(exclude_patterns, exclude_options)
157
154
  end
158
- @glob_cache[cache_key] = list
155
+ list
159
156
  end
160
157
 
161
158
  #-----------------------------------------------------------------------#
@@ -52,7 +52,7 @@ module Pod
52
52
 
53
53
  # Initialize a new instance
54
54
  #
55
- # @param [String, Pathname] root @see root
55
+ # @param [String, Pathname] root @see #root
56
56
  #
57
57
  def initialize(root)
58
58
  FileUtils.mkdir_p(root)
@@ -62,6 +62,7 @@ module Pod
62
62
  @checkout_sources = {}
63
63
  @development_pods = {}
64
64
  @pods_with_absolute_path = []
65
+ @stored_podspecs = {}
65
66
  end
66
67
 
67
68
  # @return [Lockfile] the manifest which contains the information about the
@@ -209,9 +210,9 @@ module Pod
209
210
  # @return [Specification] the specification if the file is found.
210
211
  #
211
212
  def specification(name)
212
- if file = specification_path(name)
213
- original_path = development_pods[name]
214
- Specification.from_file(original_path || file)
213
+ @stored_podspecs[name] ||= if file = specification_path(name)
214
+ original_path = development_pods[name]
215
+ Specification.from_file(original_path || file)
215
216
  end
216
217
  end
217
218
 
@@ -242,7 +243,7 @@ module Pod
242
243
  # @param [String] name
243
244
  # the name of the pod
244
245
  #
245
- # @param [String, Pathname] podspec
246
+ # @param [String, Pathname, Specification] podspec
246
247
  # The contents of the specification (String) or the path to a
247
248
  # podspec file (Pathname).
248
249
  #
@@ -252,23 +253,35 @@ module Pod
252
253
  def store_podspec(name, podspec, _external_source = false, json = false)
253
254
  file_name = json ? "#{name}.podspec.json" : "#{name}.podspec"
254
255
  output_path = specifications_root + file_name
255
- output_path.dirname.mkpath
256
- if podspec.is_a?(String)
257
- output_path.open('w') { |f| f.puts(podspec) }
258
- else
259
- unless podspec.exist?
260
- raise Informative, "No podspec found for `#{name}` in #{podspec}"
256
+
257
+ spec =
258
+ case podspec
259
+ when String
260
+ output_path.open('w') { |f| f.puts(podspec) }
261
+ Specification.from_file(output_path)
262
+ when Pathname
263
+ unless podspec.exist?
264
+ raise Informative, "No podspec found for `#{name}` in #{podspec}"
265
+ end
266
+ FileUtils.copy(podspec, output_path)
267
+ Specification.from_file(podspec)
268
+ when Specification
269
+ raise ArgumentError, 'can only store Specification objects as json' unless json
270
+ output_path.open('w') { |f| f.puts(podspec.to_pretty_json) }
271
+ podspec.dup
272
+ else
273
+ raise ArgumentError, "Unknown type for podspec: #{podspec.inspect}"
261
274
  end
262
- FileUtils.copy(podspec, output_path)
263
- end
264
275
 
265
- Dir.chdir(podspec.is_a?(Pathname) ? File.dirname(podspec) : Dir.pwd) do
266
- spec = Specification.from_file(output_path)
276
+ # we force the file to be the file in the sandbox, so specs that have been serialized to
277
+ # json maintain a consistent checksum.
278
+ # this is safe to do because `spec` is always a clean instance
279
+ spec.defined_in_file = output_path
267
280
 
268
- unless spec.name == name
269
- raise Informative, "The name of the given podspec `#{spec.name}` doesn't match the expected one `#{name}`"
270
- end
281
+ unless spec.name == name
282
+ raise Informative, "The name of the given podspec `#{spec.name}` doesn't match the expected one `#{name}`"
271
283
  end
284
+ @stored_podspecs[spec.name] = spec
272
285
  end
273
286
 
274
287
  #-------------------------------------------------------------------------#
@@ -367,8 +380,6 @@ module Pod
367
380
  # @return [Hash{String=>Pathname}] The path of the Pods' podspecs with a local source
368
381
  # grouped by their root name.
369
382
  #
370
- # @todo Rename (e.g. `pods_with_local_path`)
371
- #
372
383
  attr_reader :development_pods
373
384
 
374
385
  # Checks if a Pod is locally sourced?
@@ -393,28 +404,5 @@ module Pod
393
404
  end
394
405
 
395
406
  #-------------------------------------------------------------------------#
396
-
397
- public
398
-
399
- # @!group Pods Helpers
400
-
401
- # Creates the file accessors for the given Pod Targets.
402
- #
403
- # @param [Array<PodTarget>] pod_targets
404
- # The Pod Targets to create file accessors for.
405
- #
406
- def create_file_accessors(pod_targets)
407
- pod_targets.each do |pod_target|
408
- pod_root = pod_dir(pod_target.root_spec.name)
409
- path_list = PathList.new(pod_root)
410
- file_accessors = pod_target.specs.map do |spec|
411
- FileAccessor.new(path_list, spec.consumer(pod_target.platform))
412
- end
413
- pod_target.file_accessors ||= []
414
- pod_target.file_accessors.concat(file_accessors)
415
- end
416
- end
417
-
418
- #-------------------------------------------------------------------------#
419
407
  end
420
408
  end
@@ -31,7 +31,7 @@ module Pod
31
31
  "named `#{name}`.\n"
32
32
  message << "(#{e})\n" if Config.instance.verbose?
33
33
  message << 'You can try adding it manually in ' \
34
- '`~/.cocoapods/repos` or via `pod repo add`.'
34
+ "`#{Config.instance.repos_dir}` or via `pod repo add`."
35
35
  raise Informative, message
36
36
  ensure
37
37
  UI.title_level = previous_title_level