|
1 | 1 | import Ajv from 'ajv'; |
2 | 2 | import { |
3 | | - ApplyRequestData, ImportRequestData, ImportResponseData, |
| 3 | + ApplyRequestData, |
| 4 | + CommandRequestData, |
| 5 | + CommandRequestDataSchema, |
| 6 | + ImportRequestData, |
| 7 | + ImportResponseData, |
4 | 8 | InitializeResponseData, |
5 | 9 | IpcMessageSchema, |
6 | 10 | IpcMessageV2, |
7 | | - MessageCmd, PlanRequestData, PlanResponseData, |
8 | | - SpawnStatus, |
9 | | - SudoRequestData, |
10 | | - SudoRequestDataSchema, ValidateRequestData, ValidateResponseData |
| 11 | + MessageCmd, |
| 12 | + PlanRequestData, |
| 13 | + PlanResponseData, |
| 14 | + ValidateRequestData, |
| 15 | + ValidateResponseData |
11 | 16 | } from 'codify-schemas'; |
12 | 17 | import { nanoid } from 'nanoid'; |
13 | | -import { ChildProcess, SpawnOptions, fork, spawn } from 'node:child_process'; |
| 18 | +import { ChildProcess, fork } from 'node:child_process'; |
| 19 | +import fs from 'node:fs/promises'; |
| 20 | +import * as os from 'node:os'; |
14 | 21 | import path from 'node:path'; |
15 | 22 |
|
| 23 | +import { spawnSafe } from './spawn.js'; |
16 | 24 | import { CodifyTestUtils } from './test-utils.js'; |
17 | | -import fs from 'node:fs/promises'; |
18 | | -import * as os from 'node:os'; |
19 | 25 |
|
20 | 26 | const ajv = new Ajv.default({ |
21 | 27 | strict: true |
22 | 28 | }); |
23 | 29 |
|
24 | 30 | const ipcMessageValidator = ajv.compile(IpcMessageSchema); |
25 | | -const sudoRequestValidator = ajv.compile(SudoRequestDataSchema); |
| 31 | +const commandRequestValidator = ajv.compile(CommandRequestDataSchema); |
26 | 32 |
|
27 | 33 | export class PluginProcess { |
28 | 34 | childProcess: ChildProcess |
@@ -108,26 +114,26 @@ export class PluginProcess { |
108 | 114 | throw new Error(`Invalid message from plugin. ${JSON.stringify(message, null, 2)}`); |
109 | 115 | } |
110 | 116 |
|
111 | | - if (message.cmd === MessageCmd.SUDO_REQUEST) { |
| 117 | + if (message.cmd === MessageCmd.COMMAND_REQUEST) { |
112 | 118 | const { data, requestId } = message; |
113 | | - if (!sudoRequestValidator(data)) { |
114 | | - throw new Error(`Invalid sudo request from plugin. ${JSON.stringify(sudoRequestValidator.errors, null, 2)}`); |
| 119 | + if (!commandRequestValidator(data)) { |
| 120 | + throw new Error(`Invalid sudo request from plugin. ${JSON.stringify(commandRequestValidator.errors, null, 2)}`); |
115 | 121 | } |
116 | 122 |
|
117 | | - const { command, options } = data as unknown as SudoRequestData; |
118 | | - const result = await sudoSpawn(command, options); |
| 123 | + const { command, options } = data as unknown as CommandRequestData; |
| 124 | + const result = await spawnSafe(command, options); |
119 | 125 |
|
120 | 126 | cp.send(<IpcMessageV2>{ |
121 | | - cmd: MessageCmd.SUDO_REQUEST + '_Response', |
| 127 | + cmd: MessageCmd.COMMAND_REQUEST + '_Response', |
122 | 128 | data: result, |
123 | 129 | requestId, |
124 | 130 | }) |
125 | 131 | } |
126 | 132 |
|
127 | 133 | if (message.cmd === MessageCmd.PRESS_KEY_TO_CONTINUE_REQUEST) { |
128 | 134 | const { data, requestId } = message; |
129 | | - if (!sudoRequestValidator(data)) { |
130 | | - throw new Error(`Invalid sudo request from plugin. ${JSON.stringify(sudoRequestValidator.errors, null, 2)}`); |
| 135 | + if (!commandRequestValidator(data)) { |
| 136 | + throw new Error(`Invalid sudo request from plugin. ${JSON.stringify(commandRequestValidator.errors, null, 2)}`); |
131 | 137 | } |
132 | 138 |
|
133 | 139 | cp.send(<IpcMessageV2>{ |
@@ -155,59 +161,3 @@ export class PluginProcess { |
155 | 161 | } |
156 | 162 |
|
157 | 163 | } |
158 | | - |
159 | | -type CodifySpawnOptions = { |
160 | | - cwd?: string; |
161 | | - throws?: boolean, |
162 | | -} & Omit<SpawnOptions, 'detached' | 'shell' | 'stdio'> |
163 | | - |
164 | | -/** |
165 | | - * |
166 | | - * @param cmd Command to run. Ex: `rm -rf` |
167 | | - * @param opts Options for spawn |
168 | | - * |
169 | | - * @see promiseSpawn |
170 | | - * @see spawn |
171 | | - * |
172 | | - * @returns SpawnResult { status: SUCCESS | ERROR; data: string } |
173 | | - */ |
174 | | -async function sudoSpawn( |
175 | | - cmd: string, |
176 | | - opts: CodifySpawnOptions, |
177 | | -): Promise<{ data: string, status: SpawnStatus }> { |
178 | | - return new Promise((resolve) => { |
179 | | - const output: string[] = []; |
180 | | - |
181 | | - const _cmd = `sudo ${cmd}`; |
182 | | - |
183 | | - // Source start up shells to emulate a users environment vs. a non-interactive non-login shell script |
184 | | - // Ignore all stdin |
185 | | - const _process = spawn(`source ~/.zshrc; ${_cmd}`, [], { |
186 | | - ...opts, |
187 | | - shell: 'zsh', |
188 | | - stdio: ['ignore', 'pipe', 'pipe'], |
189 | | - }); |
190 | | - |
191 | | - const { stderr, stdout } = _process |
192 | | - stdout.setEncoding('utf8'); |
193 | | - stderr.setEncoding('utf8'); |
194 | | - |
195 | | - stdout.on('data', (data) => { |
196 | | - output.push(data.toString()); |
197 | | - }) |
198 | | - |
199 | | - stderr.on('data', (data) => { |
200 | | - output.push(data.toString()); |
201 | | - }) |
202 | | - |
203 | | - stdout.pipe(process.stdout); |
204 | | - stderr.pipe(process.stderr); |
205 | | - |
206 | | - _process.on('close', (code) => { |
207 | | - resolve({ |
208 | | - data: output.join(''), |
209 | | - status: code === 0 ? SpawnStatus.SUCCESS : SpawnStatus.ERROR, |
210 | | - }) |
211 | | - }) |
212 | | - }) |
213 | | -} |
0 commit comments