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