106 lines
3.5 KiB
JavaScript
106 lines
3.5 KiB
JavaScript
'use strict';
|
|||
|
|
|
||
|
|
/**
|
||
|
|
* Keep old installers instead of overwriting them.
|
||
|
|
*
|
||
|
|
* Runs automatically after `npm run dist` (see the "postdist" script). The freshly built
|
||
|
|
* version stays at the top level of dist/ so there is never a question about which file to
|
||
|
|
* install; every older version is moved into dist/archive/ and the archive is pruned to the
|
||
|
|
* most recent KEEP_VERSIONS so the folder cannot grow without bound.
|
||
|
|
*
|
||
|
|
* Zero dependencies. Set DIST_DIR to point it somewhere else (used by the tests).
|
||
|
|
*/
|
||
|
|
|
||
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
/** How many previous versions to keep. Each version is ~460 MB (installer + portable). */
|
||
|
|
const KEEP_VERSIONS = 5;
|
||
|
|
|
||
|
|
const ROOT = path.join(__dirname, '..');
|
||
|
|
const DIST = process.env.DIST_DIR || path.join(ROOT, 'dist');
|
||
|
|
const ARCHIVE = path.join(DIST, 'archive');
|
||
|
|
|
||
|
|
/** Pull "1.2.1" out of "Band Lineup Setup 1.2.1.exe". */
|
||
|
|
function versionOf(fileName) {
|
||
|
|
const match = fileName.match(/(\d+\.\d+\.\d+)/);
|
||
|
|
return match ? match[1] : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function compareVersions(a, b) {
|
||
|
|
const pa = a.split('.').map(Number);
|
||
|
|
const pb = b.split('.').map(Number);
|
||
|
|
for (let i = 0; i < 3; i += 1) {
|
||
|
|
if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
function currentVersion() {
|
||
|
|
if (process.env.CURRENT_VERSION) return process.env.CURRENT_VERSION;
|
||
|
|
return JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Installer-ish artifacts worth keeping. Build scratch (win-unpacked, logs) is left alone. */
|
||
|
|
function isArtifact(fileName) {
|
||
|
|
return /\.(exe|blockmap|dmg|zip|appx|msi)$/i.test(fileName);
|
||
|
|
}
|
||
|
|
|
||
|
|
function humanSize(bytes) {
|
||
|
|
return `${(bytes / (1024 * 1024)).toFixed(0)} MB`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function run() {
|
||
|
|
if (!fs.existsSync(DIST)) {
|
||
|
|
console.log('[archive-builds] no dist/ yet — nothing to do');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const version = currentVersion();
|
||
|
|
fs.mkdirSync(ARCHIVE, { recursive: true });
|
||
|
|
|
||
|
|
// 1. Move anything that isn't the current version out of the way.
|
||
|
|
let moved = 0;
|
||
|
|
for (const name of fs.readdirSync(DIST)) {
|
||
|
|
const from = path.join(DIST, name);
|
||
|
|
if (!fs.statSync(from).isFile() || !isArtifact(name)) continue;
|
||
|
|
const fileVersion = versionOf(name);
|
||
|
|
if (!fileVersion || fileVersion === version) continue;
|
||
|
|
const to = path.join(ARCHIVE, name);
|
||
|
|
fs.renameSync(from, to);
|
||
|
|
moved += 1;
|
||
|
|
console.log(`[archive-builds] archived ${name}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Prune the archive to the newest KEEP_VERSIONS, by version number.
|
||
|
|
const byVersion = new Map();
|
||
|
|
for (const name of fs.readdirSync(ARCHIVE)) {
|
||
|
|
const full = path.join(ARCHIVE, name);
|
||
|
|
if (!fs.statSync(full).isFile() || !isArtifact(name)) continue;
|
||
|
|
const fileVersion = versionOf(name);
|
||
|
|
if (!fileVersion) continue;
|
||
|
|
if (!byVersion.has(fileVersion)) byVersion.set(fileVersion, []);
|
||
|
|
byVersion.get(fileVersion).push(full);
|
||
|
|
}
|
||
|
|
const versions = [...byVersion.keys()].sort(compareVersions).reverse();
|
||
|
|
const drop = versions.slice(KEEP_VERSIONS);
|
||
|
|
for (const old of drop) {
|
||
|
|
for (const file of byVersion.get(old)) {
|
||
|
|
fs.unlinkSync(file);
|
||
|
|
}
|
||
|
|
console.log(`[archive-builds] pruned ${old} (keeping the newest ${KEEP_VERSIONS})`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const kept = versions.slice(0, KEEP_VERSIONS);
|
||
|
|
let bytes = 0;
|
||
|
|
for (const v of kept) {
|
||
|
|
for (const file of byVersion.get(v)) bytes += fs.statSync(file).size;
|
||
|
|
}
|
||
|
|
console.log(
|
||
|
|
`[archive-builds] current: ${version} in dist/ | archived: ${kept.join(', ') || 'none yet'}`
|
||
|
|
+ (bytes ? ` (${humanSize(bytes)})` : ''),
|
||
|
|
);
|
||
|
|
if (!moved && !kept.length) console.log('[archive-builds] first run — nothing to archive yet');
|
||
|
|
}
|
||
|
|
|
||
|
|
run();
|