0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Export backup prior to migration

Closes #847
- Added logic to export database to the `core\server\data\` folder prior
to beginning a migration.
- Factored out versioning logic from migration to prevent circular
references
This commit is contained in:
William Dibbern 2014-05-31 18:53:21 -05:00
parent 664048be4e
commit 07df9911ce
5 changed files with 99 additions and 71 deletions

View file

@ -1,8 +1,8 @@
var when = require('when'),
_ = require('lodash'),
migration = require('../migration'),
knex = require('../../models/base').knex,
schema = require('../schema').tables,
var _ = require('lodash'),
when = require('when'),
versioning = require('../versioning'),
knex = require('../../models/base').knex,
schema = require('../schema').tables,
excludedTables = ['sessions'],
exporter;
@ -10,7 +10,7 @@ var when = require('when'),
exporter = function () {
var tablesToExport = _.keys(schema);
return when.join(migration.getDatabaseVersion(), tablesToExport).then(function (results) {
return when.join(versioning.getDatabaseVersion(), tablesToExport).then(function (results) {
var version = results[0],
tables = results[1],
selectOps = _.map(tables, function (name) {

View file

@ -1,18 +1,20 @@
var _ = require('lodash'),
when = require('when'),
path = require('path'),
fs = require('fs'),
nodefn = require('when/node/function'),
errors = require('../../errors'),
client = require('../../models/base').client,
knex = require('../../models/base').knex,
sequence = require('when/sequence'),
defaultSettings = require('../default-settings'),
versioning = require('../versioning'),
Settings = require('../../models/settings').Settings,
fixtures = require('../fixtures'),
schema = require('../schema').tables,
dataExport = require('../export'),
initialVersion = '000',
schemaTables = _.keys(schema),
defaultDatabaseVersion,
init,
reset,
@ -20,58 +22,6 @@ var _ = require('lodash'),
migrateUpFreshDb,
getTables;
// Default Database Version
// The migration version number according to the hardcoded default settings
// This is the version the database should be at or migrated to
function getDefaultDatabaseVersion() {
if (!defaultDatabaseVersion) {
// This be the current version according to the software
defaultDatabaseVersion = _.find(defaultSettings.core, function (setting) {
return setting.key === 'databaseVersion';
}).defaultValue;
}
return defaultDatabaseVersion;
}
// Database Current Version
// The migration version number according to the database
// This is what the database is currently at and may need to be updated
function getDatabaseVersion() {
return knex.schema.hasTable('settings').then(function (exists) {
// Check for the current version from the settings table
if (exists) {
// Temporary code to deal with old databases with currentVersion settings
return knex('settings')
.where('key', 'databaseVersion')
.orWhere('key', 'currentVersion')
.select('value')
.then(function (versions) {
var databaseVersion = _.reduce(versions, function (memo, version) {
if (isNaN(version.value)) {
errors.throwError('Database version is not recognised');
}
return parseInt(version.value, 10) > parseInt(memo, 10) ? version.value : memo;
}, initialVersion);
if (!databaseVersion || databaseVersion.length === 0) {
// we didn't get a response we understood, assume initialVersion
databaseVersion = initialVersion;
}
return databaseVersion;
});
}
throw new Error('Settings table does not exist');
});
}
function setDatabaseVersion() {
return knex('settings')
.where('key', 'databaseVersion')
.update({ 'value': defaultDatabaseVersion });
}
function createTable(table) {
return knex.schema.createTable(table, function (t) {
var column,
@ -168,8 +118,8 @@ init = function () {
// 2. The database exists but is out of date
// 3. The database exists but the currentVersion setting does not or cannot be understood
// 4. The database has not yet been created
return getDatabaseVersion().then(function (databaseVersion) {
var defaultVersion = getDefaultDatabaseVersion();
return versioning.getDatabaseVersion().then(function (databaseVersion) {
var defaultVersion = versioning.getDefaultDatabaseVersion();
if (databaseVersion === defaultVersion) {
// 1. The database exists and is up-to-date
return when.resolve();
@ -179,7 +129,7 @@ init = function () {
// Migrate to latest version
return self.migrateUp().then(function () {
// Finally update the databases current version
return setDatabaseVersion();
return versioning.setDatabaseVersion();
});
}
if (databaseVersion > defaultVersion) {
@ -249,9 +199,20 @@ function checkMySQLPostTable() {
});
}
function backupDatabase() {
return dataExport().then(function (exportedData) {
// Save the exported data to the file system for download
var fileName = path.resolve(__dirname + '/../exported-' + (new Date().getTime()) + '.json');
return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData));
});
}
// Migrate from a specific version to the latest
migrateUp = function () {
return getTables().then(function (oldTables) {
return backupDatabase().then(function () {
return getTables();
}).then(function (oldTables) {
// if tables exist and client is mysqls check if posts table is okay
if (!_.isEmpty(oldTables) && client === 'mysql') {
return checkMySQLPostTable().then(function () {
@ -293,7 +254,6 @@ getTables = function () {
};
module.exports = {
getDatabaseVersion: getDatabaseVersion,
init: init,
reset: reset,
migrateUp: migrateUp,

View file

@ -0,0 +1,66 @@
var _ = require('lodash'),
errors = require('../../errors'),
knex = require('../../models/base').knex,
defaultSettings = require('../default-settings'),
initialVersion = '000',
defaultDatabaseVersion;
// Default Database Version
// The migration version number according to the hardcoded default settings
// This is the version the database should be at or migrated to
function getDefaultDatabaseVersion() {
if (!defaultDatabaseVersion) {
// This be the current version according to the software
defaultDatabaseVersion = _.find(defaultSettings.core, function (setting) {
return setting.key === 'databaseVersion';
}).defaultValue;
}
return defaultDatabaseVersion;
}
// Database Current Version
// The migration version number according to the database
// This is what the database is currently at and may need to be updated
function getDatabaseVersion() {
return knex.schema.hasTable('settings').then(function (exists) {
// Check for the current version from the settings table
if (exists) {
// Temporary code to deal with old databases with currentVersion settings
return knex('settings')
.where('key', 'databaseVersion')
.orWhere('key', 'currentVersion')
.select('value')
.then(function (versions) {
var databaseVersion = _.reduce(versions, function (memo, version) {
if (isNaN(version.value)) {
errors.throwError('Database version is not recognised');
}
return parseInt(version.value, 10) > parseInt(memo, 10) ? version.value : memo;
}, initialVersion);
if (!databaseVersion || databaseVersion.length === 0) {
// we didn't get a response we understood, assume initialVersion
databaseVersion = initialVersion;
}
return databaseVersion;
});
}
throw new Error('Settings table does not exist');
});
}
function setDatabaseVersion() {
return knex('settings')
.where('key', 'databaseVersion')
.update({ 'value': defaultDatabaseVersion });
}
module.exports = {
getDefaultDatabaseVersion: getDefaultDatabaseVersion,
getDatabaseVersion: getDatabaseVersion,
setDatabaseVersion: setDatabaseVersion
};

View file

@ -8,6 +8,7 @@ var testUtils = require('../utils'),
// Stuff we are testing
migration = require('../../server/data/migration'),
versioning = require('../../server/data/versioning'),
exporter = require('../../server/data/export'),
Settings = require('../../server/models/settings').Settings;
@ -39,7 +40,7 @@ describe("Exporter", function () {
it("exports data", function (done) {
// Stub migrations to return 000 as the current database version
var migrationStub = sandbox.stub(migration, "getDatabaseVersion", function () {
var versioningStub = sandbox.stub(versioning, "getDatabaseVersion", function () {
return when.resolve("003");
});
@ -61,7 +62,7 @@ describe("Exporter", function () {
// should not export sqlite data
should.not.exist(exportData.data.sqlite_sequence);
migrationStub.restore();
versioningStub.restore();
done();
}).catch(done);
});

View file

@ -8,8 +8,9 @@ var testUtils = require('../utils'),
errors = require('../../server/errors'),
// Stuff we are testing
knex = require("../../server/models/base").knex,
knex = require('../../server/models/base').knex,
migration = require('../../server/data/migration'),
versioning = require('../../server/data/versioning'),
exporter = require('../../server/data/export'),
importer = require('../../server/data/import'),
Importer000 = require('../../server/data/import/000'),
@ -113,7 +114,7 @@ describe("Import", function () {
it("imports data from 000", function (done) {
var exportData,
migrationStub = sandbox.stub(migration, "getDatabaseVersion", function () {
versioningStub = sandbox.stub(versioning, "getDatabaseVersion", function () {
return when.resolve("000");
});
@ -151,7 +152,7 @@ describe("Import", function () {
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
migrationStub.restore();
versioningStub.restore();
done();
}).catch(done);