196 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\b\proc;
 | |
| 
 | |
| use nur\A;
 | |
| use nur\base;
 | |
| use nur\shell;
 | |
| 
 | |
| abstract class AbstractCmd implements ICmd {
 | |
|   /** @var bool */
 | |
|   private $needsStdin;
 | |
|   /** @var bool */
 | |
|   private $needsTty;
 | |
|   /** @var array */
 | |
|   protected $vars;
 | |
|   /** @var array */
 | |
|   protected $cmds;
 | |
| 
 | |
|   function __construct() {
 | |
|     $this->needsStdin = true;
 | |
|     $this->needsTty = true;
 | |
|     $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";
 | |
|     shell::_fork_exec($cmd, $retcode);
 | |
|     return $retcode == 0;
 | |
|   }
 | |
| }
 |