-
Notifications
You must be signed in to change notification settings - Fork 2
/
load.go
177 lines (144 loc) · 4.27 KB
/
load.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package osmzen
import (
"embed"
"fmt"
"io/ioutil"
"os"
"path"
"github.com/paulmach/osmzen/filter"
"github.com/paulmach/osmzen/postprocess"
"github.com/paulmach/osmzen/transform"
"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
)
// DefaultConfig is the reference to yaml and csv files with the
// default configuration of kind/kind_detail mappings. These
// files are found in the config sub-directory.
//go:embed config
var DefaultConfig embed.FS
type ReadFiler interface {
ReadFile(string) ([]byte, error)
}
// Config is the full queries.yaml config file for this library.
type Config struct {
All []string `yaml:"all"`
Layers map[string]*Layer `yaml:"layers"`
PostProcess []*postprocess.Config `yaml:"post_process"`
postProcessors []postprocess.Function
clipFactors map[string]float64
}
// Layer defines config for a single layer.
type Layer struct {
ClipFactor float64 `yaml:"clip_factor"`
GeometryTypes []string `yaml:"geometry_types"`
Transforms []string `yaml:"transform"`
// Currently unused
Sort string `yaml:"sort"`
AreaInclusionThreshold int `yaml:"area-inclusion-threshold"`
filters []*filter.Filter
transforms []transform.Transform
}
// Load take a path to the queries.yaml file and load+compiles it.
func Load(filename string) (*Config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, errors.WithMessage(err, "failed to read config")
}
dir, _ := path.Split(filename)
return loadConfig(data, func(name string) ([]byte, error) {
return os.ReadFile(path.Join(dir, name))
})
}
// LoadEmbeddedConfig will load the config and layers using the compiled in assets.
//
// Deprecated: use LoadDefaultConfig instead
func LoadEmbeddedConfig(asset func(string) ([]byte, error)) (*Config, error) {
data, err := asset("queries.yaml")
if err != nil {
return nil, err
}
return loadConfig(data, asset)
}
// LoadDefaultConfig will load the default config embedded in this package.
func LoadDefaultConfig() (*Config, error) {
data, err := DefaultConfig.ReadFile("config/queries.yaml")
if err != nil {
return nil, err
}
return loadConfig(data, func(name string) ([]byte, error) {
return DefaultConfig.ReadFile("config/" + name)
})
}
func loadConfig(data []byte, asset func(name string) ([]byte, error)) (*Config, error) {
c := &Config{}
err := yaml.Unmarshal(data, &c)
if err != nil {
return nil, errors.WithMessage(err, "failed to unmarshal")
}
// clips factors is one, of potentially many things defined on the
// layer config that is needed by the post processors. All the information
// needs to be found here and passed to the compilers.
c.clipFactors = make(map[string]float64)
for _, name := range c.All {
lc := c.Layers[name]
err := lc.load(name, asset)
if err != nil {
return nil, errors.WithMessage(err, name)
}
c.clipFactors[name] = lc.ClipFactor
}
ppctx := &postprocess.CompileContext{
Asset: asset,
ClipFactors: c.clipFactors,
}
for i, p := range c.PostProcess {
f, err := postprocess.Compile(ppctx, p)
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("post process %d", i))
}
if f == nil {
continue
}
c.postProcessors = append(c.postProcessors, f)
}
return c, nil
}
func (l *Layer) load(name string, asset func(string) ([]byte, error)) error {
if l == nil {
return errors.Errorf("undefined layer")
}
data, err := asset(path.Join("yaml", name+".yaml"))
if err != nil {
return errors.WithMessage(err, fmt.Sprintf("failed to load %v", name))
}
l.filters, err = layerCompile(data)
if err != nil {
return err
}
l.transforms = make([]transform.Transform, 0, len(l.Transforms))
for _, t := range l.Transforms {
tf, ok := transform.Map(t)
if !ok {
return errors.Errorf("transform undefined: %s", t)
}
if tf != nil {
l.transforms = append(l.transforms, tf)
}
}
return nil
}
func layerCompile(data []byte) ([]*filter.Filter, error) {
l := &struct {
Filters []*filter.Filter `yaml:"filters"`
}{}
err := yaml.Unmarshal(data, &l)
if err != nil {
return nil, errors.WithMessage(err, "failed to unmarshal")
}
for i, f := range l.Filters {
if err := f.Compile(); err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed on filter %d", i))
}
}
return l.Filters, nil
}