1
|
|
|
package gom |
2
|
|
|
|
3
|
|
|
// This is copied + slightly adapted from gom's `gomfile.go` file. |
4
|
|
|
// |
5
|
|
|
// gom's license is MIT-style. |
6
|
|
|
|
7
|
|
|
import ( |
8
|
|
|
"bufio" |
9
|
|
|
"fmt" |
10
|
|
|
"io" |
11
|
|
|
"os" |
12
|
|
|
"regexp" |
13
|
|
|
"strings" |
14
|
|
|
) |
15
|
|
|
|
16
|
|
|
var qx = `'[^']*'|"[^"]*"` |
17
|
|
|
var kx = `:[a-z][a-z0-9_]*` |
18
|
|
|
var ax = `(?:\s*` + kx + `\s*|,\s*` + kx + `\s*)` |
19
|
|
|
var reGroup = regexp.MustCompile(`\s*group\s+((?:` + kx + `\s*|,\s*` + kx + `\s*)*)\s*do\s*$`) |
20
|
|
|
var reEnd = regexp.MustCompile(`\s*end\s*$`) |
21
|
|
|
var reGom = regexp.MustCompile(`^\s*gom\s+(` + qx + `)\s*((?:,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*))*)$`) |
22
|
|
|
var reOptions = regexp.MustCompile(`(,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*)\s*)`) |
23
|
|
|
|
24
|
|
|
func unquote(name string) string { |
25
|
|
|
name = strings.TrimSpace(name) |
26
|
|
|
if len(name) > 2 { |
27
|
|
|
if (name[0] == '\'' && name[len(name)-1] == '\'') || (name[0] == '"' && name[len(name)-1] == '"') { |
28
|
|
|
return name[1 : len(name)-1] |
29
|
|
|
} |
30
|
|
|
} |
31
|
|
|
return name |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
func parseOptions(line string, options map[string]interface{}) { |
35
|
|
|
ss := reOptions.FindAllStringSubmatch(line, -1) |
36
|
|
|
reA := regexp.MustCompile(ax) |
37
|
|
|
for _, s := range ss { |
38
|
|
|
kvs := strings.SplitN(strings.TrimSpace(s[0])[1:], "=>", 2) |
39
|
|
|
kvs[0], kvs[1] = strings.TrimSpace(kvs[0]), strings.TrimSpace(kvs[1]) |
40
|
|
|
if kvs[1][0] == '[' { |
41
|
|
|
as := reA.FindAllStringSubmatch(kvs[1][1:len(kvs[1])-1], -1) |
42
|
|
|
a := []string{} |
43
|
|
|
for i := range as { |
44
|
|
|
it := strings.TrimSpace(as[i][0]) |
45
|
|
|
if strings.HasPrefix(it, ",") { |
46
|
|
|
it = strings.TrimSpace(it[1:]) |
47
|
|
|
} |
48
|
|
|
if strings.HasPrefix(it, ":") { |
49
|
|
|
it = strings.TrimSpace(it[1:]) |
50
|
|
|
} |
51
|
|
|
a = append(a, it) |
52
|
|
|
} |
53
|
|
|
options[kvs[0][1:]] = a |
54
|
|
|
} else { |
55
|
|
|
options[kvs[0][1:]] = unquote(kvs[1]) |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
// Gom represents configuration from Gom. |
61
|
|
|
type Gom struct { |
62
|
|
|
name string |
63
|
|
|
options map[string]interface{} |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
func parseGomfile(filename string) ([]Gom, error) { |
67
|
|
|
f, err := os.Open(filename + ".lock") |
68
|
|
|
if err != nil { |
69
|
|
|
f, err = os.Open(filename) |
70
|
|
|
if err != nil { |
71
|
|
|
return nil, err |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
br := bufio.NewReader(f) |
75
|
|
|
|
76
|
|
|
goms := make([]Gom, 0) |
77
|
|
|
|
78
|
|
|
n := 0 |
79
|
|
|
skip := 0 |
80
|
|
|
valid := true |
81
|
|
|
var envs []string |
82
|
|
|
for { |
83
|
|
|
n++ |
84
|
|
|
lb, _, err := br.ReadLine() |
85
|
|
|
if err != nil { |
86
|
|
|
if err == io.EOF { |
87
|
|
|
return goms, nil |
88
|
|
|
} |
89
|
|
|
return nil, err |
90
|
|
|
} |
91
|
|
|
line := strings.TrimSpace(string(lb)) |
92
|
|
|
if line == "" || strings.HasPrefix(line, "#") { |
93
|
|
|
continue |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
name := "" |
97
|
|
|
options := make(map[string]interface{}) |
98
|
|
|
var items []string |
99
|
|
|
if reGroup.MatchString(line) { |
100
|
|
|
envs = strings.Split(reGroup.FindStringSubmatch(line)[1], ",") |
101
|
|
|
for i := range envs { |
102
|
|
|
envs[i] = strings.TrimSpace(envs[i])[1:] |
103
|
|
|
} |
104
|
|
|
valid = true |
105
|
|
|
continue |
106
|
|
|
} else if reEnd.MatchString(line) { |
107
|
|
|
if !valid { |
108
|
|
|
skip-- |
109
|
|
|
if skip < 0 { |
110
|
|
|
return nil, fmt.Errorf("Syntax Error at line %d", n) |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
valid = false |
114
|
|
|
envs = nil |
115
|
|
|
continue |
116
|
|
|
} else if skip > 0 { |
117
|
|
|
continue |
118
|
|
|
} else if reGom.MatchString(line) { |
119
|
|
|
items = reGom.FindStringSubmatch(line)[1:] |
120
|
|
|
name = unquote(items[0]) |
121
|
|
|
parseOptions(items[1], options) |
122
|
|
|
} else { |
123
|
|
|
return nil, fmt.Errorf("Syntax Error at line %d", n) |
124
|
|
|
} |
125
|
|
|
if envs != nil { |
126
|
|
|
options["group"] = envs |
127
|
|
|
} |
128
|
|
|
goms = append(goms, Gom{name, options}) |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|