GymPal/build-tools/hash.d

65 lines
1.9 KiB
D
Raw Normal View History

/**
* Helper for hashing the content of source files to determine if we need to
* re-compile certain sources.
*/
module hash;
import std.stdio;
import std.file;
import std.string;
import std.digest.md;
import std.base64;
const HASH_FILE = "bin/hash.txt";
/**
* Determines if the content of the source file at the given path matches
* the hash we have for it (if possible).
* Params:
* sourcePath = The path to the source file.
* Returns: True if we have a hash for the source file, and it matches the
* current hash of the file contents. False if we don't have a hash or it
* doesn't match.
*/
bool contentMatchesHash(string sourcePath) {
if (!exists(sourcePath) || !isFile(sourcePath)) return false;
string[string] hashes = readHashes();
if (sourcePath !in hashes) return false;
ubyte[16] rawHash = md5Of(readText(sourcePath));
ubyte[] savedHash = Base64.decode(hashes[sourcePath]);
return rawHash == savedHash;
}
/**
* Saves the hash of the given source path to the hash file.
* Params:
* sourcePath = The source path of the file to save.
*/
void saveHash(string sourcePath) {
if (!exists(sourcePath) || !isFile(sourcePath)) return;
ubyte[16] rawHash = md5Of(readText(sourcePath));
string hash = Base64.encode(rawHash);
string[string] hashes = readHashes();
hashes[sourcePath] = hash;
saveHashes(hashes);
}
private string[string] readHashes() {
string[string] hashes;
if (!exists(HASH_FILE)) return hashes;
auto file = File(HASH_FILE, "r");
foreach (string line; lines(file)) {
string[] parts = split(line, ":");
string sourcePath = parts[0].strip;
string hashBase64 = parts[1].strip;
hashes[sourcePath] = hashBase64;
}
return hashes;
}
private void saveHashes(string[string] hashes) {
auto file = File(HASH_FILE, "w");
foreach (string sourcePath, string hash; hashes) {
file.writefln!"%s:%s"(sourcePath, hash);
}
}