SwiftLint/Source/SwiftLintFramework/Extensions/Configuration+Cache.swift

95 lines
3.2 KiB
Swift

#if canImport(CommonCrypto)
import CommonCrypto
#else
import CryptoSwift
#endif
import Foundation
#if canImport(CommonCrypto)
private extension String {
func md5() -> String {
let context = UnsafeMutablePointer<CC_MD5_CTX>.allocate(capacity: 1)
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5_Init(context)
CC_MD5_Update(context, self, CC_LONG(lengthOfBytes(using: .utf8)))
CC_MD5_Final(&digest, context)
context.deallocate()
return digest.reduce(into: "") { $0.append(String(format: "%02x", $1)) }
}
}
#endif
extension Configuration {
// MARK: Caching Configurations By Path (In-Memory)
private static var cachedConfigurationsByPath = [String: Configuration]()
private static var cachedConfigurationsByPathLock = NSLock()
internal func setCached(atPath path: String) {
Configuration.cachedConfigurationsByPathLock.lock()
Configuration.cachedConfigurationsByPath[path] = self
Configuration.cachedConfigurationsByPathLock.unlock()
}
internal static func getCached(atPath path: String) -> Configuration? {
cachedConfigurationsByPathLock.lock()
defer { cachedConfigurationsByPathLock.unlock() }
return cachedConfigurationsByPath[path]
}
/// Returns a copy of the current `Configuration` with its `computedCacheDescription` property set to the value of
/// `cacheDescription`, which is expensive to compute.
public func withPrecomputedCacheDescription() -> Configuration {
var result = self
result.computedCacheDescription = result.cacheDescription
return result
}
// MARK: SwiftLint Cache (On-Disk)
internal var cacheDescription: String {
if let computedCacheDescription = computedCacheDescription {
return computedCacheDescription
}
let cacheRulesDescriptions = rules
.map { rule in
return [type(of: rule).description.identifier, rule.cacheDescription]
}
.sorted { rule1, rule2 in
return rule1[0] < rule2[0]
}
let jsonObject: [Any] = [
rootPath ?? FileManager.default.currentDirectoryPath,
cacheRulesDescriptions
]
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject),
let jsonString = String(data: jsonData, encoding: .utf8) {
return jsonString.md5()
}
queuedFatalError("Could not serialize configuration for cache")
}
internal var cacheURL: URL {
let baseURL: URL
if let path = cachePath {
baseURL = URL(fileURLWithPath: path)
} else {
#if os(Linux)
baseURL = URL(fileURLWithPath: "/var/tmp/")
#else
baseURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
#endif
}
let folder = baseURL.appendingPathComponent("SwiftLint/\(Version.current.value)")
do {
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true, attributes: nil)
} catch {
queuedPrintError("Error while creating cache: " + error.localizedDescription)
}
return folder
}
}