You could iteratively walk the directories, stat the directory and each file it contains, not following links and produce a hash. Here's an example:
'use strict';
// npm install siphash
var siphash = require('siphash');
// npm install walk
var walk = require('walk');
var key = siphash.string16_to_key('0123456789ABCDEF');
var walker = walk.walk('/tmp', {followLinks: false});
walker.on('directories', directoryHandler);
walker.on('file', fileHandler);
walker.on('errors', errorsHandler); // plural
walker.on('end', endHandler);
var directories = {};
var directoryHashes = [];
function addRootDirectory(name, stats) {
directories[name] = directories[name] || {
fileStats: []
};
if(stats.file) directories[name].fileStats.push(stats.file);
else if(stats.dir) directories[name].dirStats = stats.dir;
}
function directoryHandler(root, dirStatsArray, next) {
addRootDirectory(root, {dir:dirStatsArray});
next();
}
function fileHandler(root, fileStat, next) {
addRootDirectory(root, {file:fileStat});
next();
}
function errorsHandler(root, nodeStatsArray, next) {
nodeStatsArray.forEach(function (n) {
console.error('[ERROR] ' + n.name);
console.error(n.error.message || (n.error.code + ': ' + n.error.path));
});
next();
}
function endHandler() {
Object.keys(directories).forEach(function (dir) {
var hash = siphash.hash_hex(key, JSON.stringify(dir));
directoryHashes.push({
dir: dir,
hash: hash
});
});
console.log(directoryHashes);
}
You would want of course to turn this into some kind of command-line app to take arguments probably and double check that the files are returned in the correct order every time (maybe sort the file stats based on file name prior to hashing!) so that siphash returns the right hash every time.
This is not tested code.. just to provide an example of where I'd likely start with that sort of thing.
Edit: and to reduce dependencies, you could use Node's crypto lib instead of siphash if you want require('crypto');
and walk/stat the directories and files yourself if you'd like of course.