waterui_cli/dependencies/
brew.rs1use crate::{
4 toolchain::{Host, Installation, Toolchain, ToolchainError},
5 utils::CommandError,
6};
7
8#[derive(Debug, Default)]
10pub struct Brew {}
11
12impl Brew {
13 pub async fn install(&self, host: &Host, name: &str) -> Result<(), CommandError> {
22 host.run("brew", ["install", name]).await?;
23 Ok(())
24 }
25
26 pub async fn install_cask(&self, host: &Host, cask: &str) -> Result<(), CommandError> {
35 host.run("brew", ["install", "--cask", cask]).await?;
36 Ok(())
37 }
38}
39
40impl Toolchain for Brew {
41 type Installation = BrewInstallation;
42 async fn check(
43 &self,
44 host: &Host,
45 ) -> Result<(), crate::toolchain::ToolchainError<Self::Installation>> {
46 if host.which("brew").await.is_ok() {
47 Ok(())
48 } else if cfg!(target_os = "macos") {
49 Err(ToolchainError::fixable(BrewInstallation))
50 } else {
51 Err(ToolchainError::unfixable(
52 "Homebrew is only supported on macOS",
53 "Why did you try to use Homebrew on a non-macOS system?",
54 ))
55 }
56 }
57}
58
59#[derive(Debug)]
63pub struct BrewInstallation;
64
65impl Installation for BrewInstallation {
66 type Error = CommandError;
67
68 async fn install(&self, host: &Host) -> Result<(), Self::Error> {
69 host.run(
70 "sh",
71 [
72 "-c",
73 "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)",
74 ],
75 )
76 .await?;
77 Ok(())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::Brew;
84 use crate::toolchain::testing::TestMachine;
85 use crate::toolchain::{Toolchain, ToolchainError};
86
87 #[test]
88 fn ok_when_brew_on_path() {
89 let machine = TestMachine::new();
90 machine.install("brew");
91 let host = machine.host(Vec::<(String, String)>::new());
92 smol::block_on(Brew::default().check(&host)).expect("brew on PATH must be ok");
93 }
94
95 #[test]
96 fn missing_brew_classification_is_platform_scoped() {
97 let machine = TestMachine::new();
98 let host = machine.host(Vec::<(String, String)>::new());
99 let result = smol::block_on(Brew::default().check(&host));
100 if cfg!(target_os = "macos") {
101 assert!(
102 matches!(result, Err(ToolchainError::Fixable(_))),
103 "missing brew on macOS must be fixable: {result:?}"
104 );
105 } else {
106 assert!(
107 matches!(result, Err(ToolchainError::Unfixable(_))),
108 "brew off macOS must be unfixable: {result:?}"
109 );
110 }
111 }
112
113 #[test]
114 fn install_runs_brew_install() {
115 let machine = TestMachine::new();
116 machine.install("brew");
117 let host = machine.host(Vec::<(String, String)>::new());
118 smol::block_on(Brew::default().install(&host, "cmake"))
119 .expect("brew install must succeed against the fake tool");
120 smol::block_on(Brew::default().install_cask(&host, "android-studio"))
121 .expect("brew install --cask must succeed against the fake tool");
122 }
123}