Updating NPM dependencies

This commit is contained in:
Drew Heavner
2020-11-11 13:30:52 +00:00
committed by GitHub
parent 7a6fb66c63
commit bd487ef324
9068 changed files with 1400893 additions and 587661 deletions

View File

@@ -1,3 +1,20 @@
# 3.0.0
* Implement options.tmpfileCreated callback.
* Drop Node.js 6, modernize code, return Promise from async function.
* Support write TypedArray's like in node fs.writeFile.
* Remove graceful-fs dependency.
# 2.4.3
* Ignore errors raised by `fs.closeSync` when cleaning up after a write
error.
# 2.4.2
* A pair of patches to fix some fd leaks. We would leak fds with sync use
when errors occured and with async use any time fsync was not in use. (#34)
# 2.4.1
* Fix a bug where `signal-exit` instances would be leaked. This was fixed when addressing #35.

View File

@@ -4,7 +4,7 @@ write-file-atomic
This is an extension for node's `fs.writeFile` that makes its operation
atomic and allows you set ownership (uid/gid of the file).
### var writeFileAtomic = require('write-file-atomic')<br>writeFileAtomic(filename, data, [options], callback)
### var writeFileAtomic = require('write-file-atomic')<br>writeFileAtomic(filename, data, [options], [callback])
* filename **String**
* data **String** | **Buffer**
@@ -15,7 +15,7 @@ atomic and allows you set ownership (uid/gid of the file).
* encoding **String** | **Null** default = 'utf8'
* fsync **Boolean** default = true
* mode **Number** default, from existing file, if any
* Promise **Object** default = native Promise object
* tmpfileCreated **Function** called when the tmpfile is created
* callback **Function**
Atomically and asynchronously writes data to a file, replacing the file if it already
@@ -27,7 +27,7 @@ If writeFile completes successfully then, if passed the **chown** option it will
the ownership of the file. Finally it renames the file back to the filename you specified. If
it encounters errors at any of these steps it will attempt to unlink the temporary file and then
pass the error back to the caller.
If multiple writes are concurrently issued to the same file, the write operations are put into a queue and serialized in the order they were called, using Promises. Native promises are used by default, but you can inject your own promise-like object with the **Promise** option. Writes to different files are still executed in parallel.
If multiple writes are concurrently issued to the same file, the write operations are put into a queue and serialized in the order they were called, using Promises. Writes to different files are still executed in parallel.
If provided, the **chown** option requires both **uid** and **gid** properties or else
you'll get an error. If **chown** is not specified it will default to using
@@ -42,6 +42,8 @@ If options is a String, it's assumed to be the **encoding** option. The **encodi
If the **fsync** option is **false**, writeFile will skip the final fsync call.
If the **tmpfileCreated** option is specified it will be called with the name of the tmpfile when created.
Example:
```javascript
@@ -51,6 +53,20 @@ writeFileAtomic('message.txt', 'Hello Node', {chown:{uid:100,gid:50}}, function
});
```
This function also supports async/await:
```javascript
(async () => {
try {
await writeFileAtomic('message.txt', 'Hello Node', {chown:{uid:100,gid:50}});
console.log('It\'s saved!');
} catch (err) {
console.error(err);
process.exit(1);
}
})();
```
### var writeFileAtomicSync = require('write-file-atomic').sync<br>writeFileAtomicSync(filename, data, [options])
The synchronous version of **writeFileAtomic**.

View File

@@ -4,17 +4,20 @@ module.exports.sync = writeFileSync
module.exports._getTmpname = getTmpname // for testing
module.exports._cleanupOnExit = cleanupOnExit
var fs = require('graceful-fs')
var MurmurHash3 = require('imurmurhash')
var onExit = require('signal-exit')
var path = require('path')
var activeFiles = {}
const fs = require('fs')
const MurmurHash3 = require('imurmurhash')
const onExit = require('signal-exit')
const path = require('path')
const isTypedArray = require('is-typedarray')
const typedArrayToBuffer = require('typedarray-to-buffer')
const { promisify } = require('util')
const activeFiles = {}
// if we run inside of a worker_thread, `process.pid` is not unique
/* istanbul ignore next */
var threadId = (function getId () {
const threadId = (function getId () {
try {
var workerThreads = require('worker_threads')
const workerThreads = require('worker_threads')
/// if we are in main thread, this is set to `0`
return workerThreads.threadId
@@ -24,7 +27,7 @@ var threadId = (function getId () {
}
})()
var invocations = 0
let invocations = 0
function getTmpname (filename) {
return filename + '.' +
MurmurHash3(__filename)
@@ -35,139 +38,135 @@ function getTmpname (filename) {
}
function cleanupOnExit (tmpfile) {
return function () {
return () => {
try {
fs.unlinkSync(typeof tmpfile === 'function' ? tmpfile() : tmpfile)
} catch (_) {}
}
}
function writeFile (filename, data, options, callback) {
if (options) {
if (options instanceof Function) {
callback = options
options = {}
} else if (typeof options === 'string') {
options = { encoding: options }
}
} else {
options = {}
}
var Promise = options.Promise || global.Promise
var truename
var fd
var 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) {
function serializeActiveFile (absoluteName) {
return new Promise(resolve => {
// make a queue if it doesn't already exist
if (!activeFiles[absoluteName]) activeFiles[absoluteName] = []
activeFiles[absoluteName].push(resolve) // add this job to the queue
if (activeFiles[absoluteName].length === 1) resolve() // kick off the first one
}).then(function getRealPath () {
return new Promise(function (resolve) {
fs.realpath(filename, function (_, realname) {
truename = realname || filename
tmpfile = getTmpname(truename)
resolve()
})
})
}).then(function stat () {
return new Promise(function stat (resolve) {
if (options.mode && options.chown) resolve()
else {
// Either mode or chown is not explicitly set
// Default behavior is to copy it from original file
fs.stat(truename, function (err, stats) {
if (err || !stats) resolve()
else {
options = Object.assign({}, options)
})
}
if (options.mode == null) {
options.mode = stats.mode
}
if (options.chown == null && process.getuid) {
options.chown = { uid: stats.uid, gid: stats.gid }
}
resolve()
}
})
// https://github.com/isaacs/node-graceful-fs/blob/master/polyfills.js#L315-L342
function isChownErrOk (err) {
if (err.code === 'ENOSYS') {
return true
}
const nonroot = !process.getuid || process.getuid() !== 0
if (nonroot) {
if (err.code === 'EINVAL' || err.code === 'EPERM') {
return true
}
}
return false
}
async function writeFileAsync (filename, data, options = {}) {
if (typeof options === 'string') {
options = { encoding: options }
}
let fd
let tmpfile
/* istanbul ignore next -- The closure only gets called when onExit triggers */
const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile))
const absoluteName = path.resolve(filename)
try {
await serializeActiveFile(absoluteName)
const truename = await promisify(fs.realpath)(filename).catch(() => filename)
tmpfile = getTmpname(truename)
if (!options.mode || !options.chown) {
// Either mode or chown is not explicitly set
// Default behavior is to copy it from original file
const stats = await promisify(fs.stat)(truename).catch(() => {})
if (stats) {
if (options.mode == null) {
options.mode = stats.mode
}
if (options.chown == null && process.getuid) {
options.chown = { uid: stats.uid, gid: stats.gid }
}
}
})
}).then(function thenWriteFile () {
return new Promise(function (resolve, reject) {
fs.open(tmpfile, 'w', options.mode, function (err, _fd) {
fd = _fd
if (err) reject(err)
else resolve()
})
})
}).then(function write () {
return new Promise(function (resolve, reject) {
if (Buffer.isBuffer(data)) {
fs.write(fd, data, 0, data.length, 0, function (err) {
if (err) reject(err)
else resolve()
})
} else if (data != null) {
fs.write(fd, String(data), 0, String(options.encoding || 'utf8'), function (err) {
if (err) reject(err)
else resolve()
})
} else resolve()
})
}).then(function syncAndClose () {
}
fd = await promisify(fs.open)(tmpfile, 'w', options.mode)
if (options.tmpfileCreated) {
await options.tmpfileCreated(tmpfile)
}
if (isTypedArray(data)) {
data = typedArrayToBuffer(data)
}
if (Buffer.isBuffer(data)) {
await promisify(fs.write)(fd, data, 0, data.length, 0)
} else if (data != null) {
await promisify(fs.write)(fd, String(data), 0, String(options.encoding || 'utf8'))
}
if (options.fsync !== false) {
return new Promise(function (resolve, reject) {
fs.fsync(fd, function (err) {
if (err) reject(err)
else fs.close(fd, resolve)
})
})
await promisify(fs.fsync)(fd)
}
}).then(function chown () {
await promisify(fs.close)(fd)
fd = null
if (options.chown) {
return new Promise(function (resolve, reject) {
fs.chown(tmpfile, options.chown.uid, options.chown.gid, function (err) {
if (err) reject(err)
else resolve()
})
await promisify(fs.chown)(tmpfile, options.chown.uid, options.chown.gid).catch(err => {
if (!isChownErrOk(err)) {
throw err
}
})
}
}).then(function chmod () {
if (options.mode) {
return new Promise(function (resolve, reject) {
fs.chmod(tmpfile, options.mode, function (err) {
if (err) reject(err)
else resolve()
})
await promisify(fs.chmod)(tmpfile, options.mode).catch(err => {
if (!isChownErrOk(err)) {
throw err
}
})
}
}).then(function rename () {
return new Promise(function (resolve, reject) {
fs.rename(tmpfile, truename, function (err) {
if (err) reject(err)
else resolve()
})
})
}).then(function success () {
await promisify(fs.rename)(tmpfile, truename)
} finally {
if (fd) {
await promisify(fs.close)(fd).catch(
/* istanbul ignore next */
() => {}
)
}
removeOnExitHandler()
callback()
}, function fail (err) {
removeOnExitHandler()
fs.unlink(tmpfile, function () {
callback(err)
})
}).then(function checkQueue () {
await promisify(fs.unlink)(tmpfile).catch(() => {})
activeFiles[absoluteName].shift() // remove the element added by serializeSameFile
if (activeFiles[absoluteName].length > 0) {
activeFiles[absoluteName][0]() // start next job if one is pending
} else delete activeFiles[absoluteName]
})
}
}
function writeFile (filename, data, options, callback) {
if (options instanceof Function) {
callback = options
options = {}
}
const promise = writeFileAsync(filename, data, options)
if (callback) {
promise.then(callback, callback)
}
return promise
}
function writeFileSync (filename, data, options) {
@@ -178,29 +177,38 @@ function writeFileSync (filename, data, options) {
} catch (ex) {
// it's ok, it'll happen on a not yet existing file
}
var tmpfile = getTmpname(filename)
const 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 {
const 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 cleanup = cleanupOnExit(tmpfile)
var removeOnExitHandler = onExit(cleanup)
var fd = fs.openSync(tmpfile, 'w', options.mode)
let fd
const cleanup = cleanupOnExit(tmpfile)
const removeOnExitHandler = onExit(cleanup)
let threw = true
try {
fd = fs.openSync(tmpfile, 'w', options.mode || 0o666)
if (options.tmpfileCreated) {
options.tmpfileCreated(tmpfile)
}
if (isTypedArray(data)) {
data = typedArrayToBuffer(data)
}
if (Buffer.isBuffer(data)) {
fs.writeSync(fd, data, 0, data.length, 0)
} else if (data != null) {
@@ -209,14 +217,43 @@ function writeFileSync (filename, data, options) {
if (options.fsync !== false) {
fs.fsyncSync(fd)
}
fs.closeSync(fd)
if (options.chown) fs.chownSync(tmpfile, options.chown.uid, options.chown.gid)
if (options.mode) fs.chmodSync(tmpfile, options.mode)
fd = null
if (options.chown) {
try {
fs.chownSync(tmpfile, options.chown.uid, options.chown.gid)
} catch (err) {
if (!isChownErrOk(err)) {
throw err
}
}
}
if (options.mode) {
try {
fs.chmodSync(tmpfile, options.mode)
} catch (err) {
if (!isChownErrOk(err)) {
throw err
}
}
}
fs.renameSync(tmpfile, filename)
threw = false
} finally {
if (fd) {
try {
fs.closeSync(fd)
} catch (ex) {
// ignore close errors at this stage, error may have closed fd already.
}
}
removeOnExitHandler()
} catch (err) {
removeOnExitHandler()
cleanup()
throw err
if (threw) {
cleanup()
}
}
}

View File

@@ -1,58 +1,55 @@
{
"_args": [
[
"write-file-atomic@2.4.1",
"/Users/drew.heavner/Documents/Github/upload-google-play"
]
],
"_development": true,
"_from": "write-file-atomic@2.4.1",
"_id": "write-file-atomic@2.4.1",
"_from": "write-file-atomic@^3.0.0",
"_id": "write-file-atomic@3.0.3",
"_inBundle": false,
"_integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
"_integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
"_location": "/write-file-atomic",
"_phantomChildren": {},
"_requested": {
"type": "version",
"type": "range",
"registry": true,
"raw": "write-file-atomic@2.4.1",
"raw": "write-file-atomic@^3.0.0",
"name": "write-file-atomic",
"escapedName": "write-file-atomic",
"rawSpec": "2.4.1",
"rawSpec": "^3.0.0",
"saveSpec": null,
"fetchSpec": "2.4.1"
"fetchSpec": "^3.0.0"
},
"_requiredBy": [
"/@jest/transform"
],
"_resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
"_spec": "2.4.1",
"_where": "/Users/drew.heavner/Documents/Github/upload-google-play",
"_resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
"_shasum": "56bd5c5a5c70481cd19c571bd39ab965a5de56e8",
"_spec": "write-file-atomic@^3.0.0",
"_where": "/home/codespace/workspace/upload-google-play/node_modules/@jest/transform",
"author": {
"name": "Rebecca Turner",
"email": "me@re-becca.org",
"url": "http://re-becca.org"
},
"bugs": {
"url": "https://github.com/iarna/write-file-atomic/issues"
"url": "https://github.com/npm/write-file-atomic/issues"
},
"bundleDependencies": false,
"dependencies": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
"is-typedarray": "^1.0.0",
"signal-exit": "^3.0.2",
"typedarray-to-buffer": "^3.1.5"
},
"deprecated": false,
"description": "Write files in an atomic fashion w/configurable ownership",
"devDependencies": {
"mkdirp": "^0.5.1",
"require-inject": "^1.4.0",
"rimraf": "^2.5.4",
"standard": "^12.0.1",
"tap": "^12.1.3"
"require-inject": "^1.4.4",
"rimraf": "^2.6.3",
"standard": "^14.3.1",
"tap": "^14.10.6"
},
"files": [
"index.js"
],
"homepage": "https://github.com/iarna/write-file-atomic",
"homepage": "https://github.com/npm/write-file-atomic",
"keywords": [
"writeFile",
"atomic"
@@ -62,10 +59,19 @@
"name": "write-file-atomic",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/iarna/write-file-atomic.git"
"url": "git://github.com/npm/write-file-atomic.git"
},
"scripts": {
"test": "standard && tap --100 test/*.js"
"lint": "standard",
"postlint": "rimraf chowncopy good nochmod nochown nofsync nofsyncopt noopen norename \"norename nounlink\" nowrite",
"posttest": "npm run lint",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"preversion": "npm test",
"test": "tap"
},
"version": "2.4.1"
"tap": {
"100": true
},
"version": "3.0.3"
}