v6
1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import { ProcessOutput, $, Zx } from './core.js'
16import { sleep } from './goods.js'
17import { isString } from './util.js'
18import { getCtx, runInCtx } from './context.js'
19import { log } from './print.js'
20
21export { log }
22
23// Retries a command a few times. Will return after the first
24// successful attempt, or will throw after specifies attempts count.
25export function retry(count = 5, delay = 0) {
26 return async function (cmd: TemplateStringsArray, ...args: any[]) {
27 while (count-- > 0)
28 try {
29 return await $(cmd, ...args)
30 } catch (p) {
31 if (count === 0) throw p
32 if (delay) await sleep(delay)
33 }
34 return
35 }
36}
37
38// Runs and sets a timeout for a cmd
39export function withTimeout(timeout: number, signal: string) {
40 return async function (cmd: TemplateStringsArray, ...args: any[]) {
41 let p = $(cmd, ...args)
42 if (!timeout) return p
43
44 let timer = setTimeout(() => p.kill(signal), timeout)
45
46 return p.finally(() => clearTimeout(timer))
47 }
48}
49
50// A console.log() alternative which can take ProcessOutput.
51export function echo(pieces: TemplateStringsArray, ...args: any[]) {
52 let msg
53 let lastIdx = pieces.length - 1
54 if (
55 Array.isArray(pieces) &&
56 pieces.every(isString) &&
57 lastIdx === args.length
58 ) {
59 msg =
60 args.map((a, i) => pieces[i] + stringify(a)).join('') + pieces[lastIdx]
61 } else {
62 msg = [pieces, ...args].map(stringify).join(' ')
63 }
64 console.log(msg)
65}
66
67function stringify(arg: ProcessOutput | any) {
68 if (arg instanceof ProcessOutput) {
69 return arg.toString().replace(/\n$/, '')
70 }
71 return `${arg}`
72}
73
74// Starts a simple CLI spinner, and returns stop() func.
75export function startSpinner(title = '') {
76 let i = 0,
77 spin = () => process.stdout.write(` ${'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'[i++ % 10]} ${title}\r`)
78 return (
79 (id) => () =>
80 clearInterval(id)
81 )(setInterval(spin, 100))
82}
83
84export function ctx<R extends any>(cb: (_$: Zx) => R, ref: Zx = $.bind(null)): R {
85 const _$ = Object.assign(ref, getCtx())
86
87 return runInCtx(_$, cb, _$)
88}