xref: /DragonReach/src/parse/graph/mod.rs (revision b40b6b4d2f72c30a382f9f18740fa73d7fc90721)
1 use crate::{
2     error::parse_error::{ParseError, ParseErrorType},
3     unit::UnitType,
4 };
5 
6 #[cfg(target_os = "dragonos")]
7 use drstd as std;
8 use std::io::BufRead;
9 use std::string::{String, ToString};
10 use std::vec::Vec;
11 
12 use super::UnitParser;
13 
14 pub struct GraphNode {
15     value: String,
16     edges: Vec<usize>,
17     incoming_edges: Vec<usize>,
18 }
19 
20 pub struct Graph {
21     total_edge: u32,
22     max_edge: u32,
23     nodes: Vec<GraphNode>,
24     value: Vec<String>,
25 }
26 
27 impl Graph {
28     fn new() -> Self {
29         return Graph {
30             max_edge: 0,
31             total_edge: 0,
32             nodes: Vec::new(),
33             value: Vec::new(),
34         };
35     }
36 
37     pub fn add_node(&mut self, value: &String) -> usize {
38         let index = self.nodes.len();
39         //如果nodes中已经有了这个value则无需重复添加,直接返回nodes中的value对应的index
40         if let Some(idx) = self.value.iter().position(|x| *x == *value) {
41             return idx;
42         }
43         //如果value在nodes中不存在,则添加value
44         self.nodes.push(GraphNode {
45             value: value.to_string(),
46             edges: Vec::new(),
47             incoming_edges: Vec::new(),
48         });
49         self.value.push(value.to_string());
50         return index;
51     }
52     pub fn add_edge(&mut self, from: usize, to: usize) {
53         self.total_edge += 1;
54         self.nodes[from].edges.push(to);
55         self.nodes[to].incoming_edges.push(from);
56     }
57     pub fn topological_sort(&mut self) -> Result<Vec<String>, ParseError> {
58         let mut result = Vec::new();
59         let mut visited = Vec::new();
60         let mut stack = Vec::new();
61         for (i, node) in self.nodes.iter().enumerate() {
62             if node.incoming_edges.len() == 0 {
63                 stack.push(i);
64             }
65         }
66         while stack.len() > 0 {
67             let index = stack.pop().unwrap();
68             if visited.contains(&index) {
69                 continue;
70             }
71             visited.push(index);
72             result.push(self.nodes[index].value.clone());
73             let len = self.nodes[index].edges.len();
74             for i in 0..len {
75                 let edge = self.nodes[index].edges[i];
76                 self.nodes[edge].incoming_edges.retain(|&x| x != index);
77                 if self.nodes[edge].incoming_edges.len() == 0 {
78                     stack.push(edge);
79                 }
80             }
81         }
82         if result.len() != self.nodes.len() {
83             return Err(ParseError::new(
84                 ParseErrorType::ECircularDependency,
85                 "".to_string(),
86                 0,
87             ));
88         }
89         result.reverse();
90         return Ok(result);
91     }
92 
93     fn add_edges(&mut self, path: &String, after: Vec<String>) {
94         //因为service的依赖关系规模不会很大,故先使用递归实现
95         //TODO:改递归
96         for target in after {
97             let s = self.add_node(&path);
98             let t = self.add_node(&target);
99             self.add_edge(s, t);
100             if self.total_edge > self.max_edge {
101                 return;
102             }
103             self.add_edges(&target, Self::parse_after(&target));
104         }
105     }
106 
107     // TODO: 完善这里,目前还是可能会有循环依赖的问题,因为目前只判断了After字段,其他字段也有可能导致循环依赖问题
108     pub fn construct_graph(unit: String) -> Result<Graph, ParseError> {
109         //计算整个依赖图中的节点数
110         let mut node_num = 1;
111         let mut dep = Vec::new();
112         Self::get_node_num(&unit, &mut dep, &mut node_num)?;
113 
114         let mut graph: Graph = Graph::new();
115         graph.max_edge = node_num * (node_num - 1);
116 
117         graph.add_node(&unit);
118         let after = Self::parse_after(&unit);
119         //递归添加边来构建图
120         graph.add_edges(&unit, after);
121 
122         if graph.max_edge < graph.total_edge {
123             return Err(ParseError::new(
124                 ParseErrorType::ECircularDependency,
125                 unit,
126                 0,
127             ));
128         }
129 
130         return Ok(graph);
131     }
132 
133     pub fn parse_after(path: &String) -> Vec<String> {
134         let mut ret = Vec::new();
135 
136         let reader = UnitParser::get_reader(path, UnitType::Unknown).unwrap();
137 
138         let mut lines_with_after = Vec::new();
139 
140         for line_result in reader.lines() {
141             if let Ok(line) = line_result {
142                 if line.starts_with("After") {
143                     lines_with_after.push(line);
144                 }
145             }
146         }
147 
148         for line in lines_with_after {
149             let after = &line.split('=').collect::<Vec<&str>>()[1];
150             let units = after.split_whitespace().collect::<Vec<&str>>();
151 
152             for unit in units {
153                 ret.push(String::from(unit));
154             }
155         }
156 
157         ret
158     }
159 
160     /// ## 获取到unit文件依赖图节点数
161     ///
162     /// ### param file_path unit文件路径
163     ///
164     /// ### dependencies 缓存after依赖的容器
165     ///
166     /// ### total_after_count 返回节点数
167     ///
168     /// ### return
169     fn get_node_num(
170         file_path: &str,
171         dependencies: &mut Vec<String>,
172         total_after_count: &mut u32,
173     ) -> Result<(), ParseError> {
174         let reader = UnitParser::get_reader(file_path, UnitType::Unknown)?;
175 
176         let mut current_after_count = 0;
177 
178         for line_result in reader.lines() {
179             if let Ok(line) = line_result {
180                 if line.starts_with("After=") {
181                     let dependencies_str = &line[6..];
182                     let dependency_list: Vec<&str> = dependencies_str.split_whitespace().collect();
183 
184                     for dependency in dependency_list {
185                         if dependencies.contains(&dependency.to_string()) {
186                             // 循环依赖检查
187                             continue;
188                         }
189 
190                         dependencies.push(dependency.to_string());
191 
192                         // 递归解析依赖链
193                         Self::get_node_num(dependency, dependencies, total_after_count)?;
194                     }
195 
196                     current_after_count += 1;
197                 }
198             }
199         }
200 
201         *total_after_count += current_after_count;
202 
203         Ok(())
204     }
205 }
206