Launching Processes¶
Usage¶
use Innmind\Server\Control\Server\{
Command,
Process\Success,
Process\TimedOut,
Process\Failed,
Process\Signaled,
};
$process = $os
->control()
->processes()
->execute(
Command::foreground('apt-get')
->withArgument('install')
->withArgument('cowsay')
->withShortOption('y'),
);
$process
->wait()
->match(
static fn(Success $success) => doStuff(),
static fn(TimedOut|Failed|Signaled $error) => throw new RuntimeException();
);
This example waits for the installation of cowsay
before continuing via doStuff()
or it will fail with an exception.
Note
By default the process is executed with no environment variables. If you try to execute a command that is reachable only because you modified your $PATH
environment variable, you'll need to specify it via Command::foreground('command')->withEnvironment('$PATH', 'your path value')
.
This may seem restrictive at first but it's done to force your program to be explicit. And it will help other developers to understand what's needed for the command to be run.
Info
If you don't want to wait for a process to finish you can replace Command::foreground()
by Command::background()
and remove the code $process->wait()
.
If you dont't really care about the process failing or not and simply want to forward its output you can use:
use Innmind\Server\Control\Server\Process\Output\Type;
use Innmind\Immutable\Str;
$process
->output()
->foreach(static function(Str $chunk, Type $type): void {
// $type is either Type::output or Type::error
echo $chunk->toString();
});
This code will print the output of the underlying process in real time. The foreach
call will return when the process is finished.
Tip
If you still need to check the result of the process you can still call $process->wait()
, it will immediately return the result.
You can also send content to the STDIN
of the process via:
use Innmind\Filesystem\File\Content;
echo $os
->control()
->processes()
->execute(
Command::foreground('echo')
->withInput(Content::ofString('some input')),
)
->output()
->toString();
The input can be any valid Content
object, even lazy ones.
Streaming¶
By default the process output is kept in memory so you can use it multiple times. However for some commands the output can be quite large and it won't fit in memory.
For example you want to run an archive command that you want to stream to the output.
$os
->control()
->processes()
->execute(
Command::foreground('zip')
->withShortOption('q')
->withShortOption('r')
->withArgument('-')
->withArgument('some folder/')
->streamOutput(),
)
->output()
->foreach(static function(Str $chunk) {
echo $chunk->toString();
});
You won't be able to reuse the output twice, if you try it will throw a \LogicException
.
Info
However if you've walked over the whole output you can still call $process->wait()
to check if there was an error or not.
SSH¶
You can execute commands on a remote machine through SSH the same way you'd do it on the local machine via:
use Innmind\Url\Url;
$process = $os
->remote()
->ssh(Url::of('ssh://user@machine-name-or-ip:22/'))
->processes()
->execute(
Command::foreground('apt-get')
->withArgument('install')
->withArgument('cowsay'),
);
You can't specify the password to connect to the machine via the url. It's done to force you to use SSH keys.
Info
For now it's not possible to use an input when running commands through SSH.