more from lua
change yluqvoxrzyulvsxukumzqnsvutwmluwq
commit f17b39cba43553496942cea30ad890c7b2870762
author Alpha Chen <alpha@kejadlen.dev>
date
parent loxssptx
diff --git a/src/main.rs b/src/main.rs
index 95f938a..6314bfd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -61,11 +61,66 @@ impl From<LuaError> for FrorkError {
     }
 }
 
+#[derive(Debug)]
+struct Conflict {
+    expected: String,
+    actual: String,
+}
+
+impl FromLua for Conflict {
+    fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> {
+        let table = LuaTable::from_lua(value, lua)?;
+        let expected: String = table.get("expected")?;
+        let actual: String = table.get("actual")?;
+        Ok(Conflict { expected, actual })
+    }
+}
+
 #[derive(Debug)]
 enum Status {
     Ok,
     Missing,
-    ConflictUpgrade,
+    ConflictUpgrade(Conflict),
+}
+
+impl FromLuaMulti for Status {
+    fn from_lua_multi(values: LuaMultiValue, lua: &Lua) -> LuaResult<Self> {
+        // Try two values: string and conflict for conflict-upgrade
+        if let Ok((status_str, conflict)) =
+            <(String, Conflict)>::from_lua_multi(values.clone(), lua)
+        {
+            return match status_str.as_str() {
+                "conflict-upgrade" => Ok(Status::ConflictUpgrade(conflict)),
+                _ => Err(LuaError::FromLuaConversionError {
+                    from: "multivalue",
+                    to: "Status".to_string(),
+                    message: Some(
+                        "String + conflict combination only supported for conflict-upgrade"
+                            .to_string(),
+                    ),
+                }),
+            };
+        }
+
+        // Try single string
+        if let Ok(status_str) = String::from_lua_multi(values, lua) {
+            return match status_str.as_str() {
+                "ok" => Ok(Status::Ok),
+                "missing" => Ok(Status::Missing),
+                _ => Err(LuaError::FromLuaConversionError {
+                    from: "string",
+                    to: "Status".to_string(),
+                    message: Some(format!("Invalid status string: '{}'", status_str)),
+                }),
+            };
+        }
+
+        Err(LuaError::FromLuaConversionError {
+            from: "multivalue",
+            to: "Status".to_string(),
+            message: Some("Expected single string or conflict-upgrade with table".to_string()),
+        })
+    }
 }
 
 trait AssertionType: std::fmt::Display {
@@ -80,17 +135,8 @@ struct LuaAssertionType {
 }
 
 impl FromLua for LuaAssertionType {
-    fn from_lua(value: LuaValue, _lua: &Lua) -> LuaResult<Self> {
-        let table = match value {
-            LuaValue::Table(table) => table,
-            _ => {
-                return Err(LuaError::FromLuaConversionError {
-                    from: value.type_name(),
-                    to: "LuaAssertionType".to_string(),
-                    message: Some("Expected a table".to_string()),
-                });
-            }
-        };
+    fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> {
+        let table = LuaTable::from_lua(value, lua)?;
 
         let display_fn: Option<LuaFunction> = table.get("display").ok();
         let status_fn: LuaFunction = table.get("status")?;
@@ -129,9 +175,15 @@ impl Registry {
 
         // Fall back to built-in types
         match assertion_type {
-            "debug" => Debug::new(args).map(|d| Box::new(d) as Box<dyn AssertionType>),
-            "directory" => Directory::new(args).map(|d| Box::new(d) as Box<dyn AssertionType>),
-            "symlink" => Symlink::new(args).map(|s| Box::new(s) as Box<dyn AssertionType>),
+            "debug" => Debug::from_lua_multi(args, &Lua::new())
+                .map(|d| Box::new(d) as Box<dyn AssertionType>)
+                .map_err(|e| FrorkError::from(e).into()),
+            "directory" => Directory::from_lua_multi(args, &Lua::new())
+                .map(|d| Box::new(d) as Box<dyn AssertionType>)
+                .map_err(|e| FrorkError::from(e).into()),
+            "symlink" => Symlink::from_lua_multi(args, &Lua::new())
+                .map(|s| Box::new(s) as Box<dyn AssertionType>)
+                .map_err(|e| FrorkError::from(e).into()),
             _ => Err(FrorkError::UnknownAssertionType {
                 assertion_type: assertion_type.to_string(),
             }
@@ -145,15 +197,9 @@ struct Symlink {
     source: String,
 }
 
-impl Symlink {
-    fn new(args: LuaMultiValue) -> Result<Self> {
-        let (target, source) =
-            <(String, String)>::from_lua_multi(args, &Lua::new()).map_err(|_| {
-                FrorkError::InvalidArguments(
-                    "Symlink requires exactly 2 string arguments".to_string(),
-                )
-            })?;
-
+impl FromLuaMulti for Symlink {
+    fn from_lua_multi(args: LuaMultiValue, lua: &Lua) -> LuaResult<Self> {
+        let (target, source) = <(String, String)>::from_lua_multi(args, lua)?;
         Ok(Self {
             target: Utils::expand_path(&target),
             source: Utils::expand_path(&source),
@@ -209,12 +255,9 @@ struct Directory {
     path: String,
 }
 
-impl Directory {
-    fn new(args: LuaMultiValue) -> Result<Self> {
-        let path = String::from_lua_multi(args, &Lua::new()).map_err(|_| {
-            FrorkError::InvalidArguments("Directory requires exactly 1 string argument".to_string())
-        })?;
-
+impl FromLuaMulti for Directory {
+    fn from_lua_multi(args: LuaMultiValue, lua: &Lua) -> LuaResult<Self> {
+        let path = String::from_lua_multi(args, lua)?;
         Ok(Self {
             path: Utils::expand_path(&path),
         })
@@ -255,15 +298,11 @@ struct Debug {
     install_fn: Option<LuaFunction>,
 }
 
-impl Debug {
-    fn new(args: LuaMultiValue) -> Result<Self> {
-        let table = LuaTable::from_lua_multi(args, &Lua::new()).map_err(|_| {
-            FrorkError::InvalidArguments("Debug requires exactly 1 table argument".to_string())
-        })?;
-
+impl FromLuaMulti for Debug {
+    fn from_lua_multi(args: LuaMultiValue, lua: &Lua) -> LuaResult<Self> {
+        let table = LuaTable::from_lua_multi(args, lua)?;
         let status_fn: Option<LuaFunction> = table.get("status").ok();
         let install_fn: Option<LuaFunction> = table.get("install").ok();
-
         Ok(Self {
             status_fn,
             install_fn,
@@ -281,14 +320,9 @@ impl AssertionType for Debug {
     fn status(&self) -> Result<Status> {
         if let Some(ref status_fn) = self.status_fn {
             let result = status_fn
-                .call::<String>(LuaMultiValue::new())
+                .call::<Status>(LuaMultiValue::new())
                 .map_err(|e| eyre!("Debug status function failed: {}", e))?;
-            match result.as_str() {
-                "ok" => Ok(Status::Ok),
-                "missing" => Ok(Status::Missing),
-                "conflict-upgrade" => Ok(Status::ConflictUpgrade),
-                _ => Err(eyre!("Invalid status returned: '{}'", result)),
-            }
+            Ok(result)
         } else {
             Ok(Status::Ok)
         }
@@ -363,14 +397,9 @@ impl AssertionType for LuaAssertion {
     fn status(&self) -> Result<Status> {
         let result = self
             .status_fn
-            .call::<String>(self.args.clone())
+            .call::<Status>(self.args.clone())
             .map_err(FrorkError::from)?;
-        match result.as_str() {
-            "ok" => Ok(Status::Ok),
-            "missing" => Ok(Status::Missing),
-            "conflict-upgrade" => Ok(Status::ConflictUpgrade),
-            _ => Err(eyre!("Invalid status returned: '{}'", result)),
-        }
+        Ok(result)
     }
 
     fn install(&self) -> Result<()> {
@@ -635,7 +664,11 @@ fn status(status: &Status, assertion: &dyn AssertionType) -> Result<()> {
     match status {
         Status::Ok => println!("ok: {}", assertion),
         Status::Missing => println!("missing: {}", assertion),
-        Status::ConflictUpgrade => println!("conflict (upgradable): {}", assertion),
+        Status::ConflictUpgrade(conflict) => {
+            println!("conflict (upgradable): {}", assertion);
+            println!("  expected: {}", conflict.expected);
+            println!("    actual: {}", conflict.actual);
+        }
     }
     Ok(())
 }
@@ -648,8 +681,12 @@ fn satisfy(status: &Status, assertion: &dyn AssertionType) -> Result<()> {
             assertion.install()?;
             println!("ok: {}", assertion);
         }
-        Status::ConflictUpgrade => {
-            todo!("Handle conflict upgrade status in satisfy");
+        Status::ConflictUpgrade(conflict) => {
+            todo!(
+                "Handle conflict upgrade status in satisfy: expected: {}, actual: {}",
+                conflict.expected,
+                conflict.actual
+            );
         }
     }
     Ok(())