brew-bundle
change ssouvpwzzsuutxlzrqsqqtmluoqnlpzu
commit 233bf6479abb5e21b2602efdca9d4147d3c6b071
author Alpha Chen <alpha@kejadlen.dev>
date
parent xysswmxw
diff --git a/frork-cli/src/assertions.rs b/frork-cli/src/assertions.rs
index d6db6a0..95c0387 100644
--- a/frork-cli/src/assertions.rs
+++ b/frork-cli/src/assertions.rs
@@ -468,3 +468,92 @@ impl AssertionType for Brew {
         Ok(())
     }
 }
+
+pub struct BrewBundle {
+    pub brewfile: ExpandedPath,
+}
+
+impl FromLuaMulti for BrewBundle {
+    fn from_lua_multi(args: LuaMultiValue, lua: &Lua) -> LuaResult<Self> {
+        let brewfile = ExpandedPath::from_lua_multi(args, lua)?;
+        Ok(Self { brewfile })
+    }
+}
+
+impl std::fmt::Display for BrewBundle {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "brew-bundle {}", self.brewfile)
+    }
+}
+
+impl AssertionType for BrewBundle {
+    fn status(&self) -> Result<Status> {
+        // Assert platform is Darwin (macOS)
+        #[cfg(not(target_os = "macos"))]
+        return Err(eyre!("brew-bundle only supported on Darwin/macOS"));
+
+        // Assert brew binary exists
+        Utils::assert_bin("brew")?;
+
+        // First check: brew bundle check --no-upgrade
+        let (_output, exit_code) = Utils::sh_with_envs(
+            "brew",
+            &[
+                "bundle".to_string(),
+                "check".to_string(),
+                "--no-upgrade".to_string(),
+                format!("--file={}", self.brewfile),
+            ],
+            &[("HOMEBREW_NO_AUTO_UPDATE", "true")],
+        )?;
+
+        if exit_code != 0 {
+            return Ok(Status::Missing);
+        }
+
+        // Second check: brew bundle check (without --no-upgrade)
+        let (_output, exit_code) = Utils::sh_with_envs(
+            "brew",
+            &[
+                "bundle".to_string(),
+                "check".to_string(),
+                format!("--file={}", self.brewfile),
+            ],
+            &[("HOMEBREW_NO_AUTO_UPDATE", "true")],
+        )?;
+
+        if exit_code != 0 {
+            return Ok(Status::ConflictUpgrade(Conflict {
+                expected: "up-to-date packages".to_string(),
+                actual: "packages need upgrade".to_string(),
+            }));
+        }
+
+        Ok(Status::Ok)
+    }
+
+    fn install(&self) -> Result<()> {
+        // Assert platform is Darwin (macOS)
+        #[cfg(not(target_os = "macos"))]
+        return Err(eyre!("brew-bundle only supported on Darwin/macOS"));
+
+        // Assert brew binary exists
+        Utils::assert_bin("brew")?;
+
+        let (_output, exit_code) = Utils::sh(
+            "brew",
+            &[
+                "bundle".to_string(),
+                "install".to_string(),
+                format!("--file={}", self.brewfile),
+            ],
+        )?;
+
+        if exit_code != 0 {
+            return Err(eyre!("Failed to install brew bundle"));
+        }
+
+        debug!("installed: {}", self);
+        Ok(())
+    }
+}
diff --git a/frork-cli/src/main.rs b/frork-cli/src/main.rs
index 5428a8f..a6d7486 100644
--- a/frork-cli/src/main.rs
+++ b/frork-cli/src/main.rs
@@ -3,7 +3,7 @@ mod errors;
 mod utils;
 
 use assertions::{
-    AssertionType, AssertionTypeFactory, Brew, Debug, Directory, Git, LuaAssertion, LuaAssertionType,
+    AssertionType, AssertionTypeFactory, Brew, BrewBundle, Debug, Directory, Git, LuaAssertion, LuaAssertionType,
     Status, Symlink, TypedFactory,
 };
 use clap::{Parser, Subcommand};
@@ -70,6 +70,7 @@ impl Registry {
         // Return factory for built-in types
         match assertion_type {
             "brew" => Ok(Box::new(TypedFactory::<Brew>::new())),
+            "brew-bundle" => Ok(Box::new(TypedFactory::<BrewBundle>::new())),
             "debug" => Ok(Box::new(TypedFactory::<Debug>::new())),
             "directory" => Ok(Box::new(TypedFactory::<Directory>::new())),
             "git" => Ok(Box::new(TypedFactory::<Git>::new())),
diff --git a/frork-cli/src/utils.rs b/frork-cli/src/utils.rs
index b864998..79659a8 100644
--- a/frork-cli/src/utils.rs
+++ b/frork-cli/src/utils.rs
@@ -145,10 +145,17 @@ impl Utils {
     }
 
     pub fn sh(cmd: &str, args: &[String]) -> Result<(String, i32)> {
-        debug!("Executing command: {} with args: {:?}", cmd, args);
+        Self::sh_with_envs(cmd, args, &[])
+    }
+
+    pub fn sh_with_envs(cmd: &str, args: &[String], env_vars: &[(&str, &str)]) -> Result<(String, i32)> {
+        debug!("Executing command: {} with args: {:?} and envs: {:?}", cmd, args, env_vars);
+
+        let mut command = Command::new(cmd);
+        command.args(args);
+        command.envs(env_vars.iter().map(|(k, v)| (*k, *v)));
 
-        let output = Command::new(cmd)
-            .args(args)
+        let output = command
             .output()
             .map_err(|e| eyre!("Failed to execute command '{}': {}", cmd, e))?;