cocoapods 1.7.5 → 1.8.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -11
  3. data/LICENSE +13 -8
  4. data/README.md +2 -1
  5. data/lib/cocoapods/command/init.rb +18 -16
  6. data/lib/cocoapods/command/install.rb +2 -1
  7. data/lib/cocoapods/command/lib/create.rb +1 -2
  8. data/lib/cocoapods/command/lib/lint.rb +12 -11
  9. data/lib/cocoapods/command/repo/add.rb +2 -2
  10. data/lib/cocoapods/command/repo/list.rb +7 -5
  11. data/lib/cocoapods/command/repo/push.rb +15 -12
  12. data/lib/cocoapods/command/setup.rb +2 -88
  13. data/lib/cocoapods/command/spec/lint.rb +10 -9
  14. data/lib/cocoapods/command/update.rb +5 -4
  15. data/lib/cocoapods/config.rb +9 -8
  16. data/lib/cocoapods/external_sources/path_source.rb +1 -1
  17. data/lib/cocoapods/gem_version.rb +1 -1
  18. data/lib/cocoapods/generator/embed_frameworks_script.rb +1 -1
  19. data/lib/cocoapods/generator/info_plist_file.rb +2 -2
  20. data/lib/cocoapods/installer.rb +32 -12
  21. data/lib/cocoapods/installer/analyzer.rb +132 -97
  22. data/lib/cocoapods/installer/analyzer/target_inspector.rb +6 -8
  23. data/lib/cocoapods/installer/installation_options.rb +4 -0
  24. data/lib/cocoapods/installer/pod_source_installer.rb +17 -1
  25. data/lib/cocoapods/installer/podfile_validator.rb +26 -6
  26. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +37 -27
  27. data/lib/cocoapods/installer/project_cache/project_cache_version.rb +1 -1
  28. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +3 -3
  29. data/lib/cocoapods/installer/project_cache/project_metadata_cache.rb +12 -6
  30. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +32 -8
  31. data/lib/cocoapods/installer/project_cache/target_metadata.rb +6 -2
  32. data/lib/cocoapods/installer/sandbox_dir_cleaner.rb +12 -0
  33. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +1 -1
  34. data/lib/cocoapods/installer/xcode/multi_pods_project_generator.rb +3 -1
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +2 -2
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +18 -3
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +53 -11
  38. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +92 -60
  39. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +66 -50
  40. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +12 -0
  41. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +6 -2
  42. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +2 -2
  43. data/lib/cocoapods/installer/xcode/target_validator.rb +30 -14
  44. data/lib/cocoapods/native_target_extension.rb +11 -5
  45. data/lib/cocoapods/open-uri.rb +1 -1
  46. data/lib/cocoapods/project.rb +13 -7
  47. data/lib/cocoapods/resolver.rb +63 -53
  48. data/lib/cocoapods/resolver/lazy_specification.rb +14 -5
  49. data/lib/cocoapods/sandbox.rb +35 -2
  50. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +3 -4
  51. data/lib/cocoapods/sources_manager.rb +72 -43
  52. data/lib/cocoapods/target.rb +7 -1
  53. data/lib/cocoapods/target/aggregate_target.rb +13 -8
  54. data/lib/cocoapods/target/build_settings.rb +33 -10
  55. data/lib/cocoapods/target/pod_target.rb +114 -30
  56. data/lib/cocoapods/user_interface/error_report.rb +9 -5
  57. data/lib/cocoapods/validator.rb +55 -11
  58. data/lib/cocoapods/version_metadata.rb +14 -1
  59. metadata +6 -7
  60. data/lib/cocoapods/command/spec/env_spec.rb +0 -53
@@ -181,6 +181,10 @@ module Pod
181
181
  # since the previous installation.
182
182
  #
183
183
  option :incremental_installation, false
184
+
185
+ # Whether to skip generating the `Pods.xcodeproj` and perform only dependency resolution and downloading.
186
+ #
187
+ option :skip_pods_project_generation, false
184
188
  end
185
189
  end
186
190
  end
@@ -14,6 +14,11 @@ module Pod
14
14
  #
15
15
  attr_reader :sandbox
16
16
 
17
+ # @return [Podfile] the podfile that should be integrated with the user
18
+ # projects.
19
+ #
20
+ attr_reader :podfile
21
+
17
22
  # @return [Hash{Symbol=>Array}] The specifications that need to be
18
23
  # installed grouped by platform.
19
24
  #
@@ -27,11 +32,13 @@ module Pod
27
32
  # Initialize a new instance
