feat: self-update command (#8424)

This commit is contained in:
Zoltan Kochan
2024-08-19 14:26:17 +02:00
committed by GitHub
parent 202edf84bd
commit eb8bf2a993
31 changed files with 710 additions and 176 deletions

View File

@@ -0,0 +1,10 @@
---
"@pnpm/tools.plugin-commands-self-updater": major
"@pnpm/tools.path": major
"@pnpm/plugin-commands-installation": minor
"@pnpm/default-reporter": major
"@pnpm/cli-meta": minor
"pnpm": minor
---
Added a new command for upgrading pnpm itself, when it isn't managed by Corepack: `pnpm self-update`. This command will work, when pnpm was installed via the standalone script from the [pnpm installation page](https://pnpm.io/installation#using-a-standalone-script) [#8424](https://github.com/pnpm/pnpm/pull/8424).

View File

@@ -0,0 +1,3 @@
const config = require('../../jest.config.js');
module.exports = Object.assign({}, config, {});

View File

@@ -12,10 +12,11 @@
"node": ">=18.12"
},
"scripts": {
"lint": "eslint \"src/**/*.ts\"",
"test": "pnpm run compile",
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
"test": "pnpm run compile && pnpm run _test",
"prepublishOnly": "pnpm run compile",
"compile": "tsc --build && pnpm run lint --fix"
"compile": "tsc --build && pnpm run lint --fix",
"_test": "jest"
},
"repository": "https://github.com/pnpm/pnpm/blob/main/cli/cli-meta",
"keywords": [

View File

@@ -36,10 +36,39 @@ export const packageManager = {
version: pkgJson.version,
}
export function detectIfCurrentPkgIsExecutable (proc: NodeJS.Process = process): boolean {
export interface Process {
arch: NodeJS.Architecture
platform: NodeJS.Platform
pkg?: unknown
}
export function detectIfCurrentPkgIsExecutable (proc: Process = process): boolean {
return 'pkg' in proc && proc.pkg != null
}
export function isExecutedByCorepack (env: NodeJS.ProcessEnv = process.env): boolean {
return env.COREPACK_ROOT != null
}
export function getCurrentPackageName (proc: Process = process): string {
return detectIfCurrentPkgIsExecutable(proc) ? getExePackageName(proc) : 'pnpm'
}
function getExePackageName (proc: Process): string {
return `@pnpm/${normalizePlatformName(proc)}-${normalizeArchName(proc)}`
}
function normalizePlatformName (proc: Process): string {
switch (proc.platform) {
case 'win32': return 'win'
case 'darwin': return 'macos'
default: return proc.platform
}
}
function normalizeArchName (proc: Process): string {
if (proc.platform === 'win32' && proc.arch === 'ia32') {
return 'x86'
}
return proc.arch
}

View File

@@ -0,0 +1,23 @@
import { getCurrentPackageName } from '@pnpm/cli-meta'
test('getCurrentPackageName()', () => {
expect(getCurrentPackageName({
platform: 'darwin',
arch: 'arm64',
})).toBe('pnpm')
expect(getCurrentPackageName({
pkg: '.',
platform: 'win32',
arch: 'ia32',
})).toBe('@pnpm/win-x86')
expect(getCurrentPackageName({
pkg: '.',
platform: 'darwin',
arch: 'arm64',
})).toBe('@pnpm/macos-arm64')
expect(getCurrentPackageName({
pkg: '.',
platform: 'linux',
arch: 'x64',
})).toBe('@pnpm/linux-x64')
})

View File

@@ -0,0 +1,17 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "../test.lib",
"rootDir": "."
},
"include": [
"**/*.ts",
"../../../__typings__/**/*.d.ts"
],
"references": [
{
"path": ".."
}
]
}

View File

