~egtann/up

ref: 1ab0f861d8d69becf312b45bf8acdec04f8c9667 up/parser.go -rw-r--r-- 1.6 KiB
1ab0f861 — Evan Tann simplify tool 4 months ago
                                                                                
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
package up

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"strings"
)

// ParseUpfile to build a Config tree.
func ParseUpfile(r io.Reader) (*Config, error) {
	t := &Config{
		Commands: map[string][]string{},
		Vars:     map[string]string{},
	}

	var cmd, line string
	scn := bufio.NewScanner(r)
	for i := 1; scn.Scan(); i++ {
		// We might be continuing a previous line from a trailing '\'
		curLine := scn.Text()
		trimmedLine := strings.TrimSpace(curLine)
		if trimmedLine == "" {
			continue
		}
		if trimmedLine[0] == '#' {
			continue
		}

		if cmd != "" && curLine[0] != '\t' {
			cmd = ""
		}

		// We're parsing a command
		if cmd != "" {
			line += trimmedLine
			if line[len(line)-1] == '\\' {
				line = line[:len(line)-1]
				continue
			}
			t.Commands[cmd] = append(t.Commands[cmd], line)
			line = ""
			continue
		}

		// We're not parsing a command. Either we're parsing a variable
		// or a command name. Attempt to parse a variable first.
		varParts := strings.SplitN(curLine, "=", 2)
		if len(varParts) == 2 {
			t.Vars[varParts[0]] = varParts[1]
			continue
		}

		// We're not parsing a variable, so we're parsing a command
		// name.
		if strings.Index(curLine, ":") == -1 {
			return nil, fmt.Errorf("line %d: missing colon in command", i)
		}
		parts := strings.SplitN(curLine, ":", 2)
		cmd = parts[0]
		if parts[1] != "" {
			return nil, fmt.Errorf("line %d: unexpected content after colon", i)
		}
		if t.DefaultCommand == "" {
			t.DefaultCommand = cmd
		}
	}
	if err := scn.Err(); err != nil {
		return nil, fmt.Errorf("scan: %w", err)
	}
	if len(t.Commands) == 0 {
		return nil, errors.New("no commands")
	}
	return t, nil
}