feat: advance FreeCAD exact parity evidence
This commit is contained in:
81
scripts/run-freecad-gui-workflow-oracle.mjs
Normal file
81
scripts/run-freecad-gui-workflow-oracle.mjs
Normal file
@@ -0,0 +1,81 @@
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { mkdir, writeFile } from 'node:fs/promises'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||
const executable = resolve(root, '.cache/freecad/install-desktop/bin/FreeCAD')
|
||||
const probe = resolve(root, 'scripts/freecad-gui-workflow-oracle.py')
|
||||
const sysroot = resolve(root, '.cache/freecad/sysroot')
|
||||
const outputDirectory = resolve(root, '.cache/freecad/gui-workflow-oracle')
|
||||
const resultFile = resolve(outputDirectory, 'partdesign-pad-success-result.json')
|
||||
const reportPath = resolve(root, 'config/freecad-gui-workflow-oracle.json')
|
||||
const configDirectory = resolve(outputDirectory, 'config')
|
||||
const userConfig = resolve(configDirectory, 'user.cfg')
|
||||
const systemConfig = resolve(configDirectory, 'system.cfg')
|
||||
const marker = 'FREECAD_GUI_WORKFLOW_RESULT='
|
||||
const timeoutMs = Number(process.env.FREECAD_GUI_WORKFLOW_TIMEOUT_MS || 120_000)
|
||||
const fail = (message) => { throw new Error(`FreeCAD GUI workflow oracle: ${message}`) }
|
||||
|
||||
await mkdir(outputDirectory, { recursive: true })
|
||||
mkdirSync(configDirectory, { recursive: true })
|
||||
const emptyConfig = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n<FCParameters><FCParamGroup Name="Root"/></FCParameters>\n'
|
||||
writeFileSync(userConfig, emptyConfig)
|
||||
writeFileSync(systemConfig, emptyConfig)
|
||||
|
||||
const runtimeEnv = {
|
||||
...process.env,
|
||||
PYTHONPATH: `${resolve(sysroot, 'usr/lib/python3/dist-packages')}${process.env.PYTHONPATH ? `:${process.env.PYTHONPATH}` : ''}`,
|
||||
LD_LIBRARY_PATH: `${resolve(sysroot, 'usr/lib/x86_64-linux-gnu')}${process.env.LD_LIBRARY_PATH ? `:${process.env.LD_LIBRARY_PATH}` : ''}`,
|
||||
MATPLOTLIBRC: resolve(sysroot, 'usr/share/matplotlib/mpl-data/matplotlibrc'),
|
||||
MPLBACKEND: 'Agg',
|
||||
FREECAD_GUI_WORKFLOW_RESULT_FILE: resultFile,
|
||||
}
|
||||
const execution = spawnSync('xvfb-run', ['-a', executable, '--user-cfg', userConfig, '--system-cfg', systemConfig, '--python-path', resolve(sysroot, 'usr/lib/python3/dist-packages'), probe], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 32 * 1024 * 1024,
|
||||
timeout: timeoutMs,
|
||||
env: runtimeEnv,
|
||||
})
|
||||
const output = `${execution.stdout ?? ''}\n${execution.stderr ?? ''}`
|
||||
const markerLine = output.split(/\r?\n/).find((line) => line.startsWith(marker))
|
||||
const resultBytes = (() => { try { return readFileSync(resultFile, 'utf8') } catch { return '' } })()
|
||||
if (execution.error || (execution.status !== 0 && !resultBytes && !markerLine)) fail(`native probe exited with ${execution.status}: ${[execution.error?.message, output.trim()].filter(Boolean).join('\n')}`)
|
||||
const result = JSON.parse(resultBytes || markerLine.slice(marker.length))
|
||||
if (result.freecadVersion !== '1.1.1' || result.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail(`native baseline mismatch: ${JSON.stringify(result)}`)
|
||||
if (result.workflowId !== 'partdesign-pad-task' || result.commandId !== 'PartDesign_Pad' || result.state !== 'success' || result.success !== true) fail(`Pad success workflow failed: ${JSON.stringify(result)}`)
|
||||
|
||||
const report = {
|
||||
schemaVersion: 1,
|
||||
baseline: {
|
||||
freecadVersion: result.freecadVersion,
|
||||
commit: result.gitCommit,
|
||||
profile: 'desktop-xvfb-isolated-config',
|
||||
},
|
||||
generatedBy: './npmw run probe:freecad-gui-workflow',
|
||||
checkedBy: './npmw run check:freecad-gui-workflow',
|
||||
family: {
|
||||
id: result.workflowId,
|
||||
primaryCommand: result.commandId,
|
||||
exactTask: 'EX-UI-03',
|
||||
source: '.cache/freecad/FreeCAD/src/Mod/PartDesign/Gui/Command.cpp',
|
||||
},
|
||||
workflows: {
|
||||
success: result,
|
||||
},
|
||||
remainingStates: ['disabled', 'failure', 'cancel', 'recovery'],
|
||||
exactPromotionReady: false,
|
||||
}
|
||||
await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`)
|
||||
console.log(JSON.stringify({
|
||||
status: 'freecad-gui-workflow-generated',
|
||||
family: report.family.id,
|
||||
command: report.family.primaryCommand,
|
||||
state: result.state,
|
||||
bodyTip: result.after.bodyTip,
|
||||
volume: result.after.pad.volume,
|
||||
taskOpened: result.taskPanel.opened.activeDialog,
|
||||
taskClosed: !result.taskPanel.closed.activeDialog,
|
||||
report: 'config/freecad-gui-workflow-oracle.json',
|
||||
}, null, 2))
|
||||
Reference in New Issue
Block a user