diff options
120 files changed, 2044 insertions, 2237 deletions
diff --git a/deps/npm/README.md b/deps/npm/README.md index 642e1a51eb..7e4a5f38a7 100644 --- a/deps/npm/README.md +++ b/deps/npm/README.md @@ -50,7 +50,7 @@ npm <command> * [**Documentation**](https://docs.npmjs.com/) - Official docs & how-tos for all things **npm** * Note: you can also search docs locally with `npm help-search <query>` * [**Bug Tracker**](https://github.com/npm/cli/issues) - Search or submit bugs against the CLI -* [**Roadmap**](https://github.com/npm/roadmap) - Track & follow along with our public roadmap +* [**Roadmap**](https://github.com/orgs/github/projects/4247/views/1?filterQuery=npm) - Track & follow along with our public roadmap * [**Feedback**](https://github.com/npm/feedback) - Contribute ideas & discussion around the npm registry, website & CLI * [**RFCs**](https://github.com/npm/rfcs) - Contribute ideas & specifications for the API/design of the npm CLI * [**Service Status**](https://status.npmjs.org/) - Monitor the current status & see incident reports for the website & registry diff --git a/deps/npm/docs/content/commands/npm-bin.md b/deps/npm/docs/content/commands/npm-bin.md index 94b72cfd5c..b344ea2fc9 100644 --- a/deps/npm/docs/content/commands/npm-bin.md +++ b/deps/npm/docs/content/commands/npm-bin.md @@ -34,6 +34,8 @@ Print the folder where npm will install executables. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-ci.md b/deps/npm/docs/content/commands/npm-ci.md index 2bb542a725..3374bf1e25 100644 --- a/deps/npm/docs/content/commands/npm-ci.md +++ b/deps/npm/docs/content/commands/npm-ci.md @@ -1,7 +1,7 @@ --- title: npm-ci section: 1 -description: Install a project with a clean slate +description: Clean install a project --- ### Synopsis @@ -28,12 +28,7 @@ it's meant to be used in automated environments such as test platforms, continuous integration, and deployment -- or any situation where you want to make sure you're doing a clean install of your dependencies. -`npm ci` will be significantly faster when: - -- There is a `package-lock.json` or `npm-shrinkwrap.json` file. -- The `node_modules` folder is missing or empty. - -In short, the main differences between using `npm install` and `npm ci` are: +The main differences between using `npm install` and `npm ci` are: * The project **must** have an existing `package-lock.json` or `npm-shrinkwrap.json`. diff --git a/deps/npm/docs/content/commands/npm-config.md b/deps/npm/docs/content/commands/npm-config.md index a66a198ce4..809e42a1be 100644 --- a/deps/npm/docs/content/commands/npm-config.md +++ b/deps/npm/docs/content/commands/npm-config.md @@ -124,6 +124,8 @@ Not supported by all npm commands. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See @@ -156,6 +158,15 @@ The command to run for `npm edit` and `npm config edit`. When passed to `npm config` this refers to which config file to use. +When set to "global" mode, packages are installed into the `prefix` folder +instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the `{prefix}/lib/node_modules` folder, instead + of the current working directory. +* bin files are linked to `{prefix}/bin` +* man pages are linked to `{prefix}/share/man` + <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> diff --git a/deps/npm/docs/content/commands/npm-diff.md b/deps/npm/docs/content/commands/npm-diff.md index 7dcc8af7c3..7183e4a2b7 100644 --- a/deps/npm/docs/content/commands/npm-diff.md +++ b/deps/npm/docs/content/commands/npm-diff.md @@ -248,6 +248,8 @@ Treat all files as text in `npm diff`. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-install-test.md b/deps/npm/docs/content/commands/npm-install-test.md index 3dd860ea5c..18e374869d 100644 --- a/deps/npm/docs/content/commands/npm-install-test.md +++ b/deps/npm/docs/content/commands/npm-install-test.md @@ -70,6 +70,8 @@ rather than using npm's default semver range operator. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-install.md b/deps/npm/docs/content/commands/npm-install.md index d6668a2c2b..318df5780e 100644 --- a/deps/npm/docs/content/commands/npm-install.md +++ b/deps/npm/docs/content/commands/npm-install.md @@ -460,6 +460,8 @@ rather than using npm's default semver range operator. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-link.md b/deps/npm/docs/content/commands/npm-link.md index 975c807c38..34c67aa3de 100644 --- a/deps/npm/docs/content/commands/npm-link.md +++ b/deps/npm/docs/content/commands/npm-link.md @@ -153,6 +153,8 @@ rather than using npm's default semver range operator. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-ls.md b/deps/npm/docs/content/commands/npm-ls.md index ded8c0c0d2..5ad4593bfa 100644 --- a/deps/npm/docs/content/commands/npm-ls.md +++ b/deps/npm/docs/content/commands/npm-ls.md @@ -137,6 +137,8 @@ Output parseable results from commands that write to standard output. For * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-outdated.md b/deps/npm/docs/content/commands/npm-outdated.md index 6fa026550e..1bf2de039c 100644 --- a/deps/npm/docs/content/commands/npm-outdated.md +++ b/deps/npm/docs/content/commands/npm-outdated.md @@ -150,6 +150,8 @@ Output parseable results from commands that write to standard output. For * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-prefix.md b/deps/npm/docs/content/commands/npm-prefix.md index 39328bcc88..6f08e43fa8 100644 --- a/deps/npm/docs/content/commands/npm-prefix.md +++ b/deps/npm/docs/content/commands/npm-prefix.md @@ -51,6 +51,8 @@ npm prefix -g * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-rebuild.md b/deps/npm/docs/content/commands/npm-rebuild.md index 52c368c8c5..fa5b0cfa97 100644 --- a/deps/npm/docs/content/commands/npm-rebuild.md +++ b/deps/npm/docs/content/commands/npm-rebuild.md @@ -42,6 +42,8 @@ will be rebuilt. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-root.md b/deps/npm/docs/content/commands/npm-root.md index 40b58e4b33..80545235fc 100644 --- a/deps/npm/docs/content/commands/npm-root.md +++ b/deps/npm/docs/content/commands/npm-root.md @@ -41,6 +41,8 @@ echo "Global packages installed in: ${global_node_modules}" * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/commands/npm-set-script.md b/deps/npm/docs/content/commands/npm-set-script.md index 0fc267f760..8695b43f14 100644 --- a/deps/npm/docs/content/commands/npm-set-script.md +++ b/deps/npm/docs/content/commands/npm-set-script.md @@ -7,6 +7,8 @@ description: Set tasks in the scripts section of package.json ### Synopsis An npm command that lets you create a task in the `scripts` section of the `package.json`. +Deprecated. + <!-- AUTOGENERATED USAGE DESCRIPTIONS START --> <!-- automatically generated, do not edit manually --> <!-- see lib/commands/set-script.js --> diff --git a/deps/npm/docs/content/commands/npm-update.md b/deps/npm/docs/content/commands/npm-update.md index 421d04ca3d..55aad182fc 100644 --- a/deps/npm/docs/content/commands/npm-update.md +++ b/deps/npm/docs/content/commands/npm-update.md @@ -188,6 +188,8 @@ Will also prevent writing to `package-lock.json` if set to `false`. * Default: false * Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. Operates in "global" mode, so that packages are installed into the `prefix` folder instead of the current working directory. See diff --git a/deps/npm/docs/content/using-npm/config.md b/deps/npm/docs/content/using-npm/config.md index a33e791bb8..12b508582a 100644 --- a/deps/npm/docs/content/using-npm/config.md +++ b/deps/npm/docs/content/using-npm/config.md @@ -687,23 +687,6 @@ results in no commit being made at all. <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> -#### `global` - -* Default: false -* Type: Boolean - -Operates in "global" mode, so that packages are installed into the `prefix` -folder instead of the current working directory. See -[folders](/configuring-npm/folders) for more on the differences in behavior. - -* packages are installed into the `{prefix}/lib/node_modules` folder, instead - of the current working directory. -* bin files are linked to `{prefix}/bin` -* man pages are linked to `{prefix}/share/man` - -<!-- automatically generated, do not edit manually --> -<!-- see lib/utils/config/definitions.js --> - #### `global-style` * Default: false @@ -1001,6 +984,15 @@ npm registry. Must be IPv4 in versions of Node prior to 0.12. When passed to `npm config` this refers to which config file to use. +When set to "global" mode, packages are installed into the `prefix` folder +instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the `{prefix}/lib/node_modules` folder, instead + of the current working directory. +* bin files are linked to `{prefix}/bin` +* man pages are linked to `{prefix}/share/man` + <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> @@ -1941,6 +1933,25 @@ Alias for `--include=dev`. <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> +#### `global` + +* Default: false +* Type: Boolean +* DEPRECATED: `--global`, `--local` are deprecated. Use `--location=global` + instead. + +Operates in "global" mode, so that packages are installed into the `prefix` +folder instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the `{prefix}/lib/node_modules` folder, instead + of the current working directory. +* bin files are linked to `{prefix}/bin` +* man pages are linked to `{prefix}/share/man` + +<!-- automatically generated, do not edit manually --> +<!-- see lib/utils/config/definitions.js --> + #### `init.author.email` * Default: "" diff --git a/deps/npm/docs/output/commands/npm-bin.html b/deps/npm/docs/output/commands/npm-bin.html index 5961ea7e50..7b957b6014 100644 --- a/deps/npm/docs/output/commands/npm-bin.html +++ b/deps/npm/docs/output/commands/npm-bin.html @@ -165,6 +165,8 @@ npm command-line interface <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-ci.html b/deps/npm/docs/output/commands/npm-ci.html index 713f7b0c81..4f9a194ae5 100644 --- a/deps/npm/docs/output/commands/npm-ci.html +++ b/deps/npm/docs/output/commands/npm-ci.html @@ -137,7 +137,7 @@ npm command-line interface <section id="content"> <header class="title"> <h1 id="npm-ci">npm-ci</h1> -<span class="description">Install a project with a clean slate</span> +<span class="description">Clean install a project</span> </header> <section id="table_of_contents"> @@ -161,12 +161,7 @@ aliases: clean-install, ic, install-clean, isntall-clean it's meant to be used in automated environments such as test platforms, continuous integration, and deployment -- or any situation where you want to make sure you're doing a clean install of your dependencies.</p> -<p><code>npm ci</code> will be significantly faster when:</p> -<ul> -<li>There is a <code>package-lock.json</code> or <code>npm-shrinkwrap.json</code> file.</li> -<li>The <code>node_modules</code> folder is missing or empty.</li> -</ul> -<p>In short, the main differences between using <code>npm install</code> and <code>npm ci</code> are:</p> +<p>The main differences between using <code>npm install</code> and <code>npm ci</code> are:</p> <ul> <li>The project <strong>must</strong> have an existing <code>package-lock.json</code> or <code>npm-shrinkwrap.json</code>.</li> diff --git a/deps/npm/docs/output/commands/npm-config.html b/deps/npm/docs/output/commands/npm-config.html index f8b279756d..e267531fc0 100644 --- a/deps/npm/docs/output/commands/npm-config.html +++ b/deps/npm/docs/output/commands/npm-config.html @@ -223,6 +223,8 @@ saving them to your <code>package.json</code>.</li> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See @@ -251,6 +253,15 @@ to "global"</li> <li>Type: "global", "user", or "project"</li> </ul> <p>When passed to <code>npm config</code> this refers to which config file to use.</p> +<p>When set to "global" mode, packages are installed into the <code>prefix</code> folder +instead of the current working directory. See +<a href="../configuring-npm/folders.html">folders</a> for more on the differences in behavior.</p> +<ul> +<li>packages are installed into the <code>{prefix}/lib/node_modules</code> folder, instead +of the current working directory.</li> +<li>bin files are linked to <code>{prefix}/bin</code></li> +<li>man pages are linked to <code>{prefix}/share/man</code></li> +</ul> <!-- raw HTML omitted --> <!-- raw HTML omitted --> <h4 id="long"><code>long</code></h4> diff --git a/deps/npm/docs/output/commands/npm-diff.html b/deps/npm/docs/output/commands/npm-diff.html index 13ed989c46..7ee9d76d22 100644 --- a/deps/npm/docs/output/commands/npm-diff.html +++ b/deps/npm/docs/output/commands/npm-diff.html @@ -334,6 +334,8 @@ located within the folder <code>./lib/</code> and changed lines of code within t <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-install-test.html b/deps/npm/docs/output/commands/npm-install-test.html index 6306ceb593..fce049dc2c 100644 --- a/deps/npm/docs/output/commands/npm-install-test.html +++ b/deps/npm/docs/output/commands/npm-install-test.html @@ -196,6 +196,8 @@ rather than using npm's default semver range operator.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-install.html b/deps/npm/docs/output/commands/npm-install.html index 509702b5bd..ca6ca1ee26 100644 --- a/deps/npm/docs/output/commands/npm-install.html +++ b/deps/npm/docs/output/commands/npm-install.html @@ -522,6 +522,8 @@ rather than using npm's default semver range operator.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-link.html b/deps/npm/docs/output/commands/npm-link.html index f7d5f66a9e..cb43c0478d 100644 --- a/deps/npm/docs/output/commands/npm-link.html +++ b/deps/npm/docs/output/commands/npm-link.html @@ -251,6 +251,8 @@ rather than using npm's default semver range operator.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 579b54a388..10caff53c3 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -166,7 +166,7 @@ tree at all, use <a href="../commands/npm-explain.html"><code>npm explain</code> the results to only the paths to the packages named. Note that nested packages will <em>also</em> show the paths to the specified packages. For example, running <code>npm ls promzard</code> in npm's source tree will show:</p> -<pre lang="bash"><code>npm@8.10.0 /path/to/npm +<pre lang="bash"><code>npm@8.11.0 /path/to/npm └─┬ init-package-json@0.0.4 └── promzard@0.1.5 </code></pre> @@ -246,6 +246,8 @@ saving them to your <code>package.json</code>.</li> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-outdated.html b/deps/npm/docs/output/commands/npm-outdated.html index 0bdb9f9a66..15030d6008 100644 --- a/deps/npm/docs/output/commands/npm-outdated.html +++ b/deps/npm/docs/output/commands/npm-outdated.html @@ -268,6 +268,8 @@ saving them to your <code>package.json</code>.</li> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-prefix.html b/deps/npm/docs/output/commands/npm-prefix.html index 2f30214426..df6960ef97 100644 --- a/deps/npm/docs/output/commands/npm-prefix.html +++ b/deps/npm/docs/output/commands/npm-prefix.html @@ -176,6 +176,8 @@ also specified.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-rebuild.html b/deps/npm/docs/output/commands/npm-rebuild.html index f4524f1a4f..84837a3be5 100644 --- a/deps/npm/docs/output/commands/npm-rebuild.html +++ b/deps/npm/docs/output/commands/npm-rebuild.html @@ -173,6 +173,8 @@ will be rebuilt.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-root.html b/deps/npm/docs/output/commands/npm-root.html index e0595fd8e7..c9cc1d4b67 100644 --- a/deps/npm/docs/output/commands/npm-root.html +++ b/deps/npm/docs/output/commands/npm-root.html @@ -170,6 +170,8 @@ echo "Global packages installed in: ${global_node_modules}" <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm-set-script.html b/deps/npm/docs/output/commands/npm-set-script.html index 51b29d87fa..d9bc6b6077 100644 --- a/deps/npm/docs/output/commands/npm-set-script.html +++ b/deps/npm/docs/output/commands/npm-set-script.html @@ -147,6 +147,7 @@ npm command-line interface <div id="_content"><h3 id="synopsis">Synopsis</h3> <p>An npm command that lets you create a task in the <code>scripts</code> section of the <code>package.json</code>.</p> +<p>Deprecated.</p> <!-- raw HTML omitted --> <!-- raw HTML omitted --> <!-- raw HTML omitted --> diff --git a/deps/npm/docs/output/commands/npm-update.html b/deps/npm/docs/output/commands/npm-update.html index d88ea8578b..d0cb6d5f75 100644 --- a/deps/npm/docs/output/commands/npm-update.html +++ b/deps/npm/docs/output/commands/npm-update.html @@ -275,6 +275,8 @@ be <em>downgraded</em>.</p> <ul> <li>Default: false</li> <li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> </ul> <p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> folder instead of the current working directory. See diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index 4a816cc1a9..99c109c4e2 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -149,7 +149,7 @@ npm command-line interface <!-- raw HTML omitted --> <!-- raw HTML omitted --> <h3 id="version">Version</h3> -<p>8.10.0</p> +<p>8.11.0</p> <h3 id="description">Description</h3> <p>npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency diff --git a/deps/npm/docs/output/using-npm/config.html b/deps/npm/docs/output/using-npm/config.html index d00c7654e1..ef033b8693 100644 --- a/deps/npm/docs/output/using-npm/config.html +++ b/deps/npm/docs/output/using-npm/config.html @@ -142,7 +142,7 @@ npm command-line interface <section id="table_of_contents"> <h2 id="table-of-contents">Table of contents</h2> -<div id="_table_of_contents"><ul><li><a href="#description">Description</a></li><ul><li><a href="#command-line-flags">Command Line Flags</a></li><li><a href="#environment-variables">Environment Variables</a></li><li><a href="#npmrc-files">npmrc Files</a></li><li><a href="#default-configs">Default Configs</a></li></ul><li><a href="#shorthands-and-other-cli-niceties">Shorthands and Other CLI Niceties</a></li><li><a href="#config-settings">Config Settings</a></li><ul><li><a href="#auth"><code>_auth</code></a></li><li><a href="#access"><code>access</code></a></li><li><a href="#all"><code>all</code></a></li><li><a href="#allow-same-version"><code>allow-same-version</code></a></li><li><a href="#audit"><code>audit</code></a></li><li><a href="#audit-level"><code>audit-level</code></a></li><li><a href="#before"><code>before</code></a></li><li><a href="#bin-links"><code>bin-links</code></a></li><li><a href="#browser"><code>browser</code></a></li><li><a href="#ca"><code>ca</code></a></li><li><a href="#cache"><code>cache</code></a></li><li><a href="#cafile"><code>cafile</code></a></li><li><a href="#call"><code>call</code></a></li><li><a href="#cert"><code>cert</code></a></li><li><a href="#ci-name"><code>ci-name</code></a></li><li><a href="#cidr"><code>cidr</code></a></li><li><a href="#color"><code>color</code></a></li><li><a href="#commit-hooks"><code>commit-hooks</code></a></li><li><a href="#depth"><code>depth</code></a></li><li><a href="#description2"><code>description</code></a></li><li><a href="#diff"><code>diff</code></a></li><li><a href="#diff-dst-prefix"><code>diff-dst-prefix</code></a></li><li><a href="#diff-ignore-all-space"><code>diff-ignore-all-space</code></a></li><li><a href="#diff-name-only"><code>diff-name-only</code></a></li><li><a href="#diff-no-prefix"><code>diff-no-prefix</code></a></li><li><a href="#diff-src-prefix"><code>diff-src-prefix</code></a></li><li><a href="#diff-text"><code>diff-text</code></a></li><li><a href="#diff-unified"><code>diff-unified</code></a></li><li><a href="#dry-run"><code>dry-run</code></a></li><li><a href="#editor"><code>editor</code></a></li><li><a href="#engine-strict"><code>engine-strict</code></a></li><li><a href="#fetch-retries"><code>fetch-retries</code></a></li><li><a href="#fetch-retry-factor"><code>fetch-retry-factor</code></a></li><li><a href="#fetch-retry-maxtimeout"><code>fetch-retry-maxtimeout</code></a></li><li><a href="#fetch-retry-mintimeout"><code>fetch-retry-mintimeout</code></a></li><li><a href="#fetch-timeout"><code>fetch-timeout</code></a></li><li><a href="#force"><code>force</code></a></li><li><a href="#foreground-scripts"><code>foreground-scripts</code></a></li><li><a href="#format-package-lock"><code>format-package-lock</code></a></li><li><a href="#fund"><code>fund</code></a></li><li><a href="#git"><code>git</code></a></li><li><a href="#git-tag-version"><code>git-tag-version</code></a></li><li><a href="#global"><code>global</code></a></li><li><a href="#global-style"><code>global-style</code></a></li><li><a href="#globalconfig"><code>globalconfig</code></a></li><li><a href="#heading"><code>heading</code></a></li><li><a href="#https-proxy"><code>https-proxy</code></a></li><li><a href="#if-present"><code>if-present</code></a></li><li><a href="#ignore-scripts"><code>ignore-scripts</code></a></li><li><a href="#include"><code>include</code></a></li><li><a href="#include-staged"><code>include-staged</code></a></li><li><a href="#include-workspace-root"><code>include-workspace-root</code></a></li><li><a href="#init-author-email"><code>init-author-email</code></a></li><li><a href="#init-author-name"><code>init-author-name</code></a></li><li><a href="#init-author-url"><code>init-author-url</code></a></li><li><a href="#init-license"><code>init-license</code></a></li><li><a href="#init-module"><code>init-module</code></a></li><li><a href="#init-version"><code>init-version</code></a></li><li><a href="#install-links"><code>install-links</code></a></li><li><a href="#json"><code>json</code></a></li><li><a href="#key"><code>key</code></a></li><li><a href="#legacy-bundling"><code>legacy-bundling</code></a></li><li><a href="#legacy-peer-deps"><code>legacy-peer-deps</code></a></li><li><a href="#link"><code>link</code></a></li><li><a href="#local-address"><code>local-address</code></a></li><li><a href="#location"><code>location</code></a></li><li><a href="#lockfile-version"><code>lockfile-version</code></a></li><li><a href="#loglevel"><code>loglevel</code></a></li><li><a href="#logs-dir"><code>logs-dir</code></a></li><li><a href="#logs-max"><code>logs-max</code></a></li><li><a href="#long"><code>long</code></a></li><li><a href="#maxsockets"><code>maxsockets</code></a></li><li><a href="#message"><code>message</code></a></li><li><a href="#node-options"><code>node-options</code></a></li><li><a href="#node-version"><code>node-version</code></a></li><li><a href="#noproxy"><code>noproxy</code></a></li><li><a href="#npm-version"><code>npm-version</code></a></li><li><a href="#offline"><code>offline</code></a></li><li><a href="#omit"><code>omit</code></a></li><li><a href="#omit-lockfile-registry-resolved"><code>omit-lockfile-registry-resolved</code></a></li><li><a href="#otp"><code>otp</code></a></li><li><a href="#pack-destination"><code>pack-destination</code></a></li><li><a href="#package"><code>package</code></a></li><li><a href="#package-lock"><code>package-lock</code></a></li><li><a href="#package-lock-only"><code>package-lock-only</code></a></li><li><a href="#parseable"><code>parseable</code></a></li><li><a href="#prefer-offline"><code>prefer-offline</code></a></li><li><a href="#prefer-online"><code>prefer-online</code></a></li><li><a href="#prefix"><code>prefix</code></a></li><li><a href="#preid"><code>preid</code></a></li><li><a href="#progress"><code>progress</code></a></li><li><a href="#proxy"><code>proxy</code></a></li><li><a href="#read-only"><code>read-only</code></a></li><li><a href="#rebuild-bundle"><code>rebuild-bundle</code></a></li><li><a href="#registry"><code>registry</code></a></li><li><a href="#save"><code>save</code></a></li><li><a href="#save-bundle"><code>save-bundle</code></a></li><li><a href="#save-dev"><code>save-dev</code></a></li><li><a href="#save-exact"><code>save-exact</code></a></li><li><a href="#save-optional"><code>save-optional</code></a></li><li><a href="#save-peer"><code>save-peer</code></a></li><li><a href="#save-prefix"><code>save-prefix</code></a></li><li><a href="#save-prod"><code>save-prod</code></a></li><li><a href="#scope"><code>scope</code></a></li><li><a href="#script-shell"><code>script-shell</code></a></li><li><a href="#searchexclude"><code>searchexclude</code></a></li><li><a href="#searchlimit"><code>searchlimit</code></a></li><li><a href="#searchopts"><code>searchopts</code></a></li><li><a href="#searchstaleness"><code>searchstaleness</code></a></li><li><a href="#shell"><code>shell</code></a></li><li><a href="#sign-git-commit"><code>sign-git-commit</code></a></li><li><a href="#sign-git-tag"><code>sign-git-tag</code></a></li><li><a href="#strict-peer-deps"><code>strict-peer-deps</code></a></li><li><a href="#strict-ssl"><code>strict-ssl</code></a></li><li><a href="#tag"><code>tag</code></a></li><li><a href="#tag-version-prefix"><code>tag-version-prefix</code></a></li><li><a href="#timing"><code>timing</code></a></li><li><a href="#umask"><code>umask</code></a></li><li><a href="#unicode"><code>unicode</code></a></li><li><a href="#update-notifier"><code>update-notifier</code></a></li><li><a href="#usage"><code>usage</code></a></li><li><a href="#user-agent"><code>user-agent</code></a></li><li><a href="#userconfig"><code>userconfig</code></a></li><li><a href="#version"><code>version</code></a></li><li><a href="#versions"><code>versions</code></a></li><li><a href="#viewer"><code>viewer</code></a></li><li><a href="#which"><code>which</code></a></li><li><a href="#workspace"><code>workspace</code></a></li><li><a href="#workspaces"><code>workspaces</code></a></li><li><a href="#workspaces-update"><code>workspaces-update</code></a></li><li><a href="#yes"><code>yes</code></a></li><li><a href="#also"><code>also</code></a></li><li><a href="#auth-type"><code>auth-type</code></a></li><li><a href="#cache-max"><code>cache-max</code></a></li><li><a href="#cache-min"><code>cache-min</code></a></li><li><a href="#dev"><code>dev</code></a></li><li><a href="#initauthoremail"><code>init.author.email</code></a></li><li><a href="#initauthorname"><code>init.author.name</code></a></li><li><a href="#initauthorurl"><code>init.author.url</code></a></li><li><a href="#initlicense"><code>init.license</code></a></li><li><a href="#initmodule"><code>init.module</code></a></li><li><a href="#initversion"><code>init.version</code></a></li><li><a href="#only"><code>only</code></a></li><li><a href="#optional"><code>optional</code></a></li><li><a href="#production"><code>production</code></a></li><li><a href="#shrinkwrap"><code>shrinkwrap</code></a></li><li><a href="#sso-poll-frequency"><code>sso-poll-frequency</code></a></li><li><a href="#sso-type"><code>sso-type</code></a></li><li><a href="#tmp"><code>tmp</code></a></li></ul><li><a href="#see-also">See also</a></li></ul></div> +<div id="_table_of_contents"><ul><li><a href="#description">Description</a></li><ul><li><a href="#command-line-flags">Command Line Flags</a></li><li><a href="#environment-variables">Environment Variables</a></li><li><a href="#npmrc-files">npmrc Files</a></li><li><a href="#default-configs">Default Configs</a></li></ul><li><a href="#shorthands-and-other-cli-niceties">Shorthands and Other CLI Niceties</a></li><li><a href="#config-settings">Config Settings</a></li><ul><li><a href="#auth"><code>_auth</code></a></li><li><a href="#access"><code>access</code></a></li><li><a href="#all"><code>all</code></a></li><li><a href="#allow-same-version"><code>allow-same-version</code></a></li><li><a href="#audit"><code>audit</code></a></li><li><a href="#audit-level"><code>audit-level</code></a></li><li><a href="#before"><code>before</code></a></li><li><a href="#bin-links"><code>bin-links</code></a></li><li><a href="#browser"><code>browser</code></a></li><li><a href="#ca"><code>ca</code></a></li><li><a href="#cache"><code>cache</code></a></li><li><a href="#cafile"><code>cafile</code></a></li><li><a href="#call"><code>call</code></a></li><li><a href="#cert"><code>cert</code></a></li><li><a href="#ci-name"><code>ci-name</code></a></li><li><a href="#cidr"><code>cidr</code></a></li><li><a href="#color"><code>color</code></a></li><li><a href="#commit-hooks"><code>commit-hooks</code></a></li><li><a href="#depth"><code>depth</code></a></li><li><a href="#description2"><code>description</code></a></li><li><a href="#diff"><code>diff</code></a></li><li><a href="#diff-dst-prefix"><code>diff-dst-prefix</code></a></li><li><a href="#diff-ignore-all-space"><code>diff-ignore-all-space</code></a></li><li><a href="#diff-name-only"><code>diff-name-only</code></a></li><li><a href="#diff-no-prefix"><code>diff-no-prefix</code></a></li><li><a href="#diff-src-prefix"><code>diff-src-prefix</code></a></li><li><a href="#diff-text"><code>diff-text</code></a></li><li><a href="#diff-unified"><code>diff-unified</code></a></li><li><a href="#dry-run"><code>dry-run</code></a></li><li><a href="#editor"><code>editor</code></a></li><li><a href="#engine-strict"><code>engine-strict</code></a></li><li><a href="#fetch-retries"><code>fetch-retries</code></a></li><li><a href="#fetch-retry-factor"><code>fetch-retry-factor</code></a></li><li><a href="#fetch-retry-maxtimeout"><code>fetch-retry-maxtimeout</code></a></li><li><a href="#fetch-retry-mintimeout"><code>fetch-retry-mintimeout</code></a></li><li><a href="#fetch-timeout"><code>fetch-timeout</code></a></li><li><a href="#force"><code>force</code></a></li><li><a href="#foreground-scripts"><code>foreground-scripts</code></a></li><li><a href="#format-package-lock"><code>format-package-lock</code></a></li><li><a href="#fund"><code>fund</code></a></li><li><a href="#git"><code>git</code></a></li><li><a href="#git-tag-version"><code>git-tag-version</code></a></li><li><a href="#global-style"><code>global-style</code></a></li><li><a href="#globalconfig"><code>globalconfig</code></a></li><li><a href="#heading"><code>heading</code></a></li><li><a href="#https-proxy"><code>https-proxy</code></a></li><li><a href="#if-present"><code>if-present</code></a></li><li><a href="#ignore-scripts"><code>ignore-scripts</code></a></li><li><a href="#include"><code>include</code></a></li><li><a href="#include-staged"><code>include-staged</code></a></li><li><a href="#include-workspace-root"><code>include-workspace-root</code></a></li><li><a href="#init-author-email"><code>init-author-email</code></a></li><li><a href="#init-author-name"><code>init-author-name</code></a></li><li><a href="#init-author-url"><code>init-author-url</code></a></li><li><a href="#init-license"><code>init-license</code></a></li><li><a href="#init-module"><code>init-module</code></a></li><li><a href="#init-version"><code>init-version</code></a></li><li><a href="#install-links"><code>install-links</code></a></li><li><a href="#json"><code>json</code></a></li><li><a href="#key"><code>key</code></a></li><li><a href="#legacy-bundling"><code>legacy-bundling</code></a></li><li><a href="#legacy-peer-deps"><code>legacy-peer-deps</code></a></li><li><a href="#link"><code>link</code></a></li><li><a href="#local-address"><code>local-address</code></a></li><li><a href="#location"><code>location</code></a></li><li><a href="#lockfile-version"><code>lockfile-version</code></a></li><li><a href="#loglevel"><code>loglevel</code></a></li><li><a href="#logs-dir"><code>logs-dir</code></a></li><li><a href="#logs-max"><code>logs-max</code></a></li><li><a href="#long"><code>long</code></a></li><li><a href="#maxsockets"><code>maxsockets</code></a></li><li><a href="#message"><code>message</code></a></li><li><a href="#node-options"><code>node-options</code></a></li><li><a href="#node-version"><code>node-version</code></a></li><li><a href="#noproxy"><code>noproxy</code></a></li><li><a href="#npm-version"><code>npm-version</code></a></li><li><a href="#offline"><code>offline</code></a></li><li><a href="#omit"><code>omit</code></a></li><li><a href="#omit-lockfile-registry-resolved"><code>omit-lockfile-registry-resolved</code></a></li><li><a href="#otp"><code>otp</code></a></li><li><a href="#pack-destination"><code>pack-destination</code></a></li><li><a href="#package"><code>package</code></a></li><li><a href="#package-lock"><code>package-lock</code></a></li><li><a href="#package-lock-only"><code>package-lock-only</code></a></li><li><a href="#parseable"><code>parseable</code></a></li><li><a href="#prefer-offline"><code>prefer-offline</code></a></li><li><a href="#prefer-online"><code>prefer-online</code></a></li><li><a href="#prefix"><code>prefix</code></a></li><li><a href="#preid"><code>preid</code></a></li><li><a href="#progress"><code>progress</code></a></li><li><a href="#proxy"><code>proxy</code></a></li><li><a href="#read-only"><code>read-only</code></a></li><li><a href="#rebuild-bundle"><code>rebuild-bundle</code></a></li><li><a href="#registry"><code>registry</code></a></li><li><a href="#save"><code>save</code></a></li><li><a href="#save-bundle"><code>save-bundle</code></a></li><li><a href="#save-dev"><code>save-dev</code></a></li><li><a href="#save-exact"><code>save-exact</code></a></li><li><a href="#save-optional"><code>save-optional</code></a></li><li><a href="#save-peer"><code>save-peer</code></a></li><li><a href="#save-prefix"><code>save-prefix</code></a></li><li><a href="#save-prod"><code>save-prod</code></a></li><li><a href="#scope"><code>scope</code></a></li><li><a href="#script-shell"><code>script-shell</code></a></li><li><a href="#searchexclude"><code>searchexclude</code></a></li><li><a href="#searchlimit"><code>searchlimit</code></a></li><li><a href="#searchopts"><code>searchopts</code></a></li><li><a href="#searchstaleness"><code>searchstaleness</code></a></li><li><a href="#shell"><code>shell</code></a></li><li><a href="#sign-git-commit"><code>sign-git-commit</code></a></li><li><a href="#sign-git-tag"><code>sign-git-tag</code></a></li><li><a href="#strict-peer-deps"><code>strict-peer-deps</code></a></li><li><a href="#strict-ssl"><code>strict-ssl</code></a></li><li><a href="#tag"><code>tag</code></a></li><li><a href="#tag-version-prefix"><code>tag-version-prefix</code></a></li><li><a href="#timing"><code>timing</code></a></li><li><a href="#umask"><code>umask</code></a></li><li><a href="#unicode"><code>unicode</code></a></li><li><a href="#update-notifier"><code>update-notifier</code></a></li><li><a href="#usage"><code>usage</code></a></li><li><a href="#user-agent"><code>user-agent</code></a></li><li><a href="#userconfig"><code>userconfig</code></a></li><li><a href="#version"><code>version</code></a></li><li><a href="#versions"><code>versions</code></a></li><li><a href="#viewer"><code>viewer</code></a></li><li><a href="#which"><code>which</code></a></li><li><a href="#workspace"><code>workspace</code></a></li><li><a href="#workspaces"><code>workspaces</code></a></li><li><a href="#workspaces-update"><code>workspaces-update</code></a></li><li><a href="#yes"><code>yes</code></a></li><li><a href="#also"><code>also</code></a></li><li><a href="#auth-type"><code>auth-type</code></a></li><li><a href="#cache-max"><code>cache-max</code></a></li><li><a href="#cache-min"><code>cache-min</code></a></li><li><a href="#dev"><code>dev</code></a></li><li><a href="#global"><code>global</code></a></li><li><a href="#initauthoremail"><code>init.author.email</code></a></li><li><a href="#initauthorname"><code>init.author.name</code></a></li><li><a href="#initauthorurl"><code>init.author.url</code></a></li><li><a href="#initlicense"><code>init.license</code></a></li><li><a href="#initmodule"><code>init.module</code></a></li><li><a href="#initversion"><code>init.version</code></a></li><li><a href="#only"><code>only</code></a></li><li><a href="#optional"><code>optional</code></a></li><li><a href="#production"><code>production</code></a></li><li><a href="#shrinkwrap"><code>shrinkwrap</code></a></li><li><a href="#sso-poll-frequency"><code>sso-poll-frequency</code></a></li><li><a href="#sso-type"><code>sso-type</code></a></li><li><a href="#tmp"><code>tmp</code></a></li></ul><li><a href="#see-also">See also</a></li></ul></div> </section> <div id="_content"><h3 id="description">Description</h3> @@ -696,22 +696,6 @@ but is not in the <code>PATH</code>, then set this to the full path to the git b results in no commit being made at all.</p> <!-- raw HTML omitted --> <!-- raw HTML omitted --> -<h4 id="global"><code>global</code></h4> -<ul> -<li>Default: false</li> -<li>Type: Boolean</li> -</ul> -<p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> -folder instead of the current working directory. See -<a href="../configuring-npm/folders.html">folders</a> for more on the differences in behavior.</p> -<ul> -<li>packages are installed into the <code>{prefix}/lib/node_modules</code> folder, instead -of the current working directory.</li> -<li>bin files are linked to <code>{prefix}/bin</code></li> -<li>man pages are linked to <code>{prefix}/share/man</code></li> -</ul> -<!-- raw HTML omitted --> -<!-- raw HTML omitted --> <h4 id="global-style"><code>global-style</code></h4> <ul> <li>Default: false</li> @@ -951,6 +935,15 @@ to "global"</li> <li>Type: "global", "user", or "project"</li> </ul> <p>When passed to <code>npm config</code> this refers to which config file to use.</p> +<p>When set to "global" mode, packages are installed into the <code>prefix</code> folder +instead of the current working directory. See +<a href="../configuring-npm/folders.html">folders</a> for more on the differences in behavior.</p> +<ul> +<li>packages are installed into the <code>{prefix}/lib/node_modules</code> folder, instead +of the current working directory.</li> +<li>bin files are linked to <code>{prefix}/bin</code></li> +<li>man pages are linked to <code>{prefix}/share/man</code></li> +</ul> <!-- raw HTML omitted --> <!-- raw HTML omitted --> <h4 id="lockfile-version"><code>lockfile-version</code></h4> @@ -1701,6 +1694,24 @@ in a future version of npm in favor of web-based login.</li> <p>Alias for <code>--include=dev</code>.</p> <!-- raw HTML omitted --> <!-- raw HTML omitted --> +<h4 id="global"><code>global</code></h4> +<ul> +<li>Default: false</li> +<li>Type: Boolean</li> +<li>DEPRECATED: <code>--global</code>, <code>--local</code> are deprecated. Use <code>--location=global</code> +instead.</li> +</ul> +<p>Operates in "global" mode, so that packages are installed into the <code>prefix</code> +folder instead of the current working directory. See +<a href="../configuring-npm/folders.html">folders</a> for more on the differences in behavior.</p> +<ul> +<li>packages are installed into the <code>{prefix}/lib/node_modules</code> folder, instead +of the current working directory.</li> +<li>bin files are linked to <code>{prefix}/bin</code></li> +<li>man pages are linked to <code>{prefix}/share/man</code></li> +</ul> +<!-- raw HTML omitted --> +<!-- raw HTML omitted --> <h4 id="initauthoremail"><code>init.author.email</code></h4> <ul> <li>Default: ""</li> diff --git a/deps/npm/lib/commands/bin.js b/deps/npm/lib/commands/bin.js index 4200d5b8ca..9ba3cb4003 100644 --- a/deps/npm/lib/commands/bin.js +++ b/deps/npm/lib/commands/bin.js @@ -15,7 +15,7 @@ class Bin extends BaseCommand { async exec (args) { const b = this.npm.bin this.npm.output(b) - if (this.npm.config.get('global') && !path.split(delimiter).includes(b)) { + if (this.npm.global && !path.split(delimiter).includes(b)) { log.error('bin', '(not in PATH env variable)') } } diff --git a/deps/npm/lib/commands/birthday.js b/deps/npm/lib/commands/birthday.js index c7b5b31c54..cdd6db6286 100644 --- a/deps/npm/lib/commands/birthday.js +++ b/deps/npm/lib/commands/birthday.js @@ -1,13 +1,15 @@ const BaseCommand = require('../base-command.js') +const log = require('../utils/log-shim') class Birthday extends BaseCommand { static name = 'birthday' - static description = 'Birthday' + static description = 'Birthday, deprecated' static ignoreImplicitWorkspace = true static isShellout = true async exec () { this.npm.config.set('yes', true) + log.warn('birthday', 'birthday is deprecated and will be removed in a future release') return this.npm.exec('exec', ['@npmcli/npm-birthday']) } } diff --git a/deps/npm/lib/commands/cache.js b/deps/npm/lib/commands/cache.js index 634c8dbb42..862f346adb 100644 --- a/deps/npm/lib/commands/cache.js +++ b/deps/npm/lib/commands/cache.js @@ -10,11 +10,7 @@ const jsonParse = require('json-parse-even-better-errors') const localeCompare = require('@isaacs/string-locale-compare')('en') const log = require('../utils/log-shim') -const searchCachePackage = async (path, spec, cacheKeys) => { - const parsed = npa(spec) - if (parsed.rawSpec !== '' && parsed.type === 'tag') { - throw new Error(`Cannot list cache keys for a tagged package.`) - } +const searchCachePackage = async (path, parsed, cacheKeys) => { /* eslint-disable-next-line max-len */ const searchMFH = new RegExp(`^make-fetch-happen:request-cache:.*(?<!/[@a-zA-Z]+)/${parsed.name}/-/(${parsed.name}[^/]+.tgz)$`) const searchPack = new RegExp(`^make-fetch-happen:request-cache:.*/${parsed.escapedName}$`) @@ -50,6 +46,7 @@ const searchCachePackage = async (path, spec, cacheKeys) => { if (!packument.versions || typeof packument.versions !== 'object') { continue } + // assuming this is a packument for (const ver of Object.keys(packument.versions)) { if (semver.satisfies(ver, parsed.rawSpec)) { @@ -148,6 +145,7 @@ class Cache extends BaseCommand { } this.npm.output(`Deleted: ${key}`) await cacache.rm.entry(cachePath, key) + // XXX this could leave other entries without content! await cacache.rm.content(cachePath, entry.integrity) } } @@ -204,7 +202,11 @@ class Cache extends BaseCommand { // get results for each package spec specified const results = new Set() for (const spec of specs) { - const keySet = await searchCachePackage(cachePath, spec, cacheKeys) + const parsed = npa(spec) + if (parsed.rawSpec !== '' && parsed.type === 'tag') { + throw this.usageError('Cannot list cache keys for a tagged package.') + } + const keySet = await searchCachePackage(cachePath, parsed, cacheKeys) for (const key of keySet) { results.add(key) } diff --git a/deps/npm/lib/commands/ci.js b/deps/npm/lib/commands/ci.js index eb1e02bcdc..2a6125d564 100644 --- a/deps/npm/lib/commands/ci.js +++ b/deps/npm/lib/commands/ci.js @@ -8,19 +8,10 @@ const readdir = util.promisify(fs.readdir) const log = require('../utils/log-shim.js') const validateLockfile = require('../utils/validate-lockfile.js') -const removeNodeModules = async where => { - const rimrafOpts = { glob: false } - process.emit('time', 'npm-ci:rm') - const path = `${where}/node_modules` - // get the list of entries so we can skip the glob for performance - const entries = await readdir(path, null).catch(er => []) - await Promise.all(entries.map(f => rimraf(`${path}/${f}`, rimrafOpts))) - process.emit('timeEnd', 'npm-ci:rm') -} const ArboristWorkspaceCmd = require('../arborist-cmd.js') class CI extends ArboristWorkspaceCmd { - static description = 'Install a project with a clean slate' + static description = 'Clean install a project' static name = 'ci' static params = [ 'audit', @@ -30,10 +21,10 @@ class CI extends ArboristWorkspaceCmd { ] async exec () { - if (this.npm.config.get('global')) { - const err = new Error('`npm ci` does not work for global packages') - err.code = 'ECIGLOBAL' - throw err + if (this.npm.global) { + throw Object.assign(new Error('`npm ci` does not work for global packages'), { + code: 'ECIGLOBAL', + }) } const where = this.npm.prefix @@ -46,17 +37,14 @@ class CI extends ArboristWorkspaceCmd { } const arb = new Arborist(opts) - await Promise.all([ - arb.loadVirtual().catch(er => { - log.verbose('loadVirtual', er.stack) - const msg = - 'The `npm ci` command can only install with an existing package-lock.json or\n' + - 'npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or\n' + - 'later to generate a package-lock.json file, then try again.' - throw new Error(msg) - }), - removeNodeModules(where), - ]) + await arb.loadVirtual().catch(er => { + log.verbose('loadVirtual', er.stack) + const msg = + 'The `npm ci` command can only install with an existing package-lock.json or\n' + + 'npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or\n' + + 'later to generate a package-lock.json file, then try again.' + throw this.usageError(msg) + }) // retrieves inventory of packages from loaded virtual tree (lock file) const virtualInventory = new Map(arb.virtualTree.inventory) @@ -70,15 +58,24 @@ class CI extends ArboristWorkspaceCmd { // throws a validation error in case of mismatches const errors = validateLockfile(virtualInventory, arb.idealTree.inventory) if (errors.length) { - throw new Error( + throw this.usageError( '`npm ci` can only install packages when your package.json and ' + 'package-lock.json or npm-shrinkwrap.json are in sync. Please ' + 'update your lock file with `npm install` ' + 'before continuing.\n\n' + - errors.join('\n') + '\n' + errors.join('\n') ) } + // Only remove node_modules after we've successfully loaded the virtual + // tree and validated the lockfile + await this.npm.time('npm-ci:rm', async () => { + const path = `${where}/node_modules` + // get the list of entries so we can skip the glob for performance + const entries = await readdir(path, null).catch(er => []) + return Promise.all(entries.map(f => rimraf(`${path}/${f}`, { glob: false }))) + }) + await arb.reify(opts) const ignoreScripts = this.npm.config.get('ignore-scripts') diff --git a/deps/npm/lib/commands/config.js b/deps/npm/lib/commands/config.js index 0432abac39..96dd4abcaf 100644 --- a/deps/npm/lib/commands/config.js +++ b/deps/npm/lib/commands/config.js @@ -276,7 +276,7 @@ ${defData} msg.push('') } - if (!this.npm.config.get('global')) { + if (!this.npm.global) { const pkgPath = resolve(this.npm.prefix, 'package.json') const pkg = await rpj(pkgPath).catch(() => ({})) diff --git a/deps/npm/lib/commands/dedupe.js b/deps/npm/lib/commands/dedupe.js index 96d1ac2ae9..2cc44b2a9f 100644 --- a/deps/npm/lib/commands/dedupe.js +++ b/deps/npm/lib/commands/dedupe.js @@ -22,7 +22,7 @@ class Dedupe extends ArboristWorkspaceCmd { ] async exec (args) { - if (this.npm.config.get('global')) { + if (this.npm.global) { const er = new Error('`npm dedupe` does not work in global mode.') er.code = 'EDEDUPEGLOBAL' throw er diff --git a/deps/npm/lib/commands/diff.js b/deps/npm/lib/commands/diff.js index 11ee78265e..b8a64bd98a 100644 --- a/deps/npm/lib/commands/diff.js +++ b/deps/npm/lib/commands/diff.js @@ -50,7 +50,7 @@ class Diff extends BaseCommand { // node_modules is sometimes under ./lib, and in global mode we're only ever // walking through node_modules (because we will have been given a package // name already) - if (this.npm.config.get('global')) { + if (this.npm.global) { this.top = resolve(this.npm.globalDir, '..') } else { this.top = this.prefix diff --git a/deps/npm/lib/commands/dist-tag.js b/deps/npm/lib/commands/dist-tag.js index 42cad80df0..a207e422cb 100644 --- a/deps/npm/lib/commands/dist-tag.js +++ b/deps/npm/lib/commands/dist-tag.js @@ -148,7 +148,7 @@ class DistTag extends BaseCommand { async list (spec, opts) { if (!spec) { - if (this.npm.config.get('global')) { + if (this.npm.global) { throw this.usageError() } const { name } = await readPackage(path.resolve(this.npm.prefix, 'package.json')) diff --git a/deps/npm/lib/commands/fund.js b/deps/npm/lib/commands/fund.js index 787a5193f0..09ca81653b 100644 --- a/deps/npm/lib/commands/fund.js +++ b/deps/npm/lib/commands/fund.js @@ -45,7 +45,7 @@ class Fund extends ArboristWorkspaceCmd { throw err } - if (this.npm.config.get('global')) { + if (this.npm.global) { const err = new Error('`npm fund` does not support global packages') err.code = 'EFUNDGLOBAL' throw err diff --git a/deps/npm/lib/commands/install.js b/deps/npm/lib/commands/install.js index d1f6d1481d..4cda364483 100644 --- a/deps/npm/lib/commands/install.js +++ b/deps/npm/lib/commands/install.js @@ -106,7 +106,7 @@ class Install extends ArboristWorkspaceCmd { // the /path/to/node_modules/.. const globalTop = resolve(this.npm.globalDir, '..') const ignoreScripts = this.npm.config.get('ignore-scripts') - const isGlobalInstall = this.npm.config.get('global') + const isGlobalInstall = this.npm.global const where = isGlobalInstall ? globalTop : this.npm.prefix const forced = this.npm.config.get('force') const scriptShell = this.npm.config.get('script-shell') || undefined diff --git a/deps/npm/lib/commands/link.js b/deps/npm/lib/commands/link.js index d656791469..80a60d36e3 100644 --- a/deps/npm/lib/commands/link.js +++ b/deps/npm/lib/commands/link.js @@ -43,7 +43,7 @@ class Link extends ArboristWorkspaceCmd { } async exec (args) { - if (this.npm.config.get('global')) { + if (this.npm.global) { throw Object.assign( new Error( 'link should never be --global.\n' + diff --git a/deps/npm/lib/commands/ls.js b/deps/npm/lib/commands/ls.js index 06268fe7e0..cfd9cb5a50 100644 --- a/deps/npm/lib/commands/ls.js +++ b/deps/npm/lib/commands/ls.js @@ -52,7 +52,7 @@ class LS extends ArboristWorkspaceCmd { const all = this.npm.config.get('all') const color = this.npm.color const depth = this.npm.config.get('depth') - const global = this.npm.config.get('global') + const global = this.npm.global const json = this.npm.config.get('json') const link = this.npm.config.get('link') const long = this.npm.config.get('long') diff --git a/deps/npm/lib/commands/outdated.js b/deps/npm/lib/commands/outdated.js index 0953c17ca1..081e75a2c6 100644 --- a/deps/npm/lib/commands/outdated.js +++ b/deps/npm/lib/commands/outdated.js @@ -27,7 +27,7 @@ class Outdated extends ArboristWorkspaceCmd { async exec (args) { const global = path.resolve(this.npm.globalDir, '..') - const where = this.npm.config.get('global') + const where = this.npm.global ? global : this.npm.prefix @@ -140,7 +140,7 @@ class Outdated extends ArboristWorkspaceCmd { getEdgesOut (node) { // TODO: normalize usage of edges and avoid looping through nodes here - if (this.npm.config.get('global')) { + if (this.npm.global) { for (const child of node.children.values()) { this.trackEdge(child) } @@ -166,7 +166,7 @@ class Outdated extends ArboristWorkspaceCmd { } getWorkspacesEdges (node) { - if (this.npm.config.get('global')) { + if (this.npm.global) { return } diff --git a/deps/npm/lib/commands/owner.js b/deps/npm/lib/commands/owner.js index 9338b22a5e..4797e9c7ec 100644 --- a/deps/npm/lib/commands/owner.js +++ b/deps/npm/lib/commands/owner.js @@ -50,7 +50,7 @@ class Owner extends BaseCommand { // reaches registry in order to autocomplete rm if (argv[2] === 'rm') { - if (this.npm.config.get('global')) { + if (this.npm.global) { return [] } const { name } = await readJson(resolve(this.npm.prefix, 'package.json')) @@ -126,7 +126,7 @@ class Owner extends BaseCommand { async getPkg (prefix, pkg) { if (!pkg) { - if (this.npm.config.get('global')) { + if (this.npm.global) { throw this.usageError() } const { name } = await readJson(resolve(prefix, 'package.json')) diff --git a/deps/npm/lib/commands/pack.js b/deps/npm/lib/commands/pack.js index 41fef5cb45..8190ceecaf 100644 --- a/deps/npm/lib/commands/pack.js +++ b/deps/npm/lib/commands/pack.js @@ -44,7 +44,11 @@ class Pack extends BaseCommand { // noise generated during packing const tarballs = [] for (const { arg, manifest } of manifests) { - const tarballData = await libpack(arg, this.npm.flatOptions) + const tarballData = await libpack(arg, { + ...this.npm.flatOptions, + prefix: this.npm.localPrefix, + workspaces: this.workspacePaths, + }) const pkgContents = await getContents(manifest, tarballData) tarballs.push(pkgContents) } diff --git a/deps/npm/lib/commands/pkg.js b/deps/npm/lib/commands/pkg.js index 3a8e01f65b..5fac9bfb54 100644 --- a/deps/npm/lib/commands/pkg.js +++ b/deps/npm/lib/commands/pkg.js @@ -29,7 +29,7 @@ class Pkg extends BaseCommand { this.prefix = prefix } - if (this.npm.config.get('global')) { + if (this.npm.global) { throw Object.assign( new Error(`There's no package.json file to manage on global mode`), { code: 'EPKGGLOBAL' } diff --git a/deps/npm/lib/commands/publish.js b/deps/npm/lib/commands/publish.js index cbf0ccf4d6..da6437fa9c 100644 --- a/deps/npm/lib/commands/publish.js +++ b/deps/npm/lib/commands/publish.js @@ -80,7 +80,12 @@ class Publish extends BaseCommand { } // we pass dryRun: true to libnpmpack so it doesn't write the file to disk - const tarballData = await pack(spec, { ...opts, dryRun: true }) + const tarballData = await pack(spec, { + ...opts, + dryRun: true, + prefix: this.npm.localPrefix, + workspaces: this.workspacePaths, + }) const pkgContents = await getContents(manifest, tarballData) // The purpose of re-reading the manifest is in case it changed, diff --git a/deps/npm/lib/commands/rebuild.js b/deps/npm/lib/commands/rebuild.js index 0e8a1510bd..3e6046d8df 100644 --- a/deps/npm/lib/commands/rebuild.js +++ b/deps/npm/lib/commands/rebuild.js @@ -26,7 +26,7 @@ class Rebuild extends ArboristWorkspaceCmd { async exec (args) { const globalTop = resolve(this.npm.globalDir, '..') - const where = this.npm.config.get('global') ? globalTop : this.npm.prefix + const where = this.npm.global ? globalTop : this.npm.prefix const arb = new Arborist({ ...this.npm.flatOptions, path: where, diff --git a/deps/npm/lib/commands/set-script.js b/deps/npm/lib/commands/set-script.js index a6b7c3a50c..a085f72a31 100644 --- a/deps/npm/lib/commands/set-script.js +++ b/deps/npm/lib/commands/set-script.js @@ -5,7 +5,7 @@ const log = require('../utils/log-shim') const BaseCommand = require('../base-command.js') class SetScript extends BaseCommand { - static description = 'Set tasks in the scripts section of package.json' + static description = 'Set tasks in the scripts section of package.json, deprecated' static params = ['workspace', 'workspaces', 'include-workspace-root'] static name = 'set-script' static usage = ['[<script>] [<command>]'] @@ -34,6 +34,8 @@ class SetScript extends BaseCommand { async exec (args) { this.validate(args) + log.warn('set-script', + 'set-script is deprecated, use `npm pkg set scripts.scriptname="cmd" instead.') const warn = await this.doSetScript(this.npm.localPrefix, args[0], args[1]) if (warn) { log.warn('set-script', `Script "${args[0]}" was overwritten`) diff --git a/deps/npm/lib/commands/shrinkwrap.js b/deps/npm/lib/commands/shrinkwrap.js index 67cde15818..a240f03935 100644 --- a/deps/npm/lib/commands/shrinkwrap.js +++ b/deps/npm/lib/commands/shrinkwrap.js @@ -15,7 +15,7 @@ class Shrinkwrap extends BaseCommand { // // loadVirtual, fall back to loadActual // rename shrinkwrap file type, and tree.meta.save() - if (this.npm.config.get('global')) { + if (this.npm.global) { const er = new Error('`npm shrinkwrap` does not work for global packages') er.code = 'ESHRINKWRAPGLOBAL' throw er diff --git a/deps/npm/lib/commands/uninstall.js b/deps/npm/lib/commands/uninstall.js index 5911818b6f..e4a193cc5c 100644 --- a/deps/npm/lib/commands/uninstall.js +++ b/deps/npm/lib/commands/uninstall.js @@ -21,13 +21,12 @@ class Uninstall extends ArboristWorkspaceCmd { async exec (args) { // the /path/to/node_modules/.. - const global = this.npm.config.get('global') - const path = global + const path = this.npm.global ? resolve(this.npm.globalDir, '..') : this.npm.localPrefix if (!args.length) { - if (!global) { + if (!this.npm.global) { throw new Error('Must provide a package name to remove') } else { let pkg diff --git a/deps/npm/lib/commands/update.js b/deps/npm/lib/commands/update.js index c2c3502eed..ca80d61537 100644 --- a/deps/npm/lib/commands/update.js +++ b/deps/npm/lib/commands/update.js @@ -39,7 +39,7 @@ class Update extends ArboristWorkspaceCmd { async exec (args) { const update = args.length === 0 ? true : args const global = path.resolve(this.npm.globalDir, '..') - const where = this.npm.config.get('global') + const where = this.npm.global ? global : this.npm.prefix diff --git a/deps/npm/lib/commands/view.js b/deps/npm/lib/commands/view.js index d78ee77dc0..efb298a03b 100644 --- a/deps/npm/lib/commands/view.js +++ b/deps/npm/lib/commands/view.js @@ -91,7 +91,7 @@ class View extends BaseCommand { const local = /^\.@/.test(pkg) || pkg === '.' if (local) { - if (this.npm.config.get('global')) { + if (this.npm.global) { throw new Error('Cannot use view command in global mode.') } const dir = this.npm.prefix diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 732362565e..2197f11a52 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -129,7 +129,6 @@ class Npm extends EventEmitter { }) } - const isGlobal = this.config.get('global') const workspacesEnabled = this.config.get('workspaces') // if cwd is a workspace, the default is set to [that workspace] const implicitWorkspace = this.config.get('workspace', 'default').length > 0 @@ -160,7 +159,7 @@ class Npm extends EventEmitter { execPromise = Promise.reject( new Error('Can not use --no-workspaces and --workspace at the same time')) } else if (filterByWorkspaces) { - if (isGlobal) { + if (this.global) { execPromise = Promise.reject(new Error('Workspaces not supported for global packages')) } else { execPromise = command.execWorkspaces(args, workspacesFilters) @@ -333,6 +332,10 @@ class Npm extends EventEmitter { return this.#chalk } + get global () { + return this.config.get('global') || this.config.get('location') === 'global' + } + get logColor () { return this.flatOptions.logColor } @@ -409,7 +412,7 @@ class Npm extends EventEmitter { } get dir () { - return this.config.get('global') ? this.globalDir : this.localDir + return this.global ? this.globalDir : this.localDir } get globalBin () { @@ -422,15 +425,15 @@ class Npm extends EventEmitter { } get bin () { - return this.config.get('global') ? this.globalBin : this.localBin + return this.global ? this.globalBin : this.localBin } get prefix () { - return this.config.get('global') ? this.globalPrefix : this.localPrefix + return this.global ? this.globalPrefix : this.localPrefix } set prefix (r) { - const k = this.config.get('global') ? 'globalPrefix' : 'localPrefix' + const k = this.global ? 'globalPrefix' : 'localPrefix' this[k] = r } diff --git a/deps/npm/lib/utils/config/definitions.js b/deps/npm/lib/utils/config/definitions.js index c4be3a6584..92fbbd1e6d 100644 --- a/deps/npm/lib/utils/config/definitions.js +++ b/deps/npm/lib/utils/config/definitions.js @@ -811,6 +811,9 @@ define('global', { default: false, type: Boolean, short: 'g', + deprecated: ` + \`--global\`, \`--local\` are deprecated. Use \`--location=global\` instead. + `, description: ` Operates in "global" mode, so that packages are installed into the \`prefix\` folder instead of the current working directory. See @@ -1179,12 +1182,24 @@ define('location', { `, description: ` When passed to \`npm config\` this refers to which config file to use. + + When set to "global" mode, packages are installed into the \`prefix\` folder + instead of the current working directory. See + [folders](/configuring-npm/folders) for more on the differences in behavior. + + * packages are installed into the \`{prefix}/lib/node_modules\` folder, + instead of the current working directory. + * bin files are linked to \`{prefix}/bin\` + * man pages are linked to \`{prefix}/share/man\` `, flatten: (key, obj, flatOptions) => { flatten(key, obj, flatOptions) if (flatOptions.global) { flatOptions.location = 'global' } + if (obj.location === 'global') { + flatOptions.global = true + } }, }) diff --git a/deps/npm/lib/utils/get-identity.js b/deps/npm/lib/utils/get-identity.js index e77c2eea4c..f4aedb89b3 100644 --- a/deps/npm/lib/utils/get-identity.js +++ b/deps/npm/lib/utils/get-identity.js @@ -1,39 +1,24 @@ const npmFetch = require('npm-registry-fetch') -const needsAuthError = (msg) => - Object.assign(new Error(msg), { code: 'ENEEDAUTH' }) - -module.exports = async (npm, opts = {}) => { +module.exports = async (npm, opts) => { const { registry } = opts - if (!registry) { - throw Object.assign(new Error('No registry specified.'), { code: 'ENOREGISTRY' }) - } // First, check if we have a user/pass-based auth const creds = npm.config.getCredentialsByURI(registry) - const { username: usernameFromURI, token } = creds + if (creds.username) { + return creds.username + } - if (usernameFromURI) { - // Found username; return it - return usernameFromURI - } else if (token) { - // No username, but we have a token; fetch the username from registry - const registryData = await npmFetch.json('/-/whoami', { - ...opts, - }) - const { username: usernameFromRegistry } = registryData - // Retrieved username from registry; return it - if (usernameFromRegistry) { - return usernameFromRegistry - } else { - // Didn't get username from registry; bad token - throw needsAuthError( - 'Your auth token is no longer valid. Please login again.' - ) - } - } else { - // At this point, if they have a credentials object, it doesn't have a - // token or auth in it. Probably just the default registry. - throw needsAuthError('This command requires you to be logged in.') + // No username, but we have a token; fetch the username from registry + if (creds.token) { + const registryData = await npmFetch.json('/-/whoami', { ...opts }) + return registryData.username } + + // At this point, even if they have a credentials object, it doesn't have a + // valid token. + throw Object.assign( + new Error('This command requires you to be logged in.'), + { code: 'ENEEDAUTH' } + ) } diff --git a/deps/npm/man/man1/npm-bin.1 b/deps/npm/man/man1/npm-bin.1 index efe38ee8d9..9c6d2ccf4c 100644 --- a/deps/npm/man/man1/npm-bin.1 +++ b/deps/npm/man/man1/npm-bin.1 @@ -20,6 +20,9 @@ Print the folder where npm will install executables\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1 index 3aefdfc80b..70182bf407 100644 --- a/deps/npm/man/man1/npm-ci.1 +++ b/deps/npm/man/man1/npm-ci.1 @@ -1,6 +1,6 @@ .TH "NPM\-CI" "1" "May 2022" "" "" .SH "NAME" -\fBnpm-ci\fR \- Install a project with a clean slate +\fBnpm-ci\fR \- Clean install a project .SS Synopsis .P .RS 2 @@ -17,16 +17,7 @@ it's meant to be used in automated environments such as test platforms, continuous integration, and deployment \-\- or any situation where you want to make sure you're doing a clean install of your dependencies\. .P -\fBnpm ci\fP will be significantly faster when: -.RS 0 -.IP \(bu 2 -There is a \fBpackage\-lock\.json\fP or \fBnpm\-shrinkwrap\.json\fP file\. -.IP \(bu 2 -The \fBnode_modules\fP folder is missing or empty\. - -.RE -.P -In short, the main differences between using \fBnpm install\fP and \fBnpm ci\fP are: +The main differences between using \fBnpm install\fP and \fBnpm ci\fP are: .RS 0 .IP \(bu 2 The project \fBmust\fR have an existing \fBpackage\-lock\.json\fP or diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1 index 19f9ab6a06..88ffa9aa05 100644 --- a/deps/npm/man/man1/npm-config.1 +++ b/deps/npm/man/man1/npm-config.1 @@ -117,6 +117,9 @@ Not supported by all npm commands\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P @@ -155,6 +158,20 @@ Type: "global", "user", or "project" .RE .P When passed to \fBnpm config\fP this refers to which config file to use\. +.P +When set to "global" mode, packages are installed into the \fBprefix\fP folder +instead of the current working directory\. See +npm help folders for more on the differences in behavior\. +.RS 0 +.IP \(bu 2 +packages are installed into the \fB{prefix}/lib/node_modules\fP folder, instead +of the current working directory\. +.IP \(bu 2 +bin files are linked to \fB{prefix}/bin\fP +.IP \(bu 2 +man pages are linked to \fB{prefix}/share/man\fP + +.RE .SS \fBlong\fP .RS 0 .IP \(bu 2 diff --git a/deps/npm/man/man1/npm-diff.1 b/deps/npm/man/man1/npm-diff.1 index 90bdfa9476..d32c343f06 100644 --- a/deps/npm/man/man1/npm-diff.1 +++ b/deps/npm/man/man1/npm-diff.1 @@ -232,6 +232,9 @@ Treat all files as text in \fBnpm diff\fP\|\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1 index 17aadace62..e29397bf94 100644 --- a/deps/npm/man/man1/npm-install-test.1 +++ b/deps/npm/man/man1/npm-install-test.1 @@ -56,6 +56,9 @@ rather than using npm's default semver range operator\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1 index 7630adb0e2..4bb41f2d7b 100644 --- a/deps/npm/man/man1/npm-install.1 +++ b/deps/npm/man/man1/npm-install.1 @@ -467,6 +467,9 @@ rather than using npm's default semver range operator\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1 index f59c746519..1b982044e4 100644 --- a/deps/npm/man/man1/npm-link.1 +++ b/deps/npm/man/man1/npm-link.1 @@ -145,6 +145,9 @@ rather than using npm's default semver range operator\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1 index 42f9baf965..1efd612984 100644 --- a/deps/npm/man/man1/npm-ls.1 +++ b/deps/npm/man/man1/npm-ls.1 @@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show: .P .RS 2 .nf -npm@8\.10\.0 /path/to/npm +npm@8\.11\.0 /path/to/npm └─┬ init\-package\-json@0\.0\.4 └── promzard@0\.1\.5 .fi @@ -127,6 +127,9 @@ Output parseable results from commands that write to standard output\. For Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1 index 9fe1ddf692..03bcf92588 100644 --- a/deps/npm/man/man1/npm-outdated.1 +++ b/deps/npm/man/man1/npm-outdated.1 @@ -159,6 +159,9 @@ Output parseable results from commands that write to standard output\. For Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-prefix.1 b/deps/npm/man/man1/npm-prefix.1 index 2434c34678..e053f315ff 100644 --- a/deps/npm/man/man1/npm-prefix.1 +++ b/deps/npm/man/man1/npm-prefix.1 @@ -40,6 +40,9 @@ npm prefix \-g Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-rebuild.1 b/deps/npm/man/man1/npm-rebuild.1 index dab000878d..f3c51a34e4 100644 --- a/deps/npm/man/man1/npm-rebuild.1 +++ b/deps/npm/man/man1/npm-rebuild.1 @@ -28,6 +28,9 @@ will be rebuilt\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-root.1 b/deps/npm/man/man1/npm-root.1 index 4e1a94be7b..a9143ebe88 100644 --- a/deps/npm/man/man1/npm-root.1 +++ b/deps/npm/man/man1/npm-root.1 @@ -29,6 +29,9 @@ echo "Global packages installed in: ${global_node_modules}" Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm-set-script.1 b/deps/npm/man/man1/npm-set-script.1 index 96ee6e3e34..85106d95fb 100644 --- a/deps/npm/man/man1/npm-set-script.1 +++ b/deps/npm/man/man1/npm-set-script.1 @@ -5,6 +5,8 @@ .P An npm command that lets you create a task in the \fBscripts\fP section of the \fBpackage\.json\fP\|\. .P +Deprecated\. +.P .RS 2 .nf npm set\-script [<script>] [<command>] diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1 index fa2903a18c..aebe0c8895 100644 --- a/deps/npm/man/man1/npm-update.1 +++ b/deps/npm/man/man1/npm-update.1 @@ -180,6 +180,9 @@ Will also prevent writing to \fBpackage\-lock\.json\fP if set to \fBfalse\fP\|\. Default: false .IP \(bu 2 Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. .RE .P diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1 index c540497252..6ac72ad35c 100644 --- a/deps/npm/man/man1/npm.1 +++ b/deps/npm/man/man1/npm.1 @@ -4,7 +4,7 @@ .SS Synopsis .SS Version .P -8\.10\.0 +8\.11\.0 .SS Description .P npm is the package manager for the Node JavaScript platform\. It puts diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7 index f727a19f25..e3dc9a9952 100644 --- a/deps/npm/man/man7/config.7 +++ b/deps/npm/man/man7/config.7 @@ -739,28 +739,6 @@ Type: Boolean .P Tag the commit when using the \fBnpm version\fP command\. Setting this to false results in no commit being made at all\. -.SS \fBglobal\fP -.RS 0 -.IP \(bu 2 -Default: false -.IP \(bu 2 -Type: Boolean - -.RE -.P -Operates in "global" mode, so that packages are installed into the \fBprefix\fP -folder instead of the current working directory\. See -npm help folders for more on the differences in behavior\. -.RS 0 -.IP \(bu 2 -packages are installed into the \fB{prefix}/lib/node_modules\fP folder, instead -of the current working directory\. -.IP \(bu 2 -bin files are linked to \fB{prefix}/bin\fP -.IP \(bu 2 -man pages are linked to \fB{prefix}/share/man\fP - -.RE .SS \fBglobal\-style\fP .RS 0 .IP \(bu 2 @@ -1066,6 +1044,20 @@ Type: "global", "user", or "project" .RE .P When passed to \fBnpm config\fP this refers to which config file to use\. +.P +When set to "global" mode, packages are installed into the \fBprefix\fP folder +instead of the current working directory\. See +npm help folders for more on the differences in behavior\. +.RS 0 +.IP \(bu 2 +packages are installed into the \fB{prefix}/lib/node_modules\fP folder, instead +of the current working directory\. +.IP \(bu 2 +bin files are linked to \fB{prefix}/bin\fP +.IP \(bu 2 +man pages are linked to \fB{prefix}/share/man\fP + +.RE .SS \fBlockfile\-version\fP .RS 0 .IP \(bu 2 @@ -2027,6 +2019,31 @@ DEPRECATED: Please use \-\-include=dev instead\. .RE .P Alias for \fB\-\-include=dev\fP\|\. +.SS \fBglobal\fP +.RS 0 +.IP \(bu 2 +Default: false +.IP \(bu 2 +Type: Boolean +.IP \(bu 2 +DEPRECATED: \fB\-\-global\fP, \fB\-\-local\fP are deprecated\. Use \fB\-\-location=global\fP +instead\. + +.RE +.P +Operates in "global" mode, so that packages are installed into the \fBprefix\fP +folder instead of the current working directory\. See +npm help folders for more on the differences in behavior\. +.RS 0 +.IP \(bu 2 +packages are installed into the \fB{prefix}/lib/node_modules\fP folder, instead +of the current working directory\. +.IP \(bu 2 +bin files are linked to \fB{prefix}/bin\fP +.IP \(bu 2 +man pages are linked to \fB{prefix}/share/man\fP + +.RE .SS \fBinit\.author\.email\fP .RS 0 .IP \(bu 2 diff --git a/deps/npm/node_modules/cacache/lib/content/read.js b/deps/npm/node_modules/cacache/lib/content/read.js index 0aeb454725..f5128fe185 100644 --- a/deps/npm/node_modules/cacache/lib/content/read.js +++ b/deps/npm/node_modules/cacache/lib/content/read.js @@ -1,42 +1,35 @@ 'use strict' -const util = require('util') - -const fs = require('fs') +const fs = require('@npmcli/fs') const fsm = require('fs-minipass') const ssri = require('ssri') const contentPath = require('./path') const Pipeline = require('minipass-pipeline') -const lstat = util.promisify(fs.lstat) -const readFile = util.promisify(fs.readFile) -const copyFile = util.promisify(fs.copyFile) - module.exports = read const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024 -function read (cache, integrity, opts = {}) { +async function read (cache, integrity, opts = {}) { const { size } = opts - return withContentSri(cache, integrity, (cpath, sri) => { + const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => { // get size - return lstat(cpath).then(stat => ({ stat, cpath, sri })) - }).then(({ stat, cpath, sri }) => { - if (typeof size === 'number' && stat.size !== size) { - throw sizeError(size, stat.size) - } + const stat = await fs.lstat(cpath) + return { stat, cpath, sri } + }) + if (typeof size === 'number' && stat.size !== size) { + throw sizeError(size, stat.size) + } - if (stat.size > MAX_SINGLE_READ_SIZE) { - return readPipeline(cpath, stat.size, sri, new Pipeline()).concat() - } + if (stat.size > MAX_SINGLE_READ_SIZE) { + return readPipeline(cpath, stat.size, sri, new Pipeline()).concat() + } - return readFile(cpath, null).then((data) => { - if (!ssri.checkData(data, sri)) { - throw integrityError(sri, cpath) - } + const data = await fs.readFile(cpath, { encoding: null }) + if (!ssri.checkData(data, sri)) { + throw integrityError(sri, cpath) + } - return data - }) - }) + return data } const readPipeline = (cpath, size, sri, stream) => { @@ -58,7 +51,7 @@ module.exports.sync = readSync function readSync (cache, integrity, opts = {}) { const { size } = opts return withContentSriSync(cache, integrity, (cpath, sri) => { - const data = fs.readFileSync(cpath) + const data = fs.readFileSync(cpath, { encoding: null }) if (typeof size === 'number' && size !== data.length) { throw sizeError(size, data.length) } @@ -77,16 +70,19 @@ module.exports.readStream = readStream function readStream (cache, integrity, opts = {}) { const { size } = opts const stream = new Pipeline() - withContentSri(cache, integrity, (cpath, sri) => { - // just lstat to ensure it exists - return lstat(cpath).then((stat) => ({ stat, cpath, sri })) - }).then(({ stat, cpath, sri }) => { + // Set all this up to run on the stream and then just return the stream + Promise.resolve().then(async () => { + const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => { + // just lstat to ensure it exists + const stat = await fs.lstat(cpath) + return { stat, cpath, sri } + }) if (typeof size === 'number' && size !== stat.size) { return stream.emit('error', sizeError(size, stat.size)) } readPipeline(cpath, stat.size, sri, stream) - }, er => stream.emit('error', er)) + }).catch(err => stream.emit('error', err)) return stream } @@ -96,7 +92,7 @@ module.exports.copy.sync = copySync function copy (cache, integrity, dest) { return withContentSri(cache, integrity, (cpath, sri) => { - return copyFile(cpath, dest) + return fs.copyFile(cpath, dest) }) } @@ -108,14 +104,17 @@ function copySync (cache, integrity, dest) { module.exports.hasContent = hasContent -function hasContent (cache, integrity) { +async function hasContent (cache, integrity) { if (!integrity) { - return Promise.resolve(false) + return false } - return withContentSri(cache, integrity, (cpath, sri) => { - return lstat(cpath).then((stat) => ({ size: stat.size, sri, stat })) - }).catch((err) => { + try { + return await withContentSri(cache, integrity, async (cpath, sri) => { + const stat = await fs.lstat(cpath) + return { size: stat.size, sri, stat } + }) + } catch (err) { if (err.code === 'ENOENT') { return false } @@ -128,7 +127,7 @@ function hasContent (cache, integrity) { return false } } - }) + } } module.exports.hasContent.sync = hasContentSync @@ -159,61 +158,47 @@ function hasContentSync (cache, integrity) { }) } -function withContentSri (cache, integrity, fn) { - const tryFn = () => { - const sri = ssri.parse(integrity) - // If `integrity` has multiple entries, pick the first digest - // with available local data. - const algo = sri.pickAlgorithm() - const digests = sri[algo] - - if (digests.length <= 1) { - const cpath = contentPath(cache, digests[0]) - return fn(cpath, digests[0]) - } else { - // Can't use race here because a generic error can happen before - // a ENOENT error, and can happen before a valid result - return Promise - .all(digests.map((meta) => { - return withContentSri(cache, meta, fn) - .catch((err) => { - if (err.code === 'ENOENT') { - return Object.assign( - new Error('No matching content found for ' + sri.toString()), - { code: 'ENOENT' } - ) - } - return err - }) - })) - .then((results) => { - // Return the first non error if it is found - const result = results.find((r) => !(r instanceof Error)) - if (result) { - return result - } - - // Throw the No matching content found error - const enoentError = results.find((r) => r.code === 'ENOENT') - if (enoentError) { - throw enoentError - } - - // Throw generic error - throw results.find((r) => r instanceof Error) - }) +async function withContentSri (cache, integrity, fn) { + const sri = ssri.parse(integrity) + // If `integrity` has multiple entries, pick the first digest + // with available local data. + const algo = sri.pickAlgorithm() + const digests = sri[algo] + + if (digests.length <= 1) { + const cpath = contentPath(cache, digests[0]) + return fn(cpath, digests[0]) + } else { + // Can't use race here because a generic error can happen before + // a ENOENT error, and can happen before a valid result + const results = await Promise.all(digests.map(async (meta) => { + try { + return await withContentSri(cache, meta, fn) + } catch (err) { + if (err.code === 'ENOENT') { + return Object.assign( + new Error('No matching content found for ' + sri.toString()), + { code: 'ENOENT' } + ) + } + return err + } + })) + // Return the first non error if it is found + const result = results.find((r) => !(r instanceof Error)) + if (result) { + return result } - } - return new Promise((resolve, reject) => { - try { - tryFn() - .then(resolve) - .catch(reject) - } catch (err) { - reject(err) + // Throw the No matching content found error + const enoentError = results.find((r) => r.code === 'ENOENT') + if (enoentError) { + throw enoentError } - }) + + // Throw generic error + throw results.find((r) => r instanceof Error) + } } function withContentSriSync (cache, integrity, fn) { diff --git a/deps/npm/node_modules/cacache/lib/content/rm.js b/deps/npm/node_modules/cacache/lib/content/rm.js index 50612364e9..f7333053b3 100644 --- a/deps/npm/node_modules/cacache/lib/content/rm.js +++ b/deps/npm/node_modules/cacache/lib/content/rm.js @@ -8,13 +8,13 @@ const rimraf = util.promisify(require('rimraf')) module.exports = rm -function rm (cache, integrity) { - return hasContent(cache, integrity).then((content) => { - // ~pretty~ sure we can't end up with a content lacking sri, but be safe - if (content && content.sri) { - return rimraf(contentPath(cache, content.sri)).then(() => true) - } else { - return false - } - }) +async function rm (cache, integrity) { + const content = await hasContent(cache, integrity) + // ~pretty~ sure we can't end up with a content lacking sri, but be safe + if (content && content.sri) { + await rimraf(contentPath(cache, content.sri)) + return true + } else { + return false + } } diff --git a/deps/npm/node_modules/cacache/lib/content/write.js b/deps/npm/node_modules/cacache/lib/content/write.js index b0aa18c12b..62388dc81d 100644 --- a/deps/npm/node_modules/cacache/lib/content/write.js +++ b/deps/npm/node_modules/cacache/lib/content/write.js @@ -1,10 +1,11 @@ 'use strict' +const events = require('events') const util = require('util') const contentPath = require('./path') const fixOwner = require('../util/fix-owner') -const fs = require('fs') +const fs = require('@npmcli/fs') const moveFile = require('../util/move-file') const Minipass = require('minipass') const Pipeline = require('minipass-pipeline') @@ -15,8 +16,6 @@ const ssri = require('ssri') const uniqueFilename = require('unique-filename') const fsm = require('fs-minipass') -const writeFile = util.promisify(fs.writeFile) - module.exports = write async function write (cache, data, opts = {}) { @@ -36,7 +35,7 @@ async function write (cache, data, opts = {}) { const tmp = await makeTmp(cache, opts) try { - await writeFile(tmp.target, data, { flag: 'wx' }) + await fs.writeFile(tmp.target, data, { flag: 'wx' }) await moveToDestination(tmp, cache, sri, opts) return { integrity: sri, size: data.length } } finally { @@ -115,7 +114,21 @@ async function handleContent (inputStream, cache, opts) { } } -function pipeToTmp (inputStream, cache, tmpTarget, opts) { +async function pipeToTmp (inputStream, cache, tmpTarget, opts) { + const outStream = new fsm.WriteStream(tmpTarget, { + flags: 'wx', + }) + + if (opts.integrityEmitter) { + // we need to create these all simultaneously since they can fire in any order + const [integrity, size] = await Promise.all([ + events.once(opts.integrityEmitter, 'integrity').then(res => res[0]), + events.once(opts.integrityEmitter, 'size').then(res => res[0]), + new Pipeline(inputStream, outStream).promise(), + ]) + return { integrity, size } + } + let integrity let size const hashStream = ssri.integrityStream({ @@ -130,43 +143,28 @@ function pipeToTmp (inputStream, cache, tmpTarget, opts) { size = s }) - const outStream = new fsm.WriteStream(tmpTarget, { - flags: 'wx', - }) - - // NB: this can throw if the hashStream has a problem with - // it, and the data is fully written. but pipeToTmp is only - // called in promisory contexts where that is handled. - const pipeline = new Pipeline( - inputStream, - hashStream, - outStream - ) - - return pipeline.promise().then(() => ({ integrity, size })) + const pipeline = new Pipeline(inputStream, hashStream, outStream) + await pipeline.promise() + return { integrity, size } } -function makeTmp (cache, opts) { +async function makeTmp (cache, opts) { const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix) - return fixOwner.mkdirfix(cache, path.dirname(tmpTarget)).then(() => ({ + await fixOwner.mkdirfix(cache, path.dirname(tmpTarget)) + return { target: tmpTarget, moved: false, - })) + } } -function moveToDestination (tmp, cache, sri, opts) { +async function moveToDestination (tmp, cache, sri, opts) { const destination = contentPath(cache, sri) const destDir = path.dirname(destination) - return fixOwner - .mkdirfix(cache, destDir) - .then(() => { - return moveFile(tmp.target, destination) - }) - .then(() => { - tmp.moved = true - return fixOwner.chownr(cache, destination) - }) + await fixOwner.mkdirfix(cache, destDir) + await moveFile(tmp.target, destination) + tmp.moved = true + await fixOwner.chownr(cache, destination) } function sizeError (expected, found) { diff --git a/deps/npm/node_modules/cacache/lib/entry-index.js b/deps/npm/node_modules/cacache/lib/entry-index.js index 9d4485624a..cbfa619099 100644 --- a/deps/npm/node_modules/cacache/lib/entry-index.js +++ b/deps/npm/node_modules/cacache/lib/entry-index.js @@ -2,7 +2,7 @@ const util = require('util') const crypto = require('crypto') -const fs = require('fs') +const fs = require('@npmcli/fs') const Minipass = require('minipass') const path = require('path') const ssri = require('ssri') @@ -17,11 +17,6 @@ const _rimraf = require('rimraf') const rimraf = util.promisify(_rimraf) rimraf.sync = _rimraf.sync -const appendFile = util.promisify(fs.appendFile) -const readFile = util.promisify(fs.readFile) -const readdir = util.promisify(fs.readdir) -const writeFile = util.promisify(fs.writeFile) - module.exports.NotFoundError = class NotFoundError extends Error { constructor (cache, key) { super(`No cache entry for ${key} found in ${cache}`) @@ -85,7 +80,7 @@ async function compact (cache, key, matchFn, opts = {}) { } const write = async (tmp) => { - await writeFile(tmp.target, newIndex, { flag: 'wx' }) + await fs.writeFile(tmp.target, newIndex, { flag: 'wx' }) await fixOwner.mkdirfix(cache, path.dirname(bucket)) // we use @npmcli/move-file directly here because we // want to overwrite the existing file @@ -118,7 +113,7 @@ async function compact (cache, key, matchFn, opts = {}) { module.exports.insert = insert -function insert (cache, key, integrity, opts = {}) { +async function insert (cache, key, integrity, opts = {}) { const { metadata, size } = opts const bucket = bucketPath(cache, key) const entry = { @@ -128,36 +123,32 @@ function insert (cache, key, integrity, opts = {}) { size, metadata, } - return fixOwner - .mkdirfix(cache, path.dirname(bucket)) - .then(() => { - const stringified = JSON.stringify(entry) - // NOTE - Cleverness ahoy! - // - // This works because it's tremendously unlikely for an entry to corrupt - // another while still preserving the string length of the JSON in - // question. So, we just slap the length in there and verify it on read. - // - // Thanks to @isaacs for the whiteboarding session that ended up with - // this. - return appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`) - }) - .then(() => fixOwner.chownr(cache, bucket)) - .catch((err) => { - if (err.code === 'ENOENT') { - return undefined - } + try { + await fixOwner.mkdirfix(cache, path.dirname(bucket)) + const stringified = JSON.stringify(entry) + // NOTE - Cleverness ahoy! + // + // This works because it's tremendously unlikely for an entry to corrupt + // another while still preserving the string length of the JSON in + // question. So, we just slap the length in there and verify it on read. + // + // Thanks to @isaacs for the whiteboarding session that ended up with + // this. + await fs.appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`) + await fixOwner.chownr(cache, bucket) + } catch (err) { + if (err.code === 'ENOENT') { + return undefined + } - throw err - // There's a class of race conditions that happen when things get deleted - // during fixOwner, or between the two mkdirfix/chownr calls. - // - // It's perfectly fine to just not bother in those cases and lie - // that the index entry was written. Because it's a cache. - }) - .then(() => { - return formatEntry(cache, entry) - }) + throw err + // There's a class of race conditions that happen when things get deleted + // during fixOwner, or between the two mkdirfix/chownr calls. + // + // It's perfectly fine to just not bother in those cases and lie + // that the index entry was written. Because it's a cache. + } + return formatEntry(cache, entry) } module.exports.insert.sync = insertSync @@ -187,25 +178,24 @@ function insertSync (cache, key, integrity, opts = {}) { module.exports.find = find -function find (cache, key) { +async function find (cache, key) { const bucket = bucketPath(cache, key) - return bucketEntries(bucket) - .then((entries) => { - return entries.reduce((latest, next) => { - if (next && next.key === key) { - return formatEntry(cache, next) - } else { - return latest - } - }, null) - }) - .catch((err) => { - if (err.code === 'ENOENT') { - return null + try { + const entries = await bucketEntries(bucket) + return entries.reduce((latest, next) => { + if (next && next.key === key) { + return formatEntry(cache, next) } else { - throw err + return latest } - }) + }, null) + } catch (err) { + if (err.code === 'ENOENT') { + return null + } else { + throw err + } + } } module.exports.find.sync = findSync @@ -257,67 +247,64 @@ function lsStream (cache) { const indexDir = bucketDir(cache) const stream = new Minipass({ objectMode: true }) - readdirOrEmpty(indexDir).then(buckets => Promise.all( - buckets.map(bucket => { + // Set all this up to run on the stream and then just return the stream + Promise.resolve().then(async () => { + const buckets = await readdirOrEmpty(indexDir) + await Promise.all(buckets.map(async (bucket) => { const bucketPath = path.join(indexDir, bucket) - return readdirOrEmpty(bucketPath).then(subbuckets => Promise.all( - subbuckets.map(subbucket => { - const subbucketPath = path.join(bucketPath, subbucket) - - // "/cachename/<bucket 0xFF>/<bucket 0xFF>./*" - return readdirOrEmpty(subbucketPath).then(entries => Promise.all( - entries.map(entry => { - const entryPath = path.join(subbucketPath, entry) - return bucketEntries(entryPath).then(entries => - // using a Map here prevents duplicate keys from - // showing up twice, I guess? - entries.reduce((acc, entry) => { - acc.set(entry.key, entry) - return acc - }, new Map()) - ).then(reduced => { - // reduced is a map of key => entry - for (const entry of reduced.values()) { - const formatted = formatEntry(cache, entry) - if (formatted) { - stream.write(formatted) - } - } - }).catch(err => { - if (err.code === 'ENOENT') { - return undefined - } - throw err - }) - }) - )) - }) - )) - }) - )) - .then( - () => stream.end(), - err => stream.emit('error', err) - ) + const subbuckets = await readdirOrEmpty(bucketPath) + await Promise.all(subbuckets.map(async (subbucket) => { + const subbucketPath = path.join(bucketPath, subbucket) + + // "/cachename/<bucket 0xFF>/<bucket 0xFF>./*" + const subbucketEntries = await readdirOrEmpty(subbucketPath) + await Promise.all(subbucketEntries.map(async (entry) => { + const entryPath = path.join(subbucketPath, entry) + try { + const entries = await bucketEntries(entryPath) + // using a Map here prevents duplicate keys from showing up + // twice, I guess? + const reduced = entries.reduce((acc, entry) => { + acc.set(entry.key, entry) + return acc + }, new Map()) + // reduced is a map of key => entry + for (const entry of reduced.values()) { + const formatted = formatEntry(cache, entry) + if (formatted) { + stream.write(formatted) + } + } + } catch (err) { + if (err.code === 'ENOENT') { + return undefined + } + throw err + } + })) + })) + })) + stream.end() + }).catch(err => stream.emit('error', err)) return stream } module.exports.ls = ls -function ls (cache) { - return lsStream(cache).collect().then(entries => - entries.reduce((acc, xs) => { - acc[xs.key] = xs - return acc - }, {}) - ) +async function ls (cache) { + const entries = await lsStream(cache).collect() + return entries.reduce((acc, xs) => { + acc[xs.key] = xs + return acc + }, {}) } module.exports.bucketEntries = bucketEntries -function bucketEntries (bucket, filter) { - return readFile(bucket, 'utf8').then((data) => _bucketEntries(data, filter)) +async function bucketEntries (bucket, filter) { + const data = await fs.readFile(bucket, 'utf8') + return _bucketEntries(data, filter) } module.exports.bucketEntries.sync = bucketEntriesSync @@ -406,7 +393,7 @@ function formatEntry (cache, entry, keepAll) { } function readdirOrEmpty (dir) { - return readdir(dir).catch((err) => { + return fs.readdir(dir).catch((err) => { if (err.code === 'ENOENT' || err.code === 'ENOTDIR') { return [] } diff --git a/deps/npm/node_modules/cacache/lib/get.js b/deps/npm/node_modules/cacache/lib/get.js index 58f357b1da..cc9d8f6796 100644 --- a/deps/npm/node_modules/cacache/lib/get.js +++ b/deps/npm/node_modules/cacache/lib/get.js @@ -8,52 +8,48 @@ const index = require('./entry-index') const memo = require('./memoization') const read = require('./content/read') -function getData (cache, key, opts = {}) { +async function getData (cache, key, opts = {}) { const { integrity, memoize, size } = opts const memoized = memo.get(cache, key, opts) if (memoized && memoize !== false) { - return Promise.resolve({ + return { metadata: memoized.entry.metadata, data: memoized.data, integrity: memoized.entry.integrity, size: memoized.entry.size, - }) + } } - return index.find(cache, key, opts).then((entry) => { - if (!entry) { - throw new index.NotFoundError(cache, key) - } + const entry = await index.find(cache, key, opts) + if (!entry) { + throw new index.NotFoundError(cache, key) + } + const data = await read(cache, entry.integrity, { integrity, size }) + if (memoize) { + memo.put(cache, entry, data, opts) + } - return read(cache, entry.integrity, { integrity, size }).then((data) => { - if (memoize) { - memo.put(cache, entry, data, opts) - } - - return { - data, - metadata: entry.metadata, - size: entry.size, - integrity: entry.integrity, - } - }) - }) + return { + data, + metadata: entry.metadata, + size: entry.size, + integrity: entry.integrity, + } } module.exports = getData -function getDataByDigest (cache, key, opts = {}) { +async function getDataByDigest (cache, key, opts = {}) { const { integrity, memoize, size } = opts const memoized = memo.get.byDigest(cache, key, opts) if (memoized && memoize !== false) { - return Promise.resolve(memoized) + return memoized } - return read(cache, key, { integrity, size }).then((res) => { - if (memoize) { - memo.put.byDigest(cache, key, res, opts) - } - return res - }) + const res = await read(cache, key, { integrity, size }) + if (memoize) { + memo.put.byDigest(cache, key, res, opts) + } + return res } module.exports.byDigest = getDataByDigest @@ -131,36 +127,35 @@ function getStream (cache, key, opts = {}) { } const stream = new Pipeline() - index - .find(cache, key) - .then((entry) => { - if (!entry) { - throw new index.NotFoundError(cache, key) - } - - stream.emit('metadata', entry.metadata) - stream.emit('integrity', entry.integrity) - stream.emit('size', entry.size) - stream.on('newListener', function (ev, cb) { - ev === 'metadata' && cb(entry.metadata) - ev === 'integrity' && cb(entry.integrity) - ev === 'size' && cb(entry.size) - }) - - const src = read.readStream( - cache, - entry.integrity, - { ...opts, size: typeof size !== 'number' ? entry.size : size } - ) - - if (memoize) { - const memoStream = new Collect.PassThrough() - memoStream.on('collect', data => memo.put(cache, entry, data, opts)) - stream.unshift(memoStream) - } - stream.unshift(src) + // Set all this up to run on the stream and then just return the stream + Promise.resolve().then(async () => { + const entry = await index.find(cache, key) + if (!entry) { + throw new index.NotFoundError(cache, key) + } + + stream.emit('metadata', entry.metadata) + stream.emit('integrity', entry.integrity) + stream.emit('size', entry.size) + stream.on('newListener', function (ev, cb) { + ev === 'metadata' && cb(entry.metadata) + ev === 'integrity' && cb(entry.integrity) + ev === 'size' && cb(entry.size) }) - .catch((err) => stream.emit('error', err)) + + const src = read.readStream( + cache, + entry.integrity, + { ...opts, size: typeof size !== 'number' ? entry.size : size } + ) + + if (memoize) { + const memoStream = new Collect.PassThrough() + memoStream.on('collect', data => memo.put(cache, entry, data, opts)) + stream.unshift(memoStream) + } + stream.unshift(src) + }).catch((err) => stream.emit('error', err)) return stream } @@ -204,27 +199,26 @@ function info (cache, key, opts = {}) { } module.exports.info = info -function copy (cache, key, dest, opts = {}) { - return index.find(cache, key, opts).then((entry) => { - if (!entry) { - throw new index.NotFoundError(cache, key) - } - return read.copy(cache, entry.integrity, dest, opts) - .then(() => { - return { - metadata: entry.metadata, - size: entry.size, - integrity: entry.integrity, - } - }) - }) +async function copy (cache, key, dest, opts = {}) { + const entry = await index.find(cache, key, opts) + if (!entry) { + throw new index.NotFoundError(cache, key) + } + await read.copy(cache, entry.integrity, dest, opts) + return { + metadata: entry.metadata, + size: entry.size, + integrity: entry.integrity, + } } module.exports.copy = copy -function copyByDigest (cache, key, dest, opts = {}) { - return read.copy(cache, key, dest, opts).then(() => key) +async function copyByDigest (cache, key, dest, opts = {}) { + await read.copy(cache, key, dest, opts) + return key } + module.exports.copy.byDigest = copyByDigest module.exports.hasContent = read.hasContent diff --git a/deps/npm/node_modules/cacache/lib/put.js b/deps/npm/node_modules/cacache/lib/put.js index eed51874f9..9fc932d5f6 100644 --- a/deps/npm/node_modules/cacache/lib/put.js +++ b/deps/npm/node_modules/cacache/lib/put.js @@ -14,20 +14,16 @@ const putOpts = (opts) => ({ module.exports = putData -function putData (cache, key, data, opts = {}) { +async function putData (cache, key, data, opts = {}) { const { memoize } = opts opts = putOpts(opts) - return write(cache, data, opts).then((res) => { - return index - .insert(cache, key, res.integrity, { ...opts, size: res.size }) - .then((entry) => { - if (memoize) { - memo.put(cache, entry, data, opts) - } + const res = await write(cache, data, opts) + const entry = await index.insert(cache, key, res.integrity, { ...opts, size: res.size }) + if (memoize) { + memo.put(cache, entry, data, opts) + } - return res.integrity - }) - }) + return res.integrity } module.exports.stream = putStream @@ -68,17 +64,14 @@ function putStream (cache, key, opts = {}) { // last but not least, we write the index and emit hash and size, // and memoize if we're doing that pipeline.push(new Flush({ - flush () { + async flush () { if (!error) { - return index - .insert(cache, key, integrity, { ...opts, size }) - .then((entry) => { - if (memoize && memoData) { - memo.put(cache, entry, memoData, opts) - } - pipeline.emit('integrity', integrity) - pipeline.emit('size', size) - }) + const entry = await index.insert(cache, key, integrity, { ...opts, size }) + if (memoize && memoData) { + memo.put(cache, entry, memoData, opts) + } + pipeline.emit('integrity', integrity) + pipeline.emit('size', size) } }, })) diff --git a/deps/npm/node_modules/cacache/lib/util/fix-owner.js b/deps/npm/node_modules/cacache/lib/util/fix-owner.js index bc14def4e4..182fcb028f 100644 --- a/deps/npm/node_modules/cacache/lib/util/fix-owner.js +++ b/deps/npm/node_modules/cacache/lib/util/fix-owner.js @@ -33,40 +33,38 @@ const getSelf = () => { module.exports.chownr = fixOwner -function fixOwner (cache, filepath) { +async function fixOwner (cache, filepath) { if (!process.getuid) { // This platform doesn't need ownership fixing - return Promise.resolve() + return } getSelf() if (self.uid !== 0) { // almost certainly can't chown anyway - return Promise.resolve() + return } - return Promise.resolve(inferOwner(cache)).then((owner) => { - const { uid, gid } = owner + const { uid, gid } = await inferOwner(cache) - // No need to override if it's already what we used. - if (self.uid === uid && self.gid === gid) { - return - } + // No need to override if it's already what we used. + if (self.uid === uid && self.gid === gid) { + return + } - return inflight('fixOwner: fixing ownership on ' + filepath, () => - chownr( - filepath, - typeof uid === 'number' ? uid : self.uid, - typeof gid === 'number' ? gid : self.gid - ).catch((err) => { - if (err.code === 'ENOENT') { - return null - } - - throw err - }) - ) - }) + return inflight('fixOwner: fixing ownership on ' + filepath, () => + chownr( + filepath, + typeof uid === 'number' ? uid : self.uid, + typeof gid === 'number' ? gid : self.gid + ).catch((err) => { + if (err.code === 'ENOENT') { + return null + } + + throw err + }) + ) } module.exports.chownr.sync = fixOwnerSync @@ -105,26 +103,25 @@ function fixOwnerSync (cache, filepath) { module.exports.mkdirfix = mkdirfix -function mkdirfix (cache, p, cb) { +async function mkdirfix (cache, p, cb) { // we have to infer the owner _before_ making the directory, even though // we aren't going to use the results, since the cache itself might not // exist yet. If we mkdirp it, then our current uid/gid will be assumed // to be correct if it creates the cache folder in the process. - return Promise.resolve(inferOwner(cache)).then(() => { - return mkdirp(p) - .then((made) => { - if (made) { - return fixOwner(cache, made).then(() => made) - } - }) - .catch((err) => { - if (err.code === 'EEXIST') { - return fixOwner(cache, p).then(() => null) - } - - throw err - }) - }) + await inferOwner(cache) + try { + const made = await mkdirp(p) + if (made) { + await fixOwner(cache, made) + return made + } + } catch (err) { + if (err.code === 'EEXIST') { + await fixOwner(cache, p) + return null + } + throw err + } } module.exports.mkdirfix.sync = mkdirfixSync diff --git a/deps/npm/node_modules/cacache/lib/util/move-file.js b/deps/npm/node_modules/cacache/lib/util/move-file.js index 3739cea3df..a0b40413cb 100644 --- a/deps/npm/node_modules/cacache/lib/util/move-file.js +++ b/deps/npm/node_modules/cacache/lib/util/move-file.js @@ -1,18 +1,13 @@ 'use strict' -const fs = require('fs') -const util = require('util') -const chmod = util.promisify(fs.chmod) -const unlink = util.promisify(fs.unlink) -const stat = util.promisify(fs.stat) +const fs = require('@npmcli/fs') const move = require('@npmcli/move-file') const pinflight = require('promise-inflight') module.exports = moveFile -function moveFile (src, dest) { - const isWindows = global.__CACACHE_TEST_FAKE_WINDOWS__ || - process.platform === 'win32' +async function moveFile (src, dest) { + const isWindows = process.platform === 'win32' // This isn't quite an fs.rename -- the assumption is that // if `dest` already exists, and we get certain errors while @@ -23,47 +18,39 @@ function moveFile (src, dest) { // content their own way. // // Note that, as the name suggests, this strictly only supports file moves. - return new Promise((resolve, reject) => { - fs.link(src, dest, (err) => { - if (err) { - if (isWindows && err.code === 'EPERM') { - // XXX This is a really weird way to handle this situation, as it - // results in the src file being deleted even though the dest - // might not exist. Since we pretty much always write files to - // deterministic locations based on content hash, this is likely - // ok (or at worst, just ends in a future cache miss). But it would - // be worth investigating at some time in the future if this is - // really what we want to do here. - return resolve() - } else if (err.code === 'EEXIST' || err.code === 'EBUSY') { - // file already exists, so whatever - return resolve() - } else { - return reject(err) + try { + await fs.link(src, dest) + } catch (err) { + if (isWindows && err.code === 'EPERM') { + // XXX This is a really weird way to handle this situation, as it + // results in the src file being deleted even though the dest + // might not exist. Since we pretty much always write files to + // deterministic locations based on content hash, this is likely + // ok (or at worst, just ends in a future cache miss). But it would + // be worth investigating at some time in the future if this is + // really what we want to do here. + } else if (err.code === 'EEXIST' || err.code === 'EBUSY') { + // file already exists, so whatever + } else { + throw err + } + } + try { + await Promise.all([ + fs.unlink(src), + !isWindows && fs.chmod(dest, '0444'), + ]) + } catch (e) { + return pinflight('cacache-move-file:' + dest, async () => { + await fs.stat(dest).catch((err) => { + if (err.code !== 'ENOENT') { + // Something else is wrong here. Bail bail bail + throw err } - } else { - return resolve() - } - }) - }) - .then(() => { - // content should never change for any reason, so make it read-only - return Promise.all([ - unlink(src), - !isWindows && chmod(dest, '0444'), - ]) - }) - .catch(() => { - return pinflight('cacache-move-file:' + dest, () => { - return stat(dest).catch((err) => { - if (err.code !== 'ENOENT') { - // Something else is wrong here. Bail bail bail - throw err - } - // file doesn't already exist! let's try a rename -> copy fallback - // only delete if it successfully copies - return move(src, dest) - }) }) + // file doesn't already exist! let's try a rename -> copy fallback + // only delete if it successfully copies + return move(src, dest) }) + } } diff --git a/deps/npm/node_modules/cacache/lib/util/tmp.js b/deps/npm/node_modules/cacache/lib/util/tmp.js index 0a5a50eba3..b4437cfcbe 100644 --- a/deps/npm/node_modules/cacache/lib/util/tmp.js +++ b/deps/npm/node_modules/cacache/lib/util/tmp.js @@ -7,15 +7,13 @@ const path = require('path') module.exports.mkdir = mktmpdir -function mktmpdir (cache, opts = {}) { +async function mktmpdir (cache, opts = {}) { const { tmpPrefix } = opts const tmpDir = path.join(cache, 'tmp') - return fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' }) - .then(() => { - // do not use path.join(), it drops the trailing / if tmpPrefix is unset - const target = `${tmpDir}${path.sep}${tmpPrefix || ''}` - return fs.mkdtemp(target, { owner: 'inherit' }) - }) + await fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' }) + // do not use path.join(), it drops the trailing / if tmpPrefix is unset + const target = `${tmpDir}${path.sep}${tmpPrefix || ''}` + return fs.mkdtemp(target, { owner: 'inherit' }) } module.exports.withTmp = withTmp diff --git a/deps/npm/node_modules/cacache/lib/verify.js b/deps/npm/node_modules/cacache/lib/verify.js index a39fb6ce1d..52692a01d1 100644 --- a/deps/npm/node_modules/cacache/lib/verify.js +++ b/deps/npm/node_modules/cacache/lib/verify.js @@ -5,7 +5,7 @@ const util = require('util') const pMap = require('p-map') const contentPath = require('./content/path') const fixOwner = require('./util/fix-owner') -const fs = require('fs') +const fs = require('@npmcli/fs') const fsm = require('fs-minipass') const glob = util.promisify(require('glob')) const index = require('./entry-index') @@ -18,11 +18,6 @@ const globify = pattern => pattern.split('\\').join('/') const hasOwnProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key) -const stat = util.promisify(fs.stat) -const truncate = util.promisify(fs.truncate) -const writeFile = util.promisify(fs.writeFile) -const readFile = util.promisify(fs.readFile) - const verifyOpts = (opts) => ({ concurrency: 20, log: { silly () {} }, @@ -31,7 +26,7 @@ const verifyOpts = (opts) => ({ module.exports = verify -function verify (cache, opts) { +async function verify (cache, opts) { opts = verifyOpts(opts) opts.log.silly('verify', 'verifying cache at', cache) @@ -45,56 +40,47 @@ function verify (cache, opts) { markEndTime, ] - return steps - .reduce((promise, step, i) => { - const label = step.name - const start = new Date() - return promise.then((stats) => { - return step(cache, opts).then((s) => { - s && - Object.keys(s).forEach((k) => { - stats[k] = s[k] - }) - const end = new Date() - if (!stats.runTime) { - stats.runTime = {} - } - - stats.runTime[label] = end - start - return Promise.resolve(stats) - }) + const stats = {} + for (const step of steps) { + const label = step.name + const start = new Date() + const s = await step(cache, opts) + if (s) { + Object.keys(s).forEach((k) => { + stats[k] = s[k] }) - }, Promise.resolve({})) - .then((stats) => { - stats.runTime.total = stats.endTime - stats.startTime - opts.log.silly( - 'verify', - 'verification finished for', - cache, - 'in', - `${stats.runTime.total}ms` - ) - return stats - }) + } + const end = new Date() + if (!stats.runTime) { + stats.runTime = {} + } + stats.runTime[label] = end - start + } + stats.runTime.total = stats.endTime - stats.startTime + opts.log.silly( + 'verify', + 'verification finished for', + cache, + 'in', + `${stats.runTime.total}ms` + ) + return stats } -function markStartTime (cache, opts) { - return Promise.resolve({ startTime: new Date() }) +async function markStartTime (cache, opts) { + return { startTime: new Date() } } -function markEndTime (cache, opts) { - return Promise.resolve({ endTime: new Date() }) +async function markEndTime (cache, opts) { + return { endTime: new Date() } } -function fixPerms (cache, opts) { +async function fixPerms (cache, opts) { opts.log.silly('verify', 'fixing cache permissions') - return fixOwner - .mkdirfix(cache, cache) - .then(() => { - // TODO - fix file permissions too - return fixOwner.chownr(cache, cache) - }) - .then(() => null) + await fixOwner.mkdirfix(cache, cache) + // TODO - fix file permissions too + await fixOwner.chownr(cache, cache) + return null } // Implements a naive mark-and-sweep tracing garbage collector. @@ -106,7 +92,7 @@ function fixPerms (cache, opts) { // 4. If content is live, verify its checksum and delete it if it fails // 5. If content is not marked as live, rimraf it. // -function garbageCollect (cache, opts) { +async function garbageCollect (cache, opts) { opts.log.silly('verify', 'garbage collecting content') const indexStream = index.lsStream(cache) const liveContent = new Set() @@ -117,156 +103,135 @@ function garbageCollect (cache, opts) { liveContent.add(entry.integrity.toString()) }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { indexStream.on('end', resolve).on('error', reject) - }).then(() => { - const contentDir = contentPath.contentDir(cache) - return glob(globify(path.join(contentDir, '**')), { - follow: false, - nodir: true, - nosort: true, - }).then((files) => { - return Promise.resolve({ - verifiedContent: 0, - reclaimedCount: 0, - reclaimedSize: 0, - badContentCount: 0, - keptSize: 0, - }).then((stats) => - pMap( - files, - (f) => { - const split = f.split(/[/\\]/) - const digest = split.slice(split.length - 3).join('') - const algo = split[split.length - 4] - const integrity = ssri.fromHex(digest, algo) - if (liveContent.has(integrity.toString())) { - return verifyContent(f, integrity).then((info) => { - if (!info.valid) { - stats.reclaimedCount++ - stats.badContentCount++ - stats.reclaimedSize += info.size - } else { - stats.verifiedContent++ - stats.keptSize += info.size - } - return stats - }) - } else { - // No entries refer to this content. We can delete. - stats.reclaimedCount++ - return stat(f).then((s) => { - return rimraf(f).then(() => { - stats.reclaimedSize += s.size - return stats - }) - }) - } - }, - { concurrency: opts.concurrency } - ).then(() => stats) - ) - }) }) -} - -function verifyContent (filepath, sri) { - return stat(filepath) - .then((s) => { - const contentInfo = { - size: s.size, - valid: true, - } - return ssri - .checkStream(new fsm.ReadStream(filepath), sri) - .catch((err) => { - if (err.code !== 'EINTEGRITY') { - throw err - } - - return rimraf(filepath).then(() => { - contentInfo.valid = false - }) - }) - .then(() => contentInfo) - }) - .catch((err) => { - if (err.code === 'ENOENT') { - return { size: 0, valid: false } + const contentDir = contentPath.contentDir(cache) + const files = await glob(globify(path.join(contentDir, '**')), { + follow: false, + nodir: true, + nosort: true, + }) + const stats = { + verifiedContent: 0, + reclaimedCount: 0, + reclaimedSize: 0, + badContentCount: 0, + keptSize: 0, + } + await pMap( + files, + async (f) => { + const split = f.split(/[/\\]/) + const digest = split.slice(split.length - 3).join('') + const algo = split[split.length - 4] + const integrity = ssri.fromHex(digest, algo) + if (liveContent.has(integrity.toString())) { + const info = await verifyContent(f, integrity) + if (!info.valid) { + stats.reclaimedCount++ + stats.badContentCount++ + stats.reclaimedSize += info.size + } else { + stats.verifiedContent++ + stats.keptSize += info.size + } + } else { + // No entries refer to this content. We can delete. + stats.reclaimedCount++ + const s = await fs.stat(f) + await rimraf(f) + stats.reclaimedSize += s.size } + return stats + }, + { concurrency: opts.concurrency } + ) + return stats +} +async function verifyContent (filepath, sri) { + const contentInfo = {} + try { + const { size } = await fs.stat(filepath) + contentInfo.size = size + contentInfo.valid = true + await ssri.checkStream(new fsm.ReadStream(filepath), sri) + } catch (err) { + if (err.code === 'ENOENT') { + return { size: 0, valid: false } + } + if (err.code !== 'EINTEGRITY') { throw err - }) + } + + await rimraf(filepath) + contentInfo.valid = false + } + return contentInfo } -function rebuildIndex (cache, opts) { +async function rebuildIndex (cache, opts) { opts.log.silly('verify', 'rebuilding index') - return index.ls(cache).then((entries) => { - const stats = { - missingContent: 0, - rejectedEntries: 0, - totalEntries: 0, - } - const buckets = {} - for (const k in entries) { - /* istanbul ignore else */ - if (hasOwnProperty(entries, k)) { - const hashed = index.hashKey(k) - const entry = entries[k] - const excluded = opts.filter && !opts.filter(entry) - excluded && stats.rejectedEntries++ - if (buckets[hashed] && !excluded) { - buckets[hashed].push(entry) - } else if (buckets[hashed] && excluded) { - // skip - } else if (excluded) { - buckets[hashed] = [] - buckets[hashed]._path = index.bucketPath(cache, k) - } else { - buckets[hashed] = [entry] - buckets[hashed]._path = index.bucketPath(cache, k) - } + const entries = await index.ls(cache) + const stats = { + missingContent: 0, + rejectedEntries: 0, + totalEntries: 0, + } + const buckets = {} + for (const k in entries) { + /* istanbul ignore else */ + if (hasOwnProperty(entries, k)) { + const hashed = index.hashKey(k) + const entry = entries[k] + const excluded = opts.filter && !opts.filter(entry) + excluded && stats.rejectedEntries++ + if (buckets[hashed] && !excluded) { + buckets[hashed].push(entry) + } else if (buckets[hashed] && excluded) { + // skip + } else if (excluded) { + buckets[hashed] = [] + buckets[hashed]._path = index.bucketPath(cache, k) + } else { + buckets[hashed] = [entry] + buckets[hashed]._path = index.bucketPath(cache, k) } } - return pMap( - Object.keys(buckets), - (key) => { - return rebuildBucket(cache, buckets[key], stats, opts) - }, - { concurrency: opts.concurrency } - ).then(() => stats) - }) + } + await pMap( + Object.keys(buckets), + (key) => { + return rebuildBucket(cache, buckets[key], stats, opts) + }, + { concurrency: opts.concurrency } + ) + return stats } -function rebuildBucket (cache, bucket, stats, opts) { - return truncate(bucket._path).then(() => { - // This needs to be serialized because cacache explicitly - // lets very racy bucket conflicts clobber each other. - return bucket.reduce((promise, entry) => { - return promise.then(() => { - const content = contentPath(cache, entry.integrity) - return stat(content) - .then(() => { - return index - .insert(cache, entry.key, entry.integrity, { - metadata: entry.metadata, - size: entry.size, - }) - .then(() => { - stats.totalEntries++ - }) - }) - .catch((err) => { - if (err.code === 'ENOENT') { - stats.rejectedEntries++ - stats.missingContent++ - return - } - throw err - }) +async function rebuildBucket (cache, bucket, stats, opts) { + await fs.truncate(bucket._path) + // This needs to be serialized because cacache explicitly + // lets very racy bucket conflicts clobber each other. + for (const entry of bucket) { + const content = contentPath(cache, entry.integrity) + try { + await fs.stat(content) + await index.insert(cache, entry.key, entry.integrity, { + metadata: entry.metadata, + size: entry.size, }) - }, Promise.resolve()) - }) + stats.totalEntries++ + } catch (err) { + if (err.code === 'ENOENT') { + stats.rejectedEntries++ + stats.missingContent++ + } else { + throw err + } + } + } } function cleanTmp (cache, opts) { @@ -278,7 +243,7 @@ function writeVerifile (cache, opts) { const verifile = path.join(cache, '_lastverified') opts.log.silly('verify', 'writing verifile to ' + verifile) try { - return writeFile(verifile, '' + +new Date()) + return fs.writeFile(verifile, `${Date.now()}`) } finally { fixOwner.chownr.sync(cache, verifile) } @@ -286,8 +251,7 @@ function writeVerifile (cache, opts) { module.exports.lastRun = lastRun -function lastRun (cache) { - return readFile(path.join(cache, '_lastverified'), 'utf8').then( - (data) => new Date(+data) - ) +async function lastRun (cache) { + const data = await fs.readFile(path.join(cache, '_lastverified'), { encoding: 'utf8' }) + return new Date(+data) } diff --git a/deps/npm/node_modules/cacache/package.json b/deps/npm/node_modules/cacache/package.json index cd7e4de5e0..8e54901b45 100644 --- a/deps/npm/node_modules/cacache/package.json +++ b/deps/npm/node_modules/cacache/package.json @@ -1,6 +1,6 @@ { "name": "cacache", - "version": "16.0.7", + "version": "16.1.0", "cache-version": { "content": "2", "index": "5" @@ -69,20 +69,16 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.4.1", + "@npmcli/template-oss": "3.4.3", "tap": "^16.0.0" }, - "tap": { - "100": true, - "test-regex": "test/[^/]*.js" - }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "windowsCI": false, - "version": "3.4.1" + "version": "3.4.3" }, "author": "GitHub Inc." } diff --git a/deps/npm/node_modules/libnpmpack/package.json b/deps/npm/node_modules/libnpmpack/package.json index 3fcf630cce..02f06a8bbf 100644 --- a/deps/npm/node_modules/libnpmpack/package.json +++ b/deps/npm/node_modules/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "4.0.3", + "version": "4.1.0", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -40,7 +40,7 @@ "dependencies": { "@npmcli/run-script": "^3.0.0", "npm-package-arg": "^9.0.1", - "pacote": "^13.0.5" + "pacote": "^13.5.0" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" diff --git a/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js b/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js index ae2ad8c766..7a7572ba03 100644 --- a/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js +++ b/deps/npm/node_modules/make-fetch-happen/lib/cache/entry.js @@ -1,21 +1,16 @@ const { Request, Response } = require('minipass-fetch') const Minipass = require('minipass') -const MinipassCollect = require('minipass-collect') const MinipassFlush = require('minipass-flush') -const MinipassPipeline = require('minipass-pipeline') const cacache = require('cacache') const url = require('url') +const CachingMinipassPipeline = require('../pipeline.js') const CachePolicy = require('./policy.js') const cacheKey = require('./key.js') const remote = require('../remote.js') const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop) -// maximum amount of data we will buffer into memory -// if we'll exceed this, we switch to streaming -const MAX_MEM_SIZE = 5 * 1024 * 1024 // 5MB - // allow list for request headers that will be written to the cache index // note: we will also store any request headers // that are named in a response's vary header @@ -256,13 +251,12 @@ class CacheEntry { } const size = this.response.headers.get('content-length') - const fitsInMemory = !!size && Number(size) < MAX_MEM_SIZE - const shouldBuffer = this.options.memoize !== false && fitsInMemory const cacheOpts = { algorithms: this.options.algorithms, metadata: getMetadata(this.request, this.response, this.options), size, - memoize: fitsInMemory && this.options.memoize, + integrity: this.options.integrity, + integrityEmitter: this.response.body.hasIntegrityEmitter && this.response.body, } let body = null @@ -275,52 +269,31 @@ class CacheEntry { cacheWriteReject = reject }) - body = new MinipassPipeline(new MinipassFlush({ + body = new CachingMinipassPipeline({ events: ['integrity', 'size'] }, new MinipassFlush({ flush () { return cacheWritePromise }, })) - - let abortStream, onResume - if (shouldBuffer) { - // if the result fits in memory, use a collect stream to gather - // the response and write it to cacache while also passing it through - // to the user - onResume = () => { - const collector = new MinipassCollect.PassThrough() - abortStream = collector - collector.on('collect', (data) => { - // TODO if the cache write fails, log a warning but return the response anyway - cacache.put(this.options.cachePath, this.key, data, cacheOpts) - .then(cacheWriteResolve, cacheWriteReject) - }) - body.unshift(collector) - body.unshift(this.response.body) - } - } else { - // if it does not fit in memory, create a tee stream and use - // that to pipe to both the cache and the user simultaneously - onResume = () => { - const tee = new Minipass() - const cacheStream = cacache.put.stream(this.options.cachePath, this.key, cacheOpts) - abortStream = cacheStream - tee.pipe(cacheStream) - // TODO if the cache write fails, log a warning but return the response anyway - cacheStream.promise().then(cacheWriteResolve, cacheWriteReject) - body.unshift(tee) - body.unshift(this.response.body) - } + // this is always true since if we aren't reusing the one from the remote fetch, we + // are using the one from cacache + body.hasIntegrityEmitter = true + + const onResume = () => { + const tee = new Minipass() + const cacheStream = cacache.put.stream(this.options.cachePath, this.key, cacheOpts) + // re-emit the integrity and size events on our new response body so they can be reused + cacheStream.on('integrity', i => body.emit('integrity', i)) + cacheStream.on('size', s => body.emit('size', s)) + // stick a flag on here so downstream users will know if they can expect integrity events + tee.pipe(cacheStream) + // TODO if the cache write fails, log a warning but return the response anyway + cacheStream.promise().then(cacheWriteResolve, cacheWriteReject) + body.unshift(tee) + body.unshift(this.response.body) } body.once('resume', onResume) body.once('end', () => body.removeListener('resume', onResume)) - this.response.body.on('error', (err) => { - // the abortStream will either be a MinipassCollect if we buffer - // or a cacache write stream, either way be sure to listen for - // errors from the actual response and avoid writing data that we - // know to be invalid to the cache - abortStream.destroy(err) - }) } else { await cacache.index.insert(this.options.cachePath, this.key, null, cacheOpts) } @@ -331,7 +304,7 @@ class CacheEntry { // the header anyway this.response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath)) this.response.headers.set('x-local-cache-key', encodeURIComponent(this.key)) - this.response.headers.set('x-local-cache-mode', shouldBuffer ? 'buffer' : 'stream') + this.response.headers.set('x-local-cache-mode', 'stream') this.response.headers.set('x-local-cache-status', status) this.response.headers.set('x-local-cache-time', new Date().toISOString()) const newResponse = new Response(body, { @@ -346,9 +319,6 @@ class CacheEntry { // use the cached data to create a response and return it async respond (method, options, status) { let response - const size = Number(this.response.headers.get('content-length')) - const fitsInMemory = !!size && size < MAX_MEM_SIZE - const shouldBuffer = this.options.memoize !== false && fitsInMemory if (method === 'HEAD' || [301, 308].includes(this.response.status)) { // if the request is a HEAD, or the response is a redirect, // then the metadata in the entry already includes everything @@ -358,66 +328,44 @@ class CacheEntry { // we're responding with a full cached response, so create a body // that reads from cacache and attach it to a new Response const body = new Minipass() - const removeOnResume = () => body.removeListener('resume', onResume) - let onResume - if (shouldBuffer) { - onResume = async () => { - removeOnResume() - try { - const content = await cacache.get.byDigest( + const headers = { ...this.policy.responseHeaders() } + const onResume = () => { + const cacheStream = cacache.get.stream.byDigest( + this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } + ) + cacheStream.on('error', async (err) => { + cacheStream.pause() + if (err.code === 'EINTEGRITY') { + await cacache.rm.content( this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } ) - body.end(content) - } catch (err) { - if (err.code === 'EINTEGRITY') { - await cacache.rm.content( - this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } - ) - } - if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') { - await CacheEntry.invalidate(this.request, this.options) - } - body.emit('error', err) } - } - } else { - onResume = () => { - const cacheStream = cacache.get.stream.byDigest( - this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } - ) - cacheStream.on('error', async (err) => { - cacheStream.pause() - if (err.code === 'EINTEGRITY') { - await cacache.rm.content( - this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } - ) - } - if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') { - await CacheEntry.invalidate(this.request, this.options) - } - body.emit('error', err) - cacheStream.resume() - }) - cacheStream.pipe(body) - } + if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') { + await CacheEntry.invalidate(this.request, this.options) + } + body.emit('error', err) + cacheStream.resume() + }) + // emit the integrity and size events based on our metadata so we're consistent + body.emit('integrity', this.entry.integrity) + body.emit('size', Number(headers['content-length'])) + cacheStream.pipe(body) } body.once('resume', onResume) - body.once('end', removeOnResume) + body.once('end', () => body.removeListener('resume', onResume)) response = new Response(body, { url: this.entry.metadata.url, counter: options.counter, status: 200, - headers: { - ...this.policy.responseHeaders(), - }, + headers, }) } response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath)) response.headers.set('x-local-cache-hash', encodeURIComponent(this.entry.integrity)) response.headers.set('x-local-cache-key', encodeURIComponent(this.key)) - response.headers.set('x-local-cache-mode', shouldBuffer ? 'buffer' : 'stream') + response.headers.set('x-local-cache-mode', 'stream') response.headers.set('x-local-cache-status', status) response.headers.set('x-local-cache-time', new Date(this.entry.metadata.time).toUTCString()) return response diff --git a/deps/npm/node_modules/make-fetch-happen/lib/pipeline.js b/deps/npm/node_modules/make-fetch-happen/lib/pipeline.js new file mode 100644 index 0000000000..b1d221b2d0 --- /dev/null +++ b/deps/npm/node_modules/make-fetch-happen/lib/pipeline.js @@ -0,0 +1,41 @@ +'use strict' + +const MinipassPipeline = require('minipass-pipeline') + +class CachingMinipassPipeline extends MinipassPipeline { + #events = [] + #data = new Map() + + constructor (opts, ...streams) { + // CRITICAL: do NOT pass the streams to the call to super(), this will start + // the flow of data and potentially cause the events we need to catch to emit + // before we've finished our own setup. instead we call super() with no args, + // finish our setup, and then push the streams into ourselves to start the + // data flow + super() + this.#events = opts.events + + /* istanbul ignore next - coverage disabled because this is pointless to test here */ + if (streams.length) { + this.push(...streams) + } + } + + on (event, handler) { + if (this.#events.includes(event) && this.#data.has(event)) { + return handler(...this.#data.get(event)) + } + + return super.on(event, handler) + } + + emit (event, ...data) { + if (this.#events.includes(event)) { + this.#data.set(event, data) + } + + return super.emit(event, ...data) + } +} + +module.exports = CachingMinipassPipeline diff --git a/deps/npm/node_modules/make-fetch-happen/lib/remote.js b/deps/npm/node_modules/make-fetch-happen/lib/remote.js index a8b8d2a019..763fc0d488 100644 --- a/deps/npm/node_modules/make-fetch-happen/lib/remote.js +++ b/deps/npm/node_modules/make-fetch-happen/lib/remote.js @@ -1,9 +1,9 @@ const Minipass = require('minipass') -const MinipassPipeline = require('minipass-pipeline') const fetch = require('minipass-fetch') const promiseRetry = require('promise-retry') const ssri = require('ssri') +const CachingMinipassPipeline = require('./pipeline.js') const getAgent = require('./agent.js') const pkg = require('../package.json') @@ -53,7 +53,16 @@ const remoteFetch = (request, options) => { // we got a 200 response and the user has specified an expected // integrity value, so wrap the response in an ssri stream to verify it const integrityStream = ssri.integrityStream({ integrity: _opts.integrity }) - res = new fetch.Response(new MinipassPipeline(res.body, integrityStream), res) + const pipeline = new CachingMinipassPipeline({ + events: ['integrity', 'size'], + }, res.body, integrityStream) + // we also propagate the integrity and size events out to the pipeline so we can use + // this new response body as an integrityEmitter for cacache + integrityStream.on('integrity', i => pipeline.emit('integrity', i)) + integrityStream.on('size', s => pipeline.emit('size', s)) + res = new fetch.Response(pipeline, res) + // set an explicit flag so we know if our response body will emit integrity and size + res.body.hasIntegrityEmitter = true } res.headers.set('x-fetch-attempts', attemptNum) diff --git a/deps/npm/node_modules/make-fetch-happen/package.json b/deps/npm/node_modules/make-fetch-happen/package.json index e1e8e97518..2e6153b99f 100644 --- a/deps/npm/node_modules/make-fetch-happen/package.json +++ b/deps/npm/node_modules/make-fetch-happen/package.json @@ -1,6 +1,6 @@ { "name": "make-fetch-happen", - "version": "10.1.3", + "version": "10.1.5", "description": "Opinionated, caching, retrying fetch client", "main": "lib/index.js", "files": [ @@ -37,7 +37,7 @@ "license": "ISC", "dependencies": { "agentkeepalive": "^4.2.1", - "cacache": "^16.0.2", + "cacache": "^16.1.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", @@ -55,7 +55,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.4.3", + "@npmcli/template-oss": "3.5.0", "mkdirp": "^1.0.4", "nock": "^13.2.4", "rimraf": "^3.0.2", @@ -73,6 +73,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.4.3" + "version": "3.5.0" } } diff --git a/deps/npm/node_modules/npm-packlist/lib/index.js b/deps/npm/node_modules/npm-packlist/lib/index.js index c7b0db5f60..e4a2e76c54 100644 --- a/deps/npm/node_modules/npm-packlist/lib/index.js +++ b/deps/npm/node_modules/npm-packlist/lib/index.js @@ -33,6 +33,33 @@ const fs = require('fs') const glob = require('glob') const globify = pattern => pattern.split('\\').join('/') +const readOutOfTreeIgnoreFiles = (root, rel, result = '') => { + for (const file of ['.gitignore', '.npmignore']) { + try { + const ignoreContent = fs.readFileSync(path.join(root, file), { encoding: 'utf8' }) + result += ignoreContent + '\n' + } catch (err) { + // we ignore ENOENT errors completely because we don't care if the file doesn't exist + // but we throw everything else because failing to read a file that does exist is + // something that the user likely wants to know about. we don't need to test this. + /* istanbul ignore next */ + if (err.code !== 'ENOENT') { + throw err + } + } + } + + if (!rel) { + return result + } + + const firstRel = rel.split(path.sep)[0] + const newRoot = path.join(root, firstRel) + const newRel = path.relative(newRoot, path.join(root, rel)) + + return readOutOfTreeIgnoreFiles(newRoot, newRel, result) +} + const pathHasPkg = (input) => { if (!input.startsWith('node_modules/')) { return false @@ -119,9 +146,31 @@ class Walker extends IgnoreWalker { this.bundledScopes = Array.from(new Set( this.bundled.filter(f => /^@/.test(f)) .map(f => f.split('/')[0]))) - const rules = defaultRules.join('\n') + '\n' this.packageJsonCache = this.parent ? this.parent.packageJsonCache : (opt.packageJsonCache || new Map()) + let rules = defaultRules.join('\n') + '\n' + + if (opt.prefix && opt.workspaces) { + const gPath = globify(opt.path) + const gPrefix = globify(opt.prefix) + const gWorkspaces = opt.workspaces.map((ws) => globify(ws)) + // if opt.path and opt.prefix are not the same directory, and opt.workspaces has opt.path + // in it, then we know that opt.path is a workspace directory. in order to not drop ignore + // rules from directories between the workspace root (opt.prefix) and the workspace itself + // (opt.path), we need to find and read those now + /* istanbul ignore else */ + if (gPath !== gPrefix && gWorkspaces.includes(gPath)) { + // relpath is the relative path between the prefix and the parent of opt.path + // we use the parent because ignore-walk will read the files in opt.path already + const relpath = path.relative(opt.prefix, path.dirname(opt.path)) + rules += readOutOfTreeIgnoreFiles(opt.prefix, relpath) + } else if (gPath === gPrefix) { + // on the other hand, if the path and the prefix are the same, then we ignore workspaces + // so that we don't pack workspaces inside of a root project + rules += opt.workspaces.map((ws) => globify(path.relative(opt.path, ws))).join('\n') + } + } + super.onReadIgnoreFile(rootBuiltinRules, rules, _ => _) } else { this.bundled = [] diff --git a/deps/npm/node_modules/npm-packlist/package.json b/deps/npm/node_modules/npm-packlist/package.json index e79d1d4b82..dfa0188b4c 100644 --- a/deps/npm/node_modules/npm-packlist/package.json +++ b/deps/npm/node_modules/npm-packlist/package.json @@ -1,6 +1,6 @@ { "name": "npm-packlist", - "version": "5.0.3", + "version": "5.1.0", "description": "Get a list of the files to add from a folder into an npm package", "directories": { "test": "test" @@ -20,7 +20,7 @@ ], "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.4.2", + "@npmcli/template-oss": "3.5.0", "mutate-fs": "^2.1.1", "tap": "^16.0.1" }, @@ -56,6 +56,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.4.2" + "version": "3.5.0" } } diff --git a/deps/npm/node_modules/pacote/README.md b/deps/npm/node_modules/pacote/README.md index 11822dbb48..eac48f69fe 100644 --- a/deps/npm/node_modules/pacote/README.md +++ b/deps/npm/node_modules/pacote/README.md @@ -168,6 +168,10 @@ resolved, and other properties, as they are determined. is unlikely to change in the span of a single command. * `silent` A boolean that determines whether the banner is displayed when calling `@npmcli/run-script`. +* `verifySignatures` A boolean that will make pacote verify the + integrity signature of a manifest, if present. There must be a + configured `_keys` entry in the config that is scoped to the + registry the manifest is being fetched from. ### Advanced API diff --git a/deps/npm/node_modules/pacote/lib/dir.js b/deps/npm/node_modules/pacote/lib/dir.js index 598b029f7a..502379810a 100644 --- a/deps/npm/node_modules/pacote/lib/dir.js +++ b/deps/npm/node_modules/pacote/lib/dir.js @@ -63,10 +63,12 @@ class DirFetcher extends Fetcher { stream.resolved = this.resolved stream.integrity = this.integrity + const { prefix, workspaces } = this.opts + // run the prepare script, get the list of files, and tar it up // pipe to the stream, and proxy errors the chain. this[_prepareDir]() - .then(() => packlist({ path: this.resolved })) + .then(() => packlist({ path: this.resolved, prefix, workspaces })) .then(files => tar.c(tarCreateOptions(this.package), files) .on('error', er => stream.emit('error', er)).pipe(stream)) .catch(er => stream.emit('error', er)) diff --git a/deps/npm/node_modules/pacote/lib/registry.js b/deps/npm/node_modules/pacote/lib/registry.js index e8ca16f596..2eb37bcecc 100644 --- a/deps/npm/node_modules/pacote/lib/registry.js +++ b/deps/npm/node_modules/pacote/lib/registry.js @@ -7,6 +7,7 @@ const npa = require('npm-package-arg') const rpj = require('read-package-json-fast') const pickManifest = require('npm-pick-manifest') const ssri = require('ssri') +const crypto = require('crypto') // Corgis are cute. 🐕🐶 const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' @@ -14,8 +15,6 @@ const fullDoc = 'application/json' const fetch = require('npm-registry-fetch') -// TODO: memoize reg requests, so we don't even have to check cache - const _headers = Symbol('_headers') class RegistryFetcher extends Fetcher { constructor (spec, opts) { @@ -39,28 +38,30 @@ class RegistryFetcher extends Fetcher { this.packumentUrl = removeTrailingSlashes(this.registry) + '/' + this.spec.escapedName + const parsed = new URL(this.registry) + const regKey = `//${parsed.host}${parsed.pathname}` + // unlike the nerf-darted auth keys, this one does *not* allow a mismatch + // of trailing slashes. It must match exactly. + if (this.opts[`${regKey}:_keys`]) { + this.registryKeys = this.opts[`${regKey}:_keys`] + } + // XXX pacote <=9 has some logic to ignore opts.resolved if // the resolved URL doesn't go to the same registry. // Consider reproducing that here, to throw away this.resolved // in that case. } - resolve () { - if (this.resolved) { - return Promise.resolve(this.resolved) - } - - // fetching the manifest sets resolved and (usually) integrity - return this.manifest().then(() => { - if (this.resolved) { - return this.resolved - } - + async resolve () { + // fetching the manifest sets resolved and (if present) integrity + await this.manifest() + if (!this.resolved) { throw Object.assign( new Error('Invalid package manifest: no `dist.tarball` field'), { package: this.spec.toString() } ) - }) + } + return this.resolved } [_headers] () { @@ -87,91 +88,127 @@ class RegistryFetcher extends Fetcher { // npm-registry-fetch the packument // set the appropriate header for corgis if fullMetadata isn't set // return the res.json() promise - const p = fetch(this.packumentUrl, { - ...this.opts, - headers: this[_headers](), - spec: this.spec, - // never check integrity for packuments themselves - integrity: null, - }).then(res => res.json().then(packument => { + try { + const res = await fetch(this.packumentUrl, { + ...this.opts, + headers: this[_headers](), + spec: this.spec, + // never check integrity for packuments themselves + integrity: null, + }) + const packument = await res.json() packument._cached = res.headers.has('x-local-cache') packument._contentLength = +res.headers.get('content-length') if (this.packumentCache) { this.packumentCache.set(this.packumentUrl, packument) } return packument - })).catch(er => { + } catch (err) { if (this.packumentCache) { this.packumentCache.delete(this.packumentUrl) } - if (er.code === 'E404' && !this.fullMetadata) { - // possible that corgis are not supported by this registry - this.fullMetadata = true - return this.packument() + if (err.code !== 'E404' || this.fullMetadata) { + throw err } - throw er - }) - if (this.packumentCache) { - this.packumentCache.set(this.packumentUrl, p) + // possible that corgis are not supported by this registry + this.fullMetadata = true + return this.packument() } - return p } - manifest () { + async manifest () { if (this.package) { - return Promise.resolve(this.package) + return this.package } - return this.packument() - .then(packument => pickManifest(packument, this.spec.fetchSpec, { - ...this.opts, - defaultTag: this.defaultTag, - before: this.before, - }) /* XXX add ETARGET and E403 revalidation of cached packuments here */) - .then(mani => { - // add _resolved and _integrity from dist object - const { dist } = mani - if (dist) { - this.resolved = mani._resolved = dist.tarball - mani._from = this.from - const distIntegrity = dist.integrity ? ssri.parse(dist.integrity) - : dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', { ...this.opts }) - : null - if (distIntegrity) { - if (!this.integrity) { - this.integrity = distIntegrity - } else if (!this.integrity.match(distIntegrity)) { - // only bork if they have algos in common. - // otherwise we end up breaking if we have saved a sha512 - // previously for the tarball, but the manifest only - // provides a sha1, which is possible for older publishes. - // Otherwise, this is almost certainly a case of holding it - // wrong, and will result in weird or insecure behavior - // later on when building package tree. - for (const algo of Object.keys(this.integrity)) { - if (distIntegrity[algo]) { - throw Object.assign(new Error( - `Integrity checksum failed when using ${algo}: ` + - `wanted ${this.integrity} but got ${distIntegrity}.` - ), { code: 'EINTEGRITY' }) - } - } - // made it this far, the integrity is worthwhile. accept it. - // the setter here will take care of merging it into what we - // already had. - this.integrity = distIntegrity + const packument = await this.packument() + const mani = await pickManifest(packument, this.spec.fetchSpec, { + ...this.opts, + defaultTag: this.defaultTag, + before: this.before, + }) + /* XXX add ETARGET and E403 revalidation of cached packuments here */ + + // add _resolved and _integrity from dist object + const { dist } = mani + if (dist) { + this.resolved = mani._resolved = dist.tarball + mani._from = this.from + const distIntegrity = dist.integrity ? ssri.parse(dist.integrity) + : dist.shasum ? ssri.fromHex(dist.shasum, 'sha1', { ...this.opts }) + : null + if (distIntegrity) { + if (this.integrity && !this.integrity.match(distIntegrity)) { + // only bork if they have algos in common. + // otherwise we end up breaking if we have saved a sha512 + // previously for the tarball, but the manifest only + // provides a sha1, which is possible for older publishes. + // Otherwise, this is almost certainly a case of holding it + // wrong, and will result in weird or insecure behavior + // later on when building package tree. + for (const algo of Object.keys(this.integrity)) { + if (distIntegrity[algo]) { + throw Object.assign(new Error( + `Integrity checksum failed when using ${algo}: ` + + `wanted ${this.integrity} but got ${distIntegrity}.` + ), { code: 'EINTEGRITY' }) } } } - if (this.integrity) { - mani._integrity = String(this.integrity) - if (dist.signatures) { + // made it this far, the integrity is worthwhile. accept it. + // the setter here will take care of merging it into what we already + // had. + this.integrity = distIntegrity + } + } + if (this.integrity) { + mani._integrity = String(this.integrity) + if (dist.signatures) { + if (this.opts.verifySignatures) { + if (this.registryKeys) { + // validate and throw on error, then set _signatures + const message = `${mani._id}:${mani._integrity}` + for (const signature of dist.signatures) { + const publicKey = this.registryKeys.filter(key => (key.keyid === signature.keyid))[0] + if (!publicKey) { + throw Object.assign(new Error( + `${mani._id} has a signature with keyid: ${signature.keyid} ` + + 'but no corresponding public key can be found.' + ), { code: 'EMISSINGSIGNATUREKEY' }) + } + const validPublicKey = + !publicKey.expires || (Date.parse(publicKey.expires) > Date.now()) + if (!validPublicKey) { + throw Object.assign(new Error( + `${mani._id} has a signature with keyid: ${signature.keyid} ` + + `but the corresponding public key has expired ${publicKey.expires}` + ), { code: 'EEXPIREDSIGNATUREKEY' }) + } + const verifier = crypto.createVerify('SHA256') + verifier.write(message) + verifier.end() + const valid = verifier.verify( + publicKey.pemkey, + signature.sig, + 'base64' + ) + if (!valid) { + throw Object.assign(new Error( + 'Integrity checksum signature failed: ' + + `key ${publicKey.keyid} signature ${signature.sig}` + ), { code: 'EINTEGRITYSIGNATURE' }) + } + } mani._signatures = dist.signatures } + // if no keys, don't set _signatures + } else { + mani._signatures = dist.signatures } - this.package = rpj.normalize(mani) - return this.package - }) + } + } + this.package = rpj.normalize(mani) + return this.package } [_tarballFromResolved] () { diff --git a/deps/npm/node_modules/pacote/package.json b/deps/npm/node_modules/pacote/package.json index 2f4323c441..5045e3f06a 100644 --- a/deps/npm/node_modules/pacote/package.json +++ b/deps/npm/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "13.3.0", + "version": "13.5.0", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { @@ -26,7 +26,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.4.3", + "@npmcli/template-oss": "3.5.0", "hosted-git-info": "^5.0.0", "mutate-fs": "^2.1.1", "nock": "^13.2.4", @@ -54,7 +54,7 @@ "minipass": "^3.1.6", "mkdirp": "^1.0.4", "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.0.0", + "npm-packlist": "^5.1.0", "npm-pick-manifest": "^7.0.0", "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0", @@ -74,7 +74,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.4.3", + "version": "3.5.0", "windowsCI": false } } diff --git a/deps/npm/node_modules/ssri/lib/index.js b/deps/npm/node_modules/ssri/lib/index.js index e2732fd072..1443137cbc 100644 --- a/deps/npm/node_modules/ssri/lib/index.js +++ b/deps/npm/node_modules/ssri/lib/index.js @@ -30,6 +30,10 @@ const getOptString = options => !options || !options.length const _onEnd = Symbol('_onEnd') const _getOptions = Symbol('_getOptions') +const _emittedSize = Symbol('_emittedSize') +const _emittedIntegrity = Symbol('_emittedIntegrity') +const _emittedVerified = Symbol('_emittedVerified') + class IntegrityStream extends MiniPass { constructor (opts) { super() @@ -63,6 +67,22 @@ class IntegrityStream extends MiniPass { this.optString = getOptString(options) } + on (ev, handler) { + if (ev === 'size' && this[_emittedSize]) { + return handler(this[_emittedSize]) + } + + if (ev === 'integrity' && this[_emittedIntegrity]) { + return handler(this[_emittedIntegrity]) + } + + if (ev === 'verified' && this[_emittedVerified]) { + return handler(this[_emittedVerified]) + } + + return super.on(ev, handler) + } + emit (ev, data) { if (ev === 'end') { this[_onEnd]() @@ -103,9 +123,14 @@ class IntegrityStream extends MiniPass { err.sri = this.sri this.emit('error', err) } else { + this[_emittedSize] = this.size this.emit('size', this.size) + this[_emittedIntegrity] = newSri this.emit('integrity', newSri) - match && this.emit('verified', match) + if (match) { + this[_emittedVerified] = match + this.emit('verified', match) + } } } } diff --git a/deps/npm/node_modules/ssri/package.json b/deps/npm/node_modules/ssri/package.json index 84448afc3c..91c1f91978 100644 --- a/deps/npm/node_modules/ssri/package.json +++ b/deps/npm/node_modules/ssri/package.json @@ -1,6 +1,6 @@ { "name": "ssri", - "version": "9.0.0", + "version": "9.0.1", "description": "Standard Subresource Integrity library -- parses, serializes, generates, and verifies integrity metadata according to the SRI spec.", "main": "lib/index.js", "files": [ @@ -50,7 +50,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.2.2", + "@npmcli/template-oss": "3.5.0", "tap": "^16.0.1" }, "engines": { @@ -58,6 +58,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.2.2" + "version": "3.5.0" } } diff --git a/deps/npm/package.json b/deps/npm/package.json index e654f94102..f616f038db 100644 --- a/deps/npm/package.json +++ b/deps/npm/package.json @@ -1,5 +1,5 @@ { - "version": "8.10.0", + "version": "8.11.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -65,7 +65,7 @@ "@npmcli/run-script": "^3.0.1", "abbrev": "~1.1.1", "archy": "~1.0.0", - "cacache": "^16.0.7", + "cacache": "^16.1.0", "chalk": "^4.1.2", "chownr": "^2.0.0", "cli-columns": "^4.0.0", @@ -90,7 +90,7 @@ "libnpmsearch": "^5.0.2", "libnpmteam": "^4.0.2", "libnpmversion": "^3.0.1", - "make-fetch-happen": "^10.1.3", + "make-fetch-happen": "^10.1.5", "minipass": "^3.1.6", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", @@ -107,7 +107,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "^6.0.2", "opener": "^1.5.2", - "pacote": "^13.3.0", + "pacote": "^13.4.1", "parse-conflict-json": "^2.0.2", "proc-log": "^2.0.1", "qrcode-terminal": "^0.12.0", @@ -117,7 +117,7 @@ "readdir-scoped-modules": "^1.1.0", "rimraf": "^3.0.2", "semver": "^7.3.7", - "ssri": "^9.0.0", + "ssri": "^9.0.1", "tar": "^6.1.11", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", diff --git a/deps/npm/tap-snapshots/test/lib/commands/cache.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/cache.js.test.cjs new file mode 100644 index 0000000000..1cd6994534 --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/commands/cache.js.test.cjs @@ -0,0 +1,63 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/lib/commands/cache.js TAP cache ls > logs cache entries 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/test-package +make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz +` + +exports[`test/lib/commands/cache.js TAP cache ls corrupted > logs cache entries with bad data 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted +make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz +` + +exports[`test/lib/commands/cache.js TAP cache ls missing packument version not an object > logs cache entry for packument 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version +` + +exports[`test/lib/commands/cache.js TAP cache ls nonpublic registry > logs cache entry for extemporaneously and its tarball 1`] = ` +make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/ +make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously +` + +exports[`test/lib/commands/cache.js TAP cache ls pkgs > logs cache entries for npm and webpack and one webpack tgz 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/npm +make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz +make-fetch-happen:request-cache:https://registry.npmjs.org/webpack +make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz +` + +exports[`test/lib/commands/cache.js TAP cache ls scoped and scoped slash > logs cache entries for @gar and @fritzy 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown +make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion +` + +exports[`test/lib/commands/cache.js TAP cache ls special > logs cache entries for foo 1`] = ` +make-fetch-happen:request-cache:https://registry.npmjs.org/foo +make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz +` + +exports[`test/lib/commands/cache.js TAP cache rm > logs deleting single entry 1`] = ` +Deleted: make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz +` + +exports[`test/lib/commands/cache.js TAP cache verify > shows verified cache output 1`] = ` +Cache verified and compressed ({PATH}) +Content verified: 0 (0 bytes) +Index entries: 0 +Finished in xxxs +` + +exports[`test/lib/commands/cache.js TAP cache verify w/ extra output > shows extra output 1`] = ` +Cache verified and compressed ({PATH}) +Content verified: 17057 (1644485260 bytes) +Corrupted content removed: 12345 +Content garbage-collected: 1144 (248164665 bytes) +Missing content: 92 +Index entries: 20175 +Finished in xxxs +` diff --git a/deps/npm/tap-snapshots/test/lib/commands/ci.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/ci.js.test.cjs deleted file mode 100644 index d6a7471778..0000000000 --- a/deps/npm/tap-snapshots/test/lib/commands/ci.js.test.cjs +++ /dev/null @@ -1,13 +0,0 @@ -/* IMPORTANT - * This snapshot file is auto-generated, but designed for humans. - * It should be checked into source control and tracked carefully. - * Re-generate by setting TAP_SNAPSHOT=1 and running tests. - * Make sure to inspect the output below. Do not ignore changes! - */ -'use strict' -exports[`test/lib/commands/ci.js TAP should throw error when ideal inventory mismatches virtual > must match snapshot 1`] = ` -\`npm ci\` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with \`npm install\` before continuing. - -Invalid: lock file's foo@1.0.0 does not satisfy foo@2.0.0 - -` diff --git a/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs index 20915cdd87..b8c274b085 100644 --- a/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -69,7 +69,7 @@ Run "npm help bin" for more info ` exports[`test/lib/load-all-commands.js TAP load each command birthday > must match snapshot 1`] = ` -Birthday +Birthday, deprecated Usage: npm birthday @@ -113,7 +113,7 @@ Run "npm help cache" for more info ` exports[`test/lib/load-all-commands.js TAP load each command ci > must match snapshot 1`] = ` -Install a project with a clean slate +Clean install a project Usage: npm ci @@ -802,7 +802,7 @@ Run "npm help set" for more info ` exports[`test/lib/load-all-commands.js TAP load each command set-script > must match snapshot 1`] = ` -Set tasks in the scripts section of package.json +Set tasks in the scripts section of package.json, deprecated Usage: npm set-script [<script>] [<command>] diff --git a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/deps/npm/tap-snapshots/test/lib/npm.js.test.cjs index 8d7dbfedc3..c7c75ce84b 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/npm.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/utils/npm-usage.js TAP usage basic usage > must match snapshot 1`] = ` +exports[`test/lib/npm.js TAP usage basic usage > must match snapshot 1`] = ` npm <command> Usage: @@ -41,7 +41,7 @@ Configuration fields: npm help 7 config npm@{VERSION} {BASEDIR} ` -exports[`test/lib/utils/npm-usage.js TAP usage set process.stdout.columns columns=0 > must match snapshot 1`] = ` +exports[`test/lib/npm.js TAP usage set process.stdout.columns columns=0 > must match snapshot 1`] = ` npm <command> Usage: @@ -77,7 +77,7 @@ Configuration fields: npm help 7 config npm@{VERSION} {BASEDIR} ` -exports[`test/lib/utils/npm-usage.js TAP usage set process.stdout.columns columns=90 > must match snapshot 1`] = ` +exports[`test/lib/npm.js TAP usage set process.stdout.columns columns=90 > must match snapshot 1`] = ` npm <command> Usage: @@ -113,7 +113,7 @@ Configuration fields: npm help 7 config npm@{VERSION} {BASEDIR} ` -exports[`test/lib/utils/npm-usage.js TAP usage with browser > must match snapshot 1`] = ` +exports[`test/lib/npm.js TAP usage with browser > must match snapshot 1`] = ` npm <command> Usage: @@ -149,7 +149,7 @@ Configuration fields: npm help 7 config npm@{VERSION} {BASEDIR} ` -exports[`test/lib/utils/npm-usage.js TAP usage with long > must match snapshot 1`] = ` +exports[`test/lib/npm.js TAP usage with long > must match snapshot 1`] = ` npm <command> Usage: @@ -166,7 +166,7 @@ npm help npm more involved overview All commands: access Set access level on published packages - + Usage: npm access public [<package>] npm access restricted [<package>] @@ -177,29 +177,29 @@ All commands: npm access ls-packages [<user>|<scope>|<scope:team>] npm access ls-collaborators [<package> [<user>]] npm access edit [<package>] - + Options: [--registry <registry>] [--otp <otp>] - + Run "npm help access" for more info adduser Add a registry user account - + Usage: npm adduser - + Options: [--registry <registry>] [--scope <@scope>] - + aliases: login, add-user - + Run "npm help adduser" for more info audit Run a security audit - + Usage: npm audit [fix] - + Options: [--audit-level <info|low|moderate|high|critical|none>] [--dry-run] [-f|--force] [--json] [--package-lock-only] @@ -207,35 +207,35 @@ All commands: [--foreground-scripts] [--ignore-scripts] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + Run "npm help audit" for more info bin Display npm bin folder - + Usage: npm bin - + Options: [-g|--global] - + Run "npm help bin" for more info bugs Report bugs for a package in a web browser - + Usage: npm bugs [<pkgname> [<pkgname> ...]] - + Options: [--no-browser|--browser <browser>] [--registry <registry>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + alias: issues - + Run "npm help bugs" for more info cache Manipulates packages cache - + Usage: npm cache add <tarball file> npm cache add <folder> @@ -245,80 +245,80 @@ All commands: npm cache clean [<key>] npm cache ls [<name>@<version>] npm cache verify - + Options: [--cache <cache>] - + Run "npm help cache" for more info - ci Install a project with a clean slate - + ci Clean install a project + Usage: npm ci - + Options: [--no-audit] [--foreground-scripts] [--ignore-scripts] [--script-shell <script-shell>] - + aliases: clean-install, ic, install-clean, isntall-clean - + Run "npm help ci" for more info completion Tab Completion for npm - + Usage: npm completion - + Run "npm help completion" for more info config Manage the npm configuration files - + Usage: npm config set <key>=<value> [<key>=<value> ...] npm config get [<key> [<key> ...]] npm config delete <key> [<key> ...] npm config list [--json] npm config edit - + Options: [--json] [-g|--global] [--editor <editor>] [-L|--location <global|user|project>] [-l|--long] - + alias: c - + Run "npm help config" for more info dedupe Reduce duplication in the package tree - + Usage: npm dedupe - + Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: ddp - + Run "npm help dedupe" for more info deprecate Deprecate a version of a package - + Usage: npm deprecate <pkg>[@<version>] <message> - + Options: [--registry <registry>] [--otp <otp>] - + Run "npm help deprecate" for more info diff The registry diff command - + Usage: npm diff [...<paths>] - + Options: [--diff <pkg-name|spec|version> [--diff <pkg-name|spec|version> ...]] [--diff-name-only] [--diff-unified <number>] [--diff-ignore-all-space] @@ -326,174 +326,174 @@ All commands: [--diff-text] [-g|--global] [--tag <tag>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + Run "npm help diff" for more info dist-tag Modify package distribution tags - + Usage: npm dist-tag add <pkg>@<version> [<tag>] npm dist-tag rm <pkg> <tag> npm dist-tag ls [<pkg>] - + Options: [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + alias: dist-tags - + Run "npm help dist-tag" for more info docs Open documentation for a package in a web browser - + Usage: npm docs [<pkgname> [<pkgname> ...]] - + Options: [--no-browser|--browser <browser>] [--registry <registry>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + alias: home - + Run "npm help docs" for more info doctor Check your npm environment - + Usage: npm doctor - + Options: [--registry <registry>] - + Run "npm help doctor" for more info edit Edit an installed package - + Usage: npm edit <pkg>[/<subpkg>...] - + Options: [--editor <editor>] - + Run "npm help edit" for more info exec Run a command from a local or remote npm package - + Usage: npm exec -- <pkg>[@<version>] [args...] npm exec --package=<pkg>[@<version>] -- <cmd> [args...] npm exec -c '<cmd> [args...]' npm exec --package=foo -c '<cmd> [args...]' - + Options: [--package <pkg>[@<version>] [--package <pkg>[@<version>] ...]] [-c|--call <call>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + alias: x - + Run "npm help exec" for more info explain Explain installed packages - + Usage: npm explain <folder | specifier> - + Options: [--json] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] - + alias: why - + Run "npm help explain" for more info explore Browse an installed package - + Usage: npm explore <pkg> [ -- <command>] - + Options: [--shell <shell>] - + Run "npm help explore" for more info find-dupes Find duplication in the package tree - + Usage: npm find-dupes - + Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + Run "npm help find-dupes" for more info fund Retrieve funding information - + Usage: npm fund [[<@scope>/]<pkg>] - + Options: [--json] [--no-browser|--browser <browser>] [--unicode] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [--which <fundingSourceNumber>] - + Run "npm help fund" for more info get Get a value from the npm configuration - + Usage: npm get [<key> ...] (See \`npm config\`) - + Run "npm help get" for more info help Get help on npm - + Usage: npm help <term> [<terms..>] - + Options: [--viewer <viewer>] - + alias: hlep - + Run "npm help help" for more info hook Manage registry hooks - + Usage: npm hook add <pkg> <url> <secret> [--type=<type>] npm hook ls [pkg] npm hook rm <id> npm hook update <id> <url> <secret> - + Options: [--registry <registry>] [--otp <otp>] - + Run "npm help hook" for more info init Create a package.json file - + Usage: npm init [--force|-f|--yes|-y|--scope] npm init <@scope> (same as \`npx <@scope>/create\`) npm init [<@scope>/]<name> (same as \`npx [<@scope>/]create-<name>\`) - + Options: [-y|--yes] [-f|--force] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + aliases: create, innit - + Run "npm help init" for more info install Install a package - + Usage: npm install [<@scope>/]<pkg> npm install [<@scope>/]<pkg>@<tag> @@ -505,7 +505,7 @@ All commands: npm install <tarball url> npm install <git:// url> npm install <github username>/<github project> - + Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] @@ -514,26 +514,26 @@ All commands: [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall - + Run "npm help install" for more info install-ci-test Install a project with a clean slate and run tests - + Usage: npm install-ci-test - + Options: [--no-audit] [--foreground-scripts] [--ignore-scripts] [--script-shell <script-shell>] - + alias: cit - + Run "npm help install-ci-test" for more info install-test Install package(s) and run tests - + Usage: npm install-test [<@scope>/]<pkg> npm install-test [<@scope>/]<pkg>@<tag> @@ -545,7 +545,7 @@ All commands: npm install-test <tarball url> npm install-test <git:// url> npm install-test <github username>/<github project> - + Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] @@ -554,17 +554,17 @@ All commands: [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: it - + Run "npm help install-test" for more info link Symlink a package folder - + Usage: npm link (in package dir) npm link [<@scope>/]<pkg>[@<version>] - + Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] @@ -573,126 +573,126 @@ All commands: [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: ln - + Run "npm help link" for more info ll List installed packages - + Usage: npm ll [[<@scope>/]<pkg> ...] - + Options: [-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global] [--depth <depth>] [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]] [--link] [--package-lock-only] [--unicode] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: la - + Run "npm help ll" for more info login Add a registry user account - + Usage: npm adduser - + Options: [--registry <registry>] [--scope <@scope>] - + aliases: login, add-user - + Run "npm help adduser" for more info logout Log out of the registry - + Usage: npm logout - + Options: [--registry <registry>] [--scope <@scope>] - + Run "npm help logout" for more info ls List installed packages - + Usage: npm ls [[<@scope>/]<pkg> ...] - + Options: [-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global] [--depth <depth>] [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]] [--link] [--package-lock-only] [--unicode] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: list - + Run "npm help ls" for more info org Manage orgs - + Usage: npm org set orgname username [developer | admin | owner] npm org rm orgname username npm org ls orgname [<username>] - + Options: [--registry <registry>] [--otp <otp>] [--json] [-p|--parseable] - + alias: ogr - + Run "npm help org" for more info outdated Check for outdated packages - + Usage: npm outdated [[<@scope>/]<pkg> ...] - + Options: [-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] - + Run "npm help outdated" for more info owner Manage package owners - + Usage: npm owner add <user> [<@scope>/]<pkg> npm owner rm <user> [<@scope>/]<pkg> npm owner ls [<@scope>/]<pkg> - + Options: [--registry <registry>] [--otp <otp>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] - + alias: author - + Run "npm help owner" for more info pack Create a tarball from a package - + Usage: npm pack [[<@scope>/]<pkg>...] - + Options: [--dry-run] [--json] [--pack-destination <pack-destination>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + Run "npm help pack" for more info ping Ping npm registry - + Usage: npm ping - + Options: [--registry <registry>] - + Run "npm help ping" for more info pkg Manages your package.json @@ -712,272 +712,272 @@ All commands: Run "npm help pkg" for more info prefix Display prefix - + Usage: npm prefix [-g] - + Options: [-g|--global] - + Run "npm help prefix" for more info profile Change settings on your registry profile - + Usage: npm profile enable-2fa [auth-only|auth-and-writes] npm profile disable-2fa npm profile get [<key>] npm profile set <key> <value> - + Options: [--registry <registry>] [--json] [-p|--parseable] [--otp <otp>] - + Run "npm help profile" for more info prune Remove extraneous packages - + Usage: npm prune [[<@scope>/]<pkg>...] - + Options: [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]] [--dry-run] [--json] [--foreground-scripts] [--ignore-scripts] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + Run "npm help prune" for more info publish Publish a package - + Usage: npm publish [<folder>] - + Options: [--tag <tag>] [--access <restricted|public>] [--dry-run] [--otp <otp>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + Run "npm help publish" for more info rebuild Rebuild a package - + Usage: npm rebuild [[<@scope>/]<name>[@<version>] ...] - + Options: [-g|--global] [--no-bin-links] [--foreground-scripts] [--ignore-scripts] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + alias: rb - + Run "npm help rebuild" for more info repo Open package repository page in the browser - + Usage: npm repo [<pkgname> [<pkgname> ...]] - + Options: [--no-browser|--browser <browser>] [--registry <registry>] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + Run "npm help repo" for more info restart Restart a package - + Usage: npm restart [-- <args>] - + Options: [--ignore-scripts] [--script-shell <script-shell>] - + Run "npm help restart" for more info root Display npm root - + Usage: npm root - + Options: [-g|--global] - + Run "npm help root" for more info run-script Run arbitrary package scripts - + Usage: npm run-script <command> [-- <args>] - + Options: [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--if-present] [--ignore-scripts] [--script-shell <script-shell>] - + aliases: run, rum, urn - + Run "npm help run-script" for more info search Search for packages - + Usage: npm search [search terms ...] - + Options: [-l|--long] [--json] [--color|--no-color|--color always] [-p|--parseable] [--no-description] [--searchopts <searchopts>] [--searchexclude <searchexclude>] [--registry <registry>] [--prefer-online] [--prefer-offline] [--offline] - + aliases: find, s, se - + Run "npm help search" for more info set Set a value in the npm configuration - + Usage: npm set <key>=<value> [<key>=<value> ...] (See \`npm config\`) - + Run "npm help set" for more info - set-script Set tasks in the scripts section of package.json - + set-script Set tasks in the scripts section of package.json, deprecated + Usage: npm set-script [<script>] [<command>] - + Options: [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + Run "npm help set-script" for more info shrinkwrap Lock down dependency versions for publication - + Usage: npm shrinkwrap - + Run "npm help shrinkwrap" for more info star Mark your favorite packages - + Usage: npm star [<pkg>...] - + Options: [--registry <registry>] [--unicode] [--otp <otp>] - + Run "npm help star" for more info stars View packages marked as favorites - + Usage: npm stars [<user>] - + Options: [--registry <registry>] - + Run "npm help stars" for more info start Start a package - + Usage: npm start [-- <args>] - + Options: [--ignore-scripts] [--script-shell <script-shell>] - + Run "npm help start" for more info stop Stop a package - + Usage: npm stop [-- <args>] - + Options: [--ignore-scripts] [--script-shell <script-shell>] - + Run "npm help stop" for more info team Manage organization teams and team memberships - + Usage: npm team create <scope:team> [--otp <otpcode>] npm team destroy <scope:team> [--otp <otpcode>] npm team add <scope:team> <user> [--otp <otpcode>] npm team rm <scope:team> <user> [--otp <otpcode>] npm team ls <scope>|<scope:team> - + Options: [--registry <registry>] [--otp <otp>] [-p|--parseable] [--json] - + Run "npm help team" for more info test Test a package - + Usage: npm test [-- <args>] - + Options: [--ignore-scripts] [--script-shell <script-shell>] - + aliases: tst, t - + Run "npm help test" for more info token Manage your authentication tokens - + Usage: npm token list npm token revoke <id|token> npm token create [--read-only] [--cidr=list] - + Options: [--read-only] [--cidr <cidr> [--cidr <cidr> ...]] [--registry <registry>] [--otp <otp>] - + Run "npm help token" for more info uninstall Remove a package - + Usage: npm uninstall [<@scope>/]<pkg>... - + Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + aliases: unlink, remove, rm, r, un - + Run "npm help uninstall" for more info unpublish Remove a package from the registry - + Usage: npm unpublish [<@scope>/]<pkg>[@<version>] - + Options: [--dry-run] [-f|--force] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] - + Run "npm help unpublish" for more info unstar Remove an item from your favorite packages - + Usage: npm unstar [<pkg>...] - + Options: [--registry <registry>] [--unicode] [--otp <otp>] - + Run "npm help unstar" for more info update Update packages - + Usage: npm update [<pkg>...] - + Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-g|--global] [--global-style] [--legacy-bundling] @@ -986,47 +986,47 @@ All commands: [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] - + aliases: up, upgrade, udpate - + Run "npm help update" for more info version Bump a package version - + Usage: npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git] - + Options: [--allow-same-version] [--no-commit-hooks] [--no-git-tag-version] [--json] [--preid prerelease-id] [--sign-git-tag] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--no-workspaces-update] [--include-workspace-root] - + alias: verison - + Run "npm help version" for more info view View registry info - + Usage: npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...] - + Options: [--json] [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]] [-ws|--workspaces] [--include-workspace-root] - + aliases: info, show, v - + Run "npm help view" for more info whoami Display npm username - + Usage: npm whoami - + Options: [--registry <registry>] - + Run "npm help whoami" for more info Specify configs in the ini-formatted file: diff --git a/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index c31a6b7dc7..b12dccdb76 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -731,6 +731,8 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for globa * Default: false * Type: Boolean +* DEPRECATED: \`--global\`, \`--local\` are deprecated. Use \`--location=global\` + instead. Operates in "global" mode, so that packages are installed into the \`prefix\` folder instead of the current working directory. See @@ -1077,6 +1079,15 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for locat * Type: "global", "user", or "project" When passed to \`npm config\` this refers to which config file to use. + +When set to "global" mode, packages are installed into the \`prefix\` folder +instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the \`{prefix}/lib/node_modules\` folder, instead + of the current working directory. +* bin files are linked to \`{prefix}/bin\` +* man pages are linked to \`{prefix}/share/man\` ` exports[`test/lib/utils/config/definitions.js TAP > config description for lockfile-version 1`] = ` diff --git a/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 0ec2ca17a4..cacbe96a74 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -560,23 +560,6 @@ results in no commit being made at all. <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> -#### \`global\` - -* Default: false -* Type: Boolean - -Operates in "global" mode, so that packages are installed into the \`prefix\` -folder instead of the current working directory. See -[folders](/configuring-npm/folders) for more on the differences in behavior. - -* packages are installed into the \`{prefix}/lib/node_modules\` folder, instead - of the current working directory. -* bin files are linked to \`{prefix}/bin\` -* man pages are linked to \`{prefix}/share/man\` - -<!-- automatically generated, do not edit manually --> -<!-- see lib/utils/config/definitions.js --> - #### \`global-style\` * Default: false @@ -874,6 +857,15 @@ npm registry. Must be IPv4 in versions of Node prior to 0.12. When passed to \`npm config\` this refers to which config file to use. +When set to "global" mode, packages are installed into the \`prefix\` folder +instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the \`{prefix}/lib/node_modules\` folder, instead + of the current working directory. +* bin files are linked to \`{prefix}/bin\` +* man pages are linked to \`{prefix}/share/man\` + <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> @@ -1814,6 +1806,25 @@ Alias for \`--include=dev\`. <!-- automatically generated, do not edit manually --> <!-- see lib/utils/config/definitions.js --> +#### \`global\` + +* Default: false +* Type: Boolean +* DEPRECATED: \`--global\`, \`--local\` are deprecated. Use \`--location=global\` + instead. + +Operates in "global" mode, so that packages are installed into the \`prefix\` +folder instead of the current working directory. See +[folders](/configuring-npm/folders) for more on the differences in behavior. + +* packages are installed into the \`{prefix}/lib/node_modules\` folder, instead + of the current working directory. +* bin files are linked to \`{prefix}/bin\` +* man pages are linked to \`{prefix}/share/man\` + +<!-- automatically generated, do not edit manually --> +<!-- see lib/utils/config/definitions.js --> + #### \`init.author.email\` * Default: "" diff --git a/deps/npm/test/fixtures/mock-npm.js b/deps/npm/test/fixtures/mock-npm.js index c9701ebc23..a79812fb71 100644 --- a/deps/npm/test/fixtures/mock-npm.js +++ b/deps/npm/test/fixtures/mock-npm.js @@ -224,6 +224,10 @@ class MockNpm { } } + get global () { + return this.config.get('global') || this.config.get('location') === 'global' + } + output (...msg) { if (this.base.output) { return this.base.output(msg) diff --git a/deps/npm/test/fixtures/mock-registry.js b/deps/npm/test/fixtures/mock-registry.js index a62890b72e..8fb5a055ff 100644 --- a/deps/npm/test/fixtures/mock-registry.js +++ b/deps/npm/test/fixtures/mock-registry.js @@ -192,6 +192,10 @@ class MockRegistry { }).reply(200, { ...manifest, users }) } + ping ({ body = {}, responseCode = 200 } = {}) { + this.nock = this.nock.get('/-/ping?write=true').reply(responseCode, body) + } + async package ({ manifest, times = 1, query, tarballs }) { let nock = this.nock const spec = npa(manifest.name) @@ -202,16 +206,21 @@ class MockRegistry { nock = nock.reply(200, manifest) if (tarballs) { for (const version in tarballs) { - // for (const version in manifest.versions) { - const packument = manifest.versions[version] - const dist = new URL(packument.dist.tarball) - const tarball = await pacote.tarball(tarballs[version]) - nock.get(dist.pathname).reply(200, tarball) + const m = manifest.versions[version] + nock = await this.tarball({ manifest: m, tarball: tarballs[version] }) } } this.nock = nock } + async tarball ({ manifest, tarball }) { + const nock = this.nock + const dist = new URL(manifest.dist.tarball) + const tar = await pacote.tarball(tarball) + nock.get(dist.pathname).reply(200, tar) + return nock + } + // either pass in packuments if you need to set specific attributes besides version, // or an array of versions // the last packument in the packuments or versions array will be tagged latest diff --git a/deps/npm/test/lib/commands/cache.js b/deps/npm/test/lib/commands/cache.js index 6023127691..72a7ce96aa 100644 --- a/deps/npm/test/lib/commands/cache.js +++ b/deps/npm/test/lib/commands/cache.js @@ -1,442 +1,309 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm.js') -const path = require('path') -const npa = require('npm-package-arg') - -let outputOutput = [] - -let rimrafPath = '' -const rimraf = (path, cb) => { - rimrafPath = path - return cb() -} - -let logOutput = [] - -let tarballStreamSpec = '' -let tarballStreamOpts = {} -const pacote = { - tarball: { - stream: (spec, handler, opts) => { - tarballStreamSpec = spec - tarballStreamOpts = opts - return handler({ - resume: () => {}, - promise: () => Promise.resolve(), - }) - }, - }, -} - -let cacacheEntries = {} -let cacacheContent = {} - -const setupCacacheFixture = () => { - cacacheEntries = {} - cacacheContent = {} - const pkgs = [ - ['webpack@4.44.1', 'https://registry.npmjs.org', true], - ['npm@1.2.0', 'https://registry.npmjs.org', true], - ['webpack@4.47.0', 'https://registry.npmjs.org', true], - ['foo@1.2.3-beta', 'https://registry.npmjs.org', true], - ['ape-ecs@2.1.7', 'https://registry.npmjs.org', true], - ['@fritzy/staydown@3.1.1', 'https://registry.npmjs.org', true], - ['@gar/npm-expansion@2.1.0', 'https://registry.npmjs.org', true], - ['@gar/npm-expansion@3.0.0-beta', 'https://registry.npmjs.org', true], - ['extemporaneously@44.2.2', 'https://somerepo.github.org', false], - ['corrupted@3.1.0', 'https://registry.npmjs.org', true], - ['missing-dist@23.0.0', 'https://registry.npmjs.org', true], - ['missing-version@16.2.0', 'https://registry.npmjs.org', true], - ] - pkgs.forEach(pkg => addCacachePkg(...pkg)) - // corrupt the packument - cacacheContent[ - /* eslint-disable-next-line max-len */ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted'].integrity] - ].data = Buffer.from('<>>>}"') - // nuke the version dist - cacacheContent[ - /* eslint-disable-next-line max-len */ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist'].integrity] - ].data = Buffer.from(JSON.stringify({ versions: { '23.0.0': {} } })) - // make the version a non-object - cacacheContent[ - /* eslint-disable-next-line max-len */ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version'].integrity] - ].data = Buffer.from(JSON.stringify({ versions: 'hello' })) -} - -const packuments = {} +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') +const MockRegistry = require('../../fixtures/mock-registry.js') +const mockGlobals = require('../../fixtures/mock-globals') -let contentId = 0 -const cacacheVerifyStats = { - keptSize: 100, - verifiedContent: 1, - totalEntries: 1, - runTime: { total: 2000 }, -} +const cacache = require('cacache') +const fs = require('@npmcli/fs') +const path = require('path') -const addCacacheKey = (key, content) => { - contentId++ - cacacheEntries[key] = { integrity: `${contentId}` } - cacacheContent[`${contentId}`] = {} -} -const addCacachePkg = (spec, registry, publicURL) => { - const parts = npa(spec) - const ver = parts.rawSpec || '1.0.0' - let url = `${registry}/${parts.name}/-/${parts.name}-${ver}.tgz` - if (!publicURL) { - url = `${registry}/aabbcc/${contentId}` - } - const key = `make-fetch-happen:request-cache:${url}` - const pkey = `make-fetch-happen:request-cache:${registry}/${parts.escapedName}` - if (!packuments[parts.escapedName]) { - packuments[parts.escapedName] = { - versions: {}, - } - addCacacheKey(pkey) - } - packuments[parts.escapedName].versions[ver] = { - dist: { - tarball: url, - }, - } - addCacacheKey(key) - cacacheContent[cacacheEntries[pkey].integrity] = { - data: Buffer.from(JSON.stringify(packuments[parts.escapedName])), - } -} +const pkg = 'test-package' -const cacache = { - verify: (path) => { - return cacacheVerifyStats - }, - get: (path, key) => { - if (cacacheEntries[key] === undefined - || cacacheContent[cacacheEntries[key].integrity] === undefined) { - throw new Error() - } - return cacacheContent[cacacheEntries[key].integrity] - }, - rm: { - entry: (path, key) => { - if (cacacheEntries[key] === undefined) { - throw new Error() - } - delete cacacheEntries[key] - }, - content: (path, sha) => { - delete cacacheContent[sha] - }, - }, - ls: (path) => { - return cacacheEntries - }, +t.cleanSnapshot = str => { + return str + .replace(/Finished in [0-9.s]+/g, 'Finished in xxxs') + .replace(/Cache verified and compressed (.*)/, 'Cache verified and compressed ({PATH})') } -const Cache = t.mock('../../../lib/commands/cache.js', { - cacache, - pacote, - rimraf, - 'proc-log': { - silly: (...args) => { - logOutput.push(['silly', ...args]) - }, - warn: (...args) => { - logOutput.push(['warn', ...args]) - }, - }, -}) - -const npm = mockNpm({ - cache: '/fake/path', - flatOptions: { force: false }, - config: { force: false }, - output: (msg) => { - outputOutput.push(msg) - }, -}) -const cache = new Cache(npm) - t.test('cache no args', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( - cache.exec([]), + npm.exec('cache', []), { code: 'EUSAGE' }, 'should throw usage instructions' ) }) t.test('cache clean', async t => { + const { npm } = await loadMockNpm(t) await t.rejects( - cache.exec(['clean']), - 'the npm cache self-heals', + npm.exec('cache', ['clean']), + /the npm cache self-heals/, 'should throw warning' ) }) t.test('cache clean (force)', async t => { - npm.config.set('force', true) - npm.flatOptions.force = true - t.teardown(() => { - rimrafPath = '' - npm.config.force = false - npm.flatOptions.force = false + const { npm } = await loadMockNpm(t, { + cacheDir: { _cacache: {} }, + config: { force: true }, }) - - await cache.exec(['clear']) - t.equal(rimrafPath, path.join(npm.cache, '_cacache')) + const cache = path.join(npm.cache, '_cacache') + await npm.exec('cache', ['clean']) + t.notOk(fs.existsSync(cache), 'cache dir was removed') }) t.test('cache add no arg', async t => { - t.teardown(() => { - logOutput = [] - }) - + const { npm } = await loadMockNpm(t) await t.rejects( - cache.exec(['add']), + npm.exec('cache', ['add']), { code: 'EUSAGE', message: 'First argument to `add` is required', }, 'throws usage error' ) - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', []], - ], 'logs correctly') }) -t.test('cache add pkg only', async t => { - t.teardown(() => { - logOutput = [] - tarballStreamSpec = '' - tarballStreamOpts = {} +t.test('cache add single pkg', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: { + package: { + 'package.json': JSON.stringify({ + name: pkg, + version: '1.0.0', + }), + }, + }, }) - - await cache.exec(['add', 'mypkg']) - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', ['mypkg']], - ['silly', 'cache add', 'spec', 'mypkg'], - ], 'logs correctly') - t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote') - t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') + const cache = path.join(npm.cache, '_cacache') + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + const manifest = registry.manifest({ name: pkg }) + await registry.package({ manifest, tarballs: { '1.0.0': path.join(npm.prefix, 'package') } }) + await npm.exec('cache', ['add', pkg]) + t.equal(joinedOutput(), '') + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz')) + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package')) }) t.test('cache add multiple pkgs', async t => { - t.teardown(() => { - outputOutput = [] - tarballStreamSpec = '' - tarballStreamOpts = {} + const pkg2 = 'test-package-two' + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: { + package: { + 'package.json': JSON.stringify({ + name: pkg, + version: '1.0.0', + }), + }, + }, }) - - await cache.exec(['add', 'mypkg', 'anotherpkg']) - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', ['mypkg', 'anotherpkg']], - ['silly', 'cache add', 'spec', 'mypkg'], - ['silly', 'cache add', 'spec', 'anotherpkg'], - ], 'logs correctly') - t.equal(tarballStreamSpec, 'anotherpkg', 'passes the correct spec to pacote') - t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') + const cache = path.join(npm.cache, '_cacache') + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + const manifest = registry.manifest({ name: pkg }) + const manifest2 = registry.manifest({ name: pkg2 }) + await registry.package({ manifest, tarballs: { '1.0.0': path.join(npm.prefix, 'package') } }) + await registry.package({ + manifest: manifest2, tarballs: { '1.0.0': path.join(npm.prefix, 'package') }, + }) + await npm.exec('cache', ['add', pkg, pkg2]) + t.equal(joinedOutput(), '') + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz')) + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package')) + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package-two/-/test-package-two-1.0.0.tgz')) + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package-two')) }) t.test('cache ls', async t => { - t.teardown(() => { - outputOutput = [] - logOutput = [] - }) - setupCacacheFixture() - await cache.exec(['ls']) - t.strictSame(outputOutput, [ - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-3.0.0-beta.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs/-/ape-ecs-2.1.7.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', - 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', - 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', - ]) + const keys = [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package', + // eslint-disable-next-line max-len + 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz', + ] + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + for (const key of keys) { + await cacache.put(cache, key, 'test data') + } + await npm.exec('cache', ['ls']) + t.matchSnapshot(joinedOutput(), 'logs cache entries') }) t.test('cache ls pkgs', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'webpack@>4.44.1', 'npm']) - t.strictSame(outputOutput, [ + const keys = [ 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', - ]) + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.40.0.tgz', + ] + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + for (const key of keys) { + await cacache.put(cache, key, 'test data') + } + await cacache.put(cache, + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', + JSON.stringify({ versions: { + '4.40.0': { dist: { tarball: 'https://registry.npmjs.org/webpack/-/webpack-4.40.0.tgz' } }, + '4.47.0': { dist: { tarball: 'https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz' } }, + } }) + ) + await npm.exec('cache', ['ls', 'webpack@>4.44.1', 'npm']) + t.matchSnapshot(joinedOutput(), 'logs cache entries for npm and webpack and one webpack tgz') }) t.test('cache ls special', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'foo@1.2.3-beta']) - t.strictSame(outputOutput, [ + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + await cacache.put(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', + JSON.stringify({ versions: { '1.2.3-beta': {} } }) + ) + await cacache.put(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', - ]) + 'test-data' + ) + await npm.exec('cache', ['ls', 'foo@1.2.3-beta']) + t.matchSnapshot(joinedOutput(), 'logs cache entries for foo') }) t.test('cache ls nonpublic registry', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'extemporaneously']) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + await cacache.put(cache, 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', - ]) + JSON.stringify({ + versions: { '1.0.0': { dist: { tarball: 'https://somerepo.github.org/aabbcc/' } } }, + }) + ) + await cacache.put(cache, + 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/', + 'test data' + ) + await npm.exec('cache', ['ls', 'extemporaneously']) + t.matchSnapshot(joinedOutput(), 'logs cache entry for extemporaneously and its tarball') }) t.test('cache ls tagged', async t => { - t.teardown(() => { - outputOutput = [] - }) + const { npm } = await loadMockNpm(t) await t.rejects( - cache.exec(['ls', 'webpack@latest']), - 'tagged package', - 'should throw warning' + npm.exec('cache', ['ls', 'webpack@latest']), + { code: 'EUSAGE' }, + 'should throw usage error' ) }) t.test('cache ls scoped and scoped slash', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', '@fritzy/staydown', '@gar/npm-expansion']) - t.strictSame(outputOutput, [ - /* eslint-disable-next-line max-len */ + const keys = [ + // eslint-disable-next-line max-len 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', - /* eslint-disable-next-line max-len */ + // eslint-disable-next-line max-len 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', - ]) + ] + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + for (const key of keys) { + await cacache.put(cache, key, 'test data') + } + await npm.exec('cache', ['ls', '@fritzy/staydown', '@gar/npm-expansion']) + t.matchSnapshot(joinedOutput(), 'logs cache entries for @gar and @fritzy') }) t.test('cache ls corrupted', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'corrupted']) - t.strictSame(outputOutput, [ + const keys = [ 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', - ]) -}) - -t.test('cache ls missing packument dist', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'missing-dist']) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', - ]) + ] + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + for (const key of keys) { + await cacache.put(cache, key, Buffer.from('<>>>}"')) + } + await npm.exec('cache', ['ls', 'corrupted']) + t.matchSnapshot(joinedOutput(), 'logs cache entries with bad data') }) t.test('cache ls missing packument version not an object', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['ls', 'missing-version']) - t.strictSame(outputOutput, [ + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + await cacache.put(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', - /* eslint-disable-next-line max-len */ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', - ]) + JSON.stringify({ versions: 'not an object' }) + ) + await npm.exec('cache', ['ls', 'missing-version']) + t.matchSnapshot(joinedOutput(), 'logs cache entry for packument') }) t.test('cache rm', async t => { - t.teardown(() => { - outputOutput = [] - }) - await cache.exec(['rm', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz']) - t.strictSame(outputOutput, [ - /* eslint-disable-next-line max-len */ - 'Deleted: make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', - ]) + const { npm, joinedOutput } = await loadMockNpm(t) + const cache = path.join(npm.cache, '_cacache') + // eslint-disable-next-line max-len + await cacache.put(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package', '{}') + // eslint-disable-next-line max-len + await cacache.put(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz', 'test data') + // eslint-disable-next-line max-len + await npm.exec('cache', ['rm', 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz']) + t.matchSnapshot(joinedOutput(), 'logs deleting single entry') + // eslint-disable-next-line max-len + t.resolves(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package')) + // eslint-disable-next-line max-len + t.rejects(cacache.get(cache, 'make-fetch-happen:request-cache:https://registry.npmjs.org/test-package/-/test-package-1.0.0.tgz')) }) t.test('cache rm unfound', async t => { - t.teardown(() => { - outputOutput = [] - logOutput = [] - }) - await cache.exec(['rm', 'made-up-key']) - t.strictSame(logOutput, [ - ['warn', 'Not Found: made-up-key'], - ], 'logs correctly') + const { npm, joinedOutput } = await loadMockNpm(t) + await npm.exec('cache', ['rm', 'made-up-key']) + t.same(joinedOutput(), '', 'no errors, no output') }) t.test('cache verify', async t => { - t.teardown(() => { - outputOutput = [] - }) + const { npm, joinedOutput } = await loadMockNpm(t) + await npm.exec('cache', ['verify']) + t.matchSnapshot(joinedOutput(), 'shows verified cache output') +}) - await cache.exec(['verify']) - t.match(outputOutput, [ - `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`, - 'Content verified: 1 (100 bytes)', - 'Index entries: 1', - 'Finished in 2s', - ], 'prints correct output') +t.test('cache verify as part of home', async t => { + const { npm, joinedOutput, prefix } = await loadMockNpm(t) + mockGlobals(t, { 'process.env.HOME': path.dirname(prefix) }) + await npm.exec('cache', ['verify']) + t.match(joinedOutput(), 'Cache verified and compressed (~', 'contains ~ shorthand') }) t.test('cache verify w/ extra output', async t => { - npm.cache = `${process.env.HOME}/fake/path` - cacacheVerifyStats.badContentCount = 1 - cacacheVerifyStats.reclaimedCount = 2 - cacacheVerifyStats.reclaimedSize = 200 - cacacheVerifyStats.missingContent = 3 - t.teardown(() => { - npm.cache = '/fake/path' - outputOutput = [] - delete cacacheVerifyStats.badContentCount - delete cacacheVerifyStats.reclaimedCount - delete cacacheVerifyStats.reclaimedSize - delete cacacheVerifyStats.missingContent + const verify = { + runTime: { + markStartTime: 0, + fixPerms: 3, + garbageCollect: 54982, + rebuildIndex: 62779, + cleanTmp: 62781, + writeVerifile: 62783, + markEndTime: 62783, + total: 62783, + }, + verifiedContent: 17057, + reclaimedCount: 1144, + reclaimedSize: 248164665, + badContentCount: 12345, + keptSize: 1644485260, + missingContent: 92, + rejectedEntries: 92, + totalEntries: 20175, + } + const { npm, joinedOutput } = await loadMockNpm(t, { + mocks: { cacache: { verify: () => verify } }, }) - - await cache.exec(['check']) - t.match(outputOutput, [ - `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`, - 'Content verified: 1 (100 bytes)', - 'Corrupted content removed: 1', - 'Content garbage-collected: 2 (200 bytes)', - 'Missing content: 3', - 'Index entries: 1', - 'Finished in 2s', - ], 'prints correct output') + await npm.exec('cache', ['verify']) + t.matchSnapshot(joinedOutput(), 'shows extra output') }) t.test('cache completion', async t => { + const { npm } = await loadMockNpm(t) + const cache = await npm.cmd('cache') const { completion } = cache const testComp = (argv, expect) => { diff --git a/deps/npm/test/lib/commands/ci.js b/deps/npm/test/lib/commands/ci.js index 978cd03b87..179cee6c9b 100644 --- a/deps/npm/test/lib/commands/ci.js +++ b/deps/npm/test/lib/commands/ci.js @@ -1,316 +1,201 @@ -const fs = require('fs') -const util = require('util') -const readdir = util.promisify(fs.readdir) - const t = require('tap') - -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -t.test('should ignore scripts with --ignore-scripts', async t => { - const SCRIPTS = [] - let REIFY_CALLED = false - const CI = t.mock('../../../lib/commands/ci.js', { - '../../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/run-script': ({ event }) => { - SCRIPTS.push(event) - }, - '@npmcli/arborist': function () { - this.loadVirtual = async () => {} - this.reify = () => { - REIFY_CALLED = true - } - this.buildIdealTree = () => {} - this.virtualTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - this.idealTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } +const { load: _loadMockNpm } = require('../../fixtures/mock-npm') +const MockRegistry = require('../../fixtures/mock-registry.js') + +const path = require('path') +const fs = require('@npmcli/fs') + +// t.cleanSnapshot = str => str.replace(/ in [0-9ms]+/g, ' in {TIME}') + +const loadMockNpm = async (t, opts) => { + const mock = await _loadMockNpm(t, opts) + const registry = new MockRegistry({ + tap: t, + registry: mock.npm.config.get('registry'), + }) + return { registry, ...mock } +} + +const packageJson = { + name: 'test-package', + version: '1.0.0', + dependencies: { + abbrev: '^1.0.0', + }, +} +const packageLock = { + name: 'test-package', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'test-package', + version: '1.0.0', + dependencies: { + abbrev: '^1.0.0', + }, }, - }) + 'node_modules/abbrev': { + version: '1.0.0', + resolved: 'https://registry.npmjs.org/abbrev/-/abbrev-1.0.0.tgz', + // integrity changes w/ each test cause the path is different? + }, + }, + dependencies: { + abbrev: { + version: '1.0.0', + resolved: 'https://registry.npmjs.org/abbrev/-/abbrev-1.0.0.tgz', + // integrity changes w/ each test cause the path is different? + }, + }, +} + +const abbrev = { + 'package.json': '{"name": "abbrev", "version": "1.0.0"}', + test: 'test file', +} + +t.test('reifies, audits, removes node_modules', async t => { + const { npm, joinedOutput, registry } = await loadMockNpm(t, { + prefixDir: { + abbrev: abbrev, + 'package.json': JSON.stringify(packageJson), + 'package-lock.json': JSON.stringify(packageLock), + node_modules: { test: 'test file that will be removed' }, + }, + }) + const manifest = registry.manifest({ name: 'abbrev' }) + await registry.tarball({ + manifest: manifest.versions['1.0.0'], + tarball: path.join(npm.prefix, 'abbrev'), + }) + registry.nock.post('/-/npm/v1/security/advisories/bulk').reply(200, {}) + await npm.exec('ci', []) + t.match(joinedOutput(), 'added 1 package, and audited 2 packages in') + await t.resolveMatch( + fs.exists(path.join(npm.prefix, 'node_modules', 'test')), + false, + 'existing node_modules is removed' + ) + await t.resolveMatch( + fs.exists(path.join(npm.prefix, 'node_modules', 'abbrev')), + true, + 'installs abbrev' + ) +}) - const npm = mockNpm({ - globalDir: 'path/to/node_modules/', - prefix: 'foo', +t.test('--no-audit and --ignore-scripts', async t => { + const { npm, joinedOutput, registry } = await loadMockNpm(t, { config: { - global: false, 'ignore-scripts': true, + audit: false, }, - }) - const ci = new CI(npm) - - await ci.exec([]) - t.equal(REIFY_CALLED, true, 'called reify') - t.strictSame(SCRIPTS, [], 'no scripts when running ci') -}) - -t.test('should use Arborist and run-script', async t => { - const scripts = [ - 'preinstall', - 'install', - 'postinstall', - 'prepublish', // XXX should we remove this finally?? - 'preprepare', - 'prepare', - 'postprepare', - ] - - // set to true when timer starts, false when it ends - // when the test is done, we assert that all timers ended - const timers = {} - const onTime = msg => { - if (timers[msg]) { - throw new Error(`saw duplicate timer: ${msg}`) - } - timers[msg] = true - } - const onTimeEnd = msg => { - if (!timers[msg]) { - throw new Error(`ended timer that was not started: ${msg}`) - } - timers[msg] = false - } - process.on('time', onTime) - process.on('timeEnd', onTimeEnd) - t.teardown(() => { - process.removeListener('time', onTime) - process.removeListener('timeEnd', onTimeEnd) - }) - - const path = t.testdir({ - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.2.3', - }), + prefixDir: { + abbrev: { + 'package.json': '{"name": "abbrev", "version": "1.0.0"}', + test: 'test-file', }, - '.dotdir': {}, - '.dotfile': 'a file with a dot', + 'package.json': JSON.stringify({ + ...packageJson, + // Would make install fail + scripts: { install: 'echo "SHOULD NOT RUN" && exit 1' }, + }), + 'package-lock.json': JSON.stringify(packageLock), }, }) - const expectRimrafs = 3 - let actualRimrafs = 0 - - const CI = t.mock('../../../lib/commands/ci.js', { - '../../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/run-script': opts => { - t.match(opts, { event: scripts.shift() }) - }, - '@npmcli/arborist': function (args) { - t.ok(args, 'gets options object') - this.loadVirtual = () => { - t.ok(true, 'loadVirtual is called') - return Promise.resolve(true) - } - this.reify = () => { - t.ok(true, 'reify is called') - } - this.buildIdealTree = () => {} - this.virtualTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - this.idealTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - }, - rimraf: (path, ...args) => { - actualRimrafs++ - t.ok(path, 'rimraf called with path') - // callback is always last arg - args.pop()() - }, - '../../../lib/utils/reify-output.js': function (arb) { - t.ok(arb, 'gets arborist tree') - }, + require('nock').emitter.on('no match', req => { + t.fail('Should not audit') }) - - const npm = mockNpm({ - prefix: path, - config: { - global: false, - }, + const manifest = registry.manifest({ name: 'abbrev' }) + await registry.tarball({ + manifest: manifest.versions['1.0.0'], + tarball: path.join(npm.prefix, 'abbrev'), }) - const ci = new CI(npm) - - await ci.exec(null) - for (const [msg, result] of Object.entries(timers)) { - t.notOk(result, `properly resolved ${msg} timer`) - } - t.match(timers, { 'npm-ci:rm': false }, 'saw the rimraf timer') - t.equal(actualRimrafs, expectRimrafs, 'removed the right number of things') - t.strictSame(scripts, [], 'called all scripts') + await npm.exec('ci', []) + t.match(joinedOutput(), 'added 1 package in', 'would fail if install script ran') }) -t.test('should pass flatOptions to Arborist.reify', async t => { - t.plan(1) - const CI = t.mock('../../../lib/commands/ci.js', { - '../../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/run-script': opts => {}, - '@npmcli/arborist': function () { - this.loadVirtual = () => Promise.resolve(true) - this.reify = async (options) => { - t.equal(options.production, true, 'should pass flatOptions to Arborist.reify') - } - this.buildIdealTree = () => {} - this.virtualTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - this.idealTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } +t.test('lifecycle scripts', async t => { + const scripts = [] + const { npm, registry } = await loadMockNpm(t, { + prefixDir: { + abbrev: abbrev, + 'package.json': JSON.stringify(packageJson), + 'package-lock.json': JSON.stringify(packageLock), + }, + mocks: { + '@npmcli/run-script': (opts) => { + t.ok(opts.banner) + scripts.push(opts.event) + }, }, }) - const npm = mockNpm({ - prefix: 'foo', - flatOptions: { - production: true, - }, + const manifest = registry.manifest({ name: 'abbrev' }) + await registry.tarball({ + manifest: manifest.versions['1.0.0'], + tarball: path.join(npm.prefix, 'abbrev'), }) - const ci = new CI(npm) - await ci.exec(null) + registry.nock.post('/-/npm/v1/security/advisories/bulk').reply(200, {}) + await npm.exec('ci', []) + t.same(scripts, [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', + 'preprepare', + 'prepare', + 'postprepare', + ], 'runs appropriate scripts, in order') }) t.test('should throw if package-lock.json or npm-shrinkwrap missing', async t => { - const testDir = t.testdir({ - 'index.js': 'some contents', - 'package.json': 'some info', - }) - - const CI = t.mock('../../../lib/commands/ci.js', { - '@npmcli/run-script': opts => {}, - '../../../lib/utils/reify-finish.js': async () => {}, - 'proc-log': { - verbose: () => { - t.ok(true, 'log fn called') + const { npm } = await loadMockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify(packageJson), + node_modules: { + 'test-file': 'should not be removed', }, }, }) - const npm = mockNpm({ - prefix: testDir, - config: { - global: false, - }, - }) - const ci = new CI(npm) - await t.rejects( - ci.exec(null), - /package-lock.json/, - 'throws error when there is no package-lock' + await t.rejects(npm.exec('ci', []), { code: 'EUSAGE', message: /package-lock.json/ }) + await t.resolveMatch( + fs.exists(path.join(npm.prefix, 'node_modules', 'test-file')), + true, + 'does not remove node_modules' ) }) t.test('should throw ECIGLOBAL', async t => { - const CI = t.mock('../../../lib/commands/ci.js', { - '@npmcli/run-script': opts => {}, - '../../../lib/utils/reify-finish.js': async () => {}, - }) - const npm = mockNpm({ - prefix: 'foo', - config: { - global: true, - }, - }) - const ci = new CI(npm) - await t.rejects( - ci.exec(null), - { code: 'ECIGLOBAL' }, - 'throws error with global packages' - ) -}) - -t.test('should remove existing node_modules before installing', async t => { - t.plan(3) - const testDir = t.testdir({ - node_modules: { - 'some-file': 'some contents', - }, + const { npm } = await loadMockNpm(t, { + config: { global: true }, }) - - const CI = t.mock('../../../lib/commands/ci.js', { - '@npmcli/run-script': opts => {}, - '../../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/arborist': function () { - this.loadVirtual = () => Promise.resolve(true) - this.reify = async (options) => { - t.equal(options.packageLock, true, 'npm ci should never ignore lock') - t.equal(options.save, false, 'npm ci should never save') - // check if node_modules was removed before reifying - const contents = await readdir(testDir) - const nodeModules = contents.filter((path) => path.startsWith('node_modules')) - t.same(nodeModules, ['node_modules'], 'should only have the node_modules directory') - } - this.buildIdealTree = () => {} - this.virtualTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - this.idealTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - }, - }) - - const npm = mockNpm({ - prefix: testDir, - config: { - global: false, - }, - }) - const ci = new CI(npm) - - await ci.exec(null) + await t.rejects(npm.exec('ci', []), { code: 'ECIGLOBAL' }) }) t.test('should throw error when ideal inventory mismatches virtual', async t => { - const CI = t.mock('../../../lib/commands/ci.js', { - '../../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/run-script': ({ event }) => {}, - '@npmcli/arborist': function () { - this.loadVirtual = async () => {} - this.reify = () => {} - this.buildIdealTree = () => {} - this.virtualTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '1.0.0' }], - ]), - } - this.idealTree = { - inventory: new Map([ - ['foo', { name: 'foo', version: '2.0.0' }], - ]), - } - }, - }) - - const npm = mockNpm({ - globalDir: 'path/to/node_modules/', - prefix: 'foo', - config: { - global: false, - 'ignore-scripts': true, + const { npm, registry } = await loadMockNpm(t, { + prefixDir: { + abbrev: abbrev, + 'package.json': JSON.stringify({ + ...packageJson, + dependencies: { notabbrev: '^1.0.0' }, + }), + 'package-lock.json': JSON.stringify(packageLock), + node_modules: { + 'test-file': 'should not be removed', + }, }, }) - const ci = new CI(npm) - - try { - await ci.exec([]) - } catch (err) { - t.matchSnapshot(err.message) - } + const manifest = registry.manifest({ name: 'notabbrev' }) + await registry.package({ manifest }) + await t.rejects( + npm.exec('ci', []), + { code: 'EUSAGE', message: /in sync/ } + ) + await t.resolveMatch( + fs.exists(path.join(npm.prefix, 'node_modules', 'test-file')), + true, + 'does not remove node_modules' + ) }) diff --git a/deps/npm/test/lib/commands/deprecate.js b/deps/npm/test/lib/commands/deprecate.js index 8a925fc2a6..3a610a703a 100644 --- a/deps/npm/test/lib/commands/deprecate.js +++ b/deps/npm/test/lib/commands/deprecate.js @@ -44,7 +44,7 @@ t.test('completion', async t => { registry.whoami({ statusCode: 404, body: {} }) - t.rejects(testComp([], []), { code: 'ENEEDAUTH' }) + t.rejects(testComp([], []), { code: 'EINVALIDTYPE' }) }) t.test('no args', async t => { diff --git a/deps/npm/test/lib/commands/exec.js b/deps/npm/test/lib/commands/exec.js index 1117885b91..049ed327c8 100644 --- a/deps/npm/test/lib/commands/exec.js +++ b/deps/npm/test/lib/commands/exec.js @@ -473,7 +473,7 @@ t.test('npm exec foo, not present locally but in central loc', async t => { await exec.exec(['foo', 'one arg', 'two arg']) t.strictSame(MKDIRPS, [installDir], 'need to make install dir') t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [], 'no need to install again, already there') + t.strictSame(ARB_REIFY, [], 'no need to install again, already there') t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` t.match(RUN_SCRIPTS, [ diff --git a/deps/npm/test/lib/commands/outdated.js b/deps/npm/test/lib/commands/outdated.js index 14647ce6ce..4803c7e171 100644 --- a/deps/npm/test/lib/commands/outdated.js +++ b/deps/npm/test/lib/commands/outdated.js @@ -343,7 +343,9 @@ t.test('should return if no outdated deps', async t => { }) await outdated(testDir, { - global: false, + config: { + global: false, + }, }).exec([]) t.equal(logs.length, 0, 'no logs') }) @@ -369,7 +371,9 @@ t.test('throws if error with a dep', async t => { await t.rejects( outdated(testDir, { - global: false, + config: { + global: false, + }, }).exec([]), 'There is an error with this package.' ) @@ -388,7 +392,9 @@ t.test('should skip missing non-prod deps', async t => { }) await outdated(testDir, { - global: false, + config: { + global: false, + }, }).exec([]) t.equal(logs.length, 0, 'no logs') }) diff --git a/deps/npm/test/lib/commands/ping.js b/deps/npm/test/lib/commands/ping.js index f808e0ac3b..dd2f83de08 100644 --- a/deps/npm/test/lib/commands/ping.js +++ b/deps/npm/test/lib/commands/ping.js @@ -1,113 +1,67 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') +const MockRegistry = require('../../fixtures/mock-registry.js') -t.test('pings', async t => { - t.plan(6) - - const registry = 'https://registry.npmjs.org' - let noticeCalls = 0 - const Ping = t.mock('../../../lib/commands/ping.js', { - '../../../lib/utils/ping.js': function (spec) { - t.equal(spec.registry, registry, 'passes flatOptions') - return {} - }, - 'proc-log': { - notice: (type, spec) => { - ++noticeCalls - if (noticeCalls === 1) { - t.equal(type, 'PING', 'should log a PING') - t.equal(spec, registry, 'should log the registry url') - } else { - t.equal(type, 'PONG', 'should log a PONG') - t.match(spec, /\d+ms/, 'should log the elapsed milliseconds') - } - }, - }, - }) - const npm = mockNpm({ - config: { registry }, - flatOptions: { registry }, +t.test('no details', async t => { + const { npm, logs, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), }) - const ping = new Ping(npm) - - await ping.exec([]) - t.equal(noticeCalls, 2, 'should have logged 2 lines') + registry.ping() + await npm.exec('ping', []) + t.match(logs.notice, [['PING', 'https://registry.npmjs.org/'], ['PONG', /[0-9]+ms/]]) + t.equal(joinedOutput(), '') }) -t.test('pings and logs details', async t => { - t.plan(8) +t.test('with details', async t => { + const { npm, logs, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.ping({ body: { test: true } }) + await npm.exec('ping', []) + t.match(logs.notice, [ + ['PING', 'https://registry.npmjs.org/'], + ['PONG', /[0-9]+ms/], + ['PONG', '{\n "test": true\n}'], + ]) + t.match(joinedOutput(), '') +}) - const registry = 'https://registry.npmjs.org' - const details = { extra: 'data' } - let noticeCalls = 0 - const Ping = t.mock('../../../lib/commands/ping.js', { - '../../../lib/utils/ping.js': function (spec) { - t.equal(spec.registry, registry, 'passes flatOptions') - return details - }, - 'proc-log': { - notice: (type, spec) => { - ++noticeCalls - if (noticeCalls === 1) { - t.equal(type, 'PING', 'should log a PING') - t.equal(spec, registry, 'should log the registry url') - } else if (noticeCalls === 2) { - t.equal(type, 'PONG', 'should log a PONG') - t.match(spec, /\d+ms/, 'should log the elapsed milliseconds') - } else { - t.equal(type, 'PONG', 'should log a PONG') - const parsed = JSON.parse(spec) - t.match(parsed, details, 'should log JSON stringified details') - } - }, - }, +t.test('valid json', async t => { + const { npm, logs, joinedOutput } = await loadMockNpm(t, { + config: { json: true }, }) - const npm = mockNpm({ - config: { registry }, - flatOptions: { registry }, + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.ping() + await npm.exec('ping', []) + t.match(logs.notice, [['PING', 'https://registry.npmjs.org/'], ['PONG', /[0-9]+ms/]]) + t.match(JSON.parse(joinedOutput()), { + registry: npm.config.get('registry'), + time: /[0-9]+/, + details: {}, }) - const ping = new Ping(npm) - - await ping.exec([]) - t.equal(noticeCalls, 3, 'should have logged 3 lines') }) -t.test('pings and returns json', async t => { - t.plan(9) - - const registry = 'https://registry.npmjs.org' - const details = { extra: 'data' } - let noticeCalls = 0 - const Ping = t.mock('../../../lib/commands/ping.js', { - '../../../lib/utils/ping.js': function (spec) { - t.equal(spec.registry, registry, 'passes flatOptions') - return details - }, - 'proc-log': { - notice: (type, spec) => { - ++noticeCalls - if (noticeCalls === 1) { - t.equal(type, 'PING', 'should log a PING') - t.equal(spec, registry, 'should log the registry url') - } else { - t.equal(type, 'PONG', 'should log a PONG') - t.match(spec, /\d+ms/, 'should log the elapsed milliseconds') - } - }, - }, +t.test('invalid json', async t => { + const { npm, logs, joinedOutput } = await loadMockNpm(t, { + config: { json: true }, }) - const npm = mockNpm({ - config: { registry, json: true }, - flatOptions: { registry }, - output: function (spec) { - const parsed = JSON.parse(spec) - t.equal(parsed.registry, registry, 'returns the correct registry url') - t.match(parsed.details, details, 'prints returned details') - t.type(parsed.time, 'number', 'returns time as a number') - }, + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.ping({ body: '{not: real"json]' }) + await npm.exec('ping', []) + t.match(logs.notice, [['PING', 'https://registry.npmjs.org/'], ['PONG', /[0-9]+ms/]]) + t.match(JSON.parse(joinedOutput()), { + registry: npm.config.get('registry'), + time: /[0-9]+/, + details: {}, }) - const ping = new Ping(npm) - - await ping.exec([]) - t.equal(noticeCalls, 2, 'should have logged 2 lines') }) diff --git a/deps/npm/test/lib/commands/set-script.js b/deps/npm/test/lib/commands/set-script.js index 2c4fe57d68..cf0df53af1 100644 --- a/deps/npm/test/lib/commands/set-script.js +++ b/deps/npm/test/lib/commands/set-script.js @@ -130,7 +130,7 @@ t.test('warns when overwriting', async t => { }) await setScript.exec(['arg1', 'arg2']) - t.hasStrict(WARN_OUTPUT[0], ['set-script', 'Script "arg1" was overwritten'], 'warning was logged') + t.hasStrict(WARN_OUTPUT[1], ['set-script', 'Script "arg1" was overwritten'], 'warning was logged') }) t.test('workspaces', async t => { diff --git a/deps/npm/test/lib/commands/whoami.js b/deps/npm/test/lib/commands/whoami.js index f483bd46d5..ad7c223888 100644 --- a/deps/npm/test/lib/commands/whoami.js +++ b/deps/npm/test/lib/commands/whoami.js @@ -5,7 +5,7 @@ const MockRegistry = require('../../fixtures/mock-registry.js') const username = 'foo' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } -t.test('npm whoami', async (t) => { +t.test('npm whoami', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { config: auth }) const registry = new MockRegistry({ tap: t, @@ -17,7 +17,7 @@ t.test('npm whoami', async (t) => { t.equal(joinedOutput(), username, 'should print username') }) -t.test('npm whoami --json', async (t) => { +t.test('npm whoami --json', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true, @@ -33,3 +33,23 @@ t.test('npm whoami --json', async (t) => { await npm.exec('whoami', []) t.equal(JSON.parse(joinedOutput()), username, 'should print username') }) + +t.test('credentials from token', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + '//registry.npmjs.org/:username': username, + '//registry.npmjs.org/:_password': 'hunter2', + }, + }) + await npm.exec('whoami', []) + t.equal(joinedOutput(), username, 'should print username') +}) + +t.test('not logged in', async t => { + const { npm } = await loadMockNpm(t, { + config: { + json: true, + }, + }) + await t.rejects(npm.exec('whoami', []), { code: 'ENEEDAUTH' }) +}) diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js index 566cbca20f..cd692a93f5 100644 --- a/deps/npm/test/lib/npm.js +++ b/deps/npm/test/lib/npm.js @@ -654,3 +654,61 @@ t.test('implicit workspace accept', async t => { }) await t.rejects(mock.npm.exec('org', []), /.*Usage/) }) + +t.test('usage', async t => { + const { npm } = await loadMockNpm(t) + t.afterEach(() => { + npm.config.set('viewer', null) + npm.config.set('long', false) + npm.config.set('userconfig', '/some/config/file/.npmrc') + }) + const { dirname } = require('path') + const basedir = dirname(dirname(__dirname)) + t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') + .split(require('../../package.json').version).join('{VERSION}') + + npm.config.set('viewer', null) + npm.config.set('long', false) + npm.config.set('userconfig', '/some/config/file/.npmrc') + + t.test('basic usage', async t => { + t.matchSnapshot(await npm.usage) + t.end() + }) + + t.test('with browser', async t => { + npm.config.set('viewer', 'browser') + t.matchSnapshot(await npm.usage) + t.end() + }) + + t.test('with long', async t => { + npm.config.set('long', true) + t.matchSnapshot(await npm.usage) + t.end() + }) + + t.test('set process.stdout.columns', async t => { + const { columns } = process.stdout + t.teardown(() => { + Object.defineProperty(process.stdout, 'columns', { + value: columns, + enumerable: true, + configurable: true, + writable: true, + }) + }) + const cases = [0, 90] + for (const cols of cases) { + t.test(`columns=${cols}`, async t => { + Object.defineProperty(process.stdout, 'columns', { + value: cols, + enumerable: true, + configurable: true, + writable: true, + }) + t.matchSnapshot(await npm.usage) + }) + } + }) +}) diff --git a/deps/npm/test/lib/utils/get-identity.js b/deps/npm/test/lib/utils/get-identity.js deleted file mode 100644 index 5e6de9ca9c..0000000000 --- a/deps/npm/test/lib/utils/get-identity.js +++ /dev/null @@ -1,103 +0,0 @@ -const t = require('tap') - -t.test('throws ENOREGISTRY when no registry option is provided', async (t) => { - t.plan(2) - const getIdentity = t.mock('../../../lib/utils/get-identity.js') - - try { - await getIdentity({}) - } catch (err) { - t.equal(err.code, 'ENOREGISTRY', 'assigns the appropriate error code') - t.equal(err.message, 'No registry specified.', 'returns the correct error message') - } -}) - -t.test('returns username from uri when provided', async (t) => { - t.plan(1) - - const getIdentity = t.mock('../../../lib/utils/get-identity.js') - const npm = { - config: { - getCredentialsByURI: () => { - return { username: 'foo' } - }, - }, - } - - const identity = await getIdentity(npm, { registry: 'https://registry.npmjs.org' }) - t.equal(identity, 'foo', 'returns username from uri') -}) - -t.test('calls registry whoami when token is provided', async (t) => { - t.plan(3) - - const options = { - registry: 'https://registry.npmjs.org', - token: 'thisisnotreallyatoken', - } - - const getIdentity = t.mock('../../../lib/utils/get-identity.js', { - 'npm-registry-fetch': { - json: (path, opts) => { - t.equal(path, '/-/whoami', 'calls whoami') - t.same(opts, options, 'passes through provided options') - return { username: 'foo' } - }, - }, - }) - const npm = { - config: { - getCredentialsByURI: () => options, - }, - } - - const identity = await getIdentity(npm, options) - t.equal(identity, 'foo', 'fetched username from registry') -}) - -t.test('throws ENEEDAUTH when response does not include a username', async (t) => { - t.plan(3) - - const options = { - registry: 'https://registry.npmjs.org', - token: 'thisisnotreallyatoken', - } - - const getIdentity = t.mock('../../../lib/utils/get-identity.js', { - 'npm-registry-fetch': { - json: (path, opts) => { - t.equal(path, '/-/whoami', 'calls whoami') - t.same(opts, options, 'passes through provided options') - return {} - }, - }, - }) - const npm = { - config: { - getCredentialsByURI: () => options, - }, - } - - try { - await getIdentity(npm, options) - } catch (err) { - t.equal(err.code, 'ENEEDAUTH', 'throws correct error code') - } -}) - -t.test('throws ENEEDAUTH when neither username nor token is configured', async (t) => { - t.plan(1) - const getIdentity = t.mock('../../../lib/utils/get-identity.js', { - }) - const npm = { - config: { - getCredentialsByURI: () => ({}), - }, - } - - try { - await getIdentity(npm, { registry: 'https://registry.npmjs.org' }) - } catch (err) { - t.equal(err.code, 'ENEEDAUTH', 'throws correct error code') - } -}) diff --git a/deps/npm/test/lib/utils/is-windows.js b/deps/npm/test/lib/utils/is-windows.js deleted file mode 100644 index a1d520f062..0000000000 --- a/deps/npm/test/lib/utils/is-windows.js +++ /dev/null @@ -1,39 +0,0 @@ -const t = require('tap') - -const mockGlobals = require('../../fixtures/mock-globals') - -t.test('is not windows', async t => { - mockGlobals(t, { 'process.platform': 'posix' }) - t.match({ - isWindows: false, - isWindowsShell: false, - }, t.mock('../../../lib/utils/is-windows.js')) -}) - -t.test('is windows, shell', async t => { - mockGlobals(t, { - 'process.platform': 'win32', - 'process.env': { - MSYSTEM: 'notmingw', - TERM: 'notcygwin', - }, - }) - t.match({ - isWindows: true, - isWindowsShell: true, - }, t.mock('../../../lib/utils/is-windows.js')) -}) - -t.test('is windows, not shell', async t => { - mockGlobals(t, { - 'process.platform': 'win32', - 'process.env': { - MSYSTEM: 'MINGW32', - TERM: 'cygwin', - }, - }) - t.match({ - isWindows: true, - isWindowsShell: false, - }, t.mock('../../../lib/utils/is-windows.js')) -}) diff --git a/deps/npm/test/lib/utils/npm-usage.js b/deps/npm/test/lib/utils/npm-usage.js deleted file mode 100644 index 035d4bbb21..0000000000 --- a/deps/npm/test/lib/utils/npm-usage.js +++ /dev/null @@ -1,60 +0,0 @@ -const t = require('tap') -const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') - -t.test('usage', async t => { - const { npm } = await loadMockNpm(t) - t.afterEach(() => { - npm.config.set('viewer', null) - npm.config.set('long', false) - npm.config.set('userconfig', '/some/config/file/.npmrc') - }) - const { dirname } = require('path') - const basedir = dirname(dirname(dirname(__dirname))) - t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') - .split(require('../../../package.json').version).join('{VERSION}') - - npm.config.set('viewer', null) - npm.config.set('long', false) - npm.config.set('userconfig', '/some/config/file/.npmrc') - - t.test('basic usage', async t => { - t.matchSnapshot(await npm.usage) - t.end() - }) - - t.test('with browser', async t => { - npm.config.set('viewer', 'browser') - t.matchSnapshot(await npm.usage) - t.end() - }) - - t.test('with long', async t => { - npm.config.set('long', true) - t.matchSnapshot(await npm.usage) - t.end() - }) - - t.test('set process.stdout.columns', async t => { - const { columns } = process.stdout - t.teardown(() => { - Object.defineProperty(process.stdout, 'columns', { - value: columns, - enumerable: true, - configurable: true, - writable: true, - }) - }) - const cases = [0, 90] - for (const cols of cases) { - t.test(`columns=${cols}`, async t => { - Object.defineProperty(process.stdout, 'columns', { - value: cols, - enumerable: true, - configurable: true, - writable: true, - }) - t.matchSnapshot(await npm.usage) - }) - } - }) -}) diff --git a/deps/npm/test/lib/utils/ping.js b/deps/npm/test/lib/utils/ping.js deleted file mode 100644 index 1bebfa69d2..0000000000 --- a/deps/npm/test/lib/utils/ping.js +++ /dev/null @@ -1,35 +0,0 @@ -const t = require('tap') - -t.test('pings', async (t) => { - t.plan(3) - - const options = { fake: 'options' } - const response = { some: 'details' } - const ping = t.mock('../../../lib/utils/ping.js', { - 'npm-registry-fetch': (url, opts) => { - t.equal(url, '/-/ping?write=true', 'calls the correct url') - t.equal(opts, options, 'passes through options') - return { json: () => Promise.resolve(response) } - }, - }) - - const res = await ping(options) - t.match(res, response, 'returns json response') -}) - -t.test('catches errors and returns empty json', async (t) => { - t.plan(3) - - const options = { fake: 'options' } - const response = { some: 'details' } - const ping = t.mock('../../../lib/utils/ping.js', { - 'npm-registry-fetch': (url, opts) => { - t.equal(url, '/-/ping?write=true', 'calls the correct url') - t.equal(opts, options, 'passes through options') - return { json: () => Promise.reject(response) } - }, - }) - - const res = await ping(options) - t.match(res, {}, 'returns empty json response') -}) |