about summary refs log tree commit diff stats
path: root/pkgs/by-name/ba/back/src/config
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-03-08 21:50:22 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-03-09 13:44:42 +0100
commita9ff6e1c86ad51b3fa568ea7caa992df5db8c316 (patch)
tree65cb6404fce4f84be9ed6561ed152d0d21e3b875 /pkgs/by-name/ba/back/src/config
parentscripts/get_dns.sh: Init (diff)
downloadnixos-server-a9ff6e1c86ad51b3fa568ea7caa992df5db8c316.zip
pkgs/back: Support listing all repos via the `/` path
This change required porting all webhandling from rocket to hyper,
because we needed fine grained control over the path the user
requested. This should also improve the memory and resources footprint
because hyper is more lower level.

I also changed all of the templates from `format!()` calls to a real
templating language because I needed to touch most code paths anyway.
Diffstat (limited to 'pkgs/by-name/ba/back/src/config')
-rw-r--r--pkgs/by-name/ba/back/src/config/mod.rs110
1 files changed, 98 insertions, 12 deletions
diff --git a/pkgs/by-name/ba/back/src/config/mod.rs b/pkgs/by-name/ba/back/src/config/mod.rs
index 7351ad8..1161ce3 100644
--- a/pkgs/by-name/ba/back/src/config/mod.rs
+++ b/pkgs/by-name/ba/back/src/config/mod.rs
@@ -18,21 +18,97 @@ use gix::ThreadSafeRepository;
 use serde::Deserialize;
 use url::Url;
 
-use crate::error::{self, Error};
+use crate::{
+    error::{self, Error},
+    git_bug::dag::is_git_bug,
+};
 
 pub struct BackConfig {
-    // NOTE(@bpeetz): We do not need to html escape this, as the value must be a valid url. As such
-    // `<tags>` of all kinds _should_ be invalid.  <2024-12-26>
+    /// The url to the source code of back. This is needed, because back is licensed under the
+    /// AGPL.
     pub source_code_repository_url: Url,
-    pub repository: ThreadSafeRepository,
+
+    /// A list of the repositories known to back.
+    /// This list is constructed from the `scan_path` and the `project_list` file.
+    pub repositories: BackRepositories,
+
+    /// The root url this instance of back is hosted on.
+    /// For example:
+    ///     `issues.foss-syndicate.org`
     pub root: Url,
 }
 
+pub struct BackRepositories {
+    repositories: Vec<BackRepository>,
+
+    /// The path that is the common parent of all the repositories.
+    scan_path: PathBuf,
+}
+
+impl BackRepositories {
+    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+        self.into_iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a BackRepositories {
+    type Item = <&'a Vec<BackRepository> as IntoIterator>::Item;
+
+    type IntoIter = <&'a Vec<BackRepository> as IntoIterator>::IntoIter;
+
+    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 fn scan_path(&self) -> &Path {
+        &self.scan_path
+    }
+}
+
+pub struct BackRepository {
+    repo_path: PathBuf,
+}
+
+impl BackRepository {
+    pub fn open(&self, scan_path: &Path) -> Result<ThreadSafeRepository, error::Error> {
+        let repo = ThreadSafeRepository::open(scan_path.join(&self.repo_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
+    }
+}
+
 #[derive(Deserialize)]
 struct RawBackConfig {
     source_code_repository_url: Url,
-    repository_path: PathBuf,
     root_url: Url,
+    project_list: PathBuf,
+    scan_path: PathBuf,
 }
 
 impl BackConfig {
@@ -56,16 +132,26 @@ impl TryFrom<RawBackConfig> for BackConfig {
     type Error = error::Error;
 
     fn try_from(value: RawBackConfig) -> Result<Self, Self::Error> {
-        let repository = {
-            ThreadSafeRepository::open(&value.repository_path).map_err(|err| Error::RepoOpen {
-                repository_path: value.repository_path,
-                error: Box::new(err),
-            })
-        }?;
+        let repositories = fs::read_to_string(&value.project_list)
+            .map_err(|err| error::Error::ProjectListRead {
+                error: err,
+                file: value.project_list,
+            })?
+            .lines()
+            .try_fold(vec![], |mut acc, path| {
+                acc.push(BackRepository {
+                    repo_path: PathBuf::from(path),
+                });
+
+                Ok::<_, Self::Error>(acc)
+            })?;
 
         Ok(Self {
-            repository,
             source_code_repository_url: value.source_code_repository_url,
+            repositories: BackRepositories {
+                repositories,
+                scan_path: value.scan_path,
+            },
             root: value.root_url,
         })
     }