Skip to content

Commit 4f4c58c

Browse files
authored
feat: do not alter file ownership (npm#59)
BREAKING CHANGE: this module no longer attempts to change file ownership automatically
1 parent decf1c0 commit 4f4c58c

File tree

7 files changed

+43
-53
lines changed

7 files changed

+43
-53
lines changed

lib/check-bin.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ const isWindows = require('./is-windows.js')
44
const binTarget = require('./bin-target.js')
55
const { resolve, dirname } = require('path')
66
const readCmdShim = require('read-cmd-shim')
7-
const fs = require('fs')
8-
const { promisify } = require('util')
9-
const readlink = promisify(fs.readlink)
7+
const { readlink } = require('fs/promises')
108

119
const checkBin = async ({ bin, path, top, global, force }) => {
1210
// always ok to clobber when forced

lib/fix-bin.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
// make sure that bins are executable, and that they don't have
22
// windows line-endings on the hashbang line.
3-
const fs = require('fs')
4-
const { promisify } = require('util')
3+
const {
4+
chmod,
5+
open,
6+
readFile,
7+
} = require('fs/promises')
58

69
const execMode = 0o777 & (~process.umask())
710

811
const writeFileAtomic = require('write-file-atomic')
9-
const open = promisify(fs.open)
10-
const close = promisify(fs.close)
11-
const read = promisify(fs.read)
12-
const chmod = promisify(fs.chmod)
13-
const readFile = promisify(fs.readFile)
1412

1513
const isWindowsHashBang = buf =>
1614
buf[0] === '#'.charCodeAt(0) &&
@@ -19,16 +17,16 @@ const isWindowsHashBang = buf =>
1917

2018
const isWindowsHashbangFile = file => {
2119
const FALSE = () => false
22-
return open(file, 'r').then(fd => {
20+
return open(file, 'r').then(fh => {
2321
const buf = Buffer.alloc(2048)
24-
return read(fd, buf, 0, 2048, 0)
22+
return fh.read(buf, 0, 2048, 0)
2523
.then(
2624
() => {
2725
const isWHB = isWindowsHashBang(buf)
28-
return close(fd).then(() => isWHB, () => isWHB)
26+
return fh.close().then(() => isWHB, () => isWHB)
2927
},
3028
// don't leak FD if read() fails
31-
() => close(fd).then(FALSE, FALSE)
29+
() => fh.close().then(FALSE, FALSE)
3230
)
3331
}, FALSE)
3432
}

lib/link-gently.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,25 @@
44
// if there's a symlink already, pointing into our pkg, remove it first
55
// then create the symlink
66

7-
const { promisify } = require('util')
87
const { resolve, dirname } = require('path')
9-
const mkdirp = require('mkdirp-infer-owner')
10-
const fs = require('fs')
11-
const symlink = promisify(fs.symlink)
12-
const readlink = promisify(fs.readlink)
13-
const lstat = promisify(fs.lstat)
8+
const { lstat, mkdir, readlink, rm, symlink } = require('fs/promises')
149
const throwNonEnoent = er => {
1510
if (er.code !== 'ENOENT') {
1611
throw er
1712
}
1813
}
1914

15+
const rmOpts = {
16+
recursive: true,
17+
force: true,
18+
}
19+
2020
// even in --force mode, we never create a link over a link we've
2121
// already created. you can have multiple packages in a tree trying
2222
// to contend for the same bin, or the same manpage listed multiple times,
2323
// which creates a race condition and nondeterminism.
2424
const seen = new Set()
2525

26-
// disable glob in our rimraf calls
27-
const rimraf = promisify(require('rimraf'))
28-
const rm = path => rimraf(path, { glob: false })
29-
3026
const SKIP = Symbol('skip - missing or already installed')
3127
const CLOBBER = Symbol('clobber - ours or in forceful mode')
3228

@@ -52,7 +48,7 @@ const linkGently = async ({ path, to, from, absFrom, force }) => {
5248
// exists! maybe clobber if we can
5349
if (stTo) {
5450
if (!stTo.isSymbolicLink()) {
55-
return force && rm(to).then(() => CLOBBER)
51+
return force && rm(to, rmOpts).then(() => CLOBBER)
5652
}
5753

5854
return readlink(to).then(target => {
@@ -62,14 +58,14 @@ const linkGently = async ({ path, to, from, absFrom, force }) => {
6258

6359
target = resolve(dirname(to), target)
6460
if (target.indexOf(path) === 0 || force) {
65-
return rm(to).then(() => CLOBBER)
61+
return rm(to, rmOpts).then(() => CLOBBER)
6662
}
6763
// neither skip nor clobber
6864
return false
6965
})
7066
} else {
7167
// doesn't exist, dir might not either
72-
return mkdirp(dirname(to))
68+
return mkdir(dirname(to), { recursive: true })
7369
}
7470
})
7571
.then(skipOrClobber => {
@@ -78,7 +74,7 @@ const linkGently = async ({ path, to, from, absFrom, force }) => {
7874
}
7975
return symlink(from, to, 'file').catch(er => {
8076
if (skipOrClobber === CLOBBER || force) {
81-
return rm(to).then(() => symlink(from, to, 'file'))
77+
return rm(to, rmOpts).then(() => symlink(from, to, 'file'))
8278
}
8379
throw er
8480
}).then(() => true)

lib/shim-bin.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
const { promisify } = require('util')
21
const { resolve, dirname } = require('path')
3-
const fs = require('fs')
4-
const lstat = promisify(fs.lstat)
2+
const { lstat } = require('fs/promises')
53
const throwNonEnoent = er => {
64
if (er.code !== 'ENOENT') {
75
throw er

package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,14 @@
2323
],
2424
"license": "ISC",
2525
"dependencies": {
26-
"cmd-shim": "^5.0.0",
27-
"mkdirp-infer-owner": "^2.0.0",
26+
"cmd-shim": "^6.0.0",
2827
"npm-normalize-package-bin": "^2.0.0",
2928
"read-cmd-shim": "^3.0.0",
30-
"rimraf": "^3.0.0",
3129
"write-file-atomic": "^4.0.0"
3230
},
3331
"devDependencies": {
3432
"@npmcli/eslint-config": "^3.0.1",
3533
"@npmcli/template-oss": "4.5.1",
36-
"mkdirp": "^1.0.3",
3734
"require-inject": "^1.4.4",
3835
"tap": "^16.0.1"
3936
},

test/fix-bin.js

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@ t.test('dont fix non-windows hashbang file', async t => {
2929

3030
t.test('failure to read means not a windows hash bang file', async t => {
3131
const fsMock = {
32-
...fs,
33-
read: (a, b, c, d, e, cb) => {
34-
fsMock.read = null
35-
process.nextTick(() => cb(new Error('witaf')))
32+
...fs.promises,
33+
open: async (...args) => {
34+
const fh = await fs.promises.open(...args)
35+
fh.read = async () => {
36+
throw new Error('witaf')
37+
}
38+
return fh
3639
},
3740
}
41+
3842
const mockedFixBin = requireInject('../lib/fix-bin.js', {
39-
fs: fsMock,
43+
'fs/promises': fsMock,
4044
})
4145

4246
const dir = t.testdir({
@@ -52,14 +56,17 @@ t.test('failure to read means not a windows hash bang file', async t => {
5256

5357
t.test('failure to close is ignored', async t => {
5458
const fsMock = {
55-
...fs,
56-
close: (fd, cb) => {
57-
fsMock.close = fs.close
58-
process.nextTick(() => cb(new Error('witaf')))
59+
...fs.promises,
60+
open: async (...args) => {
61+
const fh = await fs.promises.open(...args)
62+
fh.close = async () => {
63+
throw new Error('witaf')
64+
}
65+
return fh
5966
},
6067
}
6168
const mockedFixBin = requireInject('../lib/fix-bin.js', {
62-
fs: fsMock,
69+
'fs/promises': fsMock,
6370
})
6471

6572
const dir = t.testdir({

test/shim-bin.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ const requireInject = require('require-inject')
33
const fs = require('fs')
44
const { statSync } = fs
55
const path = require('path').win32
6-
const mkdirp = require('mkdirp')
76

87
t.test('basic shim bin', async t => {
98
const dir = t.testdir({
@@ -15,7 +14,7 @@ t.test('basic shim bin', async t => {
1514
},
1615
notashim: 'definitely not',
1716
})
18-
const shimBin = requireInject('../lib/shim-bin.js', { path, mkdirp })
17+
const shimBin = requireInject('../lib/shim-bin.js', { path })
1918
await shimBin({
2019
path: `${dir}/pkg`,
2120
to: `${dir}/bin/hello`,
@@ -83,10 +82,9 @@ t.test('eperm on stat', async t => {
8382
})
8483
const shimBin = requireInject('../lib/shim-bin.js', {
8584
path,
86-
mkdirp,
87-
fs: {
88-
...fs,
89-
lstat: (_, cb) => cb(Object.assign(new Error('wakawaka'), {
85+
'fs/promises': {
86+
...fs.promises,
87+
lstat: () => Promise.reject(Object.assign(new Error('wakawaka'), {
9088
code: 'EPERM',
9189
})),
9290
},
@@ -113,7 +111,6 @@ t.test('strange enoent from read-cmd-shim', async t => {
113111
})
114112
const shimBin = requireInject('../lib/shim-bin.js', {
115113
path,
116-
mkdirp,
117114
'read-cmd-shim': () => Promise.reject(Object.assign(new Error('xyz'), {
118115
code: 'ENOENT',
119116
})),
@@ -163,7 +160,6 @@ t.test('unknown error from read-cmd-shim', async t => {
163160
})
164161
const shimBin = requireInject('../lib/shim-bin.js', {
165162
path,
166-
mkdirp,
167163
'read-cmd-shim': () => Promise.reject(Object.assign(new Error('xyz'), {
168164
code: 'ELDERGAWDS',
169165
})),

0 commit comments

Comments
 (0)