Executing Processes¶
The run() function¶
Castor provides a run() function to execute external processes.
use Castor\Attribute\AsTask;
use function Castor\run;
#[AsTask(description: 'Run a sub-process')]
function run_(): void
{
run('examples/basic/run/my-script.sh');
run(['grep', '-rni', 'todo', 'examples/']);
}
You can pass a string or an array of string for this function. When passing a string, arguments will not be escaped - use it carefully.
Process object¶
Under the hood, Castor uses the
Symfony\Component\Process\Process
object to execute the process. The run() function will return this object. So
you can use the API of this class to interact with the underlying process:
use Castor\Attribute\AsTask;
use JoliCode\PhpOsHelper\OsHelper;
use function Castor\context;
use function Castor\io;
use function Castor\run;
#[AsTask(description: 'Run a sub-process and display information about it')]
function ls(): void
{
if (OsHelper::isWindows()) {
$process = run('dir');
} else {
$process = run('ls -alh && echo $foo', context()->withQuiet()->withEnvironment(['foo' => 'ba\'"`r']));
}
io()->writeln('Output:' . $process->getOutput());
io()->writeln('Error output: ' . $process->getErrorOutput());
io()->writeln('Exit code: ' . $process->getExitCode());
}
Note
Without the allowFailure option, Castor would throw an exception if the process execution failed. See this documentation for more information about failure handling.
Processing the output¶
By default, Castor will forward the stdout and stderr to the current terminal.
If you do not want to print the process output you can use a context with the
quiet option to true:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask(description: 'Executes something but does not output anything')]
function quiet(): void
{
$process = run('ls -alh', context()->withQuiet()); // will not print anything
// If you want to get the output, you can still do it:
// io()->writeln('Output:' . $process->getOutput());
}
The capture() function¶
Castor provides a capture() function that will run the process quietly,
trims the output, then returns it:
use Castor\Attribute\AsTask;
use function Castor\capture;
use function Castor\io;
#[AsTask(description: 'Run a sub-process and display information about it, with capture() function')]
function capture_(): void
{
$time = capture('date +%H:%M:%S');
io()->writeln("Current time: {$time}");
}
The exit_code() function¶
Castor provides a exit_code() function that will run the command, allowing
the process to fail and return its exit code. This is particularly useful when
running tasks on CI as this allows the CI to know if the task failed or not:
use Castor\Attribute\AsTask;
use function Castor\exit_code;
#[AsTask(description: 'Run a sub-process and return its exit code, with exit_code() function')]
function exit_code_(): int
{
return exit_code('test -f unknown-file');
}
Interactive Process¶
If you want to run an interactive process, you can transform any context into an interactive one:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function interactive(): void
{
run('vim', context()->toInteractive());
}
PTY & TTY¶
By default, Castor will use a pseudo terminal (PTY) to run the underlying process,
which allows to have nice output in most cases.
For some commands you may want to disable the PTY and use a TTY instead. You can
do that by setting the tty option to true:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask(description: 'Run a command with TTY enabled')]
function tty(): void
{
run('echo bar', context()->withTty(true));
}
Warning
When using a TTY, the output of the command is empty in the process object
(when using getOutput() or getErrorOutput()).
You can also disable the PTY by setting the pty option to false. If pty
and tty are both set to false, the standard input will not be forwarded to
the process:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask(description: 'Run a command with PTY disabled')]
function pty(): void
{
run('echo "bar"', context()->withPty(false));
}