use std::{cell::OnceCell, path::PathBuf};
use anyhow::Result;
use clap::Parser;
use dadk_config::{
common::target_arch::TargetArch, manifest::DadkManifestFile, rootfs::RootFSConfigFile,
};
use derive_builder::Builder;
use manifest::parse_manifest;
use crate::{
console::CommandLineArgs,
utils::{abs_path, check_dir_exists},
};
mod manifest;
#[derive(Debug, Clone, Builder)]
pub struct DADKExecContext {
pub command: CommandLineArgs,
manifest: Option<DadkManifestFile>,
rootfs: OnceCell<RootFSConfigFile>,
}
pub fn build_exec_context() -> Result<DADKExecContext> {
let mut builder = DADKExecContextBuilder::create_empty();
builder.command(CommandLineArgs::parse());
builder.rootfs(OnceCell::new());
if builder.command.as_ref().unwrap().action.needs_manifest() {
parse_manifest(&mut builder).expect("Failed to parse manifest");
} else {
builder.manifest(None);
}
let ctx: DADKExecContext = builder.build()?;
ctx.setup_workdir().expect("Failed to setup workdir");
Ok(ctx)
}
impl DADKExecContext {
pub fn workdir(&self) -> PathBuf {
abs_path(&PathBuf::from(&self.command.workdir))
}
fn setup_workdir(&self) -> Result<()> {
std::env::set_current_dir(&self.workdir()).expect("Failed to set current directory");
Ok(())
}
pub fn rootfs(&self) -> &RootFSConfigFile {
self.rootfs.get_or_init(|| {
RootFSConfigFile::load(&self.manifest().metadata.rootfs_config)
.expect("Failed to load rootfs config")
})
}
pub fn manifest(&self) -> &DadkManifestFile {
self.manifest.as_ref().unwrap()
}
pub fn sysroot_dir(&self) -> Result<PathBuf> {
check_dir_exists(&self.manifest().metadata.sysroot_dir)
.map(|p| p.clone())
.map_err(|e| anyhow::anyhow!("Failed to get sysroot dir: {}", e))
}
pub fn cache_root_dir(&self) -> Result<PathBuf> {
check_dir_exists(&self.manifest().metadata.cache_root_dir)
.map(|p| p.clone())
.map_err(|e| anyhow::anyhow!("Failed to get cache root dir: {}", e))
}
#[deprecated]
pub fn user_config_dir(&self) -> Result<PathBuf> {
check_dir_exists(&self.manifest().metadata.user_config_dir)
.map(|p| p.clone())
.map_err(|e| anyhow::anyhow!("Failed to get user config dir: {}", e))
}
pub fn target_arch(&self) -> TargetArch {
self.manifest().metadata.arch
}
pub fn disk_image_path(&self) -> PathBuf {
self.workdir()
.join(format!("bin/{}.img", self.disk_image_basename()))
}
pub fn disk_mount_path(&self) -> PathBuf {
self.workdir()
.join(format!("bin/mnt/{}", self.disk_image_basename()))
}
fn disk_image_basename(&self) -> String {
let arch: String = self.target_arch().into();
format!("disk-image-{}", arch)
}
pub fn disk_image_size(&self) -> usize {
self.rootfs().metadata.size
}
}