69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
import { existsSync, readFileSync, statSync } from 'fs';
|
|
|
|
const MB = 1024 * 1024;
|
|
/** At or above this the package is refused: GitHub warns at 50 MB and rejects at 100 MB. */
|
|
export const PATCH_MAX_BYTES = 49 * MB;
|
|
export const PATCH_WARN_BYTES = 10 * MB;
|
|
export const PATCH_BINARY_FILE_WARN_BYTES = 1 * MB;
|
|
|
|
export interface PatchSizeReport {
|
|
bytes: number;
|
|
errors: string[];
|
|
warnings: string[];
|
|
}
|
|
|
|
function fmt(bytes: number): string {
|
|
return `${(bytes / MB).toFixed(1)} MB`;
|
|
}
|
|
|
|
/** Binary files in a `git diff --binary` patch whose size exceeds the threshold. */
|
|
export function largeBinaryFiles(
|
|
patchText: string,
|
|
thresholdBytes = PATCH_BINARY_FILE_WARN_BYTES
|
|
): { path: string; bytes: number }[] {
|
|
const out: { path: string; bytes: number }[] = [];
|
|
const lines = patchText.split('\n');
|
|
let current = '';
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i];
|
|
const header = /^diff --git a\/.* b\/(.*)$/.exec(line);
|
|
if (header) {
|
|
current = header[1];
|
|
continue;
|
|
}
|
|
if (line === 'GIT binary patch') {
|
|
const m = /^(?:literal|delta) (\d+)$/.exec(lines[i + 1] ?? '');
|
|
const bytes = m ? parseInt(m[1], 10) : 0;
|
|
if (bytes > thresholdBytes) out.push({ path: current, bytes });
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export function checkWorkspacePatchSize(patchPath: string): PatchSizeReport {
|
|
const report: PatchSizeReport = { bytes: 0, errors: [], warnings: [] };
|
|
if (!existsSync(patchPath)) return report;
|
|
report.bytes = statSync(patchPath).size;
|
|
if (report.bytes >= PATCH_MAX_BYTES) {
|
|
report.errors.push(
|
|
`environment/workspace.patch is ${fmt(report.bytes)} — the limit is ${fmt(PATCH_MAX_BYTES)}. ` +
|
|
'Remove large files (model weights, datasets, archives, build output) and regenerate the patch; ' +
|
|
'use a tiny dummy fixture or a stub instead.'
|
|
);
|
|
return report;
|
|
}
|
|
if (report.bytes >= PATCH_WARN_BYTES) {
|
|
report.warnings.push(
|
|
`environment/workspace.patch is ${fmt(report.bytes)} (limit ${fmt(PATCH_MAX_BYTES)}) — ` +
|
|
'check it contains only what the task needs'
|
|
);
|
|
}
|
|
for (const f of largeBinaryFiles(readFileSync(patchPath, 'latin1'))) {
|
|
report.warnings.push(
|
|
`workspace.patch adds a ${fmt(f.bytes)} binary file: ${f.path} — ` +
|
|
'prefer a tiny dummy fixture (e.g. a small random-init checkpoint) or a stub'
|
|
);
|
|
}
|
|
return report;
|
|
}
|