mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-05 07:46:10 -04:00
fix: make pnpm setup free of garbled characters (#4712)
The output used to be garbled on non-English systems, but not anymore.
This commit is contained in:
5
.changeset/dirty-dryers-lie.md
Normal file
5
.changeset/dirty-dryers-lie.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-setup": patch
|
||||
---
|
||||
|
||||
fix: make `pnpm setup` free of garbled characters.
|
||||
@@ -12,7 +12,8 @@ function findEnvValuesInRegistry (regEntries: string, envVarName: string): IEnvi
|
||||
}
|
||||
|
||||
function setEnvVarInRegistry (envVarName: string, envVarValue: string) {
|
||||
return execa('reg', ['add', REG_KEY, '/v', envVarName, '/t', 'REG_EXPAND_SZ', '/d', envVarValue, '/f'])
|
||||
// `windowsHide` in `execa` is true by default, which will cause `chcp` to have no effect.
|
||||
return execa('reg', ['add', REG_KEY, '/v', envVarName, '/t', 'REG_EXPAND_SZ', '/d', envVarValue, '/f'], { windowsHide: false })
|
||||
}
|
||||
|
||||
function pathIncludesDir (pathValue: string, dir: string): boolean {
|
||||
@@ -29,9 +30,21 @@ function pathIncludesDir (pathValue: string, dir: string): boolean {
|
||||
export async function setupWindowsEnvironmentPath (pnpmHomeDir: string, opts: { force: boolean }): Promise<string> {
|
||||
// Use `chcp` to make `reg` use utf8 encoding for output.
|
||||
// Otherwise, the non-ascii characters in the environment variables will become garbled characters.
|
||||
const queryResult = await execa(`chcp 65001>nul && reg query ${REG_KEY}`, undefined, { shell: true })
|
||||
|
||||
const chcpResult = await execa('chcp')
|
||||
const cpMatch = /\d+/.exec(chcpResult.stdout) ?? []
|
||||
const cpBak = parseInt(cpMatch[0])
|
||||
if (chcpResult.failed || cpBak === 0) {
|
||||
return `exec chcp failed: ${cpBak}, ${chcpResult.stderr}`
|
||||
}
|
||||
|
||||
await execa('chcp', ['65001'])
|
||||
|
||||
const queryResult = await execa('reg', ['query', REG_KEY], { windowsHide: false })
|
||||
|
||||
if (queryResult.failed) {
|
||||
await execa('chcp', [cpBak.toString()])
|
||||
|
||||
return 'Win32 registry environment values could not be retrieved'
|
||||
}
|
||||
|
||||
@@ -45,6 +58,8 @@ export async function setupWindowsEnvironmentPath (pnpmHomeDir: string, opts: {
|
||||
if (homeValueMatch.length === 1 && !opts.force) {
|
||||
const currentHomeDir = homeValueMatch[0].groups.data
|
||||
if (currentHomeDir !== pnpmHomeDir) {
|
||||
await execa('chcp', [cpBak.toString()])
|
||||
|
||||
throw new PnpmError('DIFFERENT_HOME_DIR_IS_SET', `Currently 'PNPM_HOME' is set to '${currentHomeDir}'`, {
|
||||
hint: 'If you want to override the existing PNPM_HOME env variable, use the --force option',
|
||||
})
|
||||
@@ -87,5 +102,7 @@ export async function setupWindowsEnvironmentPath (pnpmHomeDir: string, opts: {
|
||||
await execa('setx', ['PNPM_HOME', pnpmHomeDir])
|
||||
}
|
||||
|
||||
await execa('chcp', [cpBak.toString()])
|
||||
|
||||
return logger.join('\n')
|
||||
}
|
||||
|
||||
@@ -26,7 +26,13 @@ afterAll(() => {
|
||||
const regKey = 'HKEY_CURRENT_USER\\Environment'
|
||||
|
||||
test('Win32 registry environment values could not be retrieved', async () => {
|
||||
execa['mockResolvedValue']({
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValue({
|
||||
failed: true,
|
||||
})
|
||||
|
||||
@@ -34,6 +40,6 @@ test('Win32 registry environment values could not be retrieved', async () => {
|
||||
pnpmHomeDir: __dirname,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(output).toContain('Win32 registry environment values could not be retrieved')
|
||||
})
|
||||
|
||||
@@ -27,6 +27,12 @@ const regKey = 'HKEY_CURRENT_USER\\Environment'
|
||||
|
||||
test('Environment PATH is not configured correctly', async () => {
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: 'SOME KIND OF ERROR OR UNSUPPORTED RESPONSE FORMAT',
|
||||
}).mockResolvedValue({
|
||||
@@ -37,6 +43,6 @@ test('Environment PATH is not configured correctly', async () => {
|
||||
pnpmHomeDir: __dirname,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(output).toContain('Current PATH is not set. No changes to this environment variable are applied')
|
||||
})
|
||||
|
||||
@@ -27,11 +27,17 @@ const regKey = 'HKEY_CURRENT_USER\\Environment'
|
||||
|
||||
test('Environment PATH is empty', async () => {
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
Path REG_EXPAND_SZ
|
||||
`,
|
||||
`,
|
||||
}).mockResolvedValue({
|
||||
failed: false,
|
||||
})
|
||||
@@ -40,6 +46,6 @@ HKEY_CURRENT_USER\\Environment
|
||||
pnpmHomeDir: __dirname,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(output).toContain('Current PATH is empty. No changes to this environment variable are applied')
|
||||
})
|
||||
|
||||
@@ -29,6 +29,12 @@ test('Successful first time installation', async () => {
|
||||
const currentPathInRegistry = '%USERPROFILE%\\AppData\\Local\\Microsoft\\WindowsApps;%USERPROFILE%\\.config\\etc;'
|
||||
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
@@ -49,10 +55,10 @@ HKEY_CURRENT_USER\\Environment
|
||||
pnpmHomeDir: __dirname,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(2, 'reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_EXPAND_SZ', '/d', __dirname, '/f'])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${__dirname};${currentPathInRegistry}`, '/f'])
|
||||
expect(execa).toHaveBeenNthCalledWith(4, 'setx', ['PNPM_HOME', __dirname])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(4, 'reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_EXPAND_SZ', '/d', __dirname, '/f'], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(5, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${__dirname};${currentPathInRegistry}`, '/f'], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(6, 'setx', ['PNPM_HOME', __dirname])
|
||||
expect(output).toContain(`Setting 'PNPM_HOME' to value '${__dirname}`)
|
||||
expect(output).toContain('Updating PATH')
|
||||
expect(output).toContain('PNPM_HOME ENV VAR SET')
|
||||
|
||||
@@ -29,6 +29,12 @@ test('PNPM_HOME is already set, but path is updated', async () => {
|
||||
const currentPathInRegistry = '%USERPROFILE%\\AppData\\Local\\Microsoft\\WindowsApps;%USERPROFILE%\\.config\\etc;'
|
||||
const pnpmHomeDir = '.pnpm\\home'
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
@@ -45,9 +51,9 @@ HKEY_CURRENT_USER\\Environment
|
||||
|
||||
const output = await setup.handler({ pnpmHomeDir })
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(2, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${'.pnpm\\home'};${currentPathInRegistry}`, '/f'])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'setx', ['PNPM_HOME', '.pnpm\\home'])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(4, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${'.pnpm\\home'};${currentPathInRegistry}`, '/f'], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(5, 'setx', ['PNPM_HOME', '.pnpm\\home'])
|
||||
expect(output).toContain('Updating PATH')
|
||||
expect(output).toContain('PATH UPDATED')
|
||||
})
|
||||
|
||||
@@ -27,6 +27,12 @@ const regKey = 'HKEY_CURRENT_USER\\Environment'
|
||||
|
||||
test('setup throws an error if PNPM_HOME is already set to a different directory', async () => {
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
@@ -47,6 +53,12 @@ HKEY_CURRENT_USER\\Environment
|
||||
|
||||
test('setup overrides PNPM_HOME, when setup is forced', async () => {
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
@@ -64,6 +76,6 @@ HKEY_CURRENT_USER\\Environment
|
||||
pnpmHomeDir,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(output).toContain(`Setting 'PNPM_HOME' to value '${pnpmHomeDir}'`)
|
||||
})
|
||||
|
||||
@@ -29,6 +29,12 @@ test('Failure to install', async () => {
|
||||
const currentPathInRegistry = '%USERPROFILE%\\AppData\\Local\\Microsoft\\WindowsApps;%USERPROFILE%\\.config\\etc;'
|
||||
|
||||
execa['mockResolvedValueOnce']({
|
||||
failed: false,
|
||||
stdout: '活动代码页: 936',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: '',
|
||||
}).mockResolvedValueOnce({
|
||||
failed: false,
|
||||
stdout: `
|
||||
HKEY_CURRENT_USER\\Environment
|
||||
@@ -49,11 +55,11 @@ HKEY_CURRENT_USER\\Environment
|
||||
pnpmHomeDir: __dirname,
|
||||
})
|
||||
|
||||
expect(execa).toHaveBeenNthCalledWith(1, `chcp 65001>nul && reg query ${regKey}`, undefined, { shell: true })
|
||||
expect(execa).toHaveBeenNthCalledWith(2, 'reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_EXPAND_SZ', '/d', __dirname, '/f'])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${__dirname};${currentPathInRegistry}`, '/f'])
|
||||
expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(4, 'reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_EXPAND_SZ', '/d', __dirname, '/f'], { windowsHide: false })
|
||||
expect(execa).toHaveBeenNthCalledWith(5, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `${__dirname};${currentPathInRegistry}`, '/f'], { windowsHide: false })
|
||||
expect(output).toContain(`Setting 'PNPM_HOME' to value '${__dirname}`)
|
||||
expect(output).toContain('FAILED TO SET PNPM_HOME')
|
||||
expect(output).toContain('Updating PATH')
|
||||
expect(output).toContain('FAILED TO UPDATE PATH')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user