import shutil import sys import os import random import osdk.build as build import osdk.utils as utils import osdk.environments as environments CMDS = {} def parseOptions(args: list[str]) -> dict: result = { 'opts': {}, 'args': [] } for arg in args: if arg.startswith("--"): if "=" in arg: key, value = arg[2:].split("=", 1) result['opts'][key] = value else: result['opts'][arg[2:]] = True else: result['args'].append(arg) return result def runCmd(opts: dict, args: list[str]) -> None: if len(args) == 0: print(f"Usage: {args[0]} run ") sys.exit(1) out = build.buildOne(opts.get('env', 'host-clang'), args[0]) print(f"{utils.Colors.BOLD}Running: {args[0]}{utils.Colors.RESET}") utils.runCmd(out, *args[1:]) def kvmAvailable() -> bool: if os.path.exists("/dev/kvm") and \ os.access("/dev/kvm", os.R_OK): return True return False BOOTAGENT = "loader" def bootCmd(opts: dict, args: list[str]) -> None: imageDir = utils.mkdirP(".build/image") efiBootDir = utils.mkdirP(".build/image/EFI/BOOT") bootDir = utils.mkdirP(".build/image/boot") ovmf = utils.downloadFile( "https://retrage.github.io/edk2-nightly/bin/DEBUGX64_OVMF.fd") hjert = build.buildOne("kernel-x86_64", "hjert") shutil.copy(hjert, f"{bootDir}/kernel.elf") if BOOTAGENT == "loader": loader = build.buildOne("efi-x86_64", "loader") shutil.copy(loader, f"{efiBootDir}/BOOTX64.EFI") elif BOOTAGENT == "limine": limine = utils.downloadFile( "https://github.com/limine-bootloader/limine/raw/v3.0-branch-binary/BOOTX64.EFI") limineSys = utils.downloadFile( "https://github.com/limine-bootloader/limine/raw/v3.0-branch-binary/limine.sys") shutil.copy(limineSys, f"{bootDir}/limine.sys") shutil.copy('meta/images/limine-x86_64/limine.cfg', f"{bootDir}/limine.cfg") shutil.copy(limine, f"{efiBootDir}/BOOTX64.EFI") qemuCmd = [ "qemu-system-x86_64", "-no-reboot", "-d", "guest_errors", "-serial", "mon:stdio", "-bios", ovmf, "-m", "256M", "-smp", "4", "-drive", f"file=fat:rw:{imageDir},media=disk,format=raw", ] if kvmAvailable(): qemuCmd += ["-enable-kvm"] else: print("KVM not available, using QEMU-TCG") utils.runCmd(*qemuCmd) def buildCmd(opts: dict, args: list[str]) -> None: env = opts.get('env', 'host-clang') if len(args) == 0: build.buildAll(env) else: for component in args: build.buildOne(env, component) def cleanCmd(opts: dict, args: list[str]) -> None: shutil.rmtree(".build", ignore_errors=True) def nukeCmd(opts: dict, args: list[str]) -> None: shutil.rmtree(".build", ignore_errors=True) shutil.rmtree(".cache", ignore_errors=True) def idCmd(opts: dict, args: list[str]) -> None: i = hex(random.randint(0, 2**64)) print("64bit: " + i) print("32bit: " + i[:10]) def helpCmd(opts: dict, args: list[str]) -> None: print(f"Usage: osdk [options...] []") print("") print("Description:") print(" Operating System Development Kit.") print("") print("Commands:") for cmd in CMDS: print(" " + cmd + " - " + CMDS[cmd]["desc"]) print("") print("Enviroments:") availableToolchains = environments.available() if len(availableToolchains) == 0: print(" No environments available") else: for env in environments.available(): print(" " + env) print("") print("Variants:") for var in environments.VARIANTS: print(" " + var) print("") CMDS = { "run": { "func": runCmd, "desc": "Run a component on the host", }, "boot": { "func": bootCmd, "desc": "Boot a component in a QEMU instance", }, "build": { "func": buildCmd, "desc": "Build one or more components", }, "clean": { "func": cleanCmd, "desc": "Clean the build directory", }, "nuke": { "func": nukeCmd, "desc": "Clean the build directory and cache", }, "id": { "func": idCmd, "desc": "Generate a 64bit random id", }, "help": { "func": helpCmd, "desc": "Show this help message", }, } def main(): argv = sys.argv try: if len(argv) < 2: helpCmd({}, []) else: o = parseOptions(argv[2:]) if not argv[1] in CMDS: print(f"Unknown command: {argv[1]}") print("") print(f"Use '{argv[0]} help' for a list of commands") return 1 CMDS[argv[1]]["func"](o['opts'], o['args']) return 0 except utils.CliException as e: print() print(f"{utils.Colors.RED}{e.msg}{utils.Colors.RESET}") return 1