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:
liuxingbaoyu
2022-05-11 01:04:14 +08:00
committed by GitHub
parent 52b0576af4
commit 460ccf60e5
9 changed files with 89 additions and 19 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/plugin-commands-setup": patch
---
fix: make `pnpm setup` free of garbled characters.

View File

@@ -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')
}

View File

@@ -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')
})

View File

@@ -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')
})

View File

@@ -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')
})

View File

@@ -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')

View File

@@ -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')
})

View File

@@ -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}'`)
})

View File

@@ -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')
})
})