From 09d1e594652dfbca99faa1692559f5ac6772ffc4 Mon Sep 17 00:00:00 2001 From: Gustavo Henke Date: Sun, 26 May 2024 22:06:36 +1000 Subject: [PATCH 1/4] Embed spawn-command into concurrently --- src/concurrently.ts | 5 ++--- src/{get-spawn-opts.spec.ts => spawn.spec.ts} | 2 +- src/{get-spawn-opts.ts => spawn.ts} | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) rename src/{get-spawn-opts.spec.ts => spawn.spec.ts} (95%) rename src/{get-spawn-opts.ts => spawn.ts} (67%) diff --git a/src/concurrently.ts b/src/concurrently.ts index e995939d..06f585f9 100644 --- a/src/concurrently.ts +++ b/src/concurrently.ts @@ -1,7 +1,6 @@ import assert from 'assert'; import _ from 'lodash'; import { cpus } from 'os'; -import spawn from 'spawn-command'; import { Writable } from 'stream'; import treeKill from 'tree-kill'; @@ -13,10 +12,10 @@ import { ExpandNpmWildcard } from './command-parser/expand-npm-wildcard'; import { StripQuotes } from './command-parser/strip-quotes'; import { CompletionListener, SuccessCondition } from './completion-listener'; import { FlowController } from './flow-control/flow-controller'; -import { getSpawnOpts } from './get-spawn-opts'; import { Logger } from './logger'; import { OutputWriter } from './output-writer'; import { PrefixColorSelector } from './prefix-color-selector'; +import { getSpawnOpts, spawn } from './spawn'; const defaults: ConcurrentlyOptions = { spawn, @@ -119,7 +118,7 @@ export type ConcurrentlyOptions = { /** * A function that will spawn commands. - * Defaults to the `spawn-command` module. + * Defaults to a function that spawns using either `cmd.exe` or `/bin/sh`. */ spawn: SpawnCommand; diff --git a/src/get-spawn-opts.spec.ts b/src/spawn.spec.ts similarity index 95% rename from src/get-spawn-opts.spec.ts rename to src/spawn.spec.ts index 935ddd85..2dea9cc6 100644 --- a/src/get-spawn-opts.spec.ts +++ b/src/spawn.spec.ts @@ -1,4 +1,4 @@ -import { getSpawnOpts } from './get-spawn-opts'; +import { getSpawnOpts } from './spawn'; const baseProcess = { platform: 'win32' as const, diff --git a/src/get-spawn-opts.ts b/src/spawn.ts similarity index 67% rename from src/get-spawn-opts.ts rename to src/spawn.ts index a65d6faa..4c84f2af 100644 --- a/src/get-spawn-opts.ts +++ b/src/spawn.ts @@ -1,6 +1,21 @@ -import { SpawnOptions } from 'child_process'; +import { ChildProcess, spawn as baseSpawn, SpawnOptions } from 'child_process'; import supportsColor from 'supports-color'; +/** + * Spawns a command using `cmd.exe` on Windows, or `/bin/sh` elsewhere. + */ +// Implementation based off of https://github.com/mmalecki/spawn-command/blob/v0.0.2-1/lib/spawn-command.js +export function spawn(command: string, options: SpawnOptions): ChildProcess { + let file = '/bin/sh'; + let args = ['-c', command]; + if (process.platform === 'win32') { + file = 'cmd.exe'; + args = ['/s', '/c', `"${command}"`]; + options.windowsVerbatimArguments = true; + } + return baseSpawn(file, args, options); +} + export const getSpawnOpts = ({ colorSupport = supportsColor.stdout, cwd, From e4e41f7b909aec1f401eca775a9c2551a18b32d7 Mon Sep 17 00:00:00 2001 From: Gustavo Henke Date: Sun, 26 May 2024 22:07:10 +1000 Subject: [PATCH 2/4] Remove dependency --- declarations/spawn-command.d.ts | 6 ------ package.json | 1 - pnpm-lock.yaml | 9 +-------- 3 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 declarations/spawn-command.d.ts diff --git a/declarations/spawn-command.d.ts b/declarations/spawn-command.d.ts deleted file mode 100644 index 4f1cd5fe..00000000 --- a/declarations/spawn-command.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'spawn-command' { - import { ChildProcess, SpawnOptions } from 'child_process'; - - function spawnCommand(command: string, options: SpawnOptions): ChildProcess; - export = spawnCommand; -} diff --git a/package.json b/package.json index 6ec63e19..e1b6a5d0 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", - "spawn-command": "0.0.2-1", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b0a019a0..f49535d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: false @@ -20,9 +20,6 @@ dependencies: shell-quote: specifier: ^1.8.1 version: 1.8.1 - spawn-command: - specifier: 0.0.2-1 - version: 0.0.2-1 supports-color: specifier: ^8.1.1 version: 8.1.1 @@ -4386,10 +4383,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /spawn-command@0.0.2-1: - resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} - dev: false - /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true From cad40b42c08e0d019f3643f030283fac4a50d1f9 Mon Sep 17 00:00:00 2001 From: Gustavo Henke Date: Sun, 26 May 2024 22:07:36 +1000 Subject: [PATCH 3/4] Remove reference from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7f1ad32d..a9edd791 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ tired of opening terminals and made **concurrently**. - Cross platform (including Windows) - Output is easy to follow with prefixes - With `--kill-others` switch, all commands are killed if one dies -- Spawns commands with [spawn-command](https://github.com/mmalecki/spawn-command) ## Installation From 3f61979f2b6f356bef0a30dad8d20b90c1a62326 Mon Sep 17 00:00:00 2001 From: Gustavo Henke Date: Sun, 26 May 2024 23:16:52 +1000 Subject: [PATCH 4/4] Add tests --- src/spawn.spec.ts | 58 +++++++++++++++++++++++++++++++---------------- src/spawn.ts | 10 ++++++-- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/spawn.spec.ts b/src/spawn.spec.ts index 2dea9cc6..9fb7ec88 100644 --- a/src/spawn.spec.ts +++ b/src/spawn.spec.ts @@ -1,4 +1,4 @@ -import { getSpawnOpts } from './spawn'; +import { getSpawnOpts, spawn } from './spawn'; const baseProcess = { platform: 'win32' as const, @@ -6,29 +6,47 @@ const baseProcess = { env: {}, }; -it('sets detached mode to false for Windows platform', () => { - expect(getSpawnOpts({ process: baseProcess }).detached).toBe(false); -}); +describe('spawn()', () => { + it('spawns the given command', async () => { + const fakeSpawn = jest.fn(); + spawn('echo banana', {}, fakeSpawn, baseProcess); + expect(fakeSpawn).toHaveBeenCalled(); + expect(fakeSpawn.mock.calls[0][1].join(' ')).toContain('echo banana'); + }); -it('sets stdio to inherit when raw', () => { - expect(getSpawnOpts({ raw: true }).stdio).toBe('inherit'); + it('returns spawned process', async () => { + const childProcess = {}; + const fakeSpawn = jest.fn().mockReturnValue(childProcess); + const child = spawn('echo banana', {}, fakeSpawn, baseProcess); + expect(child).toBe(childProcess); + }); }); -it('merges FORCE_COLOR into env vars if color supported', () => { - const process = { ...baseProcess, env: { foo: 'bar' } }; - expect(getSpawnOpts({ process, colorSupport: false }).env).toEqual(process.env); - expect(getSpawnOpts({ process, colorSupport: { level: 1 } }).env).toEqual({ - FORCE_COLOR: '1', - foo: 'bar', +describe('getSpawnOpts()', () => { + it('sets detached mode to false for Windows platform', () => { + expect(getSpawnOpts({ process: baseProcess }).detached).toBe(false); }); -}); -it('sets default cwd to process.cwd()', () => { - const process = { ...baseProcess, cwd: () => 'process-cwd' }; - expect(getSpawnOpts({ process }).cwd).toBe('process-cwd'); -}); + it('sets stdio to inherit when raw', () => { + expect(getSpawnOpts({ raw: true }).stdio).toBe('inherit'); + }); -it('overrides default cwd', () => { - const cwd = 'foobar'; - expect(getSpawnOpts({ cwd }).cwd).toBe(cwd); + it('merges FORCE_COLOR into env vars if color supported', () => { + const process = { ...baseProcess, env: { foo: 'bar' } }; + expect(getSpawnOpts({ process, colorSupport: false }).env).toEqual(process.env); + expect(getSpawnOpts({ process, colorSupport: { level: 1 } }).env).toEqual({ + FORCE_COLOR: '1', + foo: 'bar', + }); + }); + + it('sets default cwd to process.cwd()', () => { + const process = { ...baseProcess, cwd: () => 'process-cwd' }; + expect(getSpawnOpts({ process }).cwd).toBe('process-cwd'); + }); + + it('overrides default cwd', () => { + const cwd = 'foobar'; + expect(getSpawnOpts({ cwd }).cwd).toBe(cwd); + }); }); diff --git a/src/spawn.ts b/src/spawn.ts index 4c84f2af..510d46de 100644 --- a/src/spawn.ts +++ b/src/spawn.ts @@ -5,7 +5,13 @@ import supportsColor from 'supports-color'; * Spawns a command using `cmd.exe` on Windows, or `/bin/sh` elsewhere. */ // Implementation based off of https://github.com/mmalecki/spawn-command/blob/v0.0.2-1/lib/spawn-command.js -export function spawn(command: string, options: SpawnOptions): ChildProcess { +export function spawn( + command: string, + options: SpawnOptions, + // For testing + spawn: (command: string, args: string[], options: SpawnOptions) => ChildProcess = baseSpawn, + process: Pick = global.process, +): ChildProcess { let file = '/bin/sh'; let args = ['-c', command]; if (process.platform === 'win32') { @@ -13,7 +19,7 @@ export function spawn(command: string, options: SpawnOptions): ChildProcess { args = ['/s', '/c', `"${command}"`]; options.windowsVerbatimArguments = true; } - return baseSpawn(file, args, options); + return spawn(file, args, options); } export const getSpawnOpts = ({