93 lines
2.4 KiB
Swift
93 lines
2.4 KiB
Swift
import Foundation
|
|
import CryptoKit
|
|
|
|
final class FileUpdateChecker {
|
|
|
|
private let hashesFileName = "hashes.json"
|
|
|
|
private let input: URL
|
|
|
|
/**
|
|
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] = [:]
|
|
|
|
var numberOfFilesLoaded: Int {
|
|
previousFiles.count
|
|
}
|
|
|
|
var numberOfFilesAccessed: Int {
|
|
accessedFiles.count
|
|
}
|
|
|
|
init(input: URL) {
|
|
self.input = input
|
|
}
|
|
|
|
enum LoadResult {
|
|
case notLoaded
|
|
case loaded
|
|
case failed(String)
|
|
}
|
|
|
|
func loadPreviousRun(from folder: URL) -> LoadResult {
|
|
let url = folder.appendingPathComponent(hashesFileName)
|
|
guard url.exists else {
|
|
return .notLoaded
|
|
}
|
|
let data: Data
|
|
do {
|
|
data = try Data(contentsOf: url)
|
|
} catch {
|
|
return .failed("Failed to read hashes from last run: \(error)")
|
|
}
|
|
do {
|
|
self.previousFiles = try JSONDecoder().decode(from: data)
|
|
} catch {
|
|
return .failed("Failed to decode hashes from last run: \(error)")
|
|
}
|
|
return .loaded
|
|
}
|
|
|
|
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 writeDetectedFileChanges(to folder: URL) -> String? {
|
|
let url = folder.appendingPathComponent(hashesFileName)
|
|
do {
|
|
let encoder = JSONEncoder()
|
|
encoder.outputFormatting = .prettyPrinted
|
|
let data = try encoder.encode(accessedFiles)
|
|
try data.write(to: url)
|
|
return nil
|
|
} catch {
|
|
return "Failed to save file hashes: \(error)"
|
|
}
|
|
}
|
|
}
|
|
|
|
var notFound = 0
|