Class: Pod::PrebuildCache::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods-binary-matchup/Integration_cache.rb

Constant Summary collapse

@@dependency_graph =

类变量用于跟踪依赖关系和失效的pod

{}

Class Method Summary collapse

Class Method Details

.build_simple_dependency_graph(target, total_targets) ⇒ Object

构建简单的依赖关系图(从targets获取)



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 221

def self.build_simple_dependency_graph(target, total_targets)                
    return if total_targets.nil? || total_targets.empty?
    
    Pod::UI.puts "🔍 Building reverse dependency graph for cache validation..."
    begin
        pod_name = target.pod_name
        @@dependency_graph[pod_name] = []
        dependencies = []
        temp_dependencies = find_reverse_dependencies(target, total_targets)
        if !temp_dependencies.nil?
            dependencies = temp_dependencies
        end

        @@dependency_graph[pod_name] = dependencies                    
    rescue => e
        Pod::UI.puts "⚠️  Warning: Error processing target #{target}: #{e.message}"
    end                
end

.cache_dir_for_pod(pod_name) ⇒ Object

获取特定pod的缓存目录



29
30
31
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 29

def self.cache_dir_for_pod(pod_name)
    File.join(cache_root_dir, pod_name)
end

.cache_exists?(pod_name) ⇒ Boolean

检查缓存是否存在

Returns:

  • (Boolean)


87
88
89
90
91
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 87

def self.cache_exists?(pod_name)
    cache_dir = cache_dir_for_pod(pod_name)
    Pod::UI.puts "🔍 cache_exists? #{cache_dir}"
    Dir.exist?(cache_dir) && !Dir.empty?(cache_dir)
end

.cache_root_dirObject

获取缓存根目录



17
18
19
20
21
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 17

def self.cache_root_dir
    cache_dir = File.expand_path("~/.PodCache/#{Pod.main_deployment_target_name}")
    FileUtils.mkdir_p(cache_dir) unless Dir.exist?(cache_dir)
    cache_dir
end

.cached_manifest_pathObject

获取manifest.lock缓存路径



24
25
26
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 24

def self.cached_manifest_path
    File.join(cache_root_dir, 'Manifest.lock')
end

.cascade_invalidate_dependents(invalidated_pod) ⇒ Object

级联失效依赖当前pod的其他pod



265
266
267
268
269
270
271
272
273
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 265

def self.cascade_invalidate_dependents(invalidated_pod)                
    # 查找所有依赖invalidated_pod的pod
    dependenciess = @@dependency_graph[invalidated_pod]
    return if dependenciess.nil? || !dependenciess.any?
    invalidate_pod_cache(invalidated_pod)
    dependenciess.each do |dependent_pod|
        invalidate_pod_cache(dependent_pod)
    end
end

.clear_all_cachesObject

清空所有缓存



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 143

def self.clear_all_caches
    begin
        cache_dir = cache_root_dir
        
        # 删除除了cached_manifest.lock之外的所有缓存
        Dir.glob("#{cache_dir}/*").each do |path|
            next if File.basename(path) == 'Manifest.lock'
            
            if Dir.exist?(path)
                FileUtils.rm_rf(path)
                Pod::UI.puts "🗑️  Cleared cache directory: #{File.basename(path)}"
            end
        end
        
        Pod::UI.puts "✅ All pod caches cleared due to dependency changes"
        
    rescue => e
        Pod::UI.puts "❌ Error clearing caches: #{e.message}"
    end
end

.find_reverse_dependencies(target_to_find, all_pod_targets) ⇒ Object

获取指定target的反向依赖(哪些targets依赖于它)



209
210
211
212
213
214
215
216
217
218
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 209

def self.find_reverse_dependencies(target_to_find, all_pod_targets)
    reverse_deps = all_pod_targets.select do |pod_target|
        # 跳过自己
        next false if pod_target.pod_name == target_to_find.pod_name
        # 检查当前pod_target的正向递归依赖中是否包含目标target
        pod_target.recursive_dependent_targets.include?(target_to_find)
    end

    reverse_deps.map { |item| item.pod_name }
end

.get_cached_pod_version(pod_name, cached_manifest_path) ⇒ Object

从缓存的manifest中获取pod版本(复用get_pod_version的逻辑)



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 192

