mod.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. //! # 配置解析器
  2. //!
  3. //! 用于解析配置文件,生成任务列表
  4. //!
  5. //! 您需要指定一个配置文件目录,解析器会自动解析该目录下的所有配置文件。
  6. //! 软件包的配置文件必须以`.dadk`作为后缀名,内容格式为json。
  7. //!
  8. //! ## 简介
  9. //!
  10. //! 在每个配置文件中,您需要指定软件包的名称、版本、描述、任务类型、依赖、构建配置和安装配置。DADK会根据这些信息生成任务列表。
  11. //!
  12. //! ## 配置文件格式
  13. //!
  14. //! ```json
  15. //! {
  16. //! "name": "软件包名称",
  17. //! "version": "软件包版本",
  18. //! "description": "软件包描述",
  19. //! "task_type": {任务类型(该部分详见`TaskType`的文档)},
  20. //! "depends": [{依赖项(该部分详见Dependency的文档)}],
  21. //! "build": {构建配置(该部分详见BuildConfig的文档)},
  22. //! "install": {安装配置(该部分详见InstallConfig的文档)},
  23. //! "envs" : [{ "key": "环境变量名", "value": "环境变量值" }]
  24. //! "build_once": (可选) 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果。
  25. //! }
  26. use std::{
  27. fmt::Debug,
  28. fs::{DirEntry, ReadDir},
  29. path::PathBuf,
  30. };
  31. use log::{debug, error, info};
  32. use self::task::DADKTask;
  33. pub mod task;
  34. pub mod task_log;
  35. #[cfg(test)]
  36. mod tests;
  37. /// # 配置解析器
  38. ///
  39. /// 用于解析配置文件,生成任务列表
  40. #[derive(Debug)]
  41. pub struct Parser {
  42. /// 配置文件目录
  43. config_dir: PathBuf,
  44. /// 扫描到的配置文件列表
  45. config_files: Vec<PathBuf>,
  46. }
  47. pub struct ParserError {
  48. pub config_file: Option<PathBuf>,
  49. pub error: InnerParserError,
  50. }
  51. impl Debug for ParserError {
  52. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  53. match &self.error {
  54. InnerParserError::IoError(e) => {
  55. if let Some(config_file) = &self.config_file {
  56. write!(
  57. f,
  58. "IO Error while parsing config file {}: {}",
  59. config_file.display(),
  60. e
  61. )
  62. } else {
  63. write!(f, "IO Error while parsing config files: {}", e)
  64. }
  65. }
  66. InnerParserError::JsonError(e) => {
  67. if let Some(config_file) = &self.config_file {
  68. write!(
  69. f,
  70. "Json Error while parsing config file {}: {}",
  71. config_file.display(),
  72. e
  73. )
  74. } else {
  75. write!(f, "Json Error while parsing config file: {}", e)
  76. }
  77. }
  78. InnerParserError::TaskError(e) => {
  79. if let Some(config_file) = &self.config_file {
  80. write!(
  81. f,
  82. "Error while parsing config file {}: {}",
  83. config_file.display(),
  84. e
  85. )
  86. } else {
  87. write!(f, "Error while parsing config file: {}", e)
  88. }
  89. }
  90. }
  91. }
  92. }
  93. #[derive(Debug)]
  94. pub enum InnerParserError {
  95. IoError(std::io::Error),
  96. JsonError(serde_json::Error),
  97. TaskError(String),
  98. }
  99. impl Parser {
  100. pub fn new(config_dir: PathBuf) -> Self {
  101. Self {
  102. config_dir,
  103. config_files: Vec::new(),
  104. }
  105. }
  106. /// # 解析所有配置文件,生成任务列表
  107. ///
  108. /// ## 参数
  109. ///
  110. /// * `config_dir` - 配置文件所在目录
  111. ///
  112. /// ## 返回值
  113. ///
  114. /// * `Ok(Vec<(PathBuf, DADKTask)>)` - 任务列表(配置文件路径, 任务)
  115. /// * `Err(ParserError)` - 解析错误
  116. pub fn parse(&mut self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> {
  117. self.scan_config_files()?;
  118. info!("Found {} config files", self.config_files.len());
  119. let r: Result<Vec<(PathBuf, DADKTask)>, ParserError> = self.gen_tasks();
  120. if r.is_err() {
  121. error!("Error while parsing config files: {:?}", r);
  122. }
  123. return r;
  124. }
  125. /// # 扫描配置文件目录,找到所有配置文件
  126. fn scan_config_files(&mut self) -> Result<(), ParserError> {
  127. info!("Scanning config files in {}", self.config_dir.display());
  128. let mut dir_queue: Vec<PathBuf> = Vec::new();
  129. // 将config目录加入队列
  130. dir_queue.push(self.config_dir.clone());
  131. while !dir_queue.is_empty() {
  132. // 扫描目录,找到所有*.dadk文件
  133. let dir = dir_queue.pop().unwrap();
  134. let entries: ReadDir = std::fs::read_dir(&dir).map_err(|e| ParserError {
  135. config_file: None,
  136. error: InnerParserError::IoError(e),
  137. })?;
  138. for entry in entries {
  139. let entry: DirEntry = entry.map_err(|e| ParserError {
  140. config_file: None,
  141. error: InnerParserError::IoError(e),
  142. })?;
  143. let path: PathBuf = entry.path();
  144. if path.is_dir() {
  145. dir_queue.push(path);
  146. } else if path.is_file() {
  147. let extension: Option<&std::ffi::OsStr> = path.extension();
  148. if extension.is_none() {
  149. continue;
  150. }
  151. let extension: &std::ffi::OsStr = extension.unwrap();
  152. if extension.to_ascii_lowercase() != "dadk" {
  153. continue;
  154. }
  155. // 找到一个配置文件, 加入列表
  156. self.config_files.push(path);
  157. }
  158. }
  159. }
  160. return Ok(());
  161. }
  162. /// # 解析所有配置文件,生成任务列表
  163. ///
  164. /// 一旦发生错误,立即返回
  165. ///
  166. /// ## 返回值
  167. ///
  168. /// * `Ok(Vec<DADKTask>)` - 任务列表
  169. /// * `Err(ParserError)` - 解析错误
  170. fn gen_tasks(&self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> {
  171. let mut result_vec = Vec::new();
  172. for config_file in &self.config_files {
  173. let task: DADKTask = self.parse_config_file(config_file)?;
  174. debug!("Parsed config file {}: {:?}", config_file.display(), task);
  175. result_vec.push((config_file.clone(), task));
  176. }
  177. return Ok(result_vec);
  178. }
  179. /// # 解析单个配置文件,生成任务
  180. ///
  181. /// ## 参数
  182. ///
  183. /// * `config_file` - 配置文件路径
  184. ///
  185. /// ## 返回值
  186. ///
  187. /// * `Ok(DADKTask)` - 生成好的任务
  188. /// * `Err(ParserError)` - 解析错误
  189. pub(super) fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask, ParserError> {
  190. let content = std::fs::read_to_string(config_file).map_err(|e| ParserError {
  191. config_file: Some(config_file.clone()),
  192. error: InnerParserError::IoError(e),
  193. })?;
  194. // 从json字符串中解析出DADKTask
  195. let mut task: DADKTask = serde_json::from_str(&content).map_err(|e| ParserError {
  196. config_file: Some(config_file.clone()),
  197. error: InnerParserError::JsonError(e),
  198. })?;
  199. debug!("Parsed config file {}: {:?}", config_file.display(), task);
  200. // 去除字符串中的空白字符
  201. task.trim();
  202. // 校验DADKTask的参数是否合法
  203. task.validate().map_err(|e| ParserError {
  204. config_file: Some(config_file.clone()),
  205. error: InnerParserError::TaskError(e),
  206. })?;
  207. return Ok(task);
  208. }
  209. }