import readdir from "readdir-enhanced"; import fs from "fs"; import crypto from "crypto"; import multimatch from "multimatch"; function applyExcludeFilter(stat, excludeFilters) { // match exclude, return immediatley if (excludeFilters.length > 0) { // todo this could be a performance problem... const pathWithFolderSlash = stat.path + (stat.isDirectory() ? "/" : ""); const excludeMatch = multimatch(pathWithFolderSlash, excludeFilters, { matchBase: true, dot: true }); if (excludeMatch.length > 0) { return false; } } return true; } /** * @param algorithm : "md5" | "sha1" | "sha256" | "sha512" */ async function fileHash(filename, algorithm) { return new Promise((resolve, reject) => { // Algorithm depends on availability of OpenSSL on platform // Another algorithms: "sha1", "md5", "sha256", "sha512" ... let shasum = crypto.createHash(algorithm); try { let s = fs.createReadStream(filename); s.on("data", function (data) { shasum.update(data) }); s.on("error", function (error) { reject(error); }); // making digest s.on("end", function () { const hash = shasum.digest("hex") return resolve(hash); }); } catch (error) { return reject("calc fail"); } }); } function createLocalState(localFiles, args) { console.log(`Creating local state at ${args["local-dir"]}${args["state-name"]}`); fs.writeFileSync(`${args["local-dir"]}${args["state-name"]}`, JSON.stringify(localFiles, undefined, 4), { encoding: "utf8" }); console.log("Local state created"); } async function getLocalFiles(args) { const files = await readdir.async(args["local-dir"], { deep: true, stats: true, sep: "/", filter: (stat) => applyExcludeFilter(stat, args.exclude) }); let records = []; for (let stat of files) { if (stat.isDirectory()) { records.push({ type: "folder", name: stat.path, size: undefined }); continue; } if (stat.isFile()) { records.push({ type: "file", name: stat.path, size: stat.size, hash: await fileHash(args["local-dir"] + stat.path, "sha256") }); continue; } if (stat.isSymbolicLink()) { console.warn("This script is currently unable to handle symbolic links - please add a feature request if you need this"); } } return { description: 'Don\'t delete', version: '1.0.0', generatedTime: new Date().getTime(), data: records }; } try { const filename = ".generate-file-hash.json"; const _args = { 'local-dir': './', 'state-name': filename, 'exclude': [ '**/node_modules/**', '**/.git*/**', '**/.git*/**', filename, ] }; const localFiles = await getLocalFiles(_args); createLocalState(localFiles, _args); } catch (error) { console.log(error); }