hexo-theme-amane/include/util/migrate.js

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;