Skip to content

Commit

Permalink
refactor: plugin-commands-env
Browse files Browse the repository at this point in the history
  • Loading branch information
zkochan committed Nov 13, 2022
1 parent f60d6c4 commit 9ad96e2
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 108 deletions.
113 changes: 7 additions & 106 deletions packages/plugin-commands-env/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import { promises as fs, existsSync } from 'fs'
import path from 'path'
import { docsUrl } from '@pnpm/cli-utils'
import { PnpmError } from '@pnpm/error'
import { createFetchFromRegistry } from '@pnpm/fetch'
import { resolveNodeVersion } from '@pnpm/node.resolver'
import { globalInfo } from '@pnpm/logger'
import { removeBin } from '@pnpm/remove-bins'
import cmdShim from '@zkochan/cmd-shim'
import rimraf from '@zkochan/rimraf'
import renderHelp from 'render-help'
import { getNodeDir, NvmNodeCommandOptions, getNodeVersionsBaseDir } from './node'
import { getNodeMirror } from './getNodeMirror'
import { parseNodeEditionSpecifier } from './parseNodeEditionSpecifier'
import { listLocalVersions, listRemoteVersions } from './envList'
import { getNodeExecPathInBinDir, getNodeExecPathAndTargetDir, getNodeExecPathInNodeDir } from './utils'
import { envRemove } from './envRemove'
import { envUse } from './envUse'
import { NvmNodeCommandOptions } from './node'
import { envList } from './envList'

