taskSshExec('remote.example.com', 'user') * ->remoteDir('/var/www/html') * ->exec('ls -la') * ->exec('chmod g+x logs') * ->run(); * * ``` * * You can even exec other tasks (which implement CommandInterface): * * ```php * $gitTask = $this->taskGitStack() * ->checkout('master') * ->pull(); * * $this->taskSshExec('remote.example.com') * ->remoteDir('/var/www/html/site') * ->exec($gitTask) * ->run(); * ``` * * You can configure the remote directory for all future calls: * * ```php * \Robo\Task\Remote\Ssh::configure('remoteDir', '/some-dir'); * ``` */ class Ssh extends BaseTask implements CommandInterface, SimulatedInterface { use \Robo\Common\CommandReceiver; use \Robo\Common\ExecOneCommand; /** * @var null|string */ protected $hostname; /** * @var null|string */ protected $user; /** * @var bool */ protected $stopOnFail = true; /** * @var array */ protected $exec = []; /** * Changes to the given directory before running commands. * * @var string */ protected $remoteDir; /** * @param null|string $hostname * @param null|string $user */ public function __construct($hostname = null, $user = null) { $this->hostname = $hostname; $this->user = $user; } /** * @param string $hostname * * @return $this */ public function hostname($hostname) { $this->hostname = $hostname; return $this; } /** * @param string $user * * @return $this */ public function user($user) { $this->user = $user; return $this; } /** * Whether or not to chain commands together with && and stop the chain if one command fails. * * @param bool $stopOnFail * * @return $this */ public function stopOnFail($stopOnFail = true) { $this->stopOnFail = $stopOnFail; return $this; } /** * Changes to the given directory before running commands. * * @param string $remoteDir * * @return $this */ public function remoteDir($remoteDir) { $this->remoteDir = $remoteDir; return $this; } /** * @param string $filename * * @return $this */ public function identityFile($filename) { $this->option('-i', $filename); return $this; } /** * @param int $port * * @return $this */ public function port($port) { $this->option('-p', $port); return $this; } /** * @return $this */ public function forcePseudoTty() { $this->option('-t'); return $this; } /** * @return $this */ public function quiet() { $this->option('-q'); return $this; } /** * @return $this */ public function verbose() { $this->option('-v'); return $this; } /** * @param string|string[]|CommandInterface $command * * @return $this */ public function exec($command) { if (is_array($command)) { $command = implode(' ', array_filter($command)); } $this->exec[] = $command; return $this; } /** * Returns command that can be executed. * This method is used to pass generated command from one task to another. * * @return string */ public function getCommand() { $commands = []; foreach ($this->exec as $command) { $commands[] = $this->receiveCommand($command); } $remoteDir = $this->remoteDir ? $this->remoteDir : $this->getConfigValue('remoteDir'); if (!empty($remoteDir)) { array_unshift($commands, sprintf('cd "%s"', $remoteDir)); } $command = implode($this->stopOnFail ? ' && ' : ' ; ', $commands); return $this->sshCommand($command); } /** * {@inheritdoc} */ public function run() { $this->validateParameters(); $command = $this->getCommand(); return $this->executeCommand($command); } /** * {@inheritdoc} */ public function simulate($context) { $command = $this->getCommand(); $this->printTaskInfo("Running {command}", ['command' => $command] + $context); } protected function validateParameters() { if (empty($this->hostname)) { throw new TaskException($this, 'Please set a hostname'); } if (empty($this->exec)) { throw new TaskException($this, 'Please add at least one command'); } } /** * Returns an ssh command string running $command on the remote. * * @param string|CommandInterface $command * * @return string */ protected function sshCommand($command) { $command = $this->receiveCommand($command); $sshOptions = $this->arguments; $hostSpec = $this->hostname; if ($this->user) { $hostSpec = $this->user . '@' . $hostSpec; } return "ssh{$sshOptions} {$hostSpec} '{$command}'"; } }