Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/c4spar/deno-dzx
🦕 Deno shell tools inspired by zx.
https://github.com/c4spar/deno-dzx
Last synced: 13 days ago
JSON representation
🦕 Deno shell tools inspired by zx.
- Host: GitHub
- URL: https://github.com/c4spar/deno-dzx
- Owner: c4spar
- License: mit
- Created: 2021-05-07T21:06:56.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2022-07-17T18:29:09.000Z (over 2 years ago)
- Last Synced: 2024-10-23T06:07:25.434Z (21 days ago)
- Language: TypeScript
- Homepage:
- Size: 269 KB
- Stars: 132
- Watchers: 3
- Forks: 4
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
dzx
Deno shell tools inspired by zx## Example
> **Warning** This project is in a very experimental state. Many things are
> subject to change.```typescript
import {
$,
async,
cd,
fs,
io,
path,
} from "https://deno.land/x/[email protected]/mod.ts";// Output stdout & stderr. Can be: true, false, 0, 1 or 2. Default is: 1
$.verbose = 2;
$.shell = "/usr/local/bin/zsh";console.log(`Hello from ${$.blue.bold("dzx")}!`);
const branch = await $`git branch --show-current`;
await $`dep deploy --branch=${branch}`;await Promise.all([
$`deno lint`,
$`deno fmt --check`,
$`deno test --allow-all`,
]);const name = "foo bar";
await $`mkdir ./tmp/${name}`; // Params will be quoted if required: /tmp/'foo bar'.cd("tmp/foo bar");
console.log(Deno.cwd()); // ./tmp/foo barcd("tmp");
console.log(Deno.cwd()); // ./tmpawait async.delay(1000);
const basename = path.basename(import.meta.url);
const stdin = await io.readAll(Deno.stdin);
await fs.ensureDir("./tmp");
```## Content
- [Usage](#usage)
- [Shell](#shell)
- [Variables](#variables)
- [Methods](#methods)
- [Process](#process)
- [Std modules](#std-modules)
- [Globals](#globals)
- [CLI](#cli)
- [Install](#install)
- [Execute scripts via cli](#execute-scripts-via-cli)
- [Permissions](#permissions)
- [Markdown](#markdown)
- [Experimental](#experimental)
- [Worker](#worker)
- [Contributing](#contributing)
- [License](#license)## Usage
`dzx` has different entry points.
- `./mod.ts`: Exports the shell and all std modules.
```ts
import { $, cd, path } from "https://deno.land/x/[email protected]/mod.ts";
// or
import $ from "https://deno.land/x/[email protected]/mod.ts";
```- `./shell.ts`: Exports only the shell.
```ts
import { $ } from "https://deno.land/x/[email protected]/shell.ts";
// or
import $ from "https://deno.land/x/[email protected]/shell.ts";
```### Shell
The `$` symbol (shell) is the main context of `dzx`.
#### Variables
- **$.shell:** Set the shell that is used by `` $`command` ``. Default:
`/bin/bash`
- **$.prefix:** Command prefix. Default: `set -euo pipefail;`.
- **$.mainModule:** The executed dzx script.
- **$.verbose:** Enable debugging output (log shell commands and execution
time).
- **$.stdout:** Change stdout mode of `` $`command` ``. Can be `"inherit"`,
`"piped"`, `"null"` or `number`. Default: `"piped"`
- **$.stderr:** Change stderr mode of `` $`command` ``. Can be `"inherit"`,
`"piped"`, `"null"` or `number`. Default: `"piped"`
- **$.args:** Equivalent to `Deno.args`, but without the script name as first
argument.
- **$.startTime:** The execution start time in ms.
- **$.time:** The time left since execution start (now() - $.startTime).
- **$.quote:** Parser method that is used to safely quote strings. Used by:
`` $`command` ``#### Methods
- `` $`command` ``: Executes a shell command and returns a `Process` instance.
The [`Process`](#process) class has several chainable methods.```ts
const count = parseInt(await $`ls -1 | wc -l`);
console.log(`Files count: ${count}`);
```If the executed program was successful, an instance of `ProcessOutput` will be
return.```ts
class ProcessOutput {
readonly stdout: string;
readonly stderr: string;
readonly combined: string;
readonly status: Deno.ProcessStatus;
toString(): string;
}
```If the executed program returns a non-zero exit code, a `ProcessError` will be
thrown.The `ProcessError` class extends from the `Error` class and implements all
properties and methods from `ProcessOutput`.```ts
try {
await $`exit 1`;
} catch (error) {
console.log(`Exit code: ${error.status.code}`);
console.log(`Error: ${error.stderr}`);
}
```- `` $o`command` ``: Executes a shell command and _only returns its trimmed
stdout_ (without throwing an error)```ts
const stdout = await $o`pwd`);
console.log(stdout); // -> '/home/code/project
```If the executed program returns a non-zero exit code, no error will be thrown.
Either the failed processes stdout will be the return value, or an empty
string will be returned by default```ts
const stdout = await $o`echo 'hello' >&2; exit 1;`);
console.log(stdout); // -> ""
```- `` $e`command` ``: Executes a shell command and _only returns its trimmed
stderr_ (without throwing an error)```ts
const stderr = await $e`pwd`);
console.log(stderr); // -> ""
```If the executed program returns a non-zero exit code, no error will be thrown.
Either the failed processes stderr will be the return value, or an empty
string will be returned by default```ts
const stderr = await $e`echo 'hello' >&2; exit 1;`);
console.log(stderr); // -> "hello"
```- `cd()`: Change the current working directory. If path does not exist, an error
is thrown. The path is always relative to the original `cwd`, unless the path
is an absolute path or starts with `~` which indecates the home directory.```ts
console.log(Deno.cwd()); // --> /example/directory
cd("foo/bar");
console.log(Deno.cwd()); // --> /example/directory/foo/bar
cd("foo/baz");
console.log(Deno.cwd()); // --> /example/directory/foo/baz
cd("/tmp");
console.log(Deno.cwd()); // --> /tmp
cd("~/Documents");
console.log(Deno.cwd()); // --> [HOME]/Documents
```- `` quote`string` ``: The quote methods quotes safly a string. by default the
`shq` package is used. Can be overidden with `$.quote`.#### Process
Methods and properties of the `Process` class which implements
`Promise` and is returned by the `$` method.- `.pid`: Returns the process id of the executed command.
```ts
// Get the process id.
const child = $`echo foo`;
console.log("pid:", child.pid);
await child;
```- `.noThrow`: If invoked the command doesn't throw an error if the command
returns a none-zero exit code.```ts
// Don't throw an error for none-zero exit codes.
const { status } = await $`exit 1`.noThrow;
```- `.statusCode`: Returns the status code of the executed command and calls
`.noThrow` internally to catch the error and return the status code.```ts
// Get only the status code.
const statusCode: number = await $`exit 1`.statusCode;
```- `.stdout` Returns `Promise` and resolves with the stdout output.
```ts
// Get only stdout.
const foo: string = await $`echo foo; echo bar >&2`.stdout;
```- `.stderr` Returns `Promise` and resolves with the stderr output.
```ts
// Get only stderr.
const bar: string = await $`echo foo; echo bar >&2`.stderr;
```- `.retry(retries: number | RetryCallback)` Retry the command `n` times if it
fails.```ts
// Retry the command 3 times.
await $`exit 1`.retry(3);// Retry the command 3 times using a callback handler.
await $`exit 1`.retry(({ retries }: ProcessError) => retries < 3);
```- `.delay(delay: number)` Number of milliseconds to delay the retry of a failed
command. Default: `500````ts
// Retry the command 3 times but wait 1sec before executing it again.
await $`exit 1`.retry(3).delay(1000);
```- `.timeout(timeout: number)` Throws an error if the command takes longer than
the provided `timeout` in milliseconds.```ts
// Kill the command if it takes longer than one second.
await $`sleep 10`.timeout(1000);
```- `.cwd(path: string)` Set the cwd for the current process.
```ts
// Change process cwd.
await $`pwd`.cwd("examples");
```- `.env(name: string, value: string | number | boolean | Record)`
Defines an environment variable which is only set for the current process. If
the value is an object, `JSON.stringify(value)` will be used as value for the
environment variable.```ts
// Pass environment variable to process.
await $`echo $FOO_BAR`.env("FOO_BAR", 123);
```- `.kill(signal: Deno.Signal)` Kills the running process.
```ts
// Manually kill the command.
const child = $`sleep 10`;
setTimout(() => child.kill("SIGINT"), 100);
await child;
```### Std modules
> **Note** The `./mod.ts` module exports several `deno/std` modules. If you
> don't need these modules you can just import the `$` symbol from the
> `./shell.ts` module.- **$.\[style]:** Cliffy's color module. A chainable wrapper for Deno's
`std/fmt/colors` module. Available on the global `$` symbol.```ts
console.log($.blue.bold("Hello world!"));
```- **async:** Deno's `std/async` module.
```ts
await async.delay(1000);
```- **path:** Deno's `std/path` module.
```ts
const basename = path.basename(import.meta.url);
const options: path.GlobToRegExpOptions = { os: "linux" };
const regex: RegExp = path.globToRegExp("*.ts", options);
```- **io:** Deno's `std/io` module.
```ts
const fileReader = await Deno.open("./example.txt");
for await (let line of io.readLines(fileReader)) {
console.log(line);
}
```- **streams:** Deno's `std/streams` module.
```ts
const data = await streams.readAll(Deno.stdin);
```- **fs:** Deno's `std/fs` module.
```ts
fs.ensureDir("./tmp");
```- **log:** Deno's `std/log` module.
```ts
log.info("Some info!");
```- **flags:** Deno's `std/flags` module.
```ts
const args: flags.Args = flags.parse($.args);
```### Globals
> **Note** Globals are mostly used by the cli. In most cases you don't need
> globals and you can just import all members from `./mod.ts` or `./shell.ts`.When impoting `./globals.ts`, all members exported by `./mod.ts` are globally
available.```ts
import "https://deno.land/x/[email protected]/globals.ts";cd("foo/bar");
await $`ls | wc -l`;
```## CLI
The CLI is a tool-chain and playground for dzx. It can execute scripts and
provides some sub-commands like `repl` and `eval` where `dzx` is globally
available.### Install
```
deno install --allow-all -f https://deno.land/x/[email protected]/dzx.ts
```### Commands
- **dzx** `[script] [...args]`: Run a local or remote dzx script (optional in a
web worker). If invoked without argument the `repl` will be started.```shell
dzx --worker ./example.ts
```- **dzx bundle** `[script]`: Bundle a dzx script to a standalone deno script.
Can also read from stdin.```shell
dzx bundle ./example.ts > bundle.js
deno run --allow-read --allow-env --allow-run bundle.js
```- **dzx compile** `[...permissions] [script] [...script-arguments]`: Compile an
dzx script to a standalone binary. Can also read from stdin.```shell
dzx compile --allow-read --allow-env --allow-run ./example.ts --port 8080
```> Note that when reading from `stdin`, you must separate "deno compile" flags
> (i.e. your permissions) from your "script args" with a double dash (`--`),
> i.e.
> ```shell
> cat ./example.ts | dzx compile --allow-read -- --port 8080
> ```
> It is also recommended when reading from `stdin` that you pass the --output
> flag with your permissions to specify the output file name, otherwise the
> compiled file will be emitted with a random value as its name.- **dzx eval**: Evaluate a dzx script from command line.
```shell
dzx eval "console.log($.shell)"
```Eval can also read from stdin:
```shell
echo "console.log($.shell)" | dzx eval
```- **dzx repl**: Start a dzx repl (Read eval print loop).
The `repl` command starts a deno repl bootstrapped with the dzx runtime code.
- **dzx upgrade**: Upgrade the `dzx` executable to latest or given version.
Upgrade to latest version:
```shell
dzx upgrade
```Upgrade to specific version:
```shell
dzx upgrade --version 3.0.0
```List all available versions:
```shell
dzx upgrade --list-versions
```### Execute scripts via cli
You can run a script with the cli by simply calling dzx followed by the filename
`dzx script.ts`.When a dzx script is executed via CLI, you don't need to import anything. All
exports are automatically globally available. This applies also to commands like
`dzx eval "console.log($)"`.To create an executable script, add next shebang at the beginning of your
script:```
#!/usr/bin/env dzx
```After making your script executable,
```shell
chmod +x ./script.js
```you can simply run it with:
```shell
./script.js
```To enable typescript support in your IDE, you can optionally add a tripple slash
reference to the top of the file.```
#!/usr/bin/env dzx
///
```### Permissions
You can use `dzx` without installation by using next shebang. This also allows
you to explicitly set the permissions for your script.```typescript
#!/usr/bin/env deno run --allow-run --allow-read --allow-env https://deno.land/x/[email protected]/dzx.ts
///console.log(`Hello ${$.blue.bold("world")}!`);
```### Markdown
With `dzx` you can run the `js`/`ts` code blocks from a Markdown file as if they
were a regular script. This is very convenient when you want to blend some
nicely formatted documentation in with the actual steps of execution.Give it a try by running:
```bash
dzx ./examples/markdown.md
```> **Note** See the [markdown example](./examples/markdown.md) for further
> documentation and notes.### Experimental
#### worker
> **Warning** This is an exerminental feature. Permission flags doesn't support
> values currently. Read permissions are required by default.If `dzx` is called with `-w` or `--worker`, the script is executed inside an
isolated web worker. If enabled, you can pass explicit permissions directly to
the `dzx` cli.```typescript
#!/usr/bin/env dzx --worker --allow-read
///console.log(`Hello from ${$.blue.bold("worker")}!`);
```## Contributing
Any kind of contribution is very welcome!
## License
[MIT](LICENSE)