diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 14 | ||||
| -rw-r--r-- | src/plymouthd.rs | 43 | ||||
| -rw-r--r-- | src/theme.rs | 104 | 
3 files changed, 161 insertions, 0 deletions
| diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..54bee5b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,14 @@ +mod plymouthd; +mod theme; + +pub use plymouthd::Plymouthd; +pub use theme::Theme; + +use std::io; + +fn ini_to_io_err(e: ini::ini::Error) -> io::Error { +    match e { +        ini::ini::Error::Io(x) => x, +        ini::ini::Error::Parse(x) => io::Error::new(io::ErrorKind::InvalidData, x), +    } +}
\ No newline at end of file diff --git a/src/plymouthd.rs b/src/plymouthd.rs new file mode 100644 index 0000000..9e991e6 --- /dev/null +++ b/src/plymouthd.rs @@ -0,0 +1,43 @@ +use std::path::Path; +use std::io; + +use ini::Ini; + +pub struct Plymouthd { +    conf: Ini, +} + +impl Plymouthd { +    pub fn from_ini(conf: Ini) -> Self { +        Self { conf } +    } + +    pub fn from_file<P: AsRef<Path>>(filename: P) -> io::Result<Self> { +        let conf = Ini::load_from_file(filename).map_err(|e| super::ini_to_io_err(e))?; +        Ok(Self { conf }) +    } + +    pub fn default() -> io::Result<Self> { +        Self::from_file("/etc/plymouth/plymouthd.conf") +    } + +    pub fn current_theme(&self) -> Option<&str> { +        self.conf +            .section(Some("Daemon")) +            .and_then(|s| s.get("Theme")) +    } +} + +#[cfg(test)] +mod tests { +    use super::*; + +    #[test] +    fn default_theme_from_ini() { +        let mut ini = Ini::new(); +        ini.with_section(Some("Daemon")).set("Theme", "spinner"); + +        let conf = Plymouthd::from_ini(ini); +        assert!(conf.current_theme().unwrap() == "spinner"); +    } +} diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 0000000..2ac93f8 --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,104 @@ +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +use ini::Ini; + +pub const THEMES_DIRECTORY: &str = "/usr/share/plymouth/themes"; +pub const THEME_FILE_EXTENSION: &str = "plymouth"; + +#[derive(Debug)] +pub struct Theme { +    path: PathBuf, +    name: String, +    description: String, +    module_name: String, +} + +fn find_theme_config_file(path: &Path) -> io::Result<PathBuf> { +    fs::read_dir(&path)? +        .filter_map(|p| p.ok()) +        .map(|e| e.path()) +        .filter(|p| match p.extension() { +            Some(ext) => ext == THEME_FILE_EXTENSION, +            None => false, +        }) +        .nth(0) +        .map_or( +            Err(io::Error::new( +                io::ErrorKind::NotFound, +                "No *.plymouth file found in directory", +            )), +            |e| Ok(e), +        ) +} + +impl Theme { +    pub fn from_ini<P: AsRef<Path>>(path: P, ini: Ini) -> Self { +        let theme_section = ini +            .section(Some("Plymouth Theme")) +            .expect("could not find [Plymouth Theme] section"); +        let name = theme_section.get("Name").unwrap_or("").into(); +        let description = theme_section.get("Description").unwrap_or("").into(); +        let module_name = theme_section.get("ModuleName").unwrap_or("").into(); + +        Theme { +            path: PathBuf::from(path.as_ref()), +            name, +            description, +            module_name, +        } +    } + +    pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> { +        let config_path = find_theme_config_file(path.as_ref())?; + +        let ini = Ini::load_from_file(&config_path).map_err(|e| super::ini_to_io_err(e))?; + +        Ok(Self::from_ini(path, ini)) +    } + +    pub fn from_name(name: &str) -> io::Result<Self> { +        let path = Path::new(THEMES_DIRECTORY).join(name); +        Self::from_path(path) +    } + +    pub fn list() -> io::Result<impl Iterator<Item = String>> { +        fs::read_dir(THEMES_DIRECTORY).and_then(|d| { +            Ok(d.filter_map(|p| p.ok()) +                .filter_map(|e| e.file_name().into_string().ok())) +        }) +    } +} + +#[cfg(test)] +mod tests { +    use super::*; + +    #[test] +    fn from_ini() { +        let mut ini = Ini::new(); +        ini.with_section(Some("Plymouth Theme")) +            .set("Name", "foobar") +            .set("Description", "A foo and a bar.") +            .set("ModuleName", "script"); + +        let theme = Theme::from_ini("/dev/null", ini); +        assert!(theme.name == "foobar"); +        assert!(theme.description == "A foo and a bar."); +        assert!(theme.module_name == "script"); +    } + +    #[test] +    fn from_ini_default_values() { +        let mut ini = Ini::new(); +        // rust-ini does not support creating an empty section, so we add +        // a fake foo=bar entry to create the section +        ini.with_section(Some("Plymouth Theme")).set("foo", "bar"); + +        let theme = Theme::from_ini("/dev/null", ini); +        assert!(theme.name == ""); +        assert!(theme.description == ""); +        assert!(theme.module_name == ""); +    } +} | 
