Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deps: bin-links@3.0.0 write-file-atomic@4.0.0 #4254

Merged
merged 2 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions node_modules/bin-links/lib/bin-target.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const isWindows = require('./is-windows.js')
const getPrefix = require('./get-prefix.js')
const getNodeModules = require('./get-node-modules.js')
const {dirname} = require('path')
const { dirname } = require('path')

module.exports = ({top, path}) =>
module.exports = ({ top, path }) =>
!top ? getNodeModules(path) + '/.bin'
: isWindows ? getPrefix(path)
: dirname(getPrefix(path)) + '/bin'
: isWindows ? getPrefix(path)
: dirname(getPrefix(path)) + '/bin'
47 changes: 26 additions & 21 deletions node_modules/bin-links/lib/check-bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,74 @@
// either rejects or resolves to nothing. return value not relevant.
const isWindows = require('./is-windows.js')
const binTarget = require('./bin-target.js')
const {resolve, dirname} = require('path')
const { resolve, dirname } = require('path')
const readCmdShim = require('read-cmd-shim')
const fs = require('fs')
const {promisify} = require('util')
const { promisify } = require('util')
const readlink = promisify(fs.readlink)

const checkBin = async ({bin, path, top, global, force}) => {
const checkBin = async ({ bin, path, top, global, force }) => {
// always ok to clobber when forced
// always ok to clobber local bins, or when forced
if (force || !global || !top)
if (force || !global || !top) {
return
}

// ok, need to make sure, then
const target = resolve(binTarget({path, top}), bin)
const target = resolve(binTarget({ path, top }), bin)
path = resolve(path)
return isWindows ? checkShim({target, path}) : checkLink({target, path})
return isWindows ? checkShim({ target, path }) : checkLink({ target, path })
}

// only enoent is allowed. anything else is a problem.
const handleReadLinkError = async ({er, target}) =>
const handleReadLinkError = async ({ er, target }) =>
er.code === 'ENOENT' ? null
: failEEXIST({target})
: failEEXIST({ target })

const checkLink = async ({target, path}) => {
const checkLink = async ({ target, path }) => {
const current = await readlink(target)
.catch(er => handleReadLinkError({er, target}))
.catch(er => handleReadLinkError({ er, target }))

if (!current)
if (!current) {
return
}

const resolved = resolve(dirname(target), current)

if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0)
return failEEXIST({target})
if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) {
return failEEXIST({ target })
}
}

const handleReadCmdShimError = ({er, target}) =>
const handleReadCmdShimError = ({ er, target }) =>
er.code === 'ENOENT' ? null
: failEEXIST({target})
: failEEXIST({ target })

const failEEXIST = ({target}) =>
const failEEXIST = ({ target }) =>
Promise.reject(Object.assign(new Error('EEXIST: file already exists'), {
path: target,
code: 'EEXIST',
}))

const checkShim = async ({target, path}) => {
const checkShim = async ({ target, path }) => {
const shims = [
target,
target + '.cmd',
target + '.ps1',
]
await Promise.all(shims.map(async target => {
const current = await readCmdShim(target)
.catch(er => handleReadCmdShimError({er, target}))
.catch(er => handleReadCmdShimError({ er, target }))

if (!current)
if (!current) {
return
}

const resolved = resolve(dirname(target), current.replace(/\\/g, '/'))

if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0)
return failEEXIST({target})
if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) {
return failEEXIST({ target })
}
}))
}

Expand Down
8 changes: 5 additions & 3 deletions node_modules/bin-links/lib/check-bins.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ const normalize = require('npm-normalize-package-bin')
const checkBins = async ({ pkg, path, top, global, force }) => {
// always ok to clobber when forced
// always ok to clobber local bins, or when forced
if (force || !global || !top)
if (force || !global || !top) {
return
}

pkg = normalize(pkg)
if (!pkg.bin)
if (!pkg.bin) {
return
}

await Promise.all(Object.keys(pkg.bin)
.map(bin => checkBin({bin, path, top, global, force})))
.map(bin => checkBin({ bin, path, top, global, force })))
}
module.exports = checkBins
5 changes: 3 additions & 2 deletions node_modules/bin-links/lib/get-node-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// {prefix}/node_modules/{name}. Can't rely on pkg.name, because
// it might be installed as an alias.