28
33
  #
29
34
  # @param [Sandbox] sandbox @see #sandbox
35
+ # @param [Podfile] podfile @see #podfile
30
36
  # @param [Hash{Symbol=>Array}] specs_by_platform @see #specs_by_platform
31
37
  # @param [Boolean] can_cache @see #can_cache
32
38
  #
33
- def initialize(sandbox, specs_by_platform, can_cache: true)
39
+ def initialize(sandbox, podfile, specs_by_platform, can_cache: true)
34
40
  @sandbox = sandbox
41
+ @podfile = podfile
35
42
  @specs_by_platform = specs_by_platform
36
43
  @can_cache = can_cache
37
44
  end
@@ -61,6 +68,7 @@ module Pod
61
68
  def install!
62
69
  download_source unless predownloaded? || local?
63
70
  PodSourcePreparer.new(root_spec, root).prepare! if local?
71
+ sandbox.remove_local_podspec(name) unless predownloaded? || local? || external?
64
72
  end
65
73
 
66
74
  # Cleans the installations if appropriate.
@@ -191,6 +199,14 @@ module Pod
191
199
  sandbox.local?(root_spec.name)
192
200
  end
193
201
 
202
+ # @return [Boolean] whether the pod uses an external source (e.g. :podspec) in the
203
+ # resolution process to retrieve its podspec.
204
+ #
205
+ def external?
206
+ @dependencies ||= podfile.dependencies.select(&:external?).map(&:name)
207
+ @dependencies.include?(root_spec.name)
208
+ end
209
+
194
210
  def released?
195
211
  !local? && !predownloaded? && sandbox.specification(root_spec.name) != root_spec
196
212
  end
@@ -122,15 +122,35 @@ module Pod
122
122
  end
123
123
 
124
124
  # Verifies that no dependencies in the Podfile will end up not being built
125
- # at all. In other words, all dependencies _must_ belong to a non-abstract
125
+ # at all. In other words, all dependencies should belong to a non-abstract
126
126
  # target, or be inherited by a target where `inheritance == complete`.
127
127
  #
128
128
  def validate_no_abstract_only_pods!
129
- all_dependencies = @podfile_dependency_cache.podfile_dependencies
130
- concrete_dependencies = @podfile_dependency_cache.target_definition_list.reject(&:abstract?).flat_map { |td| @podfile_dependency_cache.target_definition_dependencies(td) }
131
- abstract_only_dependencies = all_dependencies - concrete_dependencies
132
- abstract_only_dependencies.each do |dep|
133
- add_error "The dependency `#{dep}` is not used in any concrete target."
129
+ @podfile_dependency_cache.target_definition_list.each do |target_definition|
130
+ dependencies = @podfile_dependency_cache.target_definition_dependencies(target_definition)
131
+ next if dependencies.empty?
132
+ next unless target_definition.abstract?
133
+
134
+ children = target_definition.recursive_children
135
+ next if children.any? { |child_target_definition| target_definition_inherits?(:parent => target_definition, :child => child_target_definition) }
136
+
137
+ add_warning "The abstract target #{target_definition.name} is not inherited by a concrete target, " \
138
+ "so the following dependencies won't make it into any targets in your project:" \
139
+ "\n - #{dependencies.map(&:to_s).sort.join("\n - ")}"
140
+
141
+ next if target_definition.platform
142
+
143
+ add_error "The abstract target #{target_definition.name} must specify a platform since its dependencies are not inherited by a concrete target."
144
+ end
145
+ end
146
+
147
+ def target_definition_inherits?(parent: nil, child: nil)
148
+ if parent == child
149
+ true
150
+ elsif child.exclusive?
151
+ false
152
+ else
153
+ target_definition_inherits?(:parent => parent, :child => child.parent)
134
154
  end
135
155
  end
136
156
 
@@ -75,15 +75,19 @@ module Pod
75
75
  return full_install_results
76
76
  end
77
77
 
78
+ if project_names_changed?(pod_targets, cache)
79
+ UI.message 'Ignoring project cache due to project name changes.'
80
+ return full_install_results
81
+ end
82
+
78
83
  pod_targets_to_generate = Set[]
79
84
  aggregate_targets_to_generate = Set[]
80
- added_targets, removed_targets = compute_added_and_removed_targets(target_by_label,
81
- cache_key_by_target_label.keys,
82
- cache.cache_key_by_target_label.keys)
85
+ added_targets = compute_added_targets(target_by_label, cache_key_by_target_label.keys, cache.cache_key_by_target_label.keys)
83
86
  added_pod_targets, added_aggregate_targets = added_targets.partition { |target| target.is_a?(PodTarget) }
