-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathparse.go
More file actions
129 lines (111 loc) · 3.49 KB
/
parse.go
File metadata and controls
129 lines (111 loc) · 3.49 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
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
// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nginxconf
import (
"bytes"
"fmt"
"io"
"os"
crossplane "github.com/nginxinc/nginx-go-crossplane"
)
// parseNginxConfig uses the crossplane parser to parse NGINX configuration.
// The body parameter contains the raw config bytes, and filename is used
// as the source file name. Included files are resolved from disk.
func parseNginxConfig(body []byte, filename string) ([]Directive, error) {
payload, err := crossplane.Parse(filename, &crossplane.ParseOptions{
// Use a custom Open function so the main config body is read from
// the provided bytes instead of from disk. Included files are
// opened normally from the filesystem.
Open: func(path string) (io.ReadCloser, error) {
if path == filename {
return io.NopCloser(bytes.NewReader(body)), nil
}
return os.Open(path)
},
// Combine all included files into a single config tree so the
// caller sees a unified set of directives.
CombineConfigs: true,
// Skip directive validation because the adapter handles
// unrecognized directives by emitting warnings rather than errors.
SkipDirectiveContextCheck: true,
SkipDirectiveArgsCheck: true,
})
if err != nil {
return nil, fmt.Errorf("crossplane parse: %v", err)
}
if len(payload.Config) == 0 {
return nil, nil
}
return convertDirectives(payload.Config[0].Parsed), nil
}
// convertDirectives converts crossplane Directives into the adapter's Directive type.
func convertDirectives(cpDirs crossplane.Directives) []Directive {
var dirs []Directive
for _, cpDir := range cpDirs {
if cpDir.IsComment() {
continue
}
dir := Directive{
// Params combines the directive name and its arguments into a
// single slice, matching the convention used by the rest of
// the adapter code (Params[0] is the name).
Params: append([]string{cpDir.Directive}, cpDir.Args...),
File: cpDir.File,
Line: cpDir.Line,
}
if cpDir.IsBlock() {
dir.Block = convertDirectives(cpDir.Block)
}
dirs = append(dirs, dir)
}
return dirs
}
// Directive represents an nginx configuration directive.
type Directive struct {
// Params contains the name and parameters on
// the line. The first element is the name.
Params []string
// Block contains the block contents, if present.
Block []Directive
File string
Line int
}
// Name returns the value of the first parameter.
func (d Directive) Name() string {
return d.Param(0)
}
// Param returns the parameter at position idx.
func (d Directive) Param(idx int) string {
if idx < len(d.Params) {
return d.Params[idx]
}
return ""
}
func getDirective(dirs []Directive, name string) (Directive, bool) {
for _, dir := range dirs {
if dir.Name() == name {
return dir, true
}
}
return Directive{}, false
}
func getAllDirectives(dirs []Directive, name string) []Directive {
var matched []Directive
for _, dir := range dirs {
if dir.Name() == name {
matched = append(matched, dir)
}
}
return matched
}