forked from Masterminds/glide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
130 lines (120 loc) · 3.03 KB
/
parser.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
package gom
// This is copied + slightly adapted from gom's `gomfile.go` file.
//
// gom's license is MIT-style.
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
"strings"
)
var qx = `'[^']*'|"[^"]*"`
var kx = `:[a-z][a-z0-9_]*`
var ax = `(?:\s*` + kx + `\s*|,\s*` + kx + `\s*)`
var reGroup = regexp.MustCompile(`\s*group\s+((?:` + kx + `\s*|,\s*` + kx + `\s*)*)\s*do\s*$`)
var reEnd = regexp.MustCompile(`\s*end\s*$`)
var reGom = regexp.MustCompile(`^\s*gom\s+(` + qx + `)\s*((?:,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*))*)$`)
var reOptions = regexp.MustCompile(`(,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*)\s*)`)
func unquote(name string) string {
name = strings.TrimSpace(name)
if len(name) > 2 {
if (name[0] == '\'' && name[len(name)-1] == '\'') || (name[0] == '"' && name[len(name)-1] == '"') {
return name[1 : len(name)-1]
}
}
return name
}
func parseOptions(line string, options map[string]interface{}) {
ss := reOptions.FindAllStringSubmatch(line, -1)
reA := regexp.MustCompile(ax)
for _, s := range ss {
kvs := strings.SplitN(strings.TrimSpace(s[0])[1:], "=>", 2)
kvs[0], kvs[1] = strings.TrimSpace(kvs[0]), strings.TrimSpace(kvs[1])
if kvs[1][0] == '[' {
as := reA.FindAllStringSubmatch(kvs[1][1:len(kvs[1])-1], -1)
a := []string{}
for i := range as {
it := strings.TrimSpace(as[i][0])
if strings.HasPrefix(it, ",") {
it = strings.TrimSpace(it[1:])
}
if strings.HasPrefix(it, ":") {
it = strings.TrimSpace(it[1:])
}
a = append(a, it)
}
options[kvs[0][1:]] = a
} else {
options[kvs[0][1:]] = unquote(kvs[1])
}
}
}
// Gom represents configuration from Gom.
type Gom struct {
name string
options map[string]interface{}
}
func parseGomfile(filename string) ([]Gom, error) {
f, err := os.Open(filename + ".lock")
if err != nil {
f, err = os.Open(filename)
if err != nil {
return nil, err
}
}
br := bufio.NewReader(f)
goms := make([]Gom, 0)
n := 0
skip := 0
valid := true
var envs []string
for {
n++
lb, _, err := br.ReadLine()
if err != nil {
if err == io.EOF {
return goms, nil
}
return nil, err
}
line := strings.TrimSpace(string(lb))
if line == "" || strings.HasPrefix(line, "#") {
continue
}
name := ""
options := make(map[string]interface{})
var items []string
if reGroup.MatchString(line) {
envs = strings.Split(reGroup.FindStringSubmatch(line)[1], ",")
for i := range envs {
envs[i] = strings.TrimSpace(envs[i])[1:]
}
valid = true
continue
} else if reEnd.MatchString(line) {
if !valid {
skip--
if skip < 0 {
return nil, fmt.Errorf("Syntax Error at line %d", n)
}
}
valid = false
envs = nil
continue
} else if skip > 0 {
continue
} else if reGom.MatchString(line) {
items = reGom.FindStringSubmatch(line)[1:]
name = unquote(items[0])
parseOptions(items[1], options)
} else {
return nil, fmt.Errorf("Syntax Error at line %d", n)
}
if envs != nil {
options["group"] = envs
}
goms = append(goms, Gom{name, options})
}
}