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