CHGenerator/Sources/Generator/Files/FileUpdateChecker.swift
2022-09-18 16:48:15 +02:00

89 lines
2.5 KiB
Swift

import Foundation
import CryptoKit
final class FileUpdateChecker {
private static let hashesFileName = "hashes.json"
private let input: URL
private var hashesFile: URL {
input.appendingPathComponent(FileUpdateChecker.hashesFileName)
}
/**
The hashes of all accessed files from the previous run
The key is the relative path to the file from the source
*/
private var previousFiles: [String : Data] = [:]
/**
The paths of all files which were accessed, with their new hashes
This list is used to check if a file was modified, and to write all accessed files back to disk
*/
private var accessedFiles: [String : Data] = [:]
private var source: String {
"FileUpdateChecker"
}
init(input: URL) {
self.input = input
guard hashesFile.exists else {
log.add(info: "No file hashes loaded, regarding all content as new", source: source)
return
}
let data: Data
do {
data = try Data(contentsOf: hashesFile)
} catch {
log.add(
warning: "File hashes could not be read, regarding all content as new",
source: source,
error: error)
return
}
do {
self.previousFiles = try JSONDecoder().decode(from: data)
} catch {
log.add(
warning: "File hashes could not be decoded, regarding all content as new",
source: source,
error: error)
return
}
}
func fileHasChanged(at path: String) -> Bool {
guard let oldHash = previousFiles[path] else {
// Image wasn't used last time, so treat as new
return true
}
guard let newHash = accessedFiles[path] else {
// Each image should have been loaded once
// before using this function
fatalError()
}
return oldHash != newHash
}
func didLoad(_ data: Data, at path: String) {
accessedFiles[path] = SHA256.hash(data: data).data
}
func writeDetectedFileChangesToDisk() {
do {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(accessedFiles)
try data.write(to: hashesFile)
} catch {
log.add(warning: "Failed to save file hashes", source: source, error: error)
}
}
}