@@ -46,14 +46,14 @@ interface UpdateMessageOptions {
}
function renderUpdateMessage (opts: UpdateMessageOptions): string {
if (opts.currentPkgIsExecutable && opts.env.PNPM_HOME) {
return 'Run a script from: https://pnpm.io/installation'
}
const updateCommand = renderUpdateCommand(opts)
return `Run "${chalk.magenta(updateCommand)}" to update.`
}
function renderUpdateCommand (opts: UpdateMessageOptions): string {
if (opts.env.PNPM_HOME) {
return 'pnpm self-update'
}
if (isExecutedByCorepack(opts.env)) {
return `corepack install -g pnpm@${opts.latestVersion}`
}

View File

@@ -34,7 +34,7 @@ exports[`print update notification that suggests to use the standalone scripts f
│ │
│ Update available! 10.0.0 → 11.0.0. │
│ Changelog: https://github.com/pnpm/pnpm/releases/tag/v11.0.0 │
Run a script from: https://pnpm.io/installation
Run "pnpm self-update" to update.
│ │
│ Follow @pnpmjs for updates: https://x.com/pnpmjs │
│ │

View File

@@ -9,5 +9,6 @@ import * as remove from './remove'
import * as unlink from './unlink'
import * as update from './update'
import * as importCommand from './import'
import { type InstallCommandOptions } from './install'
export { add, ci, dedupe, fetch, install, link, prune, remove, unlink, update, importCommand }
export { add, ci, dedupe, fetch, install, link, prune, remove, unlink, update, importCommand, type InstallCommandOptions }

252
pnpm-lock.yaml generated
View File

@@ -5592,6 +5592,12 @@ importers:
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../__utils__/test-ipc-server
'@pnpm/tools.path':
specifier: workspace:*
version: link:../tools/path
'@pnpm/tools.plugin-commands-self-updater':
specifier: workspace:*
version: link:../tools/plugin-commands-self-updater
'@pnpm/types':
specifier: workspace:*
version: link:../packages/types
@@ -7285,6 +7291,73 @@ importers:
specifier: workspace:*
version: 'link:'
tools/path:
devDependencies:
'@pnpm/tools.path':
specifier: workspace:*
version: 'link:'
tools/plugin-commands-self-updater:
dependencies:
'@pnpm/cli-meta':
specifier: workspace:*
version: link:../../cli/cli-meta
'@pnpm/cli-utils':
specifier: workspace:*
version: link:../../cli/cli-utils
'@pnpm/client':
specifier: workspace:*
version: link:../../pkg-manager/client
'@pnpm/config':
specifier: workspace:*
version: link:../../config/config
'@pnpm/error':
specifier: workspace:*
version: link:../../packages/error
'@pnpm/link-bins':
specifier: workspace:*
version: link:../../pkg-manager/link-bins
'@pnpm/logger':
specifier: ^5.1.0
version: 5.2.0
'@pnpm/pick-registry-for-package':
specifier: workspace:*
version: link:../../config/pick-registry-for-package
'@pnpm/plugin-commands-installation':
specifier: workspace:*
version: link:../../pkg-manager/plugin-commands-installation
'@pnpm/tools.path':
specifier: workspace:*
version: link:../path
ramda:
specifier: 'catalog:'
version: '@pnpm/ramda@0.28.1'
render-help:
specifier: 'catalog:'
version: 1.0.3
devDependencies:
'@pnpm/env.path':
specifier: workspace:*
version: link:../../env/path
'@pnpm/prepare':
specifier: workspace:*
version: link:../../__utils__/prepare
'@pnpm/tools.plugin-commands-self-updater':
specifier: workspace:*
version: 'link:'
'@types/cross-spawn':
specifier: 'catalog:'
version: 6.0.6
'@types/ramda':
specifier: 'catalog:'
version: 0.29.12
cross-spawn:
specifier: 'catalog:'
version: 7.0.3
nock:
specifier: 'catalog:'
version: 13.3.4
worker:
dependencies:
'@pnpm/cafs-types':
@@ -8515,10 +8588,6 @@ packages:
resolution: {integrity: sha512-PRy5Ck1Jz0P6W7+cV4E1OQDnIQRKLkhrg+rvfPkGtk2TfJmuIZAvq25E8NUn5DMtODWZ1xG0Yro2jgMXUiz3tg==}
engines: {node: '>=18.12'}
'@pnpm/logger@5.0.0':
resolution: {integrity: sha512-YfcB2QrX+Wx1o6LD1G2Y2fhDhOix/bAY/oAnMpHoNLsKkWIRbt1oKLkIFvxBMzLwAEPqnYWguJrYC+J6i4ywbw==}
engines: {node: '>=12.17'}
'@pnpm/logger@5.2.0':
resolution: {integrity: sha512-dCdSs2wPCweMkRLdISAKBOKSWeq/9iS9aanWgjoUkFs06KN2o5XGFg53oCXg/KbZhF9AXS3vMHPwTebzCeAEsA==}
engines: {node: '>=18.12'}
@@ -14913,7 +14982,7 @@ snapshots:
'@jest/console@29.7.0':
dependencies:
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
jest-message-util: 29.7.0
jest-util: 29.7.0
@@ -14926,14 +14995,14 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0(@babel/types@7.24.7)
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.9.0
exit: 0.1.2
graceful-fs: 4.2.11(patch_hash=ivtm2a2cfr5pomcfbedhmr5v2q)
jest-changed-files: 29.7.0
jest-config: 29.7.0(@babel/types@7.24.7)(@types/node@20.14.9)(ts-node@10.9.2(@types/node@18.19.34)(typescript@5.5.4))
jest-config: 29.7.0(@babel/types@7.24.7)(@types/node@22.2.0)(ts-node@10.9.2(@types/node@18.19.34)(typescript@5.5.4))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -14959,7 +15028,7 @@ snapshots:
dependencies:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
jest-mock: 29.7.0
'@jest/expect-utils@29.7.0':
@@ -14977,7 +15046,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
'@types/node': 20.14.9
'@types/node': 22.2.0
jest-message-util: 29.7.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -14999,7 +15068,7 @@ snapshots:
'@jest/transform': 29.7.0(@babel/types@7.24.7)
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.25
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
collect-v8-coverage: 1.0.2
exit: 0.1.2
@@ -15071,7 +15140,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/yargs': 17.0.32
chalk: 4.1.2
@@ -15164,20 +15233,6 @@ snapshots:
'@pnpm/types': 12.0.0
load-json-file: 6.2.0
'@pnpm/cli-utils@4.0.1(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
'@pnpm/config': 21.8.0(@pnpm/logger@5.0.0)
'@pnpm/default-reporter': 13.1.12(@pnpm/logger@5.0.0)
'@pnpm/error': 6.0.1
'@pnpm/logger': 5.0.0
'@pnpm/manifest-utils': 6.0.6(@pnpm/logger@5.0.0)
'@pnpm/package-is-installable': 9.0.6(@pnpm/logger@5.0.0)
'@pnpm/read-project-manifest': 6.0.6
'@pnpm/types': 12.0.0
chalk: 4.1.2
load-json-file: 6.2.0
'@pnpm/cli-utils@4.0.1(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
@@ -15200,36 +15255,6 @@ snapshots:
'@pnpm/config.env-replace@3.0.0': {}
'@pnpm/config@21.8.0(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/catalogs.config': 0.1.0
'@pnpm/catalogs.types': 0.1.0
'@pnpm/config.env-replace': 3.0.0
'@pnpm/constants': 8.0.0
'@pnpm/error': 6.0.1
'@pnpm/git-utils': 2.0.0
'@pnpm/matcher': 6.0.0
'@pnpm/npm-conf': 2.3.0
'@pnpm/pnpmfile': 6.0.9(@pnpm/logger@5.0.0)
'@pnpm/read-project-manifest': 6.0.6
'@pnpm/types': 12.0.0
'@pnpm/workspace.read-manifest': 2.2.0
better-path-resolve: 1.0.0
camelcase: 6.3.0
camelcase-keys: 6.2.2
can-write-to-dir: 1.1.1
is-subdir: 1.2.0
is-windows: 1.0.2
normalize-registry-url: 2.0.0
path-absolute: 1.0.1
path-name: 1.0.0
ramda: '@pnpm/ramda@0.28.1'
read-ini-file: 4.0.0
realpath-missing: 1.1.0
which: '@pnpm/which@3.0.1'
transitivePeerDependencies:
- '@pnpm/logger'
'@pnpm/config@21.8.0(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/catalogs.config': 0.1.0
@@ -15262,11 +15287,6 @@ snapshots:
'@pnpm/constants@8.0.0': {}
'@pnpm/core-loggers@10.0.5(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/logger': 5.0.0
'@pnpm/types': 12.0.0
'@pnpm/core-loggers@10.0.5(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/logger': 5.2.0
@@ -15284,30 +15304,6 @@ snapshots:
'@pnpm/dedupe.types@2.0.0': {}
'@pnpm/default-reporter@13.1.12(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
'@pnpm/config': 21.8.0(@pnpm/logger@5.0.0)
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.0.0)
'@pnpm/dedupe.issues-renderer': 2.0.0
'@pnpm/dedupe.types': 2.0.0
'@pnpm/error': 6.0.1
'@pnpm/logger': 5.0.0
'@pnpm/render-peer-issues': 5.0.6
'@pnpm/types': 12.0.0
ansi-diff: 1.1.1
boxen: 5.1.2
chalk: 4.1.2
cli-truncate: 2.1.0
normalize-path: 3.0.0
pretty-bytes: 5.6.0
pretty-ms: 7.0.1
ramda: '@pnpm/ramda@0.28.1'
rxjs: 7.8.1
semver: 7.6.2
stacktracey: 2.1.8
string-length: 4.0.2
'@pnpm/default-reporter@13.1.12(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
@@ -15391,24 +15387,11 @@ snapshots:
dependencies:
ci-info: 3.9.0
'@pnpm/logger@5.0.0':
dependencies:
bole: 5.0.14
ndjson: 2.0.0
'@pnpm/logger@5.2.0':
dependencies:
bole: 5.0.14
ndjson: 2.0.0
'@pnpm/manifest-utils@6.0.6(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.0.0)
'@pnpm/error': 6.0.1
'@pnpm/types': 12.0.0
transitivePeerDependencies:
- '@pnpm/logger'
'@pnpm/manifest-utils@6.0.6(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.2.0)
@@ -15424,9 +15407,9 @@ snapshots:
'@pnpm/meta-updater@2.0.3':
dependencies:
'@pnpm/find-workspace-dir': 7.0.1
'@pnpm/logger': 5.0.0
'@pnpm/logger': 5.2.0
'@pnpm/types': 11.0.0
'@pnpm/workspace.find-packages': 4.0.6(@pnpm/logger@5.0.0)
'@pnpm/workspace.find-packages': 4.0.6(@pnpm/logger@5.2.0)
'@pnpm/workspace.read-manifest': 2.2.0
load-json-file: 7.0.1
meow: 11.0.0
@@ -15520,18 +15503,6 @@ snapshots:
'@pnpm/os.env.path-extender-posix': 2.0.0
'@pnpm/os.env.path-extender-windows': 2.0.0
'@pnpm/package-is-installable@9.0.6(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.0.0)
'@pnpm/error': 6.0.1
'@pnpm/logger': 5.0.0
'@pnpm/types': 12.0.0
detect-libc: 2.0.3
execa: safe-execa@0.1.2
mem: 8.1.1
semver: 7.6.2
'@pnpm/package-is-installable@9.0.6(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/cli-meta': 6.1.0
@@ -15574,19 +15545,6 @@ snapshots:
'@pnpm/patching.types@1.0.0': {}
'@pnpm/pnpmfile@6.0.9(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.0.0)
'@pnpm/crypto.base32-hash': 3.0.0
'@pnpm/error': 6.0.1
'@pnpm/hooks.types': 2.0.7
'@pnpm/lockfile.types': 1.0.1
'@pnpm/logger': 5.0.0
'@pnpm/store-controller-types': 18.1.4
'@pnpm/types': 12.0.0
chalk: 4.1.2
path-absolute: 1.0.1
'@pnpm/pnpmfile@6.0.9(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/core-loggers': 10.0.5(@pnpm/logger@5.2.0)
@@ -15686,14 +15644,6 @@ snapshots:
dependencies:
isexe: 2.0.0
'@pnpm/workspace.find-packages@4.0.6(@pnpm/logger@5.0.0)':
dependencies:
'@pnpm/cli-utils': 4.0.1(@pnpm/logger@5.0.0)
'@pnpm/fs.find-packages': 4.0.2
'@pnpm/logger': 5.0.0
'@pnpm/types': 12.0.0
'@pnpm/util.lex-comparator': 3.0.0
'@pnpm/workspace.find-packages@4.0.6(@pnpm/logger@5.2.0)':
dependencies:
'@pnpm/cli-utils': 4.0.1(@pnpm/logger@5.2.0)
@@ -15820,12 +15770,12 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/responselike': 1.0.3
'@types/cross-spawn@6.0.6':
dependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/emscripten@1.39.13': {}
@@ -15836,7 +15786,7 @@ snapshots:
'@types/glob@8.1.0':
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/graceful-fs@4.1.9':
dependencies:
@@ -15848,7 +15798,7 @@ snapshots:
'@types/http-proxy@1.17.14':
dependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/ini@1.3.31': {}
@@ -15883,7 +15833,7 @@ snapshots:
'@types/keyv@3.1.4':
dependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/lodash.clonedeep@4.5.9':
dependencies:
@@ -15926,7 +15876,6 @@ snapshots:
'@types/node@22.2.0':
dependencies:
undici-types: 6.13.0
optional: true
'@types/normalize-package-data@2.4.4': {}
@@ -15944,7 +15893,7 @@ snapshots:
'@types/responselike@1.0.3':
dependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
'@types/retry@0.12.5': {}
@@ -18880,7 +18829,7 @@ snapshots:
'@jest/expect': 29.7.0
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
co: 4.6.0
dedent: 1.5.3
@@ -18953,7 +18902,7 @@ snapshots:
- babel-plugin-macros
- supports-color
jest-config@29.7.0(@babel/types@7.24.7)(@types/node@20.14.9)(ts-node@10.9.2(@types/node@18.19.34)(typescript@5.5.4)):
jest-config@29.7.0(@babel/types@7.24.7)(@types/node@22.2.0)(ts-node@10.9.2(@types/node@18.19.34)(typescript@5.5.4)):
dependencies:
'@babel/core': 7.24.7
'@jest/test-sequencer': 29.7.0
@@ -18978,7 +18927,7 @@ snapshots:
slash: 3.0.0
strip-json-comments: 3.1.1
optionalDependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
ts-node: 10.9.2(@types/node@18.19.34)(typescript@5.5.4)
transitivePeerDependencies:
- '@babel/types'
@@ -19009,7 +18958,7 @@ snapshots:
'@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
jest-mock: 29.7.0
jest-util: 29.7.0
@@ -19019,7 +18968,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.9
'@types/node': 20.14.9
'@types/node': 22.2.0
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11(patch_hash=ivtm2a2cfr5pomcfbedhmr5v2q)
@@ -19058,7 +19007,7 @@ snapshots:
jest-mock@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
jest-util: 29.7.0
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@@ -19093,7 +19042,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0(@babel/types@7.24.7)
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11(patch_hash=ivtm2a2cfr5pomcfbedhmr5v2q)
@@ -19122,7 +19071,7 @@ snapshots:
'@jest/test-result': 29.7.0
'@jest/transform': 29.7.0(@babel/types@7.24.7)
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
cjs-module-lexer: 1.3.1
collect-v8-coverage: 1.0.2
@@ -19169,7 +19118,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11(patch_hash=ivtm2a2cfr5pomcfbedhmr5v2q)
@@ -19188,7 +19137,7 @@ snapshots:
dependencies:
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
'@types/node': 20.14.9
'@types/node': 22.2.0
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -19197,7 +19146,7 @@ snapshots:
jest-worker@29.7.0:
dependencies:
'@types/node': 20.14.9
'@types/node': 22.2.0
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -21456,8 +21405,7 @@ snapshots:
undici-types@5.26.5: {}
undici-types@6.13.0:
optional: true
undici-types@6.13.0: {}
unified@9.2.2:
dependencies:

View File

@@ -24,6 +24,7 @@ packages:
- pkg-manifest/*
- patching/*
- pnpm
- tools/*
- worker
- pnpm/artifacts/*
- releasing/*

View File

@@ -73,6 +73,8 @@
"@pnpm/tabtab": "catalog:",
"@pnpm/test-fixtures": "workspace:*",
"@pnpm/test-ipc-server": "workspace:*",
"@pnpm/tools.path": "workspace:*",
"@pnpm/tools.plugin-commands-self-updater": "workspace:*",
"@pnpm/types": "workspace:*",
"@pnpm/worker": "workspace:*",
"@pnpm/workspace.find-packages": "workspace:*",

View File

@@ -7,6 +7,7 @@ import { doctor } from '@pnpm/plugin-commands-doctor'
import { env } from '@pnpm/plugin-commands-env'
import { deploy } from '@pnpm/plugin-commands-deploy'
import { add, ci, dedupe, fetch, install, link, prune, remove, unlink, update, importCommand } from '@pnpm/plugin-commands-installation'
import { selfUpdate } from '@pnpm/tools.plugin-commands-self-updater'
import { list, ll, why } from '@pnpm/plugin-commands-listing'
import { licenses } from '@pnpm/plugin-commands-licenses'
import { outdated } from '@pnpm/plugin-commands-outdated'
@@ -120,6 +121,7 @@ const commands: CommandDefinition[] = [
fetch,
generateCompletion,
importCommand,
selfUpdate,
init,
install,
installTest,

View File

@@ -105,7 +105,7 @@ export async function main (inputArgv: string[]): Promise<void> {
checkUnknownSetting: false,
ignoreNonAuthSettingsFromLocal: isDlxCommand,
}) as typeof config
if (!isExecutedByCorepack() && cmd !== 'setup' && config.wantedPackageManager != null) {
if (!isExecutedByCorepack() && cmd !== 'setup' && cmd !== 'self-update' && config.wantedPackageManager != null) {
if (config.managePackageManagerVersions) {
await switchCliVersion(config)
} else {

View File

@@ -2,8 +2,9 @@ import fs from 'fs'
import path from 'path'
import { type Config } from '@pnpm/config'
import { globalWarn } from '@pnpm/logger'
import { detectIfCurrentPkgIsExecutable, packageManager } from '@pnpm/cli-meta'
import { getCurrentPackageName, packageManager } from '@pnpm/cli-meta'
import { prependDirsToPath } from '@pnpm/env.path'
import { getToolDirPath } from '@pnpm/tools.path'
import spawn from 'cross-spawn'
import semver from 'semver'
import { pnpmCmds } from './cmd'
@@ -15,8 +16,14 @@ export async function switchCliVersion (config: Config): Promise<void> {
globalWarn(`Cannot switch to pnpm@${pm.version}: "${pm.version}" is not a valid version`)
return
}
const pkgName = detectIfCurrentPkgIsExecutable() ? getExePackageName() : 'pnpm'
const dir = path.join(config.pnpmHomeDir, '.tools', pkgName.replaceAll('/', '+'), pm.version)
const pkgName = getCurrentPackageName()
const dir = getToolDirPath({
pnpmHomeDir: config.pnpmHomeDir,
tool: {
name: pkgName,
version: pm.version,
},
})
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true })
fs.writeFileSync(path.join(dir, 'package.json'), '{}')
@@ -40,14 +47,3 @@ export async function switchCliVersion (config: Config): Promise<void> {
})
process.exit(status ?? 0)
}
function getExePackageName () {
const platform = process.platform === 'win32'
? 'win'
: process.platform === 'darwin'
? 'macos'
: process.platform
const arch = platform === 'win' && process.arch === 'ia32' ? 'x86' : process.arch
return `@pnpm/${platform}-${arch}`
}

View File

@@ -153,6 +153,12 @@
{
"path": "../store/plugin-commands-store-inspecting"
},
{
"path": "../tools/path"
},
{
"path": "../tools/plugin-commands-self-updater"
},
{
"path": "../worker"
},

15
tools/path/README.md Normal file
View File

@@ -0,0 +1,15 @@
# @pnpm/tools.path
> Path to tools
[![npm version](https://img.shields.io/npm/v/@pnpm/tools.path.svg)](https://www.npmjs.com/package/@pnpm/tools.path)
## Installation
```
pnpm add @pnpm/tools.path
```
## License
MIT

39
tools/path/package.json Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "@pnpm/tools.path",
"version": "0.0.0",
"description": "Path to tools",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"!*.map"
],
"scripts": {
"lint": "eslint \"src/**/*.ts\"",
"prepublishOnly": "pnpm run compile",
"test": "pnpm run compile",
"compile": "tsc --build && pnpm run lint --fix"
},
"repository": "https://github.com/pnpm/pnpm/blob/main/tools/path",
"keywords": [
"pnpm9",
"pnpm"
],
"engines": {
"node": ">=18.12"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"homepage": "https://github.com/pnpm/pnpm/blob/main/tools/path#readme",
"dependencies": {
},
"devDependencies": {
"@pnpm/tools.path": "workspace:*"
},
"funding": "https://opencollective.com/pnpm",
"exports": {
".": "./lib/index.js"
}
}

13
tools/path/src/index.ts Normal file
View File

@@ -0,0 +1,13 @@
import path from 'path'
export function getToolDirPath (
opts: {
pnpmHomeDir: string
tool: {
name: string
version: string
}
}
): string {
return path.join(opts.pnpmHomeDir, '.tools', opts.tool.name.replaceAll('/', '+'), opts.tool.version)
}

12
tools/path/tsconfig.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "@pnpm/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": [
"src/**/*.ts",
"../../__typings__/**/*.d.ts"
],
"references": []
}

View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"../../__typings__/**/*.d.ts"
]
}

View File

@@ -0,0 +1,15 @@
# @pnpm/tools.plugin-commands-self-updater
> A command for updating pnpm itself
[![npm version](https://img.shields.io/npm/v/@pnpm/tools.plugin-commands-self-updater.svg)](https://www.npmjs.com/package/@pnpm/tools.plugin-commands-self-updater)
## Installation
```
pnpm add @pnpm/tools.plugin-commands-self-updater
```
## License
MIT

View File

@@ -0,0 +1,3 @@
const config = require('../../jest.config.js');
module.exports = Object.assign({}, config, {});

View File

@@ -0,0 +1,60 @@
{
"name": "@pnpm/tools.plugin-commands-self-updater",
"version": "0.0.0",
"description": "A command for updating pnpm itself",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"!*.map"
],
"scripts": {
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
"prepublishOnly": "pnpm run compile",
"test": "pnpm run compile && pnpm run _test",
"compile": "tsc --build && pnpm run lint --fix",
"_test": "jest"
},
"repository": "https://github.com/pnpm/pnpm/blob/main/tools/plugin-commands-self-updater",
"keywords": [
"pnpm9",
"pnpm"
],
"engines": {
"node": ">=18.12"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"homepage": "https://github.com/pnpm/pnpm/blob/main/tools/plugin-commands-self-updater#readme",
"dependencies": {
"@pnpm/cli-meta": "workspace:*",
"@pnpm/cli-utils": "workspace:*",
"@pnpm/client": "workspace:*",
"@pnpm/config": "workspace:*",
"@pnpm/error": "workspace:*",
"@pnpm/link-bins": "workspace:*",
"@pnpm/pick-registry-for-package": "workspace:*",
"@pnpm/plugin-commands-installation": "workspace:*",
"@pnpm/tools.path": "workspace:*",
"ramda": "catalog:",
"render-help": "catalog:"
},
"devDependencies": {
"@pnpm/env.path": "workspace:*",
"@pnpm/prepare": "workspace:*",
"@pnpm/tools.plugin-commands-self-updater": "workspace:*",
"@types/cross-spawn": "catalog:",
"@types/ramda": "catalog:",
"cross-spawn": "catalog:",
"nock": "catalog:"
},
"peerDependencies": {
"@pnpm/logger": "^5.1.0"
},
"funding": "https://opencollective.com/pnpm",
"exports": {
".": "./lib/index.js"
}
}

View File

@@ -0,0 +1,3 @@
import * as selfUpdate from './selfUpdate'
export { selfUpdate }

View File

@@ -0,0 +1,88 @@
import fs from 'fs'
import path from 'path'
import { docsUrl } from '@pnpm/cli-utils'
import { getCurrentPackageName, packageManager, isExecutedByCorepack } from '@pnpm/cli-meta'
import { createResolver } from '@pnpm/client'
import { pickRegistryForPackage } from '@pnpm/pick-registry-for-package'
import { types as allTypes } from '@pnpm/config'
import { PnpmError } from '@pnpm/error'
import { globalWarn } from '@pnpm/logger'
import { add, type InstallCommandOptions } from '@pnpm/plugin-commands-installation'
import { getToolDirPath } from '@pnpm/tools.path'
import { linkBins } from '@pnpm/link-bins'
import pick from 'ramda/src/pick'
import renderHelp from 'render-help'
export function rcOptionsTypes (): Record<string, unknown> {
return pick([], allTypes)
}
export function cliOptionsTypes (): Record<string, unknown> {
return {
...rcOptionsTypes(),
}
}
export const commandNames = ['self-update']
export function help (): string {
return renderHelp({
description: 'Updates pnpm to the latest version',
descriptionLists: [],
url: docsUrl('self-update'),
usages: [],
})
}
export type SelfUpdateCommandOptions = InstallCommandOptions
export async function handler (
opts: SelfUpdateCommandOptions
): Promise<undefined | string> {
if (isExecutedByCorepack()) {
throw new PnpmError('CANT_SELF_UPDATE_IN_COREPACK', 'You should update pnpm with corepack')
}
const { resolve } = createResolver({ ...opts, authConfig: opts.rawConfig })
const pkgName = 'pnpm'
const resolution = await resolve({ alias: pkgName, pref: 'latest' }, {
lockfileDir: opts.lockfileDir ?? opts.dir,
preferredVersions: {},
projectDir: opts.dir,
registry: pickRegistryForPackage(opts.registries, pkgName, 'latest'),
})
if (!resolution?.manifest) {
throw new PnpmError('CANNOT_RESOLVE_PNPM', 'Cannot find latest version of pnpm')
}
if (resolution.manifest.version === packageManager.version) {
return `The currently active ${packageManager.name} v${packageManager.version} is already "latest" and doesn't need an update`
}
const currentPkgName = getCurrentPackageName()
const dir = getToolDirPath({
pnpmHomeDir: opts.pnpmHomeDir,
tool: {
name: currentPkgName,
version: resolution.manifest.version,
},
})
if (fs.existsSync(dir)) {
await linkBins(path.join(dir, opts.modulesDir ?? 'node_modules'), opts.pnpmHomeDir,
{
warn: globalWarn,
}
)
return `The latest version, v${resolution.manifest.version}, is already present on the system. It was activated by linking it from ${dir}.`
}
fs.mkdirSync(dir, { recursive: true })
fs.writeFileSync(path.join(dir, 'package.json'), '{}')
await add.handler(
{
...opts,
dir,
lockfileDir: dir,
bin: opts.pnpmHomeDir,
},
[`${currentPkgName}@${resolution.manifest.version}`]
)
return undefined
}

