about summary refs log tree commit diff stats
path: root/pkgs/by-name/ba/back/src/config/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ba/back/src/config/mod.rs')
-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,
         })
     }