debian_analyzer/
config.rs

1//! Lintian-brush configuration file.
2use crate::Certainty;
3use breezyshim::tree::WorkingTree;
4use configparser::ini::Ini;
5use log::warn;
6
7const SUPPORTED_KEYS: &[&str] = &[
8    "compat-release",
9    "minimum-certainty",
10    "allow-reformatting",
11    "update-changelog",
12];
13
14/// Configuration file name
15pub const PACKAGE_CONFIG_FILENAME: &str = "debian/lintian-brush.conf";
16
17/// Configuration file
18pub struct Config {
19    obj: Ini,
20}
21
22impl Config {
23    /// Load configuration from a working tree
24    pub fn from_workingtree(
25        tree: &dyn WorkingTree,
26        subpath: &std::path::Path,
27    ) -> std::io::Result<Self> {
28        let path = tree
29            .abspath(&subpath.join(PACKAGE_CONFIG_FILENAME))
30            .unwrap();
31        Self::load_from_path(&path)
32    }
33
34    /// Load configuration from a path
35    pub fn load_from_path(path: &std::path::Path) -> Result<Self, std::io::Error> {
36        let mut ini = Ini::new();
37        let data = std::fs::read_to_string(path)?;
38        ini.read(data).map_err(|e| std::io::Error::other(e))?;
39
40        for (section, contents) in ini.get_map_ref() {
41            if section != "default" {
42                warn!(
43                    "unknown section {} in {}, ignoring.",
44                    section,
45                    path.display()
46                );
47                continue;
48            }
49            for key in contents.keys() {
50                if !SUPPORTED_KEYS.contains(&key.as_str()) {
51                    warn!(
52                        "unknown key {} in section {} in {}, ignoring.",
53                        key,
54                        section,
55                        path.display()
56                    );
57
58                    continue;
59                }
60            }
61        }
62
63        Ok(Config { obj: ini })
64    }
65
66    /// Return the compatibility release.
67    pub fn compat_release(&self) -> Option<String> {
68        self.obj.get("default", "compat-release").and_then(|value| {
69            let codename = crate::release_info::resolve_release_codename(&value, None);
70            if codename.is_none() {
71                warn!("unknown compat release {}, ignoring.", value);
72            }
73            codename
74        })
75    }
76
77    /// Return whether reformatting is allowed.
78    pub fn allow_reformatting(&self) -> Option<bool> {
79        match self.obj.getbool("default", "allow-reformatting") {
80            Ok(value) => value,
81            Err(e) => {
82                warn!("invalid allow-reformatting value {}, ignoring.", e);
83                None
84            }
85        }
86    }
87
88    /// Return the minimum certainty level for changes to be applied.
89    pub fn minimum_certainty(&self) -> Option<Certainty> {
90        self.obj
91            .get("default", "minimum-certainty")
92            .and_then(|value| {
93                value
94                    .parse::<Certainty>()
95                    .inspect_err(|_e| {
96                        warn!("invalid minimum-certainty value {}, ignoring.", value);
97                    })
98                    .ok()
99            })
100    }
101
102    /// Return whether the changelog should be updated.
103    pub fn update_changelog(&self) -> Option<bool> {
104        match self.obj.getbool("default", "update-changelog") {
105            Ok(value) => value,
106            Err(e) => {
107                warn!("invalid update-changelog value {}, ignoring.", e);
108                None
109            }
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_compat_release() {
120        let td = tempfile::tempdir().unwrap();
121        std::fs::create_dir(td.path().join("debian")).unwrap();
122        std::fs::write(
123            td.path().join("debian/lintian-brush.conf"),
124            "compat-release = testing\n",
125        )
126        .unwrap();
127        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
128
129        let testing = crate::release_info::resolve_release_codename("testing", None);
130
131        assert_eq!(cfg.compat_release(), testing);
132    }
133
134    #[test]
135    fn test_minimum_certainty() {
136        let td = tempfile::tempdir().unwrap();
137        std::fs::create_dir(td.path().join("debian")).unwrap();
138        std::fs::write(
139            td.path().join("debian/lintian-brush.conf"),
140            "minimum-certainty = possible\n",
141        )
142        .unwrap();
143        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
144
145        assert_eq!(cfg.minimum_certainty(), Some(Certainty::Possible));
146    }
147
148    #[test]
149    fn test_update_changelog() {
150        let td = tempfile::tempdir().unwrap();
151        std::fs::create_dir(td.path().join("debian")).unwrap();
152        std::fs::write(
153            td.path().join("debian/lintian-brush.conf"),
154            "update-changelog = True\n",
155        )
156        .unwrap();
157        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
158
159        assert_eq!(cfg.update_changelog(), Some(true));
160    }
161
162    #[test]
163    fn test_unknown() {
164        let td = tempfile::tempdir().unwrap();
165        std::fs::create_dir(td.path().join("debian")).unwrap();
166        std::fs::write(
167            td.path().join("debian/lintian-brush.conf"),
168            "unknown = dunno\n",
169        )
170        .unwrap();
171        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
172        assert_eq!(cfg.compat_release(), None);
173    }
174
175    #[test]
176    fn test_missing() {
177        let td = tempfile::tempdir().unwrap();
178        let path = td.path().join("debian/lintian-brush.conf");
179        let cfg = Config::load_from_path(&path);
180        assert!(cfg.is_err());
181    }
182}