View File

Binary file not shown.

View File

@@ -0,0 +1,168 @@
import fs from 'fs'
import path from 'path'
import { prependDirsToPath } from '@pnpm/env.path'
import { tempDir } from '@pnpm/prepare'
import { selfUpdate } from '@pnpm/tools.plugin-commands-self-updater'
import spawn from 'cross-spawn'
import nock from 'nock'
jest.mock('@pnpm/cli-meta', () => {
const actualModule = jest.requireActual('@pnpm/cli-meta')
return {
...actualModule,
packageManager: {
name: 'pnpm',
version: '9.0.0',
},
}
})
afterEach(() => {
nock.cleanAll()
nock.disableNetConnect()
})
beforeEach(() => {
nock.enableNetConnect()
})
function prepare () {
const dir = tempDir(false)
return {
argv: {
original: [],
},
cliOptions: {},
linkWorkspacePackages: true,
bail: true,
pnpmHomeDir: dir,
registries: {
default: 'https://registry.npmjs.org/',
},
rawLocalConfig: {},
sort: false,
rootProjectManifestDir: process.cwd(),
bin: process.cwd(),
workspaceConcurrency: 1,
extraEnv: {},
pnpmfile: '',
rawConfig: {},
cacheDir: path.join(dir, '.cache'),
virtualStoreDirMaxLength: 120,
dir: process.cwd(),
}
}
test('self-update', async () => {
const opts = prepare()
nock(opts.registries.default)
.get('/pnpm')
.reply(200, {
name: 'pnpm',
'dist-tags': {
latest: '9.1.0',
},
versions: {
'9.1.0': {
name: 'pnpm',
version: '9.1.0',
dist: {
shasum: '217063ce3fcbf44f3051666f38b810f1ddefee4a',
tarball: `${opts.registries.default}pnpm/-/pnpm-9.1.0.tgz`,
fileCount: 880,
integrity: 'sha512-Z/WHmRapKT5c8FnCOFPVcb6vT3U8cH9AyyK+1fsVeMaq07bEEHzLO6CzW+AD62IaFkcayDbIe+tT+dVLtGEnJA==',
},
},
},
})
nock(opts.registries.default)
.get('/pnpm/-/pnpm-9.1.0.tgz')
.replyWithFile(200, path.join(__dirname, 'pnpm-9.1.0.tgz'))
await selfUpdate.handler(opts)
const pnpmPkgJson = JSON.parse(fs.readFileSync(path.join(opts.pnpmHomeDir, '.tools/pnpm/9.1.0/node_modules/pnpm/package.json'), 'utf8'))
expect(pnpmPkgJson.version).toBe('9.1.0')
const pnpmEnv = prependDirsToPath([opts.pnpmHomeDir])
const { status, stdout } = spawn.sync('pnpm', ['-v'], {
env: {
...process.env,
[pnpmEnv.name]: pnpmEnv.value,
},
})
expect(status).toBe(0)
expect(stdout.toString().trim()).toBe('9.1.0')
})
test('self-update does nothing when pnpm is up to date', async () => {
const opts = prepare()
nock(opts.registries.default)
.get('/pnpm')
.reply(200, {
name: 'pnpm',
'dist-tags': {
latest: '9.0.0',
},
versions: {
'9.0.0': {
name: 'pnpm',
version: '9.0.0',
dist: {
shasum: '217063ce3fcbf44f3051666f38b810f1ddefee4a',
tarball: `${opts.registries.default}pnpm/-/pnpm-9.1.0.tgz`,
fileCount: 880,
integrity: 'sha512-Z/WHmRapKT5c8FnCOFPVcb6vT3U8cH9AyyK+1fsVeMaq07bEEHzLO6CzW+AD62IaFkcayDbIe+tT+dVLtGEnJA==',
},
},
},
})
const output = await selfUpdate.handler(opts)
expect(output).toBe('The currently active pnpm v9.0.0 is already "latest" and doesn\'t need an update')
})
test('self-update links pnpm that is already present on the disk', async () => {
const opts = prepare()
nock(opts.registries.default)
.get('/pnpm')
.reply(200, {
name: 'pnpm',
'dist-tags': {
latest: '9.2.0',
},
versions: {
'9.2.0': {
name: 'pnpm',
version: '9.2.0',
dist: {
shasum: '217063ce3fcbf44f3051666f38b810f1ddefee4a',
tarball: `${opts.registries.default}pnpm/-/pnpm-9.2.0.tgz`,
fileCount: 880,
integrity: 'sha512-Z/WHmRapKT5c8FnCOFPVcb6vT3U8cH9AyyK+1fsVeMaq07bEEHzLO6CzW+AD62IaFkcayDbIe+tT+dVLtGEnJA==',
},
},
},
})
const latestPnpmDir = path.join(opts.pnpmHomeDir, '.tools/pnpm/9.2.0/node_modules/pnpm')
fs.mkdirSync(latestPnpmDir, { recursive: true })
fs.writeFileSync(path.join(latestPnpmDir, 'package.json'), JSON.stringify({ name: 'pnpm', bin: 'bin.js' }), 'utf8')
fs.writeFileSync(path.join(latestPnpmDir, 'bin.js'), `#!/usr/bin/env node
console.log('9.2.0')`, 'utf8')
const output = await selfUpdate.handler(opts)
expect(output).toBe(`The latest version, v9.2.0, is already present on the system. It was activated by linking it from ${path.join(latestPnpmDir, '../..')}.`)
const pnpmEnv = prependDirsToPath([opts.pnpmHomeDir])
const { status, stdout } = spawn.sync('pnpm', ['-v'], {
env: {
...process.env,
[pnpmEnv.name]: pnpmEnv.value,
},
})
expect(status).toBe(0)
expect(stdout.toString().trim()).toBe('9.2.0')
})

View File

@@ -0,0 +1,17 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "../test.lib",
"rootDir": "."
},
"include": [
"**/*.ts",
"../../../__typings__/**/*.d.ts"
],
"references": [
{
"path": ".."
}
]
}

View File

@@ -0,0 +1,46 @@
{
"extends": "@pnpm/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": [
"src/**/*.ts",
"../../__typings__/**/*.d.ts"
],
"references": [
{
"path": "../../__utils__/prepare"
},
{
"path": "../../cli/cli-meta"
},
{
"path": "../../cli/cli-utils"
},
{
"path": "../../config/config"
},
{
"path": "../../config/pick-registry-for-package"
},
{
"path": "../../env/path"
},
{
"path": "../../packages/error"
},
{
"path": "../../pkg-manager/client"
},
{
"path": "../../pkg-manager/link-bins"
},
{
"path": "../../pkg-manager/plugin-commands-installation"
},
{
"path": "../path"
}
]
}

View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"../../__typings__/**/*.d.ts"
]
}