about summary refs log tree commit diff stats
path: root/src/config/mod.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-06 15:45:11 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-06 15:45:11 +0200
commita6baea06697f6c76c695dc4198099deb8ba916e0 (patch)
tree476a3865f6b4bef04751ba20534813a58892811b /src/config/mod.rs
parentchore: Initial commit (diff)
downloadback-a6baea06697f6c76c695dc4198099deb8ba916e0.zip
feat(treewide): Prepare for first release
This commit contains many changes, as they were developed alongside
`git-bug-rs` and unfortunately not separately committed.

A toplevel summary would include:
- Appropriate redirects,
- The templating moved to `vy` (as this works with rustfmt formatting),
- Search support (via `git-bug-rs`),
- And better layout in the link section.
Diffstat (limited to 'src/config/mod.rs')
-rw-r--r--src/config/mod.rs66
1 files changed, 48 insertions, 18 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 6c90fce..07c6c29 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -15,16 +15,13 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use gix::ThreadSafeRepository;
+use git_bug::{entities::issue::Issue, replica::Replica};
 use serde::Deserialize;
 use url::Url;
 
-use crate::{
-    error::{self, Error},
-    git_bug::dag::is_git_bug,
-};
+use crate::error::{self, Error};
 
-#[derive(Deserialize)]
+#[derive(Debug, Deserialize)]
 pub struct BackConfig {
     /// The url to the source code of back. This is needed, because back is licensed under the
     /// AGPL.
@@ -35,17 +32,24 @@ pub struct BackConfig {
     ///     `issues.foss-syndicate.org`
     pub root_url: Url,
 
-    project_list: PathBuf,
+    /// The file that list all the projects.
+    ///
+    /// This is `cgit`'s `project-list` setting.
+    pub project_list: PathBuf,
 
     /// The path that is the common parent of all the repositories.
+    ///
+    /// This is `cgit`'s `scan-path` setting.
     pub scan_path: PathBuf,
 }
 
+#[derive(Debug)]
 pub struct BackRepositories {
     repositories: Vec<BackRepository>,
 }
 
 impl BackRepositories {
+    #[must_use]
     pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
         self.into_iter()
     }
@@ -62,23 +66,31 @@ impl<'a> IntoIterator for &'a BackRepositories {
 
 impl BackRepositories {
     /// Try to get the repository at path `path`.
-    /// If no repository was registered/found at `path`, returns an error.
-    pub fn get(&self, path: &Path) -> Result<&BackRepository, error::Error> {
+    ///
+    /// # Errors
+    /// - If no repository was registered/found at `path`
+    pub fn get(&self, path: &Path) -> Result<&BackRepository, Error> {
         self.repositories
             .iter()
             .find(|p| p.repo_path == path)
-            .ok_or(error::Error::RepoFind {
+            .ok_or(Error::RepoFind {
                 repository_path: path.to_owned(),
             })
     }
 }
 
+#[derive(Debug)]
 pub struct BackRepository {
     repo_path: PathBuf,
 }
 
 impl BackRepository {
-    pub fn open(&self, scan_path: &Path) -> Result<ThreadSafeRepository, error::Error> {
+    /// Open this repository.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the repository could not be opened.
+    pub fn open(&self, scan_path: &Path) -> Result<Replica, Error> {
         let path = {
             let base = scan_path.join(&self.repo_path);
             if base.is_dir() {
@@ -87,30 +99,43 @@ impl BackRepository {
                 PathBuf::from(base.display().to_string() + ".git")
             }
         };
-        let repo = ThreadSafeRepository::open(path).map_err(|err| Error::RepoOpen {
-            repository_path: self.repo_path.to_owned(),
+        let repo = Replica::from_path(path).map_err(|err| Error::RepoOpen {
+            repository_path: self.repo_path.clone(),
             error: Box::new(err),
         })?;
-        if is_git_bug(&repo.to_thread_local())? {
+
+        // We could also check that Identity data is in the Replica,
+        // but Issue existent is paramount.
+        if repo.contains::<Issue>()? {
             Ok(repo)
         } else {
-            Err(error::Error::NotGitBug {
+            Err(Error::NotGitBug {
                 path: self.repo_path.clone(),
             })
         }
     }
 
+    #[must_use]
     pub fn path(&self) -> &Path {
         &self.repo_path
     }
 }
 
 impl BackConfig {
+    /// Returns the repositories of this [`BackConfig`].
+    ///
+    /// # Note
+    /// This will always re-read the `projects.list` file, to pick up repositories that were added
+    /// in the mean time.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the associated IO operations fail.
     pub fn repositories(&self) -> error::Result<BackRepositories> {
         let repositories = fs::read_to_string(&self.project_list)
-            .map_err(|err| error::Error::ProjectListRead {
+            .map_err(|err| Error::ProjectListRead {
                 error: err,
-                file: self.project_list.to_owned(),
+                file: self.project_list.clone(),
             })?
             .lines()
             .try_fold(vec![], |mut acc, path| {
@@ -118,11 +143,16 @@ impl BackConfig {
                     repo_path: PathBuf::from(path),
                 });
 
-                Ok::<_, error::Error>(acc)
+                Ok::<_, Error>(acc)
             })?;
         Ok(BackRepositories { repositories })
     }
 
+    /// Construct this [`BackConfig`] from a config file.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the associated IO operations fail.
     pub fn from_config_file(path: &Path) -> error::Result<Self> {
         let value = fs::read_to_string(path).map_err(|err| Error::ConfigRead {
             file: path.to_owned(),