Skip to content

Commit 53ed632

Browse files
committedOct 2, 2024
deps: update write-file-atomic@6.0.0
1 parent ab40dab commit 53ed632

File tree

7 files changed

+362
-15
lines changed

7 files changed

+362
-15
lines changed
 

‎node_modules/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@
121121
!/archy
122122
!/balanced-match
123123
!/bin-links
124+
!/bin-links/node_modules/
125+
/bin-links/node_modules/*
126+
!/bin-links/node_modules/write-file-atomic
124127
!/binary-extensions
125128
!/brace-expansion
126129
!/cacache
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Copyright (c) 2015, Rebecca Turner
2+
3+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
4+
5+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
'use strict'
2+
module.exports = writeFile
3+
module.exports.sync = writeFileSync
4+
module.exports._getTmpname = getTmpname // for testing
5+
module.exports._cleanupOnExit = cleanupOnExit
6+
7+
const fs = require('fs')
8+
const MurmurHash3 = require('imurmurhash')
9+
const { onExit } = require('signal-exit')
10+
const path = require('path')
11+
const { promisify } = require('util')
12+
const activeFiles = {}
13+
14+
// if we run inside of a worker_thread, `process.pid` is not unique
15+
/* istanbul ignore next */
16+
const threadId = (function getId () {
17+
try {
18+
const workerThreads = require('worker_threads')
19+
20+
/// if we are in main thread, this is set to `0`
21+
return workerThreads.threadId
22+
} catch (e) {
23+
// worker_threads are not available, fallback to 0
24+
return 0
25+
}
26+
})()
27+
28+
let invocations = 0
29+
function getTmpname (filename) {
30+
return filename + '.' +
31+
MurmurHash3(__filename)
32+
.hash(String(process.pid))
33+
.hash(String(threadId))
34+
.hash(String(++invocations))
35+
.result()
36+
}
37+
38+
function cleanupOnExit (tmpfile) {
39+
return () => {
40+
try {
41+
fs.unlinkSync(typeof tmpfile === 'function' ? tmpfile() : tmpfile)
42+
} catch {
43+
// ignore errors
44+
}
45+
}
46+
}
47+
48+
function serializeActiveFile (absoluteName) {
49+
return new Promise(resolve => {
50+
// make a queue if it doesn't already exist
51+
if (!activeFiles[absoluteName]) {
52+
activeFiles[absoluteName] = []
53+
}
54+
55+
activeFiles[absoluteName].push(resolve) // add this job to the queue
56+
if (activeFiles[absoluteName].length === 1) {
57+
resolve()
58+
} // kick off the first one
59+
})
60+
}
61+
62+
// https://github.com/isaacs/node-graceful-fs/blob/master/polyfills.js#L315-L342
63+
function isChownErrOk (err) {
64+
if (err.code === 'ENOSYS') {
65+
return true
66+
}
67+
68+
const nonroot = !process.getuid || process.getuid() !== 0
69+
if (nonroot) {
70+
if (err.code === 'EINVAL' || err.code === 'EPERM') {
71+
return true
72+
}
73+
}
74+
75+
return false
76+
}
77+
78+
async function writeFileAsync (filename, data, options = {}) {
79+
if (typeof options === 'string') {
80+
options = { encoding: options }
81+
}
82+
83+
let fd
84+
let tmpfile
85+
/* istanbul ignore next -- The closure only gets called when onExit triggers */
86+
const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile))
87+
const absoluteName = path.resolve(filename)
88+
89+
try {
90+
await serializeActiveFile(absoluteName)
91+
const truename = await promisify(fs.realpath)(filename).catch(() => filename)
92+
tmpfile = getTmpname(truename)
93+
94+
if (!options.mode || !options.chown) {
95+
// Either mode or chown is not explicitly set
96+
// Default behavior is to copy it from original file
97+
const stats = await promisify(fs.stat)(truename).catch(() => {})
98+
if (stats) {
99+
if (options.mode == null) {
100+
options.mode = stats.mode
101+
}
102+
103+
if (options.chown == null && process.getuid) {
104+
options.chown = { uid: stats.uid, gid: stats.gid }
105+
}
106+
}
107+
}
108+
109+
fd = await promisify(fs.open)(tmpfile, 'w', options.mode)
110+
if (options.tmpfileCreated) {
111+
await options.tmpfileCreated(tmpfile)
112+
}
113+
if (ArrayBuffer.isView(data)) {
114+
await promisify(fs.write)(fd, data, 0, data.length, 0)
115+
} else if (data != null) {
116+
await promisify(fs.write)(fd, String(data), 0, String(options.encoding || 'utf8'))
117+
}
118+
119+
if (options.fsync !== false) {
120+
await promisify(fs.fsync)(fd)
121+
}
122+
123+
await promisify(fs.close)(fd)
124+
fd = null
125+
126+
if (options.chown) {
127+
await promisify(fs.chown)(tmpfile, options.chown.uid, options.chown.gid).catch(err => {
128+
if (!isChownErrOk(err)) {
129+
throw err
130+
}
131+
})
132+
}
133+
134+
if (options.mode) {
135+
await promisify(fs.chmod)(tmpfile, options.mode).catch(err => {
136+
if (!isChownErrOk(err)) {
137+
throw err
138+
}
139+
})
140+
}
141+
142+
await promisify(fs.rename)(tmpfile, truename)
143+
} finally {
144+
if (fd) {
145+
await promisify(fs.close)(fd).catch(
146+
/* istanbul ignore next */
147+
() => {}
148+
)
149+
}
150+
removeOnExitHandler()
151+
await promisify(fs.unlink)(tmpfile).catch(() => {})
152+
activeFiles[absoluteName].shift() // remove the element added by serializeSameFile
153+
if (activeFiles[absoluteName].length > 0) {
154+
activeFiles[absoluteName][0]() // start next job if one is pending
155+
} else {
156+
delete activeFiles[absoluteName]
157+
}
158+
}
159+
}
160+
161+
async function writeFile (filename, data, options, callback) {
162+
if (options instanceof Function) {
163+
callback = options
164+
options = {}
165+
}
166+
167+
const promise = writeFileAsync(filename, data, options)
168+
if (callback) {
169+
try {
170+
const result = await promise
171+
return callback(result)
172+
} catch (err) {
173+
return callback(err)
174+
}
175+
}
176+
177+
return promise
178+
}
179+
180+
function writeFileSync (filename, data, options) {
181+
if (typeof options === 'string') {
182+
options = { encoding: options }
183+
} else if (!options) {
184+
options = {}
185+
}
186+
try {
187+
filename = fs.realpathSync(filename)
188+
} catch (ex) {
189+
// it's ok, it'll happen on a not yet existing file
190+
}
191+
const tmpfile = getTmpname(filename)
192+
193+
if (!options.mode || !options.chown) {
194+
// Either mode or chown is not explicitly set
195+
// Default behavior is to copy it from original file
196+
try {
197+
const stats = fs.statSync(filename)
198+
options = Object.assign({}, options)
199+
if (!options.mode) {
200+
options.mode = stats.mode
201+
}
202+
if (!options.chown && process.getuid) {
203+
options.chown = { uid: stats.uid, gid: stats.gid }
204+
}
205+
} catch (ex) {
206+
// ignore stat errors
207+
}
208+
}
209+
210+
let fd
211+
const cleanup = cleanupOnExit(tmpfile)
212+
const removeOnExitHandler = onExit(cleanup)
213+
214+
let threw = true
215+
try {
216+
fd = fs.openSync(tmpfile, 'w', options.mode || 0o666)
217+
if (options.tmpfileCreated) {
218+
options.tmpfileCreated(tmpfile)
219+
}
220+
if (ArrayBuffer.isView(data)) {
221+
fs.writeSync(fd, data, 0, data.length, 0)
222+
} else if (data != null) {
223+
fs.writeSync(fd, String(data), 0, String(options.encoding || 'utf8'))
224+
}
225+
if (options.fsync !== false) {
226+
fs.fsyncSync(fd)
227+
}
228+
229+
fs.closeSync(fd)
230+
fd = null
231+
232+
if (options.chown) {
233+
try {
234+
fs.chownSync(tmpfile, options.chown.uid, options.chown.gid)
235+
} catch (err) {
236+
if (!isChownErrOk(err)) {
237+
throw err
238+
}
239+
}
240+
}
241+
242+
if (options.mode) {
243+
try {
244+
fs.chmodSync(tmpfile, options.mode)
245+
} catch (err) {
246+
if (!isChownErrOk(err)) {
247+
throw err
248+
}
249+
}
250+
}
251+
252+
fs.renameSync(tmpfile, filename)
253+
threw = false
254+
} finally {
255+
if (fd) {
256+
try {
257+
fs.closeSync(fd)
258+
} catch (ex) {
259+
// ignore close errors at this stage, error may have closed fd already.
260+
}
261+
}
262+
removeOnExitHandler()
263+
if (threw) {
264+
cleanup()
265+
}
266+
}
267+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"name": "write-file-atomic",
3+
"version": "5.0.1",
4+
"description": "Write files in an atomic fashion w/configurable ownership",
5+
"main": "./lib/index.js",
6+
"scripts": {
7+
"test": "tap",
8+
"posttest": "npm run lint",
9+
"lint": "eslint \"**/*.js\"",
10+
"postlint": "template-oss-check",
11+
"lintfix": "npm run lint -- --fix",
12+
"snap": "tap",
13+
"template-oss-apply": "template-oss-apply --force"
14+
},
15+
"repository": {
16+
"type": "git",
17+
"url": "https://github.com/npm/write-file-atomic.git"
18+
},
19+
"keywords": [
20+
"writeFile",
21+
"atomic"
22+
],
23+
"author": "GitHub Inc.",
24+
"license": "ISC",
25+
"bugs": {
26+
"url": "https://github.com/npm/write-file-atomic/issues"
27+
},
28+
"homepage": "https://github.com/npm/write-file-atomic",
29+
"dependencies": {
30+
"imurmurhash": "^0.1.4",
31+
"signal-exit": "^4.0.1"
32+
},
33+
"devDependencies": {
34+
"@npmcli/eslint-config": "^4.0.0",
35+
"@npmcli/template-oss": "4.14.1",
36+
"tap": "^16.0.1"
37+
},
38+
"files": [
39+
"bin/",
40+
"lib/"
41+
],
42+
"engines": {
43+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
44+
},
45+
"templateOSS": {
46+
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
47+
"windowsCI": false,
48+
"version": "4.14.1",
49+
"publish": "true"
50+
},
51+
"tap": {
52+
"nyc-arg": [
53+
"--exclude",
54+
"tap-snapshots/**"
55+
]
56+
}
57+
}

