diff --git a/bin/pact-broker.ts b/bin/pact-broker.ts index 2927c077..6c614acd 100644 --- a/bin/pact-broker.ts +++ b/bin/pact-broker.ts @@ -1,14 +1,20 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.brokerFullPath, - process.argv.slice(2), + standalone().brokerFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pact-message.ts b/bin/pact-message.ts index aae607ae..d1d2214c 100644 --- a/bin/pact-message.ts +++ b/bin/pact-message.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.messageFullPath, - process.argv.slice(2), + standalone().messageFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pact-mock-service.ts b/bin/pact-mock-service.ts index f4967f26..b3542900 100644 --- a/bin/pact-mock-service.ts +++ b/bin/pact-mock-service.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.mockServiceFullPath, - process.argv.slice(2), + standalone().mockServiceFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pact-provider-verifier.ts b/bin/pact-provider-verifier.ts index b4152fc6..706fc925 100644 --- a/bin/pact-provider-verifier.ts +++ b/bin/pact-provider-verifier.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.verifierFullPath, - process.argv.slice(2), + standalone().verifierFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pact-stub-service.ts b/bin/pact-stub-service.ts index 690a9c49..3e02e29c 100644 --- a/bin/pact-stub-service.ts +++ b/bin/pact-stub-service.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.stubFullPath, - process.argv.slice(2), + standalone().stubFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pact.ts b/bin/pact.ts index 3c51100e..d4afad30 100644 --- a/bin/pact.ts +++ b/bin/pact.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.pactFullPath, - process.argv.slice(2), + standalone().pactFullPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/bin/pactflow.ts b/bin/pactflow.ts index afde93a4..fddc26fd 100644 --- a/bin/pactflow.ts +++ b/bin/pactflow.ts @@ -1,14 +1,21 @@ #!/usr/bin/env node import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; +import { + standalone, + standaloneUseShell, + setStandaloneArgs, +} from '../src/pact-standalone'; + +const args = process.argv.slice(2); +const opts = standaloneUseShell ? { shell: true } : {}; const { error, status } = childProcess.spawnSync( - rubyStandalone.pactflowFullPath, - process.argv.slice(2), + standalone().pactflowPath, + setStandaloneArgs(args, standaloneUseShell), { stdio: 'inherit', - shell: true, + ...opts, } ); if (error) throw error; diff --git a/src/pact-standalone.ts b/src/pact-standalone.ts index 94a0ccf8..3dc11632 100644 --- a/src/pact-standalone.ts +++ b/src/pact-standalone.ts @@ -67,4 +67,49 @@ export const standalone = ( }; }; +const isWindows = process.platform === 'win32'; + +function quoteCmdArg(arg: string) { + return `"${arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; +} + +function quotePwshArg(arg: string) { + return `'${arg.replace(/'/g, "''")}'`; +} + +function quotePosixShArg(arg: string) { + return `'${arg.replace(/'/g, "'\\''")}'`; +} + +function testWindowsExe(cmd: string, file: string) { + return new RegExp(`^(?:.*\\\\)?${cmd}(?:\\.exe)?$`, 'i').test(file); +} + +function parseArgs(unparsed_args: string[]) { + if (isWindows === true) { + const file = process.env['comspec'] || 'cmd.exe'; + if (testWindowsExe('cmd', file) === true) { + return unparsed_args.map((i) => quoteCmdArg(i)); + } + if (testWindowsExe('(powershell|pwsh)', file) || file.endsWith('/pwsh')) { + return unparsed_args.map((i) => quotePwshArg(i)); + } + return unparsed_args; + } + return unparsed_args.map((i) => quotePosixShArg(i)); +} + +export function setStandaloneArgs( + unparsed_args: string[], + shell: boolean +): string[] { + let parsedArgs = unparsed_args; + if (shell === true) { + parsedArgs = parseArgs(unparsed_args); + } + return parsedArgs; +} + +export const standaloneUseShell = isWindows; + export default standalone();