Files
band-lineup-display/scripts/archive-builds.js
T

106 lines
3.5 KiB
JavaScript
Raw Normal View History

'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();