index.js
3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
'use strict';
var PromiseA;
try {
PromiseA = require('bluebird');
} catch(e) {
PromiseA = global.Promise;
}
var util = require('util');
var promisify = util.promisify || PromiseA.promisify;
if (!PromiseA || !promisify) {
throw new Error("DON'T PANIC. Everything is A-OK."
+ " However, you're on a really old version of node. All you need to do is `npm install --save bluebird`"
+ " (in your project directory, which is probably '" + require('path').dirname(require.main.filename) + "')"
+ " and everything will work just fine.");
}
var fs = require('fs');
var writeFileAsync = promisify(fs.writeFile);
var unlinkAsync = promisify(fs.unlink);
var renameAsync = promisify(fs.rename);
var crypto = require('crypto');
function noop() {
}
function create(options) {
if (!options) {
options = {};
}
if (!options.tmp) {
options.tmp = 'tmp';
}
if (!options.bak) {
options.bak = 'bak';
}
if (options.tmp === options.bak) {
throw new Error("'tmp' and 'bak' suffixes cannot be the same... duh");
}
var tmpnamefn = options.tmpnamefn || function (pathname) {
return pathname + '.' + crypto.randomBytes(8).toString('hex') + '.' + options.tmp;
};
var baknamefn = options.baknamefn || function (pathname) {
return pathname + '.' + options.bak;
};
/*
var namefn = options.namefn || function (pathname) {
return pathname;
};
*/
var sfs = {
writeFileAsync: function (filename, data, options) {
return sfs.stage(filename, data, options).then(function (tmpname) {
//console.log(filename);
return sfs.commit(tmpname, filename);
});
}
, stageAsync: function (filename, data, options) {
var tmpname = tmpnamefn(filename);
//console.log(tmpname);
return writeFileAsync(tmpname, data, options).then(function () {
return tmpname;
});
}
, commitAsync: function (tmpname, filename) {
var bakname = baknamefn(filename);
// this may not exist
return unlinkAsync(bakname).then(noop, noop).then(function () {
// this may not exist
//console.log(namefn(filename), '->', bakname);
return renameAsync(filename, bakname).then(function () {
//console.log('created bak');
}, noop);
}).then(function () {
// this must be successful
//console.log(filename, '->', filename);
return renameAsync(tmpname, filename).then(noop, function (err) {
//console.error(err);
return sfs.revert(filename).then(function () {
return PromiseA.reject(err);
});
});
});
}
, revertAsync: function (filename) {
return new PromiseA(function (resolve, reject) {
var bakname = baknamefn(filename);
var tmpname = tmpnamefn(filename);
var reader = fs.createReadStream(bakname);
var writer = fs.createWriteStream(tmpname);
reader.on('error', reject);
writer.on('error', reject);
reader.pipe(writer);
writer.on('close', function () {
sfs.commit(tmpname, filename).then(resolve, reject);
});
});
}
, tmpnamefn: tmpnamefn
, baknamefn: baknamefn
, create: create
};
sfs.writeFile = sfs.writeFileAsync;
sfs.stage = sfs.stageAsync;
sfs.commit = sfs.commitAsync;
sfs.revert = sfs.revertAsync;
return sfs;
}
module.exports = create();