mod.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. //! }
  25. use std::{
  26. fmt::Debug,
  27. fs::{DirEntry, ReadDir},
  28. path::PathBuf,
  29. };
  30. use log::{error, info, debug};
  31. use self::task::DADKTask;
  32. pub mod task;
  33. /// # 配置解析器
  34. ///
  35. /// 用于解析配置文件,生成任务列表
  36. #[derive(Debug)]
  37. pub struct Parser {
  38. /// 配置文件目录
  39. config_dir: PathBuf,
  40. /// 扫描到的配置文件列表
  41. config_files: Vec<PathBuf>,
  42. }
  43. pub struct ParserError {
  44. pub config_file: Option<PathBuf>,
  45. pub error: InnerParserError,
  46. }
  47. impl Debug for ParserError {
  48. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  49. match &self.error {
  50. InnerParserError::IoError(e) => {
  51. if let Some(config_file) = &self.config_file {
  52. write!(
  53. f,
  54. "IO Error while parsing config file {}: {}",
  55. config_file.display(),
  56. e
  57. )
  58. } else {
  59. write!(f, "IO Error while parsing config files: {}", e)
  60. }
  61. }
  62. InnerParserError::JsonError(e) => {
  63. if let Some(config_file) = &self.config_file {
  64. write!(
  65. f,
  66. "Json Error while parsing config file {}: {}",
  67. config_file.display(),
  68. e
  69. )
  70. } else {
  71. write!(f, "Json Error while parsing config file: {}", e)
  72. }
  73. }
  74. InnerParserError::TaskError(e) => {
  75. if let Some(config_file) = &self.config_file {
  76. write!(
  77. f,
  78. "Error while parsing config file {}: {}",
  79. config_file.display(),
  80. e
  81. )
  82. } else {
  83. write!(f, "Error while parsing config file: {}", e)
  84. }
  85. }
  86. }
  87. }
  88. }
  89. #[derive(Debug)]
  90. pub enum InnerParserError {
  91. IoError(std::io::Error),
  92. JsonError(serde_json::Error),
  93. TaskError(String),
  94. }
  95. impl Parser {
  96. pub fn new(config_dir: PathBuf) -> Self {
  97. Self {
  98. config_dir,
  99. config_files: Vec::new(),
  100. }
  101. }
  102. /// # 解析所有配置文件,生成任务列表
  103. ///
  104. /// ## 参数
  105. ///
  106. /// * `config_dir` - 配置文件所在目录
  107. ///
  108. /// ## 返回值
  109. ///
  110. /// * `Ok(Vec<(PathBuf, DADKTask)>)` - 任务列表(配置文件路径, 任务)
  111. /// * `Err(ParserError)` - 解析错误
  112. pub fn parse(&mut self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> {
  113. self.scan_config_files()?;
  114. info!("Found {} config files", self.config_files.len());
  115. let r: Result<Vec<(PathBuf, DADKTask)>, ParserError> = self.gen_tasks();
  116. if r.is_err() {
  117. error!("Error while parsing config files: {:?}", r);
  118. }
  119. return r;
  120. }
  121. /// # 扫描配置文件目录,找到所有配置文件
  122. fn scan_config_files(&mut self) -> Result<(), ParserError> {
  123. info!("Scanning config files in {}", self.config_dir.display());
  124. let mut dir_queue: Vec<PathBuf> = Vec::new();
  125. // 将config目录加入队列
  126. dir_queue.push(self.config_dir.clone());
  127. while !dir_queue.is_empty() {
  128. // 扫描目录,找到所有*.dadk文件
  129. let dir = dir_queue.pop().unwrap();
  130. let entries: ReadDir = std::fs::read_dir(&dir).map_err(|e| ParserError {
  131. config_file: None,
  132. error: InnerParserError::IoError(e),
  133. })?;
  134. for entry in entries {
  135. let entry: DirEntry = entry.map_err(|e| ParserError {
  136. config_file: None,
  137. error: InnerParserError::IoError(e),
  138. })?;
  139. let path: PathBuf = entry.path();
  140. if path.is_dir() {
  141. dir_queue.push(path);
  142. } else if path.is_file() {
  143. let extension: Option<&std::ffi::OsStr> = path.extension();
  144. if extension.is_none() {
  145. continue;
  146. }
  147. let extension: &std::ffi::OsStr = extension.unwrap();
  148. if extension.to_ascii_lowercase() != "dadk" {
  149. continue;
  150. }
  151. // 找到一个配置文件, 加入列表
  152. self.config_files.push(path);
  153. }
  154. }
  155. }
  156. return Ok(());
  157. }
  158. /// # 解析所有配置文件,生成任务列表
  159. ///
  160. /// 一旦发生错误,立即返回
  161. ///
  162. /// ## 返回值
  163. ///
  164. /// * `Ok(Vec<DADKTask>)` - 任务列表
  165. /// * `Err(ParserError)` - 解析错误
  166. fn gen_tasks(&self) -> Result<Vec<(PathBuf, DADKTask)>, ParserError> {
  167. let mut result_vec = Vec::new();
  168. for config_file in &self.config_files {
  169. let task: DADKTask = self.parse_config_file(config_file)?;
  170. debug!("Parsed config file {}: {:?}", config_file.display(), task);
  171. result_vec.push((config_file.clone(), task));
  172. }
  173. return Ok(result_vec);
  174. }
  175. /// # 解析单个配置文件,生成任务
  176. ///
  177. /// ## 参数
  178. ///
  179. /// * `config_file` - 配置文件路径
  180. ///
  181. /// ## 返回值
  182. ///
  183. /// * `Ok(DADKTask)` - 生成好的任务
  184. /// * `Err(ParserError)` - 解析错误
  185. fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask, ParserError> {
  186. let content = std::fs::read_to_string(config_file).map_err(|e| ParserError {
  187. config_file: Some(config_file.clone()),
  188. error: InnerParserError::IoError(e),
  189. })?;
  190. // 从json字符串中解析出DADKTask
  191. let mut task: DADKTask = serde_json::from_str(&content).map_err(|e| ParserError {
  192. config_file: Some(config_file.clone()),
  193. error: InnerParserError::JsonError(e),
  194. })?;
  195. debug!("Parsed config file {}: {:?}", config_file.display(), task);
  196. // 去除字符串中的空白字符
  197. task.trim();
  198. // 校验DADKTask的参数是否合法
  199. task.validate().map_err(|e| ParserError {
  200. config_file: Some(config_file.clone()),
  201. error: InnerParserError::TaskError(e),
  202. })?;
  203. return Ok(task);
  204. }
  205. }