import fg from "fast-glob"; import fs from "fs"; import assert from "assert"; import { log } from "./logging.js"; import Path from "path"; import { execSync } from "child_process"; // fast-glob is old and can't do import as export const glob = (path) => { if(process.platform === "win32") { // fast-glob doesn't understand \\ or C:\ const fixed_path = path.replace("C:","").replaceAll('\\', '/') return fg.sync(fixed_path); } else { return fg.sync(path); } } export const changed = (source, target) => { // we want the source to error if it doesn't exist const s_stat = fs.statSync(source); // but target might not exist, which would mean it's a change const t_stat = fs.statSync(target, {throwIfNoEntry: false}); return !t_stat || s_stat.mtimeMs > t_stat.mtimeMs; } export const mkdir = (dir) => { /* Makes a directory recursively. */ if(!fs.existsSync(dir)) { log.debug(`making dir ${dir}`); fs.mkdirSync(dir, { recursive: true }); } } /** * Given any path to a file, makes sure all its directories are in place. * * @param { string } -- path to file */ export const mkdir_to = (target) => { let dirs = Path.parse(target); mkdir(dirs.dir); } export const write = (target, data) => { /* Convenience function that makes sure the dir is there then writes the data. */ mkdir_to(target); fs.writeFileSync(target, data); } export const copy = (src, dest, filter=null) => { /** Like write but does an OS copy after making the target dir. When given a * filter it will give the filter function the arguments, let it return contents, * then write those instead of a copy. */ mkdir_to(dest); if(filter) { try { let raw_data = fs.readFileSync(src); let data = filter(src, dest, raw_data); write(dest, data); } catch (error) { log.error(error, "Problem with filter write in copy"); } } else { fs.copyFileSync(src, dest); } } export const rm = (file_name, ignore=false) => { log.warn("Deleting file", file_name); try { fs.unlinkSync(file_name); } catch(error) { if(ignore) { log.debug(`Requested delete file ${file_name} doesn't exist, but ignored.`); } else { log.error(error, file_name); throw error; } } } export const index_rollup = (src_index, target_index, contents, key) => { let index = JSON.parse(fs.readFileSync(src_index)); index[key] = glob(contents).map(f => JSON.parse(fs.readFileSync(f))); assert(index[key] !== undefined, `Attempt to load contents into ${key} for ${src_index} failed with undefined.`); write(target_index, JSON.stringify(index)); return index; } export const exec = (cmd, opts) => { log.info(`EXEC ${cmd}`); return execSync(cmd, opts); } export const exec_i = (cmd, opts={}) => { return exec(cmd, {stdio: [process.stdout, process.stderr, process.stdin], ...opts}); } export default { index_rollup, rm, exec, changed, mkdir, mkdir_to, write, copy, exec_i, glob }