-
Notifications
You must be signed in to change notification settings - Fork 32
/
config.go
111 lines (86 loc) · 2.43 KB
/
config.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
package editorconfig
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"golang.org/x/mod/semver"
)
// ErrInvalidVersion represents a standard error with the semantic version.
var ErrInvalidVersion = errors.New("invalid semantic version")
// Config holds the configuration.
type Config struct {
Path string
Name string
Version string
Parser Parser
Graceful bool
}
// Load loads definition of a given file.
func (config *Config) Load(filename string) (*Definition, error) {
definition, warning, err := config.LoadGraceful(filename)
if warning != nil {
err = errors.Join(err, warning)
}
return definition, err
}
// Load loads definition of a given file with warnings and error.
func (config *Config) LoadGraceful(filename string) (*Definition, error, error) { //nolint:funlen
// idiomatic go allows empty struct
if config.Parser == nil {
config.Parser = new(SimpleParser)
}
absFilename, err := filepath.Abs(filename)
if err != nil {
return nil, nil, fmt.Errorf("cannot get absolute path for %q: %w", filename, err)
}
ecFile := config.Name
if ecFile == "" {
ecFile = ConfigNameDefault
}
definition := &Definition{}
definition.Raw = make(map[string]string)
if config.Version != "" {
version := config.Version
if !strings.HasPrefix(version, "v") {
version = "v" + version
}
if ok := semver.IsValid(version); !ok {
return nil, nil, fmt.Errorf("version %s error: %w", config.Version, ErrInvalidVersion)
}
definition.version = version
}
var warning error
dir := absFilename
for dir != filepath.Dir(dir) {
dir = filepath.Dir(dir)
ec, warn, err := config.Parser.ParseIniGraceful(filepath.Join(dir, ecFile))
if warn != nil {
warning = errors.Join(warning, warn)
}
if err != nil {
if errors.Is(err, os.ErrNotExist) {
continue
}
return nil, nil, fmt.Errorf("cannot parse the ini file %q: %w", ecFile, err)
}
// give it the current config.
ec.config = config
relativeFilename := absFilename
if len(dir) < len(relativeFilename) {
relativeFilename = relativeFilename[len(dir):]
}
// turn any Windows-y filename into the standard forward slash ones.
relativeFilename = filepath.ToSlash(relativeFilename)
def, err := ec.GetDefinitionForFilename(relativeFilename)
if err != nil {
return nil, nil, fmt.Errorf("cannot get definition for %q: %w", relativeFilename, err)
}
definition.merge(def)
if ec.Root {
break
}
}
return definition, warning, nil
}