60 lines
4.0 KiB
JavaScript
60 lines
4.0 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import { spawnSync } from 'node:child_process'
|
|
import { PROJECT, hash } from './upload.mjs'
|
|
import { loadCosMediaManifest, isMediaFile } from '../../build/tang-detective-cos-media.mjs'
|
|
import { validateNativeOutput } from '../../build/validate-tang-detective-output.mjs'
|
|
|
|
const sourceDirectory = path.join(PROJECT, 'native/tang-detective')
|
|
const media = loadCosMediaManifest({ sourceDirectory })
|
|
if (!media || media.sourceSnapshot.actual.size !== 269 || media.sourceSnapshot.missingMedia.length !== 204
|
|
|| !media.sourceSnapshot.prune) throw new Error('FULLY_CLEANED_CHECKOUT_REQUIRED')
|
|
const receiptFile = path.join(PROJECT, 'build/tang-detective-media-prune-receipt.json')
|
|
const receipt = JSON.parse(fs.readFileSync(receiptFile))
|
|
const recoveryDirectory = '/Users/dagedagededagege/Pictures/tang-media-backup-20260908.9hdgCE/pruned-originals'
|
|
const removed = [...receipt.entries.map(entry => ({ ...entry, projectPath: `native/tang-detective/${entry.sourcePath}` })),
|
|
...receipt.additionalUnusedFiles]
|
|
for (const entry of removed) {
|
|
if (fs.existsSync(path.join(PROJECT, entry.projectPath))) throw new Error('REMOVED_PROJECT_FILE_REAPPEARED')
|
|
const bytes = fs.readFileSync(path.join(recoveryDirectory, entry.projectPath))
|
|
if (bytes.length !== entry.bytes || hash(bytes) !== entry.sha256) throw new Error('RECOVERY_BYTES_CHANGED')
|
|
}
|
|
const report = { schemaVersion: 1, startedAt: new Date().toISOString(), passed: false,
|
|
uploadRunId: media.uploadRunId, sourceManifestSha256: media.sourceManifestSha256,
|
|
mediaManifestSha256: media.manifestSha256, pruneReceiptSha256: hash(fs.readFileSync(receiptFile)),
|
|
nonMediaSourceFilesByteVerified: 269, sourceMediaFilesRemaining: 0,
|
|
removedProjectFiles: removed.length, removedProjectBytes: receipt.removedProjectBytes,
|
|
recoveryFilesByteVerified: removed.length, commands: [],
|
|
boundary: 'Actual cleaned checkout, installed compiler and offline automated tests only. Not real-device, medical, backend deployment or release acceptance.' }
|
|
const outputFile = path.join(PROJECT, 'build/tang-detective-cleanup-verification.json')
|
|
const save = () => fs.writeFileSync(outputFile, JSON.stringify(report, null, 2) + '\n')
|
|
save()
|
|
for (const [command, args] of [
|
|
['npm', ['run', 'test:tang']],
|
|
['npm', ['run', 'build:mp-weixin']],
|
|
['npm', ['run', 'check:tang-output']],
|
|
[process.execPath, ['scripts/check-tang-native-compiler.cjs']],
|
|
]) {
|
|
const result = spawnSync(command, args, { cwd: PROJECT, encoding: 'utf8', timeout: 120000, maxBuffer: 16 * 1024 * 1024 })
|
|
report.commands.push({ command: [command, ...args], exitCode: result.status, signal: result.signal,
|
|
stdout: result.stdout, stderr: result.stderr, passed: result.status === 0 && !result.error })
|
|
save()
|
|
console.log(JSON.stringify({ command: [command, ...args], exitCode: result.status }))
|
|
if (!report.commands.at(-1).passed) throw new Error('POST_CLEANUP_COMMAND_FAILED')
|
|
}
|
|
report.output = validateNativeOutput(path.join(PROJECT, 'dist/build/mp-weixin'))
|
|
const walk = (dir, prefix = '') => fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
if (['node_modules', 'dist', 'unpackage', '.git'].includes(entry.name)) return []
|
|
const relative = prefix + entry.name
|
|
if (entry.isSymbolicLink()) throw new Error('UNEXPECTED_OUTPUT_SYMLINK')
|
|
return entry.isDirectory() ? walk(path.join(dir, entry.name), relative + '/') : [relative]
|
|
})
|
|
report.remainingHostMedia = walk(PROJECT).filter(file => !/^(node_modules|dist|unpackage|\.git)\//.test(file) && isMediaFile(file))
|
|
report.passed = report.output.passed && report.output.mediaMode === 'cos' && report.output.packagedMediaFiles === 0
|
|
report.completedAt = new Date().toISOString()
|
|
save()
|
|
console.log(JSON.stringify({ passed: report.passed, sourceMediaFilesRemaining: 0, packagedTangMediaFiles: report.output.packagedMediaFiles,
|
|
totalBuildBytes: report.output.outputSizes.totalFileBytes, mainPackageBytes: report.output.outputSizes.mainPackageFileBytes,
|
|
remainingHostMedia: report.remainingHostMedia, outputFile }))
|
|
if (!report.passed) process.exitCode = 1
|