From e09d0b85966d44eb208db075b6d27a1997ca5dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 22 Jul 2011 21:32:56 +0200 Subject: [PATCH 1/9] added configuration model --- Model/Command.php | 17 +++ Model/Deployment.php | 129 +++++++++++++++++++ Model/Identity.php | 131 +++++++++++++++++++ Model/Server.php | 293 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 570 insertions(+) create mode 100644 Model/Command.php create mode 100644 Model/Deployment.php create mode 100644 Model/Identity.php create mode 100644 Model/Server.php diff --git a/Model/Command.php b/Model/Command.php new file mode 100644 index 0000000..5ff939e --- /dev/null +++ b/Model/Command.php @@ -0,0 +1,17 @@ + + */ +class Command +{ + /** + * @return string + */ + public function getCommandLine() + { + return ''; + } +} diff --git a/Model/Deployment.php b/Model/Deployment.php new file mode 100644 index 0000000..821f3ff --- /dev/null +++ b/Model/Deployment.php @@ -0,0 +1,129 @@ + + */ +class Deployment +{ + const STATUS_UNKNOWN = 0; + const STATUS_STARTED = 1; + const STATUS_SUCCESS = 2; + const STATUS_ERROR = 3; + const STATUS_SCHEDULED = 4; + + /** + * @var string + */ + protected $message; + + /** + * @var \DateTime + */ + protected $deployedAt; + + /** + * @var integer + */ + protected $status; + + /** + * @var string + */ + protected $directory; + + /** + * @var string|null + */ + protected $logs; + + public function __construct($message = null) + { + $this->message = $message; + $this->deployedAt = null; + $this->status = self::STATUS_UNKNOWN; + $this->directory = null; + $this->logs = null; + } + + /** + * @param \DateTime $deployedAt + */ + public function setDeployedAt($deployedAt) + { + $this->deployedAt = $deployedAt; + } + + /** + * @return \DateTime + */ + public function getDeployedAt() + { + return $this->deployedAt; + } + + /** + * @param string $directory + */ + public function setDirectory($directory) + { + $this->directory = $directory; + } + + /** + * @return string + */ + public function getDirectory() + { + return $this->directory; + } + + /** + * @param null|string $logs + */ + public function setLogs($logs) + { + $this->logs = $logs; + } + + /** + * @return null|string + */ + public function getLogs() + { + return $this->logs; + } + + /** + * @param string $message + */ + public function setMessage($message) + { + $this->message = $message; + } + + /** + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param int $status + */ + public function setStatus($status) + { + $this->status = $status; + } + + /** + * @return int + */ + public function getStatus() + { + return $this->status; + } +} diff --git a/Model/Identity.php b/Model/Identity.php new file mode 100644 index 0000000..63772df --- /dev/null +++ b/Model/Identity.php @@ -0,0 +1,131 @@ + + */ +class Identity +{ + /** + * @var string + */ + protected $user; + + /** + * @var string|null + */ + protected $password; + + /** + * @var string|null + */ + protected $publicKeyFile; + + /** + * @var string|null + */ + protected $privateKeyFile; + + /** + * @var string|null + */ + protected $keyPassphrase; + + public function __construct($user = null) + { + $this->user = $user; + $this->password = null; + $this->publicKeyFile = null; + $this->privateKeyFile = null; + $this->keyPassphrase = null; + } + + /** + * @return boolean + */ + public function hasKey() + { + return $this->getPublicKeyFile() && $this->getPrivateKeyFile(); + } + + /** + * @param null|string $keyPassphrase + */ + public function setKeyPassphrase($keyPassphrase) + { + $this->keyPassphrase = $keyPassphrase; + } + + /** + * @return null|string + */ + public function getKeyPassphrase() + { + return $this->keyPassphrase; + } + + /** + * @param null|string $password + */ + public function setPassword($password) + { + $this->password = $password; + } + + /** + * @return null|string + */ + public function getPassword() + { + return $this->password; + } + + /** + * @param null|string $privateKeyFile + */ + public function setPrivateKeyFile($privateKeyFile) + { + $this->privateKeyFile = $privateKeyFile; + } + + /** + * @return null|string + */ + public function getPrivateKeyFile() + { + return $this->privateKeyFile; + } + + /** + * @param null|string $publicKeyFile + */ + public function setPublicKeyFile($publicKeyFile) + { + $this->publicKeyFile = $publicKeyFile; + } + + /** + * @return null|string + */ + public function getPublicKeyFile() + { + return $this->publicKeyFile; + } + + /** + * @param string $user + */ + public function setUser($user) + { + $this->user = $user; + } + + /** + * @return string + */ + public function getUser() + { + return $this->user; + } +} diff --git a/Model/Server.php b/Model/Server.php new file mode 100644 index 0000000..780db4a --- /dev/null +++ b/Model/Server.php @@ -0,0 +1,293 @@ + + */ +class Server +{ + /** + * @var string + */ + protected $name; + + /** + * @var string|null + */ + protected $description; + + /** + * @var string + */ + protected $host; + + /** + * @var string + */ + protected $path; + + /** + * @var string + */ + protected $decorator; + + /** + * @var ArrayCollection + */ + protected $versions; + + /** + * @var string|null + */ + protected $sshAdapter; + + /** + * @var Identity|null + */ + protected $sshIdentity; + + /** + * @var integer + */ + protected $sshPort; + + /** + * @var string|null + */ + protected $deployerAdapter; + + /** + * @var Identity|null + */ + protected $deployerIdentity; + + /** + * @var integer + */ + protected $deployerPort; + + /** + * @var array + */ + protected $deployerConfig; + + public function __construct($name = null) + { + $this->name = $name; + $this->description = null; + $this->host = null; + $this->path = null; + $this->decorator = 'None'; + $this->versions = new ArrayCollection(); + $this->sshAdapter = null; + $this->sshIdentity = null; + $this->sshPort = 22; + $this->deployerAdapter = null; + $this->deployerIdentity = null; + $this->deployerPort = null; + $this->deployerConfig = array(); + } + + /** + * @param string $decorator + */ + public function setDecorator($decorator) + { + $this->decorator = $decorator; + } + + /** + * @return string + */ + public function getDecorator() + { + return $this->decorator; + } + + /** + * @param null|string $deployerAdapter + */ + public function setDeployerAdapter($deployerAdapter) + { + $this->deployerAdapter = $deployerAdapter; + } + + /** + * @return null|string + */ + public function getDeployerAdapter() + { + return $this->deployerAdapter; + } + + /** + * @param array $deployerConfig + */ + public function setDeployerConfig(array $deployerConfig) + { + $this->deployerConfig = $deployerConfig; + } + + /** + * @return array + */ + public function getDeployerConfig() + { + return $this->deployerConfig; + } + + /** + * @param Identity|null $deployerIdentity + */ + public function setDeployerIdentity($deployerIdentity) + { + $this->deployerIdentity = $deployerIdentity; + } + + /** + * @return Identity|null + */ + public function getDeployerIdentity() + { + return $this->deployerIdentity; + } + + /** + * @param int $deployerPort + */ + public function setDeployerPort($deployerPort) + { + $this->deployerPort = $deployerPort; + } + + /** + * @return int + */ + public function getDeployerPort() + { + return $this->deployerPort; + } + + /** + * @param null|string $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return null|string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $host + */ + public function setHost($host) + { + $this->host = $host; + } + + /** + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $path + */ + public function setPath($path) + { + $this->path = $path; + } + + /** + * @return string + */ + public function getPath() + { + return $this->path; + } + + /** + * @param null|string $sshAdapter + */ + public function setSshAdapter($sshAdapter) + { + $this->sshAdapter = $sshAdapter; + } + + /** + * @return null|string + */ + public function getSshAdapter() + { + return $this->sshAdapter; + } + + /** + * @param Identity|null $sshIdentity + */ + public function setSshIdentity($sshIdentity) + { + $this->sshIdentity = $sshIdentity; + } + + /** + * @return Identity|null + */ + public function getSshIdentity() + { + return $this->sshIdentity; + } + + /** + * @param int $sshPort + */ + public function setSshPort($sshPort) + { + $this->sshPort = $sshPort; + } + + /** + * @return int + */ + public function getSshPort() + { + return $this->sshPort; + } + + /** + * @return ArrayCollection + */ + public function getVersions() + { + return $this->versions; + } +} From 2f9fcca96cf80f5cbe30a6a3ea924a72040c81dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 22 Jul 2011 21:33:51 +0200 Subject: [PATCH 2/9] added base protocol classes --- Protocol/AbstractProtocol.php | 50 +++++++++++++++++++++++++++++++++ Protocol/Output.php | 28 ++++++++++++++++++ Protocol/OutputEvent.php | 42 +++++++++++++++++++++++++++ Protocol/ProtocolInterface.php | 10 +++++++ Protocol/TransfertInterface.php | 21 ++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 Protocol/AbstractProtocol.php create mode 100644 Protocol/Output.php create mode 100644 Protocol/OutputEvent.php create mode 100644 Protocol/ProtocolInterface.php create mode 100644 Protocol/TransfertInterface.php diff --git a/Protocol/AbstractProtocol.php b/Protocol/AbstractProtocol.php new file mode 100644 index 0000000..4702b30 --- /dev/null +++ b/Protocol/AbstractProtocol.php @@ -0,0 +1,50 @@ + + */ +class AbstractProtocol +{ + protected $dispatcher; + protected $outputs; + + public function __construct(EventDispatcher $dispatcher, $rootDir) + { + $this->dispatcher = $dispatcher; + $this->rootDir = $rootDir; + $this->outputs = array(); + } + + public function getOutputs() + { + return $this->outputs; + } + + public function addOutput(Output $output) + { + $this->outputs[] = $output; + + $this->dispatcher->dispatch('onOutput', new OutputEvent($this, $output)); + } + + protected function startSession() + { + $this->outputs = array(); + } + + protected function executeProcess($command, $cwd = null) + { + $that = $this; + $callback = function($type, $line) use ($that) { $that->addOutput(new Output($line, $type !== 'ou')); }; + $process = new Process($command, $cwd ?: $this->rootDir); + $status = $process->run($callback); + + return $status === 0; + } +} diff --git a/Protocol/Output.php b/Protocol/Output.php new file mode 100644 index 0000000..cef9e9f --- /dev/null +++ b/Protocol/Output.php @@ -0,0 +1,28 @@ + + */ +class Output +{ + protected $message; + protected $isError; + + public function __construct($message, $isError = false) + { + $this->message = $message; + $this->isError = $isError; + } + + public function getMessage() + { + return $this->message; + } + + public function getIsError() + { + return $this->isError; + } +} diff --git a/Protocol/OutputEvent.php b/Protocol/OutputEvent.php new file mode 100644 index 0000000..63019fd --- /dev/null +++ b/Protocol/OutputEvent.php @@ -0,0 +1,42 @@ + + */ +class OutputEvent extends Event +{ + protected $subject; + protected $timestamp; + protected $output; + + public function __construct(ProtocolInterface $subject, Output $output) + { + $this->subject = $subject; + $this->timestamp = time(); + $this->output = $output; + } + + public function getSubject() + { + return $this->subject; + } + + public function getTimestamp() + { + return $this->timestamp; + } + + public function getMessage() + { + return $this->output->getMessage(); + } + + public function getIsError() + { + return $this->output->getIsError(); + } +} diff --git a/Protocol/ProtocolInterface.php b/Protocol/ProtocolInterface.php new file mode 100644 index 0000000..c8ec62c --- /dev/null +++ b/Protocol/ProtocolInterface.php @@ -0,0 +1,10 @@ + + */ +interface ProtocolInterface +{ +} diff --git a/Protocol/TransfertInterface.php b/Protocol/TransfertInterface.php new file mode 100644 index 0000000..65bcca5 --- /dev/null +++ b/Protocol/TransfertInterface.php @@ -0,0 +1,21 @@ + + */ +interface TransfertInterface extends ProtocolInterface +{ + /** + * Deploy project on distant server. + * + * @param Deployment $deployment Deployment configuration + * @param Server $server Server configuration + * @return boolean Success (or not) + */ + public function transfert(Deployment $deployment, Server $server); +} From 296f4ae5437bda75d1641b066164c7d0e80fe09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 22 Jul 2011 21:34:07 +0200 Subject: [PATCH 3/9] added protocol exceptions --- Exceptions/AuthenticationException.php | 37 ++++++++++++++++++++++ Exceptions/ConnectionException.php | 37 ++++++++++++++++++++++ Exceptions/ProtocolException.php | 43 ++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 Exceptions/AuthenticationException.php create mode 100644 Exceptions/ConnectionException.php create mode 100644 Exceptions/ProtocolException.php diff --git a/Exceptions/AuthenticationException.php b/Exceptions/AuthenticationException.php new file mode 100644 index 0000000..ab4f3be --- /dev/null +++ b/Exceptions/AuthenticationException.php @@ -0,0 +1,37 @@ + + */ +class AuthenticationException extends ProtocolException +{ + protected $host; + protected $identity; + + public function __construct(ProtocolInterface $protocol, $host, Identity $identity) + { + $this->protocol = $protocol; + $this->host = $host; + $this->identity = $identity; + } + + public function getWarning() + { + return sprintf('Authentication failed on %s for %s', $this->host, $this->identity->getUser()); + } + + public function getHost() + { + return $this->host; + } + + public function getIdentity() + { + return $this->identity; + } +} diff --git a/Exceptions/ConnectionException.php b/Exceptions/ConnectionException.php new file mode 100644 index 0000000..4d2720a --- /dev/null +++ b/Exceptions/ConnectionException.php @@ -0,0 +1,37 @@ + + */ +class ConnectionException extends ProtocolException +{ + protected $protocol; + protected $host; + protected $port; + + public function __construct(ProtocolInterface $protocol, $host, $port) + { + $this->protocol = $protocol; + $this->host = $host; + $this->port = $port; + } + + public function getWarning() + { + return sprintf('Connection failed on %s:%s', $this->host, $this->port); + } + + public function getHost() + { + return $this->host; + } + + public function getPort() + { + return $this->port; + } +} diff --git a/Exceptions/ProtocolException.php b/Exceptions/ProtocolException.php new file mode 100644 index 0000000..dc5f4df --- /dev/null +++ b/Exceptions/ProtocolException.php @@ -0,0 +1,43 @@ + + */ +class ProtocolException extends \RuntimeException +{ + protected $protocol; + protected $warning; + + public function __construct(ProtocolInterface $protocol, $warning) + { + $this->protocol = $protocol; + $this->warning = $warning; + } + + public function getMessage() + { + return sprintf('[%s]: $message', $this->getProtocolName(), $this->message); + } + + public function getProtocol() + { + return $this->protocol; + } + + public function getWarning() + { + return $this->warning; + } + + public function getProtocolName() + { + $class = get_class($this->protocol); + + return substr($class, strrpos($class, '\\') + 1); + } +} From 6e19036e86cb4a86413221e0dbc47b4e20262efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 22 Jul 2011 21:34:39 +0200 Subject: [PATCH 4/9] added shell (ssh) protocol --- Protocol/Shell/ShellInterface.php | 22 +++++++++ Protocol/Shell/Ssh2.php | 75 +++++++++++++++++++++++++++++++ Protocol/Shell/SshProcess.php | 47 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 Protocol/Shell/ShellInterface.php create mode 100644 Protocol/Shell/Ssh2.php create mode 100644 Protocol/Shell/SshProcess.php diff --git a/Protocol/Shell/ShellInterface.php b/Protocol/Shell/ShellInterface.php new file mode 100644 index 0000000..53d489c --- /dev/null +++ b/Protocol/Shell/ShellInterface.php @@ -0,0 +1,22 @@ + + */ +interface ShellInterface extends ProtocolInterface +{ + /** + * Execute commands on distant server. + * + * @param Server $server Server configuration + * @param array $commands Commands to execute + * @return boolean Success (or not) + */ + public function execute(Server $server, array $commands); +} diff --git a/Protocol/Shell/Ssh2.php b/Protocol/Shell/Ssh2.php new file mode 100644 index 0000000..fd3d5bd --- /dev/null +++ b/Protocol/Shell/Ssh2.php @@ -0,0 +1,75 @@ + + */ +class Ssh2 extends AbstractProtocol implements ShellInterface +{ + public function execute(Server $server, array $commands) + { + list($session, $shell) = $this->connect($server); + + foreach ($commands as $command) { + $output = ssh2_exec($session, $command); + $errors = ssh2_fetch_stream($output, SSH2_STREAM_STDERR); + + $this->addStream($output, false); + $this->addStream($errors, true); + } + + $this->disconnect($shell); + + return !$errors; + } + + protected function connect(Server $server) + { + if (!$session = ssh2_connect($server->getHost(), $server->getSshPort())) { + throw new ConnectionException($this, $server->getHost(), $server->getSshPort()); + } + + if (!$this->authenticate($session, $server->getSshIdentity())) { + throw new AuthenticationException($this, $server->getHost(), $server->getSshIdentity()); + } + + if (!$shell = ssh2_shell($session)) { + throw new ProtocolException($this, 'Failed opening shell'); + } + + return array($session, $shell); + } + + protected function disconnect($shell) + { + fclose($shell); + } + + protected function addStream($output, $isError) + { + stream_set_blocking($output, true); + + foreach (explode("\n", stream_get_contents($output)) as $message){ + $this->addOutput(new Output($message, $isError)); + } + + fclose($output); + } + + protected function authenticate($session, Identity $identity) + { + if ($identity->hasKey() && ssh2_auth_pubkey_file($session, $identity->getUser(), $identity->getPublicKeyFile(), $identity->getPrivateKeyFile(), $identity->getKeyPassphrase())) { + return true; + } + + return ssh2_auth_password($session, $identity->getUser(), $identity->getPassword()); + } +} diff --git a/Protocol/Shell/SshProcess.php b/Protocol/Shell/SshProcess.php new file mode 100644 index 0000000..75da882 --- /dev/null +++ b/Protocol/Shell/SshProcess.php @@ -0,0 +1,47 @@ + + */ +class SshProcess extends AbstractProtocol implements ShellInterface +{ + public function execute(Server $server, array $commands) + { + $this->connect($server); + + $ok = true; + foreach ($commands as $command) { + if (!$this->executeProcess($command)) { + $ok = false; + } + } + + $this->disconnect(); + + return $ok; + } + + protected function connect(Server $server) + { + $this->startSession(); + + if ($server->getSshIdentity()->hasKey()) { + $command = ''; + } else { + $command = ''; + } + + return $this->executeProcess($command); + } + + protected function disconnect() + { + return $this->executeProcess('exit'); + } +} From 46af3af754d4bf44ba4a94e9fc728bf4f1ae9b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 22 Jul 2011 23:50:49 +0200 Subject: [PATCH 5/9] completed ssh process commands --- Protocol/Shell/SshProcess.php | 36 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Protocol/Shell/SshProcess.php b/Protocol/Shell/SshProcess.php index 75da882..a0cdd48 100644 --- a/Protocol/Shell/SshProcess.php +++ b/Protocol/Shell/SshProcess.php @@ -13,35 +13,39 @@ class SshProcess extends AbstractProtocol implements ShellInterface { public function execute(Server $server, array $commands) { - $this->connect($server); + $this->startSession(); $ok = true; foreach ($commands as $command) { - if (!$this->executeProcess($command)) { + if (!$this->executeProcess($this->buildCommand($server, $command))) { $ok = false; } } - $this->disconnect(); - return $ok; } - protected function connect(Server $server) + protected function buildCommand(Server $server, $command) { - $this->startSession(); - if ($server->getSshIdentity()->hasKey()) { - $command = ''; + return sprintf( + 'ssh %s@%s:%s -i %s -i %s %s', + $server->getSshIdentity()->getUser(), + $server->getHost(), + $server->getSshPort(), + $server->getSshIdentity()->getPrivateKeyFile(), + $server->getSshIdentity()->getPublicKeyFile(), + $command + ); } else { - $command = ''; + return sprintf( + 'spawn ssh %s@%s:%s %s; expect "*?assword:*"; send -- "%s\n"', + $server->getSshIdentity()->getUser(), + $server->getHost(), + $server->getSshPort(), + $command, + $server->getSshIdentity()->getPassword() + ); } - - return $this->executeProcess($command); - } - - protected function disconnect() - { - return $this->executeProcess('exit'); } } From 540d4f7f1fd90bbce9205403603eb090322d45ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Sat, 23 Jul 2011 09:34:56 +0200 Subject: [PATCH 6/9] refactored shell protocol --- .../Exceptions}/AuthenticationException.php | 2 +- Protocol/Exceptions/AvailabilityException.php | 25 +++++++++++++++++++ .../Exceptions}/ConnectionException.php | 2 +- .../Exceptions}/ProtocolException.php | 2 +- .../FilesInterface.php} | 6 ++--- Protocol/Shell/ShellInterface.php | 6 ++--- Protocol/Shell/Ssh2.php | 8 +++--- Protocol/Shell/SshProcess.php | 4 +-- 8 files changed, 40 insertions(+), 15 deletions(-) rename {Exceptions => Protocol/Exceptions}/AuthenticationException.php (93%) create mode 100644 Protocol/Exceptions/AvailabilityException.php rename {Exceptions => Protocol/Exceptions}/ConnectionException.php (92%) rename {Exceptions => Protocol/Exceptions}/ProtocolException.php (93%) rename Protocol/{TransfertInterface.php => Files/FilesInterface.php} (77%) diff --git a/Exceptions/AuthenticationException.php b/Protocol/Exceptions/AuthenticationException.php similarity index 93% rename from Exceptions/AuthenticationException.php rename to Protocol/Exceptions/AuthenticationException.php index ab4f3be..5f38597 100644 --- a/Exceptions/AuthenticationException.php +++ b/Protocol/Exceptions/AuthenticationException.php @@ -1,6 +1,6 @@ + */ +class AvailabilityException +{ + protected $protocol; + protected $server; + + public function __constrcut($protocol, Server $server) + { + $this->protocol = $protocol; + $this->server = $server; + } + + public function getMessage() + { + return sprintf('%s protocol is not available for server %s', ucfirst($this->protocol), $this->server->getName()); + } +} diff --git a/Exceptions/ConnectionException.php b/Protocol/Exceptions/ConnectionException.php similarity index 92% rename from Exceptions/ConnectionException.php rename to Protocol/Exceptions/ConnectionException.php index 4d2720a..0557cb6 100644 --- a/Exceptions/ConnectionException.php +++ b/Protocol/Exceptions/ConnectionException.php @@ -1,6 +1,6 @@ */ -interface TransfertInterface extends ProtocolInterface +interface FilesInterface extends ProtocolInterface { /** * Deploy project on distant server. * - * @param Deployment $deployment Deployment configuration * @param Server $server Server configuration + * @param Deployment $deployment Deployment configuration * @return boolean Success (or not) */ - public function transfert(Deployment $deployment, Server $server); + public function transfert(Server $server, Deployment $deployment); } diff --git a/Protocol/Shell/ShellInterface.php b/Protocol/Shell/ShellInterface.php index 53d489c..057620b 100644 --- a/Protocol/Shell/ShellInterface.php +++ b/Protocol/Shell/ShellInterface.php @@ -4,7 +4,7 @@ use BeSimple\DeploymentBundle\Protocol\ProtocolInterface; use BeSimple\DeploymentBundle\Model\Server; -use BeSimple\DeploymentBundle\Model\Command; +use BeSimple\DeploymentBundle\Model\Commands; /** * @author: Jean-François Simon @@ -15,8 +15,8 @@ interface ShellInterface extends ProtocolInterface * Execute commands on distant server. * * @param Server $server Server configuration - * @param array $commands Commands to execute + * @param Commands $commands Commands to execute * @return boolean Success (or not) */ - public function execute(Server $server, array $commands); + public function execute(Server $server, Commands $commands); } diff --git a/Protocol/Shell/Ssh2.php b/Protocol/Shell/Ssh2.php index fd3d5bd..26e2f8f 100644 --- a/Protocol/Shell/Ssh2.php +++ b/Protocol/Shell/Ssh2.php @@ -4,17 +4,17 @@ use BeSimple\DeploymentBundle\Protocol\AbstractProtocol; use BeSimple\DeploymentBundle\Model\Server; -use BeSimple\DeploymentBundle\Model\Command; +use BeSimple\DeploymentBundle\Model\Commands; use BeSimple\DeploymentBundle\Model\Identity; -use BeSimple\DeploymentBundle\Exceptions\ConnectionException; -use BeSimple\DeploymentBundle\Exceptions\AuthenticationException; +use BeSimple\DeploymentBundle\Protocol\Exceptions\ConnectionException; +use BeSimple\DeploymentBundle\Protocol\Exceptions\AuthenticationException; /** * @author: Jean-François Simon */ class Ssh2 extends AbstractProtocol implements ShellInterface { - public function execute(Server $server, array $commands) + public function execute(Server $server, Commands $commands) { list($session, $shell) = $this->connect($server); diff --git a/Protocol/Shell/SshProcess.php b/Protocol/Shell/SshProcess.php index a0cdd48..a9d1248 100644 --- a/Protocol/Shell/SshProcess.php +++ b/Protocol/Shell/SshProcess.php @@ -4,14 +4,14 @@ use BeSimple\DeploymentBundle\Protocol\AbstractProtocol; use BeSimple\DeploymentBundle\Model\Server; -use BeSimple\DeploymentBundle\Model\Command; +use BeSimple\DeploymentBundle\Model\Commands; /** * @author: Jean-François Simon */ class SshProcess extends AbstractProtocol implements ShellInterface { - public function execute(Server $server, array $commands) + public function execute(Server $server, Commands $commands) { $this->startSession(); From 59495911aa6e743eb7746602f2c6166d0fac5c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Sat, 23 Jul 2011 09:37:21 +0200 Subject: [PATCH 7/9] added protocol interfaces --- Model/Command.php | 79 ++++++- Model/Commands.php | 91 ++++++++ Model/Server.php | 238 ++------------------ Model/Transfert.php | 10 + Protocol/Files/FilesInterface.php | 9 +- Protocol/Versioning/VersioningInterface.php | 22 ++ 6 files changed, 229 insertions(+), 220 deletions(-) create mode 100644 Model/Commands.php create mode 100644 Model/Transfert.php create mode 100644 Protocol/Versioning/VersioningInterface.php diff --git a/Model/Command.php b/Model/Command.php index 5ff939e..1a80f40 100644 --- a/Model/Command.php +++ b/Model/Command.php @@ -7,11 +7,86 @@ */ class Command { + const TYPE_SHELL = 1; + const TYPE_SYMFONY = 2; + + /** + * @var integer + */ + protected $type; + + /** + * @var string + */ + protected $command; + + /** + * @param int $type + * @param string|null $command + */ + public function __contsruct($type = self::TYPE_SHELL, $command = null) + { + $this->type = $type; + $this->command = $command; + } + /** * @return string */ - public function getCommandLine() + public function getCommandLine($symfonyPattern) + { + if ($this->type === self::TYPE_SYMFONY) { + return sprintf($symfonyPattern, $this->command); + } + + return $this->command; + } + + /** + * @param string $command + */ + public function setCommand($command) + { + $this->command = $command; + } + + /** + * @return string + */ + public function getCommand() + { + return $this->command; + } + + /** + * @param string $symfony + */ + public function setSymfony($symfony) + { + $this->symfony = $symfony; + } + + /** + * @return string + */ + public function getSymfony() + { + return $this->symfony; + } + + /** + * @param integer $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return integer + */ + public function getType() { - return ''; + return $this->type; } } diff --git a/Model/Commands.php b/Model/Commands.php new file mode 100644 index 0000000..c061719 --- /dev/null +++ b/Model/Commands.php @@ -0,0 +1,91 @@ + + */ +class Commands implements \Iterator, \Countable +{ + /** + * @var string + */ + protected $symfonyPattern; + + /** + * @var array + */ + protected $commands; + + /** + * @var integer + */ + protected $cursor; + + /** + * @param string $symfonyPattern + */ + public function __construct($symfonyPattern = './app/console %s') + { + $this->symfonyPattern = $symfonyPattern; + $this->commands = array(); + $this->cursor = 0; + } + + /** + * @return string + */ + public function current() + { + return $this->commands[$this->cursor]->getCommandLine($this->symfonyPattern); + } + + /** + * @param Command $command + * @return void + */ + public function push(Command $command) + { + $this->commands[] = $command; + } + + /** + * @return integer + */ + public function count() + { + return count($this->commands); + } + + /** + * @return void + */ + public function rewind() + { + $this->cursor = 0; + } + + /** + * @return void + */ + public function next() + { + $this->cursor ++; + } + + /** + * @return integer + */ + public function key() + { + return $this->cursor; + } + + /** + * @return boolean + */ + public function valid() + { + return isset($this->commands[$this->cursor]); + } +} diff --git a/Model/Server.php b/Model/Server.php index 780db4a..fd9a7ec 100644 --- a/Model/Server.php +++ b/Model/Server.php @@ -9,6 +9,9 @@ */ class Server { + const DEPLOYMENT_METHOD_FILES = 1; + const DEPLOYMENT_METHOD_VERSIONING = 2; + /** * @var string */ @@ -42,37 +45,42 @@ class Server /** * @var string|null */ - protected $sshAdapter; + protected $shellAdapter; /** * @var Identity|null */ - protected $sshIdentity; + protected $shellIdentity; /** * @var integer */ - protected $sshPort; + protected $shellPort; /** * @var string|null */ - protected $deployerAdapter; + protected $filesAdapter; /** * @var Identity|null */ - protected $deployerIdentity; + protected $filesIdentity; /** * @var integer */ - protected $deployerPort; + protected $filesPort; /** - * @var array + * @var string */ - protected $deployerConfig; + protected $versioningSource; + + /** + * @var integer + */ + protected $deploymentMethod; public function __construct($name = null) { @@ -82,212 +90,14 @@ public function __construct($name = null) $this->path = null; $this->decorator = 'None'; $this->versions = new ArrayCollection(); - $this->sshAdapter = null; - $this->sshIdentity = null; - $this->sshPort = 22; - $this->deployerAdapter = null; - $this->deployerIdentity = null; - $this->deployerPort = null; - $this->deployerConfig = array(); - } - - /** - * @param string $decorator - */ - public function setDecorator($decorator) - { - $this->decorator = $decorator; - } - - /** - * @return string - */ - public function getDecorator() - { - return $this->decorator; - } - - /** - * @param null|string $deployerAdapter - */ - public function setDeployerAdapter($deployerAdapter) - { - $this->deployerAdapter = $deployerAdapter; - } - - /** - * @return null|string - */ - public function getDeployerAdapter() - { - return $this->deployerAdapter; - } - - /** - * @param array $deployerConfig - */ - public function setDeployerConfig(array $deployerConfig) - { - $this->deployerConfig = $deployerConfig; - } - - /** - * @return array - */ - public function getDeployerConfig() - { - return $this->deployerConfig; - } - - /** - * @param Identity|null $deployerIdentity - */ - public function setDeployerIdentity($deployerIdentity) - { - $this->deployerIdentity = $deployerIdentity; - } - - /** - * @return Identity|null - */ - public function getDeployerIdentity() - { - return $this->deployerIdentity; - } - - /** - * @param int $deployerPort - */ - public function setDeployerPort($deployerPort) - { - $this->deployerPort = $deployerPort; - } - - /** - * @return int - */ - public function getDeployerPort() - { - return $this->deployerPort; - } - - /** - * @param null|string $description - */ - public function setDescription($description) - { - $this->description = $description; - } - - /** - * @return null|string - */ - public function getDescription() - { - return $this->description; + $this->shellAdapter = null; + $this->shellIdentity = null; + $this->shellPort = null; + $this->filesAdapter = null; + $this->filesIdentity = null; + $this->filesPort = null; + $this->versioningSource = array(); + $this->deploymentMethod = self::DEPLOYMENT_METHOD_FILES; } - /** - * @param string $host - */ - public function setHost($host) - { - $this->host = $host; - } - - /** - * @return string - */ - public function getHost() - { - return $this->host; - } - - /** - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $path - */ - public function setPath($path) - { - $this->path = $path; - } - - /** - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * @param null|string $sshAdapter - */ - public function setSshAdapter($sshAdapter) - { - $this->sshAdapter = $sshAdapter; - } - - /** - * @return null|string - */ - public function getSshAdapter() - { - return $this->sshAdapter; - } - - /** - * @param Identity|null $sshIdentity - */ - public function setSshIdentity($sshIdentity) - { - $this->sshIdentity = $sshIdentity; - } - - /** - * @return Identity|null - */ - public function getSshIdentity() - { - return $this->sshIdentity; - } - - /** - * @param int $sshPort - */ - public function setSshPort($sshPort) - { - $this->sshPort = $sshPort; - } - - /** - * @return int - */ - public function getSshPort() - { - return $this->sshPort; - } - - /** - * @return ArrayCollection - */ - public function getVersions() - { - return $this->versions; - } } diff --git a/Model/Transfert.php b/Model/Transfert.php new file mode 100644 index 0000000..dbb3be5 --- /dev/null +++ b/Model/Transfert.php @@ -0,0 +1,10 @@ + + */ +class Transfert +{ +} diff --git a/Protocol/Files/FilesInterface.php b/Protocol/Files/FilesInterface.php index 4c01250..d5f2085 100644 --- a/Protocol/Files/FilesInterface.php +++ b/Protocol/Files/FilesInterface.php @@ -1,9 +1,10 @@ @@ -17,5 +18,5 @@ interface FilesInterface extends ProtocolInterface * @param Deployment $deployment Deployment configuration * @return boolean Success (or not) */ - public function transfert(Server $server, Deployment $deployment); + public function transfert(Server $server, Transfert $transfert); } diff --git a/Protocol/Versioning/VersioningInterface.php b/Protocol/Versioning/VersioningInterface.php new file mode 100644 index 0000000..cecf2ac --- /dev/null +++ b/Protocol/Versioning/VersioningInterface.php @@ -0,0 +1,22 @@ + + */ +interface VersioningInterface extends ProtocolInterface +{ + /** + * Update project on distant server. + * + * @param Server $server Server configuration + * @param string $deployment Branch, tag or URL + * @return boolean Success (or not) + */ + public function checkout(Server $server, $source); +} From 366ea5eb8d9c0bc81271502eb81b37f6a4cba723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Sat, 23 Jul 2011 09:37:41 +0200 Subject: [PATCH 8/9] added protocol factory & proxy --- Protocol/ProtocolFactory.php | 106 +++++++++++++++++++++++++++++++++++ Protocol/ProtocolProxy.php | 73 ++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 Protocol/ProtocolFactory.php create mode 100644 Protocol/ProtocolProxy.php diff --git a/Protocol/ProtocolFactory.php b/Protocol/ProtocolFactory.php new file mode 100644 index 0000000..42d5db6 --- /dev/null +++ b/Protocol/ProtocolFactory.php @@ -0,0 +1,106 @@ + + */ +class ProtocolFactory +{ + const TYPE_SHELL = 'shell'; + const TYPE_FILES = 'files'; + const TYPE_VERSIONING = 'versioning'; + + protected $dispatcher; + protected $rootDir; + protected $container; + + /** + * @param EventDispatcher $dispatcher + * @param string $rootDir + * @param Container $container + */ + public function __construct(EventDispatcher $dispatcher, $rootDir, Container $container) + { + $this->dispatcher = $dispatcher; + $this->rootDir = $rootDir; + $this->container = $container; + } + + public function server($name) + { + + } + + /** + * @param string|null $adapter + * @return ShellInterface + */ + public function shell($adapter = null) + { + return $this->protocol(self::TYPE_SHELL, $adapter ?: $this->getDefaultShellAdapter()); + } + + /** + * @param string|null $adapter + * @return FilesInterface + */ + public function files($adapter = null) + { + return $this->protocol(self::TYPE_FILES, $adapter ?: $this->getDefaultFilesAdapter()); + } + + /** + * @param string $adapter + * @return VersioningInterface + */ + public function versioning($adapter) + { + return $this->protocol(self::TYPE_VERSIONING, $adapter); + } + + /** + * @param string $serverName + * @return ProtocolProxy + */ + public function proxy($serverName) + { + $server = $this->server($serverName); + $shell = $this->shell($server->getShellAdapter()); + $files = $this->files($server->getFilesAdapter()); + $versioning = $this->versioning($server->getVersioningAdapter()); + + return new ProtocolProxy($server, $shell, $files, $versioning); + } + + /** + * @param string $type + * @param string $adapter + * @return ProtocolInterface + */ + protected function protocol($type, $adapter) + { + $class = $this->container->getParameter(sprintf('be_simple_deployment.%s.%s.class', $type, $adapter)); + + return new $class($this->dispatcher, $this->rootDir); + } + + protected function getDefaultShellAdapter() + { + if (function_exists('shell2_connect')) { + return 'shell2'; + } + + return 'shell_process'; + } + + protected function getDefaultFilesAdapter() + { + return 'ftp'; + } +} diff --git a/Protocol/ProtocolProxy.php b/Protocol/ProtocolProxy.php new file mode 100644 index 0000000..917aec7 --- /dev/null +++ b/Protocol/ProtocolProxy.php @@ -0,0 +1,73 @@ + + */ +class ProtocolProxy +{ + protected $server; + protected $shell; + protected $files; + protected $versioning; + + /** + * @param Server $server + * @param ShellInterface $shell + * @param FilesInterface|null $files + * @param VersioningInterface|null $versioning + */ + public function __construct(Server $server, ShellInterface $shell, FilesInterface $files = null, VersioningInterface $versioning = null) + { + $this->server = $server; + $this->shell = $shell; + $this->files = $files; + $this->versioning = $versioning; + } + + /** + * @param Commands $commands + * @return boolean + */ + public function execute(Commands $commands) + { + return $this->shell->execute($this->server, $commands); + } + + /** + * @param Deployment $deployment + * @return boolean + * @throw AvailabilityException + */ + public function transfert(Transfert $transfert) + { + if (is_null($this->files)) { + throw new AvailabilityException('Files transfert', $this->server); + } + + return $this->files->transfert($this->server, $transfert); + } + + /** + * @param string $source + * @return boolean + * @throw AvailabilityException + */ + public function checkout($source) + { + if (is_null($this->versioning)) { + throw new AvailabilityException('Versioning', $this->server); + } + + return $this->versioning->checkout($this->server, $source); + } +} From fff9688aa770c51e91e12c372544e65843e5525d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Sat, 23 Jul 2011 09:53:28 +0200 Subject: [PATCH 9/9] added transfert model --- Model/Transfert.php | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Model/Transfert.php b/Model/Transfert.php index dbb3be5..afcabe1 100644 --- a/Model/Transfert.php +++ b/Model/Transfert.php @@ -2,9 +2,83 @@ namespace BeSimple\DeploymentBundle\Model; +use Symfony\Component\Finder\Finder; + /** * @author: Jean-François Simon */ class Transfert { + /** + * @var string + */ + protected $rootDir; + + /** + * @var array + */ + protected $ignore; + + /** + * @param string $rootDir + */ + public function __construct($rootDir) + { + $this->rootDir = $rootDir; + $this->ignore = array(); + } + + /** + * @return Finder + */ + public function getFinder(Finder $finder = null) + { + $finder = $finder ?: new Finder(); + + foreach ($this->ignore as $pattern) { + $finder->notName($pattern); + } + + return $finder->in($this->rootDir); + } + + /** + * @param string $pattern + */ + public function addIgnore($pattern) + { + $this->ignore[] = $pattern; + } + + /** + * @param array $ignore + */ + public function setIgnore(array $ignore) + { + $this->ignore = $ignore; + } + + /** + * @return array + */ + public function getIgnore() + { + return $this->ignore; + } + + /** + * @param string $rootDir + */ + public function setRootDir($rootDir) + { + $this->rootDir = $rootDir; + } + + /** + * @return string + */ + public function getRootDir() + { + return $this->rootDir; + } }