public function runSilently($cmd) { // enforce our inputs Contract::RequiresValue($cmd, is_string($cmd)); // what are we doing? $log = usingLog()->startAction("run command: {$cmd}"); // the output that we will return to the caller $output = ''; // how we will talk with the command $pipesSpec = [['file', 'php://stdin', 'r'], ['pipe', 'w'], ['pipe', 'w']]; $pipes = []; // start the process $process = proc_open($cmd, $pipesSpec, $pipes); // was there a problem? // // NOTE: this only occurs when something like a fork() failure // happens, which makes it very difficult to test for in a // unit test // @codeCoverageIgnoreStart if (!$process) { $return = new CommandResult(255, ''); return $return; } // @codeCoverageIgnoreEnd // we do not want to block whilst reading from the child process's // stdout and stderr stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); // at this point, our command may be running ... // OR our command may have failed with an error // // best thing to do is to keep reading from our pipes until // the pipes no longer exist while (!feof($pipes[1]) || !feof($pipes[2])) { // block until there is something to read, or until the // timeout has happened // // this makes sure that we do not burn CPU for the sake of it $readable = [$pipes[1], $pipes[2]]; $writeable = $except = []; stream_select($readable, $writeable, $except, 1); // check all the streams for output if ($line = fgets($pipes[1])) { $log->captureOutput(rtrim($line)); $output = $output . $line; } if ($line = fgets($pipes[2])) { $log->captureOutput(rtrim($line)); $output = $output . $line; } } // at this point, our pipes have been closed // we can assume that the child process has finished $retval = proc_close($process); // all done $log->endAction("return code is '{$retval}'"); $result = new CommandResult($retval, $output); return $result; }
public function uploadFile($sourceFilename, $destFilename) { // vet our input Contract::RequiresValue($sourceFilename, is_string($sourceFilename)); Contract::RequiresValue($sourceFilename, !empty($sourceFilename)); Contract::RequiresValue($sourceFilename, is_file($sourceFilename)); Contract::RequiresValue($destFilename, is_string($destFilename)); Contract::RequiresValue($destFilename, !empty($destFilename)); // make the params printable / executable // $printableParams = $this->convertParamsForUse($params); // what are we doing? $log = usingLog()->startAction("upload file '{$sourceFilename}' to host as '{$destFilename}'"); // do we actually have everything we need to run the command? if (!$this->hasSshUsername()) { throw new E4xx_NeedSshUsername(); } if (!$this->hasIpAddress()) { throw new E4xx_NeedIpAddress(); } // build the full command // // the options that we pass (by default) to SCP: // // -o StrictHostKeyChecking=no // do not verify the SSH host key (avoids an interactive prompt) // -i <private_key> // use specified private key to access the remote/guest OS // <username>@<hostname> // who we are logging in as (should never be root) // <additional SSH options> // any other flags, such as -n to force non-interactive session $fullCommand = 'scp ' . ' ' . $this->getSshKeyForUse() . ' ' . $this->getScpOptionsForUse() . ' "' . $sourceFilename . '" ' . ' "' . $this->getSshUsername() . '@' . $this->getIpAddress() . ':' . $destFilename . '"'; // run the command $commandRunner = $this->st->getNewCommandRunner(); $result = $commandRunner->runSilently($fullCommand); // all done $log->endAction("return code was '{$result->returnCode}'"); return $result; }
/** * an alternative to using PHP's built-in var_dump() * * @param string $name * a human-readable name to describe $var * * @param mixed $var * the variable to dump * * @return void */ public function logVardump($name, $var) { // enforce our inputs Contract::RequiresValue($name, is_string($name)); // $var can be anything, so there is no contract to enforce // pass this on to our plugins foreach ($this->plugins as $plugin) { $plugin->logVardump($name, $var); } }
public function uploadFile($sourceFilename, $destFilename) { // vet our input Contract::RequiresValue($sourceFilename, is_string($sourceFilename)); Contract::RequiresValue($sourceFilename, !empty($sourceFilename)); Contract::RequiresValue($sourceFilename, is_file($sourceFilename)); Contract::RequiresValue($destFilename, is_string($destFilename)); Contract::RequiresValue($destFilename, !empty($destFilename)); // make the params printable / executable // $printableParams = $this->convertParamsForUse($params); // what are we doing? $log = usingLog()->startAction("copy file '{$sourceFilename}' to localhost as '{$destFilename}'"); // build the full command // $fullCommand = 'cp ' . "'" . $sourceFilename . "' " . "'" . $destFilename . "'"; // run the command $commandRunner = $this->st->getNewCommandRunner(); $result = $commandRunner->runSilently($fullCommand); // all done $log->endAction("return code was '{$result->returnCode}'"); return $result; }