forked from realvnc-labs/tacoscript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate.go
More file actions
90 lines (75 loc) · 2.52 KB
/
validate.go
File metadata and controls
90 lines (75 loc) · 2.52 KB
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
package script
import (
"fmt"
"strings"
"github.com/cloudradar-monitoring/tacoscript/tasks"
"github.com/cloudradar-monitoring/tacoscript/utils"
"github.com/elliotchance/orderedmap"
)
func isCyclic(curScriptID string,
scriptIDToRequiredScriptIDsMap map[string][]string,
visited map[string]bool,
requestStack,
cyclicItems *orderedmap.OrderedMap) bool {
if isInRequestStack, ok := requestStack.Get(curScriptID); ok && isInRequestStack.(bool) {
cyclicItems.Set(curScriptID, true)
return true
}
if isVisited, ok := visited[curScriptID]; ok && isVisited {
return false
}
visited[curScriptID] = true
requestStack.Set(curScriptID, true)
cyclicItems.Set(curScriptID, true)
if requirements, ok := scriptIDToRequiredScriptIDsMap[curScriptID]; ok {
for _, requirement := range requirements {
isCyclic := isCyclic(requirement, scriptIDToRequiredScriptIDsMap, visited, requestStack, cyclicItems)
if isCyclic {
return true
}
}
}
requestStack.Set(curScriptID, false)
cyclicItems.Delete(curScriptID)
return false
}
func ValidateScripts(scrpts tasks.Scripts) error {
scriptIDToNodesMap := make(map[string][]string)
scriptIDsMap := make(map[string]bool, len(scrpts))
requirements := make(map[string]string)
errs := utils.Errors{}
for _, script := range scrpts {
scriptIDToNodesMap[script.ID] = make([]string, 0)
scriptIDsMap[script.ID] = true
for _, task := range script.Tasks {
for k, reqName := range task.GetRequirements() {
requirements[reqName] = fmt.Sprintf("%s.%s[%d]", task.GetPath(), tasks.RequireField, k)
scriptIDToNodesMap[script.ID] = append(scriptIDToNodesMap[script.ID], reqName)
if reqName == script.ID {
errs.Add(fmt.Errorf("task at path '%s' cannot require own script '%s'", task.GetPath(), script.ID))
continue
}
}
}
}
reqFailures := make([]string, 0, len(requirements))
for reqName, reqPath := range requirements {
if _, ok := scriptIDsMap[reqName]; !ok {
reqFailures = append(reqFailures, fmt.Sprintf("'%s' at path '%s'", reqName, reqPath))
}
}
if len(reqFailures) > 0 {
errs.Add(fmt.Errorf("missing required scripts %s", strings.Join(reqFailures, ", ")))
}
requestStack := orderedmap.NewOrderedMap()
visited := make(map[string]bool)
for curScriptID := range scriptIDToNodesMap {
cyclicItms := orderedmap.NewOrderedMap()
isCyclic := isCyclic(curScriptID, scriptIDToNodesMap, visited, requestStack, cyclicItms)
if isCyclic {
errs.Add(fmt.Errorf("cyclic requirements are detected: '%s'", cyclicItms.Keys()))
break
}
}
return errs.ToError()
}