Skip to content
This repository has been archived by the owner on Oct 2, 2022. It is now read-only.

Rollback functionality and optionally logging revision activity to the database #53

Open
wants to merge 7 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
104 changes: 98 additions & 6 deletions DBV.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,60 @@ public function revisionsAction()
}
}

public function jumptoAction(){

$final_revision = isset($_POST['revision']) ? intval($_POST['revision']) : 0;
$current_revision = $this->_getCurrentRevision();
$revisions = $this->_getRevisions();

foreach($revisions as $revision){

//move forward
if($revision > $current_revision && $revision <= $final_revision){

$files = $this->_getRevisionFiles($revision);
if (count($files)) {
foreach ($files as $file) {
$file = DBV_REVISIONS_PATH . DS . $revision . DS . $file;
if (!$this->_runFile($file)) {
break 2;
}
}
}

//rollback
}elseif($revision <= $current_revision && $revision > $final_revision){

$files = $this->_getRevisionRollbackFiles($revision);

if (count($files)) {
foreach ($files as $file) {
$file = DBV_REVISIONS_PATH . DS . $revision . DS . 'rollback' . DS . $file;
if (!$this->_runFile($file)) {
break 2;
}
}
}
}
}

$this->_setCurrentRevision($final_revision);

$this->confirm(__("Jumped to revision #{revision}", array('revision' => "<strong>$final_revision</strong>")));
if ($this->_isXMLHttpRequest()) {
$return = array(
'messages' => array(),
'revision' => $this->_getCurrentRevision()
);
foreach ($this->_log as $message) {
$return['messages'][$message['type']][] = $message['message'];
}
$this->_json($return);

} else {
$this->indexAction();
}
}

