mur_common/config/
turn_track.rs1use super::*;
4
5pub const TURN_TRACK_DEFAULT_TRIGGERS: &[&str] = &["cargo"];
7pub const TURN_TRACK_DEFAULT_CACHE_DIRS: &[&str] = &["target"];
9pub const TURN_TRACK_DEFAULT_SKIP_SUBDIRS: &[&str] = &["incremental"];
11pub const TURN_TRACK_DEFAULT_MIN_FREE_GIB: u64 = 20;
13pub const TURN_TRACK_DEFAULT_TURN_TARGET_SUBDIR: &str = "turns";
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
17pub struct TurnTrackConfig {
18 #[serde(default)]
19 pub warm_build_cache: WarmBuildCacheConfig,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct WarmBuildCacheConfig {
24 #[serde(default = "turn_track_default_enabled")]
25 pub enabled: bool,
26 #[serde(default = "turn_track_default_triggers")]
27 pub triggers: Vec<String>,
28 #[serde(default = "turn_track_default_cache_dirs")]
29 pub cache_dirs: Vec<String>,
30 #[serde(default = "turn_track_default_skip_subdirs")]
31 pub skip_subdirs: Vec<String>,
32 #[serde(default = "turn_track_default_min_free_gib")]
33 pub min_free_gib: u64,
34 #[serde(default = "turn_track_default_turn_target_subdir")]
37 pub turn_target_subdir: String,
38}
39
40impl WarmBuildCacheConfig {
41 pub fn validated_subdir(&self) -> &str {
44 let mut parts = std::path::Path::new(&self.turn_target_subdir).components();
45 match (parts.next(), parts.next()) {
46 (Some(std::path::Component::Normal(_)), None) => &self.turn_target_subdir,
47 _ => TURN_TRACK_DEFAULT_TURN_TARGET_SUBDIR,
48 }
49 }
50}
51
52fn strings(v: &[&str]) -> Vec<String> {
53 v.iter().map(|s| s.to_string()).collect()
54}
55
56fn turn_track_default_enabled() -> bool {
57 true
58}
59
60fn turn_track_default_triggers() -> Vec<String> {
61 strings(TURN_TRACK_DEFAULT_TRIGGERS)
62}
63
64fn turn_track_default_cache_dirs() -> Vec<String> {
65 strings(TURN_TRACK_DEFAULT_CACHE_DIRS)
66}
67
68fn turn_track_default_skip_subdirs() -> Vec<String> {
69 strings(TURN_TRACK_DEFAULT_SKIP_SUBDIRS)
70}
71
72fn turn_track_default_min_free_gib() -> u64 {
73 TURN_TRACK_DEFAULT_MIN_FREE_GIB
74}
75
76fn turn_track_default_turn_target_subdir() -> String {
77 TURN_TRACK_DEFAULT_TURN_TARGET_SUBDIR.to_string()
78}
79
80impl Default for WarmBuildCacheConfig {
81 fn default() -> Self {
82 Self {
83 enabled: turn_track_default_enabled(),
84 triggers: turn_track_default_triggers(),
85 cache_dirs: turn_track_default_cache_dirs(),
86 skip_subdirs: turn_track_default_skip_subdirs(),
87 min_free_gib: turn_track_default_min_free_gib(),
88 turn_target_subdir: turn_track_default_turn_target_subdir(),
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn turn_track_defaults_when_absent() {
99 let c: Config = serde_yaml::from_str("{}").unwrap();
100 let w = &c.turn_track.warm_build_cache;
101 assert!(w.enabled);
102 assert_eq!(w.triggers, vec!["cargo".to_string()]);
103 assert_eq!(w.cache_dirs, vec!["target".to_string()]);
104 assert_eq!(w.skip_subdirs, vec!["incremental".to_string()]);
105 assert_eq!(w.min_free_gib, 20);
106 assert_eq!(w.turn_target_subdir, "turns");
107 }
108
109 #[test]
110 fn turn_track_partial_override() {
111 let c: Config =
112 serde_yaml::from_str("turn_track:\n warm_build_cache:\n min_free_gib: 5\n")
113 .unwrap();
114 let w = &c.turn_track.warm_build_cache;
115 assert_eq!(w.min_free_gib, 5);
116 assert!(w.enabled);
117 assert_eq!(w.triggers, vec!["cargo".to_string()]);
118 assert_eq!(w.cache_dirs, vec!["target".to_string()]);
119 assert_eq!(w.skip_subdirs, vec!["incremental".to_string()]);
120 assert_eq!(w.turn_target_subdir, "turns");
121 }
122
123 #[test]
124 fn turn_target_subdir_rejects_path_escape() {
125 let with = |s: &str| WarmBuildCacheConfig {
126 turn_target_subdir: s.to_string(),
127 ..Default::default()
128 };
129 for bad in ["", "..", ".", "a/b", "/abs", "../x"] {
130 assert_eq!(with(bad).validated_subdir(), "turns", "input {bad:?}");
131 }
132 assert_eq!(with("x").validated_subdir(), "x");
133 }
134}