diff --git a/bin/npm.ps1 b/bin/npm.ps1 new file mode 100644 index 0000000000000..f2f236adc23db --- /dev/null +++ b/bin/npm.ps1 @@ -0,0 +1,35 @@ +#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +} +$ret=0 + +$nodeexe = "node$exe" +$nodebin = $(Get-Command $nodeexe -ErrorAction SilentlyContinue -ErrorVariable F).Source +if ($nodebin -eq $null) { + Write-Host "$nodeexe not found." + exit 1 +} +$nodedir = $(New-Object -ComObject Scripting.FileSystemObject).GetFile("$nodebin").ParentFolder.Path + +$npmclijs="$nodedir/node_modules/npm/bin/npm-cli.js" +$npmprefix=(& $nodeexe $npmclijs prefix -g) +if ($LASTEXITCODE -ne 0) { + Write-Host "Could not determine Node.js install directory" + exit 1 +} +$npmprefixclijs="$npmprefix/node_modules/npm/bin/npm-cli.js" + +# Support pipeline input +if ($MyInvocation.ExpectingInput) { + $input | & $nodeexe $npmprefixclijs $args +} else { + & $nodeexe $npmprefixclijs $args +} +$ret=$LASTEXITCODE +exit $ret diff --git a/bin/npx.ps1 b/bin/npx.ps1 new file mode 100644 index 0000000000000..437e2a7b74c3a --- /dev/null +++ b/bin/npx.ps1 @@ -0,0 +1,35 @@ +#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +} +$ret=0 + +$nodeexe = "node$exe" +$nodebin = $(Get-Command $nodeexe -ErrorAction SilentlyContinue -ErrorVariable F).Source +if ($nodebin -eq $null) { + Write-Host "$nodeexe not found." + exit 1 +} +$nodedir = $(New-Object -ComObject Scripting.FileSystemObject).GetFile("$nodebin").ParentFolder.Path + +$npmclijs="$nodedir/node_modules/npm/bin/npm-cli.js" +$npmprefix=(& $nodeexe $npmclijs prefix -g) +if ($LASTEXITCODE -ne 0) { + Write-Host "Could not determine Node.js install directory" + exit 1 +} +$npmprefixclijs="$npmprefix/node_modules/npm/bin/npx-cli.js" + +# Support pipeline input +if ($MyInvocation.ExpectingInput) { + $input | & $nodeexe $npmprefixclijs $args +} else { + & $nodeexe $npmprefixclijs $args +} +$ret=$LASTEXITCODE +exit $ret diff --git a/test/bin/windows-shims.js b/test/bin/windows-shims.js index 6cd859001f2ed..29c257fc7954d 100644 --- a/test/bin/windows-shims.js +++ b/test/bin/windows-shims.js @@ -1,6 +1,6 @@ const t = require('tap') const { spawnSync } = require('child_process') -const { resolve, join, extname, basename } = require('path') +const { resolve, join, extname, basename, sep } = require('path') const { readFileSync, chmodSync, readdirSync } = require('fs') const Diff = require('diff') const { sync: which } = require('which') @@ -18,6 +18,12 @@ const SHIMS = readdirSync(BIN).reduce((acc, shim) => { const SHIM_EXTS = [...new Set(Object.keys(SHIMS).map(p => extname(p)))] +// windows requires each segment of a command path to be quoted when using shell: true +const quotePath = (cmd) => cmd + .split(sep) + .map(p => p.includes(' ') ? `"${p}"` : p) + .join(sep) + t.test('shim contents', t => { // these scripts should be kept in sync so this tests the contents of each // and does a diff to ensure the only differences between them are necessary @@ -49,6 +55,13 @@ t.test('shim contents', t => { t.strictSame([...letters], ['M', 'X'], 'all other changes are m->x') t.end() }) + + t.test('pwsh', t => { + const { diff, letters } = diffFiles(SHIMS['npm.ps1'], SHIMS['npx.ps1']) + t.equal(diff.length, 0) + t.strictSame([...letters], ['M', 'X'], 'all other changes are m->x') + t.end() + }) }) t.test('run shims', t => { @@ -133,6 +146,7 @@ t.test('run shims', t => { const shells = Object.entries({ cmd: 'cmd', + pwsh: 'pwsh', git: join(ProgramFiles, 'Git', 'bin', 'bash.exe'), 'user git': join(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe'), wsl: join(SystemRoot, 'System32', 'bash.exe'), @@ -197,6 +211,11 @@ t.test('run shims', t => { case 'bash.exe': args.push(bin) break + case 'pwsh.exe': + cmd = quotePath(cmd) + args.push(`${bin}.ps1`) + opts.shell = true + break default: throw new Error('unknown shell') }