Skip to content

Commit

Permalink
fix: use root ctx as getCtx fallback
Browse files Browse the repository at this point in the history
closes #424
  • Loading branch information
antongolub committed Jun 3, 2022
1 parent 6fe3031 commit 3604b46
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 36 deletions.
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -41,6 +41,7 @@
"coverage": "c8 --reporter=html npm test"
},
"dependencies": {
"@qiwi/deep-proxy": "^1.10.3",
"@types/fs-extra": "^9.0.13",
"@types/minimist": "^1.2.2",
"@types/node": "^17.0",
Expand All @@ -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"
Expand Down
12 changes: 5 additions & 7 deletions src/context.ts
Expand Up @@ -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
Expand All @@ -38,17 +38,15 @@ export type Context = Options & {
reject: any
}

let root: Options
// @ts-ignore
export let root: Options = function () {}

const storage = new AsyncLocalStorage<Options>()

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
}
Expand Down
62 changes: 34 additions & 28 deletions src/core.ts
Expand Up @@ -23,47 +23,53 @@ 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)

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<Zx>(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
Expand All @@ -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<ProcessOutput> {
child?: ChildProcessByStdio<Writable, Readable, Readable>
Expand Down Expand Up @@ -184,7 +190,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {

let options: SpawnOptionsWithStdioTuple<any, StdioPipe, StdioPipe> = {
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.
Expand Down

0 comments on commit 3604b46

Please sign in to comment.