feat: first impl
This commit is contained in:
164
src/Command.php
Normal file
164
src/Command.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nih\CommandBuilder;
|
||||
|
||||
use RuntimeException;
|
||||
use Stringable;
|
||||
use ValueError;
|
||||
|
||||
final class Command
|
||||
{
|
||||
public readonly string $command;
|
||||
|
||||
private array $args = [];
|
||||
private ?array $envs = null;
|
||||
private ?string $cwd = null;
|
||||
|
||||
private ?Stdio $stdin = null;
|
||||
private ?Stdio $stdout = null;
|
||||
private ?Stdio $stderr = null;
|
||||
|
||||
public function __construct(string $command)
|
||||
{
|
||||
if (strlen($command) === 0) {
|
||||
throw new ValueError('Empty command');
|
||||
}
|
||||
|
||||
$this->command = $command;
|
||||
$this->args[] = $this->command;
|
||||
}
|
||||
|
||||
public function arg(string|Stringable $arg): static
|
||||
{
|
||||
$this->args[] = (string) $arg;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string|Stringable> $args
|
||||
*/
|
||||
public function args(array $args): static
|
||||
{
|
||||
foreach ($args as $arg) {
|
||||
$this->args[] = (string) $arg;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cwd(string|Stringable $cwd): static
|
||||
{
|
||||
$this->cwd = (string) $cwd;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function env(string $var, string|Stringable $value): static
|
||||
{
|
||||
$this->envs[$var] = escapeshellarg((string) $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|Stringable> $envs
|
||||
*/
|
||||
public function envs(array $envs): static
|
||||
{
|
||||
foreach ($envs as $var => $value) {
|
||||
$this->envs[$var] = escapeshellarg((string) $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function stdin(Stdio $in): static
|
||||
{
|
||||
$this->stdin = $in;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function stdout(Stdio $out): static
|
||||
{
|
||||
$this->stdout = $out;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function stderr(Stdio $err): static
|
||||
{
|
||||
$this->stderr = $err;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shell Run the command with or without a shell
|
||||
*/
|
||||
public function spawn(bool $shell = true): Child
|
||||
{
|
||||
$fd[0] = $this->stdin instanceof Stdio
|
||||
? $this->stdin->getDescriptorSpec()
|
||||
: ['pipe', 'r'];
|
||||
|
||||
$fd[1] = $this->stdout instanceof Stdio
|
||||
? $this->stdout->getDescriptorSpec()
|
||||
: ['pipe', 'w'];
|
||||
|
||||
$fd[2] = $this->stderr instanceof Stdio
|
||||
? $this->stderr->getDescriptorSpec()
|
||||
: ['pipe', 'w'];
|
||||
|
||||
if ($shell) {
|
||||
$command = implode(' ', array_map(escapeshellarg(...), $this->args));
|
||||
} else if (is_executable($this->command)) {
|
||||
$command = $this->args;
|
||||
} else {
|
||||
throw new CommandException(sprintf(
|
||||
'Command "%s" is not executable',
|
||||
$this->command,
|
||||
));
|
||||
}
|
||||
|
||||
$proc = proc_open($command, $fd, $pipes, $this->cwd, $this->envs);
|
||||
if ($proc === false) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
$stdin = array_key_exists(0, $pipes)
|
||||
? new ChildStdin($pipes[0])
|
||||
: null;
|
||||
|
||||
$stdout = array_key_exists(1, $pipes)
|
||||
? new ChildStdout($pipes[1])
|
||||
: null;
|
||||
|
||||
$stderr = array_key_exists(2, $pipes)
|
||||
? new ChildStderr($pipes[2])
|
||||
: null;
|
||||
|
||||
return new Child($stdin, $stdout, $stderr, $proc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shell Run the command with or without a shell
|
||||
*/
|
||||
public function output(bool $shell = true): Output
|
||||
{
|
||||
return $this->spawn($shell)->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shell Run the command with or without a shell
|
||||
*/
|
||||
public function status(bool $shell = true): int
|
||||
{
|
||||
return $this->spawn($shell)->status();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shell Run the command with or without a shell
|
||||
*/
|
||||
public function wait(bool $shell = true): void
|
||||
{
|
||||
$this->spawn($shell)->wait();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user