import { join } from "node:path"; import { ROOT, DATA_DIR } from "./config.ts"; const LIQUIBASE = join(ROOT, "db", "tools", "liquibase", "liquibase"); const SQLITE_JDBC = join(ROOT, "db", "tools", "sqlite-jdbc.jar"); const BOOTSTRAP = join(ROOT, "db", "bootstrap-tools.sh"); async function ensureTools(): Promise { try { await Deno.stat(LIQUIBASE); await Deno.stat(SQLITE_JDBC); return true; } catch { const cmd = new Deno.Command("bash", { args: [BOOTSTRAP], stdout: "piped", stderr: "piped", }); const { code, stdout, stderr } = await cmd.output(); if (code !== 0) { console.warn( "[liquibase] bootstrap failed:\n", new TextDecoder().decode(stdout), new TextDecoder().decode(stderr), ); return false; } return true; } } async function updateOne(name: "app" | "platform"): Promise { const dir = join(ROOT, "db", name); const dbPath = join(DATA_DIR, `${name}.db`); const cmd = new Deno.Command(LIQUIBASE, { args: [ "--defaultsFile=liquibase.properties", `--classpath=${SQLITE_JDBC}`, `--url=jdbc:sqlite:${dbPath}`, "update", ], cwd: dir, stdout: "piped", stderr: "piped", }); const { code, stdout, stderr } = await cmd.output(); const out = new TextDecoder().decode(stdout); const err = new TextDecoder().decode(stderr); if (code !== 0) { throw new Error(`Liquibase update failed for ${name}:\n${out}\n${err}`); } } let ran = false; /** Apply Liquibase changelogs for app.db and platform.db (idempotent). */ export async function runLiquibase(): Promise { if (ran) return; if (!await ensureTools()) { console.warn("[liquibase] CLI missing; run ./db/update.sh"); ran = true; return; } await updateOne("app"); await updateOne("platform"); ran = true; }