UNPKG

sc4

Version:

A command line utility for automating SimCity 4 modding tasks & modifying savegames

65 lines (64 loc) 2.29 kB
// # plugins-duplicates-command.ts import { createHash } from 'node:crypto'; import fs from 'node:fs'; import path from 'node:path'; import PQueue from 'p-queue'; import { FileScanner } from 'sc4/plugins'; import logger from '#cli/logger.js'; import { styleText } from 'node:util'; export async function pluginsDuplicates(opts) { const { directory = process.env.SC4_PLUGINS, } = opts; const cwd = path.resolve(process.cwd(), directory); const glob = new FileScanner('**/*', { cwd }); let info = []; const map = {}; const queue = new PQueue({ concurrency: 250 }); logger.progress.start('Scanning plugins'); for await (let file of glob) { queue.add(async () => { let contents = await fs.promises.readFile(file); let hash = createHash('sha256') .update(contents) .digest('hex'); let basename = path.basename(file); info.push({ hash, basename, path: path.relative(cwd, file), }); map[hash] ??= 0; map[hash]++; }); } await queue.onIdle(); logger.progress.succeed(); // Fiter out anything that has a unique hash. info = info.filter(info => map[info.hash] > 1); info.sort((a, b) => a.path < b.path ? -1 : 1); // Cool, everything has been scanned. Let's group based on filename, and the // subgroup by hash. let table = []; let grouped = Object.groupBy(info, info => info.hash); for (let hash of Object.keys(grouped)) { let group = grouped[hash]; for (let i = 0; i < group.length; i++) { let info = group[i]; table.push({ ...i === 0 ? { hash: { [Symbol.for('nodejs.util.inspect.custom')]() { return styleText('yellow', hash.slice(0, 9)); }, }, } : null, file: { [Symbol.for('nodejs.util.inspect.custom')]() { return styleText('cyan', info.path); }, }, }); } table.push({}); } console.table(table, ['hash', 'file']); }