84
- removed_aggregate_targets = removed_targets.select { |target| target.is_a?(AggregateTarget) }
85
87
  pod_targets_to_generate.merge(added_pod_targets)
86
- aggregate_targets_to_generate.merge(added_aggregate_targets + removed_aggregate_targets)
88
+ aggregate_targets_to_generate.merge(added_aggregate_targets)
89
+
90
+ removed_aggregate_target_labels = compute_removed_targets(cache_key_by_target_label.keys, cache.cache_key_by_target_label.keys)
87
91
 
88
92
  changed_targets = compute_changed_targets_from_cache(cache_key_by_target_label, target_by_label, cache)
89
93
  changed_pod_targets, changed_aggregate_targets = changed_targets.partition { |target| target.is_a?(PodTarget) }
@@ -95,23 +99,21 @@ module Pod
95
99
  pod_targets_to_generate.merge(dirty_pod_targets)
96
100
  aggregate_targets_to_generate.merge(dirty_aggregate_targets)
97
101
 
98
- # Since multi xcodeproj will group targets by PodTarget#pod_name into individual projects, we
99
- # need to append these "sibling" targets to the list of targets we need to generate before finalizing the total list,
102
+ # Since multi xcodeproj will group targets by PodTarget#project_name into individual projects, we need to
103
+ # append these "sibling" targets to the list of targets we need to generate before finalizing the total list,
100
104
  # otherwise we will end up with missing targets.
101
105
  #
102
106
  sibling_pod_targets = compute_sibling_pod_targets(pod_targets, pod_targets_to_generate)
103
107
  pod_targets_to_generate.merge(sibling_pod_targets)
104
108
 
105
- # We either return the full list of aggregate targets or none since the aggregate targets go into the Pods.xcodeproj
106
- # and so we need to regenerate all aggregate targets when regenerating Pods.xcodeproj.
109
+ # We either return the full list of aggregate targets or none since the aggregate targets go into the
110
+ # Pods.xcodeproj and so we need to regenerate all aggregate targets when regenerating Pods.xcodeproj.
111
+ total_aggregate_targets_to_generate = unless aggregate_targets_to_generate.empty? && removed_aggregate_target_labels.empty?
112
+ aggregate_targets
113
+ end
107
114
 
108
- total_aggregate_targets_to_generate =
109
- unless aggregate_targets_to_generate.empty?
110
- aggregate_targets
111
- end
112
-
113
- ProjectCacheAnalysisResult.new(pod_targets_to_generate.to_a, total_aggregate_targets_to_generate, cache_key_by_target_label,
114
- build_configurations, project_object_version)
115
+ ProjectCacheAnalysisResult.new(pod_targets_to_generate.to_a, total_aggregate_targets_to_generate,
116
+ cache_key_by_target_label, build_configurations, project_object_version)
115
117
  end
116
118
 
117
119
  private
@@ -122,23 +124,24 @@ module Pod
122
124
  when PodTarget
123
125
  local = sandbox.local?(target.pod_name)
124
126
  checkout_options = sandbox.checkout_sources[target.pod_name]
125
- [label, TargetCacheKey.from_pod_target(target, :is_local_pod => local, :checkout_options => checkout_options)]
127
+ [label, TargetCacheKey.from_pod_target(sandbox, target, :is_local_pod => local,
128
+ :checkout_options => checkout_options)]
126
129
  when AggregateTarget
127
- [label, TargetCacheKey.from_aggregate_target(target)]
130
+ [label, TargetCacheKey.from_aggregate_target(sandbox, target)]
128
131
  else
129
132
  raise "[BUG] Unknown target type #{target}"
130
133
  end
131
134
  end]
132
135
  end
133
136
 
134
- def compute_added_and_removed_targets(target_by_label, target_labels, cached_target_labels)
135
- added_targets = (target_labels - cached_target_labels).map do |label|
137
+ def compute_added_targets(target_by_label, target_labels, cached_target_labels)
138
+ (target_labels - cached_target_labels).map do |label|
136
139
  target_by_label[label]
137
140
  end
138
- removed_targets = (cached_target_labels - target_labels).map do |label|
139
- target_by_label[label]
140
- end
141
- [added_targets, removed_targets]
141
+ end
142
+
143
+ def compute_removed_targets(target_labels, cached_target_labels)
144
+ cached_target_labels - target_labels
142
145
  end
