forked from clan/clan-core
Merge pull request 'add qemu-wayland' (#612) from Mic92-main into main
This commit is contained in:
commit
006ce36b8a
19
pkgs/aemu/default.nix
Normal file
19
pkgs/aemu/default.nix
Normal file
@ -0,0 +1,19 @@
|
||||
{ clangStdenv
|
||||
, fetchgit
|
||||
, cmake
|
||||
}:
|
||||
|
||||
clangStdenv.mkDerivation {
|
||||
pname = "aemu";
|
||||
version = "unstable-2023-11-10";
|
||||
src = fetchgit {
|
||||
url = "https://android.googlesource.com/platform/hardware/google/aemu";
|
||||
rev = "ed69e33fb47e6cbe1b1d07c63d4d293dabc770f6";
|
||||
hash = "sha256-HYwGT48fPC3foqYvhw+RUsnkoEHgQXfMFGQVSpDu4v4=";
|
||||
};
|
||||
cmakeFlags = [
|
||||
"-DAEMU_COMMON_GEN_PKGCONFIG=ON"
|
||||
"-DAEMU_COMMON_BUILD_CONFIG=gfxstream"
|
||||
];
|
||||
nativeBuildInputs = [ cmake ];
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import select
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from collections.abc import Iterator
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, TypeVar
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from .custom_logger import ThreadFormatter, get_caller
|
||||
from .deal import deal
|
||||
from .errors import ClanError
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, log: logging.Logger) -> None:
|
||||
self.log: logging.Logger = log
|
||||
self.p: subprocess.Popen[str] | None = None
|
||||
self._output: queue.SimpleQueue[str | None] = queue.SimpleQueue()
|
||||
self.returncode: int | None = None
|
||||
self.done: bool = False
|
||||
self.stdout: list[str] = []
|
||||
self.stderr: list[str] = []
|
||||
|
||||
def close_queue(self) -> None:
|
||||
if self.p is not None:
|
||||
self.returncode = self.p.returncode
|
||||
self._output.put(None)
|
||||
self.done = True
|
||||
|
||||
def run(
|
||||
self,
|
||||
cmd: list[str],
|
||||
env: dict[str, str] | None = None,
|
||||
cwd: Path | None = None,
|
||||
name: str = "command",
|
||||
) -> None:
|
||||
self.running = True
|
||||
self.log.debug(f"Command: {shlex.join(cmd)}")
|
||||
self.log.debug(f"Caller: {get_caller()}")
|
||||
|
||||
cwd_res = None
|
||||
if cwd is not None:
|
||||
if not cwd.exists():
|
||||
raise ClanError(f"Working directory {cwd} does not exist")
|
||||
if not cwd.is_dir():
|
||||
raise ClanError(f"Working directory {cwd} is not a directory")
|
||||
cwd_res = cwd.resolve()
|
||||
self.log.debug(f"Working directory: {cwd_res}")
|
||||
|
||||
self.p = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf-8",
|
||||
cwd=cwd_res,
|
||||
env=env,
|
||||
)
|
||||
assert self.p.stdout is not None and self.p.stderr is not None
|
||||
os.set_blocking(self.p.stdout.fileno(), False)
|
||||
os.set_blocking(self.p.stderr.fileno(), False)
|
||||
|
||||
while self.p.poll() is None:
|
||||
# Check if stderr is ready to be read from
|
||||
rlist, _, _ = select.select([self.p.stderr, self.p.stdout], [], [], 1)
|
||||
for fd in rlist:
|
||||
try:
|
||||
for line in fd:
|
||||
self.log.debug(f"[{name}] {line.rstrip()}")
|
||||
if fd == self.p.stderr:
|
||||
self.stderr.append(line)
|
||||
else:
|
||||
self.stdout.append(line)
|
||||
self._output.put(line)
|
||||
except BlockingIOError:
|
||||
continue
|
||||
|
||||
if self.p.returncode != 0:
|
||||
raise ClanError(f"Failed to run command: {shlex.join(cmd)}")
|
||||
|
||||
|
||||
class TaskStatus(str, Enum):
|
||||
NOTSTARTED = "NOTSTARTED"
|
||||
RUNNING = "RUNNING"
|
||||
FINISHED = "FINISHED"
|
||||
FAILED = "FAILED"
|
||||
|
||||
|
||||
class BaseTask:
|
||||
def __init__(self, uuid: UUID, num_cmds: int) -> None:
|
||||
# constructor
|
||||
self.uuid: UUID = uuid
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(ThreadFormatter())
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.addHandler(handler)
|
||||
self.log = logger
|
||||
self.log = logger
|
||||
self.procs: list[Command] = []
|
||||
self.status = TaskStatus.NOTSTARTED
|
||||
self.logs_lock = threading.Lock()
|
||||
self.error: Exception | None = None
|
||||
|
||||
for _ in range(num_cmds):
|
||||
cmd = Command(self.log)
|
||||
self.procs.append(cmd)
|
||||
|
||||
def _run(self) -> None:
|
||||
self.status = TaskStatus.RUNNING
|
||||
try:
|
||||
self.run()
|
||||
# TODO: We need to check, if too many commands have been initialized,
|
||||
# but not run. This would deadlock the log_lines() function.
|
||||
# Idea: Run next(cmds) and check if it raises StopIteration if not,
|
||||
# we have too many commands
|
||||
except Exception as e:
|
||||
# FIXME: fix exception handling here
|
||||
traceback.print_exception(*sys.exc_info())
|
||||
self.error = e
|
||||
self.log.exception(e)
|
||||
self.status = TaskStatus.FAILED
|
||||
else:
|
||||
self.status = TaskStatus.FINISHED
|
||||
finally:
|
||||
for proc in self.procs:
|
||||
proc.close_queue()
|
||||
|
||||
def run(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
## TODO: Test when two clients are connected to the same task
|
||||
def log_lines(self) -> Iterator[str]:
|
||||
with self.logs_lock:
|
||||
for proc in self.procs:
|
||||
if self.status == TaskStatus.FINISHED:
|
||||
return
|
||||
# process has finished
|
||||
if proc.done:
|
||||
for line in proc.stdout:
|
||||
yield line
|
||||
for line in proc.stderr:
|
||||
yield line
|
||||
else:
|
||||
while maybe_line := proc._output.get():
|
||||
yield maybe_line
|
||||
|
||||
def commands(self) -> Iterator[Command]:
|
||||
yield from self.procs
|
||||
|
||||
|
||||
# TODO: We need to test concurrency
|
||||
class TaskPool:
|
||||
def __init__(self) -> None:
|
||||
self.lock: threading.RLock = threading.RLock()
|
||||
self.pool: dict[UUID, BaseTask] = {}
|
||||
|
||||
def __getitem__(self, uuid: UUID) -> BaseTask:
|
||||
with self.lock:
|
||||
if uuid not in self.pool:
|
||||
raise ClanError(f"Task with uuid {uuid} does not exist")
|
||||
return self.pool[uuid]
|
||||
|
||||
def __setitem__(self, uuid: UUID, task: BaseTask) -> None:
|
||||
with self.lock:
|
||||
if uuid in self.pool:
|
||||
raise KeyError(f"Task with uuid {uuid} already exists")
|
||||
if type(uuid) is not UUID:
|
||||
raise TypeError("uuid must be of type UUID")
|
||||
self.pool[uuid] = task
|
||||
|
||||
|
||||
POOL: TaskPool = TaskPool()
|
||||
|
||||
|
||||
@deal.raises(ClanError)
|
||||
def get_task(uuid: UUID) -> BaseTask:
|
||||
global POOL
|
||||
return POOL[uuid]
|
||||
|
||||
|
||||
T = TypeVar("T", bound="BaseTask")
|
||||
|
||||
|
||||
@deal.raises(ClanError)
|
||||
def create_task(task_type: type[T], *args: Any) -> T:
|
||||
global POOL
|
||||
|
||||
# check if task_type is a callable
|
||||
if not callable(task_type):
|
||||
raise ClanError("task_type must be callable")
|
||||
uuid = uuid4()
|
||||
|
||||
task = task_type(uuid, *args)
|
||||
POOL[uuid] = task
|
||||
threading.Thread(target=task._run).start()
|
||||
return task
|
@ -1,19 +1,22 @@
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from uuid import UUID
|
||||
from typing import IO
|
||||
|
||||
from ..dirs import module_root
|
||||
from ..errors import ClanError
|
||||
from ..nix import nix_build, nix_config, nix_eval, nix_shell
|
||||
from ..task_manager import BaseTask, Command, create_task
|
||||
from .inspect import VmConfig, inspect_vm
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def qemu_command(
|
||||
vm: VmConfig,
|
||||
@ -87,162 +90,189 @@ def qemu_command(
|
||||
return command
|
||||
|
||||
|
||||
class BuildVmTask(BaseTask):
|
||||
def __init__(self, uuid: UUID, vm: VmConfig, nix_options: list[str] = []) -> None:
|
||||
super().__init__(uuid, num_cmds=7)
|
||||
self.vm = vm
|
||||
self.nix_options = nix_options
|
||||
def get_vm_create_info(vm: VmConfig, nix_options: list[str]) -> dict[str, str]:
|
||||
config = nix_config()
|
||||
system = config["system"]
|
||||
|
||||
def get_vm_create_info(self, cmds: Iterator[Command]) -> dict[str, str]:
|
||||
config = nix_config()
|
||||
system = config["system"]
|
||||
|
||||
clan_dir = self.vm.flake_url
|
||||
machine = self.vm.flake_attr
|
||||
cmd = next(cmds)
|
||||
cmd.run(
|
||||
nix_build(
|
||||
[
|
||||
f'{clan_dir}#clanInternals.machines."{system}"."{machine}".config.system.clan.vm.create',
|
||||
*self.nix_options,
|
||||
]
|
||||
),
|
||||
name="buildvm",
|
||||
clan_dir = vm.flake_url
|
||||
machine = vm.flake_attr
|
||||
cmd = nix_build(
|
||||
[
|
||||
f'{clan_dir}#clanInternals.machines."{system}"."{machine}".config.system.clan.vm.create',
|
||||
*nix_options,
|
||||
]
|
||||
)
|
||||
proc = subprocess.run(
|
||||
cmd,
|
||||
check=False,
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
raise ClanError(
|
||||
f"Failed to build vm config: {shlex.join(cmd)} failed with: {proc.returncode}"
|
||||
)
|
||||
vm_json = "".join(cmd.stdout).strip()
|
||||
self.log.debug(f"VM JSON path: {vm_json}")
|
||||
with open(vm_json) as f:
|
||||
return json.load(f)
|
||||
try:
|
||||
return json.loads(Path(proc.stdout.strip()).read_text())
|
||||
except json.JSONDecodeError as e:
|
||||
raise ClanError(f"Failed to parse vm config: {e}")
|
||||
|
||||
def get_clan_name(self, cmds: Iterator[Command]) -> str:
|
||||
clan_dir = self.vm.flake_url
|
||||
cmd = next(cmds)
|
||||
cmd.run(
|
||||
nix_eval([f"{clan_dir}#clanInternals.clanName"]) + self.nix_options,
|
||||
name="clanname",
|
||||
|
||||
def get_clan_name(vm: VmConfig, nix_options: list[str]) -> str:
|
||||
clan_dir = vm.flake_url
|
||||
cmd = nix_eval([f"{clan_dir}#clanInternals.clanName"]) + nix_options
|
||||
proc = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
check=False,
|
||||
text=True,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
raise ClanError(
|
||||
f"Failed to get clan name: {shlex.join(cmd)} failed with: {proc.returncode}"
|
||||
)
|
||||
clan_name = cmd.stdout[0].strip().strip('"')
|
||||
return clan_name
|
||||
|
||||
def run(self) -> None:
|
||||
cmds = self.commands()
|
||||
|
||||
machine = self.vm.flake_attr
|
||||
self.log.debug(f"Creating VM for {machine}")
|
||||
|
||||
# TODO: We should get this from the vm argument
|
||||
nixos_config = self.get_vm_create_info(cmds)
|
||||
clan_name = self.get_clan_name(cmds)
|
||||
|
||||
self.log.debug(f"Building VM for clan name: {clan_name}")
|
||||
|
||||
flake_dir = Path(self.vm.flake_url)
|
||||
flake_dir.mkdir(exist_ok=True)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir_:
|
||||
tmpdir = Path(tmpdir_)
|
||||
xchg_dir = tmpdir / "xchg"
|
||||
xchg_dir.mkdir(exist_ok=True)
|
||||
secrets_dir = tmpdir / "secrets"
|
||||
secrets_dir.mkdir(exist_ok=True)
|
||||
disk_img = tmpdir / "disk.img"
|
||||
spice_socket = tmpdir / "spice.sock"
|
||||
|
||||
env = os.environ.copy()
|
||||
env["CLAN_DIR"] = str(self.vm.flake_url)
|
||||
|
||||
env["PYTHONPATH"] = str(
|
||||
":".join(sys.path)
|
||||
) # TODO do this in the clanCore module
|
||||
env["SECRETS_DIR"] = str(secrets_dir)
|
||||
|
||||
# Only generate secrets for local clans
|
||||
if isinstance(self.vm.flake_url, Path) and self.vm.flake_url.is_dir():
|
||||
cmd = next(cmds)
|
||||
if Path(self.vm.flake_url).is_dir():
|
||||
cmd.run(
|
||||
[nixos_config["generateSecrets"], clan_name],
|
||||
env=env,
|
||||
name="generateSecrets",
|
||||
)
|
||||
else:
|
||||
self.log.warning("won't generate secrets for non local clan")
|
||||
|
||||
cmd = next(cmds)
|
||||
cmd.run(
|
||||
[nixos_config["uploadSecrets"]],
|
||||
env=env,
|
||||
name="uploadSecrets",
|
||||
)
|
||||
|
||||
cmd = next(cmds)
|
||||
cmd.run(
|
||||
nix_shell(
|
||||
["qemu"],
|
||||
[
|
||||
"qemu-img",
|
||||
"create",
|
||||
"-f",
|
||||
"raw",
|
||||
str(disk_img),
|
||||
"1024M",
|
||||
],
|
||||
),
|
||||
name="createDisk",
|
||||
)
|
||||
|
||||
cmd = next(cmds)
|
||||
cmd.run(
|
||||
nix_shell(
|
||||
["e2fsprogs"],
|
||||
[
|
||||
"mkfs.ext4",
|
||||
"-L",
|
||||
"nixos",
|
||||
str(disk_img),
|
||||
],
|
||||
),
|
||||
name="formatDisk",
|
||||
)
|
||||
|
||||
cmd = next(cmds)
|
||||
|
||||
qemu_cmd = qemu_command(
|
||||
self.vm,
|
||||
nixos_config,
|
||||
xchg_dir=xchg_dir,
|
||||
secrets_dir=secrets_dir,
|
||||
disk_img=disk_img,
|
||||
spice_socket=spice_socket,
|
||||
)
|
||||
|
||||
print("$ " + shlex.join(qemu_cmd))
|
||||
packages = ["qemu"]
|
||||
if self.vm.graphics:
|
||||
packages.append("virt-viewer")
|
||||
|
||||
env = os.environ.copy()
|
||||
remote_viewer_mimetypes = module_root() / "vms" / "mimetypes"
|
||||
env[
|
||||
"XDG_DATA_DIRS"
|
||||
] = f"{remote_viewer_mimetypes}:{env.get('XDG_DATA_DIRS', '')}"
|
||||
print(env["XDG_DATA_DIRS"])
|
||||
cmd.run(nix_shell(packages, qemu_cmd), name="qemu", env=env)
|
||||
return proc.stdout.strip().strip('"')
|
||||
|
||||
|
||||
def run_vm(
|
||||
vm: VmConfig, nix_options: list[str] = [], env: dict[str, str] = {}
|
||||
) -> BuildVmTask:
|
||||
return create_task(BuildVmTask, vm, nix_options)
|
||||
vm: VmConfig, nix_options: list[str] = [], log_fd: IO[str] | None = None
|
||||
) -> None:
|
||||
"""
|
||||
log_fd can be used to stream the output of all commands to a UI
|
||||
"""
|
||||
machine = vm.flake_attr
|
||||
log.debug(f"Creating VM for {machine}")
|
||||
|
||||
# TODO: We should get this from the vm argument
|
||||
nixos_config = get_vm_create_info(vm, nix_options)
|
||||
clan_name = get_clan_name(vm, nix_options)
|
||||
|
||||
log.debug(f"Building VM for clan name: {clan_name}")
|
||||
|
||||
flake_dir = Path(vm.flake_url)
|
||||
flake_dir.mkdir(exist_ok=True)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir_:
|
||||
tmpdir = Path(tmpdir_)
|
||||
xchg_dir = tmpdir / "xchg"
|
||||
xchg_dir.mkdir(exist_ok=True)
|
||||
secrets_dir = tmpdir / "secrets"
|
||||
secrets_dir.mkdir(exist_ok=True)
|
||||
disk_img = tmpdir / "disk.img"
|
||||
spice_socket = tmpdir / "spice.sock"
|
||||
|
||||
env = os.environ.copy()
|
||||
env["CLAN_DIR"] = str(vm.flake_url)
|
||||
|
||||
env["PYTHONPATH"] = str(
|
||||
":".join(sys.path)
|
||||
) # TODO do this in the clanCore module
|
||||
env["SECRETS_DIR"] = str(secrets_dir)
|
||||
|
||||
# Only generate secrets for local clans
|
||||
if isinstance(vm.flake_url, Path) and vm.flake_url.is_dir():
|
||||
if Path(vm.flake_url).is_dir():
|
||||
subprocess.run(
|
||||
[nixos_config["generateSecrets"], clan_name],
|
||||
env=env,
|
||||
check=False,
|
||||
stdout=log_fd,
|
||||
stderr=log_fd,
|
||||
)
|
||||
else:
|
||||
log.warning("won't generate secrets for non local clan")
|
||||
|
||||
cmd = [nixos_config["uploadSecrets"]]
|
||||
res = subprocess.run(
|
||||
cmd,
|
||||
env=env,
|
||||
check=False,
|
||||
stdout=log_fd,
|
||||
stderr=log_fd,
|
||||
)
|
||||
if res.returncode != 0:
|
||||
raise ClanError(
|
||||
f"Failed to upload secrets: {shlex.join(cmd)} failed with {res.returncode}"
|
||||
)
|
||||
|
||||
cmd = nix_shell(
|
||||
["qemu"],
|
||||
[
|
||||
"qemu-img",
|
||||
"create",
|
||||
"-f",
|
||||
"raw",
|
||||
str(disk_img),
|
||||
"1024M",
|
||||
],
|
||||
)
|
||||
res = subprocess.run(
|
||||
cmd,
|
||||
check=False,
|
||||
stdout=log_fd,
|
||||
stderr=log_fd,
|
||||
)
|
||||
if res.returncode != 0:
|
||||
raise ClanError(
|
||||
f"Failed to create disk image: {shlex.join(cmd)} failed with {res.returncode}"
|
||||
)
|
||||
|
||||
cmd = nix_shell(
|
||||
["e2fsprogs"],
|
||||
[
|
||||
"mkfs.ext4",
|
||||
"-L",
|
||||
"nixos",
|
||||
str(disk_img),
|
||||
],
|
||||
)
|
||||
res = subprocess.run(
|
||||
cmd,
|
||||
check=False,
|
||||
stdout=log_fd,
|
||||
stderr=log_fd,
|
||||
)
|
||||
if res.returncode != 0:
|
||||
raise ClanError(
|
||||
f"Failed to create ext4 filesystem: {shlex.join(cmd)} failed with {res.returncode}"
|
||||
)
|
||||
|
||||
qemu_cmd = qemu_command(
|
||||
vm,
|
||||
nixos_config,
|
||||
xchg_dir=xchg_dir,
|
||||
secrets_dir=secrets_dir,
|
||||
disk_img=disk_img,
|
||||
spice_socket=spice_socket,
|
||||
)
|
||||
|
||||
print("$ " + shlex.join(qemu_cmd))
|
||||
packages = ["qemu"]
|
||||
if vm.graphics:
|
||||
packages.append("virt-viewer")
|
||||
|
||||
env = os.environ.copy()
|
||||
remote_viewer_mimetypes = module_root() / "vms" / "mimetypes"
|
||||
env[
|
||||
"XDG_DATA_DIRS"
|
||||
] = f"{remote_viewer_mimetypes}:{env.get('XDG_DATA_DIRS', '')}"
|
||||
print(env["XDG_DATA_DIRS"])
|
||||
res = subprocess.run(
|
||||
nix_shell(packages, qemu_cmd),
|
||||
env=env,
|
||||
check=False,
|
||||
stdout=log_fd,
|
||||
stderr=log_fd,
|
||||
)
|
||||
if res.returncode != 0:
|
||||
raise ClanError(f"qemu failed with {res.returncode}")
|
||||
|
||||
|
||||
def run_command(args: argparse.Namespace) -> None:
|
||||
flake_url = args.flake_url or args.flake
|
||||
vm = asyncio.run(inspect_vm(flake_url=flake_url, flake_attr=args.machine))
|
||||
|
||||
task = run_vm(vm, args.option)
|
||||
for line in task.log_lines():
|
||||
print(line, end="")
|
||||
run_vm(vm, args.option)
|
||||
|
||||
|
||||
def register_run_parser(parser: argparse.ArgumentParser) -> None:
|
||||
|
@ -3,7 +3,6 @@ from enum import Enum
|
||||
from pydantic import BaseModel, Extra, Field
|
||||
|
||||
from ..async_cmd import CmdOut
|
||||
from ..task_manager import TaskStatus
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
@ -47,15 +46,6 @@ class VerifyMachineResponse(BaseModel):
|
||||
error: str | None
|
||||
|
||||
|
||||
class VmStatusResponse(BaseModel):
|
||||
error: str | None
|
||||
status: TaskStatus
|
||||
|
||||
|
||||
class VmCreateResponse(BaseModel):
|
||||
uuid: str
|
||||
|
||||
|
||||
class FlakeAttrResponse(BaseModel):
|
||||
flake_attrs: list[str]
|
||||
|
||||
|
@ -1,16 +1,6 @@
|
||||
import deal
|
||||
|
||||
from clan_cli import nix, task_manager
|
||||
|
||||
|
||||
@deal.cases(task_manager.get_task)
|
||||
def test_get_task(case: deal.TestCase) -> None:
|
||||
case()
|
||||
|
||||
|
||||
@deal.cases(task_manager.create_task)
|
||||
def test_create_task(case: deal.TestCase) -> None:
|
||||
case()
|
||||
from clan_cli import nix
|
||||
|
||||
|
||||
@deal.cases(nix.nix_command)
|
||||
|
@ -7,7 +7,7 @@
|
||||
./theme/flake-module.nix
|
||||
];
|
||||
|
||||
perSystem = { pkgs, config, ... }: {
|
||||
perSystem = { pkgs, config, lib, ... }: {
|
||||
packages = {
|
||||
tea-create-pr = pkgs.callPackage ./tea-create-pr { };
|
||||
zerotier-members = pkgs.callPackage ./zerotier-members { };
|
||||
@ -18,6 +18,17 @@
|
||||
nix-unit = pkgs.callPackage ./nix-unit { };
|
||||
meshname = pkgs.callPackage ./meshname { };
|
||||
inherit (pkgs.callPackages ./node-packages { }) prettier-plugin-tailwindcss;
|
||||
} // lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
aemu = pkgs.callPackage ./aemu { };
|
||||
gfxstream = pkgs.callPackage ./gfxstream {
|
||||
inherit (config.packages) aemu;
|
||||
};
|
||||
rutabaga-gfx-ffi = pkgs.callPackage ./rutabaga-gfx-ffi {
|
||||
inherit (config.packages) gfxstream aemu;
|
||||
};
|
||||
qemu-wayland = pkgs.callPackage ./qemu-wayland {
|
||||
inherit (config.packages) rutabaga-gfx-ffi;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
47
pkgs/gfxstream/default.nix
Normal file
47
pkgs/gfxstream/default.nix
Normal file
@ -0,0 +1,47 @@
|
||||
{ clangStdenv
|
||||
, fetchgit
|
||||
, aemu
|
||||
, meson
|
||||
, pkg-config
|
||||
, ninja
|
||||
, python3
|
||||
, vulkan-headers
|
||||
, vulkan-utility-libraries
|
||||
, glm
|
||||
, libglvnd
|
||||
, xorg
|
||||
}:
|
||||
|
||||
clangStdenv.mkDerivation {
|
||||
pname = "gfxstream";
|
||||
version = "unstable-2023-11-29";
|
||||
src = fetchgit {
|
||||
url = "https://android.googlesource.com/platform/hardware/google/gfxstream";
|
||||
rev = "45c27965ee5121651946f54a42b3297b26047955";
|
||||
hash = "sha256-nJVVePNro+sL7jC+ehe5Am2jWo9BK6H1AUSzoP7J1ss=";
|
||||
};
|
||||
postPatch = ''
|
||||
ln common/etc/etc.cpp host/compressedTextureFormats/etc.cpp
|
||||
ln common/etc/etc.cpp host/gl/glestranslator/GLcommon/etc.cpp
|
||||
'';
|
||||
preConfigure = ''
|
||||
export NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -I$(pwd)/common/etc/include"
|
||||
'';
|
||||
buildInputs = [
|
||||
aemu
|
||||
glm
|
||||
libglvnd
|
||||
vulkan-headers
|
||||
vulkan-utility-libraries
|
||||
xorg.libX11
|
||||
];
|
||||
mesonFlags = [
|
||||
"-Ddecoders=gles,vulkan,composer"
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
pkg-config
|
||||
ninja
|
||||
python3
|
||||
];
|
||||
}
|
15
pkgs/qemu-wayland/default.nix
Normal file
15
pkgs/qemu-wayland/default.nix
Normal file
@ -0,0 +1,15 @@
|
||||
{ qemu_kvm, rutabaga-gfx-ffi, fetchurl, lib, vulkan-loader }:
|
||||
qemu_kvm.overrideAttrs (old: {
|
||||
src = fetchurl {
|
||||
url = "https://download.qemu.org/qemu-8.2.0-rc2.tar.xz";
|
||||
hash = "sha256-AbQozd8IQNDBsA6/zE98xQboh4dWSk0/V/IsflCju9g=";
|
||||
};
|
||||
|
||||
postFixup = (old.postFixup or "") + ''
|
||||
for bin in $out/bin/qemu-system-*; do
|
||||
wrapProgram $bin \
|
||||
--prefix LD_LIBRARY_PATH ':' ${lib.getLib vulkan-loader}/lib
|
||||
done
|
||||
'';
|
||||
buildInputs = old.buildInputs ++ [ rutabaga-gfx-ffi ];
|
||||
})
|
222
pkgs/rutabaga-gfx-ffi/Cargo.lock
generated
Normal file
222
pkgs/rutabaga-gfx-ffi/Cargo.lock
generated
Normal file
@ -0,0 +1,222 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remain"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bce3a7139d2ee67d07538ee5dba997364fbc243e7e7143e96eb830c74bfaa082"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rutabaga_gfx"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "450c21b372f2bc0adafa01a5293a5b8ed2f1b691b373a97a9c60367e75c07b6d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"log",
|
||||
"nix",
|
||||
"pkg-config",
|
||||
"remain",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rutabaga_gfx_ffi"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rutabaga_gfx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96f8f25c15a0edc9b07eb66e7e6e97d124c0505435c382fde1ab7ceb188aa956"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "855e0f6af9cd72b87d8a6c586f3cb583f5cdcc62c2c80869d8cd7e96fdf7ee20"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
34
pkgs/rutabaga-gfx-ffi/default.nix
Normal file
34
pkgs/rutabaga-gfx-ffi/default.nix
Normal file
@ -0,0 +1,34 @@
|
||||
{ aemu
|
||||
, rustPlatform
|
||||
, fetchFromGitHub
|
||||
, pkg-config
|
||||
, gfxstream
|
||||
, libdrm
|
||||
}:
|
||||
|
||||
rustPlatform.buildRustPackage {
|
||||
pname = "rutabaga_gfx_ffi";
|
||||
version = "unstable-2023-12-05";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "google";
|
||||
repo = "crosvm";
|
||||
rev = "a10c83864e1d6e47773ca06e47ada4f888b30d82";
|
||||
hash = "sha256-Dd0oCgCL5LNxDuOJ6hyCXeqGyKBP0AqKamQTKXqNcjk=";
|
||||
fetchSubmodules = true;
|
||||
};
|
||||
|
||||
buildPhase = ''
|
||||
cd rutabaga_gfx/ffi
|
||||
make build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
make install prefix=$out
|
||||
'';
|
||||
|
||||
cargoHash = "sha256-oh49o/WjfT9xsQH4SUtFwNl6H3pX5Wio3FzKw+slJcQ=";
|
||||
|
||||
nativeBuildInputs = [ pkg-config ];
|
||||
buildInputs = [ gfxstream aemu libdrm ];
|
||||
}
|
Loading…
Reference in New Issue
Block a user