import { win32 as path } from 'path' import execa from 'execa' type IEnvironmentValueMatch = { groups: { name: string, type: string, data: string } } & RegExpMatchArray export async function setupWindowsEnvironmentPath (pnpmHomeDir: string): Promise { const pathRegex = /^ {4}(?PATH) {4}(?\w+) {4}(?.*)$/gim const pnpmHomeRegex = /^ {4}(?PNPM_HOME) {4}(?\w+) {4}(?.*)$/gim const regKey = 'HKEY_CURRENT_USER\\Environment' const queryResult = await execa('reg', ['query', regKey]) if (queryResult.failed) { return 'Win32 registry environment values could not be retrieved' } const queryOutput = queryResult.stdout const pathValueMatch = [...queryOutput.matchAll(pathRegex)] as IEnvironmentValueMatch[] const homeValueMatch = [...queryOutput.matchAll(pnpmHomeRegex)] as IEnvironmentValueMatch[] let commitNeeded = false let homeDir = pnpmHomeDir const logger = [] if (homeValueMatch.length === 1) { homeDir = homeValueMatch[0].groups.data logger.push(`Currently 'PNPM_HOME' is set to '${homeDir}'`) } else { logger.push(`Setting 'PNPM_HOME' to value '${homeDir}'`) const addResult = await execa('reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_EXPAND_SZ', '/d', homeDir, '/f']) if (addResult.failed) { logger.push(`\t${addResult.stderr}`) } else { commitNeeded = true logger.push(`\t${addResult.stdout}`) } } if (pathValueMatch.length === 1) { const pathData = pathValueMatch[0].groups.data if (pathData == null || pathData.trim() === '') { logger.push('Current PATH is empty. No changes to this environment variable are applied') } else { const homeDirPath = path.parse(path.normalize(homeDir)) if (pathData .split(path.delimiter) .map(p => path.normalize(p)) .map(p => path.parse(p)) .map(p => `${p.dir}${path.sep}${p.base}`.toUpperCase()) .filter(p => p !== '') .includes(`${homeDirPath.dir}${path.sep}${homeDirPath.base}`.toUpperCase())) { logger.push('PATH already contains PNPM_HOME') } else { logger.push('Updating PATH') const addResult = await execa('reg', ['add', regKey, '/v', pathValueMatch[0].groups.name, '/t', 'REG_EXPAND_SZ', '/d', `${homeDir}${path.delimiter}${pathData}`, '/f']) if (addResult.failed) { logger.push(`\t${addResult.stderr}`) } else { commitNeeded = true logger.push(`\t${addResult.stdout}`) } } } } else { logger.push('Current PATH is not set. No changes to this environment variable are applied') } if (commitNeeded) { await execa('setx', ['PNPM_HOME', homeDir]) } return logger.join('\n') }