public function saveRevisionFileAction()
{
Expand Down Expand Up @@ -332,18 +386,28 @@ protected function _getRevisions()

protected function _getCurrentRevision()
{
$file = DBV_META_PATH . DS . 'revision';
if (file_exists($file)) {
return intval(file_get_contents($file));
if(DB_REVISION_LOG){
return $this->_getAdapter()->getCurrentRevision();
}else{
$file = DBV_META_PATH . DS . 'revision';
if (file_exists($file)) {
return intval(file_get_contents($file));
}
}
return 0;
}

protected function _setCurrentRevision($revision)
{
$file = DBV_META_PATH . DS . 'revision';
if (!@file_put_contents($file, $revision)) {
$this->error("Cannot write revision file");

if(DB_REVISION_LOG){
$commit = ($_POST['commit'])? $_POST['commit'] : 'NULL';
$this->_getAdapter()->setRevision($revision, $commit);
}else{
$file = DBV_META_PATH . DS . 'revision';
if (!@file_put_contents($file, $revision)) {
$this->error("Cannot write revision file");
}
}
}

Expand All @@ -362,6 +426,21 @@ protected function _getRevisionFiles($revision)
return $return;
}

protected function _getRevisionRollbackFiles($revision)
{
$dir = DBV_REVISIONS_PATH . DS . $revision . DS . 'rollback';
$return = array();

foreach (new DirectoryIterator($dir) as $file) {
if ($file->isFile() && pathinfo($file->getFilename(), PATHINFO_EXTENSION) == 'sql') {
$return[] = $file->getBasename();
}
}

sort($return, SORT_REGULAR);
return $return;
}

protected function _getRevisionFileContents($revision, $file)
{
$path = DBV_REVISIONS_PATH . DS . $revision . DS . $file;
Expand All @@ -372,6 +451,19 @@ protected function _getRevisionFileContents($revision, $file)
return false;
}

public function findRevisionFromCommit($commit){

if(DB_REVISION_LOG && $commit){
return $this->_getAdapter()->getRevision($commit);
}else{
$this->error("You can only find revisions if you save them to the database.");
}
}

public function findLastRevision(){
return array_shift($this->_getRevisions());
}

public function log($item)
{
$this->_log[] = $item;
Expand Down
44 changes: 44 additions & 0 deletions cl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/**
* Call this file from the command line to jump to specific revision.
* Specify 'last' as its first argument to jump to the last revision.
* You can optionally specify the current commit, example:
* $ php cl.php last 53f03e596f2ce6517d4c91e4fa379e6bbf37ca4c
*
* Or specify 'rev' as a first argument and a specific revision as the second, example:
* $ php cl.php rev 4
*
* Or specify 'commit' as the first argument and a commit as the second to jump to the associated revision.
* This only works if you have the db log enabled, example:
* $ php cl.php commit 53f03e596f2ce6517d4c91e4fa379e6bbf37ca4c
*/


require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.php';
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'lib/functions.php';
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'DBV.php';

$_GET['a'] = 'jumpto';
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';

$dbv = DBV::instance();

if($argv[1] === 'last'){
$_POST['revision'] = $dbv->findLastRevision();
$_POST['commit'] = $argv[2];
}elseif($argv[1] === 'rev' && $argv[2]){
$_POST['revision'] = $argv[2];
}elseif($argv[1] === 'commit' && $argv[2]){
$rev = $dbv->findRevisionFromCommit($argv[2]);
if($rev){
$_POST['revision'] = $rev;
}else{
die('Could not find revision');
}
}else{
die("No valid arguments found. Please use 'last', 'rev' or 'commit'");
}

$dbv->authenticate();
$dbv->dispatch();
6 changes: 6 additions & 0 deletions config.php.sample
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ define('DB_ADAPTER', 'MySQL');
define('DS', DIRECTORY_SEPARATOR);
define('DBV_ROOT_PATH', dirname(__FILE__));

/**
* Use db for keeping track of current revision in the database and specify the table
*/
define('DB_REVISION_LOG', true);
define('DB_REVISION_TABLE', 'dbv_revisions');

/**
* Only edit this lines if you want to place your schema files in custom locations
* @see http://dbv.vizuina.com/documentation/#optional-settings
Expand Down
6 changes: 6 additions & 0 deletions install.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE `dbv_revisions` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`commit` varchar(255) DEFAULT NULL,
`revision` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
13 changes: 13 additions & 0 deletions lib/adapters/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,17 @@ public function getSchemaObject($name)
return $return;
}

public function getCurrentRevision(){
$result = $this->query("SELECT revision FROM " . DB_REVISION_TABLE . " ORDER BY id DESC LIMIT 1")->fetchColumn();
return ($result)? (int) $result : 0;
}

public function getRevision($commit){
$result = $this->query("SELECT revision FROM " . DB_REVISION_TABLE . " WHERE commit='" . $commit . "' ORDER BY id DESC LIMIT 1")->fetchColumn();
return ($result)? (int) $result : false;
}

public function setRevision($revision, $commit){
$this->query("INSERT INTO " . DB_REVISION_TABLE . " (commit, revision) VALUES ('" . $commit . "'," . $revision . ")");
}
}
14 changes: 14 additions & 0 deletions templates/revisions.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@
</table>
<input type="submit" class="btn btn-primary" value="Run selected revisions" />
</form>
<br/>
<h2><?php echo __('Jump to a specific revision (or rollback)'); ?></h2>
<p> If you select a revision lower then the current one it will run the rollback script for every revision inbetween the current and the selected revision.
Place your rollback script in a folder 'rollback' within the revision folder. All scripts within that folder will be run.</p>
<form method="post" action="index.php?a=jumpto" class="nomargin" id="revisions">
<select name="revision">
<?php foreach ($this->revisions as $revision): ?>
<option value="<?php echo $revision;?>" <?php echo ($this->revision == $revision)? 'selected' : ''?>>Revision <?php echo $revision;?></option>
<?php endforeach;?>
<option value="0">Revision 0</option>
</select>
<input type="submit" class="btn btn-primary" value="GO" />

</form>
<?php } else { ?>
<div class="alert alert-info nomargin">
<?php echo __('No revisions in #{path}', array('path' => '<strong>' . REVISIONS_PATH . '</strong>')) ?>
Expand Down