mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 13:54:35 +03:00
71a92194ca
closes #748 - Removed the alpha software warning - Better error message output for the whole app - can now specify an error, a context, and a help message - Improved invalid node version, start and stop messaging - Listens for Ctrl+C and exits nicely - Minor improvements to handling and errors with old DBs (temporary)
245 lines
8.5 KiB
JavaScript
245 lines
8.5 KiB
JavaScript
|
|
var _ = require('underscore'),
|
|
when = require('when'),
|
|
series = require('when/sequence'),
|
|
errors = require('../../errorHandling'),
|
|
knex = require('../../models/base').Knex,
|
|
|
|
defaultSettings = require('../default-settings'),
|
|
Settings = require('../../models/settings').Settings,
|
|
fixtures = require('../fixtures'),
|
|
|
|
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
|
|
// TODO: remove before release
|
|
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;
|
|
});
|
|
}
|
|
return when.reject('Settings table does not exist');
|
|
});
|
|
}
|
|
|
|
function setDatabaseVersion() {
|
|
return knex('settings')
|
|
.where('key', 'databaseVersion')
|
|
.update({ 'value': defaultDatabaseVersion });
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
// Check for whether data is needed to be bootstrapped or not
|
|
init: function () {
|
|
var self = this;
|
|
|
|
// There are 4 possibilities:
|
|
// 1. The database exists and is up-to-date
|
|
// 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();
|
|
|
|
if (databaseVersion === defaultVersion) {
|
|
// 1. The database exists and is up-to-date
|
|
return when.resolve();
|
|
}
|
|
|
|
if (databaseVersion < defaultVersion) {
|
|
// 2. The database exists but is out of date
|
|
return self.migrateUpFromVersion(databaseVersion);
|
|
}
|
|
|
|
if (databaseVersion > defaultVersion) {
|
|
// 3. The database exists but the currentVersion setting does not or cannot be understood
|
|
// In this case we don't understand the version because it is too high
|
|
errors.logErrorAndExit(
|
|
'Your database is not compatible with this version of Ghost',
|
|
'You will need to create a new database'
|
|
);
|
|
}
|
|
|
|
}, function (err) {
|
|
if (err === 'Settings table does not exist') {
|
|
// 4. The database has not yet been created
|
|
// Bring everything up from initial version.
|
|
return self.migrateUpFreshDb();
|
|
}
|
|
|
|
// 3. The database exists but the currentVersion setting does not or cannot be understood
|
|
// In this case the setting was missing or there was some other problem
|
|
errors.logErrorAndExit('There is a problem with the database', err.message || err);
|
|
});
|
|
},
|
|
|
|
// ### Reset
|
|
// Migrate from where we are down to nothing.
|
|
reset: function () {
|
|
var self = this;
|
|
|
|
return getDatabaseVersion().then(function (databaseVersion) {
|
|
// bring everything down from the current version
|
|
return self.migrateDownFromVersion(databaseVersion);
|
|
}, function () {
|
|
// If the settings table doesn't exist, bring everything down from initial version.
|
|
return self.migrateDownFromVersion(initialVersion);
|
|
});
|
|
},
|
|
|
|
// Only do this if we have no database at all
|
|
migrateUpFreshDb: function () {
|
|
var migration = require('./' + initialVersion);
|
|
|
|
return migration.up().then(function () {
|
|
// Load the fixtures
|
|
return fixtures.populateFixtures();
|
|
|
|
}).then(function () {
|
|
// Initialise the default settings
|
|
return Settings.populateDefaults();
|
|
});
|
|
},
|
|
|
|
// Migrate from a specific version to the latest
|
|
migrateUpFromVersion: function (version, max) {
|
|
var versions = [],
|
|
maxVersion = max || this.getVersionAfter(getDefaultDatabaseVersion()),
|
|
currVersion = version,
|
|
tasks = [];
|
|
|
|
// Aggregate all the versions we need to do migrations for
|
|
while (currVersion !== maxVersion) {
|
|
versions.push(currVersion);
|
|
currVersion = this.getVersionAfter(currVersion);
|
|
}
|
|
|
|
// Aggregate all the individual up calls to use in the series(...) below
|
|
tasks = _.map(versions, function (taskVersion) {
|
|
return function () {
|
|
try {
|
|
var migration = require('./' + taskVersion);
|
|
return migration.up();
|
|
} catch (e) {
|
|
errors.logError(e);
|
|
return when.reject(e);
|
|
}
|
|
};
|
|
});
|
|
|
|
// Run each migration in series
|
|
return series(tasks).then(function () {
|
|
// Finally update the databases current version
|
|
return setDatabaseVersion();
|
|
});
|
|
},
|
|
|
|
migrateDownFromVersion: function (version) {
|
|
var self = this,
|
|
versions = [],
|
|
minVersion = this.getVersionBefore(initialVersion),
|
|
currVersion = version,
|
|
tasks = [];
|
|
|
|
// Aggregate all the versions we need to do migrations for
|
|
while (currVersion !== minVersion) {
|
|
versions.push(currVersion);
|
|
currVersion = this.getVersionBefore(currVersion);
|
|
}
|
|
|
|
// Aggregate all the individual up calls to use in the series(...) below
|
|
tasks = _.map(versions, function (taskVersion) {
|
|
return function () {
|
|
try {
|
|
var migration = require('./' + taskVersion);
|
|
return migration.down();
|
|
} catch (e) {
|
|
errors.logError(e);
|
|
return self.migrateDownFromVersion(initialVersion);
|
|
}
|
|
};
|
|
});
|
|
|
|
// Run each migration in series
|
|
return series(tasks);
|
|
},
|
|
|
|
// Get the following version based on the current
|
|
getVersionAfter: function (currVersion) {
|
|
|
|
var currVersionNum = parseInt(currVersion, 10),
|
|
nextVersion;
|
|
|
|
// Default to initialVersion if not parsed
|
|
if (isNaN(currVersionNum)) {
|
|
currVersionNum = parseInt(initialVersion, 10);
|
|
}
|
|
|
|
currVersionNum += 1;
|
|
|
|
nextVersion = String(currVersionNum);
|
|
// Pad with 0's until 3 digits
|
|
while (nextVersion.length < 3) {
|
|
nextVersion = "0" + nextVersion;
|
|
}
|
|
|
|
return nextVersion;
|
|
},
|
|
|
|
getVersionBefore: function (currVersion) {
|
|
var currVersionNum = parseInt(currVersion, 10),
|
|
prevVersion;
|
|
|
|
if (isNaN(currVersionNum)) {
|
|
currVersionNum = parseInt(initialVersion, 10);
|
|
}
|
|
|
|
currVersionNum -= 1;
|
|
|
|
prevVersion = String(currVersionNum);
|
|
// Pad with 0's until 3 digits
|
|
while (prevVersion.length < 3) {
|
|
prevVersion = "0" + prevVersion;
|
|
}
|
|
|
|
return prevVersion;
|
|
}
|
|
}; |