A Docker-like CLI and HTTP API for managing headless VMs

Merge pull request #5 from tsirysndr/feat/debian

feat: add support for debian distribution

+92
+20
main.ts
··· 31 31 import tag from "./src/subcommands/tag.ts"; 32 32 import * as volumes from "./src/subcommands/volume.ts"; 33 33 import { 34 + constructDebianImageURL, 34 35 constructFedoraImageURL, 35 36 constructGentooImageURL, 36 37 constructNixOSImageURL, ··· 245 246 isoPath = yield* downloadIso(gentooImageURL, options); 246 247 } else { 247 248 isoPath = basename(gentooImageURL); 249 + } 250 + } 251 + 252 + const debianImageURL = yield* pipe( 253 + constructDebianImageURL(input), 254 + Effect.catchAll(() => Effect.succeed(null)), 255 + ); 256 + 257 + if (debianImageURL) { 258 + const cached = yield* pipe( 259 + basename(debianImageURL), 260 + fileExists, 261 + Effect.flatMap(() => Effect.succeed(true)), 262 + Effect.catchAll(() => Effect.succeed(false)), 263 + ); 264 + if (!cached) { 265 + isoPath = yield* downloadIso(debianImageURL, options); 266 + } else { 267 + isoPath = basename(debianImageURL); 248 268 } 249 269 } 250 270 }
+6
src/constants.ts
··· 24 24 export const GENTOO_IMG_URL: string = Deno.build.arch === "aarch64" 25 25 ? "https://distfiles.gentoo.org/releases/arm64/autobuilds/20251116T233105Z/di-arm64-console-20251116T233105Z.qcow2" 26 26 : "https://distfiles.gentoo.org/releases/amd64/autobuilds/20251116T161545Z/di-amd64-console-20251116T161545Z.qcow2"; 27 + 28 + export const DEBIAN_DEFAULT_VERSION: string = "13.2.0"; 29 + 30 + export const DEBIAN_ISO_URL: string = Deno.build.arch === "aarch64" 31 + ? `https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/debian-${DEBIAN_DEFAULT_VERSION}-arm64-netinst.iso` 32 + : `https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-${DEBIAN_DEFAULT_VERSION}-amd64-netinst.iso`;
+26
src/utils.ts
··· 5 5 import { Data, Effect, pipe } from "effect"; 6 6 import Moniker from "moniker"; 7 7 import { 8 + DEBIAN_DEFAULT_VERSION, 9 + DEBIAN_ISO_URL, 8 10 EMPTY_DISK_THRESHOLD_KB, 9 11 FEDORA_COREOS_DEFAULT_VERSION, 10 12 FEDORA_COREOS_IMG_URL, ··· 753 755 }), 754 756 ); 755 757 }; 758 + 759 + export const constructDebianImageURL = ( 760 + image: string, 761 + ): Effect.Effect<string, InvalidImageNameError, never> => { 762 + // detect with regex if image matches debian pattern: debian-<version> or debian 763 + const debianRegex = /^(debian)(-(\d+\.\d+\.\d+))?$/; 764 + const match = image.match(debianRegex); 765 + if (match?.[3]) { 766 + return Effect.succeed( 767 + DEBIAN_ISO_URL.replaceAll(DEBIAN_DEFAULT_VERSION, match[3]), 768 + ); 769 + } 770 + 771 + if (match) { 772 + return Effect.succeed(DEBIAN_ISO_URL); 773 + } 774 + 775 + return Effect.fail( 776 + new InvalidImageNameError({ 777 + image, 778 + cause: "Image name does not match Debian naming conventions.", 779 + }), 780 + ); 781 + };
+40
src/utils_test.ts
··· 1 1 import { assertEquals } from "@std/assert"; 2 2 import { Effect, pipe } from "effect"; 3 3 import { 4 + DEBIAN_ISO_URL, 4 5 FEDORA_COREOS_IMG_URL, 5 6 GENTOO_IMG_URL, 6 7 NIXOS_ISO_URL, 7 8 } from "./constants.ts"; 8 9 import { 9 10 constructCoreOSImageURL, 11 + constructDebianImageURL, 10 12 constructGentooImageURL, 11 13 constructNixOSImageURL, 12 14 } from "./utils.ts"; ··· 131 133 132 134 assertEquals(url, null); 133 135 }); 136 + 137 + Deno.test("Test valid Debian Image Name", () => { 138 + const url = Effect.runSync( 139 + pipe( 140 + constructDebianImageURL("debian-13.2.0"), 141 + Effect.catchAll((_error) => Effect.succeed(null as string | null)), 142 + ), 143 + ); 144 + 145 + const arch = Deno.build.arch === "aarch64" ? "arm64" : "amd64"; 146 + assertEquals( 147 + url, 148 + `https://cdimage.debian.org/debian-cd/current/${arch}/iso-cd/debian-13.2.0-${arch}-netinst.iso`, 149 + ); 150 + }); 151 + 152 + Deno.test("Test valid Debian Image Name", () => { 153 + const url = Effect.runSync( 154 + pipe( 155 + constructDebianImageURL("debian"), 156 + Effect.catchAll((_error) => Effect.succeed(null as string | null)), 157 + ), 158 + ); 159 + 160 + const arch = Deno.build.arch === "aarch64" ? "arm64" : "amd64"; 161 + assertEquals(url, DEBIAN_ISO_URL); 162 + }); 163 + 164 + Deno.test("Test invalid Debian Image Name", () => { 165 + const url = Effect.runSync( 166 + pipe( 167 + constructDebianImageURL("debian-latest"), 168 + Effect.catchAll((_error) => Effect.succeed(null as string | null)), 169 + ), 170 + ); 171 + 172 + assertEquals(url, null); 173 + });