]> quire.kejadlen.dev Git - quire.git/commitdiff
Extract Repo struct wrapping a resolved path
authorAlpha Chen <alpha@kejadlen.dev>
Sat, 25 Apr 2026 14:38:19 +0000 (14:38 +0000)
committerAlpha Chen <alpha@kejadlen.dev>
Sat, 25 Apr 2026 14:55:49 +0000 (07:55 -0700)
Gives commands a typed handle instead of a bare PathBuf, with room to
add methods later.

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

index f66d2f393ec3da4c999a5805275079fd91b90012..f40892459b7fe38b610d3bcf906cac1531661b25 100644 (file)
@@ -44,11 +44,14 @@ fn dispatch_git(quire: &Quire, git_cmd: &str, args: &[String]) -> Result<()> {
     let path = args[0].trim_start_matches('/');
     ensure!(!path.is_empty(), "empty repository path");
 
-    let repo_dir = quire.repo(path)?;
-    ensure!(repo_dir.is_dir(), "repository not found: {path}");
+    let repo = quire.repo(path)?;
+    ensure!(repo.exists(), "repository not found: {path}");
 
     tracing::info!(%git_cmd, %path, "dispatching git command");
-    let err = Command::new(git_cmd).arg(".").current_dir(&repo_dir).exec();
+    let err = Command::new(git_cmd)
+        .arg(".")
+        .current_dir(repo.path())
+        .exec();
 
     bail!("exec failed: {err}")
 }
index bff0b279504f2bf7206780b65a1c9147f90da562..557c59cd0c65ddd519ba05bad1f104b48808bb0b 100644 (file)
@@ -5,11 +5,11 @@ use miette::{IntoDiagnostic, Result, ensure};
 use quire::Quire;
 
 pub async fn new(quire: &Quire, name: &str) -> Result<()> {
-    let repo_dir = quire.repo(name)?;
-    ensure!(!repo_dir.is_dir(), "repository already exists: {name}");
+    let repo = quire.repo(name)?;
+    ensure!(!repo.exists(), "repository already exists: {name}");
 
     // Create parent directory for grouped repos (e.g. work/foo.git).
-    if let Some(parent) = repo_dir.parent() {
+    if let Some(parent) = repo.path().parent() {
         fs_err::create_dir_all(parent).into_diagnostic()?;
     }
 
@@ -35,13 +35,13 @@ pub async fn list(quire: &Quire) -> Result<()> {
 }
 
 pub async fn rm(quire: &Quire, name: &str) -> Result<()> {
-    let repo_dir = quire.repo(name)?;
-    ensure!(repo_dir.is_dir(), "repository not found: {name}");
+    let repo = quire.repo(name)?;
+    ensure!(repo.exists(), "repository not found: {name}");
 
-    fs_err::remove_dir_all(&repo_dir).into_diagnostic()?;
+    fs_err::remove_dir_all(repo.path()).into_diagnostic()?;
 
     // Clean up empty parent directory for grouped repos.
-    if let Some(parent) = repo_dir.parent()
+    if let Some(parent) = repo.path().parent()
         && parent != quire.repos_dir()
     {
         let _ = fs_err::remove_dir(parent);
index 66fef540a6dcbabe3fea67c9bcc9fbedd98bc4a9..6227fb258b379625330c8df179e7cd2dad1af45c 100644 (file)
@@ -4,6 +4,23 @@ use miette::{IntoDiagnostic, Result, ensure};
 
 use crate::config::Config;
 
+/// A resolved repository path.
+///
+/// Created by `Quire::repo` after validating the name.
+pub struct Repo {
+    path: PathBuf,
+}
+
+impl Repo {
+    pub fn path(&self) -> &Path {
+        &self.path
+    }
+
+    pub fn exists(&self) -> bool {
+        self.path.is_dir()
+    }
+}
+
 /// Application runtime context.
 ///
 /// Carries configuration and provides resolved paths to repositories.
@@ -25,9 +42,11 @@ impl Quire {
     ///
     /// Rejects path traversal, missing `.git` suffix, empty segments,
     /// reserved path components, and more than one level of grouping.
-    pub fn repo(&self, name: &str) -> Result<PathBuf> {
+    pub fn repo(&self, name: &str) -> Result<Repo> {
         validate_repo_name(name)?;
-        Ok(self.config.repos_dir.join(name))
+        Ok(Repo {
+            path: self.config.repos_dir.join(name),
+        })
     }
 
     /// List all repository names under the repos directory.
@@ -124,8 +143,8 @@ mod tests {
     fn repo_resolves_path() {
         let q = quire();
         assert_eq!(
-            q.repo("foo.git").unwrap(),
-            PathBuf::from("/var/quire/repos/foo.git")
+            q.repo("foo.git").unwrap().path(),
+            Path::new("/var/quire/repos/foo.git")
         );
     }