axbuild 0.4.14

An OS build lib toolkit used by arceos
Documentation
use std::{
    fs,
    path::{Path, PathBuf},
};

use anyhow::{Context, bail, ensure};

use super::{
    StarryAppBoardCase,
    build_config::{
        collect_prefixed_toml_files, default_target_for_board_config, discover_case_build_config,
    },
    discovery::{
        apps_starry_dir, available_case_names, resolve_case_relative_path, validate_case_name,
    },
};

pub(crate) fn resolve_board_case(
    workspace_root: &Path,
    case_name: &str,
    explicit_board_config: Option<&Path>,
) -> anyhow::Result<StarryAppBoardCase> {
    let case_name = validate_case_name(case_name)?;
    let apps_dir = apps_starry_dir(workspace_root);
    ensure!(
        apps_dir.is_dir(),
        "missing Starry apps directory `{}`",
        apps_dir.display()
    );

    let case_dir = apps_dir.join(case_name);
    if !case_dir.is_dir() {
        bail!(
            "unknown Starry app case `{case_name}` in {}; available cases: {}",
            apps_dir.display(),
            available_case_names(&apps_dir)?
        );
    }

    let init_path = case_dir.join("init.sh");
    ensure!(
        init_path.is_file(),
        "Starry app case `{case_name}` is missing `{}`",
        init_path.display()
    );
    let init_cmd = fs::read_to_string(&init_path)
        .with_context(|| format!("failed to read {}", init_path.display()))?;
    let init_cmd = init_cmd.trim().to_string();
    ensure!(
        !init_cmd.is_empty(),
        "Starry app case `{case_name}` has an empty init script `{}`",
        init_path.display()
    );

    let board_config_path = match explicit_board_config {
        Some(path) => resolve_explicit_board_config(&case_dir, path),
        None => discover_case_board_config(&case_dir)?,
    };
    let default_target = default_target_for_board_config(workspace_root, &board_config_path)?;
    let (build_config_path, target) =
        discover_case_build_config(&case_dir, default_target.as_deref())?;

    Ok(StarryAppBoardCase {
        name: case_name.to_string(),
        case_dir,
        init_path,
        init_cmd,
        build_config_path,
        board_config_path,
        target,
    })
}

fn discover_case_board_config(case_dir: &Path) -> anyhow::Result<PathBuf> {
    let mut configs = collect_prefixed_toml_files(case_dir, "board-")?;
    match configs.len() {
        0 => bail!(
            "Starry app case `{}` does not provide a board-<board>.toml config",
            case_dir.display()
        ),
        1 => Ok(configs.remove(0)),
        _ => bail!(
            "Starry app case `{}` provides multiple board configs; pass --board-config",
            case_dir.display()
        ),
    }
}

fn resolve_explicit_board_config(case_dir: &Path, path: &Path) -> PathBuf {
    resolve_case_relative_path(case_dir, path)
}

#[cfg(test)]
#[path = "tests/board.rs"]
mod tests;