UNPKG

link-unlink

Version:

Link and unlink with saving and restoring the previous file or directory

50 lines (49 loc) 1.95 kB
import fs from 'fs'; import { Lock } from 'lock'; import path from 'path'; import Queue from 'queue-cb'; import rimraf2 from 'rimraf2'; const lock = Lock(); function restoreLink(previous, target, callback) { rimraf2(target, { disableGlob: true }, (err)=>{ err ? callback(err) : fs.rename(previous, target, callback); }); } function worker(target, callback) { lock(target, (release)=>{ callback = release(callback); const dirname = path.dirname(target); const basename = path.basename(target); fs.readdir(dirname, (err, files)=>{ if (err) return callback(err); const matches = files.filter((x)=>x.indexOf(basename) === 0 && x.slice(basename.length)[0] === '.').map((x)=>path.join(dirname, x)); if (matches.length === 0) return rimraf2(target, { disableGlob: true }, callback); if (matches.length === 1) return restoreLink(matches[0], target, callback); const stats = []; const queue = new Queue(); matches.forEach((match)=>queue.defer((cb)=>{ fs.lstat(match, (err, stat)=>{ if (err) return callback(err); stats.push({ match, stat }); cb(); }); })); queue.await((err)=>{ if (err) return callback(err); const sorted = stats.sort((a, b)=>b.stat.ctime.valueOf() - a.stat.ctime.valueOf()); restoreLink(sorted[0].match, target, callback); }); }); }); } export default function link(target, callback) { if (typeof callback === 'function') return worker(target, callback); return new Promise((resolve, reject)=>worker(target, (err, restore)=>err ? reject(err) : resolve(restore))); }