1 //! # 配置解析器 2 //! 3 //! 用于解析配置文件,生成任务列表 4 //! 5 //! 您需要指定一个配置文件目录,解析器会自动解析该目录下的所有配置文件。 6 //! 软件包的配置文件格式为toml 7 //! 8 //! ## 简介 9 //! 10 //! 在每个配置文件中,您需要指定软件包的名称、版本、描述、任务类型、依赖、构建配置和安装配置。DADK会根据这些信息生成任务列表。 11 //! 12 //! ## 配置文件格式 13 //! 14 //! ```toml 15 //! name = "test_git" 16 //! version = "0.1.0" 17 //! description = "" 18 //! build_once = true 19 //! install_once = true 20 //! target_arch = ["x86_64"] 21 //! 22 //! [task_type] 23 //! type = "build_from_source" 24 //! source = "git" 25 //! source_path = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/test_git.git" 26 //! revison = "01cdc56863" 27 //! branch = "test" 28 //! 29 //! [build] 30 //! build-command = "make instal" 31 //! 32 //! [install] 33 //! in_dragonos_path = "/bin" 34 //! 35 //! [clean] 36 //! clean-command = "make clean" 37 //! 38 //! [depends] 39 //! depend1 = "0.1.1" 40 //! depend2 = "0.1.2" 41 //! 42 //! [envs] 43 //! PATH = "/usr/bin" 44 //! LD_LIBRARY_PATH = "/usr/lib" 45 46 use std::{ 47 fmt::Debug, 48 fs::{DirEntry, ReadDir}, 49 path::PathBuf, 50 }; 51 52 use self::task::DADKTask; 53 use config::DADKUserConfig; 54 use log::{debug, error, info}; 55 use task::{BuildConfig, CleanConfig, InstallConfig, TaskType}; 56 use toml::Table; 57 mod config; 58 pub mod task; 59 pub mod task_log; 60 61 /// # 配置解析器 62 /// 63 /// 用于解析配置文件,生成任务列表 64 #[derive(Debug)] 65 pub struct Parser { 66 /// 配置文件目录 67 config_dir: PathBuf, 68 /// 扫描到的配置文件列表 69 config_files: Vec<PathBuf>, 70 } 71 72 pub struct ParserError { 73 pub config_file: Option<PathBuf>, 74 pub error: InnerParserError, 75 } 76 impl Debug for ParserError { 77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 78 match &self.error { 79 InnerParserError::IoError(e) => { 80 if let Some(config_file) = &self.config_file { 81 write!( 82 f, 83 "IO Error while parsing config file {}: {}", 84 config_file.display(), 85 e 86 ) 87 } else { 88 write!(f, "IO Error while parsing config files: {}", e) 89 } 90 } 91 InnerParserError::TomlError(e) => { 92 if let Some(config_file) = &self.config_file { 93 write!( 94 f, 95 "Toml Error while parsing config file {}: {}", 96 config_file.display(), 97 e 98 ) 99 } else { 100 write!(f, "Toml Error while parsing config file: {}", e) 101 } 102 } 103 InnerParserError::TaskError(e) => { 104 if let Some(config_file) = &self.config_file { 105 write!( 106 f, 107 "Error while parsing config file {}: {}", 108 config_file.display(), 109 e 110 ) 111 } else { 112 write!(f, "Error while parsing config file: {}", e) 113 } 114 } 115 } 116 } 117 } 118 119 #[derive(Debug)] 120 pub enum InnerParserError { 121 IoError(std::io::Error), 122 TomlError(toml::de::Error), 123 TaskError(String), 124 } 125 126 impl Parser { 127 pub fn new(config_dir: PathBuf) -> Self { 128 Self { 129 config_dir, 130 config_files: Vec::new(), 131 } 132 } 133 134 /// # 解析所有配置文件,生成任务列表 135 /// 136 /// ## 参数 137 /// 138 /// * `config_dir` - 配置文件所在目录 139 /// 140 /// ## 返回值 141 /// 142 /// * `Ok(Vec<(PathBuf, DADKTask)>)` - 任务列表(配置文件路径, 任务) 143 /// * `Err(ParserError)` - 解析错误 144 pub fn parse(&mut self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> { 145 self.scan_config_files()?; 146 info!("Found {} config files", self.config_files.len()); 147 let r: Result<Vec<(PathBuf, DADKTask)>, ParserError> = self.gen_tasks(); 148 if r.is_err() { 149 error!("Error while parsing config files: {:?}", r); 150 } 151 return r; 152 } 153 154 /// # 扫描配置文件目录,找到所有配置文件 155 fn scan_config_files(&mut self) -> Result<(), ParserError> { 156 info!("Scanning config files in {}", self.config_dir.display()); 157 158 let mut dir_queue: Vec<PathBuf> = Vec::new(); 159 // 将config目录加入队列 160 dir_queue.push(self.config_dir.clone()); 161 162 while !dir_queue.is_empty() { 163 // 扫描目录,找到所有*.dadk文件 164 let dir = dir_queue.pop().unwrap(); 165 let entries: ReadDir = std::fs::read_dir(&dir).map_err(|e| ParserError { 166 config_file: None, 167 error: InnerParserError::IoError(e), 168 })?; 169 170 for entry in entries { 171 let entry: DirEntry = entry.map_err(|e| ParserError { 172 config_file: None, 173 error: InnerParserError::IoError(e), 174 })?; 175 176 let path: PathBuf = entry.path(); 177 if path.is_dir() { 178 dir_queue.push(path); 179 } else if path.is_file() { 180 let extension: Option<&std::ffi::OsStr> = path.extension(); 181 if extension.is_none() { 182 continue; 183 } 184 let extension: &std::ffi::OsStr = extension.unwrap(); 185 if extension.to_ascii_lowercase() != "dadk" { 186 continue; 187 } 188 // 找到一个配置文件, 加入列表 189 self.config_files.push(path); 190 } 191 } 192 } 193 194 return Ok(()); 195 } 196 197 /// # 解析所有配置文件,生成任务列表 198 /// 199 /// 一旦发生错误,立即返回 200 /// 201 /// ## 返回值 202 /// 203 /// * `Ok(Vec<DADKTask>)` - 任务列表 204 /// * `Err(ParserError)` - 解析错误 205 fn gen_tasks(&self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> { 206 let mut result_vec = Vec::new(); 207 for config_file in &self.config_files { 208 let task: DADKTask = self.parse_config_file(config_file)?; 209 debug!("Parsed config file {}: {:?}", config_file.display(), task); 210 result_vec.push((config_file.clone(), task)); 211 } 212 213 return Ok(result_vec); 214 } 215 216 /// # 解析单个配置文件,生成任务 217 /// 218 /// ## 参数 219 /// 220 /// * `config_file` - 配置文件路径 221 /// 222 /// ## 返回值 223 /// 224 /// * `Ok(DADKTask)` - 生成好的任务 225 /// * `Err(ParserError)` - 解析错误 226 pub(super) fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask, ParserError> { 227 // 从toml文件中解析出DADKTask 228 let mut task: DADKTask = Self::parse_toml_file(config_file)?; 229 230 debug!("Parsed config file {}: {:?}", config_file.display(), task); 231 232 // 去除字符串中的空白字符 233 task.trim(); 234 235 // 校验DADKTask的参数是否合法 236 task.validate().map_err(|e| ParserError { 237 config_file: Some(config_file.clone()), 238 error: InnerParserError::TaskError(e), 239 })?; 240 241 return Ok(task); 242 } 243 244 /// 解析toml文件,生成DADKTask 245 pub fn parse_toml_file(config_file: &PathBuf) -> Result<DADKTask, ParserError> { 246 let content = std::fs::read_to_string(config_file).map_err(|e| ParserError { 247 config_file: Some(config_file.clone()), 248 error: InnerParserError::IoError(e), 249 })?; 250 251 let table = content.parse::<Table>().map_err(|e| ParserError { 252 config_file: Some(config_file.clone()), 253 error: InnerParserError::TomlError(e), 254 })?; 255 256 let dadk_user_config = DADKUserConfig::parse(config_file, &table)?; 257 258 Ok(DADKTask { 259 name: dadk_user_config.standard_config.name, 260 version: dadk_user_config.standard_config.version, 261 description: dadk_user_config.standard_config.description, 262 rust_target: dadk_user_config.standard_config.rust_target, 263 task_type: TaskType::try_from(dadk_user_config.task_type_config)?, 264 depends: dadk_user_config.depends_config.depends, 265 build: BuildConfig::from(dadk_user_config.build_config), 266 install: InstallConfig::from(dadk_user_config.install_config), 267 clean: CleanConfig::from(dadk_user_config.clean_config), 268 envs: dadk_user_config.envs_config.envs, 269 build_once: dadk_user_config.standard_config.build_once, 270 install_once: dadk_user_config.standard_config.install_once, 271 target_arch: dadk_user_config.standard_config.target_arch, 272 }) 273 } 274 } 275