diff options
Diffstat (limited to 'deps/npm/node_modules/write-file-atomic/index.js')
-rw-r--r-- | deps/npm/node_modules/write-file-atomic/index.js | 110 |
1 files changed, 72 insertions, 38 deletions
diff --git a/deps/npm/node_modules/write-file-atomic/index.js b/deps/npm/node_modules/write-file-atomic/index.js index 3b5607d154..fe9fdfb9db 100644 --- a/deps/npm/node_modules/write-file-atomic/index.js +++ b/deps/npm/node_modules/write-file-atomic/index.js @@ -10,11 +10,26 @@ var onExit = require('signal-exit') var path = require('path') var activeFiles = {} +// if we run inside of a worker_thread, `process.pid` is not unique +/* istanbul ignore next */ +var threadId = (function getId () { + try { + var workerThreads = require('worker_threads') + + /// if we are in main thread, this is set to `0` + return workerThreads.threadId + } catch (e) { + // worker_threads are not available, fallback to 0 + return 0 + } +})() + var invocations = 0 function getTmpname (filename) { return filename + '.' + MurmurHash3(__filename) .hash(String(process.pid)) + .hash(String(threadId)) .hash(String(++invocations)) .result() } @@ -28,17 +43,23 @@ function cleanupOnExit (tmpfile) { } function writeFile (filename, data, options, callback) { - if (options instanceof Function) { - callback = options - options = null + if (options) { + if (options instanceof Function) { + callback = options + options = {} + } else if (typeof options === 'string') { + options = { encoding: options } + } + } else { + options = {} } - if (!options) options = {} var Promise = options.Promise || global.Promise var truename var fd var tmpfile - var removeOnExit = cleanupOnExit(() => tmpfile) + /* istanbul ignore next -- The closure only gets called when onExit triggers */ + var removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile)) var absoluteName = path.resolve(filename) new Promise(function serializeSameFile (resolve) { @@ -66,10 +87,10 @@ function writeFile (filename, data, options, callback) { else { options = Object.assign({}, options) - if (!options.mode) { + if (options.mode == null) { options.mode = stats.mode } - if (!options.chown && process.getuid) { + if (options.chown == null && process.getuid) { options.chown = { uid: stats.uid, gid: stats.gid } } resolve() @@ -100,15 +121,18 @@ function writeFile (filename, data, options, callback) { } else resolve() }) }).then(function syncAndClose () { - if (options.fsync !== false) { - return new Promise(function (resolve, reject) { + return new Promise(function (resolve, reject) { + if (options.fsync !== false) { fs.fsync(fd, function (err) { - if (err) reject(err) + if (err) fs.close(fd, () => reject(err)) else fs.close(fd, resolve) }) - }) - } + } else { + fs.close(fd, resolve) + } + }) }).then(function chown () { + fd = null if (options.chown) { return new Promise(function (resolve, reject) { fs.chown(tmpfile, options.chown.uid, options.chown.gid, function (err) { @@ -134,12 +158,16 @@ function writeFile (filename, data, options, callback) { }) }) }).then(function success () { - removeOnExit() + removeOnExitHandler() callback() - }).catch(function fail (err) { - removeOnExit() - fs.unlink(tmpfile, function () { - callback(err) + }, function fail (err) { + return new Promise(resolve => { + return fd ? fs.close(fd, resolve) : resolve() + }).then(() => { + removeOnExitHandler() + fs.unlink(tmpfile, function () { + callback(err) + }) }) }).then(function checkQueue () { activeFiles[absoluteName].shift() // remove the element added by serializeSameFile @@ -150,7 +178,8 @@ function writeFile (filename, data, options, callback) { } function writeFileSync (filename, data, options) { - if (!options) options = {} + if (typeof options === 'string') options = { encoding: options } + else if (!options) options = {} try { filename = fs.realpathSync(filename) } catch (ex) { @@ -158,26 +187,30 @@ function writeFileSync (filename, data, options) { } var tmpfile = getTmpname(filename) - try { - if (!options.mode || !options.chown) { - // Either mode or chown is not explicitly set - // Default behavior is to copy it from original file - try { - var stats = fs.statSync(filename) - options = Object.assign({}, options) - if (!options.mode) { - options.mode = stats.mode - } - if (!options.chown && process.getuid) { - options.chown = { uid: stats.uid, gid: stats.gid } - } - } catch (ex) { - // ignore stat errors + if (!options.mode || !options.chown) { + // Either mode or chown is not explicitly set + // Default behavior is to copy it from original file + try { + var stats = fs.statSync(filename) + options = Object.assign({}, options) + if (!options.mode) { + options.mode = stats.mode + } + if (!options.chown && process.getuid) { + options.chown = { uid: stats.uid, gid: stats.gid } } + } catch (ex) { + // ignore stat errors } + } + + var fd + var cleanup = cleanupOnExit(tmpfile) + var removeOnExitHandler = onExit(cleanup) + + try { - var removeOnExit = onExit(cleanupOnExit(tmpfile)) - var fd = fs.openSync(tmpfile, 'w', options.mode) + fd = fs.openSync(tmpfile, 'w', options.mode) if (Buffer.isBuffer(data)) { fs.writeSync(fd, data, 0, data.length, 0) } else if (data != null) { @@ -190,10 +223,11 @@ function writeFileSync (filename, data, options) { if (options.chown) fs.chownSync(tmpfile, options.chown.uid, options.chown.gid) if (options.mode) fs.chmodSync(tmpfile, options.mode) fs.renameSync(tmpfile, filename) - removeOnExit() + removeOnExitHandler() } catch (err) { - removeOnExit() - try { fs.unlinkSync(tmpfile) } catch (e) {} + if (fd) fs.closeSync(fd) + removeOnExitHandler() + cleanup() throw err } } |