11cb0ef41Sopenharmony_ci// On windows, create a .cmd file. 21cb0ef41Sopenharmony_ci// Read the #! in the file to see what it uses. The vast majority 31cb0ef41Sopenharmony_ci// of the time, this will be either: 41cb0ef41Sopenharmony_ci// "#!/usr/bin/env <prog> <args...>" 51cb0ef41Sopenharmony_ci// or: 61cb0ef41Sopenharmony_ci// "#!<prog> <args...>" 71cb0ef41Sopenharmony_ci// 81cb0ef41Sopenharmony_ci// Write a binroot/pkg.bin + ".cmd" file that has this line in it: 91cb0ef41Sopenharmony_ci// @<prog> <args...> %dp0%<target> %* 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciconst { 121cb0ef41Sopenharmony_ci chmod, 131cb0ef41Sopenharmony_ci mkdir, 141cb0ef41Sopenharmony_ci readFile, 151cb0ef41Sopenharmony_ci stat, 161cb0ef41Sopenharmony_ci unlink, 171cb0ef41Sopenharmony_ci writeFile, 181cb0ef41Sopenharmony_ci} = require('fs/promises') 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst { dirname, relative } = require('path') 211cb0ef41Sopenharmony_ciconst toBatchSyntax = require('./to-batch-syntax') 221cb0ef41Sopenharmony_ci// linting disabled because this regex is really long 231cb0ef41Sopenharmony_ci// eslint-disable-next-line max-len 241cb0ef41Sopenharmony_ciconst shebangExpr = /^#!\s*(?:\/usr\/bin\/env\s+(?:-S\s+)?((?:[^ \t=]+=[^ \t=]+\s+)*))?([^ \t]+)(.*)$/ 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciconst cmdShimIfExists = (from, to) => 271cb0ef41Sopenharmony_ci stat(from).then(() => cmdShim(from, to), () => {}) 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci// Try to unlink, but ignore errors. 301cb0ef41Sopenharmony_ci// Any problems will surface later. 311cb0ef41Sopenharmony_ciconst rm = path => unlink(path).catch(() => {}) 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ciconst cmdShim = (from, to) => 341cb0ef41Sopenharmony_ci stat(from).then(() => cmdShim_(from, to)) 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciconst cmdShim_ = (from, to) => Promise.all([ 371cb0ef41Sopenharmony_ci rm(to), 381cb0ef41Sopenharmony_ci rm(to + '.cmd'), 391cb0ef41Sopenharmony_ci rm(to + '.ps1'), 401cb0ef41Sopenharmony_ci]).then(() => writeShim(from, to)) 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciconst writeShim = (from, to) => 431cb0ef41Sopenharmony_ci // make a cmd file and a sh script 441cb0ef41Sopenharmony_ci // First, check if the bin is a #! of some sort. 451cb0ef41Sopenharmony_ci // If not, then assume it's something that'll be compiled, or some other 461cb0ef41Sopenharmony_ci // sort of script, and just call it directly. 471cb0ef41Sopenharmony_ci mkdir(dirname(to), { recursive: true }) 481cb0ef41Sopenharmony_ci .then(() => readFile(from, 'utf8')) 491cb0ef41Sopenharmony_ci .then(data => { 501cb0ef41Sopenharmony_ci const firstLine = data.trim().split(/\r*\n/)[0] 511cb0ef41Sopenharmony_ci const shebang = firstLine.match(shebangExpr) 521cb0ef41Sopenharmony_ci if (!shebang) { 531cb0ef41Sopenharmony_ci return writeShim_(from, to) 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci const vars = shebang[1] || '' 561cb0ef41Sopenharmony_ci const prog = shebang[2] 571cb0ef41Sopenharmony_ci const args = shebang[3] || '' 581cb0ef41Sopenharmony_ci return writeShim_(from, to, prog, args, vars) 591cb0ef41Sopenharmony_ci }, er => writeShim_(from, to)) 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ciconst writeShim_ = (from, to, prog, args, variables) => { 621cb0ef41Sopenharmony_ci let shTarget = relative(dirname(to), from) 631cb0ef41Sopenharmony_ci let target = shTarget.split('/').join('\\') 641cb0ef41Sopenharmony_ci let longProg 651cb0ef41Sopenharmony_ci let shProg = prog && prog.split('\\').join('/') 661cb0ef41Sopenharmony_ci let shLongProg 671cb0ef41Sopenharmony_ci let pwshProg = shProg && `"${shProg}$exe"` 681cb0ef41Sopenharmony_ci let pwshLongProg 691cb0ef41Sopenharmony_ci shTarget = shTarget.split('\\').join('/') 701cb0ef41Sopenharmony_ci args = args || '' 711cb0ef41Sopenharmony_ci variables = variables || '' 721cb0ef41Sopenharmony_ci if (!prog) { 731cb0ef41Sopenharmony_ci prog = `"%dp0%\\${target}"` 741cb0ef41Sopenharmony_ci shProg = `"$basedir/${shTarget}"` 751cb0ef41Sopenharmony_ci pwshProg = shProg 761cb0ef41Sopenharmony_ci args = '' 771cb0ef41Sopenharmony_ci target = '' 781cb0ef41Sopenharmony_ci shTarget = '' 791cb0ef41Sopenharmony_ci } else { 801cb0ef41Sopenharmony_ci longProg = `"%dp0%\\${prog}.exe"` 811cb0ef41Sopenharmony_ci shLongProg = `"$basedir/${prog}"` 821cb0ef41Sopenharmony_ci pwshLongProg = `"$basedir/${prog}$exe"` 831cb0ef41Sopenharmony_ci target = `"%dp0%\\${target}"` 841cb0ef41Sopenharmony_ci shTarget = `"$basedir/${shTarget}"` 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci // Subroutine trick to fix https://github.com/npm/cmd-shim/issues/10 881cb0ef41Sopenharmony_ci // and https://github.com/npm/cli/issues/969 891cb0ef41Sopenharmony_ci const head = '@ECHO off\r\n' + 901cb0ef41Sopenharmony_ci 'GOTO start\r\n' + 911cb0ef41Sopenharmony_ci ':find_dp0\r\n' + 921cb0ef41Sopenharmony_ci 'SET dp0=%~dp0\r\n' + 931cb0ef41Sopenharmony_ci 'EXIT /b\r\n' + 941cb0ef41Sopenharmony_ci ':start\r\n' + 951cb0ef41Sopenharmony_ci 'SETLOCAL\r\n' + 961cb0ef41Sopenharmony_ci 'CALL :find_dp0\r\n' 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci let cmd 991cb0ef41Sopenharmony_ci if (longProg) { 1001cb0ef41Sopenharmony_ci shLongProg = shLongProg.trim() 1011cb0ef41Sopenharmony_ci args = args.trim() 1021cb0ef41Sopenharmony_ci const variablesBatch = toBatchSyntax.convertToSetCommands(variables) 1031cb0ef41Sopenharmony_ci cmd = head 1041cb0ef41Sopenharmony_ci + variablesBatch 1051cb0ef41Sopenharmony_ci + '\r\n' 1061cb0ef41Sopenharmony_ci + `IF EXIST ${longProg} (\r\n` 1071cb0ef41Sopenharmony_ci + ` SET "_prog=${longProg.replace(/(^")|("$)/g, '')}"\r\n` 1081cb0ef41Sopenharmony_ci + ') ELSE (\r\n' 1091cb0ef41Sopenharmony_ci + ` SET "_prog=${prog.replace(/(^")|("$)/g, '')}"\r\n` 1101cb0ef41Sopenharmony_ci + ' SET PATHEXT=%PATHEXT:;.JS;=;%\r\n' 1111cb0ef41Sopenharmony_ci + ')\r\n' 1121cb0ef41Sopenharmony_ci + '\r\n' 1131cb0ef41Sopenharmony_ci // prevent "Terminate Batch Job? (Y/n)" message 1141cb0ef41Sopenharmony_ci // https://github.com/npm/cli/issues/969#issuecomment-737496588 1151cb0ef41Sopenharmony_ci + 'endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & ' 1161cb0ef41Sopenharmony_ci + `"%_prog%" ${args} ${target} %*\r\n` 1171cb0ef41Sopenharmony_ci } else { 1181cb0ef41Sopenharmony_ci cmd = `${head}${prog} ${args} ${target} %*\r\n` 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci // #!/bin/sh 1221cb0ef41Sopenharmony_ci // basedir=`dirname "$0"` 1231cb0ef41Sopenharmony_ci // 1241cb0ef41Sopenharmony_ci // case `uname` in 1251cb0ef41Sopenharmony_ci // *CYGWIN*|*MINGW*|*MSYS*) 1261cb0ef41Sopenharmony_ci // if command -v cygpath > /dev/null 2>&1; then 1271cb0ef41Sopenharmony_ci // basedir=`cygpath -w "$basedir"` 1281cb0ef41Sopenharmony_ci // fi 1291cb0ef41Sopenharmony_ci // ;; 1301cb0ef41Sopenharmony_ci // esac 1311cb0ef41Sopenharmony_ci // 1321cb0ef41Sopenharmony_ci // if [ -x "$basedir/node.exe" ]; then 1331cb0ef41Sopenharmony_ci // exec "$basedir/node.exe" "$basedir/node_modules/npm/bin/npm-cli.js" "$@" 1341cb0ef41Sopenharmony_ci // else 1351cb0ef41Sopenharmony_ci // exec node "$basedir/node_modules/npm/bin/npm-cli.js" "$@" 1361cb0ef41Sopenharmony_ci // fi 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci let sh = '#!/bin/sh\n' 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci sh = sh 1411cb0ef41Sopenharmony_ci + `basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")\n` 1421cb0ef41Sopenharmony_ci + '\n' 1431cb0ef41Sopenharmony_ci + 'case `uname` in\n' 1441cb0ef41Sopenharmony_ci + ' *CYGWIN*|*MINGW*|*MSYS*)\n' 1451cb0ef41Sopenharmony_ci + ' if command -v cygpath > /dev/null 2>&1; then\n' 1461cb0ef41Sopenharmony_ci + ' basedir=`cygpath -w "$basedir"`\n' 1471cb0ef41Sopenharmony_ci + ' fi\n' 1481cb0ef41Sopenharmony_ci + ' ;;\n' 1491cb0ef41Sopenharmony_ci + 'esac\n' 1501cb0ef41Sopenharmony_ci + '\n' 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci if (shLongProg) { 1531cb0ef41Sopenharmony_ci sh = sh 1541cb0ef41Sopenharmony_ci + `if [ -x ${shLongProg} ]; then\n` 1551cb0ef41Sopenharmony_ci + ` exec ${variables}${shLongProg} ${args} ${shTarget} "$@"\n` 1561cb0ef41Sopenharmony_ci + 'else \n' 1571cb0ef41Sopenharmony_ci + ` exec ${variables}${shProg} ${args} ${shTarget} "$@"\n` 1581cb0ef41Sopenharmony_ci + 'fi\n' 1591cb0ef41Sopenharmony_ci } else { 1601cb0ef41Sopenharmony_ci sh = sh 1611cb0ef41Sopenharmony_ci + `exec ${shProg} ${args} ${shTarget} "$@"\n` 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci // #!/usr/bin/env pwsh 1651cb0ef41Sopenharmony_ci // $basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent 1661cb0ef41Sopenharmony_ci // 1671cb0ef41Sopenharmony_ci // $ret=0 1681cb0ef41Sopenharmony_ci // $exe = "" 1691cb0ef41Sopenharmony_ci // if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { 1701cb0ef41Sopenharmony_ci // # Fix case when both the Windows and Linux builds of Node 1711cb0ef41Sopenharmony_ci // # are installed in the same directory 1721cb0ef41Sopenharmony_ci // $exe = ".exe" 1731cb0ef41Sopenharmony_ci // } 1741cb0ef41Sopenharmony_ci // if (Test-Path "$basedir/node") { 1751cb0ef41Sopenharmony_ci // # Suport pipeline input 1761cb0ef41Sopenharmony_ci // if ($MyInvocation.ExpectingInput) { 1771cb0ef41Sopenharmony_ci // input | & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args 1781cb0ef41Sopenharmony_ci // } else { 1791cb0ef41Sopenharmony_ci // & "$basedir/node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args 1801cb0ef41Sopenharmony_ci // } 1811cb0ef41Sopenharmony_ci // $ret=$LASTEXITCODE 1821cb0ef41Sopenharmony_ci // } else { 1831cb0ef41Sopenharmony_ci // # Support pipeline input 1841cb0ef41Sopenharmony_ci // if ($MyInvocation.ExpectingInput) { 1851cb0ef41Sopenharmony_ci // $input | & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args 1861cb0ef41Sopenharmony_ci // } else { 1871cb0ef41Sopenharmony_ci // & "node$exe" "$basedir/node_modules/npm/bin/npm-cli.js" $args 1881cb0ef41Sopenharmony_ci // } 1891cb0ef41Sopenharmony_ci // $ret=$LASTEXITCODE 1901cb0ef41Sopenharmony_ci // } 1911cb0ef41Sopenharmony_ci // exit $ret 1921cb0ef41Sopenharmony_ci let pwsh = '#!/usr/bin/env pwsh\n' 1931cb0ef41Sopenharmony_ci + '$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n' 1941cb0ef41Sopenharmony_ci + '\n' 1951cb0ef41Sopenharmony_ci + '$exe=""\n' 1961cb0ef41Sopenharmony_ci + 'if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {\n' 1971cb0ef41Sopenharmony_ci + ' # Fix case when both the Windows and Linux builds of Node\n' 1981cb0ef41Sopenharmony_ci + ' # are installed in the same directory\n' 1991cb0ef41Sopenharmony_ci + ' $exe=".exe"\n' 2001cb0ef41Sopenharmony_ci + '}\n' 2011cb0ef41Sopenharmony_ci if (shLongProg) { 2021cb0ef41Sopenharmony_ci pwsh = pwsh 2031cb0ef41Sopenharmony_ci + '$ret=0\n' 2041cb0ef41Sopenharmony_ci + `if (Test-Path ${pwshLongProg}) {\n` 2051cb0ef41Sopenharmony_ci + ' # Support pipeline input\n' 2061cb0ef41Sopenharmony_ci + ' if ($MyInvocation.ExpectingInput) {\n' 2071cb0ef41Sopenharmony_ci + ` $input | & ${pwshLongProg} ${args} ${shTarget} $args\n` 2081cb0ef41Sopenharmony_ci + ' } else {\n' 2091cb0ef41Sopenharmony_ci + ` & ${pwshLongProg} ${args} ${shTarget} $args\n` 2101cb0ef41Sopenharmony_ci + ' }\n' 2111cb0ef41Sopenharmony_ci + ' $ret=$LASTEXITCODE\n' 2121cb0ef41Sopenharmony_ci + '} else {\n' 2131cb0ef41Sopenharmony_ci + ' # Support pipeline input\n' 2141cb0ef41Sopenharmony_ci + ' if ($MyInvocation.ExpectingInput) {\n' 2151cb0ef41Sopenharmony_ci + ` $input | & ${pwshProg} ${args} ${shTarget} $args\n` 2161cb0ef41Sopenharmony_ci + ' } else {\n' 2171cb0ef41Sopenharmony_ci + ` & ${pwshProg} ${args} ${shTarget} $args\n` 2181cb0ef41Sopenharmony_ci + ' }\n' 2191cb0ef41Sopenharmony_ci + ' $ret=$LASTEXITCODE\n' 2201cb0ef41Sopenharmony_ci + '}\n' 2211cb0ef41Sopenharmony_ci + 'exit $ret\n' 2221cb0ef41Sopenharmony_ci } else { 2231cb0ef41Sopenharmony_ci pwsh = pwsh 2241cb0ef41Sopenharmony_ci + '# Support pipeline input\n' 2251cb0ef41Sopenharmony_ci + 'if ($MyInvocation.ExpectingInput) {\n' 2261cb0ef41Sopenharmony_ci + ` $input | & ${pwshProg} ${args} ${shTarget} $args\n` 2271cb0ef41Sopenharmony_ci + '} else {\n' 2281cb0ef41Sopenharmony_ci + ` & ${pwshProg} ${args} ${shTarget} $args\n` 2291cb0ef41Sopenharmony_ci + '}\n' 2301cb0ef41Sopenharmony_ci + 'exit $LASTEXITCODE\n' 2311cb0ef41Sopenharmony_ci } 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci return Promise.all([ 2341cb0ef41Sopenharmony_ci writeFile(to + '.ps1', pwsh, 'utf8'), 2351cb0ef41Sopenharmony_ci writeFile(to + '.cmd', cmd, 'utf8'), 2361cb0ef41Sopenharmony_ci writeFile(to, sh, 'utf8'), 2371cb0ef41Sopenharmony_ci ]).then(() => chmodShim(to)) 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ciconst chmodShim = to => Promise.all([ 2411cb0ef41Sopenharmony_ci chmod(to, 0o755), 2421cb0ef41Sopenharmony_ci chmod(to + '.cmd', 0o755), 2431cb0ef41Sopenharmony_ci chmod(to + '.ps1', 0o755), 2441cb0ef41Sopenharmony_ci]) 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_cimodule.exports = cmdShim 2471cb0ef41Sopenharmony_cicmdShim.ifExists = cmdShimIfExists 248