myt/myt-clean.js

162 lines
4.8 KiB
JavaScript
Executable File

const Myt = require('./myt');
const Command = require('./lib/command');
const fs = require('fs-extra');
const path = require('path');
/**
* Cleans old applied versions.
*/
class Clean extends Command {
static usage = {
description: 'Cleans old applied versions',
params: {
purge: 'Whether to remove non-existent scripts from DB log'
}
};
static opts = {
alias: {
purge: 'p'
},
boolean: [
'purge'
],
default: {
remote: 'production'
}
};
static reporter = {
versionsArchived: function(nVersions) {
if (nVersions)
console.log(` -> ${nVersions} versions archived.`);
else
console.log(` -> No versions archived.`);
},
versionLogPurged: function(nPurged) {
if (nPurged)
console.log(` -> ${nPurged} changes purged from log.`);
else
console.log(` -> No logs purged.`);
}
};
async run(myt, opts) {
const conn = await myt.dbConnect();
const archiveDir = path.join(opts.versionsDir, '.archive');
const dbVersion = await myt.fetchDbVersion() || {};
const number = parseInt(dbVersion.number);
const oldVersions = [];
const versionDirs = await fs.readdir(opts.versionsDir);
for (const versionDir of versionDirs) {
const version = await myt.loadVersion(versionDir);
const shouldArchive = version
&& !version.apply
&& parseInt(version.number) < number;
if (shouldArchive)
oldVersions.push(versionDir);
}
if (opts.maxOldVersions
&& oldVersions.length > opts.maxOldVersions) {
oldVersions.splice(-opts.maxOldVersions);
if (!await fs.pathExists(archiveDir))
await fs.mkdir(archiveDir);
for (const oldVersion of oldVersions) {
const srcDir = path.join(opts.versionsDir, oldVersion);
const dstDir = path.join(archiveDir, oldVersion);
if (!await fs.pathExists(dstDir))
await fs.mkdir(dstDir);
const scripts = await fs.readdir(srcDir);
for (const script of scripts) {
await fs.move(
path.join(srcDir, script),
path.join(dstDir, script),
{overwrite: true}
);
}
await fs.rmdir(srcDir);
}
this.emit('versionsArchived', oldVersions.length);
} else
this.emit('versionsArchived');
if (opts.purge) {
const versionDb = new VersionDb(myt, opts.versionsDir);
versionDb.load();
const archiveDb = new VersionDb(myt, archiveDir);
archiveDb.load();
const [res] = await conn.query(
`SELECT number, file FROM versionLog
WHERE code = ?
ORDER BY number, file`,
[opts.code]
);
let nPurged = 0;
for (const script of res) {
const hasVersion = await versionDb.hasScript(script);
const hasArchive = await archiveDb.hasScript(script);
if (!hasVersion && !hasArchive) {
await conn.query(
`DELETE FROM versionLog
WHERE code = ? AND number = ? AND file = ?`,
[opts.code, script.number, script.file]
);
nPurged++;
}
}
this.emit('versionLogPurged', nPurged);
}
}
}
class VersionDb {
constructor(myt, baseDir) {
Object.assign(this, {myt, baseDir});
}
async load() {
const map = this.map = new Map();
if (await fs.pathExists(this.baseDir)) {
const dirs = await fs.readdir(this.baseDir);
for (const dir of dirs) {
const version = this.myt.parseVersionDir(dir);
if (!version) continue;
let subdirs = map.get(version.number);
if (!subdirs) map.set(version.number, subdirs = []);
subdirs.push(dir);
}
}
return map;
}
async hasScript(script) {
const dirs = this.map.get(script.number);
if (dirs)
for (const dir of dirs) {
const scriptPath = path.join(this.baseDir, dir, script.file);
if (await fs.pathExists(scriptPath)) return true;
}
return false;
}
}
module.exports = Clean;
if (require.main === module)
new Myt().cli(Clean);