From 4c37e048dee672237e8962fdffca28e20e9f976d Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 14 Aug 2019 12:38:48 -0700 Subject: [PATCH] Work around quoted batch file names Fix: https://github.com/npm/cmd-shim/issues/10 Read %~dp0 in a subroutine, so that it does not get an incorrect value when the command name is quoted. While we're at it, bring this module up to 100% test coverage, and fix a few obvious bugs that full coverage uncovered. BREAKING CHANGE: This requires an update to read-cmd-shim, because the format of the command invocation changed, and it reads that out of the generated batch script. --- .gitignore | 2 + index.js | 52 ++- lib/to-batch-syntax.js | 1 - package.json | 3 +- tap-snapshots/test-basic.js-TAP.test.js | 440 ++++++++++++++++++++++++ test/basic.js | 349 +++++-------------- 6 files changed, 570 insertions(+), 277 deletions(-) create mode 100644 tap-snapshots/test-basic.js-TAP.test.js diff --git a/.gitignore b/.gitignore index 699b5d4..abe25dc 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ results npm-debug.log node_modules +/coverage +/.nyc_output diff --git a/index.js b/index.js index 722ad91..63a9d5a 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ // "#! " // // Write a binroot/pkg.bin + ".cmd" file that has this line in it: -// @ %~dp0 %* +// @ %dp0% %* module.exports = cmdShim cmdShim.ifExists = cmdShimIfExists @@ -43,9 +43,10 @@ function cmdShim (from, to, cb) { } function cmdShim_ (from, to, cb) { - var then = times(2, next, cb) + var then = times(3, next, cb) rm(to, then) rm(to + ".cmd", then) + rm(to + ".ps1", then) function next(er) { writeShim(from, to, cb) @@ -61,7 +62,7 @@ function writeShim (from, to, cb) { if (er) return cb(er) fs.readFile(from, "utf8", function (er, data) { - if (er) return writeShim_(from, to, null, null, cb) + if (er) return writeShim_(from, to, null, null, null, cb) var firstLine = data.trim().split(/\r*\n/)[0] , shebang = firstLine.match(shebangExpr) if (!shebang) return writeShim_(from, to, null, null, null, cb) @@ -86,50 +87,67 @@ function writeShim_ (from, to, prog, args, variables, cb) { args = args || "" variables = variables || "" if (!prog) { - prog = "\"%~dp0\\" + target + "\"" + prog = "\"%dp0%\\" + target + "\"" shProg = "\"$basedir/" + shTarget + "\"" pwshProg = shProg args = "" target = "" shTarget = "" } else { - longProg = "\"%~dp0\\" + prog + ".exe\"" + longProg = "\"%dp0%\\" + prog + ".exe\"" shLongProg = "\"$basedir/" + prog + "\"" pwshLongProg = "\"$basedir/" + prog + "$exe\"" - target = "\"%~dp0\\" + target + "\"" + target = "\"%dp0%\\" + target + "\"" shTarget = "\"$basedir/" + shTarget + "\"" } // @SETLOCAL + // @CALL :find_dp0 // - // @IF EXIST "%~dp0\node.exe" ( - // @SET "_prog=%~dp0\node.exe" + // @IF EXIST "%dp0%\node.exe" ( + // @SET "_prog=%dp0%\node.exe" // ) ELSE ( // @SET "_prog=node" // @SET PATHEXT=%PATHEXT:;.JS;=;% // ) // - // "%_prog%" "%~dp0\.\node_modules\npm\bin\npm-cli.js" %* + // "%_prog%" "%dp0%\.\node_modules\npm\bin\npm-cli.js" %* // @ENDLOCAL + // @EXIT /b + // + // :find_dp0 + // SET dp0=%~dp0 + // EXIT /b + // + // Subroutine trick to fix https://github.com/npm/cmd-shim/issues/10 + var head = '@ECHO off\r\n' + + 'SETLOCAL\r\n' + + 'CALL find_dp0\r\n' + var foot = 'ENDLOCAL\r\n' + + 'EXIT /b\r\n' + + 'find_dp0:\r\n' + + 'SET dp0=%~dp0\r\n' + + 'EXIT /b\r\n' + var cmd if (longProg) { shLongProg = shLongProg.trim(); args = args.trim(); var variableDeclarationsAsBatch = toBatchSyntax.convertToSetCommands(variables) - cmd = "@SETLOCAL\r\n" + cmd = head + variableDeclarationsAsBatch + "\r\n" - + "@IF EXIST " + longProg + " (\r\n" - + " @SET \"_prog=" + longProg.replace(/(^")|("$)/g, '') + "\"\r\n" + + "IF EXIST " + longProg + " (\r\n" + + " SET \"_prog=" + longProg.replace(/(^")|("$)/g, '') + "\"\r\n" + ") ELSE (\r\n" - + " @SET \"_prog=" + prog.replace(/(^")|("$)/g, '') + "\"\r\n" - + " @SET PATHEXT=%PATHEXT:;.JS;=;%\r\n" + + " SET \"_prog=" + prog.replace(/(^")|("$)/g, '') + "\"\r\n" + + " SET PATHEXT=%PATHEXT:;.JS;=;%\r\n" + ")\r\n" + "\r\n" + "\"%_prog%\" " + args + " " + target + " %*\r\n" - + '@ENDLOCAL\r\n' + + foot } else { - cmd = "@" + prog + " " + args + " " + target + " %*\r\n" + cmd = head + prog + " " + args + " " + target + " %*\r\n" + foot } // #!/bin/sh @@ -228,7 +246,7 @@ function writeShim_ (from, to, prog, args, variables, cb) { } function chmodShim (to, cb) { - var then = times(2, cb, cb) + var then = times(3, cb, cb) fs.chmod(to, "0755", then) fs.chmod(to + ".cmd", "0755", then) fs.chmod(to + ".ps1", "0755", then) diff --git a/lib/to-batch-syntax.js b/lib/to-batch-syntax.js index 30fda7c..f3f5ffa 100644 --- a/lib/to-batch-syntax.js +++ b/lib/to-batch-syntax.js @@ -36,7 +36,6 @@ function replaceDollarWithPercentPair(value) { var dollarExpressions = /\$\{?([^\$@#\?\- \t{}:]+)\}?/g var result = "" var startIndex = 0 - value = value || "" do { var match = dollarExpressions.exec(value) if(match) { diff --git a/package.json b/package.json index 23c4a83..f222bde 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "2.1.0", "description": "Used in npm for command line application support", "scripts": { - "test": "tap test/*.js" + "test": "tap test/*.js --100", + "snap": "TAP_SNAPSHOT=1 tap test/*.js --100" }, "repository": { "type": "git", diff --git a/tap-snapshots/test-basic.js-TAP.test.js b/tap-snapshots/test-basic.js-TAP.test.js new file mode 100644 index 0000000..e0947c6 --- /dev/null +++ b/tap-snapshots/test-basic.js-TAP.test.js @@ -0,0 +1,440 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/basic.js TAP env shebang > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +\\r +IF EXIST "%dp0%\\node.exe" (\\r + SET "_prog=%dp0%\\node.exe"\\r +) ELSE (\\r + SET "_prog=node"\\r + SET PATHEXT=%PATHEXT:;.JS;=;%\\r +)\\r +\\r +"%_prog%" "%dp0%\\from.env" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP env shebang > ps1 1`] = ` +#!/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 +if (Test-Path "$basedir/node$exe") { + & "$basedir/node$exe" "$basedir/from.env" $args + $ret=$LASTEXITCODE +} else { + & "node$exe" "$basedir/from.env" $args + $ret=$LASTEXITCODE +} +exit $ret + +` + +exports[`test/basic.js TAP env shebang > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +if [ -x "$basedir/node" ]; then + "$basedir/node" "$basedir/from.env" "$@" + ret=$? +else + node "$basedir/from.env" "$@" + ret=$? +fi +exit $ret + +` + +exports[`test/basic.js TAP env shebang with args > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +\\r +IF EXIST "%dp0%\\node.exe" (\\r + SET "_prog=%dp0%\\node.exe"\\r +) ELSE (\\r + SET "_prog=node"\\r + SET PATHEXT=%PATHEXT:;.JS;=;%\\r +)\\r +\\r +"%_prog%" --expose_gc "%dp0%\\from.env.args" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP env shebang with args > ps1 1`] = ` +#!/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 +if (Test-Path "$basedir/node$exe") { + & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args + $ret=$LASTEXITCODE +} else { + & "node$exe" --expose_gc "$basedir/from.env.args" $args + $ret=$LASTEXITCODE +} +exit $ret + +` + +exports[`test/basic.js TAP env shebang with args > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +if [ -x "$basedir/node" ]; then + "$basedir/node" --expose_gc "$basedir/from.env.args" "$@" + ret=$? +else + node --expose_gc "$basedir/from.env.args" "$@" + ret=$? +fi +exit $ret + +` + +exports[`test/basic.js TAP env shebang with variables > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +@SET NODE_PATH=./lib:%NODE_PATH%\\r +\\r +IF EXIST "%dp0%\\node.exe" (\\r + SET "_prog=%dp0%\\node.exe"\\r +) ELSE (\\r + SET "_prog=node"\\r + SET PATHEXT=%PATHEXT:;.JS;=;%\\r +)\\r +\\r +"%_prog%" "%dp0%\\from.env.variables" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP env shebang with variables > ps1 1`] = ` +#!/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 +if (Test-Path "$basedir/node$exe") { + & "$basedir/node$exe" "$basedir/from.env.variables" $args + $ret=$LASTEXITCODE +} else { + & "node$exe" "$basedir/from.env.variables" $args + $ret=$LASTEXITCODE +} +exit $ret + +` + +exports[`test/basic.js TAP env shebang with variables > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +if [ -x "$basedir/node" ]; then + NODE_PATH=./lib:$NODE_PATH "$basedir/node" "$basedir/from.env.variables" "$@" + ret=$? +else + NODE_PATH=./lib:$NODE_PATH node "$basedir/from.env.variables" "$@" + ret=$? +fi +exit $ret + +` + +exports[`test/basic.js TAP explicit shebang > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +\\r +IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r + SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r +) ELSE (\\r + SET "_prog=/usr/bin/sh"\\r + SET PATHEXT=%PATHEXT:;.JS;=;%\\r +)\\r +\\r +"%_prog%" "%dp0%\\from.sh" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP explicit shebang > ps1 1`] = ` +#!/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 +if (Test-Path "$basedir//usr/bin/sh$exe") { + & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args + $ret=$LASTEXITCODE +} else { + & "/usr/bin/sh$exe" "$basedir/from.sh" $args + $ret=$LASTEXITCODE +} +exit $ret + +` + +exports[`test/basic.js TAP explicit shebang > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +if [ -x "$basedir//usr/bin/sh" ]; then + "$basedir//usr/bin/sh" "$basedir/from.sh" "$@" + ret=$? +else + /usr/bin/sh "$basedir/from.sh" "$@" + ret=$? +fi +exit $ret + +` + +exports[`test/basic.js TAP explicit shebang with args > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +\\r +IF EXIST "%dp0%\\/usr/bin/sh.exe" (\\r + SET "_prog=%dp0%\\/usr/bin/sh.exe"\\r +) ELSE (\\r + SET "_prog=/usr/bin/sh"\\r + SET PATHEXT=%PATHEXT:;.JS;=;%\\r +)\\r +\\r +"%_prog%" -x "%dp0%\\from.sh.args" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP explicit shebang with args > ps1 1`] = ` +#!/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 +if (Test-Path "$basedir//usr/bin/sh$exe") { + & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args + $ret=$LASTEXITCODE +} else { + & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args + $ret=$LASTEXITCODE +} +exit $ret + +` + +exports[`test/basic.js TAP explicit shebang with args > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +if [ -x "$basedir//usr/bin/sh" ]; then + "$basedir//usr/bin/sh" -x "$basedir/from.sh.args" "$@" + ret=$? +else + /usr/bin/sh -x "$basedir/from.sh.args" "$@" + ret=$? +fi +exit $ret + +` + +exports[`test/basic.js TAP if exists (it does exist) > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +"%dp0%\\from.exe" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP if exists (it does exist) > ps1 1`] = ` +#!/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" +} +& "$basedir/from.exe" $args +exit $LASTEXITCODE + +` + +exports[`test/basic.js TAP if exists (it does exist) > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +"$basedir/from.exe" "$@" +exit $? + +` + +exports[`test/basic.js TAP just proceed if reading fails > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +"%dp0%\\" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP just proceed if reading fails > ps1 1`] = ` +#!/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" +} +& "$basedir/" $args +exit $LASTEXITCODE + +` + +exports[`test/basic.js TAP just proceed if reading fails > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +"$basedir/" "$@" +exit $? + +` + +exports[`test/basic.js TAP no shebang > cmd 1`] = ` +@ECHO off\\r +SETLOCAL\\r +CALL find_dp0\\r +"%dp0%\\from.exe" %*\\r +ENDLOCAL\\r +EXIT /b\\r +find_dp0:\\r +SET dp0=%~dp0\\r +EXIT /b\\r + +` + +exports[`test/basic.js TAP no shebang > ps1 1`] = ` +#!/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" +} +& "$basedir/from.exe" $args +exit $LASTEXITCODE + +` + +exports[`test/basic.js TAP no shebang > shell 1`] = ` +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')") + +case \`uname\` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=\`cygpath -w "$basedir"\`;; +esac + +"$basedir/from.exe" "$@" +exit $? + +` diff --git a/test/basic.js b/test/basic.js index 4d92557..98b207c 100755 --- a/test/basic.js +++ b/test/basic.js @@ -1,9 +1,13 @@ var test = require('tap').test var mkdirp = require('mkdirp') +var rimraf = require('rimraf') var fs = require('fs') var path = require('path') var fixtures = path.resolve(__dirname, 'fixtures') +const matchSnapshot = (t, found, name) => + t.matchSnapshot(found.replace(/\r/g, '\\r'), name) + var cmdShim = require('../') test('no shebang', function (t) { @@ -12,30 +16,78 @@ test('no shebang', function (t) { cmdShim(from, to, function(er) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh"+ - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")"+ - "\n"+ - "\ncase `uname` in"+ - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;"+ - "\nesac"+ - "\n"+ - "\n\"$basedir/from.exe\" \"$@\"\nexit $?\n") - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@\"%~dp0\\from.exe\" %*\r\n") - t.equal(fs.readFileSync(to + '.ps1', 'utf8'), - '#!/usr/bin/env pwsh'+ - '\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+ - '\n'+ - '\n$exe=""'+ - '\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+ - '\n # Fix case when both the Windows and Linux builds of Node'+ - '\n # are installed in the same directory'+ - '\n $exe=".exe"'+ - '\n}'+ - '\n& "$basedir/from.exe" $args'+ - '\nexit $LASTEXITCODE'+ - '\n') + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') + t.end() + }) +}) + +test('if exists (it does exist)', function (t) { + var from = path.resolve(fixtures, 'from.exe') + var to = path.resolve(fixtures, 'exe.shim') + cmdShim.ifExists(from, to, function(er) { + if (er) + throw er + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') + t.end() + }) +}) + +test('if exists (it does not exist)', function (t) { + var from = path.resolve(fixtures, 'argle bargle we like to sparkle') + var to = path.resolve(fixtures, 'argle-bargle-shim') + cmdShim.ifExists(from, to, function(er) { + if (er) + throw er + t.throws(() => fs.statSync(to)) + t.throws(() => fs.statSync(to + '.cmd')) + t.throws(() => fs.statSync(to + '.ps1')) + t.end() + }) +}) + +test('fails if from doesnt exist', t => { + var from = path.resolve(fixtures, 'argle bargle we like to sparkle') + var to = path.resolve(fixtures, 'argle-bargle-shim') + cmdShim(from, to, function(er) { + t.match(er, { code: 'ENOENT' }) + t.end() + }) +}) + +test('fails if mkdir fails', t => { + var from = path.resolve(fixtures, 'from.env') + var to = path.resolve(fixtures, 'from.env/a/b/c') + cmdShim(from, to, er => { + t.match(er, { code: 'ENOTDIR' }) + t.end() + }) +}) + +test('fails if to is a dir', t => { + var from = path.resolve(fixtures, 'from.env') + var to = path.resolve(fixtures) + cmdShim(from, to, er => { + t.match(er, { code: 'EISDIR' }) + rimraf.sync(to + '.cmd') + rimraf.sync(to + '.ps1') + t.end() + }) +}) + +test('just proceed if reading fails', t => { + var from = fixtures + var to = path.resolve(fixtures, 'env.shim') + cmdShim(from, to, er => { + if (er) + throw er + + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) }) @@ -47,36 +99,9 @@ test('env shebang', function (t) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh" + - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")" + - "\n" + - "\ncase `uname` in" + - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;" + - "\nesac" + - "\n" + - "\nif [ -x \"$basedir/node\" ]; then" + - "\n \"$basedir/node\" \"$basedir/from.env\" \"$@\"" + - "\n ret=$?" + - "\nelse " + - "\n node \"$basedir/from.env\" \"$@\"" + - "\n ret=$?" + - "\nfi" + - "\nexit $ret" + - "\n") - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@SETLOCAL\r" + - "\n\r" + - "\n@IF EXIST \"%~dp0\\node.exe\" (\r" + - "\n @SET \"_prog=%~dp0\\node.exe\"\r" + - "\n) ELSE (\r" + - "\n @SET \"_prog=node\"\r" + - "\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" + - "\n)\r" + - "\n\r" + - "\n\"%_prog%\" \"%~dp0\\from.env\" %*\r" + - "\n@ENDLOCAL\r" + - "\n") + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) }) @@ -88,56 +113,9 @@ test('env shebang with args', function (t) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh"+ - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")"+ - "\n"+ - "\ncase `uname` in"+ - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;"+ - "\nesac"+ - "\n"+ - "\nif [ -x \"$basedir/node\" ]; then"+ - "\n \"$basedir/node\" --expose_gc \"$basedir/from.env.args\" \"$@\""+ - "\n ret=$?"+ - "\nelse "+ - "\n node --expose_gc \"$basedir/from.env.args\" \"$@\""+ - "\n ret=$?"+ - "\nfi"+ - "\nexit $ret"+ - "\n") - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@SETLOCAL\r" + - "\n\r" + - "\n@IF EXIST \"%~dp0\\node.exe\" (\r" + - "\n @SET \"_prog=%~dp0\\node.exe\"\r" + - "\n) ELSE (\r" + - "\n @SET \"_prog=node\"\r" + - "\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" + - "\n)\r" + - "\n\r" + - "\n\"%_prog%\" --expose_gc \"%~dp0\\from.env.args\" %*\r" + - "\n@ENDLOCAL\r" + - "\n") - t.equal(fs.readFileSync(to + '.ps1', 'utf8'), - '#!/usr/bin/env pwsh'+ - '\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+ - '\n'+ - '\n$exe=""'+ - '\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+ - '\n # Fix case when both the Windows and Linux builds of Node'+ - '\n # are installed in the same directory'+ - '\n $exe=".exe"'+ - '\n}'+ - '\n$ret=0'+ - '\nif (Test-Path "$basedir/node$exe") {'+ - '\n & "$basedir/node$exe" --expose_gc "$basedir/from.env.args" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n} else {'+ - '\n & "node$exe" --expose_gc "$basedir/from.env.args" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n}'+ - '\nexit $ret'+ - '\n') + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) }) @@ -149,56 +127,9 @@ test('env shebang with variables', function (t) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh"+ - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")" + - "\n"+ - "\ncase `uname` in"+ - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;"+ - "\nesac"+ - "\n"+ - "\nif [ -x \"$basedir/node\" ]; then"+ - "\n NODE_PATH=./lib:$NODE_PATH \"$basedir/node\" \"$basedir/from.env.variables\" \"$@\""+ - "\n ret=$?"+ - "\nelse "+ - "\n NODE_PATH=./lib:$NODE_PATH node \"$basedir/from.env.variables\" \"$@\""+ - "\n ret=$?"+ - "\nfi"+ - "\nexit $ret"+ - "\n") - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@SETLOCAL\r"+ - "\n@SET NODE_PATH=./lib:%NODE_PATH%\r"+ - "\n\r" + - "\n@IF EXIST \"%~dp0\\node.exe\" (\r"+ - "\n @SET \"_prog=%~dp0\\node.exe\"\r" + - "\n) ELSE (\r"+ - "\n @SET \"_prog=node\"\r"+ - "\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" + - "\n)\r"+ - "\n\r"+ - "\n\"%_prog%\" \"%~dp0\\from.env.variables\" %*\r"+ - "\n@ENDLOCAL\r\n") - t.equal(fs.readFileSync(to + '.ps1', 'utf8'), - '#!/usr/bin/env pwsh'+ - '\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+ - '\n'+ - '\n$exe=""'+ - '\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+ - '\n # Fix case when both the Windows and Linux builds of Node'+ - '\n # are installed in the same directory'+ - '\n $exe=".exe"'+ - '\n}'+ - '\n$ret=0'+ - '\nif (Test-Path "$basedir/node$exe") {'+ - '\n & "$basedir/node$exe" "$basedir/from.env.variables" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n} else {'+ - '\n & "node$exe" "$basedir/from.env.variables" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n}'+ - '\nexit $ret'+ - '\n') + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) }) @@ -210,58 +141,9 @@ test('explicit shebang', function (t) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh" + - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")" + - "\n" + - "\ncase `uname` in" + - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;" + - "\nesac" + - "\n" + - "\nif [ -x \"$basedir//usr/bin/sh\" ]; then" + - "\n \"$basedir//usr/bin/sh\" \"$basedir/from.sh\" \"$@\"" + - "\n ret=$?" + - "\nelse " + - "\n /usr/bin/sh \"$basedir/from.sh\" \"$@\"" + - "\n ret=$?" + - "\nfi" + - "\nexit $ret" + - "\n") - - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@SETLOCAL\r" + - "\n\r" + - "\n@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" + - "\n @SET \"_prog=%~dp0\\/usr/bin/sh.exe\"\r" + - "\n) ELSE (\r" + - "\n @SET \"_prog=/usr/bin/sh\"\r" + - "\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" + - "\n)\r" + - "\n\r" + - "\n\"%_prog%\" \"%~dp0\\from.sh\" %*\r" + - "\n@ENDLOCAL\r" + - "\n") - - t.equal(fs.readFileSync(to + '.ps1', 'utf8'), - '#!/usr/bin/env pwsh'+ - '\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+ - '\n'+ - '\n$exe=""'+ - '\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+ - '\n # Fix case when both the Windows and Linux builds of Node'+ - '\n # are installed in the same directory'+ - '\n $exe=".exe"'+ - '\n}'+ - '\n$ret=0'+ - '\nif (Test-Path "$basedir//usr/bin/sh$exe") {'+ - '\n & "$basedir//usr/bin/sh$exe" "$basedir/from.sh" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n} else {'+ - '\n & "/usr/bin/sh$exe" "$basedir/from.sh" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n}'+ - '\nexit $ret'+ - '\n') + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) }) @@ -273,58 +155,9 @@ test('explicit shebang with args', function (t) { if (er) throw er - t.equal(fs.readFileSync(to, 'utf8'), - "#!/bin/sh" + - "\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")" + - "\n" + - "\ncase `uname` in" + - "\n *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w \"$basedir\"`;;" + - "\nesac" + - "\n" + - "\nif [ -x \"$basedir//usr/bin/sh\" ]; then" + - "\n \"$basedir//usr/bin/sh\" -x \"$basedir/from.sh.args\" \"$@\"" + - "\n ret=$?" + - "\nelse " + - "\n /usr/bin/sh -x \"$basedir/from.sh.args\" \"$@\"" + - "\n ret=$?" + - "\nfi" + - "\nexit $ret" + - "\n") - - t.equal(fs.readFileSync(to + '.cmd', 'utf8'), - "@SETLOCAL\r" + - "\n\r" + - "\n@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" + - "\n @SET \"_prog=%~dp0\\/usr/bin/sh.exe\"\r" + - "\n) ELSE (\r" + - "\n @SET \"_prog=/usr/bin/sh\"\r" + - "\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" + - "\n)\r" + - "\n\r" + - "\n\"%_prog%\" -x \"%~dp0\\from.sh.args\" %*\r" + - "\n@ENDLOCAL\r" + - "\n") - - t.equal(fs.readFileSync(to + '.ps1', 'utf8'), - '#!/usr/bin/env pwsh'+ - '\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent'+ - '\n'+ - '\n$exe=""'+ - '\nif ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {'+ - '\n # Fix case when both the Windows and Linux builds of Node'+ - '\n # are installed in the same directory'+ - '\n $exe=".exe"'+ - '\n}'+ - '\n$ret=0'+ - '\nif (Test-Path "$basedir//usr/bin/sh$exe") {'+ - '\n & "$basedir//usr/bin/sh$exe" -x "$basedir/from.sh.args" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n} else {'+ - '\n & "/usr/bin/sh$exe" -x "$basedir/from.sh.args" $args'+ - '\n $ret=$LASTEXITCODE'+ - '\n}'+ - '\nexit $ret'+ - '\n') + matchSnapshot(t, fs.readFileSync(to, 'utf8'), 'shell') + matchSnapshot(t, fs.readFileSync(to + '.cmd', 'utf8'), 'cmd') + matchSnapshot(t, fs.readFileSync(to + '.ps1', 'utf8'), 'ps1') t.end() }) })