Commit 98a9abb

Anton Medvedev <anton@medv.io>
2022-02-16 20:25:31
Add retry & echo
1 parent 3e4df75
experimental.d.ts
@@ -0,0 +1,26 @@
+// Copyright 2021 Google LLC
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     https://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {ProcessOutput} from './index'
+
+interface Echo {
+  (pieces: TemplateStringsArray, ...args: any[]): Promise<void>
+}
+
+interface Retry {
+  (pieces: TemplateStringsArray, ...args: any[]): Promise<ProcessOutput>
+}
+
+export const echo: Echo
+export const retry: (count: number) => Retry
experimental.mjs
@@ -0,0 +1,44 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {ProcessOutput} from './index.mjs'
+
+// Retries a command a few times. Will return after the first
+// successful attempt, or will throw after specifies attempts count.
+export const retry = (count = 5) => async (cmd, ...args) => {
+  while (count --> 0) try {
+    return await $(cmd, ...args)
+  } catch (p) {
+    if (count === 0) throw p
+  }
+}
+
+// A console.log() alternative which can take ProcessOutput.
+export const echo = (pieces, ...args) => {
+  if (!Array.isArray(pieces) || pieces.length - 1 !== args.length) {
+    throw new Error('The echo is a template string. Use as echo`...`.')
+  }
+  let msg = pieces[0], i = 0
+  while (i < args.length) {
+    msg += stringify(args[i]) + pieces[++i]
+  }
+  console.log(msg)
+}
+
+function stringify(arg) {
+  if (arg instanceof ProcessOutput) {
+    return arg.toString().replace(/\n$/, '')
+  }
+  return `${arg}`
+}
package.json
@@ -5,7 +5,8 @@
   "main": "./index.mjs",
   "exports": {
     ".": "./index.mjs",
-    "./globals": "./globals.mjs"
+    "./globals": "./globals.mjs",
+    "./experimental": "./experimental.mjs"
   },
   "types": "index.d.ts",
   "bin": {
README.md
@@ -338,6 +338,33 @@ files (when using `zx` executable).
 let {version} = require('./package.json')
 ```
 
+### Experimental
+
+The zx also provides a few experimental functions. Please leave a feedback about 
+those features in [the discussion](https://github.com/google/zx/discussions/299).
+
+#### `retry()`
+
+Retries a command a few times. Will return after the first
+successful attempt, or will throw after specifies attempts count.
+
+```js
+import {retry} from 'zx/experimental'
+
+let {stdout} = await retry(5)`curl localhost`
+```
+
+#### ``echo`...` ``
+
+A `console.log()` alternative which can take [ProcessOutput](#processoutput).
+
+```js
+import {echo} from 'zx/experimental'
+
+let branch = await $`git branch --show-current`
+echo`Current branch is ${branch}.`
+```
+
 ### FAQ
 
 #### Passing env variables
test.mjs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 import {strict as assert} from 'assert'
+import {retry} from './experimental.mjs'
 
 { // Only stdout is used during command substitution
   let hello = await $`echo Error >&2; echo Hello`
@@ -218,6 +219,14 @@ import {strict as assert} from 'assert'
   console.log(chalk.greenBright('YAML works'))
 }
 
+{ // Retry works.
+  try {
+    await retry(5)`exit 123`
+  } catch (p) {
+    assert.equal(p.exitCode, 123)
+  }
+}
+
 { // require() is working in ESM
   const {name, version} = require('./package.json')
   assert(typeof name === 'string')