111 lines
3.0 KiB
JavaScript
111 lines
3.0 KiB
JavaScript
const path = require('path');
|
|
const logger = require('hexo-log')();
|
|
|
|
class Version {
|
|
constructor(version) {
|
|
const ver = version.split('.').map(i => parseInt(i, 10));
|
|
if (ver.length !== 3) {
|
|
throw new Error('Malformed version number ' + version);
|
|
}
|
|
this.major = ver[0];
|
|
this.minor = ver[1];
|
|
this.patch = ver[2];
|
|
}
|
|
|
|
toString() {
|
|
return `${this.major}.${this.minor}.${this.patch}`;
|
|
}
|
|
}
|
|
|
|
Version.compare = function(a, b) {
|
|
if (!(a instanceof Version) || !(b instanceof Version)) {
|
|
throw new Error('Cannot compare non-Versions');
|
|
}
|
|
if (a.major !== b.major) {
|
|
return a.major - b.major;
|
|
}
|
|
if (a.minor !== b.minor) {
|
|
return a.minor - b.minor;
|
|
}
|
|
if (a.patch !== b.patch) {
|
|
return a.patch - b.patch;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
class Migration {
|
|
|
|
/**
|
|
* @param {string} version Target version
|
|
* @param {string} head File name of the previous migration
|
|
*/
|
|
constructor(version, head) {
|
|
this.version = new Version(version);
|
|
this.head = head;
|
|
}
|
|
|
|
doMigrate(config) {
|
|
throw new Error('Not implemented!');
|
|
}
|
|
|
|
migrate(config) {
|
|
logger.info(`Updating configurations from ${config.version} to ${this.version.toString()}...`);
|
|
const result = this.doMigrate(config);
|
|
result.version = this.version.toString();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
class Migrator {
|
|
constructor(root) {
|
|
this.versions = [];
|
|
this.migrations = {};
|
|
|
|
let head = 'head';
|
|
while (head) {
|
|
const migration = new(require(path.join(root, head)))();
|
|
if (!(migration instanceof Migration)) {
|
|
throw new Error(`Migration ${head} is not a Migration class.`);
|
|
}
|
|
this.versions.push(migration.version);
|
|
this.migrations[migration.version.toString()] = migration;
|
|
head = migration.head;
|
|
}
|
|
|
|
this.versions.sort(Version.compare);
|
|
}
|
|
|
|
isOudated(version) {
|
|
if (!this.versions.length) {
|
|
return false;
|
|
}
|
|
return Version.compare(new Version(version), this.getLatestVersion()) < 0;
|
|
}
|
|
|
|
getLatestVersion() {
|
|
if (!this.versions.length) {
|
|
return null;
|
|
}
|
|
return this.versions[this.versions.length - 1];
|
|
}
|
|
|
|
migrate(config, toVersion = null) {
|
|
const fVer = new Version(config.version);
|
|
const tVer = toVersion ? new Version(toVersion) : this.getLatestVersion();
|
|
// find all migrations whose version is larger than fromVer, smaller or equal to toVer
|
|
// and run migrations on the config one by one
|
|
return this.versions.filter(ver => Version.compare(ver, fVer) > 0 && Version.compare(ver, tVer) <= 0)
|
|
.sort(Version.compare)
|
|
.reduce((cfg, ver) => {
|
|
const migration = this.migrations[ver.toString()];
|
|
return migration.migrate(cfg);
|
|
}, config);
|
|
}
|
|
}
|
|
|
|
Migrator.Version = Version;
|
|
Migrator.Migration = Migration;
|
|
|
|
module.exports = Migrator;
|