import { ensureDir, writeTextAtomic } from "./fs"; import { INSTALL_STATE_DIR, INSTALL_STATE_PATH, type InstallStateRecord } from "./installState"; /** * Единственный способ записать маркер установки на диск. * * Раньше их было два. `install` писал через `writeText` — обычная перезапись * файла на месте, — а `reconfigure` через `writeTextAtomic`. Один и тот же файл, * две разные гарантии, причём слабейшая досталась команде, которая создаёт этот * файл впервые и после которой он и становится метаданными восстановления. * * Расхождение стоило дороже, чем выглядит. Перезапись на месте укорачивает файл * до нуля и только потом наполняет: любой отказ между этими моментами — потеря * питания, kill -9, ENOSPC — оставляет на сервере половину JSON: * * { * "product": "hy2xs", * "release_line": * * Такой маркер не разбирается, поэтому reconfigure/repair видят его как * отсутствующий, а clean-host — как присутствующий. Установка при этом уже * изменила хост. * * Модуль отделён от installState.ts намеренно: тот остаётся чистым (структура * записи и проверка поколения) и разбирается юнит-тестами без файловой системы * и подпроцессов. */ export async function persistInstallState(record: InstallStateRecord): Promise { await ensureDir(INSTALL_STATE_DIR, { mode: 0o755, owner: "root", group: "root" }); await writeTextAtomic(INSTALL_STATE_PATH, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o644, owner: "root", group: "root" }); }