65 lines
2.1 KiB
JavaScript
65 lines
2.1 KiB
JavaScript
/**
|
|
* Pipeline child-ctx clone, raw-chunk capture, and optional stage timeout.
|
|
*/
|
|
|
|
/**
|
|
* Shallow clone for pipeline **`/bin`** execution: session **`env`**, optional **`shellStdin`**, and
|
|
* **`bareOsStdoutCaptured`** when stdout is captured (pipe to next stage or **`>`** redirect) so
|
|
* utilities (e.g. **`ls`**) can use one-record-per-line output.
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {Record<string, string>} env
|
|
* @param {string | null} stdinText
|
|
* @param {boolean} bareOsStdoutCaptured
|
|
*/
|
|
export function bareOsPipelineChildCtx(ctx, env, stdinText, bareOsStdoutCaptured) {
|
|
const o = Object.assign({}, ctx, {
|
|
env: env && typeof env === 'object' ? { ...env } : env,
|
|
bareOsStdoutCaptured
|
|
})
|
|
if (stdinText != null) o.shellStdin = stdinText
|
|
return o
|
|
}
|
|
|
|
/**
|
|
* Convert raw binary chunks into shell pipeline capture text.
|
|
* Pipeline transport is text-based, so bytes are mapped 1:1 via char codes.
|
|
* @param {string | Uint8Array} chunk
|
|
*/
|
|
export function bareOsPipelineRawChunkToText(chunk) {
|
|
if (typeof chunk === 'string') return chunk
|
|
if (!(chunk instanceof Uint8Array)) return String(chunk)
|
|
let s = ''
|
|
for (let i = 0; i < chunk.length; i++) s += String.fromCharCode(chunk[i])
|
|
return s
|
|
}
|
|
|
|
/**
|
|
* Optional timeout guard for potentially stalled pipeline stages.
|
|
* @param {Record<string, string>} env
|
|
* @param {() => Promise<unknown>} run
|
|
* @param {string} label
|
|
*/
|
|
export async function runWithShellPipelineStageTimeout(env, run, label) {
|
|
const raw = Number.parseInt(String(env.BARE_OS_SHELL_PIPELINE_STAGE_TIMEOUT_MS || ''), 10)
|
|
const timeoutMs = Number.isFinite(raw) && raw > 0 ? Math.min(raw, 120000) : 0
|
|
if (!timeoutMs) return await run()
|
|
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
let timer = null
|
|
try {
|
|
return await Promise.race([
|
|
run(),
|
|
new Promise((_, reject) => {
|
|
timer = setTimeout(() => {
|
|
reject(
|
|
new Error(
|
|
`shell: pipeline stage timeout (${timeoutMs}ms): ${label}`
|
|
)
|
|
)
|
|
}, timeoutMs)
|
|
})
|
|
])
|
|
} finally {
|
|
if (timer) clearTimeout(timer)
|
|
}
|
|
}
|