diff options
author | isaacs <i@izs.me> | 2020-07-11 04:19:53 +0300 |
---|---|---|
committer | isaacs <i@izs.me> | 2020-07-29 21:53:10 +0300 |
commit | e46400c9484f5c66a0ba405eeb8c1340594dbf05 (patch) | |
tree | 1c3c13d9024752c4b3dc129e2f86c7963544c5a4 /node_modules/bin-links | |
parent | 73657ae140810da50847d0ff729ddbab99ba5aac (diff) |
update dependencies, refactor config loading to async
This removes a lot of very outdated dependencies, updates many to
their modern (usually promisified) versions, and updates (or removes)
code to account for the change.
Several dependencies have been completely removed, and others a bit
shuffled around, so that the node_modules folder can be bundled somewhat
more optimally than it would have otherwise.
Diffstat (limited to 'node_modules/bin-links')
24 files changed, 1132 insertions, 465 deletions
diff --git a/node_modules/bin-links/CHANGELOG.md b/node_modules/bin-links/CHANGELOG.md index e7b640c08..0531b01ca 100644 --- a/node_modules/bin-links/CHANGELOG.md +++ b/node_modules/bin-links/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## 2.0.0 + +* Rewrite to promisify and remove dependence on gentle-fs <a name="1.1.7"></a> ## [1.1.7](https://github.com/npm/bin-links/compare/v1.1.6...v1.1.7) (2019-12-26) diff --git a/node_modules/bin-links/LICENSE b/node_modules/bin-links/LICENSE index 0b6c22874..19cec97b1 100644 --- a/node_modules/bin-links/LICENSE +++ b/node_modules/bin-links/LICENSE @@ -1,235 +1,15 @@ -The npm application -Copyright (c) npm, Inc. and Contributors -Licensed on the terms of The Artistic License 2.0 +The ISC License -Node package dependencies of the npm application -Copyright (c) their respective copyright owners -Licensed on their respective license terms +Copyright (c) npm, Inc. -The npm public registry at https://registry.npmjs.org -and the npm website at https://www.npmjs.com -Operated by npm, Inc. -Use governed by terms published on https://www.npmjs.com +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. -"Node.js" -Trademark Joyent, Inc., https://joyent.com -Neither npm nor npm, Inc. are affiliated with Joyent, Inc. - -The Node.js application -Project of Node Foundation, https://nodejs.org - -The npm Logo -Copyright (c) Mathias Pettersson and Brian Hammond - -"Gubblebum Blocky" typeface -Copyright (c) Tjarda Koster, https://jelloween.deviantart.com -Used with permission - - --------- - - -The Artistic License 2.0 - -Copyright (c) 2000-2006, The Perl Foundation. - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - -Preamble - -This license establishes the terms under which a given free software -Package may be copied, modified, distributed, and/or redistributed. -The intent is that the Copyright Holder maintains some artistic -control over the development of that Package while still keeping the -Package available as open source and free software. - -You are always permitted to make arrangements wholly outside of this -license directly with the Copyright Holder of a given Package. If the -terms of this license do not permit the full use that you propose to -make of the Package, you should contact the Copyright Holder and seek -a different licensing arrangement. - -Definitions - - "Copyright Holder" means the individual(s) or organization(s) - named in the copyright notice for the entire Package. - - "Contributor" means any party that has contributed code or other - material to the Package, in accordance with the Copyright Holder's - procedures. - - "You" and "your" means any person who would like to copy, - distribute, or modify the Package. - - "Package" means the collection of files distributed by the - Copyright Holder, and derivatives of that collection and/or of - those files. A given Package may consist of either the Standard - Version, or a Modified Version. - - "Distribute" means providing a copy of the Package or making it - accessible to anyone else, or in the case of a company or - organization, to others outside of your company or organization. - - "Distributor Fee" means any fee that you charge for Distributing - this Package or providing support for this Package to another - party. It does not mean licensing fees. - - "Standard Version" refers to the Package if it has not been - modified, or has been modified only in ways explicitly requested - by the Copyright Holder. - - "Modified Version" means the Package, if it has been changed, and - such changes were not explicitly requested by the Copyright - Holder. - - "Original License" means this Artistic License as Distributed with - the Standard Version of the Package, in its current version or as - it may be modified by The Perl Foundation in the future. - - "Source" form means the source code, documentation source, and - configuration files for the Package. - - "Compiled" form means the compiled bytecode, object code, binary, - or any other form resulting from mechanical transformation or - translation of the Source form. - - -Permission for Use and Modification Without Distribution - -(1) You are permitted to use the Standard Version and create and use -Modified Versions for any purpose without restriction, provided that -you do not Distribute the Modified Version. - - -Permissions for Redistribution of the Standard Version - -(2) You may Distribute verbatim copies of the Source form of the -Standard Version of this Package in any medium without restriction, -either gratis or for a Distributor Fee, provided that you duplicate -all of the original copyright notices and associated disclaimers. At -your discretion, such verbatim copies may or may not include a -Compiled form of the Package. - -(3) You may apply any bug fixes, portability changes, and other -modifications made available from the Copyright Holder. The resulting -Package will still be considered the Standard Version, and as such -will be subject to the Original License. - - -Distribution of Modified Versions of the Package as Source - -(4) You may Distribute your Modified Version as Source (either gratis -or for a Distributor Fee, and with or without a Compiled form of the -Modified Version) provided that you clearly document how it differs -from the Standard Version, including, but not limited to, documenting -any non-standard features, executables, or modules, and provided that -you do at least ONE of the following: - - (a) make the Modified Version available to the Copyright Holder - of the Standard Version, under the Original License, so that the - Copyright Holder may include your modifications in the Standard - Version. - - (b) ensure that installation of your Modified Version does not - prevent the user installing or running the Standard Version. In - addition, the Modified Version must bear a name that is different - from the name of the Standard Version. - - (c) allow anyone who receives a copy of the Modified Version to - make the Source form of the Modified Version available to others - under - - (i) the Original License or - - (ii) a license that permits the licensee to freely copy, - modify and redistribute the Modified Version using the same - licensing terms that apply to the copy that the licensee - received, and requires that the Source form of the Modified - Version, and of any works derived from it, be made freely - available in that license fees are prohibited but Distributor - Fees are allowed. - - -Distribution of Compiled Forms of the Standard Version -or Modified Versions without the Source - -(5) You may Distribute Compiled forms of the Standard Version without -the Source, provided that you include complete instructions on how to -get the Source of the Standard Version. Such instructions must be -valid at the time of your distribution. If these instructions, at any -time while you are carrying out such distribution, become invalid, you -must provide new instructions on demand or cease further distribution. -If you provide valid instructions or cease distribution within thirty -days after you become aware that the instructions are invalid, then -you do not forfeit any of your rights under this license. - -(6) You may Distribute a Modified Version in Compiled form without -the Source, provided that you comply with Section 4 with respect to -the Source of the Modified Version. - - -Aggregating or Linking the Package - -(7) You may aggregate the Package (either the Standard Version or -Modified Version) with other packages and Distribute the resulting -aggregation provided that you do not charge a licensing fee for the -Package. Distributor Fees are permitted, and licensing fees for other -components in the aggregation are permitted. The terms of this license -apply to the use and Distribution of the Standard or Modified Versions -as included in the aggregation. - -(8) You are permitted to link Modified and Standard Versions with -other works, to embed the Package in a larger work of your own, or to -build stand-alone binary or bytecode versions of applications that -include the Package, and Distribute the result without restriction, -provided the result does not expose a direct interface to the Package. - - -Items That are Not Considered Part of a Modified Version - -(9) Works (including, but not limited to, modules and scripts) that -merely extend or make use of the Package, do not, by themselves, cause -the Package to be a Modified Version. In addition, such works are not -considered parts of the Package itself, and are not subject to the -terms of this license. - - -General Provisions - -(10) Any use, modification, and distribution of the Standard or -Modified Versions is governed by this Artistic License. By using, -modifying or distributing the Package, you accept this license. Do not -use, modify, or distribute the Package, if you do not accept this -license. - -(11) If your Modified Version has been derived from a Modified -Version made by someone other than you, you are nevertheless required -to ensure that your Modified Version complies with the requirements of -this license. - -(12) This license does not grant you the right to use any trademark, -service mark, tradename, or logo of the Copyright Holder. - -(13) This license includes the non-exclusive, worldwide, -free-of-charge patent license to make, have made, use, offer to sell, -sell, import and otherwise transfer the Package with respect to any -patent claims licensable by the Copyright Holder that are necessarily -infringed by the Package. If you institute patent litigation -(including a cross-claim or counterclaim) against any party alleging -that the Package constitutes direct or contributory patent -infringement, then this Artistic License to you shall terminate on the -date that such litigation is filed. - -(14) Disclaimer of Warranty: -THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS -IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL -LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - --------- +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. diff --git a/node_modules/bin-links/README.md b/node_modules/bin-links/README.md index 558d5c74b..4e3a8b407 100644 --- a/node_modules/bin-links/README.md +++ b/node_modules/bin-links/README.md @@ -14,19 +14,37 @@ binaries and man pages for Javascript packages * [Contributing](#contributing) * [API](#api) * [`binLinks`](#binLinks) + * [`binLinks.getPaths()`](#getPaths) ### Example ```javascript -// todo +const binLinks = require('bin-links') +const readPackageJson = require('read-package-json-fast') +binLinks({ + path: '/path/to/node_modules/some-package', + pkg: readPackageJson('/path/to/node_modules/some-package/package.json'), + + // true if it's a global install, false for local. default: false + global: true, + + // true if it's the top level package being installed, false otherwise + top: true, + + // true if you'd like to recklessly overwrite files. + force: true, +}) ``` ### Features -* Links bin files listed under the `bin` property of pkg to the node_modules/.bin -directory of the installing environment. -* Links man files listed under the `man` property of pkg to the share/man directory -of the provided optional directory prefix. +* Links bin files listed under the `bin` property of pkg to the + `node_modules/.bin` directory of the installing environment. (Or + `${prefix}/bin` for top level global packages on unix, and `${prefix}` + for top level global packages on Windows.) +* Links man files listed under the `man` property of pkg to the share/man + directory. (This is only done for top-level global packages on Unix + systems.) ### Contributing @@ -38,10 +56,19 @@ jump in if you'd like to, or even ask us questions if something isn't clear. ### API -#### <a name="binLinks"></a> `> binLinks(pkg, folder, global, opts, cb)` +#### <a name="binLinks"></a> `> binLinks({path, pkg, force, global, top})` + +Returns a Promise that resolves when the requisite things have been linked. + +#### <a name="getPaths"></a> `> binLinks.getPaths({path, pkg, global, top })` + +Returns an array of all the paths of links and shims that _might_ be +created (assuming that they exist!) for the package at the specified path. + +Does not touch the filesystem. ##### Example ```javascript -binLinks(pkg, folder, global, opts, cb) -```
\ No newline at end of file +binLinks({path, pkg, force, global, top}).then(() => console.log('bins linked!')) +``` diff --git a/node_modules/bin-links/index.js b/node_modules/bin-links/index.js index 79c2cb585..51cc410af 100644 --- a/node_modules/bin-links/index.js +++ b/node_modules/bin-links/index.js @@ -1,183 +1,30 @@ -'use strict' - -const path = require('path') -const fs = require('graceful-fs') -const BB = require('bluebird') -const gentleFs = require('gentle-fs') -const linkIfExists = BB.promisify(gentleFs.linkIfExists) -const gentleFsBinLink = BB.promisify(gentleFs.binLink) -const open = BB.promisify(fs.open) -const close = BB.promisify(fs.close) -const read = BB.promisify(fs.read, {multiArgs: true}) -const chmod = BB.promisify(fs.chmod) -const readFile = BB.promisify(fs.readFile) -const writeFileAtomic = BB.promisify(require('write-file-atomic')) -const normalize = require('npm-normalize-package-bin') - -module.exports = BB.promisify(binLinks) - -function binLinks (pkg, folder, global, opts, cb) { - pkg = normalize(pkg) - folder = path.resolve(folder) - - // if it's global, and folder is in {prefix}/node_modules, - // then bins are in {prefix}/bin - // otherwise, then bins are in folder/../.bin - var parent = pkg.name && pkg.name[0] === '@' ? path.dirname(path.dirname(folder)) : path.dirname(folder) - var gnm = global && opts.globalDir - var gtop = parent === gnm - - opts.log.info('linkStuff', opts.pkgId) - opts.log.silly('linkStuff', opts.pkgId, 'has', parent, 'as its parent node_modules') - if (global) opts.log.silly('linkStuff', opts.pkgId, 'is part of a global install') - if (gnm) opts.log.silly('linkStuff', opts.pkgId, 'is installed into a global node_modules') - if (gtop) opts.log.silly('linkStuff', opts.pkgId, 'is installed into the top-level global node_modules') - - return BB.join( - linkBins(pkg, folder, parent, gtop, opts), - linkMans(pkg, folder, parent, gtop, opts) - ).asCallback(cb) -} - -function isHashbangFile (file) { - return open(file, 'r').then(fileHandle => { - return read(fileHandle, Buffer.alloc(2), 0, 2, 0).spread((_, buf) => { - if (!hasHashbang(buf)) return [] - return read(fileHandle, Buffer.alloc(2048), 0, 2048, 0) - }).spread((_, buf) => buf && hasCR(buf), /* istanbul ignore next */ () => false) - .finally(() => close(fileHandle)) - }).catch(/* istanbul ignore next */ () => false) -} - -function hasHashbang (buf) { - const str = buf.toString() - return str.slice(0, 2) === '#!' -} - -function hasCR (buf) { - return /^#![^\n]+\r\n/.test(buf) -} - -function dos2Unix (file) { - return readFile(file, 'utf8').then(content => { - return writeFileAtomic(file, content.replace(/^(#![^\n]+)\r\n/, '$1\n')) - }) -} - -function getLinkOpts (opts, gently) { - return Object.assign({}, opts, { gently: gently }) -} - -function linkBins (pkg, folder, parent, gtop, opts) { - if (!pkg.bin || (!gtop && path.basename(parent) !== 'node_modules')) { - return - } - var linkOpts = getLinkOpts(opts, gtop && folder) - var execMode = parseInt('0777', 8) & (~opts.umask) - var binRoot = gtop ? opts.globalBin - : path.resolve(parent, '.bin') - opts.log.verbose('linkBins', [pkg.bin, binRoot, gtop]) - - return BB.map(Object.keys(pkg.bin), bin => { - var dest = path.resolve(binRoot, bin) - var src = path.resolve(folder, pkg.bin[bin]) - - /* istanbul ignore if - that unpossible */ - if (src.indexOf(folder) !== 0) { - throw new Error('invalid bin entry for package ' + - pkg._id + '. key=' + bin + ', value=' + pkg.bin[bin]) - } - - return linkBin(src, dest, linkOpts).then(() => { - // bins should always be executable. - // XXX skip chmod on windows? - return chmod(src, execMode) - }).then(() => { - return isHashbangFile(src) - }).then(isHashbang => { - if (!isHashbang) return - opts.log.silly('linkBins', 'Converting line endings of hashbang file:', src) - return dos2Unix(src) - }).then(() => { - if (!gtop) return - var dest = path.resolve(binRoot, bin) - var out = opts.parseable - ? dest + '::' + src + ':BINFILE' - : dest + ' -> ' + src - - if (!opts.json && !opts.parseable) { - opts.log.clearProgress() - console.log(out) - opts.log.showProgress() - } - }).catch(err => { - /* istanbul ignore next */ - if (err.code === 'ENOENT' && opts.ignoreScripts) return - throw err - }) - }) -} - -function linkBin (from, to, opts) { - // do not clobber global bins - if (opts.globalBin && to.indexOf(opts.globalBin) === 0) { - opts.clobberLinkGently = true - } - return gentleFsBinLink(from, to, opts) -} - -function linkMans (pkg, folder, parent, gtop, opts) { - if (!pkg.man || !gtop || process.platform === 'win32') return - - var manRoot = path.resolve(opts.prefix, 'share', 'man') - opts.log.verbose('linkMans', 'man files are', pkg.man, 'in', manRoot) - - // make sure that the mans are unique. - // otherwise, if there are dupes, it'll fail with EEXIST - var set = pkg.man.reduce(function (acc, man) { - if (typeof man !== 'string') { - return acc - } - const cleanMan = path.join('/', man).replace(/\\|:/g, '/').substr(1) - acc[path.basename(man)] = cleanMan - return acc - }, {}) - var manpages = pkg.man.filter(function (man) { - if (typeof man !== 'string') { - return false - } - const cleanMan = path.join('/', man).replace(/\\|:/g, '/').substr(1) - return set[path.basename(man)] === cleanMan - }) - - return BB.map(manpages, man => { - opts.log.silly('linkMans', 'preparing to link', man) - var parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/) - if (!parseMan) { - throw new Error( - man + ' is not a valid name for a man file. ' + - 'Man files must end with a number, ' + - 'and optionally a .gz suffix if they are compressed.' - ) - } - - var stem = parseMan[1] - var sxn = parseMan[2] - var bn = path.basename(stem) - var manSrc = path.resolve(folder, man) - /* istanbul ignore if - that unpossible */ - if (manSrc.indexOf(folder) !== 0) { - throw new Error('invalid man entry for package ' + - pkg._id + '. man=' + manSrc) - } - - var manDest = path.join(manRoot, 'man' + sxn, bn) - - // man pages should always be clobbering gently, because they are - // only installed for top-level global packages, so never destroy - // a link if it doesn't point into the folder we're linking - opts.clobberLinkGently = true - - return linkIfExists(manSrc, manDest, getLinkOpts(opts, gtop && folder)) - }) -} +const linkBins = require('./lib/link-bins.js') +const linkMans = require('./lib/link-mans.js') + +const binLinks = opts => { + const { path, pkg, force, global, top } = opts + // global top pkgs on windows get bins installed in {prefix}, and no mans + // + // unix global top pkgs get their bins installed in {prefix}/bin, + // and mans in {prefix}/share/man + // + // non-top pkgs get their bins installed in {prefix}/node_modules/.bin, + // and do not install mans + // + // 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) + 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}), + ]) +} + +binLinks.getPaths = require('./lib/get-paths.js') +module.exports = binLinks diff --git a/node_modules/bin-links/lib/bin-target.js b/node_modules/bin-links/lib/bin-target.js new file mode 100644 index 000000000..7ea0c2a96 --- /dev/null +++ b/node_modules/bin-links/lib/bin-target.js @@ -0,0 +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') + +module.exports = ({top, path}) => + !top ? getNodeModules(path) + '/.bin' + : isWindows ? getPrefix(path) + : dirname(getPrefix(path)) + '/bin' diff --git a/node_modules/bin-links/lib/fix-bin.js b/node_modules/bin-links/lib/fix-bin.js new file mode 100644 index 000000000..0f4d5fa02 --- /dev/null +++ b/node_modules/bin-links/lib/fix-bin.js @@ -0,0 +1,44 @@ +// make sure that bins are executable, and that they don't have +// windows line-endings on the hashbang line. +const fs = require('fs') +const { promisify } = require('util') + +const execMode = 0o777 & (~process.umask()) + +const writeFileAtomic = promisify(require('write-file-atomic')) +const open = promisify(fs.open) +const close = promisify(fs.close) +const read = promisify(fs.read) +const chmod = promisify(fs.chmod) +const readFile = promisify(fs.readFile) + +const isWindowsHashBang = buf => + buf[0] === '#'.charCodeAt(0) && + buf[1] === '!'.charCodeAt(0) && + /^#![^\n]+\r\n/.test(buf.toString()) + +const isWindowsHashbangFile = file => { + const FALSE = () => false + return open(file, 'r').then(fd => { + const buf = Buffer.alloc(2048) + return read(fd, buf, 0, 2048, 0) + .then( + () => { + const isWHB = isWindowsHashBang(buf) + return close(fd).then(() => isWHB, () => isWHB) + }, + // don't leak FD if read() fails + () => close(fd).then(FALSE, FALSE) + ) + }, FALSE) +} + +const dos2Unix = file => + readFile(file, 'utf8').then(content => + writeFileAtomic(file, content.replace(/^(#![^\n]+)\r\n/, '$1\n'))) + +const fixBin = file => chmod(file, execMode) + .then(() => isWindowsHashbangFile(file)) + .then(isWHB => isWHB ? dos2Unix(file) : null) + +module.exports = fixBin diff --git a/node_modules/bin-links/lib/get-node-modules.js b/node_modules/bin-links/lib/get-node-modules.js new file mode 100644 index 000000000..b67c198ef --- /dev/null +++ b/node_modules/bin-links/lib/get-node-modules.js @@ -0,0 +1,18 @@ +// we know it's global and/or not top, so the path has to be +// {prefix}/node_modules/{name}. Can't rely on pkg.name, because +// it might be installed as an alias. + +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)) + return memo.get(path) + + const scopeOrNm = dirname(path) + const nm = basename(scopeOrNm) === 'node_modules' ? scopeOrNm + : dirname(scopeOrNm) + + memo.set(path, nm) + return nm +} diff --git a/node_modules/bin-links/lib/get-paths.js b/node_modules/bin-links/lib/get-paths.js new file mode 100644 index 000000000..614c85652 --- /dev/null +++ b/node_modules/bin-links/lib/get-paths.js @@ -0,0 +1,48 @@ +// get all the paths that are (or might be) installed for a given pkg +// There's no guarantee that all of these will be installed, but if they +// 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 isWindows = require('./is-windows.js') +module.exports = ({path, pkg, global, top}) => { + if (top && !global) + return [] + + const binSet = [] + const binTarg = binTarget({path, top}) + if (pkg.bin) { + for (const bin of Object.keys(pkg.bin)) { + const b = resolve(binTarg, bin) + binSet.push(b) + if (isWindows) { + binSet.push(b + '.cmd') + binSet.push(b + '.ps1') + } + } + } + + 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) + 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) + return binSet + + manSet.push(resolve(manTarg, 'man' + sxn, base)) + } + } + + return manSet.length ? [...binSet, ...manSet] : binSet +} diff --git a/node_modules/bin-links/lib/get-prefix.js b/node_modules/bin-links/lib/get-prefix.js new file mode 100644 index 000000000..96112bf0a --- /dev/null +++ b/node_modules/bin-links/lib/get-prefix.js @@ -0,0 +1,3 @@ +const {dirname} = require('path') +const getNodeModules = require('./get-node-modules.js') +module.exports = path => dirname(getNodeModules(path)) diff --git a/node_modules/bin-links/lib/is-windows.js b/node_modules/bin-links/lib/is-windows.js new file mode 100644 index 000000000..da3b2fb22 --- /dev/null +++ b/node_modules/bin-links/lib/is-windows.js @@ -0,0 +1,2 @@ +const platform = process.env.__TESTING_BIN_LINKS_PLATFORM__ || process.platform +module.exports = platform === 'win32' diff --git a/node_modules/bin-links/lib/link-bin.js b/node_modules/bin-links/lib/link-bin.js new file mode 100644 index 000000000..4c0bde489 --- /dev/null +++ b/node_modules/bin-links/lib/link-bin.js @@ -0,0 +1,9 @@ +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}) + .then(linked => linked && fixBin(absFrom)) + +module.exports = linkBin diff --git a/node_modules/bin-links/lib/link-bins.js b/node_modules/bin-links/lib/link-bins.js new file mode 100644 index 000000000..6a1086b92 --- /dev/null +++ b/node_modules/bin-links/lib/link-bins.js @@ -0,0 +1,22 @@ +const isWindows = require('./is-windows.js') +const binTarget = require('./bin-target.js') +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}) => { + pkg = normalize(pkg) + if (!pkg.bin) + return Promise.resolve([]) + const promises = [] + 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})) + } + return Promise.all(promises) +} + +module.exports = linkBins diff --git a/node_modules/bin-links/lib/link-gently.js b/node_modules/bin-links/lib/link-gently.js new file mode 100644 index 000000000..75b157618 --- /dev/null +++ b/node_modules/bin-links/lib/link-gently.js @@ -0,0 +1,57 @@ +// if the thing isn't there, skip it +// if there's a non-symlink there already, eexist +// if there's a symlink already, pointing somewhere else, eexist +// if there's a symlink already, pointing into our pkg, remove it first +// then create the symlink + +const { promisify } = require('util') +const { resolve, dirname } = require('path') +const mkdirp = require('mkdirp-infer-owner') +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 } + +// disable glob in our rimraf calls +const rimraf = promisify(require('rimraf')) +const rm = path => rimraf(path, { glob: false }) + +const SKIP = Symbol('skip - missing or already installed') + +const linkGently = ({path, to, from, absFrom, force}) => { + // if the script or manpage isn't there, just ignore it. + // this arguably *should* be an install error of some sort, + // or at least a warning, but npm has always behaved this + // way in the past, so it'd be a breaking change + return Promise.all([ + lstat(absFrom).catch(throwNonEnoent), + lstat(to).catch(throwNonEnoent), + ]).then(([stFrom, stTo]) => { + // not present in package, skip it + if (!stFrom) + return SKIP + + // exists! maybe clobber if we can + if (stTo) { + if (!stTo.isSymbolicLink()) + return force ? rm(to) : Promise.resolve() + + return readlink(to).then(target => { + 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) + return rm(to) + }) + } else { + // doesn't exist, dir might not either + return mkdirp(dirname(to)) + } + }) + // this will fail if we didn't remove it + .then(skip => skip !== SKIP && symlink(from, to, 'file').then(() => true)) +} + +module.exports = linkGently diff --git a/node_modules/bin-links/lib/link-mans.js b/node_modules/bin-links/lib/link-mans.js new file mode 100644 index 000000000..6fb167e48 --- /dev/null +++ b/node_modules/bin-links/lib/link-mans.js @@ -0,0 +1,51 @@ +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) + return Promise.resolve([]) + + // break any links to c:\\blah or /foo/blah or ../blah + // and filter out duplicates + const set = [...new Set(pkg.man.map(man => + man ? join('/', man).replace(/\\|:/g, '/').substr(1) : null) + .filter(man => typeof man === 'string'))] + + return Promise.all(set.map(man => { + const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/) + if (!parseMan) { + return Promise.reject(Object.assign(new Error('invalid man entry name\n' + + 'Man files must end with a number, ' + + 'and optionally a .gz suffix if they are compressed.' + ), { + code: 'EBADMAN', + path, + pkgid: pkg._id, + man, + })) + } + + const stem = parseMan[1] + const sxn = parseMan[2] + const base = basename(stem) + const absFrom = resolve(path, man) + /* istanbul ignore if - that unpossible */ + if (absFrom.indexOf(path) !== 0) { + return Promise.reject(Object.assign(new Error('invalid man entry'), { + code: 'EBADMAN', + path, + pkgid: pkg._id, + man, + })) + } + + const to = resolve(target, 'man' + sxn, base) + const from = relative(dirname(to), absFrom) + + return linkGently({from, to, path, absFrom, force}) + })) +} + +module.exports = linkMans diff --git a/node_modules/bin-links/lib/man-target.js b/node_modules/bin-links/lib/man-target.js new file mode 100644 index 000000000..832d2ea35 --- /dev/null +++ b/node_modules/bin-links/lib/man-target.js @@ -0,0 +1,6 @@ +const isWindows = require('./is-windows.js') +const getPrefix = require('./get-prefix.js') +const {dirname} = require('path') + +module.exports = ({top, path}) => !top || isWindows ? null + : dirname(getPrefix(path)) + '/share/man' diff --git a/node_modules/bin-links/lib/shim-bin.js b/node_modules/bin-links/lib/shim-bin.js new file mode 100644 index 000000000..ff7c99a90 --- /dev/null +++ b/node_modules/bin-links/lib/shim-bin.js @@ -0,0 +1,64 @@ +const { promisify } = require('util') +const { resolve, dirname } = require('path') +const fs = require('fs') +const lstat = promisify(fs.lstat) +const throwNonEnoent = er => { if (er.code !== 'ENOENT') throw er } + +const cmdShim = require('cmd-shim') +const readCmdShim = require('read-cmd-shim') + +const fixBin = require('./fix-bin.js') + +const failEEXIST = ({path, to, from}) => + Promise.reject(Object.assign(new Error('EEXIST: file already exists'), { + path: to, + dest: from, + code: 'EEXIST', + })) + +const handleReadCmdShimError = ({er, from, to}) => + er.code === 'ENOENT' ? null + : er.code === 'ENOTASHIM' ? failEEXIST({from, to}) + : Promise.reject(er) + +const SKIP = Symbol('skip - missing or already installed') +const shimBin = ({path, to, from, absFrom, force}) => { + const shims = [ + to, + to + '.cmd', + to + '.ps1', + ] + return Promise.all([ + ...shims, + absFrom, + ].map(f => lstat(f).catch(throwNonEnoent))).then((stats) => { + const [ + stToBase, + stToCmd, + stToPs1, + stFrom, + ] = stats + if (!stFrom) + return SKIP + + if (force) + return + + return Promise.all(shims.map((s, i) => [s, stats[i]]).map(([s, st]) => { + if (!st) + return + return readCmdShim(s) + .then(target => { + target = resolve(dirname(to), target) + if (target.indexOf(resolve(path)) !== 0) + return failEEXIST({from, to, path}) + }, er => handleReadCmdShimError({er, from, to})) + })) + }) + .then(skip => skip !== SKIP && doShim(absFrom, to)) +} + +const doShim = (absFrom, to) => + cmdShim(absFrom, to).then(() => fixBin(absFrom)) + +module.exports = shimBin diff --git a/node_modules/bin-links/node_modules/.bin/rimraf b/node_modules/bin-links/node_modules/.bin/rimraf new file mode 120000 index 000000000..4cd49a49d --- /dev/null +++ b/node_modules/bin-links/node_modules/.bin/rimraf @@ -0,0 +1 @@ +../rimraf/bin.js
\ No newline at end of file diff --git a/node_modules/bin-links/node_modules/rimraf/CHANGELOG.md b/node_modules/bin-links/node_modules/rimraf/CHANGELOG.md new file mode 100644 index 000000000..f116f1414 --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/CHANGELOG.md @@ -0,0 +1,65 @@ +# v3.0 + +- Add `--preserve-root` option to executable (default true) +- Drop support for Node.js below version 6 + +# v2.7 + +- Make `glob` an optional dependency + +# 2.6 + +- Retry on EBUSY on non-windows platforms as well +- Make `rimraf.sync` 10000% more reliable on Windows + +# 2.5 + +- Handle Windows EPERM when lstat-ing read-only dirs +- Add glob option to pass options to glob + +# 2.4 + +- Add EPERM to delay/retry loop +- Add `disableGlob` option + +# 2.3 + +- Make maxBusyTries and emfileWait configurable +- Handle weird SunOS unlink-dir issue +- Glob the CLI arg for better Windows support + +# 2.2 + +- Handle ENOENT properly on Windows +- Allow overriding fs methods +- Treat EPERM as indicative of non-empty dir +- Remove optional graceful-fs dep +- Consistently return null error instead of undefined on success +- win32: Treat ENOTEMPTY the same as EBUSY +- Add `rimraf` binary + +# 2.1 + +- Fix SunOS error code for a non-empty directory +- Try rmdir before readdir +- Treat EISDIR like EPERM +- Remove chmod +- Remove lstat polyfill, node 0.7 is not supported + +# 2.0 + +- Fix myGid call to check process.getgid +- Simplify the EBUSY backoff logic. +- Use fs.lstat in node >= 0.7.9 +- Remove gently option +- remove fiber implementation +- Delete files that are marked read-only + +# 1.0 + +- Allow ENOENT in sync method +- Throw when no callback is provided +- Make opts.gently an absolute path +- use 'stat' if 'lstat' is not available +- Consistent error naming, and rethrow non-ENOENT stat errors +- add fiber implementation diff --git a/node_modules/bin-links/node_modules/rimraf/LICENSE b/node_modules/bin-links/node_modules/rimraf/LICENSE new file mode 100644 index 000000000..19129e315 --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +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. + +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. diff --git a/node_modules/bin-links/node_modules/rimraf/README.md b/node_modules/bin-links/node_modules/rimraf/README.md new file mode 100644 index 000000000..423b8cf85 --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/README.md @@ -0,0 +1,101 @@ +[![Build Status](https://travis-ci.org/isaacs/rimraf.svg?branch=master)](https://travis-ci.org/isaacs/rimraf) [![Dependency Status](https://david-dm.org/isaacs/rimraf.svg)](https://david-dm.org/isaacs/rimraf) [![devDependency Status](https://david-dm.org/isaacs/rimraf/dev-status.svg)](https://david-dm.org/isaacs/rimraf#info=devDependencies) + +The [UNIX command](http://en.wikipedia.org/wiki/Rm_(Unix)) `rm -rf` for node. + +Install with `npm install rimraf`, or just drop rimraf.js somewhere. + +## API + +`rimraf(f, [opts], callback)` + +The first parameter will be interpreted as a globbing pattern for files. If you +want to disable globbing you can do so with `opts.disableGlob` (defaults to +`false`). This might be handy, for instance, if you have filenames that contain +globbing wildcard characters. + +The callback will be called with an error if there is one. Certain +errors are handled for you: + +* Windows: `EBUSY` and `ENOTEMPTY` - rimraf will back off a maximum of + `opts.maxBusyTries` times before giving up, adding 100ms of wait + between each attempt. The default `maxBusyTries` is 3. +* `ENOENT` - If the file doesn't exist, rimraf will return + successfully, since your desired outcome is already the case. +* `EMFILE` - Since `readdir` requires opening a file descriptor, it's + possible to hit `EMFILE` if too many file descriptors are in use. + In the sync case, there's nothing to be done for this. But in the + async case, rimraf will gradually back off with timeouts up to + `opts.emfileWait` ms, which defaults to 1000. + +## options + +* unlink, chmod, stat, lstat, rmdir, readdir, + unlinkSync, chmodSync, statSync, lstatSync, rmdirSync, readdirSync + + In order to use a custom file system library, you can override + specific fs functions on the options object. + + If any of these functions are present on the options object, then + the supplied function will be used instead of the default fs + method. + + Sync methods are only relevant for `rimraf.sync()`, of course. + + For example: + + ```javascript + var myCustomFS = require('some-custom-fs') + + rimraf('some-thing', myCustomFS, callback) + ``` + +* maxBusyTries + + If an `EBUSY`, `ENOTEMPTY`, or `EPERM` error code is encountered + on Windows systems, then rimraf will retry with a linear backoff + wait of 100ms longer on each try. The default maxBusyTries is 3. + + Only relevant for async usage. + +* emfileWait + + If an `EMFILE` error is encountered, then rimraf will retry + repeatedly with a linear backoff of 1ms longer on each try, until + the timeout counter hits this max. The default limit is 1000. + + If you repeatedly encounter `EMFILE` errors, then consider using + [graceful-fs](http://npm.im/graceful-fs) in your program. + + Only relevant for async usage. + +* glob + + Set to `false` to disable [glob](http://npm.im/glob) pattern + matching. + + Set to an object to pass options to the glob module. The default + glob options are `{ nosort: true, silent: true }`. + + Glob version 6 is used in this module. + + Relevant for both sync and async usage. + +* disableGlob + + Set to any non-falsey value to disable globbing entirely. + (Equivalent to setting `glob: false`.) + +## rimraf.sync + +It can remove stuff synchronously, too. But that's not so good. Use +the async API. It's better. + +## CLI + +If installed with `npm install rimraf -g` it can be used as a global +command `rimraf <path> [<path> ...]` which is useful for cross platform support. + +## mkdirp + +If you need to create a directory recursively, check out +[mkdirp](https://github.com/substack/node-mkdirp). diff --git a/node_modules/bin-links/node_modules/rimraf/bin.js b/node_modules/bin-links/node_modules/rimraf/bin.js new file mode 100755 index 000000000..023814cc9 --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/bin.js @@ -0,0 +1,68 @@ +#!/usr/bin/env node + +const rimraf = require('./') + +const path = require('path') + +const isRoot = arg => /^(\/|[a-zA-Z]:\\)$/.test(path.resolve(arg)) +const filterOutRoot = arg => { + const ok = preserveRoot === false || !isRoot(arg) + if (!ok) { + console.error(`refusing to remove ${arg}`) + console.error('Set --no-preserve-root to allow this') + } + return ok +} + +let help = false +let dashdash = false +let noglob = false +let preserveRoot = true +const args = process.argv.slice(2).filter(arg => { + if (dashdash) + return !!arg + else if (arg === '--') + dashdash = true + else if (arg === '--no-glob' || arg === '-G') + noglob = true + else if (arg === '--glob' || arg === '-g') + noglob = false + else if (arg.match(/^(-+|\/)(h(elp)?|\?)$/)) + help = true + else if (arg === '--preserve-root') + preserveRoot = true + else if (arg === '--no-preserve-root') + preserveRoot = false + else + return !!arg +}).filter(arg => !preserveRoot || filterOutRoot(arg)) + +const go = n => { + if (n >= args.length) + return + const options = noglob ? { glob: false } : {} + rimraf(args[n], options, er => { + if (er) + throw er + go(n+1) + }) +} + +if (help || args.length === 0) { + // If they didn't ask for help, then this is not a "success" + const log = help ? console.log : console.error + log('Usage: rimraf <path> [<path> ...]') + log('') + log(' Deletes all files and folders at "path" recursively.') + log('') + log('Options:') + log('') + log(' -h, --help Display this usage info') + log(' -G, --no-glob Do not expand glob patterns in arguments') + log(' -g, --glob Expand glob patterns in arguments (default)') + log(' --preserve-root Do not remove \'/\' (default)') + log(' --no-preserve-root Do not treat \'/\' specially') + log(' -- Stop parsing flags') + process.exit(help ? 0 : 1) +} else + go(0) diff --git a/node_modules/bin-links/node_modules/rimraf/package.json b/node_modules/bin-links/node_modules/rimraf/package.json new file mode 100644 index 000000000..e109e110c --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/package.json @@ -0,0 +1,70 @@ +{ + "_from": "rimraf@^3.0.0", + "_id": "rimraf@3.0.2", + "_inBundle": false, + "_integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "_location": "/bin-links/rimraf", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "rimraf@^3.0.0", + "name": "rimraf", + "escapedName": "rimraf", + "rawSpec": "^3.0.0", + "saveSpec": null, + "fetchSpec": "^3.0.0" + }, + "_requiredBy": [ + "/bin-links" + ], + "_resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "_shasum": "f1a5402ba6220ad52cc1282bac1ae3aa49fd061a", + "_spec": "rimraf@^3.0.0", + "_where": "/Users/isaacs/dev/npm/cli/node_modules/bin-links", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "bin": { + "rimraf": "bin.js" + }, + "bugs": { + "url": "https://github.com/isaacs/rimraf/issues" + }, + "bundleDependencies": false, + "dependencies": { + "glob": "^7.1.3" + }, + "deprecated": false, + "description": "A deep deletion module for node (like `rm -rf`)", + "devDependencies": { + "mkdirp": "^0.5.1", + "tap": "^12.1.1" + }, + "files": [ + "LICENSE", + "README.md", + "bin.js", + "rimraf.js" + ], + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "homepage": "https://github.com/isaacs/rimraf#readme", + "license": "ISC", + "main": "rimraf.js", + "name": "rimraf", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/rimraf.git" + }, + "scripts": { + "postpublish": "git push origin --follow-tags", + "postversion": "npm publish", + "preversion": "npm test", + "test": "tap test/*.js" + }, + "version": "3.0.2" +} diff --git a/node_modules/bin-links/node_modules/rimraf/rimraf.js b/node_modules/bin-links/node_modules/rimraf/rimraf.js new file mode 100644 index 000000000..34da4171d --- /dev/null +++ b/node_modules/bin-links/node_modules/rimraf/rimraf.js @@ -0,0 +1,360 @@ +const assert = require("assert") +const path = require("path") +const fs = require("fs") +let glob = undefined +try { + glob = require("glob") +} catch (_err) { + // treat glob as optional. +} + +const defaultGlobOpts = { + nosort: true, + silent: true +} + +// for EMFILE handling +let timeout = 0 + +const isWindows = (process.platform === "win32") + +const defaults = options => { + const methods = [ + 'unlink', + 'chmod', + 'stat', + 'lstat', + 'rmdir', + 'readdir' + ] + methods.forEach(m => { + options[m] = options[m] || fs[m] + m = m + 'Sync' + options[m] = options[m] || fs[m] + }) + + options.maxBusyTries = options.maxBusyTries || 3 + options.emfileWait = options.emfileWait || 1000 + if (options.glob === false) { + options.disableGlob = true + } + if (options.disableGlob !== true && glob === undefined) { + throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') + } + options.disableGlob = options.disableGlob || false + options.glob = options.glob || defaultGlobOpts +} + +const rimraf = (p, options, cb) => { + if (typeof options === 'function') { + cb = options + options = {} + } + + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert.equal(typeof cb, 'function', 'rimraf: callback function required') + assert(options, 'rimraf: invalid options argument provided') + assert.equal(typeof options, 'object', 'rimraf: options should be object') + + defaults(options) + + let busyTries = 0 + let errState = null + let n = 0 + + const next = (er) => { + errState = errState || er + if (--n === 0) + cb(errState) + } + + const afterGlob = (er, results) => { + if (er) + return cb(er) + + n = results.length + if (n === 0) + return cb() + + results.forEach(p => { + const CB = (er) => { + if (er) { + if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && + busyTries < options.maxBusyTries) { + busyTries ++ + // try again, with the same exact callback as this one. + return setTimeout(() => rimraf_(p, options, CB), busyTries * 100) + } + + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < options.emfileWait) { + return setTimeout(() => rimraf_(p, options, CB), timeout ++) + } + + // already gone + if (er.code === "ENOENT") er = null + } + + timeout = 0 + next(er) + } + rimraf_(p, options, CB) + }) + } + + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) + + options.lstat(p, (er, stat) => { + if (!er) + return afterGlob(null, [p]) + + glob(p, options.glob, afterGlob) + }) + +} + +// Two possible strategies. +// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR +// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR +// +// Both result in an extra syscall when you guess wrong. However, there +// are likely far more normal files in the world than directories. This +// is based on the assumption that a the average number of files per +// directory is >= 1. +// +// If anyone ever complains about this, then I guess the strategy could +// be made configurable somehow. But until then, YAGNI. +const rimraf_ = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + + // sunos lets the root user unlink directories, which is... weird. + // so we have to lstat here and make sure it's not a dir. + options.lstat(p, (er, st) => { + if (er && er.code === "ENOENT") + return cb(null) + + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) + + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) + + options.unlink(p, er => { + if (er) { + if (er.code === "ENOENT") + return cb(null) + if (er.code === "EPERM") + return (isWindows) + ? fixWinEPERM(p, options, er, cb) + : rmdir(p, options, er, cb) + if (er.code === "EISDIR") + return rmdir(p, options, er, cb) + } + return cb(er) + }) + }) +} + +const fixWinEPERM = (p, options, er, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + + options.chmod(p, 0o666, er2 => { + if (er2) + cb(er2.code === "ENOENT" ? null : er) + else + options.stat(p, (er3, stats) => { + if (er3) + cb(er3.code === "ENOENT" ? null : er) + else if (stats.isDirectory()) + rmdir(p, options, er, cb) + else + options.unlink(p, cb) + }) + }) +} + +const fixWinEPERMSync = (p, options, er) => { + assert(p) + assert(options) + + try { + options.chmodSync(p, 0o666) + } catch (er2) { + if (er2.code === "ENOENT") + return + else + throw er + } + + let stats + try { + stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er + } + + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) +} + +const rmdir = (p, options, originalEr, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + + // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) + // if we guessed wrong, and it's not a directory, then + // raise the original error. + options.rmdir(p, er => { + if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) + rmkids(p, options, cb) + else if (er && er.code === "ENOTDIR") + cb(originalEr) + else + cb(er) + }) +} + +const rmkids = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + + options.readdir(p, (er, files) => { + if (er) + return cb(er) + let n = files.length + if (n === 0) + return options.rmdir(p, cb) + let errState + files.forEach(f => { + rimraf(path.join(p, f), options, er => { + if (errState) + return + if (er) + return cb(errState = er) + if (--n === 0) + options.rmdir(p, cb) + }) + }) + }) +} + +// this looks simpler, and is strictly *faster*, but will +// tie up the JavaScript thread and fail on excessively +// deep directory trees. +const rimrafSync = (p, options) => { + options = options || {} + defaults(options) + + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert(options, 'rimraf: missing options') + assert.equal(typeof options, 'object', 'rimraf: options should be object') + + let results + + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } + } + + if (!results.length) + return + + for (let i = 0; i < results.length; i++) { + const p = results[i] + + let st + try { + st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } + + try { + // sunos lets the root user unlink directories, which is... weird. + if (st && st.isDirectory()) + rmdirSync(p, options, null) + else + options.unlinkSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "EPERM") + return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) + if (er.code !== "EISDIR") + throw er + + rmdirSync(p, options, er) + } + } +} + +const rmdirSync = (p, options, originalEr) => { + assert(p) + assert(options) + + try { + options.rmdirSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "ENOTDIR") + throw originalEr + if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") + rmkidsSync(p, options) + } +} + +const rmkidsSync = (p, options) => { + assert(p) + assert(options) + options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) + + // We only end up here once we got ENOTEMPTY at least once, and + // at this point, we are guaranteed to have removed all the kids. + // So, we know that it won't be ENOENT or ENOTDIR or anything else. + // try really hard to delete stuff on windows, because it has a + // PROFOUNDLY annoying habit of not closing handles promptly when + // files are deleted, resulting in spurious ENOTEMPTY errors. + const retries = isWindows ? 100 : 1 + let i = 0 + do { + let threw = true + try { + const ret = options.rmdirSync(p, options) + threw = false + return ret + } finally { + if (++i < retries && threw) + continue + } + } while (true) +} + +module.exports = rimraf +rimraf.sync = rimrafSync diff --git a/node_modules/bin-links/package.json b/node_modules/bin-links/package.json index 45393d11c..950031ddb 100644 --- a/node_modules/bin-links/package.json +++ b/node_modules/bin-links/package.json @@ -1,67 +1,63 @@ { - "_from": "bin-links@1.1.7", - "_id": "bin-links@1.1.7", + "_from": "bin-links@latest", + "_id": "bin-links@2.1.2", "_inBundle": false, - "_integrity": "sha512-/eaLaTu7G7/o7PV04QPy1HRT65zf+1tFkPGv0sPTV0tRwufooYBQO3zrcyGgm+ja+ZtBf2GEuKjDRJ2pPG+yqA==", + "_integrity": "sha512-mtspzc/umzMiZkIRIVm93WgyT7fFVXX302qswWwlHErBVM8BgAVvB0EVOdzmtrNzs1zIKEE0dE4RR5PwtBfy7g==", "_location": "/bin-links", - "_phantomChildren": {}, + "_phantomChildren": { + "glob": "7.1.4" + }, "_requested": { - "type": "version", + "type": "tag", "registry": true, - "raw": "bin-links@1.1.7", + "raw": "bin-links@latest", "name": "bin-links", "escapedName": "bin-links", - "rawSpec": "1.1.7", + "rawSpec": "latest", "saveSpec": null, - "fetchSpec": "1.1.7" + "fetchSpec": "latest" }, "_requiredBy": [ "#USER", "/", - "/libcipm", - "/libnpm" + "/@npmcli/arborist" ], - "_resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.7.tgz", - "_shasum": "34b79ea9d0e575d7308afeff0c6b2fc24c793359", - "_spec": "bin-links@1.1.7", - "_where": "/Users/mperrotte/npminc/cli", - "author": { - "name": "Mike Sherov" - }, + "_resolved": "https://registry.npmjs.org/bin-links/-/bin-links-2.1.2.tgz", + "_shasum": "110f82e5563caf66c4483c1eb5d84043ef571660", + "_spec": "bin-links@latest", + "_where": "/Users/isaacs/dev/npm/cli", "bugs": { "url": "https://github.com/npm/bin-links/issues" }, "bundleDependencies": false, "dependencies": { - "bluebird": "^3.5.3", - "cmd-shim": "^3.0.0", - "gentle-fs": "^2.3.0", - "graceful-fs": "^4.1.15", + "cmd-shim": "^4.0.1", + "mkdirp": "^1.0.3", "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", "write-file-atomic": "^2.3.0" }, "deprecated": false, "description": "JavaScript package binary linker", "devDependencies": { - "mkdirp": "^0.5.1", - "nyc": "^13.1.0", - "rimraf": "^2.6.3", - "standard": "^10.0.3", - "standard-version": "^4.4.0", - "tap": "^12.1.3", - "weallbehave": "^1.2.0", - "weallcontribute": "^1.0.8" + "require-inject": "^1.4.4", + "tap": "^14.10.6" + }, + "engines": { + "node": ">=10" }, "files": [ - "index.js" + "index.js", + "lib/*.js" ], "homepage": "https://github.com/npm/bin-links#readme", "keywords": [ "npm", - "gentle", - "fs" + "link", + "bins" ], - "license": "Artistic-2.0", + "license": "ISC", "main": "index.js", "name": "bin-links", "repository": { @@ -69,13 +65,15 @@ "url": "git://github.com/npm/bin-links.git" }, "scripts": { - "postrelease": "npm publish && git push --follow-tags", - "posttest": "standard", - "prerelease": "npm t", - "release": "standard-version -s", - "test": "tap -J --nyc-arg=--all --coverage test/*.js --100", - "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", - "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" + "postversion": "npm publish", + "prepublishOnly": "git push --follow-tags", + "preversion": "npm t", + "snap": "tap", + "test": "tap" + }, + "tap": { + "check-coverage": true, + "coverage-map": "map.js" }, - "version": "1.1.7" + "version": "2.1.2" } |