diff --git a/src/app/launcher.php b/src/app/launcher.php index dd472f9..fed08a5 100644 --- a/src/app/launcher.php +++ b/src/app/launcher.php @@ -1,7 +1,7 @@ addRedir("null"); $cmd->fork_exec($exitcode); } finally { diff --git a/src/os/proc/AbstractCmd.php b/src/os/proc/AbstractCmd.php new file mode 100644 index 0000000..0c8ce12 --- /dev/null +++ b/src/os/proc/AbstractCmd.php @@ -0,0 +1,196 @@ +needsStdin = true; + $this->needsTty = true; + $this->vars = null; + $this->cmds = []; + } + + function then($cmd, ?string $input=null, ?string $output=null): Cmd { + if ($this instanceof Cmd) { + $this->add($cmd, $input, $output); + return $this; + } else { + return (new Cmd($this))->add($cmd, $input, $output); + } + } + + function or($cmd, ?string $input=null, ?string $output=null): CmdOr { + if ($this instanceof CmdOr) { + $this->add($cmd, $input, $output); + return $this; + } else { + return (new CmdOr($this))->add($cmd, $input, $output); + } + } + + function and($cmd, ?string $input=null, ?string $output=null): CmdAnd { + if ($this instanceof CmdAnd) { + $this->add($cmd, $input, $output); + return $this; + } else { + return (new CmdAnd($this))->add($cmd, $input, $output); + } + } + + function pipe($cmd): CmdPipe { + if ($this instanceof CmdPipe) { + $this->add($cmd); + return $this; + } else { + return new CmdPipe([$this, $cmd]); + } + } + + function isNeedsStdin(): bool { + return $this->needsStdin; + } + + function setNeedsStdin(bool $needsStdin): void { + $this->needsStdin = $needsStdin; + } + + function isNeedsTty(): bool { + return $this->needsTty; + } + + function setNeedsTty(bool $needsTty): void { + $this->needsTty = $needsTty; + } + + function addLiteralVars($vars, ?string $sep=null): void { + if (base::z($vars)) return; + if (is_array($vars)) { + if ($sep === null) $sep = "\n"; + $vars = implode($sep, $vars); + } + A::append($this->vars, strval($vars)); + } + + function addVars(?array $vars): void { + if ($vars === null) return; + foreach ($vars as $name => $value) { + $var = []; + if (!is_array($value)) $var[] = "export "; + A::merge($var, [$name, "=", shell::quote($value)]); + A::append($this->vars, implode("", $var)); + } + } + + function getVars(?string $sep=null): ?string { + if ($this->vars === null) return null; + if ($sep === null) $sep = "\n"; + return implode($sep, $this->vars); + } + + function addPrefix($prefix): void { + $count = count($this->cmds); + if ($count == 0) return; + $cmd =& $this->cmds[$count - 1]; + if ($cmd instanceof ICmd) { + $cmd->addPrefix($prefix); + } elseif (is_array($prefix)) { + $prefix = shell::join($prefix); + $cmd = "$prefix $cmd"; + } else { + $cmd = "$prefix $cmd"; + } + } + + function addRedir(?string $redir, $output=null, bool $append=false, $input=null): void { + $count = count($this->cmds); + if ($count == 0) return; + + if ($output !== null) $output = escapeshellarg($output); + if ($input !== null) $input = escapeshellarg($input); + if ($redir === "default") $redir = null; + $gt = $append? ">>": ">"; + if ($redir === null) { + $redirs = []; + if ($input !== null) $redirs[] = "<$input"; + if ($output !== null) $redirs[] = "$gt$output"; + if ($redirs) $redir = implode(" ", $redir); + } else { + switch ($redir) { + case "outonly": + case "noerr": + if ($output !== null) $redir = "$gt$output 2>/dev/null"; + else $redir = "2>/dev/null"; + break; + case "erronly": + case "noout": + if ($output !== null) $redir = "2$gt$output >/dev/null"; + else $redir = "2>&1 >/dev/null"; + break; + case "both": + case "err2out": + if ($output !== null) $redir = "$gt$output 2>&1"; + else $redir = "2>&1"; + break; + case "none": + case "null": + $redir = ">/dev/null 2>&1"; + break; + } + } + if ($redir !== null) { + $cmd =& $this->cmds[$count - 1]; + if ($cmd instanceof ICmd) { + $cmd->addRedir($redir); + } else { + $cmd = "$cmd $redir"; + } + } + } + + abstract function getCmd(?string $sep=null): string; + + function passthru(int &$retcode=null): bool { + passthru($this->getCmd(), $retcode); + return $retcode == 0; + } + + function system(string &$output=null, int &$retcode=null): bool { + $last_line = system($this->getCmd(), $retcode); + if ($last_line !== false) $output = $last_line; + return $retcode == 0; + } + + function exec(array &$output=null, int &$retcode=null): bool { + exec($this->getCmd(), $output, $retcode); + return $retcode == 0; + } + + /** + * retourner true s'il faut utiliser `exec` avec {@link fork_exec()} + * + * ne pas utiliser `exec` si des variables sont définies ou si c'est une + * composition de plusieurs commandes + */ + protected function useExec(): bool { + return $this->vars === null && count($this->cmds) == 1; + } + + function fork_exec(int &$retcode=null): bool { + $cmd = $this->getCmd(); + if ($this->useExec()) $cmd = "exec $cmd"; + sh::_fork_exec($cmd, $retcode); + return $retcode == 0; + } +} diff --git a/src/os/proc/AbstractCmdList.php b/src/os/proc/AbstractCmdList.php new file mode 100644 index 0000000..7d7a7b6 --- /dev/null +++ b/src/os/proc/AbstractCmdList.php @@ -0,0 +1,53 @@ +sep = $sep; + $this->add($cmd, $input, $output); + } + + function addLiteral($cmd): self { + A::append_nn($this->cmds, $cmd); + return $this; + } + + function add($cmd, ?string $input=null, ?string $output=null): self { + if ($cmd !== null) { + if (!($cmd instanceof ICmd)) { + shell::fix_cmd($cmd, null, $input, $output); + } + $this->cmds[] = $cmd; + } + return $this; + } + + function getCmd(?string $sep=null): string { + if ($sep === null) $sep = "\n"; + + $actualCmd = []; + A::append_nn($actualCmd, $this->getVars($sep)); + + $parts = []; + foreach ($this->cmds as $cmd) { + if ($cmd instanceof ICmd) { + $cmd = "(".$cmd->getCmd($sep).")"; + } + $parts[] = $cmd; + } + $psep = $this->sep; + if ($psep === null) $psep = $sep; + A::append($actualCmd, implode($psep, $parts)); + + return implode($sep, $actualCmd); + } +} diff --git a/src/os/proc/Cmd.php b/src/os/proc/Cmd.php new file mode 100644 index 0000000..9e33bf4 --- /dev/null +++ b/src/os/proc/Cmd.php @@ -0,0 +1,19 @@ +add($command); + } + } + $this->input = $input; + $this->output = $output; + } + + function addLiteral($cmd): self { + A::append_nn($this->cmds, $cmd); + return $this; + } + + function add($cmd): self { + if ($cmd !== null) { + if (!($cmd instanceof ICmd)) { + shell::fix_cmd($cmd); + } + $this->cmds[] = $cmd; + } + return $this; + } + + function setInput(?string $input=null): self { + $this->input = $input; + return $this; + } + + function setOutput(?string $output=null): self { + $this->output = $output; + return $this; + } + + function getCmd(?string $sep=null): string { + if ($sep === null) $sep = "\n"; + + $actualCmd = []; + A::append_nn($actualCmd, $this->getVars($sep)); + + $parts = []; + foreach ($this->cmds as $cmd) { + if ($cmd instanceof ICmd) { + $cmd = "(".$cmd->getCmd($sep).")"; + } + $parts[] = $cmd; + } + $cmd = implode(" | ", $parts); + + $input = $this->input; + $output = $this->output; + if ($input !== null || $output !== null) { + $parts = []; + if ($input !== null) $parts[] = "<".escapeshellarg($input); + $parts[] = $cmd; + if ($output !== null) $parts[] = ">".escapeshellarg($output); + $cmd = implode(" ", $parts); + } + A::append($actualCmd, $cmd); + + return implode($sep, $actualCmd); + } +} diff --git a/src/os/proc/ICmd.php b/src/os/proc/ICmd.php new file mode 100644 index 0000000..4054a9b --- /dev/null +++ b/src/os/proc/ICmd.php @@ -0,0 +1,82 @@ +