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-05-12 12:39:10 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-05-12 12:39:10 +0200
commit1e4dff1995833538f436b381bc0450a7c0080bad (patch)
tree2dc620ac9ea683cbee412b8d5818b3992462677c /src/config/mod.rs
downloadback-1e4dff1995833538f436b381bc0450a7c0080bad.zip
chore: Initial commit
Based on the version that was previously in `vhack.eu/nixos-server/pkgs/by-name/ba/back`.
Diffstat (limited to 'src/config/mod.rs')
-rw-r--r--src/config/mod.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs
new file mode 100644
index 0000000..6c90fce
--- /dev/null
+++ b/src/config/mod.rs
@@ -0,0 +1,137 @@
+// Back - An extremely simple git bug visualization system. Inspired by TVL's
+// panettone.
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This file is part of Back.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+use std::{
+    fs,
+    path::{Path, PathBuf},
+};
+
+use gix::ThreadSafeRepository;
+use serde::Deserialize;
+use url::Url;
+
+use crate::{
+    error::{self, Error},
+    git_bug::dag::is_git_bug,
+};
+
+#[derive(Deserialize)]
+pub struct BackConfig {
+    /// The url to the source code of back. This is needed, because back is licensed under the
+    /// AGPL.
+    pub source_code_repository_url: Url,
+
+    /// The root url this instance of back is hosted on.
+    /// For example:
+    ///     `issues.foss-syndicate.org`
+    pub root_url: Url,
+
+    project_list: PathBuf,
+
+    /// The path that is the common parent of all the repositories.
+    pub scan_path: PathBuf,
+}
+
+pub struct BackRepositories {
+    repositories: Vec<BackRepository>,
+}
+
+impl BackRepositories {
+    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+        self.into_iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a BackRepositories {
+    type IntoIter = <&'a Vec<BackRepository> as IntoIterator>::IntoIter;
+    type Item = <&'a Vec<BackRepository> as IntoIterator>::Item;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.repositories.iter()
+    }
+}
+
+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> {
+        self.repositories
+            .iter()
+            .find(|p| p.repo_path == path)
+            .ok_or(error::Error::RepoFind {
+                repository_path: path.to_owned(),
+            })
+    }
+}
+
+pub struct BackRepository {
+    repo_path: PathBuf,
+}
+
+impl BackRepository {
+    pub fn open(&self, scan_path: &Path) -> Result<ThreadSafeRepository, error::Error> {
+        let path = {
+            let base = scan_path.join(&self.repo_path);
+            if base.is_dir() {
+                base
+            } else {
+                PathBuf::from(base.display().to_string() + ".git")
+            }
+        };
+        let repo = ThreadSafeRepository::open(path).map_err(|err| Error::RepoOpen {
+            repository_path: self.repo_path.to_owned(),
+            error: Box::new(err),
+        })?;
+        if is_git_bug(&repo.to_thread_local())? {
+            Ok(repo)
+        } else {
+            Err(error::Error::NotGitBug {
+                path: self.repo_path.clone(),
+            })
+        }
+    }
+
+    pub fn path(&self) -> &Path {
+        &self.repo_path
+    }
+}
+
+impl BackConfig {
+    pub fn repositories(&self) -> error::Result<BackRepositories> {
+        let repositories = fs::read_to_string(&self.project_list)
+            .map_err(|err| error::Error::ProjectListRead {
+                error: err,
+                file: self.project_list.to_owned(),
+            })?
+            .lines()
+            .try_fold(vec![], |mut acc, path| {
+                acc.push(BackRepository {
+                    repo_path: PathBuf::from(path),
+                });
+
+                Ok::<_, error::Error>(acc)
+            })?;
+        Ok(BackRepositories { repositories })
+    }
+
+    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(),
+            error: err,
+        })?;
+
+        serde_json::from_str(&value).map_err(|err| Error::ConfigParse {
+            file: path.to_owned(),
+            error: err,
+        })
+    }
+}