manifest.rs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 DadkManifestFile {
  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 DadkManifestFile {
  17. pub fn load(path: &PathBuf) -> Result<Self> {
  18. // 读取文件内容
  19. let content = fs::read_to_string(path)?;
  20. Self::load_from_str(&content)
  21. }
  22. pub fn load_from_str(content: &str) -> Result<Self> {
  23. // Parse TOML content
  24. let mut manifest_toml: DadkManifestFile = 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. /// DADK builder version for isolating unstable features
  49. #[serde(default = "default_dadk_builder_version", rename = "builder-version")]
  50. pub builder_version: String,
  51. /// Rootfs configuration file path
  52. #[serde(default = "default_rootfs_config_path", rename = "rootfs-config")]
  53. pub rootfs_config: PathBuf,
  54. /// Hypervisor configuration file path
  55. #[serde(
  56. default = "default_hypervisor_config_path",
  57. rename = "hypervisor-config"
  58. )]
  59. pub hypervisor_config: PathBuf,
  60. /// Boot configuration file path
  61. #[serde(default = "default_boot_config_path", rename = "boot-config")]
  62. pub boot_config: PathBuf,
  63. /// Sysroot directory path
  64. #[serde(default = "default_sysroot_dir", rename = "sysroot-dir")]
  65. pub sysroot_dir: PathBuf,
  66. /// Root Cache directory path
  67. #[serde(default = "default_cache_root_dir", rename = "cache-root-dir")]
  68. pub cache_root_dir: PathBuf,
  69. /// User configuration directory path
  70. /// 这个字段只是临时用于兼容旧版本,v1.0版本重构完成后会删除
  71. #[deprecated(note = "This field is deprecated and will be removed in DADK 1.0")]
  72. #[serde(default = "default_user_config_dir", rename = "user-config-dir")]
  73. pub user_config_dir: PathBuf,
  74. }
  75. fn default_dadk_builder_version() -> String {
  76. "v1".to_string()
  77. }
  78. /// Returns the default path for the rootfs configuration file.
  79. fn default_rootfs_config_path() -> PathBuf {
  80. set_used_default();
  81. "config/rootfs.toml".into()
  82. }
  83. /// Returns the default path for the hypervisor configuration file.
  84. fn default_hypervisor_config_path() -> PathBuf {
  85. set_used_default();
  86. "config/hypervisor.toml".into()
  87. }
  88. /// Returns the default path for the boot configuration file.
  89. fn default_boot_config_path() -> PathBuf {
  90. set_used_default();
  91. "config/boot.toml".into()
  92. }
  93. /// Returns the default path for the sysroot directory.
  94. fn default_sysroot_dir() -> PathBuf {
  95. set_used_default();
  96. "bin/sysroot".into()
  97. }
  98. /// Returns the default path for the cache directory.
  99. fn default_cache_root_dir() -> PathBuf {
  100. set_used_default();
  101. "bin/dadk_cache".into()
  102. }
  103. fn default_user_config_dir() -> PathBuf {
  104. set_used_default();
  105. "user/dadk/config".into()
  106. }
  107. #[cfg(test)]
  108. mod tests {
  109. use super::*;
  110. use std::io::Write;
  111. use tempfile::NamedTempFile;
  112. /// Test loading a complete configuration file
  113. #[test]
  114. fn test_full_load_success() -> Result<()> {
  115. let toml_content = r#"
  116. [metadata]
  117. arch = "x86_64"
  118. rootfs-config = "config/rootfs-x86_64.toml"
  119. hypervisor-config = "config/hypervisor-x86_64.toml"
  120. boot-config = "config/boot-x86_64.toml"
  121. sysroot-dir = "bin/sysroot"
  122. cache-root-dir = "bin/dadk_cache"
  123. user-config-dir = "user/dadk/config"
  124. "#;
  125. let mut temp_file = NamedTempFile::new()?;
  126. temp_file.write_all(toml_content.as_bytes())?;
  127. let path = temp_file.path().to_path_buf();
  128. let manifest = DadkManifestFile::load(&path)?;
  129. assert_eq!(manifest.metadata.arch, TargetArch::X86_64);
  130. assert_eq!(
  131. manifest.metadata.rootfs_config,
  132. PathBuf::from("config/rootfs-x86_64.toml")
  133. );
  134. assert_eq!(
  135. manifest.metadata.hypervisor_config,
  136. PathBuf::from("config/hypervisor-x86_64.toml")
  137. );
  138. assert_eq!(
  139. manifest.metadata.boot_config,
  140. PathBuf::from("config/boot-x86_64.toml")
  141. );
  142. assert_eq!(manifest.metadata.sysroot_dir, PathBuf::from("bin/sysroot"));
  143. assert!(!manifest.used_default);
  144. Ok(())
  145. }
  146. /// Test whether an error is reported when the file does not exist.
  147. #[test]
  148. fn test_load_file_not_found() {
  149. let path = PathBuf::from("non_existent_file.toml");
  150. let result = DadkManifestFile::load(&path);
  151. assert!(result.is_err());
  152. }
  153. /// Test whether an error is reported when the TOML content is invalid
  154. #[test]
  155. fn test_load_invalid_toml() -> Result<()> {
  156. let invalid_toml_content = r#"
  157. [metadata
  158. arch = "x86_64"
  159. "#;
  160. let mut temp_file = NamedTempFile::new()?;
  161. temp_file.write_all(invalid_toml_content.as_bytes())?;
  162. let path = temp_file.path().to_path_buf();
  163. let result = DadkManifestFile::load(&path);
  164. assert!(result.is_err());
  165. Ok(())
  166. }
  167. /// Test whether an error is reported when the arch field is invalid
  168. #[test]
  169. fn test_load_invalid_arch_toml() -> Result<()> {
  170. // Invalid arch value
  171. let invalid_toml_content = r#"
  172. [metadata]
  173. arch = "abcde"
  174. "#;
  175. let mut temp_file = NamedTempFile::new()?;
  176. temp_file.write_all(invalid_toml_content.as_bytes())?;
  177. let path = temp_file.path().to_path_buf();
  178. let result = DadkManifestFile::load(&path);
  179. assert!(result.is_err());
  180. Ok(())
  181. }
  182. /// Test whether an error is reported when a required field is missing
  183. #[test]
  184. fn test_load_missing_required_fields() -> Result<()> {
  185. let toml_content = r#"
  186. [metadata]
  187. # arch field is missing
  188. "#;
  189. let mut temp_file = NamedTempFile::new()?;
  190. temp_file.write_all(toml_content.as_bytes())?;
  191. let path = temp_file.path().to_path_buf();
  192. let result = DadkManifestFile::load(&path);
  193. assert!(result.is_err());
  194. Ok(())
  195. }
  196. /// Test whether default values are used
  197. /// when the rootfs_config and other configuration file path fields are not set
  198. #[test]
  199. fn test_load_default_config_path_value() -> Result<()> {
  200. let toml_content = r#"
  201. [metadata]
  202. arch = "x86_64"
  203. "#;
  204. let mut temp_file = NamedTempFile::new()?;
  205. temp_file.write_all(toml_content.as_bytes())?;
  206. let path = temp_file.path().to_path_buf();
  207. let manifest = DadkManifestFile::load(&path)?;
  208. assert_eq!(manifest.used_default, true);
  209. assert_eq!(
  210. manifest.metadata.rootfs_config,
  211. PathBuf::from("config/rootfs.toml")
  212. );
  213. assert_eq!(
  214. manifest.metadata.hypervisor_config,
  215. PathBuf::from("config/hypervisor.toml")
  216. );
  217. assert_eq!(
  218. manifest.metadata.boot_config,
  219. PathBuf::from("config/boot.toml")
  220. );
  221. Ok(())
  222. }
  223. }