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

101 lines
3.8 KiB
Swift

#if canImport(CryptoSwift)
import CryptoSwift
#endif
import Foundation
extension Configuration {
// MARK: Caching Configurations By Identifier (In-Memory)
private static var cachedConfigurationsByIdentifier = [String: Configuration]()
private static var cachedConfigurationsByIdentifierLock = NSLock()
/// Since the cache is stored in a static var, this function is used to reset the cache during tests
internal static func resetCache() {
Self.cachedConfigurationsByIdentifierLock.lock()
Self.cachedConfigurationsByIdentifier = [:]
Self.cachedConfigurationsByIdentifierLock.unlock()
}
internal func setCached(forIdentifier identifier: String) {
Self.cachedConfigurationsByIdentifierLock.lock()
Self.cachedConfigurationsByIdentifier[identifier] = self
Self.cachedConfigurationsByIdentifierLock.unlock()
}
internal static func getCached(forIdentifier identifier: String) -> Configuration? {
cachedConfigurationsByIdentifierLock.lock()
defer { cachedConfigurationsByIdentifierLock.unlock() }
return cachedConfigurationsByIdentifier[identifier]
}
/// Returns a copy of the current `Configuration` with its `computedCacheDescription` property set to the value of
/// `cacheDescription`, which is expensive to compute.
///
/// - returns: A new `Configuration` value.
public func withPrecomputedCacheDescription() -> Configuration {
var result = self
result.computedCacheDescription = result.cacheDescription
return result
}
// MARK: Nested Config Is Self Cache
private static var nestedConfigIsSelfByIdentifier = [String: Bool]()
private static var nestedConfigIsSelfByIdentifierLock = NSLock()
internal static func setIsNestedConfigurationSelf(forIdentifier identifier: String, value: Bool) {
Self.nestedConfigIsSelfByIdentifierLock.lock()
Self.nestedConfigIsSelfByIdentifier[identifier] = value
Self.nestedConfigIsSelfByIdentifierLock.unlock()
}
internal static func getIsNestedConfigurationSelf(forIdentifier identifier: String) -> Bool {
Self.nestedConfigIsSelfByIdentifierLock.lock()
defer { Self.nestedConfigIsSelfByIdentifierLock.unlock() }
return Self.nestedConfigIsSelfByIdentifier[identifier] ?? false
}
// MARK: SwiftLint Cache (On-Disk)
internal var cacheDescription: String {
if let computedCacheDescription {
return computedCacheDescription
}
let cacheRulesDescriptions = rules
.map { rule in [type(of: rule).description.identifier, rule.cacheDescription] }
.sorted { $0[0] < $1[0] }
let jsonObject: [Any] = [rootDirectory, cacheRulesDescriptions]
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject) {
return jsonData.sha256().toHexString()
}
queuedFatalError("Could not serialize configuration for cache")
}
internal var cacheURL: URL {
let baseURL: URL
if let path = cachePath {
baseURL = URL(fileURLWithPath: path, isDirectory: true)
} else {
#if os(Linux)
baseURL = URL(fileURLWithPath: "/var/tmp/", isDirectory: true)
#else
baseURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
#endif
}
let versionedDirectory = [
"SwiftLint",
Version.current.value,
ExecutableInfo.buildID
].compactMap({ $0 }).joined(separator: "/")
let folder = baseURL.appendingPathComponent(versionedDirectory)
do {
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true, attributes: nil)
} catch {
queuedPrintError("Error while creating cache: " + error.localizedDescription)
}
return folder
}
}