Attached Files |
informative_colorized_deployment_script_report.patch [^] (16,807 bytes) 2012-02-16 03:34
[Show Content]
Index: units/admin/admin_events_handler.php
===================================================================
--- units/admin/admin_events_handler.php (revision 15111)
+++ units/admin/admin_events_handler.php (working copy)
@@ -1036,16 +1036,20 @@
*/
protected function OnDeploy(kEvent &$event)
{
- if ( isset($GLOBALS['argv']) ) {
- // command line invocation -> don't perform redirect
- $event->status = kEvent::erSTOP;
- }
-
$deployment_helper =& $this->Application->recallObject('DeploymentHelper');
/* @var $deployment_helper DeploymentHelper */
$deployment_helper->deployAll();
+ if ( $deployment_helper->isCommandLine ) {
+ // command line invocation -> don't render template
+ $event->status = kEvent::erSTOP;
+ }
+ else {
+ // browser invocation -> don't perform redirect
+ $event->redirect = false;
+ }
+
$event->SetRedirectParam('action_completed', 1);
}
@@ -1061,11 +1065,17 @@
$deployment_helper =& $this->Application->recallObject('DeploymentHelper');
/* @var $deployment_helper DeploymentHelper */
- if ( !$deployment_helper->deployAll(true) ) {
- $event->status = kEvent::erFAIL;
+ if ( $deployment_helper->deployAll(true) ) {
+ $this->Application->SetVar('action_completed', 1);
}
+
+ if ( $deployment_helper->isCommandLine ) {
+ // command line invocation -> don't render template
+ $event->status = kEvent::erSTOP;
+ }
else {
- $event->SetRedirectParam('action_completed', 1);
+ // browser invocation -> don't perform redirect
+ $event->redirect = false;
}
}
Index: units/helpers/deployment_helper.php
===================================================================
--- units/helpers/deployment_helper.php (revision 15111)
+++ units/helpers/deployment_helper.php (working copy)
@@ -16,36 +16,130 @@
class DeploymentHelper extends kHelper {
+ /**
+ * How many symbols from sql should be shown
+ */
+ const SQL_TRIM_LENGTH = 120;
+
+ /**
+ * Name of module, that is processed right now
+ *
+ * @var string
+ * @access private
+ */
private $moduleName = '';
+ /**
+ * List of sqls, associated with each revision (from project_upgrades.sql file)
+ *
+ * @var Array
+ * @access private
+ */
private $revisionSqls = Array ();
+ /**
+ * List of revision titles as user typed them (from project_upgrades.sql file)
+ * @var Array
+ */
+ private $revisionTitles = Array ();
+
+ /**
+ * Revision dependencies
+ *
+ * @var Array
+ * @access private
+ */
private $revisionDependencies = Array ();
+ /**
+ * Numbers of revisions, that were already applied
+ *
+ * @var Array
+ * @access private
+ */
private $appliedRevisions = Array ();
+ /**
+ * Don't change database, but only check syntax of project_upgrades.sql file and mark all revisions discovered as applied
+ *
+ * @var bool
+ * @access private
+ */
private $dryRun = false;
- private $lineEnding = PHP_EOL;
+ /**
+ * Remembers script invocation method
+ *
+ * @var bool
+ * @access public
+ */
+ public $isCommandLine = false;
+ /**
+ * IP Address of script invoker
+ *
+ * @var string
+ */
+ public $ip = '';
+
public function __construct()
{
parent::__construct();
set_time_limit(0);
ini_set('memory_limit', -1);
+
+ $this->isCommandLine = isset($GLOBALS['argv']) && count($GLOBALS['argv']);
+
+ if ( !$this->isCommandLine ) {
+ $this->ip = $_SERVER['REMOTE_ADDR'];
+ }
+ elseif ( isset($GLOBALS['argv'][3]) ) {
+ $this->ip = $GLOBALS['argv'][3];
+ }
}
+ /**
+ * Adds message to script execution log
+ *
+ * @param string $message
+ * @param bool $new_line
+ * @return void
+ * @access private
+ */
+ private function toLog($message, $new_line = true)
+ {
+ $log_file = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE) . '/project_upgrades.log';
+
+ $fp = fopen($log_file, 'a');
+ fwrite($fp, $message . ($new_line ? "\n" : ''));
+ fclose($fp);
+
+ chmod($log_file, 0666);
+ }
+
+ /**
+ * Loads already applied revisions list of current module
+ *
+ * @return void
+ * @access private
+ */
private function loadAppliedRevisions()
{
$sql = 'SELECT AppliedDBRevisions
FROM ' . TABLE_PREFIX . 'Modules
- WHERE Name = ' . $this->Conn->qstr( $this->moduleName );
+ WHERE Name = ' . $this->Conn->qstr($this->moduleName);
$revisions = $this->Conn->GetOne($sql);
$this->appliedRevisions = $revisions ? explode(',', $revisions) : Array ();
}
+ /**
+ * Saves applied revision numbers to current module record
+ *
+ * @return void
+ * @access private
+ */
private function saveAppliedRevisions()
{
// maybe optimize
@@ -58,13 +152,24 @@
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', '`Name` = ' . $this->Conn->qstr($this->moduleName));
}
+ /**
+ * Deploys changes from all installed modules
+ *
+ * @param bool $dry_run
+ * @return bool
+ * @access public
+ */
public function deployAll($dry_run = false)
{
- $this->dryRun = $dry_run;
- $this->lineEnding = $dry_run ? '<br/>' . PHP_EOL : PHP_EOL;
+ if ( !$this->isCommandLine ) {
+ echo '<pre style="font-size: 10pt; color: #BBB; background-color: black; border: 2px solid darkgreen; padding: 8px;">' . PHP_EOL;
+ }
$ret = true;
+ $this->dryRun = $dry_run;
+ $this->toLog(PHP_EOL . '[' . adodb_date('Y-m-d H:i:s') . '] === ' . $this->ip . ' ===');
+
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$this->moduleName = $module_name;
@@ -75,11 +180,15 @@
$ret = $ret && $this->deploy($module_name);
}
- if (!$this->dryRun) {
+ if ( $ret && !$this->dryRun ) {
$this->resetCaches();
$this->refreshThemes();
}
+ if ( !$this->isCommandLine ) {
+ echo '</pre>' . PHP_EOL;
+ }
+
return $ret;
}
@@ -92,25 +201,26 @@
*/
private function deploy($module_name)
{
- echo 'Deploying Module "' . $module_name . '":' . $this->lineEnding;
+ echo $this->colorText('Deploying Module "' . $module_name . '":', 'cyan', true) . PHP_EOL;
- echo 'Upgrading Database ... ';
if ( !$this->upgradeDatabase() ) {
return false;
}
- echo 'OK' . $this->lineEnding;
+ if ( !$this->dryRun ) {
+ $this->importLanguagePack();
+ }
- $this->importLanguagePack();
+ echo $this->colorText('Done with Module "' . $module_name . '".', 'green', true) . PHP_EOL . PHP_EOL;
- echo 'Done.' . $this->lineEnding;
-
return true;
}
/**
* Import latest languagepack (without overwrite)
*
+ * @return void
+ * @access private
*/
private function importLanguagePack()
{
@@ -120,12 +230,14 @@
echo 'Importing LanguagePack ... ';
$filename = $this->getModuleFile('english.lang');
$language_import_helper->performImport($filename, '|0|1|2|', $this->moduleName, LANG_SKIP_EXISTING);
- echo 'OK' . $this->lineEnding;
+ $this->displayStatus('OK');
}
/**
* Resets unit and section cache
*
+ * @return void
+ * @access private
*/
private function resetCaches()
{
@@ -133,41 +245,48 @@
echo 'Resetting Unit Config Cache ... ';
$admin_event = new kEvent('adm:OnResetConfigsCache');
$this->Application->HandleEvent($admin_event);
- echo 'OK' . $this->lineEnding;
+ $this->displayStatus('OK');
// 3. reset sections cache
echo 'Resetting Sections Cache ... ';
$admin_event = new kEvent('adm:OnResetSections');
$this->Application->HandleEvent($admin_event);
- echo 'OK' . $this->lineEnding;
+ $this->displayStatus('OK');
}
/**
* Rebuild theme files
*
+ * @return void
+ * @access private
*/
private function refreshThemes()
{
echo 'Rebuilding Theme Files ... ';
$admin_event = new kEvent('adm:OnRebuildThemes');
$this->Application->HandleEvent($admin_event);
- echo 'OK' . $this->lineEnding;
+ $this->displayStatus('OK');
}
/**
* Runs database upgrade script
*
* @return bool
+ * @access private
*/
private function upgradeDatabase()
{
$this->loadAppliedRevisions();
- $this->Conn->errorHandler = Array(&$this, 'handleSqlError');
+ $this->Conn->errorHandler = Array (&$this, 'handleSqlError');
+ echo 'Verifying Database Revisions ... ';
+
if ( !$this->collectDatabaseRevisions() || !$this->checkRevisionDependencies() ) {
return false;
}
+ $this->displayStatus('OK');
+
$applied = $this->applyRevisions();
$this->saveAppliedRevisions();
@@ -178,6 +297,7 @@
* Collects database revisions from "project_upgrades.sql" file.
*
* @return bool
+ * @access private
*/
private function collectDatabaseRevisions()
{
@@ -190,8 +310,8 @@
$sqls = file_get_contents($filename);
preg_match_all("/# r([\d]+)([^\:]*):.*?(\n|$)/s", $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
- if (!$matches) {
- echo 'No Database Revisions Found' . $this->lineEnding;
+ if ( !$matches ) {
+ $this->displayStatus('FAILED' . PHP_EOL . 'No Database Revisions Found');
return false;
}
@@ -206,7 +326,7 @@
if ( isset($this->revisionSqls[$revision]) ) {
// duplicate revision among non-applied ones
- echo 'Duplicate revision ' . $revision . ' found' . $this->lineEnding;
+ $this->displayStatus('FAILED' . PHP_EOL . 'Duplicate revision #' . $revision . ' found');
return false;
}
@@ -216,15 +336,16 @@
$end_pos = isset($matches[$index + 1]) ? $matches[$index + 1][0][1] : strlen($sqls);
$revision_sqls = substr($sqls, $start_pos, $end_pos - $start_pos);
- if (!$revision_sqls) {
+ if ( !$revision_sqls ) {
// resision without sqls
continue;
}
+ $this->revisionTitles[$revision] = trim($match[0][0]);
$this->revisionSqls[$revision] = $revision_sqls;
$revision_lependencies = $this->parseRevisionDependencies($match[2][0]);
- if ($revision_lependencies) {
+ if ( $revision_lependencies ) {
$this->revisionDependencies[$revision] = $revision_lependencies;
}
}
@@ -239,6 +360,7 @@
* Checks that all dependent revisions are either present now OR were applied before
*
* @return bool
+ * @access private
*/
private function checkRevisionDependencies()
{
@@ -249,14 +371,14 @@
continue;
}
- if ($revision_dependency >= $revision) {
- echo 'Revision ' . $revision . ' has incorrect dependency to revision ' . $revision_dependency . '. Only dependencies to older revisions are allowed!' . $this->lineEnding;
+ if ( $revision_dependency >= $revision ) {
+ $this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' has incorrect dependency to revision #' . $revision_dependency . '. Only dependencies to older revisions are allowed!');
return false;
}
if ( !isset($this->revisionSqls[$revision_dependency]) ) {
- echo 'Revision ' . $revision . ' depends on missing revision ' . $revision_dependency . '!' . $this->lineEnding;
+ $this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' depends on missing revision #' . $revision_dependency . '!');
return false;
}
@@ -270,49 +392,61 @@
* Runs all pending sqls
*
* @return bool
+ * @access private
*/
private function applyRevisions()
{
- if (!$this->revisionSqls) {
+ if ( !$this->revisionSqls ) {
return true;
}
- if ($this->dryRun) {
+ if ( $this->dryRun ) {
$this->appliedRevisions = array_merge($this->appliedRevisions, array_keys($this->revisionSqls));
return true;
}
- echo $this->lineEnding;
+ echo 'Upgrading Database ... ' . PHP_EOL;
foreach ($this->revisionSqls as $revision => $sqls) {
- echo 'Processing DB Revision: #' . $revision . ' ... ';
+ echo PHP_EOL . $this->colorText($this->revisionTitles[$revision], 'gray', true) . PHP_EOL; // 'Processing DB Revision: #' . $revision . ' ... ';
- $sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
- $no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", '', $sqls); // remove all comments "#" on new lines
+ $sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
+ $no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", "# \\1;\n", $sqls); // add ";" to each comment end to ensure correct split
$sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
- foreach ($sqls as $index => $sql) {
- if (!$sql || (substr($sql, 0, 1) == '#')) {
- continue; // usually last line
+ foreach ($sqls as $sql) {
+ $this->toLog($sql);
+
+ if ( substr($sql, 0, 1) == '#' ) {
+ // output comment as is
+ echo $this->colorText($sql, 'purple') . PHP_EOL;
+ continue;
}
+ elseif ( $sql ) {
+ echo mb_substr(trim(preg_replace('/(\n|\t| )+/is', ' ', $sql)), 0, self::SQL_TRIM_LENGTH) . ' ... ';
- $this->Conn->Query($sql);
+ $this->Conn->Query($sql);
- if ( $this->Conn->hasError() ) {
- // consider revisions with errors applied
- $this->appliedRevisions[] = $revision;
+ if ( $this->Conn->hasError() ) {
+ // consider revisions with errors applied
+ $this->appliedRevisions[] = $revision;
- return false;
- }
+ return false;
+ }
+ else {
+ $this->displayStatus('OK');
+ }
+ }
}
$this->appliedRevisions[] = $revision;
- echo 'OK' . $this->lineEnding;
}
+ echo PHP_EOL;
+
return true;
}
@@ -323,12 +457,15 @@
* @param string $msg
* @param string $sql
* @return bool
+ * @access public
*/
public function handleSqlError($code, $msg, $sql)
{
- echo 'Error (#' . $code . ': ' . $msg . ') during SQL processing:' . $this->lineEnding . $sql . $this->lineEnding;
- echo 'Please execute rest of sqls in this revision by hand and run deployment script again.' . $this->lineEnding;
+ $this->toLog('SQL Error #' . $code . ': ' . $msg);
+ $this->displayStatus('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg);
+ echo 'Please execute rest of SQLs in this Revision by hand and run deployment script again.' . PHP_EOL;
+
return true;
}
@@ -337,6 +474,7 @@
*
* @param int $revision
* @return bool
+ * @access private
*/
private function revisionApplied($revision)
{
@@ -362,6 +500,7 @@
*
* @param string $filename
* @return string
+ * @access private
*/
private function getModuleFile($filename)
{
@@ -375,10 +514,11 @@
*
* @param string $string
* @return Array
+ * @access private
*/
private function parseRevisionDependencies($string)
{
- if (!$string) {
+ if ( !$string ) {
return Array ();
}
@@ -386,4 +526,81 @@
return array_map('trim', $string);
}
+
+ /**
+ * Applies requested color and bold attributes to given text string
+ *
+ * @param string $text
+ * @param string $color
+ * @param bool $bold
+ * @return string
+ * @access private
+ */
+ private function colorText($text, $color, $bold = false)
+ {
+ if ( $this->isCommandLine ) {
+ $color_map = Array (
+ 'black' => 30, // dark gray (in bold)
+ 'blue' => 34, // light blue (in bold)
+ 'green' => 32, // light green (in bold)
+ 'cyan' => 36, // light cyan (in bold)
+ 'red' => 31, // light red (in bold)
+ 'purple' => 35, // light purple (in bold)
+ 'brown' => 33, // yellow (in bold)
+ 'gray' => 37, // white (in bold)
+ );
+
+ return "\033[" . ($bold ? 1 : 0) . ";" . $color_map[$color] . "m" . $text . "\033[0m";
+ }
+
+ $html_color_map = Array (
+ 'black' => Array ('normal' => '#000000', 'bold' => '#666666'),
+ 'blue' => Array ('normal' => '#00009C', 'bold' => '#3C3CFF'),
+ 'green' => Array ('normal' => '#009000', 'bold' => '#00FF00'),
+ 'cyan' => Array ('normal' => '#009C9C', 'bold' => '#00FFFF'),
+ 'red' => Array ('normal' => '#9C0000', 'bold' => '#FF0000'),
+ 'purple' => Array ('normal' => '#900090', 'bold' => '#F99CF9'),
+ 'brown' => Array ('normal' => '#C9C909', 'bold' => '#FFFF00'),
+ 'gray' => Array ('normal' => '#909090', 'bold' => '#FFFFFF'),
+ );
+
+ $html_color = $html_color_map[$color][$bold ? 'bold' : 'normal'];
+
+ return '<span style="color: ' . $html_color . '">' . $text . '</span>';
+ }
+
+ /**
+ * Makes given text bold
+ *
+ * @param string $text
+ * @return string
+ * @access private
+ */
+ private function boldText($text)
+ {
+ if ( $this->isCommandLine ) {
+ return "\033[1m" . $text . "\033[0m";
+ }
+
+ return '<strong>' . $text . '</strong>';
+ }
+
+ /**
+ * Displays last command execution status
+ *
+ * @param string $status_text
+ * @param bool $new_line
+ * @return void
+ * @access private
+ */
+ private function displayStatus($status_text, $new_line = true)
+ {
+ $color = substr($status_text, 0, 2) == 'OK' ? 'green' : 'red';
+
+ echo $this->colorText($status_text, $color, false);
+
+ if ( $new_line ) {
+ echo PHP_EOL;
+ }
+ }
}
\ No newline at end of file
deployment_script_web_output.png [^] (132,686 bytes) 2012-02-16 03:41

deployment_script_display_affected_row_count.patch [^] (380 bytes) 2012-02-20 13:10
[Show Content]
Index: deployment_helper.php
===================================================================
--- deployment_helper.php (revision 15112)
+++ deployment_helper.php (working copy)
@@ -437,7 +437,7 @@
return false;
}
else {
- $this->displayStatus('OK');
+ $this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')');
}
}
}
deployment_script_display_affected_row_count_log.patch [^] (1,354 bytes) 2012-02-22 02:45
[Show Content]
Index: units/helpers/deployment_helper.php
===================================================================
--- units/helpers/deployment_helper.php (revision 15117)
+++ units/helpers/deployment_helper.php (working copy)
@@ -418,14 +418,14 @@
$sqls = array_map('trim', $sqls);
foreach ($sqls as $sql) {
- $this->toLog($sql);
-
if ( substr($sql, 0, 1) == '#' ) {
// output comment as is
+ $this->toLog($sql);
echo $this->colorText($sql, 'purple') . PHP_EOL;
continue;
}
elseif ( $sql ) {
+ $this->toLog($sql . ' ... ', false);
echo mb_substr(trim(preg_replace('/(\n|\t| )+/is', ' ', $sql)), 0, self::SQL_TRIM_LENGTH) . ' ... ';
$this->Conn->Query($sql);
@@ -437,6 +437,7 @@
return false;
}
else {
+ $this->toLog('OK (' . $this->Conn->getAffectedRows() . ')');
$this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')');
}
}
@@ -461,7 +462,7 @@
*/
public function handleSqlError($code, $msg, $sql)
{
- $this->toLog('SQL Error #' . $code . ': ' . $msg);
+ $this->toLog('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg);
$this->displayStatus('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg);
echo 'Please execute rest of SQLs in this Revision by hand and run deployment script again.' . PHP_EOL;
|