linuxkit-utils 0.1.0

an utility to compose linuxkit manifests
Documentation
use crate::AnyError;

use crate::manifest::*;
use crate::EnvSubst;

use std::path::Path;

#[derive(Debug, Clone, ::structopt::StructOpt)]
pub struct LinuxkitMake {
    #[structopt(default_value = ".")]
    pub project_dir: String,
}

impl LinuxkitMake {
    pub fn run(&self) -> Result<(), AnyError> {
        let project_root: &Path = self.project_dir.as_str().as_ref();

        let manifest = Manifest {
            kernel: util::read_file(project_root.join("kernel.yml"))?,
            init: util::read_dir_as_vec(project_root.join("init.d"))?,
            on_boot: util::read_dir_as_vec(project_root.join("on-boot.d"))?,
            on_shutdown: util::read_dir_as_vec(project_root.join("on-shutdown.d"))?,
            services: util::read_dir_as_vec(project_root.join("services.d"))?,
            files: util::read_dir_as_vec(project_root.join("files.d"))?,
            trust: util::read_file(project_root.join("trust.yml"))?,
        };

        let manifest = manifest.env_subst(&std::env::vars().collect())?;

        let stdout = std::io::stdout();
        let stdout = stdout.lock();
        let () = ::serde_yaml::to_writer(stdout, &manifest)?;

        Ok(())
    }
}

mod util {
    use crate::AnyError;
    use ::serde::de::DeserializeOwned;
    use std::fs::OpenOptions;
    use std::path::Path;

    pub fn read_file<T, P>(path: P) -> Result<T, AnyError>
    where
        P: AsRef<Path>,
        T: DeserializeOwned,
    {
        let f = OpenOptions::new().read(true).open(path)?;
        let v = ::serde_yaml::from_reader(f)?;
        Ok(v)
    }

    pub fn read_dir_as_vec<T, P>(path: P) -> Result<Vec<T>, AnyError>
    where
        P: AsRef<Path>,
        T: DeserializeOwned,
    {
        let dir_entries = std::fs::read_dir(path)?;

        let mut items = vec![];

        for dir_entry in dir_entries {
            let dir_entry = dir_entry?;

            let file_name = dir_entry.file_name().to_string_lossy().as_ref().to_owned();

            if !dir_entry.file_type()?.is_file() {
                continue;
            }

            if !file_name.ends_with(".yml") {
                continue;
            }

            let value = read_file::<T, _>(dir_entry.path())?;

            items.push((file_name, value));
        }

        let () = items.sort_by_key(|(n, _)| n.to_owned());

        Ok(items.into_iter().map(|(_, v)| v).collect())
    }
}