/
context.go
152 lines (134 loc) · 3.61 KB
/
context.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package helpers
import (
"fmt"
"path"
"path/filepath"
"strings"
"text/template"
log "github.com/sirupsen/logrus"
"github.com/labctl/labctl/utils"
orderedmap "github.com/wk8/go-ordered-map/v2"
)
type Context struct {
// the Kong Command()
Command string
DebugCount int
Settings *Settings
Async bool
// Topology filename, used by config, serve
TopoFilename string
LabctlFilename string
// used by config, serve
TemplatePaths *orderedmap.OrderedMap[string, string]
// used by config
TemplateList []string
// Used by config
NodeFilter []string
Topo Topo
Template *template.Template
// Output of any config command. Either to the terminal or websocket
Output ResultOutput
}
type ContextJson struct {
Command string `json:"command"`
TopoFile string `json:"topofile"`
TopoError string `json:"topoerror"`
TemplatePaths []string `json:"template_paths"`
}
func (ctx *Context) AsJson() *ContextJson {
return &ContextJson{
Command: ctx.Command,
TopoFile: ctx.TopoFilename,
TopoError: ctx.Topo.TopoError,
TemplatePaths: ctx.TemplatePathsSlice(),
}
}
func (c *Context) Load() error {
err := c.Topo.Load(c.TopoFilename)
if err != nil {
c.Topo.TopoError = err.Error()
} else {
c.Topo.TopoError = ""
}
return err
}
// Convert the TemplatePath stored in an orderedmap to a []string
func (c *Context) TemplatePathsSlice() []string {
res := make([]string, 0, c.TemplatePaths.Len())
for pair := c.TemplatePaths.Oldest(); pair != nil; pair = pair.Next() {
res = append(res, pair.Value)
}
return res
}
// Initialize the TopFile and TemplatePaths
func (c *Context) InitPaths(topofile string, paths []string) (string, error) {
var err error
c.TopoFilename, err = ensureTopo(topofile)
if err != nil {
return "", err
}
p := utils.Path{Path: c.TopoFilename}
err = p.Resolve()
if err != nil {
log.Fatalf("cannot access topo file %s: %s", topofile, err)
}
c.TopoFilename = p.Path
// Init the matching labctl file
c.LabctlFilename = labctlFilename(c.TopoFilename)
c.TemplatePaths, err = initTemplatePaths(paths)
if err != nil {
return "", err
}
log.Debugf("Topo file: %s, Template paths: %s", c.TopoFilename, c.TemplatePathsSlice())
return c.TopoFilename, nil
}
// Try find a local topo file
func ensureTopo(topo string) (string, error) {
if topo != "" {
return topo, nil
}
files, err := filepath.Glob("*.clab.y*ml")
if err != nil {
return "", fmt.Errorf("could not find local topo files: %v", err)
}
if len(files) == 0 {
return "", fmt.Errorf("no local topo files")
}
if len(files) > 1 {
return "", fmt.Errorf("multiple topo files found: %v", strings.Join(files, ", "))
}
return files[0], nil
}
// Resolve TemplatePaths and return an ordered map with unique ID
// The unique ID is the key to the map & will be used by the UI
func initTemplatePaths(paths []string) (*orderedmap.OrderedMap[string, string], error) {
res := orderedmap.New[string, string]()
for _, ps := range paths {
p := utils.Path{Path: ps}
err := p.Resolve()
if err != nil {
return nil, fmt.Errorf("path %s: %s", ps, err)
}
n := filepath.Base(p.Path)
i := 1
pval, ok := res.Get(n)
for ok && pval != p.Path { // ensure a unique name & does not already exist
tmp := fmt.Sprintf("%s_%d", n, i)
pval, ok = res.Get(tmp)
if !ok {
n = tmp
}
i++
}
res.Set(n, p.Path)
log.Debugf("--template-path %s [%s]", p.Path, n)
}
return res, nil
}
// Get the labctl filename & mode matching the topology file (.clab.yaml)
func labctlFilename(p string) string {
ext := path.Ext(p)
p = p[0 : len(p)-len(ext)]
p = p[0 : len(p)-len(path.Ext(p))]
return p + ".labctl" + ext
}