Files
HolodoriCalc/scripts/holodoridb-source.mjs
T

67 lines
3.1 KiB
JavaScript

import { execFileSync } from 'node:child_process';
import { mkdirSync, readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const prepared = new Map();
export function holodoriGit(repositoryPath, args) {
return execFileSync('git', ['-c', `safe.directory=${repositoryPath.replaceAll('\\', '/')}`, '-C', repositoryPath, ...args], {
encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, stdio: ['ignore', 'pipe', 'pipe']
}).trim();
}
const git = holodoriGit;
// Each process fetches the authoritative remote once per locale, then pins all
// reads to that commit. Neither checkout files nor stale remote refs are inputs.
export function prepareHolodoriDbSource(locale, { review = false } = {}) {
if (!['eng', 'kor', 'jpn'].includes(locale)) throw new Error(`Unknown HolodoriDB locale: ${locale}`);
if (process.argv.includes('--offline')) throw new Error('HolodoriDB collection requires the remote repository; --offline is not supported.');
if (prepared.has(locale)) {
const source = prepared.get(locale);
if (!review) requireReviewedSource(locale, source);
return source;
}
const repository = `https://github.com/HolodoriDB/holodori-db-${locale}-diff.git`;
const repositoryPath = path.join(projectRoot, 'data', 'raw', 'holodoridb-remote', locale);
mkdirSync(repositoryPath, { recursive: true });
git(repositoryPath, ['init', '--bare']);
try {
git(repositoryPath, ['fetch', '--depth', '1', '--no-tags', repository, '+refs/heads/main:refs/heads/source-main']);
} catch (error) {
throw new Error(`Cannot fetch HolodoriDB ${locale} remote main; collection stopped without using cached data.`, { cause: error });
}
const commit = git(repositoryPath, ['rev-parse', 'refs/heads/source-main']);
const source = {
repository, repositoryPath, commit,
commitDate: git(repositoryPath, ['show', '-s', '--format=%cI', commit]),
commitMessage: git(repositoryPath, ['show', '-s', '--format=%s', commit])
};
prepared.set(locale, source);
if (!review) requireReviewedSource(locale, source);
return source;
}
function requireReviewedSource(locale, source) {
let report;
try {
report = JSON.parse(readFileSync(path.join(projectRoot, 'data/holodoridb-review/latest.json'), 'utf8'));
} catch {
throw new Error('Run npm run data:sync and present the full change report before collecting calculator data.');
}
const manifest = JSON.parse(readFileSync(path.join(projectRoot, 'data/holodoridb/manifest.json'), 'utf8'));
const entry = report.sources?.[locale];
if (entry?.to !== source.commit || ![entry.from, entry.to].includes(manifest.sources[locale].commit)) {
throw new Error(`HolodoriDB ${locale} changed since review. Run npm run data:sync and present the updated report first.`);
}
}
export function readHolodoriDbText(source, filename) {
return git(source.repositoryPath, ['show', `${source.commit}:${filename}`]);
}
export function readHolodoriDbTable(locale, filename) {
return JSON.parse(readHolodoriDbText(prepareHolodoriDbSource(locale), filename));
}