1use anyhow::Result;
2use std::{
3 collections::BTreeSet,
4 fs,
5 path::{Path, PathBuf},
6};
7use tracing::debug;
8
9use serde::{Deserialize, Serialize};
10
11use super::project_type::ConfigProject;
12
13#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
14pub struct ProjectGroupFile {
15 #[serde(skip)]
16 pub file_path: PathBuf,
17 #[serde(default = "tags_default")]
18 pub tags: BTreeSet<String>,
19 pub include: Vec<GroupItem>,
20}
21
22const fn tags_default() -> BTreeSet<String> {
23 BTreeSet::new()
24}
25
26#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
27#[serde(untagged)]
28pub enum GroupItem {
29 GroupFile(PathBuf),
30 Project(ConfigProject),
31}
32
33impl ProjectGroupFile {
34 pub fn new(path: &Path) -> Result<Self> {
35 debug!("reading projects directory file...");
36 let mut project_group_file: Self = serde_yaml::from_str(&fs::read_to_string(path)?)?;
37 project_group_file.file_path = path.to_path_buf();
38 debug!("finished reading project group file");
39 Ok(project_group_file)
40 }
41
42 pub fn get_projects(&self) -> Result<Vec<ConfigProject>> {
43 self.recurse_group_files(BTreeSet::new())
44 }
45
46 fn recurse_group_files(&self, tags: BTreeSet<String>) -> Result<Vec<ConfigProject>> {
47 let mut projects: Vec<_> = vec![];
48 let mut group_tags = tags;
49 group_tags.extend(self.tags.clone());
50 for item in self.include.clone() {
51 match item {
52 GroupItem::GroupFile(group_path) => {
53 let config_projects = Self::new(&group_path)?
54 .recurse_group_files(group_tags.clone())?
55 .iter_mut()
56 .map(|p| {
57 p.tags.extend(group_tags.clone());
58 p.clone()
59 })
60 .collect::<Vec<_>>();
61 projects.extend(config_projects);
62 }
63 GroupItem::Project(mut p) => {
64 p.tags.extend(group_tags.clone());
65 projects.push(p)
66 }
67 }
68 }
69 Ok(projects)
70 }
71}