const {dirname, basename} = require('path')
const { dirname, basename } = require('path')
// this gets called a lot and can't change, so memoize it
const memo = new Map()
module.exports = path => {
if (memo.has(path))
if (memo.has(path)) {
return memo.get(path)
}

const scopeOrNm = dirname(path)
const nm = basename(scopeOrNm) === 'node_modules' ? scopeOrNm
Expand Down
17 changes: 10 additions & 7 deletions node_modules/bin-links/lib/get-paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
// are present, then we can assume that they're associated.
const binTarget = require('./bin-target.js')
const manTarget = require('./man-target.js')
const {resolve, basename} = require('path')
const { resolve, basename } = require('path')
const isWindows = require('./is-windows.js')
module.exports = ({path, pkg, global, top}) => {
if (top && !global)
module.exports = ({ path, pkg, global, top }) => {
if (top && !global) {
return []
}

const binSet = []
const binTarg = binTarget({path, top})
const binTarg = binTarget({ path, top })
if (pkg.bin) {
for (const bin of Object.keys(pkg.bin)) {
const b = resolve(binTarg, bin)
Expand All @@ -22,23 +23,25 @@ module.exports = ({path, pkg, global, top}) => {
}
}

const manTarg = manTarget({path, top})
const manTarg = manTarget({ path, top })
const manSet = []
if (manTarg && pkg.man && Array.isArray(pkg.man) && pkg.man.length) {
for (const man of pkg.man) {
const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)
// invalid entries invalidate the entire man set
if (!parseMan)
if (!parseMan) {
return binSet
}

const stem = parseMan[1]
const sxn = parseMan[2]
const base = basename(stem)
const absFrom = resolve(path, man)

/* istanbul ignore if - should be impossible */
if (absFrom.indexOf(path) !== 0)
if (absFrom.indexOf(path) !== 0) {
return binSet
}

manSet.push(resolve(manTarg, 'man' + sxn, base))
}
Expand Down
2 changes: 1 addition & 1 deletion node_modules/bin-links/lib/get-prefix.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const {dirname} = require('path')
const { dirname } = require('path')
const getNodeModules = require('./get-node-modules.js')
module.exports = path => dirname(getNodeModules(path))
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const linkBins = require('./lib/link-bins.js')
const linkMans = require('./lib/link-mans.js')
const linkBins = require('./link-bins.js')
const linkMans = require('./link-mans.js')

const binLinks = opts => {
const { path, pkg, force, global, top } = opts
Expand All @@ -14,27 +14,28 @@ const binLinks = opts => {
// non-global top pkgs don't have any bins or mans linked. From here on
// out, if it's top, we know that it's global, so no need to pass that
// option further down the stack.
if (top && !global)
if (top && !global) {
return Promise.resolve()
}

return Promise.all([
// allow clobbering within the local node_modules/.bin folder.
// only global bins are protected in this way, or else it is
// yet another vector for excessive dependency conflicts.
linkBins({path, pkg, top, force: force || !top}),
linkMans({path, pkg, top, force}),
linkBins({ path, pkg, top, force: force || !top }),
linkMans({ path, pkg, top, force }),
])
}

const shimBin = require('./lib/shim-bin.js')
const linkGently = require('./lib/link-gently.js')
const shimBin = require('./shim-bin.js')
const linkGently = require('./link-gently.js')
const resetSeen = () => {
shimBin.resetSeen()
linkGently.resetSeen()
}

const checkBins = require('./lib/check-bins.js')
const getPaths = require('./lib/get-paths.js')
const checkBins = require('./check-bins.js')
const getPaths = require('./get-paths.js')

module.exports = Object.assign(binLinks, {
checkBins,
Expand Down
4 changes: 2 additions & 2 deletions node_modules/bin-links/lib/link-bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const linkGently = require('./link-gently.js')
const fixBin = require('./fix-bin.js')

// linking bins is simple. just symlink, and if we linked it, fix the bin up
const linkBin = ({path, to, from, absFrom, force}) =>
linkGently({path, to, from, absFrom, force})
const linkBin = ({ path, to, from, absFrom, force }) =>
linkGently({ path, to, from, absFrom, force })
.then(linked => linked && fixBin(absFrom))

module.exports = linkBin
9 changes: 5 additions & 4 deletions node_modules/bin-links/lib/link-bins.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ const { dirname, resolve, relative } = require('path')
const linkBin = isWindows ? require('./shim-bin.js') : require('./link-bin.js')
const normalize = require('npm-normalize-package-bin')

const linkBins = ({path, pkg, top, force}) => {
const linkBins = ({ path, pkg, top, force }) => {
pkg = normalize(pkg)
if (!pkg.bin)
if (!pkg.bin) {
return Promise.resolve([])
}
const promises = []
const target = binTarget({path, top})
const target = binTarget({ path, top })
for (const [key, val] of Object.entries(pkg.bin)) {
const to = resolve(target, key)
const absFrom = resolve(path, val)
const from = relative(dirname(to), absFrom)
promises.push(linkBin({path, from, to, absFrom, force}))
promises.push(linkBin({ path, from, to, absFrom, force }))
}
return Promise.all(promises)
}
Expand Down
47 changes: 29 additions & 18 deletions node_modules/bin-links/lib/link-gently.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ const fs = require('fs')
const symlink = promisify(fs.symlink)
const readlink = promisify(fs.readlink)
const lstat = promisify(fs.lstat)
const throwNonEnoent = er => { if (er.code !== 'ENOENT') throw er }
const throwNonEnoent = er => {
if (er.code !== 'ENOENT') {
throw er
}
}

// even in --force mode, we never create a link over a link we've
// already created. you can have multiple packages in a tree trying
Expand All @@ -24,11 +28,12 @@ const rimraf = promisify(require('rimraf'))
const rm = path => rimraf(path, { glob: false })

const SKIP = Symbol('skip - missing or already installed')
const CLOBBER = Symbol('clobber - ours or in forceful mode')
const CLOBBER = Symbol('clobber - ours or in forceful mode')

const linkGently = async ({path, to, from, absFrom, force}) => {
if (seen.has(to))
const linkGently = async ({ path, to, from, absFrom, force }) => {
if (seen.has(to)) {
return true
}
seen.add(to)

// if the script or manpage isn't there, just ignore it.
Expand All @@ -40,36 +45,42 @@ const linkGently = async ({path, to, from, absFrom, force}) => {
lstat(to).catch(throwNonEnoent),
]).then(([stFrom, stTo]) => {
// not present in package, skip it
if (!stFrom)
if (!stFrom) {
return SKIP
}

// exists! maybe clobber if we can
if (stTo) {
if (!stTo.isSymbolicLink())
if (!stTo.isSymbolicLink()) {
return force && rm(to).then(() => CLOBBER)
}

return readlink(to).then(target => {
if (target === from)
return SKIP // skip it, already set up like we want it.
if (target === from) {
return SKIP
} // skip it, already set up like we want it.

target = resolve(dirname(to), target)
if (target.indexOf(path) === 0 || force)
if (target.indexOf(path) === 0 || force) {
return rm(to).then(() => CLOBBER)
}
})
} else {
// doesn't exist, dir might not either
return mkdirp(dirname(to))
}
})
.then(skipOrClobber => {
if (skipOrClobber === SKIP)
return false
return symlink(from, to, 'file').catch(er => {
if (skipOrClobber === CLOBBER || force)
return rm(to).then(() => symlink(from, to, 'file'))
throw er
}).then(() => true)
})
.then(skipOrClobber => {
if (skipOrClobber === SKIP) {
return false
}
return symlink(from, to, 'file').catch(er => {
if (skipOrClobber === CLOBBER || force) {
return rm(to).then(() => symlink(from, to, 'file'))
}
throw er
}).then(() => true)
})
}

const resetSeen = () => {
Expand Down
9 changes: 5 additions & 4 deletions node_modules/bin-links/lib/link-mans.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ const { dirname, relative, join, resolve, basename } = require('path')
const linkGently = require('./link-gently.js')
const manTarget = require('./man-target.js')

const linkMans = ({path, pkg, top, force}) => {
const target = manTarget({path, top})
if (!target || !pkg.man || !Array.isArray(pkg.man) || !pkg.man.length)
const linkMans = ({ path, pkg, top, force }) => {
const target = manTarget({ path, top })
if (!target || !pkg.man || !Array.isArray(pkg.man) || !pkg.man.length) {
return Promise.resolve([])
}

// break any links to c:\\blah or /foo/blah or ../blah
// and filter out duplicates
Expand Down Expand Up @@ -44,7 +45,7 @@ const linkMans = ({path, pkg, top, force}) => {
const to = resolve(target, 'man' + sxn, base)
const from = relative(dirname(to), absFrom)

return linkGently({from, to, path, absFrom, force})
return linkGently({ from, to, path, absFrom, force })
}))
}

Expand Down
4 changes: 2 additions & 2 deletions node_modules/bin-links/lib/man-target.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const isWindows = require('./is-windows.js')
const getPrefix = require('./get-prefix.js')
const {dirname} = require('path')
const { dirname } = require('path')

module.exports = ({top, path}) => !top || isWindows ? null
module.exports = ({ top, path }) => !top || isWindows ? null
: dirname(getPrefix(path)) + '/share/man'
Loading