67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import { createWriteStream, existsSync, mkdirSync } from "node:fs";
|
|
import { get } from "node:https";
|
|
import { dirname, resolve } from "node:path";
|
|
import { spawn, spawnSync } from "node:child_process";
|
|
|
|
const adminerFile = resolve("tools/adminer/adminer.php");
|
|
const localPhp = resolve("tools/php/php.exe");
|
|
const host = process.env.ADMINER_HOST || "127.0.0.1";
|
|
const port = process.env.ADMINER_PORT || "8080";
|
|
const adminerDownloadUrl = process.env.ADMINER_DOWNLOAD_URL || "https://www.adminer.org/latest.php";
|
|
const phpCommand = existsSync(localPhp) ? localPhp : "php";
|
|
|
|
if (!commandExists(phpCommand)) {
|
|
console.error("Adminer needs PHP CLI. Install PHP first, then run npm run adminer again.");
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!existsSync(adminerFile)) {
|
|
mkdirSync(dirname(adminerFile), { recursive: true });
|
|
await downloadFile(adminerDownloadUrl, adminerFile);
|
|
}
|
|
|
|
const child = spawn(phpCommand, ["-S", `${host}:${port}`, adminerFile], {
|
|
stdio: "inherit",
|
|
shell: true,
|
|
});
|
|
|
|
child.on("exit", (code, signal) => {
|
|
if (signal) {
|
|
process.kill(process.pid, signal);
|
|
return;
|
|
}
|
|
|
|
process.exit(code ?? 0);
|
|
});
|
|
|
|
function commandExists(command: string): boolean {
|
|
const result = spawnSync(command, ["-v"], { stdio: "ignore", shell: true });
|
|
return result.status === 0;
|
|
}
|
|
|
|
function downloadFile(url: string, target: string): Promise<void> {
|
|
return new Promise((resolveDownload, rejectDownload) => {
|
|
const request = get(url, (response) => {
|
|
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
downloadFile(response.headers.location, target).then(resolveDownload, rejectDownload);
|
|
return;
|
|
}
|
|
|
|
if (response.statusCode !== 200) {
|
|
rejectDownload(new Error(`Adminer download failed with HTTP ${response.statusCode}`));
|
|
return;
|
|
}
|
|
|
|
const file = createWriteStream(target);
|
|
response.pipe(file);
|
|
file.on("finish", () => {
|
|
file.close();
|
|
resolveDownload();
|
|
});
|
|
file.on("error", rejectDownload);
|
|
});
|
|
|
|
request.on("error", rejectDownload);
|
|
});
|
|
}
|