1use super::ext;
2use once_cell::sync::Lazy;
3use std::{
4 collections::HashSet,
5 ffi::{OsStr, OsString},
6 path::{Path, PathBuf},
7 process::Command,
8 sync::Mutex,
9};
10
11ext!(def; Qemu);
12
13static SEARCH_DIRS: Lazy<Mutex<HashSet<PathBuf>>> = Lazy::new(|| {
14 Mutex::new(if cfg!(target_os = "windows") {
15 HashSet::from_iter([PathBuf::from(r"C:\Program Files\qemu")])
16 } else {
17 HashSet::new()
18 })
19});
20
21impl Qemu {
22 #[inline]
23 pub fn search_at(path: impl AsRef<Path>) {
24 SEARCH_DIRS
25 .lock()
26 .unwrap()
27 .insert(path.as_ref().to_path_buf());
28 }
29
30 #[inline]
31 fn find(name: impl AsRef<OsStr>) -> Self {
32 Self(Command::new(Self::find_qemu(OsString::from_iter([
33 OsStr::new("qemu-"),
34 name.as_ref(),
35 ]))))
36 }
37
38 #[inline]
39 pub fn system(arch: impl AsRef<OsStr>) -> Self {
40 Self::find(OsString::from_iter([OsStr::new("system-"), arch.as_ref()]))
41 }
42
43 #[inline]
44 pub fn img() -> Self {
45 Self::find("img")
46 }
47
48 fn find_qemu(mut name: OsString) -> OsString {
49 #[cfg(target_os = "windows")]
50 name.push(OsStr::new(".exe"));
51 SEARCH_DIRS
52 .lock()
53 .unwrap()
54 .iter()
55 .map(|dir| dir.join(&name))
56 .find(|path| path.is_file())
57 .map_or(name, |p| p.into_os_string())
58 }
59}