143
146
 
144
147
  def compute_changed_targets_from_cache(cache_key_by_target_label, target_by_label, cache)
@@ -155,7 +158,7 @@ module Pod
155
158
  support_files_dir_exists = File.exist? target.support_files_dir
156
159
  xcodeproj_exists = case target
157
160
  when PodTarget
158
- File.exist? sandbox.pod_target_project_path(target.pod_name)
161
+ File.exist? sandbox.pod_target_project_path(target.project_name)
159
162
  when AggregateTarget
160
163
  File.exist? sandbox.project_path
161
164
  else
@@ -166,8 +169,15 @@ module Pod
166
169
  end
167
170
 
168
171
  def compute_sibling_pod_targets(pod_targets, pod_targets_to_generate)
169
- pod_targets_by_name = pod_targets.group_by(&:pod_name)
170
- pod_targets_to_generate.flat_map { |t| pod_targets_by_name[t.pod_name] }
172
+ pod_targets_by_project_name = pod_targets.group_by(&:project_name)
173
+ pod_targets_to_generate.flat_map { |t| pod_targets_by_project_name[t.project_name] }
174
+ end
175
+
176
+ def project_names_changed?(pod_targets, cache)
177
+ pod_targets.any? do |pod_target|
178
+ next unless (target_cache_key = cache.cache_key_by_target_label[pod_target.label])
179
+ target_cache_key.project_name != pod_target.project_name
180
+ end
171
181
  end
172
182
  end
173
183
  end
@@ -35,7 +35,7 @@ module Pod
35
35
  # The path of the project cache to save.
36
36
  #
37
37
  def save_as(path)
38
- open(path, 'w') { |f| f.puts version.to_s }
38
+ Sandbox.update_changed_file(path, version.to_s)
39
39
  end
40
40
  end
41
41
  end
@@ -47,15 +47,15 @@ module Pod
47
47
 
48
48
  def save_as(path)
49
49
  Pathname(path).dirname.mkpath
50
- path.open('w') { |f| f.puts YAMLHelper.convert(to_hash) }
50
+ Sandbox.update_changed_file(path, YAMLHelper.convert(to_hash))
51
51
  end
52
52
 
53
- def self.from_file(path)
53
+ def self.from_file(sandbox, path)
54
54
  return ProjectInstallationCache.new unless File.exist?(path)
55
55
  contents = YAMLHelper.load_file(path)
56
56
  cache_keys = contents.fetch('CACHE_KEYS', {})
57
57
  cache_key_by_target_label = Hash[cache_keys.map do |name, key_hash|
58
- [name, TargetCacheKey.from_cache_hash(key_hash)]
58
+ [name, TargetCacheKey.from_cache_hash(sandbox, key_hash)]
59
59
  end]
60
60
  project_object_version = contents['OBJECT_VERSION']
61
61
  build_configurations = contents['BUILD_CONFIGURATIONS']
@@ -6,6 +6,10 @@ module Pod
6
6
  class ProjectMetadataCache
7
7
  require 'cocoapods/installer/project_cache/target_metadata.rb'
8
8
 
9
+ # @return [Sandbox] The sandbox where the Pods should be installed.
10
+ #
11
+ attr_reader :sandbox
12
+
9
13
  # @return [Hash{String => TargetMetadata}]
10
14
  # Hash of string by target metadata.
11
15
  #
@@ -13,9 +17,11 @@ module Pod
13
17
 
14
18
  # Initialize a new instance.
15
19
  #
20
+ # @param [Sandbox] sandbox see #sandbox
16
21
  # @param [Hash{String => TargetMetadata}] target_label_by_metadata @see #target_label_by_metadata
17
22
  #
18
- def initialize(target_label_by_metadata = {})
23
+ def initialize(sandbox, target_label_by_metadata = {})
24
+ @sandbox = sandbox
19
25
  @target_label_by_metadata = target_label_by_metadata
20
26
  end
21
27
 
@@ -32,7 +38,7 @@ module Pod
32
38
  # @return [void]
33
39
  #
34
40
  def save_as(path)
35
- path.open('w') { |f| f.puts YAMLHelper.convert_hash(to_hash, nil) }
41
+ Sandbox.update_changed_file(path, YAMLHelper.convert_hash(to_hash, nil))
36
42
  end
37
43
 
38
44
  # Updates the metadata cache based on installation results.
