Process

This struct is used to prepare configuration for process and run it.

The following methods of running a process are supported:

- execute: run process and catch its output and exit code. - spawn: spawn the process in background, and optionally pipe its output. - pipe: spawn the process and attach configurable pipes to catch output.

The configuration of a process can be done like so:

1. Create the Process instance specifying the program to run. 2. Apply your desired configuration (args, env, workDir) via calls to one of the corresponding methods. 3. Run one of execute, spawn or pipe methods, that will actually start the process.

Configuration methods are usually prefixed with set word, but they may also have semantic aliases. For example, the method setArgs also has an alias withArgs, and the method setWorkDir has an alias inWorkDir. Additionally, configuration methods always return the reference to current instance of the Process being configured.

Constructors

this
this(string program)
this(Path program)

Create new Process instance to run specified program.

Members

Aliases

inWorkDir
alias inWorkDir = setWorkDir

Set work directory for the process to be started

withArgs
alias withArgs = setArgs

Set arguments for the process

withConfig
alias withConfig = setConfig

Set process configuration

withEnv
alias withEnv = setEnv

Set environment variable (specified by key) to provided value

withFlag
alias withFlag = setFlag

Set configuration flag for process to be started

withGID
alias withGID = setGID

Set GID to run process with

withUID
alias withUID = setUID

Set UID to run process with

withUser
alias withUser = setUser

Functions

addArgs
auto ref addArgs(string[] args)

Add arguments to the process.

execute
auto execute(size_t max_output)

Execute the configured process and capture output.

execv
void execv()

Replace current process by executing program as configured by Process instance.

pipe
auto pipe(Redirect redirect)

Pipe process

setArgs
auto ref setArgs(string[] args)

Set arguments for the process

setConfig
auto ref setConfig(std.process.Config config)

Set process configuration

setEnv
auto ref setEnv(string[string] env)

Set environemnt for the process to be started

setEnv
auto ref setEnv(string key, string value)

Set environment variable (specified by key) to provided value

setFlag
auto ref setFlag(std.process.Config.Flags flag)
auto ref setFlag(std.process.Config flags)

Set configuration flag for process to be started

setGID
auto ref setGID(gid_t gid)

Set GID to run process with

setUID
auto ref setUID(uid_t uid)

Set UID to run process with

setUser
auto ref setUser(string username)

Run process as specified user

setWorkDir
auto ref setWorkDir(string workdir)
auto ref setWorkDir(Path workdir)

Set work directory for the process to be started

spawn
auto spawn(File stdin, File stdout, File stderr)

Spawn process

toString
string toString()

Return string representation of process to be started

Examples

// It is possible to run process in following way:
auto result = Process(y-program
        .withArgs("--verbose", "--help")
        .withEnv("MY_ENV_VAR", "MY_VALUE")
        .inWorkDir("my/working/directory")
        .execute()
        .ensureStatus!MyException("My error message on failure");
writeln(result.output);
// Also, in Posix system it is possible to run command as different user:
auto result = Process(y-program
        .withUser("bob")
        .execute()
        .ensureStatus!MyException("My error message on failure");
writeln(result.output);

Test simple execution of the script

import std.string;
import std.ascii : newline;

import unit_threaded.assertions;

auto temp_root = createTempPath();
scope(exit) temp_root.remove();

version(Posix) {
    import std.conv: octal;
    auto script_path = temp_root.join("test-script.sh");
    script_path.writeFile(
        "#!" ~ nativeShell ~ newline ~
        `echo "Test out: $1 $2"` ~ newline);
    // Add permission to run this script
    script_path.setAttributes(octal!755);
} else version(Windows) {
    auto script_path = temp_root.join("test-script.cmd");
    script_path.writeFile(
        "@echo off" ~ newline ~
        "echo Test out: %1 %2" ~ newline);
}

// Test the case when process executes fine
auto result = Process(script_path)
    .withArgs("Hello", "World", "test")
    .execute
    .ensureOk;
result.status.should == 0;
result.output.chomp.should == "Test out: Hello World";
result.isOk.shouldBeTrue;
result.isNotOk.shouldBeFalse;
// When we expect different successful exit-code
result.isOk(42).shouldBeFalse;
result.isNotOk(42).shouldBeTrue;
result.ensureOk(42).shouldThrow!ProcessException;

Test simple execution of the script that handles environment variables

import std.string;
import std.ascii : newline;

import unit_threaded.assertions;

auto temp_root = createTempPath();
scope(exit) temp_root.remove();

version(Posix) {
    import std.conv: octal;
    auto script_path = temp_root.join("test-script.sh");
    script_path.writeFile(
        "#!" ~ nativeShell ~ newline ~
        `echo "Test out: $1 $2, $MY_PARAM_1 $MY_PARAM_2"` ~ newline);
    // Add permission to run this script
    script_path.setAttributes(octal!755);
} else version(Windows) {
    auto script_path = temp_root.join("test-script.cmd");
    script_path.writeFile(
        "@echo off" ~ newline ~
        "echo Test out: %1 %2, %MY_PARAM_1% %MY_PARAM_2%" ~ newline);
}

// Test the case when process executes fine
auto result = Process(script_path)
    .withArgs("Hello")
    .addArgs("World")
    .withEnv("MY_PARAM_1", "the")
    .withEnv("MY_PARAM_2", "Void")
    .execute
    .ensureOk;
result.status.should == 0;
result.output.chomp.should == "Test out: Hello World, the Void";
result.isOk.shouldBeTrue;
result.isNotOk.shouldBeFalse;
// When we expect different successful exit-code
result.isOk(42).shouldBeFalse;
result.isNotOk(42).shouldBeTrue;
result.ensureOk(42).shouldThrow!ProcessException;

Meta