Class: Pod::PrebuildCache::Cache

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

Class Method Summary collapse

Class Method Details

.cache_dir_for_pod(pod_name, version) ⇒ Object

获取特定pod的缓存目录



21
22
23
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 21

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

.cache_exists?(pod_name, version) ⇒ Boolean

检查缓存是否存在

Returns:

  • (Boolean)


96
97
98
99
100
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 96

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

.cache_root_dirObject

获取缓存根目录



13
14
15
16
17
18
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 13

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

.cache_statsObject

获取缓存统计信息



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 235

def self.cache_stats
    return {} unless Dir.exist?(cache_root_dir)
    
    stats = {
        total_pods: 0,
        total_versions: 0,
        total_size: 0
    }
    
    Dir.glob("#{cache_root_dir}/*").each do |pod_dir|
        next unless Dir.exist?(pod_dir)
        
        stats[:total_pods] += 1
        
        Dir.glob("#{pod_dir}/*").each do |version_dir|
            next unless Dir.exist?(version_dir)
            
            stats[:total_versions] += 1
            
            # 计算目录大小
            size = `du -sk "#{version_dir}" 2>/dev/null`.split.first.to_i * 1024
            stats[:total_size] += size
        end
    end
    
    stats
end

.cache_valid?(pod_name, version, source_dir = nil) ⇒ Boolean

检查缓存是否存在且有效(用于验证完整性)

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 103

def self.cache_valid?(pod_name, version, source_dir = nil)
    cache_dir = cache_dir_for_pod(pod_name, version)
    return false unless Dir.exist?(cache_dir)
    
    # 如果没有提供源目录,只检查缓存是否存在
    return true if source_dir.nil?
    
    # 检查缓存的哈希文件
    hash_file = File.join(cache_dir, '.cache_hash')
    return false unless File.exist?(hash_file)
    
    begin
        cached_hash = File.read(hash_file).strip
        current_hash = calculate_dir_hash(source_dir)
        
        return cached_hash == current_hash
    rescue => e
        Pod::UI.puts "⚠️  Warning: Cannot validate cache for #{pod_name}: #{e.message}"
        return false
    end
end

.calculate_dir_hash(dir_path) ⇒ Object

计算目录内容的哈希值(用于验证缓存完整性)



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 78

def self.calculate_dir_hash(dir_path)
    return nil unless Dir.exist?(dir_path)
    
    files = Dir.glob("#{dir_path}/**/*", File::FNM_DOTMATCH).select { |f| File.file?(f) }
    files.sort!
    
    hasher = Digest::SHA256.new
    files.each do |file|
        # 添加文件路径和修改时间到哈希计算中
        relative_path = file.sub("#{dir_path}/", "")
        hasher.update(relative_path)
        hasher.update(File.mtime(file).to_s)
    end
    
    hasher.hexdigest
end

.clean_expired_cache(days = 30) ⇒ Object

清理过期缓存(可选功能)



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 211

def self.clean_expired_cache(days = 30)
    return unless Dir.exist?(cache_root_dir)
    
    cutoff_time = Time.now - (days * 24 * 60 * 60)
    cleaned_count = 0
    
    Dir.glob("#{cache_root_dir}/*/*").each do |cache_dir|
        next unless Dir.exist?(cache_dir)
        
        if File.mtime(cache_dir) < cutoff_time
            begin
                FileUtils.rm_rf(cache_dir)
                cleaned_count += 1
                Pod::UI.puts "🗑️  Cleaned expired cache: #{File.basename(File.dirname(cache_dir))}/#{File.basename(cache_dir)}"
            rescue => e
                Pod::UI.puts "❌ Failed to clean cache #{cache_dir}: #{e.message}"
            end
        end
    end
    
    Pod::UI.puts "✅ Cleaned #{cleaned_count} expired cache entries" if cleaned_count > 0
end

.copy_from_cache_if_exists(pod_name, version, target_dir) ⇒ Object

尝试从缓存拷贝到目标目录(如果缓存存在)



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 186

