/
target_cache_key.rb
176 lines (160 loc) · 6.77 KB
/
target_cache_key.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
module Pod
class Installer
module ProjectCache
# Uniquely identifies a Target.
#
class TargetCacheKey
require 'cocoapods/target/pod_target.rb'
require 'cocoapods/target/aggregate_target.rb'
require 'digest'
# @return [Sandbox] The sandbox where the Pods should be installed.
#
attr_reader :sandbox
# @return [Symbol]
# The type of target. Either aggregate or pod target.
#
attr_reader :type
# @return [Hash{String => Object}]
# The hash containing key-value pairs that identify the target.
#
attr_reader :key_hash
# Initialize a new instance.
#
# @param [Sandbox] sandbox see #sandbox
# @param [Symbol] type @see #type
# @param [Hash{String => Object}] key_hash @see #key_hash
#
def initialize(sandbox, type, key_hash)
@sandbox = sandbox
@type = type
@key_hash = key_hash
end
# Equality function used to compare TargetCacheKey objects to each other.
#
# @param [TargetCacheKey] other
# Other object to compare itself against.
#
# @return [Symbol] The difference between this and another TargetCacheKey object.
# # Symbol :none means no difference.
#
def key_difference(other)
if other.type != type
:project
else
case type
when :pod_target
return :project if (other.key_hash.keys - key_hash.keys).any?
return :project if other.key_hash['CHECKSUM'] != key_hash['CHECKSUM']
return :project if other.key_hash['SPECS'] != key_hash['SPECS']
return :project if other.key_hash['PROJECT_NAME'] != key_hash['PROJECT_NAME']
end
this_files = key_hash['FILES']
other_files = other.key_hash['FILES']
return :project if this_files != other_files
this_build_settings = key_hash['BUILD_SETTINGS_CHECKSUM']
other_build_settings = other.key_hash['BUILD_SETTINGS_CHECKSUM']
return :project if this_build_settings != other_build_settings
this_checkout_options = key_hash['CHECKOUT_OPTIONS']
other_checkout_options = other.key_hash['CHECKOUT_OPTIONS']
return :project if this_checkout_options != other_checkout_options
:none
end
end
def to_h
key_hash
end
# @return [String]
# The name of the project the target belongs to.
#
def project_name
key_hash['PROJECT_NAME']
end
# Creates a TargetCacheKey instance from the given hash.
#
# @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
#
# @param [Hash{String => Object}] key_hash
# The hash used to construct a TargetCacheKey object.
#
# @return [TargetCacheKey]
#
def self.from_cache_hash(sandbox, key_hash)
cache_hash = key_hash.dup
if files = cache_hash['FILES']
cache_hash['FILES'] = files.sort_by(&:downcase)
end
if specs = cache_hash['SPECS']
cache_hash['SPECS'] = specs.sort_by(&:downcase)
end
type = cache_hash['CHECKSUM'] ? :pod_target : :aggregate
TargetCacheKey.new(sandbox, type, cache_hash)
end
# Constructs a TargetCacheKey instance from a PodTarget.
#
# @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
#
# @param [PodTarget] pod_target
# The pod target used to construct a TargetCacheKey object.
#
# @param [Boolean] is_local_pod
# Used to also include its local files in the cache key.
#
# @param [Hash] checkout_options
# The checkout options for this pod target.
#
# @return [TargetCacheKey]
#
def self.from_pod_target(sandbox, pod_target, is_local_pod: false, checkout_options: nil)
build_settings = {}
build_settings[pod_target.label.to_s] = Hash[pod_target.build_settings.map do |k, v|
[k, Digest::MD5.hexdigest(v.xcconfig.to_s)]
end]
pod_target.test_spec_build_settings_by_config.each do |name, settings_by_config|
build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
end
pod_target.app_spec_build_settings_by_config.each do |name, settings_by_config|
build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
end
contents = {
'CHECKSUM' => pod_target.root_spec.checksum,
'SPECS' => pod_target.specs.map(&:to_s).sort_by(&:downcase),
'BUILD_SETTINGS_CHECKSUM' => build_settings,
'PROJECT_NAME' => pod_target.project_name,
}
if is_local_pod
relative_file_paths = pod_target.all_files.map { |f| f.relative_path_from(sandbox.root).to_s }
contents['FILES'] = relative_file_paths.sort_by(&:downcase)
end
contents['CHECKOUT_OPTIONS'] = checkout_options if checkout_options
TargetCacheKey.new(sandbox, :pod_target, contents)
end
# Construct a TargetCacheKey instance from an AggregateTarget.
#
# @param [Sandbox] sandbox The sandbox to use to construct a TargetCacheKey object.
#
# @param [AggregateTarget] aggregate_target
# The aggregate target used to construct a TargetCacheKey object.
#
# @return [TargetCacheKey]
#
def self.from_aggregate_target(sandbox, aggregate_target)
build_settings = {}
aggregate_target.user_build_configurations.keys.each do |configuration|
build_settings[configuration] = Digest::MD5.hexdigest(aggregate_target.build_settings(configuration).xcconfig.to_s)
end
contents = {
'BUILD_SETTINGS_CHECKSUM' => build_settings,
}
if aggregate_target.includes_resources? || aggregate_target.includes_on_demand_resources?
relative_resource_file_paths = aggregate_target.resource_paths_by_config.values.flatten.uniq
relative_on_demand_resource_file_paths = aggregate_target.on_demand_resources.map do |res|
res.relative_path_from(sandbox.project_path.dirname).to_s
end
contents['FILES'] = (relative_resource_file_paths + relative_on_demand_resource_file_paths).sort_by(&:downcase)
end
TargetCacheKey.new(sandbox, :aggregate, contents)
end
end
end
end
end