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)
39            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
40
41        for (section, contents) in ini.get_map_ref() {
42            if section != "default" {
43                warn!(
44                    "unknown section {} in {}, ignoring.",
45                    section,
46                    path.display()
47                );
48                continue;
49            }
50            for key in contents.keys() {
51                if !SUPPORTED_KEYS.contains(&key.as_str()) {
52                    warn!(
53                        "unknown key {} in section {} in {}, ignoring.",
54                        key,
55                        section,
56                        path.display()
57                    );
58
59                    continue;
60                }
61            }
62        }
63
64        Ok(Config { obj: ini })
65    }
66
67    /// Return the compatibility release.
68    pub fn compat_release(&self) -> Option<String> {
69        self.obj.get("default", "compat-release").and_then(|value| {
70            let codename = crate::release_info::resolve_release_codename(&value, None);
71            if codename.is_none() {
72                warn!("unknown compat release {}, ignoring.", value);
73            }
74            codename
75        })
76    }
77
78    /// Return whether reformatting is allowed.
79    pub fn allow_reformatting(&self) -> Option<bool> {
80        match self.obj.getbool("default", "allow-reformatting") {
81            Ok(value) => value,
82            Err(e) => {
83                warn!("invalid allow-reformatting value {}, ignoring.", e);
84                None
85            }
86        }
87    }
88
89    /// Return the minimum certainty level for changes to be applied.
90    pub fn minimum_certainty(&self) -> Option<Certainty> {
91        self.obj
92            .get("default", "minimum-certainty")
93            .and_then(|value| {
94                value
95                    .parse::<Certainty>()
96                    .inspect_err(|_e| {
97                        warn!("invalid minimum-certainty value {}, ignoring.", value);
98                    })
99                    .ok()
100            })
101    }
102
103    /// Return whether the changelog should be updated.
104    pub fn update_changelog(&self) -> Option<bool> {
105        match self.obj.getbool("default", "update-changelog") {
106            Ok(value) => value,
107            Err(e) => {
108                warn!("invalid update-changelog value {}, ignoring.", e);
109                None
110            }
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_compat_release() {
121        let td = tempfile::tempdir().unwrap();
122        std::fs::create_dir(td.path().join("debian")).unwrap();
123        std::fs::write(
124            td.path().join("debian/lintian-brush.conf"),
125            "compat-release = testing\n",
126        )
127        .unwrap();
128        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
129
130        let testing = crate::release_info::resolve_release_codename("testing", None);
131
132        assert_eq!(cfg.compat_release(), testing);
133    }
134
135    #[test]
136    fn test_minimum_certainty() {
137        let td = tempfile::tempdir().unwrap();
138        std::fs::create_dir(td.path().join("debian")).unwrap();
139        std::fs::write(
140            td.path().join("debian/lintian-brush.conf"),
141            "minimum-certainty = possible\n",
142        )
143        .unwrap();
144        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
145
146        assert_eq!(cfg.minimum_certainty(), Some(Certainty::Possible));
147    }
148
149    #[test]
150    fn test_update_changelog() {
151        let td = tempfile::tempdir().unwrap();
152        std::fs::create_dir(td.path().join("debian")).unwrap();
153        std::fs::write(
154            td.path().join("debian/lintian-brush.conf"),
155            "update-changelog = True\n",
156        )
157        .unwrap();
158        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
159
160        assert_eq!(cfg.update_changelog(), Some(true));
161    }
162
163    #[test]
164    fn test_unknown() {
165        let td = tempfile::tempdir().unwrap();
166        std::fs::create_dir(td.path().join("debian")).unwrap();
167        std::fs::write(
168            td.path().join("debian/lintian-brush.conf"),
169            "unknown = dunno\n",
170        )
171        .unwrap();
172        let cfg = Config::load_from_path(&td.path().join("debian/lintian-brush.conf")).unwrap();
173        assert_eq!(cfg.compat_release(), None);
174    }
175
176    #[test]
177    fn test_missing() {
178        let td = tempfile::tempdir().unwrap();
179        let path = td.path().join("debian/lintian-brush.conf");
180        let cfg = Config::load_from_path(&path);
181        assert!(cfg.is_err());
182    }
183}