Skip to content
This repository has been archived by the owner on Feb 15, 2022. It is now read-only.

Commit

Permalink
src: Ensure finish is only emitted _after_ our move finishes
Browse files Browse the repository at this point in the history
Further, the finish now triggers the close
  • Loading branch information
iarna committed Dec 10, 2015
1 parent ba90fb2 commit 0dbf046
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
27 changes: 24 additions & 3 deletions index.js
Expand Up @@ -31,6 +31,8 @@ function WriteStreamAtomic (path, options) {
this.__atomicTarget = path
this.__atomicChown = options.chown
this.__atomicTmp = getTmpname(path)
this.__atomicFinished = false
this.__atomicMoved = false
this.__atomicStream = fs.WriteStream(this.__atomicTmp, options)
this.__atomicStream.on('error', handleError.bind(this))

Expand All @@ -51,6 +53,26 @@ function handleError (er) {
this.emit('error', er)
}

function finish () {
if (!this.__atomicFinished) return
if (!this.__atomicMoved) return
PassThrough.prototype.emit.call(this, 'finish')
process.nextTick(function () {
this.emit('close')
}.bind(this))
}

WriteStreamAtomic.prototype.emit = function (event) {
// We'll emit this ourselves, as we need to hold off on emitting it
// until after we've completed putting the final file into place.
// To do otherwise creats a race between finish and close ;_;
if (event === 'finish') {
this.__atomicFinished = true
return finish.call(this)
}
return PassThrough.prototype.emit.apply(this, arguments)
}

WriteStreamAtomic.prototype._flush = function (cb) {
var writeStream = this
if (writeStream.__atomicChown) {
Expand All @@ -70,9 +92,8 @@ WriteStreamAtomic.prototype._flush = function (cb) {
function moveIntoPlace () {
fs.rename(writeStream.__atomicTmp, writeStream.__atomicTarget, function (err) {
cleanup(err)
process.nextTick(function () {
writeStream.emit('close')
})
writeStream.__atomicMoved = true
finish.call(writeStream)
})
}
}
11 changes: 9 additions & 2 deletions test/basic.js
@@ -1,7 +1,14 @@
var fs = require('graceful-fs')
var test = require('tap').test
var writeStream = require('../index.js')
var fs = require('fs')
var path = require('path')
var writeStream = require('../index.js')

var rename = fs.rename
fs.rename = function (from, to, cb) {
setTimeout(function () {
rename(from, to, cb)
}, 100)
}

test('basic', function (t) {
// open 10 write streams to the same file.
Expand Down

0 comments on commit 0dbf046

Please sign in to comment.