use std::collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
fn is_false(value: &bool) -> bool {
!*value
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct BuildConfig {
pub system: BuildSystem,
#[serde(default)]
pub artifacts: ArtifactConfig,
}
impl Default for BuildConfig {
fn default() -> Self {
Self {
system: BuildSystem::Cargo(Box::default()),
artifacts: ArtifactConfig::default(),
}
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct ArtifactConfig {
#[serde(default)]
pub analysis: AnalysisConfig,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct AnalysisConfig {
#[serde(default)]
pub disassembly: bool,
#[serde(default)]
pub elf_info: bool,
#[serde(default)]
pub symbols: bool,
}
impl AnalysisConfig {
pub(crate) fn is_enabled(&self) -> bool {
self.disassembly || self.elf_info || self.symbols
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub enum BuildSystem {
Custom(Custom),
Cargo(Box<Cargo>),
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct Custom {
pub build_cmd: String,
pub elf_path: String,
#[serde(default)]
pub to_bin: bool,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct Cargo {
pub env: HashMap<String, String>,
pub target: String,
pub package: String,
#[serde(default)]
pub bin: Option<String>,
#[serde(default)]
pub test: Option<String>,
pub features: Vec<String>,
pub log: Option<LogLevel>,
pub extra_config: Option<String>,
#[serde(default)]
pub profile: Option<CargoBuildProfile>,
#[serde(default, skip_serializing_if = "is_false")]
pub disable_someboot_build_config: bool,
pub args: Vec<String>,
pub pre_build_cmds: Vec<String>,
pub post_build_cmds: Vec<String>,
#[serde(default)]
pub to_bin: bool,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub enum CargoBuildProfile {
Debug,
Release,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct Depend {
pub name: String,
pub d_features: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
}
#[cfg(test)]
mod tests {
use super::{Cargo, Custom};
#[test]
fn legacy_build_configs_and_analysis_flags_parse_with_defaults() {
let legacy = "[system.Custom]\nbuild_cmd = \"make\"\nelf_path = \"kernel.elf\"\n";
let config: super::BuildConfig = toml::from_str(legacy).unwrap();
assert!(!config.artifacts.analysis.is_enabled());
let enabled = format!(
"{legacy}\n[artifacts.analysis]\ndisassembly = true\nelf_info = true\nsymbols = true\n"
);
let config: super::BuildConfig = toml::from_str(&enabled).unwrap();
assert!(config.artifacts.analysis.disassembly);
assert!(config.artifacts.analysis.elf_info);
assert!(config.artifacts.analysis.symbols);
let partial: super::BuildConfig =
toml::from_str(&format!("{legacy}\n[artifacts.analysis]\nsymbols = true\n")).unwrap();
assert!(!partial.artifacts.analysis.disassembly);
assert!(!partial.artifacts.analysis.elf_info);
assert!(partial.artifacts.analysis.symbols);
}
#[test]
fn cargo_config_defaults_someboot_injection_to_enabled_when_field_is_absent() {
let cargo: Cargo = toml::from_str(
r#"
env = {}
target = "x86_64-unknown-none"
package = "kernel"
features = []
args = []
pre_build_cmds = []
post_build_cmds = []
to_bin = false
"#,
)
.unwrap();
assert!(!cargo.disable_someboot_build_config);
}
#[test]
fn cargo_config_defaults_to_bin_to_false_when_field_is_absent() {
let cargo: Cargo = toml::from_str(
r#"
env = {}
target = "x86_64-unknown-none"
package = "kernel"
features = []
args = []
pre_build_cmds = []
post_build_cmds = []
"#,
)
.unwrap();
assert!(!cargo.to_bin);
}
#[test]
fn custom_config_defaults_to_bin_to_false_when_field_is_absent() {
let custom: Custom = toml::from_str(
r#"
build_cmd = "make"
elf_path = "target/kernel"
"#,
)
.unwrap();
assert!(!custom.to_bin);
}
#[test]
fn cargo_config_omits_someboot_disable_field_when_false() {
let cargo = Cargo {
env: Default::default(),
target: "x86_64-unknown-none".into(),
package: "kernel".into(),
features: Vec::new(),
args: Vec::new(),
pre_build_cmds: Vec::new(),
post_build_cmds: Vec::new(),
to_bin: false,
..Cargo::default()
};
let rendered = toml::to_string(&cargo).unwrap();
assert!(!rendered.contains("disable_someboot_build_config"));
}
#[test]
fn cargo_config_serializes_someboot_disable_field_when_true() {
let cargo = Cargo {
env: Default::default(),
target: "x86_64-unknown-none".into(),
package: "kernel".into(),
features: Vec::new(),
disable_someboot_build_config: true,
args: Vec::new(),
pre_build_cmds: Vec::new(),
post_build_cmds: Vec::new(),
to_bin: false,
..Cargo::default()
};
let rendered = toml::to_string(&cargo).unwrap();
assert!(rendered.contains("disable_someboot_build_config = true"));
}
}