1use std::{fmt, process::Command};
2
3#[derive(Debug)]
4pub struct Target {
5 arch: String,
6 os: String,
7}
8
9impl Target {
10 pub fn current() -> anyhow::Result<Self> {
11 let arch = command_output("uname", &["-m"])?;
12 let mut os = command_output("uname", &["-s"])?.to_lowercase();
13
14 if os == "darwin" {
15 let version = command_output("sw_vers", &["--productVersion"])?;
16 let major_version = version.split('.').next().unwrap();
17 match major_version {
18 "13" => os = "ventura".to_owned(),
19 "14" => os = "sonoma".to_owned(),
20 "15" => os = "sequoia".to_owned(),
21 "16" => os = "cheer".to_owned(),
22 _ => anyhow::bail!("Unsupported macOS version: {version}"),
23 }
24 }
25
26 Ok(Target { arch, os })
27 }
28
29 pub fn current_str() -> anyhow::Result<&'static str> {
30 let target = cache!(String).get_or_init(|| {
31 let target = Target::current()?;
32 Ok(target.to_string())
33 })?;
34 Ok(target)
35 }
36}
37
38impl fmt::Display for Target {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 write!(f, "{}_{}", self.arch, self.os)
41 }
42}
43
44fn command_output(command: &str, args: &[&str]) -> anyhow::Result<String> {
45 let bytes = Command::new(command).args(args).output()?.stdout;
46 let mut output = String::from_utf8(bytes)?;
47
48 while output.chars().last().unwrap().is_whitespace() {
49 output.pop();
50 }
51
52 Ok(output)
53}