‎node_modules/write-file-atomic/package.json

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
{
22
"name": "write-file-atomic",
3-
"version": "5.0.1",
3+
"version": "6.0.0",
44
"description": "Write files in an atomic fashion w/configurable ownership",
55
"main": "./lib/index.js",
66
"scripts": {
77
"test": "tap",
88
"posttest": "npm run lint",
9-
"lint": "eslint \"**/*.js\"",
9+
"lint": "npm run eslint",
1010
"postlint": "template-oss-check",
11-
"lintfix": "npm run lint -- --fix",
11+
"lintfix": "npm run eslint -- --fix",
1212
"snap": "tap",
13-
"template-oss-apply": "template-oss-apply --force"
13+
"template-oss-apply": "template-oss-apply --force",
14+
"eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""
1415
},
1516
"repository": {
1617
"type": "git",
17-
"url": "https://github.com/npm/write-file-atomic.git"
18+
"url": "git+https://github.com/npm/write-file-atomic.git"
1819
},
1920
"keywords": [
2021
"writeFile",
@@ -31,21 +32,21 @@
3132
"signal-exit": "^4.0.1"
3233
},
3334
"devDependencies": {
34-
"@npmcli/eslint-config": "^4.0.0",
35-
"@npmcli/template-oss": "4.14.1",
35+
"@npmcli/eslint-config": "^5.0.0",
36+
"@npmcli/template-oss": "4.23.3",
3637
"tap": "^16.0.1"
3738
},
3839
"files": [
3940
"bin/",
4041
"lib/"
4142
],
4243
"engines": {
43-
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
44+
"node": "^18.17.0 || >=20.5.0"
4445
},
4546
"templateOSS": {
4647
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
4748
"windowsCI": false,
48-
"version": "4.14.1",
49+
"version": "4.23.3",
4950
"publish": "true"
5051
},
5152
"tap": {

‎package-lock.json

+18-5
Original file line numberDiff line numberDiff line change

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
"treeverse": "^3.0.0",
119119
"validate-npm-package-name": "^6.0.0",
120120
"which": "^5.0.0",
121-
"write-file-atomic": "^5.0.1"
121+
"write-file-atomic": "^6.0.0"
122122
},
123123
"bundleDependencies": [
124124
"@isaacs/string-locale-compare",

0 commit comments

Comments
 (0)
Please sign in to comment.