]> quire.kejadlen.dev Git - quire.git/commitdiff
Simplify Config to Default and use miette bail/ensure macros
authorAlpha Chen <alpha@kejadlen.dev>
Fri, 24 Apr 2026 13:38:10 +0000 (13:38 +0000)
committerAlpha Chen <alpha@kejadlen.dev>
Fri, 24 Apr 2026 14:34:05 +0000 (07:34 -0700)
Config::load() with env var parsing was premature. Default impl is
enough for now. Switch exec.rs from if/return Err(miette!) to
ensure! and bail! for idiomatic miette usage.

Assisted-by: GLM-5.1 via pi
src/bin/quire/commands/exec.rs
src/bin/quire/main.rs
src/config.rs

index 5faf6215193f8c3ff18ef23662ee3b801b017d5b..780eb5cc6b2cb64cd24ab289eeaf72c03e89ee39 100644 (file)
@@ -1,7 +1,7 @@
 use std::os::unix::process::CommandExt;
 use std::process::Command;
 
-use miette::{Context, IntoDiagnostic, Result, miette};
+use miette::{Context, IntoDiagnostic, Result, miette, bail, ensure};
 
 use quire::Config;
 
@@ -21,34 +21,30 @@ pub async fn run(config: &Config, command: Vec<String>) -> Result<()> {
         .into_diagnostic()
         .context("failed to parse command")?;
 
-    if words.is_empty() {
-        return Err(miette!("no command provided"));
-    }
+    ensure!(!words.is_empty(), "no command provided");
 
     let git_cmd = &words[0];
 
-    if !GIT_COMMANDS.contains(&git_cmd.as_str()) {
-        return Err(miette!("unsupported command: {git_cmd}"));
-    }
+    ensure!(
+        GIT_COMMANDS.contains(&git_cmd.as_str()),
+        "unsupported command: {git_cmd}"
+    );
 
-    if words.len() != 2 {
-        return Err(miette!(
-            "expected usage: {git_cmd} '<repo>', got {} arguments",
-            words.len() - 1
-        ));
-    }
+    ensure!(
+        words.len() == 2,
+        "expected usage: {git_cmd} '<repo>', got {} arguments",
+        words.len() - 1
+    );
 
     let repo = validate_repo_path(&words[1])?;
 
     let repo_dir = config.repos_dir.join(&repo);
-    if !repo_dir.is_dir() {
-        return Err(miette!("repository not found: {repo}"));
-    }
+    ensure!(repo_dir.is_dir(), "repository not found: {repo}");
 
     tracing::info!(%git_cmd, %repo, "dispatching git command");
     let err = Command::new(git_cmd).arg(".").current_dir(&repo_dir).exec();
 
-    Err(miette!("exec failed: {err}"))
+    bail!("exec failed: {err}")
 }
 
 /// Validate a repo path argument from the SSH protocol.
@@ -59,21 +55,13 @@ pub async fn run(config: &Config, command: Vec<String>) -> Result<()> {
 fn validate_repo_path(raw: &str) -> Result<String> {
     let path = raw.trim_start_matches('/');
 
-    if path.is_empty() {
-        return Err(miette!("empty repository path"));
-    }
-
-    if path.contains("..") {
-        return Err(miette!("invalid repository path: {raw}"));
-    }
-
-    if !path.ends_with(".git") {
-        return Err(miette!("invalid repository path (must end in .git): {raw}"));
-    }
-
-    if path.contains("//") {
-        return Err(miette!("invalid repository path: {raw}"));
-    }
+    ensure!(!path.is_empty(), "empty repository path");
+    ensure!(!path.contains(".."), "invalid repository path: {raw}");
+    ensure!(
+        path.ends_with(".git"),
+        "invalid repository path (must end in .git): {raw}"
+    );
+    ensure!(!path.contains("//"), "invalid repository path: {raw}");
 
     Ok(path.to_string())
 }
index 9beb3b885e4def140a5295506ce033189828b7d9..684258924c89c2c1e21fa41e881ee50d8381ec58 100644 (file)
@@ -58,7 +58,7 @@ async fn main() -> Result<()> {
         return Ok(());
     };
 
-    let config = Config::load();
+    let config = Config::default();
 
     match command {
         Commands::Serve => commands::serve::run(&config).await?,
index 59ef55f205254497065d0825e2b28e64c90e5173..a4ad7450936c7aa269e4596b40a3bdb56af27b5e 100644 (file)
@@ -1,26 +1,17 @@
 use std::path::PathBuf;
 
-/// Application configuration resolved from environment and defaults.
+/// Application configuration.
 #[derive(Debug, Clone)]
 pub struct Config {
     /// Root directory containing bare Git repositories.
     pub repos_dir: PathBuf,
 }
 
-impl Config {
-    /// Environment variable overriding the default repository root.
-    const REPOS_DIR_ENV: &'static str = "QUIRE_REPOS_DIR";
-
-    /// Default repository root.
-    const DEFAULT_REPOS_DIR: &'static str = "/var/quire/repos";
-
-    /// Build config from environment, falling back to defaults.
-    pub fn load() -> Self {
-        let repos_dir = std::env::var(Self::REPOS_DIR_ENV)
-            .map(PathBuf::from)
-            .unwrap_or_else(|_| PathBuf::from(Self::DEFAULT_REPOS_DIR));
-
-        Self { repos_dir }
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            repos_dir: PathBuf::from("/var/quire/repos"),
+        }
     }
 }
 
@@ -30,17 +21,7 @@ mod tests {
 
     #[test]
     fn default_repos_dir() {
-        let config = Config::load();
-        assert_eq!(config.repos_dir, PathBuf::from(Config::DEFAULT_REPOS_DIR));
-    }
-
-    #[test]
-    fn env_override_repos_dir() {
-        // SAFETY: single-threaded test, no other code reading this env var concurrently.
-        unsafe { std::env::set_var(Config::REPOS_DIR_ENV, "/tmp/test-repos") };
-        let config = Config::load();
-        // SAFETY: same justification.
-        unsafe { std::env::remove_var(Config::REPOS_DIR_ENV) };
-        assert_eq!(config.repos_dir, PathBuf::from("/tmp/test-repos"));
+        let config = Config::default();
+        assert_eq!(config.repos_dir, PathBuf::from("/var/quire/repos"));
     }
 }