extraction
change tkowptkskzmntqoluktortprpvpynvvn
commit 7b70815b5255b54db9d07a054053790dfed3ae63
author Alpha Chen <alpha@kejadlen.dev>
date
parent rxrqwzpn
diff --git a/src/errors.rs b/src/errors.rs
new file mode 100644
index 0000000..8658c76
--- /dev/null
+++ b/src/errors.rs
@@ -0,0 +1,33 @@
+use mlua::prelude::*;
+use thiserror::Error;
+
+#[derive(Error, Debug, Clone)]
+pub enum FrorkError {
+    #[error("No operation specified")]
+    NoOperation,
+    #[error("Unknown assertion type: {assertion_type}")]
+    UnknownAssertionType { assertion_type: String },
+    #[error("Invalid arguments: {0}")]
+    InvalidArguments(String),
+    #[error("Missing assertion type")]
+    MissingAssertionType,
+    #[error("Lua error: {0}")]
+    Lua(String),
+}
+
+// TODO does this actually work the way I think it does? write a test to find out
+impl From<LuaError> for FrorkError {
+    fn from(err: LuaError) -> Self {
+        match err {
+            LuaError::CallbackError { cause, .. } => {
+                if let Some(frork_err) = cause.downcast_ref::<FrorkError>() {
+                    frork_err.clone()
+                } else {
+                    FrorkError::Lua(format!("Callback error: {}", cause))
+                }
+            }
+            _ => FrorkError::Lua(err.to_string()),
+        }
+    }
+}
+
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..ba8b069
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod errors;
+pub mod utils;
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 031e202..a7582b3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,18 +1,18 @@
+mod errors;
+mod utils;
+
 use clap::{Parser, Subcommand};
 use color_eyre::{Result, eyre::eyre};
+use errors::FrorkError;
 use mlua::prelude::*;
-use regex::Regex;
 use serde::Deserialize;
 use std::cell::RefCell;
 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;
 use tracing::{debug, error, info};
+use utils::Utils;
 
 #[derive(Parser)]
 #[command(name = "frork")]
@@ -30,38 +30,6 @@ enum Commands {
     Satisfy { script: String },
 }
 
-#[derive(Error, Debug, Clone)]
-pub enum FrorkError {
-    #[error("No operation specified")]
-    NoOperation,
-    #[error("Unknown operation: {operation}")]
-    UnknownOperation { operation: String },
-    #[error("Unknown assertion type: {assertion_type}")]
-    UnknownAssertionType { assertion_type: String },
-    #[error("Invalid arguments: {0}")]
-    InvalidArguments(String),
-    #[error("Missing assertion type")]
-    MissingAssertionType,
-    #[error("Lua error: {0}")]
-    Lua(String),
-}
-
-// TODO does this actually work the way I think it does? write a test to find out
-impl From<LuaError> for FrorkError {
-    fn from(err: LuaError) -> Self {
-        match err {
-            LuaError::CallbackError { cause, .. } => {
-                if let Some(frork_err) = cause.downcast_ref::<FrorkError>() {
-                    frork_err.clone()
-                } else {
-                    FrorkError::Lua(format!("Callback error: {}", cause))
-                }
-            }
-            _ => FrorkError::Lua(err.to_string()),
-        }
-    }
-}
-
 #[derive(Debug, Deserialize)]
 struct Conflict {
     expected: String,
@@ -487,107 +455,6 @@ 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());
-
-        let mut expanded = path.to_string();
-
-        // Expand tilde
-        if expanded.starts_with('~')
-            && let Ok(home) = env::var("HOME")
-        {
-            expanded = expanded.replacen('~', &home, 1);
-        }
-
-        // Expand environment variables using regex
-        expanded = ENV_VAR_REGEX
-            .replace_all(&expanded, |caps: &regex::Captures| {
-                let var_name = caps.get(1).unwrap().as_str();
-                env::var(var_name).unwrap_or_else(|_| caps.get(0).unwrap().as_str().to_string())
-            })
-            .to_string();
-
-        expanded
-    }
-
-    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))
-    }
-}
-
-impl IntoLua for Utils {
-    fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
-        let utils_table = lua.create_table()?;
-
-        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 (cmd, cmd_args) = all_args.split_first().unwrap();
-
-                let result = Utils::sh(cmd, cmd_args)
-                    .map(|(stdout, status)| (Some(stdout), status))
-                    .unwrap_or((None, -1));
-                Ok(result)
-            })?,
-        )?;
-
-        Ok(LuaValue::Table(utils_table))
-    }
-}
-
 fn setup_lua(
     handle_status: impl Fn(&Status, &dyn AssertionType) -> Result<()> + Clone + 'static,
 ) -> Result<(Lua, LuaTable, LuaTable)> {
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..617b33d
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,111 @@
+use color_eyre::{Result, eyre::eyre};
+use mlua::prelude::*;
+use regex::Regex;
+use std::env;
+use std::path::Path;
+use std::process::Command;
+use std::sync::LazyLock;
+use tracing::debug;
+
+use crate::errors::FrorkError;
+
+pub struct Utils;
+
+impl Utils {
+    pub fn chomp(s: &str) -> String {
+        s.trim_end_matches('\n').trim_end_matches('\r').to_string()
+    }
+
+    pub 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())
+    }
+
+    pub 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());
+
+        let mut expanded = path.to_string();
+
+        // Expand tilde
+        if expanded.starts_with('~')
+            && let Ok(home) = env::var("HOME")
+        {
+            expanded = expanded.replacen('~', &home, 1);
+        }
+
+        // Expand environment variables using regex
+        expanded = ENV_VAR_REGEX
+            .replace_all(&expanded, |caps: &regex::Captures| {
+                let var_name = caps.get(1).unwrap().as_str();
+                env::var(var_name).unwrap_or_else(|_| caps.get(0).unwrap().as_str().to_string())
+            })
+            .to_string();
+
+        expanded
+    }
+
+    pub 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))
+    }
+}
+
+impl IntoLua for Utils {
+    fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
+        let utils_table = lua.create_table()?;
+
+        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 (cmd, cmd_args) = all_args.split_first().unwrap();
+
+                let result = Utils::sh(cmd, cmd_args)
+                    .map(|(stdout, status)| (Some(stdout), status))
+                    .unwrap_or((None, -1));
+                Ok(result)
+            })?,
+        )?;
+
+        Ok(LuaValue::Table(utils_table))
+    }
+}