export function rcOptionsTypes () {
return {}
Expand Down Expand Up @@ -96,107 +87,17 @@ export async function handler (opts: NvmNodeCommandOptions, params: string[]) {
}
switch (params[0]) {
case 'use': {
if (!opts.global) {
throw new PnpmError('NOT_IMPLEMENTED_YET', '"pnpm env use <version>" can only be used with the "--global" option currently')
}
const fetch = createFetchFromRegistry(opts)
const { releaseChannel, versionSpecifier } = parseNodeEditionSpecifier(params[1])
const nodeMirrorBaseUrl = getNodeMirror(opts.rawConfig, releaseChannel)
const nodeVersion = await resolveNodeVersion(fetch, versionSpecifier, nodeMirrorBaseUrl)
if (!nodeVersion) {
throw new PnpmError('COULD_NOT_RESOLVE_NODEJS', `Couldn't find Node.js version matching ${params[1]}`)
}
const nodeDir = await getNodeDir(fetch, {
...opts,
useNodeVersion: nodeVersion,
nodeMirrorBaseUrl,
})
const src = getNodeExecPathInNodeDir(nodeDir)
const dest = getNodeExecPathInBinDir(opts.bin)
try {
await fs.unlink(dest)
} catch (err) {}
await fs.symlink(src, dest, 'file')
try {
let npmDir = nodeDir
if (process.platform !== 'win32') {
npmDir = path.join(npmDir, 'lib')
}
npmDir = path.join(npmDir, 'node_modules/npm')
if (opts.configDir) {
// We want the global npm settings to persist when Node.js or/and npm is changed to a different version,
// so we tell npm to read the global config from centralized place that is outside of npm's directory.
await fs.writeFile(path.join(npmDir, 'npmrc'), `globalconfig=${path.join(opts.configDir, 'npmrc')}`, 'utf-8')
}
const npmBinDir = path.join(npmDir, 'bin')
const cmdShimOpts = { createPwshFile: false }
await cmdShim(path.join(npmBinDir, 'npm-cli.js'), path.join(opts.bin, 'npm'), cmdShimOpts)
await cmdShim(path.join(npmBinDir, 'npx-cli.js'), path.join(opts.bin, 'npx'), cmdShimOpts)
} catch (err: any) { // eslint-disable-line
// ignore
}
return `Node.js ${nodeVersion as string} is activated
${dest} -> ${src}`
return envUse(opts, params.slice(1))
}
case 'remove':
case 'rm':
case 'uninstall':
case 'un': {
if (!opts.global) {
throw new PnpmError('NOT_IMPLEMENTED_YET', '"pnpm env use <version>" can only be used with the "--global" option currently')
}

const fetch = createFetchFromRegistry(opts)
const { releaseChannel, versionSpecifier } = parseNodeEditionSpecifier(params[1])
const nodeMirrorBaseUrl = getNodeMirror(opts.rawConfig, releaseChannel)
const nodeVersion = await resolveNodeVersion(fetch, versionSpecifier, nodeMirrorBaseUrl)
const nodeDir = getNodeVersionsBaseDir(opts.pnpmHomeDir)

if (!nodeVersion) {
throw new PnpmError('COULD_NOT_RESOLVE_NODEJS', `Couldn't find Node.js version matching ${params[1]}`)
}

const versionDir = path.resolve(nodeDir, nodeVersion)

if (!existsSync(versionDir)) {
throw new PnpmError('ENV_NO_NODE_DIRECTORY', `Couldn't find Node.js directory in ${versionDir}`)
}

const { nodePath, nodeLink } = await getNodeExecPathAndTargetDir(opts.pnpmHomeDir)

if (nodeLink?.includes(versionDir)) {
globalInfo(`Node.js version ${nodeVersion as string} was detected as the default one, removing ...`)

const npmPath = path.resolve(opts.pnpmHomeDir, 'npm')
const npxPath = path.resolve(opts.pnpmHomeDir, 'npx')

try {
await Promise.all([
removeBin(nodePath),
removeBin(npmPath),
removeBin(npxPath),
])
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') throw err
}
}

await rimraf(versionDir)

return `Node.js ${nodeVersion as string} is removed
${versionDir}`
return envRemove(opts, params.slice(1))
}
case 'list':
case 'ls': {
if (opts.remote) {
const nodeVersionList = await listRemoteVersions(opts, params[1])
// Make the newest version located in the end of output
return nodeVersionList.reverse().join('\n')
}
const { currentVersion, versions } = await listLocalVersions(opts)
return versions
.map(nodeVersion => `${nodeVersion === currentVersion ? '*' : ' '} ${nodeVersion}`)
.join('\n')
return envList(opts, params.slice(1))
}
default: {
throw new PnpmError('ENV_UNKNOWN_SUBCOMMAND', 'This subcommand is not known')
Expand Down
16 changes: 14 additions & 2 deletions packages/plugin-commands-env/src/envList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ import { getNodeVersionsBaseDir, NvmNodeCommandOptions } from './node'
import { parseNodeEditionSpecifier } from './parseNodeEditionSpecifier'
import { getNodeExecPathAndTargetDir, getNodeExecPathInNodeDir } from './utils'

export async function listLocalVersions (opts: NvmNodeCommandOptions) {
export async function envList (opts: NvmNodeCommandOptions, params: string[]) {
if (opts.remote) {
const nodeVersionList = await listRemoteVersions(opts, params[0])
// Make the newest version located in the end of output
return nodeVersionList.reverse().join('\n')
}
const { currentVersion, versions } = await listLocalVersions(opts)
return versions
.map(nodeVersion => `${nodeVersion === currentVersion ? '*' : ' '} ${nodeVersion}`)
.join('\n')
}

async function listLocalVersions (opts: NvmNodeCommandOptions) {
const nodeBaseDir = getNodeVersionsBaseDir(opts.pnpmHomeDir)
if (!existsSync(nodeBaseDir)) {
throw new PnpmError('ENV_NO_NODE_DIRECTORY', `Couldn't find Node.js directory in ${nodeBaseDir}`)
Expand All @@ -29,7 +41,7 @@ export async function listLocalVersions (opts: NvmNodeCommandOptions) {
}, { currentVersion: undefined as string | undefined, versions: [] as string[] })
}

export async function listRemoteVersions (opts: NvmNodeCommandOptions, versionSpec?: string) {
async function listRemoteVersions (opts: NvmNodeCommandOptions, versionSpec?: string) {
const fetch = createFetchFromRegistry(opts)
const { releaseChannel, versionSpecifier } = parseNodeEditionSpecifier(versionSpec ?? '')
const nodeMirrorBaseUrl = getNodeMirror(opts.rawConfig, releaseChannel)
Expand Down
58 changes: 58 additions & 0 deletions packages/plugin-commands-env/src/envRemove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { existsSync } from 'fs'
import path from 'path'
import { PnpmError } from '@pnpm/error'
import { createFetchFromRegistry } from '@pnpm/fetch'
import { globalInfo } from '@pnpm/logger'
import { resolveNodeVersion } from '@pnpm/node.resolver'
import { removeBin } from '@pnpm/remove-bins'
import rimraf from '@zkochan/rimraf'
import { parseNodeEditionSpecifier } from './parseNodeEditionSpecifier'
import { getNodeExecPathAndTargetDir } from './utils'
import { getNodeMirror } from './getNodeMirror'
import { getNodeVersionsBaseDir, NvmNodeCommandOptions } from './node'

export async function envRemove (opts: NvmNodeCommandOptions, params: string[]) {
if (!opts.global) {
throw new PnpmError('NOT_IMPLEMENTED_YET', '"pnpm env use <version>" can only be used with the "--global" option currently')
}

const fetch = createFetchFromRegistry(opts)
const { releaseChannel, versionSpecifier } = parseNodeEditionSpecifier(params[0])
const nodeMirrorBaseUrl = getNodeMirror(opts.rawConfig, releaseChannel)
const nodeVersion = await resolveNodeVersion(fetch, versionSpecifier, nodeMirrorBaseUrl)
const nodeDir = getNodeVersionsBaseDir(opts.pnpmHomeDir)

if (!nodeVersion) {
throw new PnpmError('COULD_NOT_RESOLVE_NODEJS', `Couldn't find Node.js version matching ${params[0]}`)
}

const versionDir = path.resolve(nodeDir, nodeVersion)

if (!existsSync(versionDir)) {
throw new PnpmError('ENV_NO_NODE_DIRECTORY', `Couldn't find Node.js directory in ${versionDir}`)
}

const { nodePath, nodeLink } = await getNodeExecPathAndTargetDir(opts.pnpmHomeDir)

if (nodeLink?.includes(versionDir)) {
globalInfo(`Node.js version ${nodeVersion as string} was detected as the default one, removing ...`)

const npmPath = path.resolve(opts.pnpmHomeDir, 'npm')
const npxPath = path.resolve(opts.pnpmHomeDir, 'npx')

try {
await Promise.all([
removeBin(nodePath),
removeBin(npmPath),
removeBin(npxPath),
])
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') throw err
}
}

await rimraf(versionDir)

return `Node.js ${nodeVersion as string} is removed
${versionDir}`
}
54 changes: 54 additions & 0 deletions packages/plugin-commands-env/src/envUse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { promises as fs } from 'fs'
import path from 'path'
import { PnpmError } from '@pnpm/error'
import { createFetchFromRegistry } from '@pnpm/fetch'
import { resolveNodeVersion } from '@pnpm/node.resolver'
import cmdShim from '@zkochan/cmd-shim'
import { getNodeDir, NvmNodeCommandOptions } from './node'
import { getNodeMirror } from './getNodeMirror'
import { parseNodeEditionSpecifier } from './parseNodeEditionSpecifier'
import { getNodeExecPathInBinDir, getNodeExecPathInNodeDir } from './utils'

export async function envUse (opts: NvmNodeCommandOptions, params: string[]) {
if (!opts.global) {
throw new PnpmError('NOT_IMPLEMENTED_YET', '"pnpm env use <version>" can only be used with the "--global" option currently')
}
const fetch = createFetchFromRegistry(opts)
const { releaseChannel, versionSpecifier } = parseNodeEditionSpecifier(params[0])
const nodeMirrorBaseUrl = getNodeMirror(opts.rawConfig, releaseChannel)
const nodeVersion = await resolveNodeVersion(fetch, versionSpecifier, nodeMirrorBaseUrl)
if (!nodeVersion) {
throw new PnpmError('COULD_NOT_RESOLVE_NODEJS', `Couldn't find Node.js version matching ${params[0]}`)
}
const nodeDir = await getNodeDir(fetch, {
...opts,
useNodeVersion: nodeVersion,
nodeMirrorBaseUrl,
})
const src = getNodeExecPathInNodeDir(nodeDir)
const dest = getNodeExecPathInBinDir(opts.bin)
try {
await fs.unlink(dest)
} catch (err) {}
await fs.symlink(src, dest, 'file')
try {
let npmDir = nodeDir
if (process.platform !== 'win32') {
npmDir = path.join(npmDir, 'lib')
}
npmDir = path.join(npmDir, 'node_modules/npm')
if (opts.configDir) {
// We want the global npm settings to persist when Node.js or/and npm is changed to a different version,
// so we tell npm to read the global config from centralized place that is outside of npm's directory.
await fs.writeFile(path.join(npmDir, 'npmrc'), `globalconfig=${path.join(opts.configDir, 'npmrc')}`, 'utf-8')
}
const npmBinDir = path.join(npmDir, 'bin')
const cmdShimOpts = { createPwshFile: false }
await cmdShim(path.join(npmBinDir, 'npm-cli.js'), path.join(opts.bin, 'npm'), cmdShimOpts)
await cmdShim(path.join(npmBinDir, 'npx-cli.js'), path.join(opts.bin, 'npx'), cmdShimOpts)
} catch (err: any) { // eslint-disable-line
// ignore
}
return `Node.js ${nodeVersion as string} is activated
${dest} -> ${src}`
}

0 comments on commit 9ad96e2

Please sign in to comment.