def self.get_cached_pod_version(pod_name, cached_manifest_path)
    begin
        # 使用缓存目录作为根目录创建PrebuildSandbox
        # 因为Manifest.lock就在cache_root_dir下,可以直接使用
        cache_dir = File.dirname(cached_manifest_path)
        temp_sandbox = Pod::PrebuildSandbox.new(cache_dir)
        
        # 复用现有的get_pod_version逻辑
        return get_pod_version(temp_sandbox, pod_name)
        
    rescue => e
        Pod::UI.puts "⚠️  Error reading cached version for #{pod_name}: #{e.message}"
        return "unknown"
    end
end

.get_pod_version(sandbox, pod_name) ⇒ Object

获取pod的版本信息,优先使用commit hash



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
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 34

def self.get_pod_version(sandbox, pod_name)
    UI.puts "🔍 starting get pod version: #{pod_name}"
    UI.puts "🔍 get_pod_version sandbox: #{sandbox.manifest_path}"
    checkout_options = sandbox.manifest.checkout_options_for_pod_named(pod_name)
    # 优先使用checkout_options中的检出来源
    if checkout_options
        UI.puts "🔍 get pod checkout version: #{pod_name}"
        if checkout_options[:tag]
            UI.puts "🔍 get pod checkout version tag: #{pod_name}# - #{checkout_options[:tag]}"
            return checkout_options[:tag]
        end
        if checkout_options[:branch]
            UI.puts "🔍 get pod checkout version branch: #{pod_name}# - #{checkout_options[:branch]}"
            return checkout_options[:branch]
        end
        if checkout_options[:commit]
            UI.puts "🔍 get pod checkout version commit: #{pod_name}# - #{checkout_options[:commit]}"
            return checkout_options[:commit]
        end
    end

    # 如果checkout_options中没有版本信息,则使用dependency中的版本信息
    dependency = sandbox.manifest.dependencies.find { |d| d.name == pod_name }
    if dependency
        UI.puts "🔍 get pod dependency version: #{pod_name}"
        external_source = dependency.external_source
        if external_source
            UI.puts "🔍 get pod dependency version podspec: #{external_source}"
            if external_source[:commit]
                UI.puts "🔍 get pod dependency version commit: #{pod_name}# - #{external_source[:commit]}"
                return external_source[:commit]
            end
            if external_source[:branch]
                UI.puts "🔍 get pod dependency version branch: #{pod_name}# - #{external_source[:branch]}"
                return external_source[:branch]
            end
        end
    end

    # 如果checkout_options和dependency中没有版本信息,则使用podspec中的version
    UI.puts "🔍 get pod spec version: #{pod_name}"
    version = sandbox.manifest.version(pod_name).version
    if version
        UI.puts "🔍 get pod spec version: #{pod_name}# - #{version}"
        return version
    end

    # 如果以上都失败,则返回unknown,理论上只要是正常的podfile.lock或者manifest.lock,都不会走到这里
    UI.puts "🔍 get pod version failed: #{pod_name}"
    return "unknown"
end

.invalidate_pod_cache(pod_name) ⇒ Object

删除pod的缓存



241
242
243
244
245
246
247
248
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 241

def self.invalidate_pod_cache(pod_name)
    cache_dir = cache_dir_for_pod(pod_name)
    Pod::UI.puts "🗑️ start Removed invalid cache for #{pod_name}"
    if Dir.exist?(cache_dir)
        FileUtils.rm_rf(cache_dir)
        Pod::UI.puts "🗑️ end  Removed invalid cache for #{pod_name}"
    end
end

.remove_all_invalid_cache(sandbox, all_targets) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 250

def self.remove_all_invalid_cache(sandbox, all_targets)
    all_targets.each do |target|
        build_simple_dependency_graph(target, all_targets)
        current_version = get_pod_version(sandbox, target.pod_name)
        if validate_pod_version_consistency(target.pod_name, current_version)
            Pod::UI.puts "🔍 validate_pod_version_consistency #{target.pod_name} #{current_version}"
        else
            cascade_invalidate_dependents(target.pod_name)
            Pod::UI.puts "❌ validate_pod_version_consistency #{target.pod_name} #{current_version}"
        end
    end
    Pod::UI.puts "📊 Dependency graph: #{@@dependency_graph}"
end

.reset_dependency_validation(sandbox = nil) ⇒ Object

重置依赖验证状态并检查manifest一致性



276
277
278
279
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 276

def self.reset_dependency_validation(sandbox = nil)
    @@dependency_graph.clear
    Pod::UI.puts "🔄 Reset dependency validation state"
