89 lines
2.5 KiB
Swift
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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|