Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithgar authored Jan 20, 2022
1 parent 14a3d95 commit 2ef9f98
Show file tree
Hide file tree
Showing 25 changed files with 298 additions and 249 deletions.
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

0 comments on commit 2ef9f98

Please sign in to comment.