fs-safe-replace.js/index.js

101 lines
2.7 KiB
JavaScript
Raw Normal View History

2015-07-17 23:07:02 +00:00
'use strict';
var PromiseA = require('bluebird').Promise;
var fs = PromiseA.promisifyAll(require('fs'));
2015-12-15 06:07:54 +00:00
var crypto = require('crypto');
2015-07-17 23:07:02 +00:00
function noop() {
}
function create(options) {
2015-12-15 06:07:54 +00:00
2015-07-17 23:07:02 +00:00
if (!options) {
options = {};
}
2015-12-15 06:07:54 +00:00
if (!options.tmp) {
options.tmp = 'tmp';
2015-07-17 23:07:02 +00:00
}
if (!options.bak) {
options.bak = 'bak';
}
2015-12-15 06:07:54 +00:00
if (options.tmp === options.bak) {
throw new Error("'tmp' and 'bak' suffixes cannot be the same... duh");
2015-07-17 23:07:02 +00:00
}
2015-12-15 06:07:54 +00:00
var tmpnamefn = options.tmpnamefn || function (pathname) {
return pathname + '.' + crypto.randomBytes(8).toString('hex') + '.' + options.tmp;
2015-07-17 23:07:02 +00:00
};
var baknamefn = options.baknamefn || function (pathname) {
return pathname + '.' + options.bak;
};
2015-12-15 06:07:54 +00:00
/*
2015-07-17 23:07:02 +00:00
var namefn = options.namefn || function (pathname) {
return pathname;
};
2015-12-15 06:07:54 +00:00
*/
2015-07-17 23:07:02 +00:00
var sfs = {
2015-12-15 07:04:55 +00:00
writeFileAsync: function (filename, data, options) {
2015-12-15 06:07:54 +00:00
return sfs.stage(filename, data, options).then(function (tmpname) {
//console.log(filename);
return sfs.commit(tmpname, filename);
});
}
2015-12-15 07:04:55 +00:00
, stageAsync: function (filename, data, options) {
2015-12-15 06:07:54 +00:00
var tmpname = tmpnamefn(filename);
//console.log(tmpname);
return fs.writeFileAsync(tmpname, data, options).then(function () {
return tmpname;
2015-07-17 23:07:02 +00:00
});
}
2015-12-15 07:04:55 +00:00
, commitAsync: function (tmpname, filename) {
2015-12-15 06:07:54 +00:00
var bakname = baknamefn(filename);
2015-07-17 23:07:02 +00:00
// this may not exist
2015-12-15 06:07:54 +00:00
return fs.unlinkAsync(bakname).then(noop, noop).then(function () {
2015-07-17 23:07:02 +00:00
// this may not exist
2015-12-15 06:07:54 +00:00
//console.log(namefn(filename), '->', bakname);
return fs.renameAsync(filename, bakname).then(function () {
2015-07-17 23:07:02 +00:00
//console.log('created bak');
}, noop);
}).then(function () {
// this must be successful
2015-12-15 06:07:54 +00:00
//console.log(filename, '->', filename);
return fs.renameAsync(tmpname, filename).then(noop, function (err) {
2015-07-17 23:07:02 +00:00
//console.error(err);
return sfs.revert(filename).then(function () {
return PromiseA.reject(err);
});
});
});
}
2015-12-15 07:04:55 +00:00
, revertAsync: function (filename) {
2015-07-17 23:07:02 +00:00
return new PromiseA(function (resolve, reject) {
2015-12-15 06:07:54 +00:00
var bakname = baknamefn(filename);
var tmpname = tmpnamefn(filename);
var reader = fs.createReadStream(bakname);
var writer = fs.createWriteStream(tmpname);
2015-07-17 23:07:02 +00:00
reader.on('error', reject);
writer.on('error', reject);
reader.pipe(writer);
2015-12-15 06:07:54 +00:00
writer.on('close', function () {
sfs.commit(tmpname, filename).then(resolve, reject);
});
2015-07-17 23:07:02 +00:00
});
}
2015-12-15 06:30:24 +00:00
, tmpnamefn: tmpnamefn
, baknamefn: baknamefn
, create: create
2015-07-17 23:07:02 +00:00
};
2015-12-15 07:04:55 +00:00
sfs.writeFile = sfs.writeFileAsync;
sfs.stage = sfs.stageAsync;
sfs.commit = sfs.commitAsync;
sfs.revert = sfs.revertAsync;
2015-07-17 23:07:02 +00:00
return sfs;
}
2015-12-15 06:30:24 +00:00
module.exports = create();