From 792bcd60b6c3708d0fae49ee19e5c74d3ae6a5e7 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Fri, 3 Jun 2022 23:37:05 +0300 Subject: [PATCH] fix: use root ctx as getCtx fallback closes #424 --- package.json | 3 ++- src/context.ts | 12 ++++------ src/core.ts | 62 +++++++++++++++++++++++++++----------------------- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 967350cf64..d54b303f1f 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "coverage": "c8 --reporter=html npm test" }, "dependencies": { + "@qiwi/deep-proxy": "^1.10.2", "@types/fs-extra": "^9.0.13", "@types/minimist": "^1.2.2", "@types/node": "^17.0", @@ -51,7 +52,7 @@ "globby": "^13.1.1", "ignore": "^5.2.0", "minimist": "^1.2.6", - "node-fetch": "^3.2.4", + "node-fetch": "^3.2.5", "ps-tree": "^1.2.0", "which": "^2.0.2", "yaml": "^2.1.1" diff --git a/src/context.ts b/src/context.ts index 75fcb6f30d..1643839018 100644 --- a/src/context.ts +++ b/src/context.ts @@ -20,7 +20,7 @@ export type Options = { cwd: string env: NodeJS.ProcessEnv prefix: string - shell: string + shell: string | boolean maxBuffer: number quote: (v: string) => string spawn: typeof spawn @@ -38,17 +38,15 @@ export type Context = Options & { reject: any } -let root: Options +// @ts-ignore +export let root: Options = function () {} const storage = new AsyncLocalStorage() export function getCtx() { - return storage.getStore() as Context -} -export function setRootCtx(ctx: Options) { - storage.enterWith(ctx) - root = ctx + return storage.getStore() as Context || root } + export function getRootCtx() { return root } diff --git a/src/core.ts b/src/core.ts index 9ce7770e49..49fa367c63 100644 --- a/src/core.ts +++ b/src/core.ts @@ -23,11 +23,12 @@ import { inspect, promisify } from 'node:util' import { spawn } from 'node:child_process' import { chalk, which } from './goods.js' -import { runInCtx, getCtx, setRootCtx, Context, Options } from './context.js' +import { runInCtx, getCtx, root, Context, Options } from './context.js' import { printCmd, log } from './print.js' import { quote, substitute } from './guards.js' import psTreeModule from 'ps-tree' +import { DeepProxy } from '@qiwi/deep-proxy' const psTree = promisify(psTreeModule) @@ -35,35 +36,40 @@ interface Zx extends Options { (pieces: TemplateStringsArray, ...args: any[]): ProcessPromise } -export const $: Zx = function (pieces: TemplateStringsArray, ...args: any[]) { - let resolve, reject - let promise = new ProcessPromise((...args) => ([resolve, reject] = args)) - - let cmd = pieces[0], - i = 0 - let quote = getCtx().quote - while (i < args.length) { - let s - if (Array.isArray(args[i])) { - s = args[i].map((x: any) => quote(substitute(x))).join(' ') - } else { - s = quote(substitute(args[i])) +export const $: Zx = new DeepProxy(root as Zx, ({trapName, DEFAULT, args: _args}) => { + if (trapName === 'apply') { + const [,, [pieces, ...args]] = _args + let resolve, reject + let promise = new ProcessPromise((...args) => ([resolve, reject] = args)) + + let cmd = pieces[0], + i = 0 + let quote = getCtx().quote + while (i < args.length) { + let s + if (Array.isArray(args[i])) { + s = args[i].map((x: any) => quote(substitute(x))).join(' ') + } else { + s = quote(substitute(args[i])) + } + cmd += s + pieces[++i] } - cmd += s + pieces[++i] - } - promise.ctx = { - ...getCtx(), - cmd, - __from: new Error().stack!.split(/^\s*at\s/m)[2].trim(), - resolve, - reject, - } + promise.ctx = { + ...getCtx(), + cmd, + __from: new Error().stack!.split(/^\s*at\s/m)[2].trim(), + resolve, + reject, + } - setImmediate(() => promise._run()) // Make sure all subprocesses are started, if not explicitly by await or then(). + setImmediate(() => promise._run()) // Make sure all subprocesses are started, if not explicitly by await or then(). - return promise -} + return promise + } + + return DEFAULT +}) $.cwd = process.cwd() $.env = process.env @@ -72,12 +78,12 @@ $.spawn = spawn $.verbose = 2 $.maxBuffer = 200 * 1024 * 1024 /* 200 MiB*/ $.prefix = '' // Bash not found, no prefix. +$.shell = true try { $.shell = which.sync('bash') $.prefix = 'set -euo pipefail;' } catch (e) {} -setRootCtx($) export class ProcessPromise extends Promise { child?: ChildProcessByStdio @@ -184,7 +190,7 @@ export class ProcessPromise extends Promise { let options: SpawnOptionsWithStdioTuple = { cwd, - shell: typeof shell === 'string' ? shell : true, + shell, stdio: [this._inheritStdin ? 'inherit' : 'pipe', 'pipe', 'pipe'], windowsHide: true, // TODO: Surprise: maxBuffer have no effect for spawn.