genpac 0.1.0

Sandbox for Gentoo ebuild development using bubblewrap
// Copyright (C) 2023 Gokul Das B
// SPDX-License-Identifier: GPL-3.0-or-later
//! Config processing for sandbox module

use crate::GlobalsFinal;
use anyhow::Result as AResult;
use serde::Deserialize;
use std::collections::HashMap;
use std::iter::Iterator;
use std::path::{Path, PathBuf};

#[derive(Deserialize)]
struct RawConfig {
    sandbox: SandBoxConfig,
}

#[derive(Deserialize)]
struct SandBoxConfig {
    command: String,
    #[serde(rename = "tmpfs-size")]
    tmpfs_size: Option<usize>,
    mounts: MountConfig,
}

#[derive(Deserialize)]
struct MountConfig {
    repos: HashMap<String, String>,
    files: Option<Vec<FileMounts>>,
}

#[derive(Deserialize)]
struct FileMounts {
    src: String,
    dest: String,
}

#[derive(Debug)]
pub(super) struct ModConfig {
    pub(super) command: String,
    pub(super) tmpfs_size: usize,
    repos: Vec<(PathBuf, PathBuf)>,
    files: Vec<(PathBuf, PathBuf)>,
}

impl ModConfig {
    pub(super) fn new(globals: &GlobalsFinal) -> AResult<Self> {
        let repopath = Path::new("/var/db/repos");
        let raw: RawConfig = toml::from_str(globals.text())?;
        let command = raw.sandbox.command;
        let tmpfs_size = raw.sandbox.tmpfs_size.unwrap_or_default();
        let repos = raw
            .sandbox
            .mounts
            .repos
            .into_iter()
            .map(|(key, val)| (globals.resolve_path(&val), repopath.join(key)))
            .collect();
        let files = raw
            .sandbox
            .mounts
            .files
            .unwrap_or_default()
            .into_iter()
            .map(|file| {
                (
                    globals.resolve_path(&file.src),
                    globals.resolve_path(&file.dest),
                )
            })
            .collect();
        Ok(Self {
            command,
            tmpfs_size,
            repos,
            files,
        })
    }

    /// Get all mount paths after verification
    pub(super) fn mountpaths(&self) -> AResult<impl Iterator<Item = &(PathBuf, PathBuf)> + '_> {
        // Verify source repos first
        for (src, _) in &self.repos {
            anyhow::ensure!(src.is_dir(), "Repository {} not found", src.display());
        }

        // Verifying source files next
        for (src, _) in &self.files {
            anyhow::ensure!(src.is_file(), "Source file {} not found", src.display());
        }

        let itr = self.repos.iter().chain(self.files.iter());
        Ok(itr)
    }
}