end

.restore_from_pod_cache(pod_name, prebuild_sandbox) ⇒ Object

从 ~/.PodCache 恢复缓存到 _prebuild 目录(版本感知版)



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 282

def self.restore_from_pod_cache(pod_name, prebuild_sandbox)
    begin
        Pod::UI.puts "🔍 Checking cache for #{pod_name}"
        
        # 获取pod版本信息
        pod_version = get_pod_version(prebuild_sandbox, pod_name)
        
        # 检查缓存是否存在
        unless cache_exists?(pod_name)
            Pod::UI.puts "⚠️  No cache found for #{pod_name}"
            return false
        end
        
        # 所有验证通过,从缓存恢复
        cache_dir = cache_dir_for_pod(pod_name)
        target_dir = prebuild_sandbox.framework_folder_path_for_pod_name(pod_name)
        
        # 确保目标目录存在
        target_dir.parent.mkpath unless target_dir.parent.exist?
        
        # 复制缓存到_prebuild
        FileUtils.cp_r(cache_dir, target_dir, :remove_destination => true)
        
        # 删除缓存标记文件
        hash_file = target_dir + '.cache_hash'
        hash_file.delete if hash_file.exist?
        
        Pod::UI.puts "📦 Successfully restored #{pod_name} (#{pod_version}) from cache"
        return true
        
    rescue => e
        Pod::UI.puts "❌ Error restoring from cache: #{e.message}"
        # 出错时也标记为失效
        return false
    end
end

.save_manifest_to_cache(sandbox) ⇒ Object

保存当前manifest.lock到缓存目录



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 122

def self.save_manifest_to_cache(sandbox)
    begin
        # 查找_Prebuild目录中的manifest.lock
        prebuild_manifest = sandbox.root + 'Manifest.lock'
        # 如果存在,复制到缓存目录
        if prebuild_manifest.exist?
            cached_path = cached_manifest_path
            FileUtils.cp(prebuild_manifest, cached_path)
            Pod::UI.puts "💾 save_manifest_to_cache Manifest.lock to cache: #{cached_path}"
            return true
        else
            Pod::UI.puts "⚠️ save_manifest_to_cache Manifest.lock not found in _Prebuild directory"
            return false
        end
    rescue => e
        Pod::UI.puts "❌ save_manifest_to_cache save Manifest.lock to cache failed: #{e.message}"
        return false
    end
end

.save_to_cache(pod_name, source_dir) ⇒ Object

保存到缓存(如果缓存不存在的话)



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
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 94

def self.save_to_cache(pod_name, source_dir)
    return unless Dir.exist?(source_dir)
    
    # 检查缓存是否已经存在,如果存在则不覆盖
    if cache_exists?(pod_name)
        Pod::UI.puts "📦 Cache already exists for #{pod_name}, skipping save"
        return true
    end
    
    cache_dir = cache_dir_for_pod(pod_name)
    
    begin
        # 创建缓存目录
        FileUtils.mkdir_p(File.dirname(cache_dir))
        
        # 删除旧缓存(如果存在)
        FileUtils.rm_rf(cache_dir) if Dir.exist?(cache_dir)
        
        # 拷贝到缓存
        FileUtils.cp_r(source_dir, cache_dir, :remove_destination => true)
        return true
    rescue => e
        Pod::UI.puts "❌ Failed to save #{pod_name} to cache: #{e.message}"
        return false
    end
end

.validate_pod_version_consistency(pod_name, current_version) ⇒ Object

验证pod版本一致性(与缓存时的manifest对比)



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 165

def self.validate_pod_version_consistency(pod_name, current_version)
    begin
        manifest_path = cached_manifest_path
        Pod::UI.puts "🔍 validate_pod_version_consistency pod_name: #{pod_name} manifest_path: #{manifest_path}"
        # 如果没有缓存的manifest,认为一致(首次构建)
        unless File.exist?(manifest_path)
            return true
        end
        
        # 创建基于缓存manifest的临时sandbox来获取缓存版本
        cached_version = get_cached_pod_version(pod_name, cached_manifest_path)
        
        # 对比版本
        if current_version == cached_version
            return true
        else
            Pod::UI.puts "🔄 #{pod_name} version changed: #{cached_version} → #{current_version}"
            return false
        end
        
    rescue => e
        Pod::UI.puts "⚠️  Error validating version consistency for #{pod_name}: #{e.message}"
        return false
    end
end