def self.copy_from_cache_if_exists(pod_name, version, target_dir)
    return false unless cache_exists?(pod_name, version)
    
    cache_dir = cache_dir_for_pod(pod_name, version)
    
    begin
        # 删除目标目录
        FileUtils.rm_rf(target_dir) if Dir.exist?(target_dir)
        
        # 从缓存拷贝到目标目录
        FileUtils.cp_r(cache_dir, target_dir, :remove_destination => true)
        
        # 删除缓存标记文件
        hash_file = File.join(target_dir, '.cache_hash')
        File.delete(hash_file) if File.exist?(hash_file)
        
        Pod::UI.puts "📦 Copied #{pod_name} (#{version}) from cache"
        return true
    rescue => e
        Pod::UI.puts "❌ Failed to copy #{pod_name} from cache: #{e.message}"
        return false
    end
end

.get_pod_version(sandbox, pod_name) ⇒ Object

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



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

def self.get_pod_version(sandbox, pod_name)
    UI.puts "🔍 starting get pod version: #{pod_name}"
    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

打印缓存统计信息



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

def self.print_cache_stats
    stats = cache_stats
    if stats[:total_pods] > 0
        size_mb = (stats[:total_size] / 1024.0 / 1024.0).round(2)
        Pod::UI.puts "📊 Cache Stats: #{stats[:total_pods]} pods, #{stats[:total_versions]} versions, #{size_mb} MB"
    else
        Pod::UI.puts "📊 Cache is empty"
    end
end

.restore_from_cache(pod_name, version, target_dir) ⇒ Object

从缓存恢复pod



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 126

def self.restore_from_cache(pod_name, version, target_dir)
    cache_dir = cache_dir_for_pod(pod_name, version)
    
    return false unless Dir.exist?(cache_dir)
    
    begin
        # 删除目标目录
        FileUtils.rm_rf(target_dir) if Dir.exist?(target_dir)
        
        # 从缓存拷贝到目标目录
        FileUtils.cp_r(cache_dir, target_dir, :remove_destination => true)
        
        # 删除缓存标记文件
        hash_file = File.join(target_dir, '.cache_hash')
        File.delete(hash_file) if File.exist?(hash_file)
        
        Pod::UI.puts "📦 Restored #{pod_name} (#{version}) from cache"
        return true
    rescue => e
        Pod::UI.puts "❌ Failed to restore #{pod_name} from cache: #{e.message}"
        return false
    end
end

.restore_from_pod_cache(pod_name, prebuild_sandbox) ⇒ Object

从 ~/.PodCache 恢复缓存到 _prebuild 目录



275
276
277
278
279
280
281
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
318
319
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 275

def self.restore_from_pod_cache(pod_name, prebuild_sandbox)
    begin
        Pod::UI.puts "🔍 Checking cache for #{pod_name} #{prebuild_sandbox}"
        
        restored_count = 0
        missing_pods = []
        
        # 获取pod版本信息
        pod_version = get_pod_version(prebuild_sandbox, pod_name)
        
        # 检查缓存是否存在
        if cache_exists?(pod_name, pod_version)
            # 从缓存复制到_prebuild目录
            cache_dir = cache_dir_for_pod(pod_name, pod_version)
            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 "📦 Restored #{pod_name} (#{pod_version}) from cache"
            restored_count += 1
        else
            missing_pods << pod_name
        end
        
        if missing_pods.empty?
            Pod::UI.puts "✅ Successfully restored all #{restored_count} pods from cache"
            return true
        else
            Pod::UI.puts "⚠️  Missing cache for #{missing_pods.count} pods: #{missing_pods.join(', ')}"
            return false
        end
        
    rescue => e
        Pod::UI.puts "❌ Error restoring from cache: #{e.message}"
        return false
    end
end

.save_to_cache(pod_name, version, source_dir) ⇒ Object

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



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
177
178
179
180
181
182
183
# File 'lib/cocoapods-binary-matchup/Integration_cache.rb', line 151

def self.save_to_cache(pod_name, version, source_dir)
    return unless Dir.exist?(source_dir)
    
    # 检查缓存是否已经存在,如果存在则不覆盖
    if cache_exists?(pod_name, version)
        Pod::UI.puts "📦 Cache already exists for #{pod_name} (#{version}), skipping save"
        return true
    end
    
    cache_dir = cache_dir_for_pod(pod_name, version)
    
    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)
        
        # 保存哈希值
        source_hash = calculate_dir_hash(source_dir)
        hash_file = File.join(cache_dir, '.cache_hash')
        File.write(hash_file, source_hash)
        
        Pod::UI.puts "💾 Saved #{pod_name} (#{version}) to cache"
        return true
    rescue => e
        Pod::UI.puts "❌ Failed to save #{pod_name} to cache: #{e.message}"
        return false
    end
end