A convenient CLI tool to quickly spin up DragonflyBSD virtual machines using QEMU with sensible defaults.
1import { Effect, pipe } from "effect";
2import { LOGS_DIR } from "../constants.ts";
3
4const ensureLogsDirectory = () =>
5 Effect.tryPromise({
6 try: () => Deno.mkdir(LOGS_DIR, { recursive: true }),
7 catch: (cause) => new Error(`Failed to create logs directory: ${cause}`),
8 });
9
10const buildLogPath = (name: string) =>
11 Effect.sync(() => `${LOGS_DIR}/${name}.log`);
12
13const buildLogCommand = (follow: boolean, logPath: string) =>
14 Effect.sync(() => ({
15 command: follow ? "tail" : "cat",
16 args: [
17 ...(follow ? ["-n", "100", "-f"] : []),
18 logPath,
19 ],
20 }));
21
22const executeLogCommand = (command: string, args: string[]) =>
23 Effect.tryPromise({
24 try: async () => {
25 const cmd = new Deno.Command(command, {
26 args,
27 stdin: "inherit",
28 stdout: "inherit",
29 stderr: "inherit",
30 });
31
32 return await cmd.spawn().status;
33 },
34 catch: (cause) => new Error(`Failed to execute log command: ${cause}`),
35 });
36
37const validateLogCommandResult = (name: string, status: Deno.CommandStatus) =>
38 Effect.sync(() => {
39 if (!status.success) {
40 throw new Error(`Failed to view logs for virtual machine ${name}`);
41 }
42 });
43
44const viewVirtualMachineLogs = (name: string, follow: boolean) =>
45 pipe(
46 ensureLogsDirectory(),
47 Effect.flatMap(() => buildLogPath(name)),
48 Effect.flatMap((logPath) =>
49 pipe(
50 buildLogCommand(follow, logPath),
51 Effect.flatMap(({ command, args }) => executeLogCommand(command, args)),
52 Effect.flatMap((status) => validateLogCommandResult(name, status)),
53 )
54 ),
55 );
56
57export default async function (name: string, follow: boolean) {
58 const program = pipe(
59 viewVirtualMachineLogs(name, follow),
60 Effect.catchAll((error) =>
61 Effect.sync(() => {
62 console.error(`Error: ${String(error)}`);
63 Deno.exit(1);
64 })
65 ),
66 );
67
68 await Effect.runPromise(program);
69}