initial commit (tested working)
This commit is contained in:
parent
4ac9bbcafe
commit
5db9d90c90
|
@ -0,0 +1,68 @@
|
|||
safe-replace
|
||||
============
|
||||
|
||||
A micro-module for safely replacing a file.
|
||||
|
||||
Commandline Reference
|
||||
---------------------
|
||||
|
||||
If I want to safely replace a file with a new version, I would do so like this:
|
||||
|
||||
```bash
|
||||
# create the new version
|
||||
touch keep.txt.new
|
||||
|
||||
# remove the previous backup
|
||||
rm -f keep.txt.bak
|
||||
|
||||
# move the current version to the backup
|
||||
mv keep.txt keep.txt.bak
|
||||
|
||||
# move the new version to the current
|
||||
mv keep.txt.new keep.txt
|
||||
```
|
||||
|
||||
If `keep.txt` became corrupt and I wanted to use the backup,
|
||||
I would do this:
|
||||
|
||||
```bash
|
||||
# copy the backup to the new version
|
||||
rsync keep.txt.bak keep.txt
|
||||
```
|
||||
|
||||
In Node
|
||||
-------
|
||||
|
||||
I ported that proccess to node.
|
||||
|
||||
```js
|
||||
// default behavior is to concat (filename + '.' + 'new')
|
||||
var safeReplace = require('safe-replace').create({ new: 'new', bak: 'bak' });
|
||||
|
||||
var data = new Buffer('A priceless document');
|
||||
safeReplace.writeFile('keep.txt', data, 'ascii').then(function () {
|
||||
fs.readdir('.', function (nodes) {
|
||||
console.log('file system nodes', nodes);
|
||||
// keep.txt
|
||||
// keep.txt.bak
|
||||
});
|
||||
});
|
||||
|
||||
// let's say I wrote keep.txt.new with my own mechanism
|
||||
safeReplace.commit('keep.txt').then(function () {
|
||||
fs.readdir('.', function (nodes) {
|
||||
console.log('file system nodes', nodes);
|
||||
// keep.txt
|
||||
// keep.txt.bak
|
||||
});
|
||||
});
|
||||
|
||||
// let's say I want to revert the file from the '.bak'
|
||||
safeReplace.revert('keep.txt').then(function () {
|
||||
fs.readdir('.', function (nodes) {
|
||||
console.log('file system nodes', nodes);
|
||||
// keep.txt
|
||||
// keep.txt.bak
|
||||
});
|
||||
});
|
||||
```
|
|
@ -0,0 +1,77 @@
|
|||
'use strict';
|
||||
|
||||
var PromiseA = require('bluebird').Promise;
|
||||
var fs = PromiseA.promisifyAll(require('fs'));
|
||||
|
||||
function noop() {
|
||||
}
|
||||
|
||||
function create(options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.new) {
|
||||
options.new = 'new';
|
||||
}
|
||||
if (!options.bak) {
|
||||
options.bak = 'bak';
|
||||
}
|
||||
if (options.new === options.bak) {
|
||||
throw new Error("'new' and 'bak' suffixes cannot be the same... duh");
|
||||
}
|
||||
|
||||
var newnamefn = options.newnamefn || function (pathname) {
|
||||
return pathname + '.' + options.new;
|
||||
};
|
||||
var baknamefn = options.baknamefn || function (pathname) {
|
||||
return pathname + '.' + options.bak;
|
||||
};
|
||||
var namefn = options.namefn || function (pathname) {
|
||||
return pathname;
|
||||
};
|
||||
|
||||
var sfs = {
|
||||
writeFile: function (filename, data, options) {
|
||||
//console.log(newnamefn(filename));
|
||||
return fs.writeFileAsync(newnamefn(filename), data, options).then(function () {
|
||||
//console.log(namefn(filename));
|
||||
return sfs.commit(namefn(filename));
|
||||
});
|
||||
}
|
||||
, commit: function (filename) {
|
||||
// this may not exist
|
||||
return fs.unlinkAsync(baknamefn(filename)).then(noop, noop).then(function () {
|
||||
// this may not exist
|
||||
//console.log(namefn(filename), '->', baknamefn(filename));
|
||||
return fs.renameAsync(namefn(filename), baknamefn(filename)).then(function () {
|
||||
//console.log('created bak');
|
||||
}, noop);
|
||||
}).then(function () {
|
||||
// this must be successful
|
||||
//console.log(newnamefn(filename), '->', namefn(filename));
|
||||
return fs.renameAsync(newnamefn(filename), namefn(filename)).then(noop, function (err) {
|
||||
//console.error(err);
|
||||
return sfs.revert(filename).then(function () {
|
||||
return PromiseA.reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
, revert: function (filename) {
|
||||
return new PromiseA(function (resolve, reject) {
|
||||
var reader = fs.createReadStream(baknamefn(filename));
|
||||
var writer = fs.createWriteStream(namefn(filename));
|
||||
|
||||
reader.on('error', reject);
|
||||
writer.on('error', reject);
|
||||
|
||||
reader.pipe(writer);
|
||||
writer.on('close', resolve);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return sfs;
|
||||
}
|
||||
|
||||
module.exports.create = create;
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
var safeReplace = require('./').create();
|
||||
//var safeReplace = require('safe-replace').create();
|
||||
var fs = require('fs');
|
||||
|
||||
safeReplace.writeFile('keep.txt', 'my precious').then(function () {
|
||||
fs.readdir('.', function (nodes) {
|
||||
console.log('file system nodes', nodes);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue