manifest.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. use std::path::PathBuf;
  2. use anyhow::Result;
  3. use serde::Deserialize;
  4. use crate::common::target_arch::TargetArch;
  5. use std::fs;
  6. use toml;
  7. /// The main configuration file for DADK
  8. #[derive(Debug, Clone, Deserialize)]
  9. pub struct DadkManifest {
  10. pub metadata: Metadata,
  11. /// A flag variable used to indicate whether
  12. /// the default value function was called during deserialization.
  13. #[serde(skip)]
  14. pub used_default: bool,
  15. }
  16. impl DadkManifest {
  17. pub fn load(path: &PathBuf) -> Result<Self> {
  18. // 读取文件内容
  19. let content = fs::read_to_string(path)?;
  20. Self::do_load(&content)
  21. }
  22. fn do_load(content: &str) -> Result<Self> {
  23. // Parse TOML content
  24. let mut manifest_toml: DadkManifest = toml::from_str(content)?;
  25. manifest_toml.used_default = check_used_default();
  26. Ok(manifest_toml)
  27. }
  28. }
  29. thread_local! {
  30. /// Global variable to track if default values were used during deserialization.
  31. static USED_DEFAULT: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
  32. }
  33. /// Call this function to set a flag when
  34. /// default values are used during DADK manifest parsing
  35. fn set_used_default() {
  36. USED_DEFAULT.with(|used_default| {
  37. used_default.set(true);
  38. });
  39. }
  40. /// Check if default values were used during deserialization.
  41. fn check_used_default() -> bool {
  42. USED_DEFAULT.with(|used_default| used_default.get())
  43. }
  44. #[derive(Debug, Clone, Deserialize)]
  45. pub struct Metadata {
  46. /// Target processor architecture
  47. pub arch: TargetArch,
  48. /// Rootfs configuration file path
  49. #[serde(default = "default_rootfs_config_path")]
  50. pub rootfs_config: PathBuf,
  51. /// Hypervisor configuration file path
  52. #[serde(default = "default_hypervisor_config_path")]
  53. pub hypervisor_config: PathBuf,
  54. /// Boot configuration file path
  55. #[serde(default = "default_boot_config_path")]
  56. pub boot_config: PathBuf,
  57. }
  58. /// Returns the default path for the rootfs configuration file.
  59. fn default_rootfs_config_path() -> PathBuf {
  60. set_used_default();
  61. "config/rootfs.toml".into()
  62. }
  63. /// Returns the default path for the hypervisor configuration file.
  64. fn default_hypervisor_config_path() -> PathBuf {
  65. set_used_default();
  66. "config/hypervisor.toml".into()
  67. }
  68. /// Returns the default path for the boot configuration file.
  69. fn default_boot_config_path() -> PathBuf {
  70. set_used_default();
  71. "config/boot.toml".into()
  72. }
  73. #[cfg(test)]
  74. mod tests {
  75. use super::*;
  76. use std::io::Write;
  77. use tempfile::NamedTempFile;
  78. /// Test loading a complete configuration file
  79. #[test]
  80. fn test_full_load_success() -> Result<()> {
  81. let toml_content = r#"
  82. [metadata]
  83. arch = "x86_64"
  84. rootfs_config = "config/rootfs-x86_64.toml"
  85. hypervisor_config = "config/hypervisor-x86_64.toml"
  86. boot_config = "config/boot-x86_64.toml"
  87. "#;
  88. let mut temp_file = NamedTempFile::new()?;
  89. temp_file.write_all(toml_content.as_bytes())?;
  90. let path = temp_file.path().to_path_buf();
  91. let manifest = DadkManifest::load(&path)?;
  92. assert_eq!(manifest.metadata.arch, TargetArch::X86_64);
  93. assert_eq!(
  94. manifest.metadata.rootfs_config,
  95. PathBuf::from("config/rootfs-x86_64.toml")
  96. );
  97. assert_eq!(
  98. manifest.metadata.hypervisor_config,
  99. PathBuf::from("config/hypervisor-x86_64.toml")
  100. );
  101. assert_eq!(
  102. manifest.metadata.boot_config,
  103. PathBuf::from("config/boot-x86_64.toml")
  104. );
  105. assert!(!manifest.used_default);
  106. Ok(())
  107. }
  108. /// Test whether an error is reported when the file does not exist.
  109. #[test]
  110. fn test_load_file_not_found() {
  111. let path = PathBuf::from("non_existent_file.toml");
  112. let result = DadkManifest::load(&path);
  113. assert!(result.is_err());
  114. }
  115. /// Test whether an error is reported when the TOML content is invalid
  116. #[test]
  117. fn test_load_invalid_toml() -> Result<()> {
  118. let invalid_toml_content = r#"
  119. [metadata
  120. arch = "x86_64"
  121. "#;
  122. let mut temp_file = NamedTempFile::new()?;
  123. temp_file.write_all(invalid_toml_content.as_bytes())?;
  124. let path = temp_file.path().to_path_buf();
  125. let result = DadkManifest::load(&path);
  126. assert!(result.is_err());
  127. Ok(())
  128. }
  129. /// Test whether an error is reported when the arch field is invalid
  130. #[test]
  131. fn test_load_invalid_arch_toml() -> Result<()> {
  132. // Invalid arch value
  133. let invalid_toml_content = r#"
  134. [metadata]
  135. arch = "abcde"
  136. "#;
  137. let mut temp_file = NamedTempFile::new()?;
  138. temp_file.write_all(invalid_toml_content.as_bytes())?;
  139. let path = temp_file.path().to_path_buf();
  140. let result = DadkManifest::load(&path);
  141. assert!(result.is_err());
  142. Ok(())
  143. }
  144. /// Test whether an error is reported when a required field is missing
  145. #[test]
  146. fn test_load_missing_required_fields() -> Result<()> {
  147. let toml_content = r#"
  148. [metadata]
  149. # arch field is missing
  150. "#;
  151. let mut temp_file = NamedTempFile::new()?;
  152. temp_file.write_all(toml_content.as_bytes())?;
  153. let path = temp_file.path().to_path_buf();
  154. let result = DadkManifest::load(&path);
  155. assert!(result.is_err());
  156. Ok(())
  157. }
  158. /// Test whether default values are used
  159. /// when the rootfs_config and other configuration file path fields are not set
  160. #[test]
  161. fn test_load_default_config_path_value() -> Result<()> {
  162. let toml_content = r#"
  163. [metadata]
  164. arch = "x86_64"
  165. "#;
  166. let mut temp_file = NamedTempFile::new()?;
  167. temp_file.write_all(toml_content.as_bytes())?;
  168. let path = temp_file.path().to_path_buf();
  169. let manifest = DadkManifest::load(&path)?;
  170. assert_eq!(manifest.used_default, true);
  171. assert_eq!(
  172. manifest.metadata.rootfs_config,
  173. PathBuf::from("config/rootfs.toml")
  174. );
  175. assert_eq!(
  176. manifest.metadata.hypervisor_config,
  177. PathBuf::from("config/hypervisor.toml")
  178. );
  179. assert_eq!(
  180. manifest.metadata.boot_config,
  181. PathBuf::from("config/boot.toml")
  182. );
  183. Ok(())
  184. }
  185. }