Files
wasm-simulator/check-linuxcnc-browser-app-source-map.sh
cnc b89d6311ff 参考所有分组,完成尽量多的内容。禁止顺手扩功能 smoke:锁定OPFS参数保存顺序
结论:按 LinuxCNC rs274ngc_pre.cc save_parameters() 的 .new、.bak、unlink/link/rename 顺序补强 OPFS/app/browser smoke 守卫,并验证临时参数文件不会残留在 OPFS。
2026-06-04 19:42:49 +08:00

115 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
# LinuxCNC source basis: this guard ties the browser app entry point to
# LinuxCNC RS274 parameter-file defaults, rs274ngc_pre.cc restore/save/read
# file semantics, and the existing OPFS-backed wasm-core bridge. It validates
# app integration policy only; it does not add CNC behavior or expand smoke
# parsing.
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
grep -F '#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak"' \
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
grep -F 'int Interp::restore_parameters(const char *filename)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'int Interp::save_parameters(const char *filename,' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'unlink(bakfile.c_str());' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'LinuxCNC browser app source map' docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F 'must not add CNC behavior' docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F '`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F '`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`' \
docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F 'orders parameter saves as backup unlink' \
docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F '<script type="module" src="/src/app.js"></script>' web/index.html >/dev/null
grep -F '<option value="linuxcnc-rs274">LINUXCNC</option>' web/index.html >/dev/null
if [[ "$(grep -Fc '<option value=' web/index.html)" -ne 1 ]]; then
echo "browser app backend selector must expose only the LinuxCNC RS274 backend" >&2
exit 1
fi
grep -F 'import { createWasmSimulator } from "./wasm-core.js";' web/src/app.js >/dev/null
grep -F 'const programPath = "programs/current.ngc";' web/src/app.js >/dev/null
grep -F 'const linuxCncParameterFileName = "rs274ngc.var";' web/src/app.js >/dev/null
grep -F 'const parameterPath = `parameters/${linuxCncParameterFileName}`;' web/src/app.js >/dev/null
grep -F 'const linuxCncBackend = "linuxcnc-rs274";' web/src/app.js >/dev/null
grep -F 'const opfsOptions = { required: true, mountPoint: "/cnc", workspacePath: "cnc-simulator" };' \
web/src/app.js >/dev/null
grep -F 'simulatorPromise = createWasmSimulator({' web/src/app.js >/dev/null
grep -F 'opfs: opfsOptions,' web/src/app.js >/dev/null
grep -F 'OPFS workspace is required for browser program parsing' web/src/app.js >/dev/null
grep -F 'await simulator.fs.opfs.writeFile(programPath, elements.input.value);' web/src/app.js >/dev/null
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
web/src/app.js >/dev/null
grep -F 'elements.backendSelect.value = linuxCncBackend;' web/src/app.js >/dev/null
grep -F 'globalThis.__cncSimulatorForTest = simulatorPromise;' web/src/app.js >/dev/null
grep -F 'app frame did not persist current program into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not persist LinuxCNC parameter state into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'OPFS PROGRAM RESTORED' web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not reload LinuxCNC parameter state from OPFS after reload' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'runSection("browser app opfs save"' test-web-wasm-browser-smoke.sh >/dev/null
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
exit 1
fi
python3 - <<'PY'
from pathlib import Path
source_map = Path("docs/linuxcnc-browser-app-source-map.md").read_text(encoding="utf-8")
for entry in [
"web/index.html",
"web/src/app.js",
"web/test-browser-wasm-smoke-app-sections.js",
]:
if f"| `{entry}` |" not in source_map:
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing app entry: {entry}")
for phrase in [
"must not add CNC behavior",
"must not expand the temporary smoke parser",
"existing `createWasmSimulator()` OPFS API",
"programs/current.ngc",
"parameters/rs274ngc.var",
"visible backend selector must stay limited",
"./check-linuxcnc-browser-app-source-map.sh",
]:
if phrase not in source_map:
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing boundary phrase: {phrase}")
app = Path("web/src/app.js").read_text(encoding="utf-8")
if "parse(" in app.replace("parseProgram", ""):
raise SystemExit("browser app should route program execution through parseFileWithParameterFile, not direct parse")
PY