From eb95635eba6c59467277fc4f4a2da364964ab8da Mon Sep 17 00:00:00 2001 From: Elfet Date: Fri, 4 Jul 2014 18:13:16 +0400 Subject: [PATCH] Refactor Deployer :elephant: --- bin/dep | 2 +- src/Console/Command.php | 42 ++++++++++++++++ src/Server/Configuration.php | 24 ++++++++++ src/Server/DryRun.php | 64 +++++++++++++++++++++++++ src/Server/PhpSecLib.php | 7 +++ src/Server/ServerInterface.php | 5 ++ src/Server/Ssh2.php | 8 ++++ src/Task.php | 6 ++- src/Task/AbstractTask.php | 38 +++++++++++++++ src/Task/TaskFactory.php | 2 +- src/TaskInterface.php | 3 ++ src/Utils/Path.php | 81 +++++++++++++++++++++++++++++++ src/functions.php | 87 ++++++++++++++++++++++++++++++---- 13 files changed, 356 insertions(+), 13 deletions(-) create mode 100644 src/Server/DryRun.php create mode 100644 src/Task/AbstractTask.php create mode 100644 src/Utils/Path.php diff --git a/bin/dep b/bin/dep index 0e5d6437..d7e56505 100755 --- a/bin/dep +++ b/bin/dep @@ -22,5 +22,5 @@ if(is_file($deployFile) && is_readable($deployFile)) { $deployer->run(); } else { - echo "deploy.php file does not found."; + echo "deploy.php file does not found.\n"; } \ No newline at end of file diff --git a/src/Console/Command.php b/src/Console/Command.php index c63ae363..4a3fb1ed 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -9,10 +9,12 @@ namespace Deployer\Console; use Deployer\Deployer; use Deployer\Server\Current; +use Deployer\Server\DryRun; use Deployer\TaskInterface; use Symfony\Component\Console\Command\Command as BaseCommand; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Command extends BaseCommand @@ -30,12 +32,52 @@ class Command extends BaseCommand { parent::__construct($name); $this->task = $task; + $this->setDescription($task->getDescription()); + $this->addOption( + 'dry-run', + null, + InputOption::VALUE_NONE, + 'Run without execution command on servers.' + ); + $this->addOption( + 'server', + null, + InputOption::VALUE_OPTIONAL, + 'Run tasks only on ths server.', + null + ); } protected function execute(InputInterface $input, OutputInterface $output) { + if (OutputInterface::VERBOSITY_NORMAL <= $output->getVerbosity()) { + $output->writeln("" + . (empty($this->getDescription()) ? $this->getName() : $this->getDescription()) + . "" + ); + } + foreach (Deployer::$servers as $name => $server) { + + if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) { + $output->writeln("Run task {$this->getName()} on server {$name}"); + } + + // Skip to specified server. + $onServer = $input->getOption('server'); + if (null !== $onServer && $onServer !== $name) { + continue; + } + + // Convert to dry run. + if ($input->getOption('dry-run')) { + $server = new DryRun($server->getConfiguration()); + } + + // Set current server. Current::setServer($name, $server); + + // Run task. $this->task->run(); } } diff --git a/src/Server/Configuration.php b/src/Server/Configuration.php index 9574af0d..e042aa08 100644 --- a/src/Server/Configuration.php +++ b/src/Server/Configuration.php @@ -35,6 +35,12 @@ class Configuration */ private $port; + /** + * Base path of server. + * @var string + */ + private $path; + /** * User of remote server. * @var string @@ -81,6 +87,16 @@ class Configuration $this->setPort($port); } + /** + * @param string $path + * @return $this + */ + public function path($path) + { + $this->path = $path; + return $this; + } + /** * Define user name for authentication. * @param string $name @@ -158,6 +174,14 @@ class Configuration return $this->password; } + /** + * @return string + */ + public function getPath() + { + return $this->path; + } + /** * @return int */ diff --git a/src/Server/DryRun.php b/src/Server/DryRun.php new file mode 100644 index 00000000..7374b07f --- /dev/null +++ b/src/Server/DryRun.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Deployer\Server; + +class DryRun implements ServerInterface +{ + /** + * @var Configuration + */ + private $config; + + /** + * @param Configuration $config + */ + public function __construct(Configuration $config) + { + $this->config = $config; + } + + /** + * {@inheritdoc} + */ + public function connect() + { + writeln("[{$this->config->getHost()}] Connecting to server."); + } + + /** + * {@inheritdoc} + */ + public function run($command) + { + writeln("[{$this->config->getHost()}] Run command: {$command}."); + } + + /** + * {@inheritdoc} + */ + public function upload($local, $remote) + { + writeln("[{$this->config->getHost()}] Upload file {$local} to {$remote}"); + } + + /** + * {@inheritdoc} + */ + public function download($local, $remote) + { + writeln("[{$this->config->getHost()}] Download file {$remote} to {$local}"); + } + + /** + *{@inheritdoc} + */ + public function getConfiguration() + { + return $this->config; + } +} \ No newline at end of file diff --git a/src/Server/PhpSecLib.php b/src/Server/PhpSecLib.php index b61b6e94..b1ec1d03 100644 --- a/src/Server/PhpSecLib.php +++ b/src/Server/PhpSecLib.php @@ -119,4 +119,11 @@ class PhpSecLib implements ServerInterface } } + /** + *{@inheritdoc} + */ + public function getConfiguration() + { + return $this->config; + } } \ No newline at end of file diff --git a/src/Server/ServerInterface.php b/src/Server/ServerInterface.php index bbc68e08..6039f20c 100644 --- a/src/Server/ServerInterface.php +++ b/src/Server/ServerInterface.php @@ -34,4 +34,9 @@ interface ServerInterface * @param string $remote Which file to download from remote server. */ public function download($local, $remote); + + /** + * @return Configuration + */ + public function getConfiguration(); } \ No newline at end of file diff --git a/src/Server/Ssh2.php b/src/Server/Ssh2.php index f411ac70..bc59f87a 100644 --- a/src/Server/Ssh2.php +++ b/src/Server/Ssh2.php @@ -133,4 +133,12 @@ class Ssh2 implements ServerInterface throw new \RuntimeException('Can not download file.'); } } + + /** + *{@inheritdoc} + */ + public function getConfiguration() + { + return $this->config; + } } \ No newline at end of file diff --git a/src/Task.php b/src/Task.php index ae3f9617..d4351e80 100644 --- a/src/Task.php +++ b/src/Task.php @@ -7,7 +7,9 @@ namespace Deployer; -class Task implements TaskInterface +use Deployer\Task\AbstractTask; + +class Task extends AbstractTask { /** * Callable body of current task. @@ -24,7 +26,7 @@ class Task implements TaskInterface } /** - * Run callback of current task. + * {@inheritdoc} */ public function run() { diff --git a/src/Task/AbstractTask.php b/src/Task/AbstractTask.php new file mode 100644 index 00000000..98f30cd7 --- /dev/null +++ b/src/Task/AbstractTask.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Deployer\Task; + +use Deployer\TaskInterface; + +abstract class AbstractTask implements TaskInterface +{ + /** + * @var string + */ + protected $description; + + /** + * Set task description + * @param string $description + * @return $this + */ + public function description($description) + { + $this->description = $description; + return $this; + } + + /** + * Description of task. + * @return string + */ + public function getDescription() + { + return $this->description; + } +} \ No newline at end of file diff --git a/src/Task/TaskFactory.php b/src/Task/TaskFactory.php index befab3a6..95a0bc85 100644 --- a/src/Task/TaskFactory.php +++ b/src/Task/TaskFactory.php @@ -17,7 +17,7 @@ class TaskFactory * Create task and save to tasks list. * @param string $name Task name. * @param callable|array $callback Code of task or array of other tasks. - * @return TaskInterface + * @return AbstractTask */ public static function create($name, $callback) { diff --git a/src/TaskInterface.php b/src/TaskInterface.php index 7f09f6b4..6a539a4b 100644 --- a/src/TaskInterface.php +++ b/src/TaskInterface.php @@ -9,5 +9,8 @@ namespace Deployer; interface TaskInterface { + /** + * Run current task. + */ public function run(); } \ No newline at end of file diff --git a/src/Utils/Path.php b/src/Utils/Path.php new file mode 100644 index 00000000..dae8851d --- /dev/null +++ b/src/Utils/Path.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Deployer\Utils; + +/** + * Path utils + * + * @package Gaufrette + * @author Antoine Hérault + */ +class Path +{ + /** + * Normalizes the given path + * + * @param string $path + * + * @return string + */ + public static function normalize($path) + { + $path = str_replace('\\', '/', $path); + $prefix = static::getAbsolutePrefix($path); + $path = substr($path, strlen($prefix)); + $parts = array_filter(explode('/', $path), 'strlen'); + $tokens = array(); + + foreach ($parts as $part) { + switch ($part) { + case '.': + continue; + case '..': + if (0 !== count($tokens)) { + array_pop($tokens); + continue; + } elseif (!empty($prefix)) { + continue; + } + default: + $tokens[] = $part; + } + } + + return $prefix . implode('/', $tokens); + } + + /** + * Indicates whether the given path is absolute or not + * + * @param string $path A normalized path + * + * @return boolean + */ + public static function isAbsolute($path) + { + return '' !== static::getAbsolutePrefix($path); + } + + /** + * Returns the absolute prefix of the given path + * + * @param string $path A normalized path + * + * @return string + */ + public static function getAbsolutePrefix($path) + { + preg_match('|^(?P([a-zA-Z]+:)?//?)|', $path, $matches); + + if (empty($matches['prefix'])) { + return ''; + } + + return strtolower($matches['prefix']); + } +} \ No newline at end of file diff --git a/src/functions.php b/src/functions.php index 49cec187..dafb81fe 100644 --- a/src/functions.php +++ b/src/functions.php @@ -5,9 +5,9 @@ * file that was distributed with this source code. */ use Deployer\Deployer; -use Deployer\Parameter; use Deployer\Server; use Deployer\Task; +use Deployer\Utils\Path; /** * @param string $name @@ -24,7 +24,7 @@ function server($name, $domain, $port = 22) * Define a new task and save to tasks list. * @param string $name Name of current task. * @param callable|array $callback Callable task or array of names of other tasks. - * @return \Deployer\TaskInterface + * @return \Deployer\Task\AbstractTask */ function task($name, $callback) { @@ -39,6 +39,11 @@ function task($name, $callback) function run($command) { $server = Server\Current::getServer(); + + if (output()->isDebug()) { + writeln("[{$server->getConfiguration()->getHost()}] $command"); + } + return $server->run($command); } @@ -50,7 +55,47 @@ function run($command) function upload($local, $remote) { $server = Server\Current::getServer(); - $server->upload($local, $remote); + + $remote = $server->getConfiguration()->getPath() . '/' . $remote; + + if (is_file($local)) { + + writeln("Upload file $local to $remote"); + + $server->upload($local, $remote); + + } elseif (is_dir($local)) { + + writeln("Upload from $local to $remote"); + + $finder = new Symfony\Component\Finder\Finder(); + $files = $finder + ->files() + ->ignoreUnreadableDirs() + ->ignoreVCS(true) + ->ignoreDotFiles(false) + ->in($local); + + if (output()->isVerbose()) { + $progress = progressHelper($files->count()); + } + + /** @var $file \Symfony\Component\Finder\SplFileInfo */ + foreach ($files as $file) { + + $server->upload( + $file->getRealPath(), + Path::normalize($remote . '/' . $file->getRelativePathname()) + ); + + if (output()->isVerbose()) { + $progress->advance(); + } + } + + } else { + throw new \RuntimeException("Uploading path '$local' does not exist."); + } } /** @@ -108,12 +153,15 @@ function get($key, $default) */ function ask($message, $default) { - $output = Deployer::get()->getOutput(); + if (output()->isQuiet()) { + return $default; + } + $dialog = Deployer::get()->getConsole()->getHelperSet()->get('dialog'); $message = "$message [$default] "; - return $dialog->ask($output, $message, $default); + return $dialog->ask(output(), $message, $default); } /** @@ -123,12 +171,15 @@ function ask($message, $default) */ function askConfirmation($message, $default = false) { - $output = Deployer::get()->getOutput(); + if (output()->isQuiet()) { + return $default; + } + $dialog = Deployer::get()->getConsole()->getHelperSet()->get('dialog'); $message = "$message [y/n] "; - if (!$dialog->askConfirmation($output, $message, $default)) { + if (!$dialog->askConfirmation(output(), $message, $default)) { return false; } @@ -141,10 +192,28 @@ function askConfirmation($message, $default = false) */ function askHiddenResponse($message) { - $output = Deployer::get()->getOutput(); $dialog = Deployer::get()->getConsole()->getHelperSet()->get('dialog'); $message = "$message "; - return $dialog->askHiddenResponse($output, $message); + return $dialog->askHiddenResponse(output(), $message); +} + +/** + * @param int $count + * @return \Symfony\Component\Console\Helper\ProgressHelper + */ +function progressHelper($count) +{ + $progress = Deployer::get()->getConsole()->getHelperSet()->get('progress'); + $progress->start(output(), $count); + return $progress; +} + +/** + * @return \Symfony\Component\Console\Output\Output + */ +function output() +{ + return Deployer::get()->getOutput(); } \ No newline at end of file