@@ -47,15 +53,15 @@ module Pod
47
53
  installation_results = pod_target_installation_results.values + aggregate_target_installation_results.values
48
54
  installation_results.each do |installation_result|
49
55
  native_target = installation_result.native_target
50
- target_label_by_metadata[native_target.name] = TargetMetadata.from_native_target(native_target)
56
+ target_label_by_metadata[native_target.name] = TargetMetadata.from_native_target(sandbox, native_target)
51
57
  end
52
58
  end
53
59
 
54
- def self.from_file(path)
55
- return ProjectMetadataCache.new unless File.exist?(path)
60
+ def self.from_file(sandbox, path)
61
+ return ProjectMetadataCache.new(sandbox) unless File.exist?(path)
56
62
  contents = YAMLHelper.load_file(path)
57
63
  target_by_label_metadata = Hash[contents.map { |target_label, hash| [target_label, TargetMetadata.from_hash(hash)] }]
58
- ProjectMetadataCache.new(target_by_label_metadata)
64
+ ProjectMetadataCache.new(sandbox, target_by_label_metadata)
59
65
  end
60
66
  end
61
67
  end
@@ -8,6 +8,10 @@ module Pod
8
8
  require 'cocoapods/target/aggregate_target.rb'
9
9
  require 'digest'
10
10
 
11
+ # @return [Sandbox] The sandbox where the Pods should be installed.
12
+ #
13
+ attr_reader :sandbox
14
+
11
15
  # @return [Symbol]
12
16
  # The type of target. Either aggregate or pod target.
13
17
  #
@@ -20,10 +24,12 @@ module Pod
20
24
 
21
25
  # Initialize a new instance.
22
26
  #
27
+ # @param [Sandbox] sandbox see #sandbox
23
28
  # @param [Symbol] type @see #type
24
29
  # @param [Hash{String => Object}] key_hash @see #key_hash
25
30
  #
26
- def initialize(type, key_hash)
31
+ def initialize(sandbox, type, key_hash)
32
+ @sandbox = sandbox
27
33
  @type = type
28
34
  @key_hash = key_hash
29
35
  end
@@ -46,6 +52,7 @@ module Pod
46
52
  return :project if other.key_hash['CHECKSUM'] != key_hash['CHECKSUM']
47
53
  return :project if other.key_hash['SPECS'] != key_hash['SPECS']
48
54
  return :project if other.key_hash['FILES'] != key_hash['FILES']
55
+ return :project if other.key_hash['PROJECT_NAME'] != key_hash['PROJECT_NAME']
49
56
  end
50
57
 
51
58
  this_build_settings = key_hash['BUILD_SETTINGS_CHECKSUM']
@@ -64,14 +71,23 @@ module Pod
64
71
  key_hash
65
72
  end
66
73
 
74
+ # @return [String]
75
+ # The name of the project the target belongs to.
76
+ #
77
+ def project_name
78
+ key_hash['PROJECT_NAME']
79
+ end
80
+
67
81
  # Creates a TargetCacheKey instance from the given hash.
68
82
  #
83
+ # @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
84
+ #
69
85
  # @param [Hash{String => Object}] key_hash
70
86
  # The hash used to construct a TargetCacheKey object.
71
87
  #
72
88
  # @return [TargetCacheKey]
73
89
  #
74
- def self.from_cache_hash(key_hash)
90
+ def self.from_cache_hash(sandbox, key_hash)
75
91
  cache_hash = key_hash.dup
76
92
  if files = cache_hash['FILES']
77
93
  cache_hash['FILES'] = files.sort_by(&:downcase)
@@ -80,11 +96,13 @@ module Pod
80
96
  cache_hash['SPECS'] = specs.sort_by(&:downcase)
81
97
  end
82
98
  type = cache_hash['CHECKSUM'] ? :pod_target : :aggregate
83
- TargetCacheKey.new(type, cache_hash)
99
+ TargetCacheKey.new(sandbox, type, cache_hash)
84
100
  end
85
101
 
86
102
  # Constructs a TargetCacheKey instance from a PodTarget.
87
103
  #
104
+ # @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
105
+ #
88
106
  # @param [PodTarget] pod_target
89
107
  # The pod target used to construct a TargetCacheKey object.
90
108
  #
@@ -96,7 +114,7 @@ module Pod
96
114
  #
97
115
  # @return [TargetCacheKey]
98
116
  #
99
- def self.from_pod_target(pod_target, is_local_pod: false, checkout_options: nil)
117
+ def self.from_pod_target(sandbox, pod_target, is_local_pod: false, checkout_options: nil)
100
118
  build_settings = {}
