Refactor Deployer 🐘

This commit is contained in:
Elfet 2014-07-04 18:13:16 +04:00
parent 1bb8fb38f2
commit eb95635eba
13 changed files with 356 additions and 13 deletions

View File

@ -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";
}

View File

@ -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("<info>"
. (empty($this->getDescription()) ? $this->getName() : $this->getDescription())
. "</info>"
);
}
foreach (Deployer::$servers as $name => $server) {
if (OutputInterface::VERBOSITY_VERY_VERBOSE <= $output->getVerbosity()) {
$output->writeln("Run task <info>{$this->getName()}</info> on server <info>{$name}</info>");
}
// 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();
}
}

View File

@ -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
*/

64
src/Server/DryRun.php Normal file
View File

@ -0,0 +1,64 @@
<?php
/* (c) Anton Medvedev <anton@elfet.ru>
*
* 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;
}
}

View File

@ -119,4 +119,11 @@ class PhpSecLib implements ServerInterface
}
}
/**
*{@inheritdoc}
*/
public function getConfiguration()
{
return $this->config;
}
}

View File

@ -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();
}

View File

@ -133,4 +133,12 @@ class Ssh2 implements ServerInterface
throw new \RuntimeException('Can not download file.');
}
}
/**
*{@inheritdoc}
*/
public function getConfiguration()
{
return $this->config;
}
}

View File

@ -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()
{

38
src/Task/AbstractTask.php Normal file
View File

@ -0,0 +1,38 @@
<?php
/* (c) Anton Medvedev <anton@elfet.ru>
*
* 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;
}
}

View File

@ -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)
{

View File

@ -9,5 +9,8 @@ namespace Deployer;
interface TaskInterface
{
/**
* Run current task.
*/
public function run();
}

81
src/Utils/Path.php Normal file
View File

@ -0,0 +1,81 @@
<?php
/* (c) Anton Medvedev <anton@elfet.ru>
*
* 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 <antoine.herault@gmail.com>
*/
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<prefix>([a-zA-Z]+:)?//?)|', $path, $matches);
if (empty($matches['prefix'])) {
return '';
}
return strtolower($matches['prefix']);
}
}

View File

@ -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 <info>$local</info> to <info>$remote</info>");
$server->upload($local, $remote);
} elseif (is_dir($local)) {
writeln("Upload from <info>$local</info> to <info>$remote</info>");
$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 = "<question>$message [$default]</question> ";
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 = "<question>$message [y/n]</question> ";
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 = "<question>$message</question> ";
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();
}