axbuild 0.4.19

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

use anyhow::Context;
use cargo_metadata::Metadata;
use log::warn;

use super::ArceosBuildConfig;
#[cfg(test)]
use super::ArceosBuildInfo;
use crate::{build, context::ResolvedBuildRequest};

pub(crate) fn resolve_build_info_path(
    package: &str,
    target: &str,
    explicit_path: Option<PathBuf>,
) -> anyhow::Result<PathBuf> {
    if let Some(path) = explicit_path {
        return Ok(path);
    }

    super::default_build_info_path(package, target)
}

#[cfg(test)]
pub(super) fn load_build_info(request: &ResolvedBuildRequest) -> anyhow::Result<ArceosBuildInfo> {
    let makefile_features = build::makefile_features_from_env();
    load_build_info_with_makefile_features(request, &makefile_features)
}

#[cfg(test)]
fn load_build_info_with_makefile_features(
    request: &ResolvedBuildRequest,
    makefile_features: &[String],
) -> anyhow::Result<ArceosBuildInfo> {
    let metadata = if makefile_features.is_empty() {
        None
    } else {
        Some(build::workspace_metadata().context("failed to load workspace metadata")?)
    };
    load_build_info_with_makefile_features_and_metadata(
        request,
        makefile_features,
        metadata.as_ref(),
    )
}

#[cfg(test)]
fn load_build_info_with_makefile_features_and_metadata(
    request: &ResolvedBuildRequest,
    makefile_features: &[String],
    metadata: Option<&Metadata>,
) -> anyhow::Result<ArceosBuildInfo> {
    Ok(
        load_build_config_with_makefile_features_and_metadata(
            request,
            makefile_features,
            metadata,
        )?
        .build_info,
    )
}

pub(super) fn load_build_config_with_makefile_features_and_metadata(
    request: &ResolvedBuildRequest,
    makefile_features: &[String],
    metadata: Option<&Metadata>,
) -> anyhow::Result<ArceosBuildConfig> {
    build::ensure_build_info(&request.build_info_path, ArceosBuildConfig::default_config)?;
    let content = fs::read_to_string(&request.build_info_path)?;
    build::reject_removed_std_field(&request.build_info_path, &content)?;
    let mut config: ArceosBuildConfig = toml::from_str(&content).with_context(|| {
        format!(
            "failed to parse build info {}",
            request.build_info_path.display()
        )
    })?;
    if config.build_info.normalize_legacy_feature_aliases() {
        warn!(
            "normalizing legacy feature aliases in build config {}",
            request.build_info_path.display()
        );
        fs::write(&request.build_info_path, toml::to_string_pretty(&config)?).with_context(
            || {
                format!(
                    "failed to rewrite normalized build info {}",
                    request.build_info_path.display()
                )
            },
        )?;
    }

    match metadata {
        Some(metadata) => build::apply_makefile_features_with_metadata(
            &mut config.build_info,
            &request.package,
            makefile_features,
            metadata,
        ),
        None => build::apply_makefile_features(
            &mut config.build_info,
            &request.package,
            makefile_features,
        ),
    }

    if let Some(smp) = request.smp {
        config.build_info.max_cpu_num = Some(smp);
    }

    Ok(config)
}

pub(crate) fn default_build_info_path(package: &str, target: &str) -> anyhow::Result<PathBuf> {
    Ok(build::default_build_info_path_in_workspace(
        &crate::context::workspace_root_path()?,
        package,
        target,
    ))
}

#[cfg(test)]
pub(super) fn resolve_build_info_path_in_dir(dir: &std::path::Path, target: &str) -> PathBuf {
    let bare_path = dir.join(format!("build-{target}.toml"));
    if bare_path.exists() {
        return bare_path;
    }

    let dotted_path = dir.join(format!(".build-{target}.toml"));
    if dotted_path.exists() {
        return dotted_path;
    }

    dotted_path
}