Simplify Config to Default and use miette bail/ensure macros
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
diff --git a/src/bin/quire/commands/exec.rs b/src/bin/quire/commands/exec.rs
index 5faf621..780eb5c 100644
--- a/src/bin/quire/commands/exec.rs
+++ b/src/bin/quire/commands/exec.rs
@@ -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())
}
diff --git a/src/bin/quire/main.rs b/src/bin/quire/main.rs
index 9beb3b8..6842589 100644
--- a/src/bin/quire/main.rs
+++ b/src/bin/quire/main.rs
@@ -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?,
diff --git a/src/config.rs b/src/config.rs
index 59ef55f..a4ad745 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -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"));
}
}