1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::collections::HashMap;
use balena_temen::ast::Expression;
use balena_temen::ast::ExpressionValue;
use balena_temen::ast::Identifier;
use balena_temen::ast::IdentifierValue;
use crate::dsl::schema::compiler::CompilationError;
use crate::dsl::schema::SchemaList;
#[derive(Debug, Clone)]
pub struct DependencyGraph {
all: HashMap<String, DependencyTree>,
}
#[derive(Debug, Clone)]
struct DependencyTree {
tree: Vec<String>,
}
pub fn dependencies_for_schema_list(
maybe_list: Option<&SchemaList>,
previous_tree: DependencyGraph,
) -> Result<DependencyGraph, CompilationError> {
match maybe_list {
None => Ok(DependencyGraph::empty()),
Some(list) => {
let mut tree = previous_tree;
for schema in list.entries() {
if let Some(when) = &schema.schema.when {
tree = tree.push(&schema.name, &when)?;
}
if let Some(children) = &schema.schema.children {
for named_child in children.entries() {
tree = dependencies_for_schema_list(named_child.schema.children.as_ref(), tree)?;
}
}
}
Ok(tree)
}
}
}
impl DependencyGraph {
pub fn contains(&self, schema_name: &str) -> bool {
self.all.contains_key(schema_name)
}
pub fn dependencies_for(&self, schema_name: &str) -> Vec<&str> {
if self.contains(schema_name) {
self.all[schema_name].tree.iter().map(|name| name.as_ref()).collect()
} else {
vec![]
}
}
}
impl DependencyGraph {
pub fn empty() -> DependencyGraph {
DependencyGraph { all: HashMap::new() }
}
fn push(self, name: &str, depends_on: &Expression) -> Result<DependencyGraph, CompilationError> {
let map = match self.all.get(name) {
None => {
let mut map = self.all.clone();
match depends_on.value {
ExpressionValue::Identifier(ref identifiers) => {
map.insert(name.to_string(), DependencyTree::start_with(identifiers)?);
}
_ => {
return Err(CompilationError::with_message(
"walking logical expression that is more than a single identifier",
));
}
}
map
}
Some(_previous) => {
return Err(CompilationError::with_message(
"merging with previously seen expression in not supported yet",
));
}
};
Ok(DependencyGraph { all: map })
}
}
impl DependencyTree {
fn start_with(identifiers: &Identifier) -> Result<DependencyTree, CompilationError> {
let mut result = vec![];
for identifier in &identifiers.values {
match identifier {
IdentifierValue::Name(name) => {
result.push(name.clone());
}
_ => return Err(CompilationError::with_message("unimplemented")),
}
}
Ok(DependencyTree { tree: result })
}
}