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 anyhow::Result; 54 use dadk_config::user::UserConfigFile; 55 use log::{debug, error, info}; 56 57 pub mod task; 58 pub mod task_log; 59 60 /// # 配置解析器 61 /// 62 /// 用于解析配置文件,生成任务列表 63 #[derive(Debug)] 64 pub struct Parser { 65 /// 配置文件目录 66 config_dir: PathBuf, 67 /// 扫描到的配置文件列表 68 config_files: Vec<PathBuf>, 69 } 70 71 pub struct ParserError { 72 pub config_file: Option<PathBuf>, 73 pub error: InnerParserError, 74 } 75 impl Debug for ParserError { 76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 77 match &self.error { 78 InnerParserError::IoError(e) => { 79 if let Some(config_file) = &self.config_file { 80 write!( 81 f, 82 "IO Error while parsing config file {}: {}", 83 config_file.display(), 84 e 85 ) 86 } else { 87 write!(f, "IO Error while parsing config files: {}", e) 88 } 89 } 90 InnerParserError::TomlError(e) => { 91 if let Some(config_file) = &self.config_file { 92 write!( 93 f, 94 "Toml Error while parsing config file {}: {}", 95 config_file.display(), 96 e 97 ) 98 } else { 99 write!(f, "Toml Error while parsing config file: {}", e) 100 } 101 } 102 InnerParserError::TaskError(e) => { 103 if let Some(config_file) = &self.config_file { 104 write!( 105 f, 106 "Error while parsing config file {}: {}", 107 config_file.display(), 108 e 109 ) 110 } else { 111 write!(f, "Error while parsing config file: {}", e) 112 } 113 } 114 } 115 } 116 } 117 118 #[derive(Debug)] 119 pub enum InnerParserError { 120 IoError(std::io::Error), 121 TomlError(toml::de::Error), 122 TaskError(String), 123 } 124 125 impl Parser { 126 pub fn new(config_dir: PathBuf) -> Self { 127 Self { 128 config_dir, 129 config_files: Vec::new(), 130 } 131 } 132 133 /// # 解析所有配置文件,生成任务列表 134 /// 135 /// ## 参数 136 /// 137 /// * `config_dir` - 配置文件所在目录 138 /// 139 /// ## 返回值 140 /// 141 /// * `Ok(Vec<(PathBuf, DADKTask)>)` - 任务列表(配置文件路径, 任务) 142 /// * `Err(ParserError)` - 解析错误 143 pub fn parse(&mut self) -> Result<Vec<(PathBuf, DADKTask)>> { 144 self.scan_config_files()?; 145 info!("Found {} config files", self.config_files.len()); 146 let r: Result<Vec<(PathBuf, DADKTask)>> = self.gen_tasks(); 147 if r.is_err() { 148 error!("Error while parsing config files: {:?}", r); 149 } 150 return r; 151 } 152 153 /// # 扫描配置文件目录,找到所有配置文件 154 fn scan_config_files(&mut self) -> Result<()> { 155 info!("Scanning config files in {}", self.config_dir.display()); 156 157 let mut dir_queue: Vec<PathBuf> = Vec::new(); 158 // 将config目录加入队列 159 dir_queue.push(self.config_dir.clone()); 160 161 while !dir_queue.is_empty() { 162 // 扫描目录,找到所有*.dadk文件 163 let dir = dir_queue.pop().unwrap(); 164 let entries: ReadDir = std::fs::read_dir(&dir)?; 165 166 for entry in entries { 167 let entry: DirEntry = entry?; 168 169 let path: PathBuf = entry.path(); 170 if path.is_dir() { 171 dir_queue.push(path); 172 } else if path.is_file() { 173 let extension: Option<&std::ffi::OsStr> = path.extension(); 174 if extension.is_none() { 175 continue; 176 } 177 let extension: &std::ffi::OsStr = extension.unwrap(); 178 if extension.to_ascii_lowercase() != "toml" { 179 continue; 180 } 181 // 找到一个配置文件, 加入列表 182 self.config_files.push(path); 183 } 184 } 185 } 186 187 return Ok(()); 188 } 189 190 /// # 解析所有配置文件,生成任务列表 191 /// 192 /// 一旦发生错误,立即返回 193 /// 194 /// ## 返回值 195 /// 196 /// * `Ok(Vec<DADKTask>)` - 任务列表 197 /// * `Err(ParserError)` - 解析错误 198 fn gen_tasks(&self) -> Result<Vec<(PathBuf, DADKTask)>> { 199 let mut result_vec = Vec::new(); 200 for config_file in &self.config_files { 201 let task: DADKTask = self.parse_config_file(config_file)?; 202 debug!("Parsed config file {}: {:?}", config_file.display(), task); 203 result_vec.push((config_file.clone(), task)); 204 } 205 206 return Ok(result_vec); 207 } 208 209 /// # 解析单个配置文件,生成任务 210 /// 211 /// ## 参数 212 /// 213 /// * `config_file` - 配置文件路径 214 /// 215 /// ## 返回值 216 /// 217 /// * `Ok(DADKTask)` - 生成好的任务 218 /// * `Err(ParserError)` - 解析错误 219 pub(super) fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask> { 220 log::trace!("Parsing config file {}", config_file.display()); 221 // 从toml文件中解析出DADKTask 222 let mut task: DADKTask = Self::parse_toml_file(config_file)?; 223 224 // 去除字符串中的空白字符 225 task.trim(); 226 227 // 校验DADKTask的参数是否合法 228 task.validate()?; 229 230 return Ok(task); 231 } 232 233 /// 解析toml文件,生成DADKTask 234 pub fn parse_toml_file(config_file: &PathBuf) -> Result<DADKTask> { 235 let dadk_user_config = UserConfigFile::load(config_file)?; 236 DADKTask::try_from(dadk_user_config) 237 } 238 } 239