Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] method based deployment #50

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ vendor
deploy
tests/test_release
.idea
_site
82 changes: 45 additions & 37 deletions lib/Pomander.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static function version()
// phake helpers
function builder()
{
if(!isset(Builder::$global)) Builder::$global = new Builder;
if (!isset(Builder::$global)) Builder::$global = new Builder;

return Builder::$global;
}
Expand All @@ -27,7 +27,7 @@ function task()
{
$deps = func_get_args();
$name = array_shift($deps);
if($deps[count($deps) - 1] instanceof Closure)
if ($deps[count($deps) - 1] instanceof Closure)
$work = array_pop($deps);
else
$work = null;
Expand All @@ -54,23 +54,28 @@ function after($task, $lambda) { builder()->after($task, $lambda); }
function desc($description) { builder()->desc($description); }

//utils
function info($status,$msg)
function info($status, $msg, $output = true)
{
puts(" * ".ansicolor("info ",32).ansicolor("$status ",35).$msg);
$line = " * " . ansicolor("info ", 32) . ansicolor("$status ", 35) . $msg;
return $output? puts($line) : "echo \"$line\"";
}

function warn($status,$msg)
function warn($status, $msg, $output = true)
{
puts(" * ".ansicolor("warn ",33).ansicolor("$status ",35).$msg);
$line = " * " . ansicolor("warn ", 33) . ansicolor("$status ", 35) . $msg;
return $output? puts($line) : "echo \"$line\"";
}

function abort($status, $msg, $code=1)
function abort($status, $msg, $code=1, $output = true)
{
puts(" * ".ansicolor("abort ",31).ansicolor("$status ",35).$msg);
$line = " * " . ansicolor("abort ", 31) . ansicolor("$status ", 35) . $msg;
if( !$output ) return "echo \"$line\" && false";

puts($line);
die($code);
}

function ansicolor($text,$color)
function ansicolor($text, $color)
{
#31 red
#32 green
Expand All @@ -85,62 +90,65 @@ function puts($text) { echo $text.PHP_EOL; }
function home()
{
$app = builder()->get_application();
if(!isset($app->home))
$app->home = trim(shell_exec("cd && pwd"),"\r\n");
if (!isset($app->home)) $app->home = trim(shell_exec('cd && pwd'), "\r\n");

return $app->home;
}

function run()
{
$cmd = array();
$silent = false;
$args = func_get_args();
if(is_bool($args[count($args)-1])) $silent = array_pop($args);
$silent = is_bool($args[count($args)-1])? array_pop($args) : false;
array_walk_recursive($args, function ($v) use (&$cmd) { $cmd[] = $v; });
$cmd = implode(" && ",$cmd);
$cmd = implode(' && ', $cmd);
if (empty($cmd)) return;
$app = builder()->get_application();

list($status, $output) = !isset($app->env)? run_local($cmd) : $app->env->exec($cmd);
if(!$silent && count($output)) puts(implode("\n", $output));

if ($status > 0) {
if ($app->can_rollback) {
warn("fail","Rolling back...");
$app->invoke('rollback');
info("rollback","rollback complete.");
exit($status);

return;
}
abort("fail","aborted!",$status);
}
if (!$silent && count($output)) puts(implode("\n", $output));

check_rollback($status);

return $output;
}

function run_local($cmd)
{
$cmd = is_array($cmd)? implode(" && ",$cmd) : $cmd;
$cmd = is_array($cmd)? implode(" && ", $cmd) : $cmd;
exec($cmd, $output, $status);

return array($status, $output);
}

// Deprecated: use run_local()
function exec_cmd($cmd)
function exec_cmd($cmd) { return run_local($cmd); }

function put($what, $where)
{
return run_local($cmd);
$app = builder()->get_application();
list($status, $output) = isset($app->env)? $app->env->put($what, $where) : run_local("cp -R $what $where");
check_rollback($status);
}

function put($what,$where)
function get($what, $where)
{
if(!isset(builder()->get_application()->env)) return run_local("cp -R $what $where");
builder()->get_application()->env->put($what,$where);
$app = builder()->get_application();
list($status, $output) = isset($app->env)? $app->env->get($what, $where) : run_local("cp -R $what $where");
check_rollback($status);
}

function get($what,$where)
{
if(!isset(builder()->get_application()->env)) return run_local("cp -R $what $where");
builder()->get_application()->env->get($what,$where);
function check_rollback($status) {
if ($status < 1) return;
$app = builder()->get_application();

if ($app->can_rollback) {
warn("fail", "Rolling back...");
$app->invoke('rollback');
info("rollback", "rollback complete.");
exit($status);

return;
}
abort("fail", "aborted!", $status);
}
15 changes: 8 additions & 7 deletions lib/Pomander/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class Environment
{
public $name, $target, $scm, $adapter;
public $name, $target, $method, $adapter;
private $config, $shell, $mysql;
private $roles;

Expand Down Expand Up @@ -45,7 +45,7 @@ public function setup()
$this->shared_dir = $this->deploy_to.'/shared';
$this->cache_dir = $this->shared_dir.'/cached_copy';
}
$this->init_scm_adapter();
$this->init_method_adapter();
}

public function __call($name, $arguments)
Expand Down Expand Up @@ -160,7 +160,6 @@ private function defaults()
"app"=>"",
"db"=>"",
"method"=>"git",
"scm"=>"git",
"adapter"=>"mysql",
"port"=>22,
"umask"=>"002",
Expand Down Expand Up @@ -188,11 +187,13 @@ private function update_target($target)
return true;
}

private function init_scm_adapter()
private function init_method_adapter()
{
$scm = "\\Pomander\\Scm\\".ucwords(strtolower($this->config["scm"]));
if( !$this->scm = new $scm($this->repository) )
abort("scm","There is no recipe for {$this->config["scm"]}, perhaps create your own?");
$method = $this->config["method"];
if( empty($this->config["method"]) && isset($this->config["scm"]) ) $method = $this->config["scm"];
$method = "\\Pomander\\Method\\".ucwords(strtolower($method));
if( !$this->method = new $method($this->repository) )
abort("method","There is no recipe for {$this->config["method"]}, perhaps create your own?");
$adapter = "\\Pomander\\Db\\".ucwords(strtolower($this->config["adapter"]));
if( !$this->adapter = new $adapter($this->database) )
abort("db","There is no recipe for {$this->config["adapter"]}, perhaps create your own?");
Expand Down
176 changes: 176 additions & 0 deletions lib/Pomander/Method.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<?php
namespace Pomander;

abstract class Method
{
public $repository, $app;

public function __construct($repository)
{
$this->repository = $repository;
$this->app = builder()->get_application();
}

/**
* @return string|array
*/
public function setup()
{
$env = $this->app->env;
if ($env->releases === false) {
$dir = $env->deploy_to;
$setup = "rm -rf \"$dir\" && {$this->setup_code($dir)}";
} else {
$dir = $env->current_dir;
$setup = "mkdir -p \"{$env->deploy_to}\" \"{$env->releases_dir}\" \"{$env->shared_dir}\"";
if ($env->remote_cache === true) $setup .= ' && ' . $this->setup_code($env->cache_dir);
}

return array(
"umask {$env->umask}",
"[ -e \"$dir\" ] && ( "
. abort("setup", "application has already been setup.", 1, false)
. " ) || ( $setup )"
);
}

/**
* @return string|array
*/
public function deploy()
{
$env = $this->app->env;
if ($env->releases === false) {
$dir = $env->deploy_to;
$deploy = "{$this->version()} > VERSION && {$this->update_code()}";
} else {
$env->release_dir = $env->releases_dir.'/'.$env->new_release();
if ($env->remote_cache === true) {
$dir = $env->cache_dir;
$deploy = "{$this->update_code()} && cp -R \"{$env->cache_dir}\" \"{$env->release_dir}\"";
} else {
$dir = $env->release_dir;
$deploy = $this->setup_code();
}
}

return array(
"cd \"$dir\"",
"( $deploy ) || ( "
. abort("deploy", "deploy folder not accessible. try running deploy:setup or deploy:cold first.", 1, false)
. " )"
);
}

/**
* @return string|array
*/
public function finalize()
{
$env = $this->app->env;
//if ($env->backup === false) $cmd[] = "rm -rf {$env->shared_dir}/backup/{$env->merged}";
if ($env->releases === false) return;

return array(
"cd \"{$env->releases_dir}\"",
"current=`ls -1t | head -n 1`",
"ln -nfs \"{$env->releases_dir}/\$current\" \"{$env->current_dir}\""
);
}

/**
* @return string|array
*/
public function cleanup()
{
$env = $this->app->env;
if($env->releases === false) return;
if($env->keep_releases === false) return;
$keep = max(1, $env->keep_releases);

info('deploy', "cleaning up old releases");

return array(
"cd \"{$env->releases_dir}\"",
"count=`ls -1t | wc -l`",
"old=$((count > {$keep} ? count - {$keep} : 0))",
"ls -1t | tail -n \$old | xargs rm -rf {}"
);
}

/**
* @return string|array
*/
public function rollback()
{
$env = $this->app->env;
if ($env->releases === false) {
$version = run(array(
"[ -e \"{$env->release_dir}/VERSION\" ]",
"(cat \"{$env->release_dir}/VERSION\") &>/dev/null"
), true);
if (!count($version) || empty($version[0])) {
abort('rollback', "no releases to roll back to");
}

$env->revision = $version[0];
return $this->update_code();
}

$rollback_to = isset($this->app['releases'])? $this->app['releases'] : 2;
$rollback = array();

if ($env->release_dir !== $env->current_dir) {
// remove broken release
info('rollback', "removing failed release.");
$rollback[] = info('rollback', "removing failed release.", false);
$rollback[] = "rm -rf \"{$env->release_dir}\"";
}

$rollback[] = info('rollback', "pointing to previous release.", false);
$rollback[] = "ln -nfs \"{$env->releases_dir}/\$previous\" \"{$env->current_dir}\"";
$rollback = implode(' && ', $rollback);

/*if($app->env->merged)
{
info("rollback", "restoring database to before merge.");
$backup = "{$app->env->shared_dir}/backup/{$app->env->merged}";
$cmd[] = $app->env->adapter->restore($backup);
if($app->env->backup === false) $cmd[] = "rm -rf $backup";
}*/

return array(
"count=`ls -1t \"{$env->releases_dir}\" | wc -l`",
"release=`ls -1t \"{$env->releases_dir}\" | head -n {$rollback_to} | tail -1`",
"([ -e \"{$env->releases_dir}/\$release\" ] && [ \$count -ge {$rollback_to} ] )",
"( $rollback ) || ( "
. abort('rollback', "no releases to roll back to", 1, false)
. " )"
);
}

/**
* @param $location
* @return string
*/
public function setup_code($location)
{
return "";
}

/**
* @return string
*/
public function update_code()
{
return "";
}

/**
* @return string
*/
public function version()
{
return "";
}
}
Loading