waterui_cli/toolchain/
meson.rs1use std::path::PathBuf;
4
5use crate::{
6 brew::Brew,
7 toolchain::{Host, Installation, Toolchain, ToolchainError},
8 utils::CommandError,
9};
10
11#[derive(Debug, Clone, Default)]
13pub struct Meson;
14
15impl Meson {
16 pub async fn path(&self, host: &Host) -> Result<PathBuf, which::Error> {
21 host.which("meson").await
22 }
23}
24
25impl Toolchain for Meson {
26 type Installation = MesonInstallation;
27
28 async fn check(&self, host: &Host) -> Result<(), ToolchainError<Self::Installation>> {
29 if host.which("meson").await.is_ok() {
30 Ok(())
31 } else {
32 Err(ToolchainError::fixable(MesonInstallation))
33 }
34 }
35}
36
37#[derive(Debug, Clone)]
39pub struct MesonInstallation;
40
41#[derive(Debug, thiserror::Error)]
43pub enum FailToInstallMeson {
44 #[error("Homebrew not found. Please install Homebrew to proceed.")]
46 BrewNotFound,
47 #[error("Failed to install meson via Homebrew: {0}")]
49 BrewInstall(#[from] CommandError),
50 #[error(
52 "Automatic installation of meson is not supported on this platform. Please install meson manually."
53 )]
54 UnsupportedPlatform,
55}
56
57impl Installation for MesonInstallation {
58 type Error = FailToInstallMeson;
59
60 async fn install(&self, host: &Host) -> Result<(), Self::Error> {
61 if cfg!(target_os = "macos") {
62 let brew = Brew::default();
63 brew.check(host)
64 .await
65 .map_err(|_| FailToInstallMeson::BrewNotFound)?;
66 brew.install(host, "meson").await?;
67 Ok(())
68 } else {
69 Err(FailToInstallMeson::UnsupportedPlatform)
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::{Meson, MesonInstallation};
77 use crate::toolchain::testing::TestMachine;
78 use crate::toolchain::{Installation, Toolchain, ToolchainError};
79
80 #[test]
81 fn ok_when_meson_on_path() {
82 let machine = TestMachine::new();
83 machine.install("meson");
84 let host = machine.host(Vec::<(String, String)>::new());
85 smol::block_on(Meson.check(&host)).expect("meson on PATH must be ok");
86 }
87
88 #[test]
89 fn missing_meson_is_fixable() {
90 let machine = TestMachine::new();
91 let host = machine.host(Vec::<(String, String)>::new());
92 let result = smol::block_on(Meson.check(&host));
93 assert!(
94 matches!(result, Err(ToolchainError::Fixable(_))),
95 "missing meson must always be fixable: {result:?}"
96 );
97 }
98
99 #[test]
100 #[cfg(target_os = "macos")]
101 fn install_runs_brew() {
102 let machine = TestMachine::new();
103 machine.install("brew");
104 let host = machine.host(Vec::<(String, String)>::new());
105 smol::block_on(MesonInstallation.install(&host))
106 .expect("brew install meson must succeed on a host that provides brew");
107 }
108
109 #[test]
110 #[cfg(not(target_os = "macos"))]
111 fn install_fails_off_macos() {
112 let machine = TestMachine::new();
113 let host = machine.host(Vec::<(String, String)>::new());
114 let result = smol::block_on(MesonInstallation.install(&host));
115 assert!(
116 matches!(result, Err(super::FailToInstallMeson::UnsupportedPlatform)),
117 "meson install must fail fast outside macOS: {result:?}"
118 );
119 }
120}