sh
change wusptnkvkypmoxpmvnrkpqwszwmkyrpk
commit 677dd257f52993a14c7f4f0ab60402b1f0bd9352
author Alpha Chen <alpha@kejadlen.dev>
date
parent mnsrpvsx
diff --git a/src/main.rs b/src/main.rs
index 8a33347..92f17fa 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,6 +7,7 @@ use std::collections::HashMap;
 use std::env;
 use std::fs;
 use std::path::Path;
+use std::process::Command;
 use std::rc::Rc;
 use std::sync::LazyLock;
 use thiserror::Error;
@@ -440,6 +441,16 @@ where
 struct Utils;
 
 impl Utils {
+    fn chomp(s: &str) -> String {
+        s.trim_end_matches('\n').trim_end_matches('\r').to_string()
+    }
+
+    fn dirname(path: &str) -> Option<String> {
+        let expanded_path = Self::expand_path(path);
+        let parent = Path::new(&expanded_path).parent()?;
+        parent.to_str().map(|s| s.to_string())
+    }
+
     fn expand_path(path: &str) -> String {
         static ENV_VAR_REGEX: LazyLock<Regex> =
             LazyLock::new(|| Regex::new(r"\$([A-Za-z_][A-Za-z0-9_]*)").unwrap());
@@ -464,10 +475,24 @@ impl Utils {
         expanded
     }
 
-    fn dirname(path: &str) -> Option<String> {
-        let expanded_path = Self::expand_path(path);
-        let parent = Path::new(&expanded_path).parent()?;
-        parent.to_str().map(|s| s.to_string())
+    fn sh(cmd: &str, args: &[String]) -> Result<(String, i32)> {
+        debug!("Executing command: {} with args: {:?}", cmd, args);
+
+        let output = Command::new(cmd)
+            .args(args)
+            .output()
+            .map_err(|e| eyre!("Failed to execute command '{}': {}", cmd, e))?;
+
+        let stdout = String::from_utf8_lossy(&output.stdout).to_string();
+        let status = output
+            .status
+            .code()
+            .ok_or_else(|| eyre!("Command '{}' terminated by signal", cmd))?;
+        debug!(
+            "Command '{}' completed with status {}, stdout: {:?}",
+            cmd, status, stdout
+        );
+        Ok((stdout, status))
     }
 }
 
@@ -475,13 +500,40 @@ impl IntoLua for Utils {
     fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
         let utils_table = lua.create_table()?;
 
-        let expand_path_fn =
-            lua.create_function(|_lua, path: String| Ok(Utils::expand_path(&path)))?;
+        utils_table.set(
+            "expand_path",
+            lua.create_function(|_lua, path: String| Ok(Utils::expand_path(&path)))?,
+        )?;
+        utils_table.set(
+            "dirname",
+            lua.create_function(|_lua, path: String| Ok(Utils::dirname(&path)))?,
+        )?;
+        utils_table.set(
+            "chomp",
+            lua.create_function(|_lua, s: String| Ok(Utils::chomp(&s)))?,
+        )?;
+        utils_table.set(
+            "sh",
+            lua.create_function(|lua, args: LuaMultiValue| {
+                let all_args: Vec<String> = args
+                    .into_iter()
+                    .map(|arg| String::from_lua(arg, lua))
+                    .collect::<Result<Vec<_>, _>>()?;
+
+                if all_args.is_empty() {
+                    return Err(LuaError::external(FrorkError::InvalidArguments(
+                        "sh requires at least a command".to_string(),
+                    )));
+                }
 
-        let dirname_fn = lua.create_function(|_lua, path: String| Ok(Utils::dirname(&path)))?;
+                let (cmd, cmd_args) = all_args.split_first().unwrap();
 
-        utils_table.set("expand_path", expand_path_fn)?;
-        utils_table.set("dirname", dirname_fn)?;
+                let result = Utils::sh(cmd, cmd_args)
+                    .map(|(stdout, status)| (Some(stdout), status))
+                    .unwrap_or((None, -1));
+                Ok(result)
+            })?,
+        )?;
 
         Ok(LuaValue::Table(utils_table))
     }
@@ -509,6 +561,8 @@ fn setup_lua(
     };
     lua.register_module("frork", &frork_table)
         .map_err(|e| eyre!("Failed to register Frork module: {}", e))?;
+    lua.register_module("flork", &frork_table)
+        .map_err(|e| eyre!("Failed to register Flork module: {}", e))?;
 
     Ok((lua, frork_table, fennel_module))
 }