1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
use std::{
collections::HashMap,
ffi::OsStr,
fs::{self},
path::PathBuf,
};
use anyhow::{Result, bail};
use serde::{Deserialize, Serialize};
pub(crate) const MAIN_CONFIG_NAME: &str = "rollup.toml";
pub(crate) const DROP_IN_NAME: &str = ".rollup.owner";
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct MainConfig {
pub(crate) owners: Vec<Owner>,
pub(crate) drop_ins: HashMap<PathBuf, DropInConfig>,
}
impl MainConfig {
pub(crate) fn get_owner(&self, owner: &str) -> Result<&Owner> {
if let Some(own) = self.owners.iter().find(|o| o.name == owner) {
Ok(own)
} else {
bail!("Failed to find owner with name: `{}`", owner)
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct Owner {
pub(crate) name: String,
pub(crate) applies_to: PathBuf,
pub(crate) last_applied_tag: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct DropInConfig {
pub(crate) owners: Vec<String>,
}
pub(crate) fn load(root: &PathBuf) -> Result<MainConfig> {
let mut main: MainConfig = {
let path = root.join(MAIN_CONFIG_NAME);
let content = fs::read_to_string(path)?;
toml::from_str(&content)?
};
let drop_ins = collect_drop_ins(root)?;
for (path, config) in drop_ins {
assert!(main.drop_ins.insert(path, config).is_none());
}
Ok(main)
}
fn collect_drop_ins(path: &PathBuf) -> Result<Vec<(PathBuf, DropInConfig)>> {
let mut output = vec![];
for entry in fs::read_dir(path)? {
let entry = entry?;
let ft = entry.file_type()?;
if ft.is_dir() {
output.extend(collect_drop_ins(&entry.path())?);
} else if ft.is_file() && entry.file_name() == OsStr::new(DROP_IN_NAME) {
let drop_in: toml::Value = {
let content = fs::read_to_string(entry.path())?;
toml::from_str(&content)?
};
let drop_in_config = DropInConfig {
owners: {
let Some(owner) = drop_in.get("owner") else {
bail!("Drop in config without `owner` field")
};
if owner.is_str() {
vec![owner.as_str().expect("We checked").to_owned()]
} else if owner.is_array() {
let mut output = vec![];
for v in owner.as_array().expect("We checked") {
if let Some(v) = v.as_str() {
output.push(v.to_owned())
} else {
bail!("Owner value in arry not string: {}", v);
}
}
output
} else {
bail!("Owner value in drop in config not string or array")
}
},
};
output.push((
entry
.path()
.parent()
.expect("All drop-ins have a parent")
.to_owned(),
drop_in_config,
));
}
}
Ok(output)
}
|