-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinclude.go
117 lines (98 loc) · 2.85 KB
/
include.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
package feature
import (
"context"
"errors"
"fmt"
iofs "io/fs"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
"github.com/joesonw/gofigure"
)
type includeFeature struct {
fs []iofs.FS
loadedContents map[string][]byte
loadedNodes map[string]bool
}
func Include(fs ...iofs.FS) gofigure.Feature {
return &includeFeature{
fs: fs,
loadedContents: map[string][]byte{},
loadedNodes: map[string]bool{},
}
}
func (*includeFeature) Name() string {
return "!include"
}
//nolint:gocyclo
func (f *includeFeature) Resolve(ctx context.Context, loader *gofigure.Loader, node *gofigure.Node) (*gofigure.Node, error) {
if node.Kind() != yaml.MappingNode {
return nil, fmt.Errorf("!include requires a mapping node")
}
fileNode, err := node.GetMappingChild("file")
if err != nil {
return nil, gofigure.NewNodeError(node, err)
}
if fileNode != nil {
pathNode, err := fileNode.GetMappingChild("path")
if err != nil {
return nil, gofigure.NewNodeError(fileNode, fmt.Errorf("unable to get path: %w", err))
}
if pathNode == nil {
return nil, gofigure.NewNodeError(fileNode, fmt.Errorf("key \"path\" is missing for file"))
}
parseNode, err := fileNode.GetMappingChild("parse")
if err != nil {
return nil, gofigure.NewNodeError(fileNode, fmt.Errorf("unable to get parse: %w", err))
}
keyNode, err := fileNode.GetMappingChild("key")
if err != nil {
return nil, gofigure.NewNodeError(fileNode, fmt.Errorf("unable to get key: %w", err))
}
parse := false
if parseNode != nil {
parse, err = parseNode.BoolValue()
if err != nil {
return nil, gofigure.NewNodeError(parseNode, err)
}
}
path := strings.TrimSpace(pathNode.Value())
contents, ok := f.loadedContents[path]
if !ok {
found := false
for _, fs := range f.fs {
contents, err = iofs.ReadFile(fs, path)
if errors.Is(err, os.ErrNotExist) {
continue
}
if err != nil {
return nil, gofigure.NewNodeError(pathNode, fmt.Errorf("unable to read file %q: %w", path, err))
}
found = true
f.loadedContents[path] = contents
break
}
if !found {
return nil, gofigure.NewNodeError(pathNode, fmt.Errorf("unable to find file %q: %w", path, os.ErrNotExist))
}
}
if !parse {
return gofigure.NewScalarNode(string(contents)), nil
}
if !f.loadedNodes[path] {
if err := loader.Load(path, f.loadedContents[path]); err != nil {
return nil, gofigure.NewNodeError(pathNode, fmt.Errorf("unable to load file %q: %w", path, err))
}
f.loadedNodes[path] = true
}
dotPath := filepath.Clean(path)
dotPath = strings.TrimSuffix(dotPath, filepath.Ext(dotPath))
dotPath = strings.ReplaceAll(dotPath, string(filepath.Separator), ".")
if keyNode != nil {
dotPath += "." + strings.TrimSpace(keyNode.Value())
}
return loader.GetNode(ctx, dotPath)
}
return gofigure.NewScalarNode(""), nil
}