diff --git a/src/Rocketeer/Abstracts/AbstractBinary.php b/src/Rocketeer/Abstracts/AbstractBinary.php index 36f7e8235..849e1bb36 100644 --- a/src/Rocketeer/Abstracts/AbstractBinary.php +++ b/src/Rocketeer/Abstracts/AbstractBinary.php @@ -177,7 +177,7 @@ protected function buildOptions($flags) // Flip array if necessary $firstKey = Arr::get(array_keys($flags), 0); - if (!is_null($firstKey) && is_int($firstKey)) { + if ($firstKey !== null && is_int($firstKey)) { $flags = array_combine( array_values($flags), array_fill(0, count($flags), null) @@ -186,9 +186,18 @@ protected function buildOptions($flags) // Build flags foreach ($flags as $flag => $value) { - $options[] = $value ? $flag.'="'.$value.'"' : $flag; + if (is_array($value)) { + foreach ($value as $v) { + $options[] = $flag.'="'.$v.'"'; + } + } else { + if (is_numeric($flag)) { + $flag = $value; + $value = null; + } + $options[] = $value ? $flag.'="'.$value.'"' : $flag; + } } - return implode(' ', $options); } @@ -203,7 +212,6 @@ protected function buildArguments($arguments) $arguments = (array) $arguments; $arguments = implode(' ', $arguments); } - return $arguments; } diff --git a/src/Rocketeer/Strategies/Deploy/SyncStrategy.php b/src/Rocketeer/Strategies/Deploy/SyncStrategy.php index 8fb067164..ff02da286 100644 --- a/src/Rocketeer/Strategies/Deploy/SyncStrategy.php +++ b/src/Rocketeer/Strategies/Deploy/SyncStrategy.php @@ -9,6 +9,7 @@ */ namespace Rocketeer\Strategies\Deploy; +use Illuminate\Support\Arr; use Rocketeer\Abstracts\Strategies\AbstractStrategy; use Rocketeer\Bash; use Rocketeer\Interfaces\Strategies\DeployStrategyInterface; @@ -20,6 +21,11 @@ class SyncStrategy extends AbstractStrategy implements DeployStrategyInterface */ protected $description = 'Uses rsync to create or update a release from the local files'; + /** + * @type integer + */ + protected $port; + /** * Deploy a new clean copy of the application. * @@ -63,25 +69,75 @@ public function update($reset = true) protected function rsyncTo($destination) { // Build host handle - $credentials = $this->connections->getServerCredentials(); - $handle = array_get($credentials, 'host'); + $arguments = []; + $handle = $this->getSyncHandle(); + + // Create options + $options = ['--verbose' => null, '--recursive' => null, '--rsh' => 'ssh', '--compress' => null]; + + // Create SSH command + $options['--rsh'] = $this->getTransport(); + + // Build arguments + $arguments[] = './'; + $arguments[] = $handle.':'.$destination; + + // Set excluded files and folders + $options['--exclude'] = ['.git', 'vendor']; + + // Create binary and command + $rsync = $this->binary('rsync'); + $command = $rsync->getCommand(null, $arguments, $options); + + return $this->bash->onLocal(function (Bash $bash) use ($command) { + return $bash->run($command); + }); + } + + /** + * Get the handle to connect with. + * + * @return string + */ + protected function getSyncHandle() + { + $credentials = $this->connections->getServerCredentials(); + $handle = array_get($credentials, 'host'); + $explodedHandle = explode(':', $handle); + + // Extract port + if (count($explodedHandle) === 2) { + $this->port = $explodedHandle[1]; + $handle = $explodedHandle[0]; + } + + // Add username if ($user = array_get($credentials, 'username')) { $handle = $user.'@'.$handle; } - // Create options - $options = '--verbose --recursive --rsh="ssh"'; - $excludes = ['.git', 'vendor']; - foreach ($excludes as $exclude) { - $options .= ' --exclude="'.$exclude.'"'; + return $handle; + } + + /** + * @return string + */ + protected function getTransport() + { + $ssh = 'ssh'; + + // Get port + if ($port = $this->getOption('port', true) ?: $this->port) { + $ssh .= ' -p '.$port; } - // Create binary and command - $rsync = $this->binary('rsync'); - $rsync = $rsync->getCommand(null, ['./', $handle.':'.$destination], $options); + // Get key + $key = $this->connections->getServerCredentials(); + $key = Arr::get($key, 'key'); + if ($key) { + $ssh .= ' -i '.$key; + } - return $this->bash->onLocal(function (Bash $bash) use ($rsync) { - return $bash->run($rsync); - }); + return $ssh; } } diff --git a/tests/Strategies/Deploy/SyncStrategyTest.php b/tests/Strategies/Deploy/SyncStrategyTest.php index 5cfeac7b4..f05d4489a 100644 --- a/tests/Strategies/Deploy/SyncStrategyTest.php +++ b/tests/Strategies/Deploy/SyncStrategyTest.php @@ -36,7 +36,7 @@ public function testCanDeployRepository() $matcher = [ 'mkdir {server}/releases/{release}', - 'rsync ./ foo@bar.com:{server}/releases/{release} --verbose --recursive --rsh="ssh" --exclude=".git" --exclude="vendor"', + 'rsync ./ foo@bar.com:{server}/releases/{release} --verbose --recursive --rsh="ssh" --compress --exclude=".git" --exclude="vendor"', ]; $this->assertHistory($matcher); @@ -48,7 +48,30 @@ public function testCanUpdateRepository() $task->getStrategy('Deploy', 'Sync')->update(); $matcher = [ - 'rsync ./ foo@bar.com:{server}/releases/{release} --verbose --recursive --rsh="ssh" --exclude=".git" --exclude="vendor"', + 'rsync ./ foo@bar.com:{server}/releases/{release} --verbose --recursive --rsh="ssh" --compress --exclude=".git" --exclude="vendor"', + ]; + + $this->assertHistory($matcher); + } + + public function testCanSpecifyKey() + { + $this->swapConfig(array( + 'rocketeer::connections' => array( + 'production' => array( + 'username' => 'foo', + 'host' => 'bar.com:80', + 'key' => '/foo/bar', + ), + ), + )); + + $task = $this->pretendTask('Deploy'); + $task->getStrategy('Deploy', 'Sync')->deploy(); + + $matcher = [ + 'mkdir {server}/releases/{release}', + 'rsync ./ foo@bar.com:{server}/releases/{release} --verbose --recursive --rsh="ssh -p 80 -i /foo/bar" --compress --exclude=".git" --exclude="vendor"', ]; $this->assertHistory($matcher);