瀏覽代碼

feat: Add dadk-manifest (#63)

* feat: Add dadk-manifest

Signed-off-by: longjin <longjin@DragonOS.org>

* 添加 target_arch的单元测试

---------

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin 5 月之前
父節點
當前提交
7fd740ac2d

+ 8 - 0
dadk-config/Cargo.toml

@@ -9,3 +9,11 @@ authors = [
 ]
 
 [dependencies]
+anyhow = { version = "1.0.90", features = ["std", "backtrace"] }
+serde = { version = "1.0.160", features = ["serde_derive"] }
+serde_json = "1.0.96"
+toml = "0.8.12"
+
+# 只有在test的情况下才会引入下列库
+[dev-dependencies]
+tempfile = "3.13.0"

+ 1 - 0
dadk-config/src/common/mod.rs

@@ -0,0 +1 @@
+pub mod target_arch;

+ 150 - 0
dadk-config/src/common/target_arch.rs

@@ -0,0 +1,150 @@
+use serde::{Deserialize, Deserializer, Serialize};
+
+/// 目标处理器架构
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TargetArch {
+    X86_64,
+    RiscV64,
+}
+
+impl TargetArch {
+    /// 期望的目标处理器架构(如果修改了枚举,那一定要修改这里)
+    pub const EXPECTED: [&'static str; 2] = ["x86_64", "riscv64"];
+}
+
+impl Default for TargetArch {
+    fn default() -> Self {
+        TargetArch::X86_64
+    }
+}
+
+impl TryFrom<&str> for TargetArch {
+    type Error = String;
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value.trim().to_ascii_lowercase().as_str() {
+            "x86_64" => Ok(TargetArch::X86_64),
+            "riscv64" => Ok(TargetArch::RiscV64),
+            _ => Err(format!("Unknown target arch: {}", value)),
+        }
+    }
+}
+
+impl Into<&str> for TargetArch {
+    fn into(self) -> &'static str {
+        match self {
+            TargetArch::X86_64 => "x86_64",
+            TargetArch::RiscV64 => "riscv64",
+        }
+    }
+}
+
+impl Into<String> for TargetArch {
+    fn into(self) -> String {
+        let x: &str = self.into();
+        x.to_string()
+    }
+}
+
+impl<'de> Deserialize<'de> for TargetArch {
+    fn deserialize<D>(deserializer: D) -> Result<TargetArch, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let s = String::deserialize(deserializer)?;
+
+        let r = TargetArch::try_from(s.as_str());
+        match r {
+            Ok(v) => Ok(v),
+            Err(_) => Err(serde::de::Error::invalid_value(
+                serde::de::Unexpected::Str(s.as_str()),
+                &format!("Expected one of {:?}", TargetArch::EXPECTED).as_str(),
+            )),
+        }
+    }
+}
+
+impl Serialize for TargetArch {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: serde::Serializer,
+    {
+        let string: String = Into::into(*self);
+        serializer.serialize_str(string.as_str())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use serde_json;
+
+    #[test]
+    fn test_default() {
+        let default_arch = TargetArch::default();
+        assert_eq!(default_arch, TargetArch::X86_64);
+    }
+
+    #[test]
+    fn test_try_from_valid() {
+        let x86_64 = TargetArch::try_from("x86_64").unwrap();
+        assert_eq!(x86_64, TargetArch::X86_64);
+
+        let riscv64 = TargetArch::try_from("riscv64").unwrap();
+        assert_eq!(riscv64, TargetArch::RiscV64);
+    }
+
+    #[test]
+    fn test_try_from_invalid() {
+        let result = TargetArch::try_from("unknown");
+        assert!(result.is_err());
+        assert_eq!(result.unwrap_err(), "Unknown target arch: unknown");
+    }
+
+    #[test]
+    fn test_into_str() {
+        let x86_64: &str = TargetArch::X86_64.into();
+        assert_eq!(x86_64, "x86_64");
+
+        let riscv64: &str = TargetArch::RiscV64.into();
+        assert_eq!(riscv64, "riscv64");
+    }
+
+    #[test]
+    fn test_into_string() {
+        let x86_64: String = TargetArch::X86_64.into();
+        assert_eq!(x86_64, "x86_64");
+
+        let riscv64: String = TargetArch::RiscV64.into();
+        assert_eq!(riscv64, "riscv64");
+    }
+
+    #[test]
+    fn test_deserialize_valid() {
+        let json_x86_64 = r#""x86_64""#;
+        let x86_64: TargetArch = serde_json::from_str(json_x86_64).unwrap();
+        assert_eq!(x86_64, TargetArch::X86_64);
+
+        let json_riscv64 = r#""riscv64""#;
+        let riscv64: TargetArch = serde_json::from_str(json_riscv64).unwrap();
+        assert_eq!(riscv64, TargetArch::RiscV64);
+    }
+
+    #[test]
+    fn test_deserialize_invalid() {
+        let json_unknown = r#""unknown""#;
+        let result: Result<TargetArch, _> = serde_json::from_str(json_unknown);
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_serialize() {
+        let x86_64 = TargetArch::X86_64;
+        let serialized_x86_64 = serde_json::to_string(&x86_64).unwrap();
+        assert_eq!(serialized_x86_64, r#""x86_64""#);
+
+        let riscv64 = TargetArch::RiscV64;
+        let serialized_riscv64 = serde_json::to_string(&riscv64).unwrap();
+        assert_eq!(serialized_riscv64, r#""riscv64""#);
+    }
+}

+ 4 - 0
dadk-config/src/lib.rs

@@ -1 +1,5 @@
+mod common;
+pub mod manifest;
 pub mod user;
+
+extern crate anyhow;

+ 123 - 0
dadk-config/src/manifest.rs

@@ -0,0 +1,123 @@
+use std::path::PathBuf;
+
+use anyhow::Result;
+use serde::Deserialize;
+
+use crate::common::target_arch::TargetArch;
+
+use std::fs;
+use toml;
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct Metadata {
+    /// Target processor architecture
+    pub arch: TargetArch,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct DadkManifest {
+    pub metadata: Metadata,
+}
+
+impl DadkManifest {
+    pub fn load(path: &PathBuf) -> Result<Self> {
+        // 读取文件内容
+        let content = fs::read_to_string(path)?;
+        Self::do_load(&content)
+    }
+
+    fn do_load(content: &str) -> Result<Self> {
+        // 解析TOML内容
+        let manifest_toml: DadkManifest = toml::from_str(&content)?;
+
+        Ok(manifest_toml)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::io::Write;
+    use tempfile::NamedTempFile;
+
+    #[test]
+    fn test_load_success() -> Result<()> {
+        let toml_content = r#"
+            [metadata]
+            arch = "x86_64"
+        "#;
+
+        let mut temp_file = NamedTempFile::new()?;
+        temp_file.write_all(toml_content.as_bytes())?;
+
+        let path = temp_file.path().to_path_buf();
+        let manifest = DadkManifest::load(&path)?;
+
+        assert_eq!(manifest.metadata.arch, TargetArch::X86_64);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_load_file_not_found() {
+        let path = PathBuf::from("non_existent_file.toml");
+        let result = DadkManifest::load(&path);
+
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_load_invalid_toml() -> Result<()> {
+        let invalid_toml_content = r#"
+            [metadata
+            arch = "x86_64"
+        "#;
+
+        let mut temp_file = NamedTempFile::new()?;
+        temp_file.write_all(invalid_toml_content.as_bytes())?;
+
+        let path = temp_file.path().to_path_buf();
+        let result = DadkManifest::load(&path);
+
+        assert!(result.is_err());
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_load_invalid_arch_toml() -> Result<()> {
+        // Invalid arch value
+        let invalid_toml_content = r#"
+            [metadata]
+            arch = "abcde"
+        "#;
+
+        let mut temp_file = NamedTempFile::new()?;
+        temp_file.write_all(invalid_toml_content.as_bytes())?;
+
+        let path = temp_file.path().to_path_buf();
+        let result = DadkManifest::load(&path);
+
+        assert!(result.is_err());
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_load_missing_required_fields() -> Result<()> {
+        let toml_content = r#"
+            [metadata]
+            # arch field is missing
+        "#;
+
+        let mut temp_file = NamedTempFile::new()?;
+        temp_file.write_all(toml_content.as_bytes())?;
+
+        let path = temp_file.path().to_path_buf();
+        let result = DadkManifest::load(&path);
+
+        assert!(result.is_err());
+
+        Ok(())
+    }
+}

+ 6 - 0
dadk-config/templates/dadk-manifest.toml

@@ -0,0 +1,6 @@
+# Configuration template placed in the root directory of the DragonOS workspace
+# Named `dadk-manifest.toml`
+
+[metadata]
+# Target architecture. Options: x86_64, riscv64
+target_arch = "x86_64"

+ 1 - 0
dadk/Cargo.toml

@@ -21,6 +21,7 @@ doc = true
 
 
 [dependencies]
+anyhow = { version = "1.0.90", features = ["std", "backtrace"] }
 dadk-user = { path = "../dadk-user" }
 env_logger = "0.11.5"
 log = "0.4.22"

+ 2 - 0
dadk/src/lib.rs

@@ -1,5 +1,7 @@
 use dadk_user::dadk_user_main;
 
+extern crate anyhow;
+
 pub fn dadk_main() {
     dadk_user_main();
 }