Skip to main content
The Deno 2 Release Candidate is here
Learn more
Module

x/proc/legacy/runners/handlers/README.md

A better way to work with processes in Deno.
Latest
File

Examples

Easy

Just Run a Command

If you just want to run a command, try simpleRunner(). It is a specialized, one-off solution, but this use case comes up a lot. It works when stdin is empty, and you don’t really care about stdout and stderr (they are written to stdout and stderr of the parent process).

In this example, I am wrapping the whole thing in a function so I can open and close the Group locally.

spd-say is installed by default on Ubuntu.

async function say(text: string): Promise<void> {
  const pg = proc.group();
  try {
    await proc.simpleRunner(pg).run({
      cmd: [
        "spd-say",
        "-w",
        "-t",
        "female3",
        text,
      ],
    });
  } finally {
    pg.close();
  }
}

await say(
  "moo moo farms are the best cow farms ever. They say moo, " +
    "they don't pollute the earth, and they give milk. Visit " +
    "moo moo farms today for only twelve easy payments of seventeen " +
    "ninety five weekly!",
);

Non-Streaming Handlers

Non-streaming data is convenient when your data is small. The non-streaming implementations guarantee that data is completely processes and errors are checked and propagated correctly. If you are using both non-streaming input and output handlers for a command, it is always safe to use the default global Group. Non-streaming code is also a bit easier to debug.

If you aren’t dealing with bigger data sizes, it’s definitely a good idea to start with the non-streaming handlers.

Bytes (Uint8Array)

Bytes can be used as input or output.

In this example, we pass some bytes to gzip to compress them and then pass those bytes to gunzip to decompress.

const pr = proc.runner(proc.bytesInput(), proc.bytesOutput())();

const original = new Uint8Array([1, 2, 3, 4, 5]);

const gzipped = await pr.run({ cmd: ["gzip"] }, original);
console.dir(gzipped);
const unzipped = await pr.run({ cmd: ["gunzip"] }, gzipped);

assertEquals(unzipped, original);

Text (string)

Text can be used as input or output.

This example shows how you can wrap/hide a call to a process in a function. Since we are not dealing with AsyncIterable data, we can create and close the Group immediately.

cowsay needs to be installed:

sudo apt install cowsay

It is a well known fact that people instinctively find things said by cows to be more credible than things not said by cows. Feel free to steal this code.

const cowsay = async (text: string): Promise<string> => {
  return await proc.runner(proc.stringInput(), proc.stringOutput())()
    .run({ cmd: ["cowsay"] }, text);
};

const whatTheCowSaid = await cowsay("*proc* is pretty cool!");

console.log(whatTheCowSaid);

/*
 *  ________________________
 * < *proc* is pretty cool! >
 *  ------------------------
 *        \   ^__^
 *         \  (oo)\_______
 *            (__)\       )\/\
 *                ||----w |
 *                ||     ||
 */

Text (string[])

When it comes to cows, go BIG or go home. Also, this demonstrates using string[] for input and output.

figlet is a utility that prints letters as ASCII art. For more features and fonts, check out toilet.

figlet needs to be installed:

sudo apt install figlet

This cow is very loud.

const moo = await proc.runner(proc.emptyInput(), proc.stringArrayOutput())()
  .run({ cmd: ["figlet", "MOO!"] });

console.log(moo.join("\n"));

/*  __  __  ___   ___  _
 * |  \/  |/ _ \ / _ \| |
 * | |\/| | | | | | | | |
 * | |  | | |_| | |_| |_|
 * |_|  |_|\___/ \___/(_)
 */

const cowSaysMoo = await proc.runner(
  stringArrayInput(),
  stringArrayOutput(),
)().run({ cmd: ["cowsay", "-n"] }, moo);

console.log(cowSaysMoo.join("\n"));

/*
 *  ________________________
 * /  __  __  ___   ___  _  \
 * | |  \/  |/ _ \ / _ \| | |
 * | | |\/| | | | | | | | | |
 * | | |  | | |_| | |_| |_| |
 * | |_|  |_|\___/ \___/(_) |
 * \                        /
 *  ------------------------
 *         \   ^__^
 *          \  (oo)\_______
 *             (__)\       )\/\
 *                 ||----w |
 *                 ||     ||
 */

In all seriousness, this is a pretty nifty way to distinguish important error messages from background noise in long log output.

The above script is the equivalent of typing in figlet "MOO!" | cowsay -n in the terminal.

Streaming Handlers

Bytes (Reader) - Input Only

Bytes (AsyncIterable<Uint8Array>)

Text (AsyncIterable<string>)

Unbuffered Handlers

Unbuffered data is useful if you need to send or receive data as soon as it is available, and you are not concerned about maximizing throughput. This is used most often for line-oriented data, where you want to see each line as it is printed.

Text (AsyncIterable<string>) - Unbuffered

Unbuffered text can be used as input or output.

If you use buffered output, lines won’t be processed until a buffer (usually 4,092 bytes) is completely full. For output that is meant to be read by a person at the terminal, this can make the process look like it is hung. By using unbuffered output, each line is printed as soon as it is ready - instant feedback.

This example demonstrates unbuffered output. I am going to run deno doc and decorate both stderr and stdout streams.

Note that you can define a custom stderr handler function in the runner(...), and stderr is always unbuffered - because it is used for real-time feedback at the console.

The program is getting a line at a time, as it is ready (no buffering), from both streams - asynchronously. These lines are immediately written to console with either a red timestamp or a blue timestamp to indicate the stream of origin.

const pg = proc.group();
try {
  for await (
    const line of proc.runner(
      proc.emptyInput(),
      proc.stringAsyncIterableUnbufferedOutput(async (stderr) => {
        for await (const line of stderr) {
          console.error(
            `${red(`${new Date().getTime()}`)} -> ${stripColor(line)}`,
          );
        }
      }),
    )(pg).run({
      cmd: [
        "deno",
        "doc",
        "--reload",
        "https://deno.land/x/proc/mod.ts",
      ],
    })
  ) {
    console.log(
      `${blue(`${new Date().getTime()}`)} -> ${stripColor(line)}`,
    );
  }
} finally {
  pg.close();
}