52 lines
2.7 KiB
TypeScript
52 lines
2.7 KiB
TypeScript
import { resolve } from "node:path"
|
||
|
||
/**
|
||
* 运行形态的判定:开发时是 `bun src/main.ts`,生产是 `bun build --compile` 出来的单二进制。
|
||
*
|
||
* 两者最要命的差别是**路径**。编译产物里 `import.meta.dir` 恒为 `/$bunfs/root`
|
||
* (Bun 把内嵌文件摊在那个虚拟目录下),于是任何 `resolve(import.meta.dir, "../..")`
|
||
* 都会指到文件系统根:`data/test_case` 变成 `/data/test_case`。这种错误不会报错,
|
||
* 只会安静地读写错地方,所以必须显式分叉,不能靠"相对路径反正差不多"。
|
||
*/
|
||
export const isCompiled = import.meta.dir.startsWith("/$bunfs")
|
||
|
||
/**
|
||
* 起一个「自己」的子进程时该用的命令。SQL 判题要 fork 一个可被 SIGKILL 的子进程,
|
||
* 见 judge/sql/index.ts。
|
||
*
|
||
* - 编译后:二进制自己就是入口,`[binary, "sql-child"]`
|
||
* - 开发时:`process.execPath` 是 bun,得把入口脚本一起带上,`[bun, main.ts, "sql-child"]`
|
||
*/
|
||
export function selfCommand(subcommand: string): string[] {
|
||
if (isCompiled) return [process.execPath, subcommand]
|
||
return [process.execPath, resolve(import.meta.dir, "main.ts"), subcommand]
|
||
}
|
||
|
||
/**
|
||
* 相对路径的解析基准。
|
||
*
|
||
* - 编译后:按进程 cwd 解析。容器里 workdir 固定,且这些目录本来就该由环境变量显式给出,
|
||
* cwd 只是最后的兜底。
|
||
* - 开发时:按仓库根解析。因为 `bun run --filter '@oj2/api' dev` 会把 cwd 切到 apps/api/,
|
||
* 而 docker/compose.dev.yml 挂给判题沙箱的是**仓库根**的 data/test_case —— 按 cwd 解析
|
||
* 就会落到 apps/api/data/ 下,两边不是同一个目录,新传的测试点判题时报「找不到测试数据」。
|
||
*/
|
||
export const pathBase = isCompiled ? process.cwd() : resolve(import.meta.dir, "../../..")
|
||
|
||
/**
|
||
* 迁移文件(`0000_*.sql` … + `meta/_journal.json`)所在目录。
|
||
*
|
||
* 这些文件**不内嵌进二进制**,而是随镜像一起装到一个固定绝对路径下。
|
||
* 之所以能这么做、也应该这么做:CLAUDE.md 里「单二进制是有代价的」那条讲的是
|
||
* 不能依赖 node_modules、不能拿 `import.meta.dir` 去推路径(编译后它恒为
|
||
* `/$bunfs/root`,往上几级就跑到文件系统根)。按一个**显式给定的绝对路径**读一个
|
||
* 数据目录不在此列。
|
||
*
|
||
* 换来的好处是 drizzle 的 `migrate()` 能原样用 —— 它靠 `_journal.json` 自动发现
|
||
* 迁移,和 Django 扫 `migrations/` 是一回事。要是改成内嵌,就得为每条迁移手写一行
|
||
* import,那是迟早会漏的账。
|
||
*/
|
||
export const migrationsDir =
|
||
process.env.OJ2_MIGRATIONS_DIR ??
|
||
(isCompiled ? "/usr/local/share/oj2/migrations" : resolve(import.meta.dir, "db"))
|