diff options
author | Forrest L Norvell <forrest@npmjs.com> | 2014-09-23 02:52:43 +0400 |
---|---|---|
committer | Forrest L Norvell <forrest@npmjs.com> | 2014-09-23 02:52:43 +0400 |
commit | 69b4d18cdbc2ae04c9afaffbd273b436a394f398 (patch) | |
tree | 2c5add4fea4c7c7ffce2a6991d5cf8341361957f /node_modules/fs-write-stream-atomic | |
parent | 26b17ff2e3b21ee26c6fdbecc8273520cff45718 (diff) |
fs-write-stream-atomic@1.0.1
Fix a race condition in our race condition fixer.
Diffstat (limited to 'node_modules/fs-write-stream-atomic')
-rw-r--r-- | node_modules/fs-write-stream-atomic/README.md | 2 | ||||
-rw-r--r-- | node_modules/fs-write-stream-atomic/index.js | 39 | ||||
-rw-r--r-- | node_modules/fs-write-stream-atomic/package.json | 29 | ||||
-rw-r--r-- | node_modules/fs-write-stream-atomic/test/basic.js | 21 |
4 files changed, 70 insertions, 21 deletions
diff --git a/node_modules/fs-write-stream-atomic/README.md b/node_modules/fs-write-stream-atomic/README.md index 0554d6861..9a15d0567 100644 --- a/node_modules/fs-write-stream-atomic/README.md +++ b/node_modules/fs-write-stream-atomic/README.md @@ -5,7 +5,7 @@ Like `fs.createWriteStream(...)`, but atomic. Writes to a tmp file and does an atomic `fs.rename` to move it into place when it's done. -First rule of debugging: **It's always a write condition.** +First rule of debugging: **It's always a race condition.** ## USAGE diff --git a/node_modules/fs-write-stream-atomic/index.js b/node_modules/fs-write-stream-atomic/index.js index cb9b99aa7..70b22ba8c 100644 --- a/node_modules/fs-write-stream-atomic/index.js +++ b/node_modules/fs-write-stream-atomic/index.js @@ -33,17 +33,37 @@ function WriteStream (path, options) { fs.WriteStream.call(this, this.__atomicTmp, options) } +function cleanup (er) { + fs.unlink(this.__atomicTmp, function () { + fs.WriteStream.prototype.emit.call(this, 'error', er) + }.bind(this)) +} + +function cleanupSync (er) { + try { + fs.unlinkSync(this.__atomicTmp) + } finally { + return fs.WriteStream.prototype.emit.call(this, 'error', er) + } +} + // When we *would* emit 'close' or 'finish', instead do our stuff WriteStream.prototype.emit = function (ev) { - if (this.__atomicDidStuff || (ev !== 'close' && ev !== 'finish')) + if (ev === 'error') + return cleanupSync(this) + + if (ev !== 'close' && ev !== 'finish') return fs.WriteStream.prototype.emit.apply(this, arguments) - atomicDoStuff.call(this, function (er) { - if (er) - this.emit('error', er) - else - this.emit(ev) - }.bind(this)) + if (ev === 'finish') { + atomicDoStuff.call(this, function (er) { + if (er) + cleanup.call(this, er) + else + fs.WriteStream.prototype.emit.call(this, 'finish') + }.bind(this)) + } + // close will be emitted later, once we do the rename } function atomicDoStuff(cb) { @@ -64,5 +84,8 @@ function atomicDoStuff(cb) { } function moveIntoPlace (cb) { - fs.rename(this.__atomicTmp, this.__atomicTarget, cb) + fs.rename(this.__atomicTmp, this.__atomicTarget, function (er) { + cb(er) + fs.WriteStream.prototype.emit.call(this, 'close') + }.bind(this)) } diff --git a/node_modules/fs-write-stream-atomic/package.json b/node_modules/fs-write-stream-atomic/package.json index 9c3babd5c..4a6594d13 100644 --- a/node_modules/fs-write-stream-atomic/package.json +++ b/node_modules/fs-write-stream-atomic/package.json @@ -1,6 +1,6 @@ { "name": "fs-write-stream-atomic", - "version": "1.0.0", + "version": "1.0.1", "description": "Like `fs.createWriteStream(...)`, but atomic.", "main": "index.js", "directories": { @@ -29,10 +29,25 @@ "url": "https://github.com/npm/fs-write-stream-atomic/issues" }, "homepage": "https://github.com/npm/fs-write-stream-atomic", - "readme": "# fs-write-stream-atomic\n\nLike `fs.createWriteStream(...)`, but atomic.\n\nWrites to a tmp file and does an atomic `fs.rename` to move it into\nplace when it's done.\n\nFirst rule of debugging: **It's always a write condition.**\n\n## USAGE\n\n```javascript\nvar fsWriteStreamAtomic = require('fs-write-stream-atomic')\n// options are optional.\nvar write = fsWriteStreamAtomic('output.txt', options)\nvar read = fs.createReadStream('input.txt')\nread.pipe(write)\n\n// When the write stream emits a 'finish' or 'close' event,\n// you can be sure that it is moved into place, and contains\n// all the bytes that were written to it, even if something else\n// was writing to `output.txt` at the same time.\n```\n\n### `fsWriteStreamAtomic(filename, [options])`\n\n* `filename` {String} The file we want to write to\n* `options` {Object}\n * `chown` {Object} User and group to set ownership after write\n * `uid` {Number}\n * `gid` {Number}\n * `encoding` {String} default = 'utf8'\n * `mode` {Number} default = `0666`\n * `flags` {String} default = `'w'`\n\n", - "readmeFilename": "README.md", - "gitHead": "81a7c1e0f9dbcfc6e7a2e004389f362c7997566c", - "_id": "fs-write-stream-atomic@1.0.0", - "_shasum": "df22968876ac5163dce116790792cb3592d16930", - "_from": "fs-write-stream-atomic@*" + "gitHead": "7db0e8159270278b097789bcefb061b5c5fa7161", + "_id": "fs-write-stream-atomic@1.0.1", + "_shasum": "5e424a143d9d29a700bb409729d6612b678f05ac", + "_from": "fs-write-stream-atomic@>=1.0.1 <2.0.0", + "_npmVersion": "2.0.2", + "_nodeVersion": "0.10.31", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "dist": { + "shasum": "5e424a143d9d29a700bb409729d6612b678f05ac", + "tarball": "http://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.1.tgz" + }, + "_resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.1.tgz" } diff --git a/node_modules/fs-write-stream-atomic/test/basic.js b/node_modules/fs-write-stream-atomic/test/basic.js index c68c7315a..159c596ab 100644 --- a/node_modules/fs-write-stream-atomic/test/basic.js +++ b/node_modules/fs-write-stream-atomic/test/basic.js @@ -13,13 +13,20 @@ test('basic', function (t) { var streams = [] for (var i = 0; i < n; i++) { var s = writeStream(target) - s.on('finish', verifier) + s.on('finish', verifier('finish')) + s.on('close', verifier('close')) streams.push(s) } var verifierCalled = 0 - function verifier () { - if (++verifierCalled < n) return + function verifier (ev) { return function () { + if (ev === 'close') + t.equal(this.__emittedFinish, true) + else { + this.__emittedFinish = true + t.equal(ev, 'finish') + } + // make sure that one of the atomic streams won. var res = fs.readFileSync(target, 'utf8') var lines = res.trim().split(/\n/) @@ -31,8 +38,12 @@ test('basic', function (t) { var resExpr = /^first write \d+\nsecond write \d+\nthird write \d+\nfinal write \d+\n$/ t.similar(res, resExpr) - t.end() - } + + // should be called once for each close, and each finish + if (++verifierCalled === n * 2) { + t.end() + } + }} // now write something to each stream. streams.forEach(function (stream, i) { |