58 lines
2.5 KiB
JavaScript
58 lines
2.5 KiB
JavaScript
import { spawn } from 'node:child_process'
|
|
import { createWriteStream, mkdirSync, writeFileSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
const frontend = process.cwd()
|
|
const root = path.resolve(frontend, '..')
|
|
const project = process.env.DODO_E2E_PROJECT
|
|
if (!project) throw new Error('DODO_E2E_PROJECT is required')
|
|
const runtimeBase = path.join(frontend, 'playwright-runtime', project)
|
|
const runtime = path.join(runtimeBase, `run-${new Date().toISOString().replace(/[:.]/g, '-')}-${process.pid}`)
|
|
const attachments = path.join(runtime, 'attachments')
|
|
const staging = path.join(runtime, 'backup-staging')
|
|
mkdirSync(attachments, { recursive: true })
|
|
mkdirSync(staging, { recursive: true })
|
|
writeFileSync(path.join(runtimeBase, 'latest.json'), JSON.stringify({ runtime, database: path.join(runtime, 'dodo.sqlite3'), attachments, staging }, null, 2))
|
|
writeFileSync(path.join(runtime, 'runtime.json'), JSON.stringify({ database: path.join(runtime, 'dodo.sqlite3'), attachments, staging }, null, 2))
|
|
|
|
const logs = {
|
|
backend: createWriteStream(path.join(runtime, 'backend.log'), { flags: 'a' }),
|
|
frontend: createWriteStream(path.join(runtime, 'frontend.log'), { flags: 'a' }),
|
|
}
|
|
const children = []
|
|
function start(command, args, options, log) {
|
|
const child = spawn(command, args, { ...options, stdio: ['ignore', 'pipe', 'pipe'] })
|
|
child.stdout.pipe(log)
|
|
child.stderr.pipe(log)
|
|
children.push(child)
|
|
return child
|
|
}
|
|
|
|
start(path.join(root, '.venv/bin/uvicorn'), ['backend.main:app', '--host', '127.0.0.1', '--port', '8781'], {
|
|
cwd: root,
|
|
env: {
|
|
...process.env,
|
|
DODO_DATABASE_URL: `sqlite+aiosqlite:///${path.join(runtime, 'dodo.sqlite3')}`,
|
|
DODO_AUTO_CREATE_SCHEMA: 'true',
|
|
DODO_COOKIE_SECURE: 'false',
|
|
DODO_ATTACHMENT_DIR: attachments,
|
|
DODO_BACKUP_STAGING_DIR: staging,
|
|
},
|
|
}, logs.backend)
|
|
start('pnpm', ['exec', 'vite', '--host', '127.0.0.1', '--port', '5173', '--strictPort'], { cwd: frontend, env: process.env }, logs.frontend)
|
|
|
|
let stopping = false
|
|
function stop(signal = 'SIGTERM') {
|
|
if (stopping) return
|
|
stopping = true
|
|
for (const child of children) if (!child.killed) child.kill(signal)
|
|
setTimeout(() => { for (const child of children) if (!child.killed) child.kill('SIGKILL') }, 3000).unref()
|
|
}
|
|
process.on('SIGTERM', () => stop())
|
|
process.on('SIGINT', () => stop())
|
|
process.on('exit', () => stop())
|
|
|
|
await Promise.all(children.map(child => new Promise((resolve, reject) => {
|
|
child.once('exit', (code, signal) => stopping ? resolve() : reject(new Error(`server exited code=${code} signal=${signal}`)))
|
|
})))
|