Skip to content

Commit 51a8af3

Browse files
ExE-Bossisaacs
authored andcommitted
Add proper support for PowerShell
PowerShell can’t properly pass string arguments containing the `&` symbol to Windows Command Prompt scripts, if the string containing the ampersand doesn’t have spaces, due to how the cmd prompt parses the `&` as a command delimiter, even in a string. This patch adds a workaround by generating a third script specifically for PowerShell. PR-URL: #34 Credit: @ExE-Boss Close: #34 Reviewed-by: @isaacs
1 parent 49f0c13 commit 51a8af3

File tree

2 files changed

+146
-1
lines changed

2 files changed

+146
-1
lines changed

index.js

+51-1
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,22 @@ function writeShim_ (from, to, prog, args, variables, cb) {
8080
, longProg
8181
, shProg = prog && prog.split("\\").join("/")
8282
, shLongProg
83+
, pwshProg = shProg && "\"" + shProg + "$exe\""
84+
, pwshLongProg
8385
shTarget = shTarget.split("\\").join("/")
8486
args = args || ""
8587
variables = variables || ""
8688
if (!prog) {
8789
prog = "\"%~dp0\\" + target + "\""
8890
shProg = "\"$basedir/" + shTarget + "\""
91+
pwshProg = shProg
8992
args = ""
9093
target = ""
9194
shTarget = ""
9295
} else {
9396
longProg = "\"%~dp0\\" + prog + ".exe\""
9497
shLongProg = "\"$basedir/" + prog + "\""
98+
pwshLongProg = "\"$basedir/" + prog + "$exe\""
9599
target = "\"%~dp0\\" + target + "\""
96100
shTarget = "\"$basedir/" + shTarget + "\""
97101
}
@@ -170,7 +174,52 @@ function writeShim_ (from, to, prog, args, variables, cb) {
170174
+ "exit $?\n"
171175
}
172176

173-
var then = times(2, next, cb)
177+
// #!/usr/bin/env pwsh
178+
// $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
179+
//
180+
// $ret=0
181+
// $exe = ""
182+
// if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
183+
// # Fix case when both the Windows and Linux builds of Node
184+
// # are installed in the same directory
185+
// $exe = ".exe"
186+
// }
187+
// if (Test-Path "$basedir/node") {
188+
// & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
189+
// $ret=$LASTEXITCODE
190+
// } else {
191+
// & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args
192+
// $ret=$LASTEXITCODE
193+
// }
194+
// exit $ret
195+
var pwsh = "#!/usr/bin/env pwsh\n"
196+
+ "$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n"
197+
+ "\n"
198+
+ "$exe=\"\"\n"
199+
+ "if ($PSVersionTable.PSVersion -lt \"6.0\" -or $IsWindows) {\n"
200+
+ " # Fix case when both the Windows and Linux builds of Node\n"
201+
+ " # are installed in the same directory\n"
202+
+ " $exe=\".exe\"\n"
203+
+ "}\n"
204+
if (shLongProg) {
205+
pwsh = pwsh
206+
+ "$ret=0\n"
207+
+ "if (Test-Path " + pwshLongProg + ") {\n"
208+
+ " & " + pwshLongProg + " " + args + " " + shTarget + " $args\n"
209+
+ " $ret=$LASTEXITCODE\n"
210+
+ "} else {\n"
211+
+ " & " + pwshProg + " " + args + " " + shTarget + " $args\n"
212+
+ " $ret=$LASTEXITCODE\n"
213+
+ "}\n"
214+
+ "exit $ret\n"
215+
} else {
216+
pwsh = pwsh
217+
+ "& " + pwshProg + " " + args + " " + shTarget + " $args\n"
218+
+ "exit $LASTEXITCODE\n"
219+
}
220+
221+
var then = times(3, next, cb)
222+
fs.writeFile(to + ".ps1", pwsh, "utf8", then)
174223
fs.writeFile(to + ".cmd", cmd, "utf8", then)
175224
fs.writeFile(to, sh, "utf8", then)
176225
function next () {
@@ -182,6 +231,7 @@ function chmodShim (to, cb) {
182231
var then = times(2, cb, cb)
183232
fs.chmod(to, "0755", then)
184233
fs.chmod(to + ".cmd", "0755", then)
234+
fs.chmod(to + ".ps1", "0755", then)
185235
}
186236

187237
function times(n, ok, cb) {

test/basic.js

+95
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ test('no shebang', function (t) {
2323
"\n\"$basedir/from.exe\" \"$@\"\nexit $?\n")
2424
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
2525
"@\"%~dp0\\from.exe\" %*\r\n")
26+
t.equal(fs.readFileSync(to + '.ps1', 'utf8'),
27+
'#!/usr/bin/env pwsh'+
28+
'\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+
29+
'\n'+
30+
'\n$exe=""'+
31+
'\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+
32+
'\n # Fix case when both the Windows and Linux builds of Node'+
33+
'\n # are installed in the same directory'+
34+
'\n $exe=".exe"'+
35+
'\n}'+
36+
'\n& "$basedir/from.exe" $args'+
37+
'\nexit $LASTEXITCODE'+
38+
'\n')
2639
t.end()
2740
})
2841
})
@@ -105,6 +118,26 @@ test('env shebang with args', function (t) {
105118
"\n\"%_prog%\" --expose_gc \"%~dp0\\from.env.args\" %*\r" +
106119
"\n@ENDLOCAL\r" +
107120
"\n")
121+
t.equal(fs.readFileSync(to + '.ps1', 'utf8'),
122+
'#!/usr/bin/env pwsh'+
123+
'\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+
124+
'\n'+
125+
'\n$exe=""'+
126+
'\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+
127+
'\n # Fix case when both the Windows and Linux builds of Node'+
128+
'\n # are installed in the same directory'+
129+
'\n $exe=".exe"'+
130+
'\n}'+
131+
'\n$ret=0'+
132+
'\nif (Test-Path "$basedir/node$exe") {'+
133+
'\n & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args'+
134+
'\n $ret=$LASTEXITCODE'+
135+
'\n} else {'+
136+
'\n & "node$exe" --expose_gc "$basedir/from.env.args" $args'+
137+
'\n $ret=$LASTEXITCODE'+
138+
'\n}'+
139+
'\nexit $ret'+
140+
'\n')
108141
t.end()
109142
})
110143
})
@@ -146,6 +179,26 @@ test('env shebang with variables', function (t) {
146179
"\n\r"+
147180
"\n\"%_prog%\" \"%~dp0\\from.env.variables\" %*\r"+
148181
"\n@ENDLOCAL\r\n")
182+
t.equal(fs.readFileSync(to + '.ps1', 'utf8'),
183+
'#!/usr/bin/env pwsh'+
184+
'\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+
185+
'\n'+
186+
'\n$exe=""'+
187+
'\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+
188+
'\n # Fix case when both the Windows and Linux builds of Node'+
189+
'\n # are installed in the same directory'+
190+
'\n $exe=".exe"'+
191+
'\n}'+
192+
'\n$ret=0'+
193+
'\nif (Test-Path "$basedir/node$exe") {'+
194+
'\n & "$basedir/node$exe" "$basedir/from.env.variables" $args'+
195+
'\n $ret=$LASTEXITCODE'+
196+
'\n} else {'+
197+
'\n & "node$exe" "$basedir/from.env.variables" $args'+
198+
'\n $ret=$LASTEXITCODE'+
199+
'\n}'+
200+
'\nexit $ret'+
201+
'\n')
149202
t.end()
150203
})
151204
})
@@ -188,6 +241,27 @@ test('explicit shebang', function (t) {
188241
"\n\"%_prog%\" \"%~dp0\\from.sh\" %*\r" +
189242
"\n@ENDLOCAL\r" +
190243
"\n")
244+
245+
t.equal(fs.readFileSync(to + '.ps1', 'utf8'),
246+
'#!/usr/bin/env pwsh'+
247+
'\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+
248+
'\n'+
249+
'\n$exe=""'+
250+
'\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+
251+
'\n # Fix case when both the Windows and Linux builds of Node'+
252+
'\n # are installed in the same directory'+
253+
'\n $exe=".exe"'+
254+
'\n}'+
255+
'\n$ret=0'+
256+
'\nif (Test-Path "$basedir//usr/bin/sh$exe") {'+
257+
'\n & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args'+
258+
'\n $ret=$LASTEXITCODE'+
259+
'\n} else {'+
260+
'\n & "/usr/bin/sh$exe" "$basedir/from.sh" $args'+
261+
'\n $ret=$LASTEXITCODE'+
262+
'\n}'+
263+
'\nexit $ret'+
264+
'\n')
191265
t.end()
192266
})
193267
})
@@ -230,6 +304,27 @@ test('explicit shebang with args', function (t) {
230304
"\n\"%_prog%\" -x \"%~dp0\\from.sh.args\" %*\r" +
231305
"\n@ENDLOCAL\r" +
232306
"\n")
307+
308+
t.equal(fs.readFileSync(to + '.ps1', 'utf8'),
309+
'#!/usr/bin/env pwsh'+
310+
'\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+
311+
'\n'+
312+
'\n$exe=""'+
313+
'\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+
314+
'\n # Fix case when both the Windows and Linux builds of Node'+
315+
'\n # are installed in the same directory'+
316+
'\n $exe=".exe"'+
317+
'\n}'+
318+
'\n$ret=0'+
319+
'\nif (Test-Path "$basedir//usr/bin/sh$exe") {'+
320+
'\n & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args'+
321+
'\n $ret=$LASTEXITCODE'+
322+
'\n} else {'+
323+
'\n & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args'+
324+
'\n $ret=$LASTEXITCODE'+
325+
'\n}'+
326+
'\nexit $ret'+
327+
'\n')
233328
t.end()
234329
})
235330
})

0 commit comments

Comments
 (0)