101
119
  build_settings[pod_target.label.to_s] = Digest::MD5.hexdigest(pod_target.build_settings.xcconfig.to_s)
102
120
  pod_target.test_spec_build_settings.each do |name, settings|
@@ -110,26 +128,32 @@ module Pod
110
128
  'CHECKSUM' => pod_target.root_spec.checksum,
111
129
  'SPECS' => pod_target.specs.map(&:to_s).sort_by(&:downcase),
112
130
  'BUILD_SETTINGS_CHECKSUM' => build_settings,
131
+ 'PROJECT_NAME' => pod_target.project_name,
113
132
  }
114
- contents['FILES'] = pod_target.all_files.sort_by(&:downcase) if is_local_pod
133
+ if is_local_pod
134
+ relative_file_paths = pod_target.all_files.map { |f| Pathname.new(f).relative_path_from(sandbox.root).to_s }
135
+ contents['FILES'] = relative_file_paths.sort_by(&:downcase)
136
+ end
115
137
  contents['CHECKOUT_OPTIONS'] = checkout_options if checkout_options
116
- TargetCacheKey.new(:pod_target, contents)
138
+ TargetCacheKey.new(sandbox, :pod_target, contents)
117
139
  end
118
140
 
119
141
  # Construct a TargetCacheKey instance from an AggregateTarget.
120
142
  #
143
+ # @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
144
+ #
121
145
  # @param [AggregateTarget] aggregate_target
122
146
  # The aggregate target used to construct a TargetCacheKey object.
123
147
  #
124
148
  # @return [TargetCacheKey]
125
149
  #
126
- def self.from_aggregate_target(aggregate_target)
150
+ def self.from_aggregate_target(sandbox, aggregate_target)
127
151
  build_settings = {}
128
152
  aggregate_target.user_build_configurations.keys.each do |configuration|
129
153
  build_settings[configuration] = Digest::MD5.hexdigest(aggregate_target.build_settings(configuration).xcconfig.to_s)
130
154
  end
131
155
 
132
- TargetCacheKey.new(:aggregate, 'BUILD_SETTINGS_CHECKSUM' => build_settings)
156
+ TargetCacheKey.new(sandbox, :aggregate, 'BUILD_SETTINGS_CHECKSUM' => build_settings)
133
157
  end
134
158
  end
135
159
  end
@@ -56,13 +56,17 @@ module Pod
56
56
 
57
57
  # Constructs a TargetMetadata instance from a native target.
58
58
  #
59
+ # @param [Sandbox] sandbox
60
+ # The sandbox used for this installation.
61
+ #
59
62
  # @param [PBXNativeTarget] native_target
60
63
  # The native target used to construct a TargetMetadata instance.
61
64
  #
62
65
  # @return [TargetMetadata]
63
66
  #
64
- def self.from_native_target(native_target)
65
- TargetMetadata.new(native_target.name, native_target.uuid, native_target.project.path.to_s)
67
+ def self.from_native_target(sandbox, native_target)
68
+ TargetMetadata.new(native_target.name, native_target.uuid,
69
+ native_target.project.path.relative_path_from(sandbox.root).to_s)
66
70
  end
67
71
  end
68
72
  end
@@ -62,6 +62,14 @@ module Pod
62
62
 
63
63
  removed_sandbox_private_headers = sandbox_private_headers(pod_targets) - sandbox_private_headers_to_install
64
64
  removed_sandbox_private_headers.each { |path| remove_dir(path) }
65
+
66
+ project_dir_names_to_install = pod_targets.map do |pod_target|
67
+ sandbox.pod_target_project_path(pod_target.project_name)
68
+ end
69
+ project_dir_names = sandbox_project_dir_names - [sandbox.project_path]
70
+
71
+ removed_project_dir_names = project_dir_names - project_dir_names_to_install
72
+ removed_project_dir_names.each { |dir| remove_dir(dir) }
65
73
  end
66
74
  end
67
75
 
@@ -75,6 +83,10 @@ module Pod
75
83
  pod_targets.flat_map { |pod_target| child_directories_of(pod_target.build_headers.root) }.uniq
76
84
  end
77
85
 
86
+ def sandbox_project_dir_names
87
+ child_directories_of(sandbox.root).select { |d| d.extname == '.xcodeproj' }
88
+ end
89
+
78
90
  def sandbox_public_headers
79
91
  child_directories_of(sandbox.public_headers.root)
80
92
  end