spiegel-keyman/resources/gosh/gosh.js
2025-05-02 13:04:39 +07:00

113 lines
3.4 KiB
JavaScript
Executable file

#!/usr/bin/env node
/*
gosh.js: launch bash script from any environment from within our package.json builds
This script will try and locate the bash.exe executable that is included in Git for Windows
on Windows platforms, and execute it within the current console. On *nix environments, it
will simply launch /bin/bash.
Usage:
Make sure gosh is installed, e.g.:
npm install '@keymanapp/resources-gosh@*'
Then, in package.json, define scripts like this:
"scripts": {
"foo": "gosh ./foo.sh ..."
}
For example, in common/web/utils/package.json, npm run build is defined as:
"build": "gosh ./build.sh -skip-package-install"
Windows launch strategy:
* If GIT_BASH_FOR_KEYMAN environment variable is defined, then this script will parse the
variable to extract the bash executable, and then use the remaining components of the
variable to launch the script with its parameters.
* If GIT_BASH_FOR_KEYMAN is *not* defined, then the script looks in the Program Files
and Program Files (x86) folders, Git/bin/bash.exe, (using the %ProgramFiles% and
%ProgramFiles(x86)% environment variables) and appends the parameters:
--init-file .../Git/etc/profile -l <script> <parameters>
*/
let fs = require('fs');
let path = require('path');
let child_process = require('child_process');
// https://stackoverflow.com/a/5767589/1836776
const args = process.argv.slice(2);
const result = process.platform == 'win32' ? launchWin32Bash() : launchNixBash();
if(!result || result.status === null) {
console.error('Subcommand failed with null exit code');
process.exit(1);
}
process.exit(result.status);
function splitQuotedString(s) {
// https://stackoverflow.com/a/18647776/1836776
// The parenthesis in the regex creates a captured group within the quotes
const regex = /[^\s"]+|"([^"]*)"/gi;
const res = [];
let match = null;
do {
//Each call to exec returns the next regex match as an array
match = regex.exec(s);
if (match != null)
{
//Index 1 in the array is the captured group if it exists
//Index 0 is the matched text, which we use if no captured group exists
res.push(match[1] ? match[1] : match[0]);
}
} while (match != null);
return res;
}
function launchWin32Bash() {
// First, look for GIT_BASH_FOR_KEYMAN variable
let bash = null, child_args = null;
if(process.env.GIT_BASH_FOR_KEYMAN) {
const env = splitQuotedString(process.env.GIT_BASH_FOR_KEYMAN);
if(!env) {
console.error('Could not parse GIT_BASH_FOR_KEYMAN');
process.exit(1);
}
bash = env[0];
child_args = env.slice(1);
} else {
// Otherwise, find bash.exe wherever we can!
const root = [process.env.ProgramFiles, process.env['ProgramFiles(x86)']].find(
r => fs.existsSync(path.join(r, 'Git', 'bin', 'bash.exe'))
);
if(!root) {
console.error('Could not find bash.exe');
process.exit(1);
}
bash = path.join(root, 'Git', 'bin', 'bash.exe');
child_args = [
'--init-file',
path.join(root, 'Git', 'etc', 'profile'),
'-l'
];
}
child_args = child_args.concat(args);
return child_process.spawnSync(bash, child_args, {shell: false, stdio:'inherit', windowsVerbatimArguments: false});
}
function launchNixBash() {
const child_args = args.slice(1);
return child_process.spawnSync(args[0], child_args, {shell: '/bin/bash', stdio:'inherit'});
}