-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig_file_type.go
125 lines (109 loc) · 3.7 KB
/
config_file_type.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
package configurator
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/matthewhartstonge/configurator/diag"
)
var (
_ ConfigParser = (*ConfigFileType)(nil)
_ ConfigFileParser = (*ConfigFileType)(nil)
_ ConfigImplementer = (*ConfigFileType)(nil)
)
// NewConfigFileType provides most functionality required to support a new file
// type. If manual unmarshaling is required, the Unmarshaler can be provided.
func NewConfigFileType(
config ConfigImplementer,
fileTypes []string,
unmarshaler Unmarshaler,
) ConfigFileType {
return ConfigFileType{
unmarshaler: unmarshaler,
Types: fileTypes,
ConfigType: ConfigType{
Config: config,
},
}
}
// Unmarshaler unmarshals a byte slice into the given interface.
type Unmarshaler func(data []byte, v interface{}) error
// ConfigFileType provides a ConfigImplementer that reads a file from disk and
// unmarshals it into the Config field. Unmarshaling expects implementations to
// match the standard library interface for Unmarshal.
type ConfigFileType struct {
// unmarshaler is a function that unmarshals a byte slice into a given
// interface.
unmarshaler Unmarshaler
// Path is the path to the file that will be read and unmarshaled.
Path string
// Types is a list of file types or dot extensions that the provider
// is able to process.
Types []string
// ConfigType is the embedded configurator.ConfigType.
ConfigType
}
// Type returns which parser is in use.
func (f *ConfigFileType) Type() string {
return "Not Implemented"
}
// Stat checks if the file exists and computes the platform specific Path and
// directly writes to the provided diagnostics.
func (f *ConfigFileType) Stat(diags *diag.Diagnostics, component diag.Component, cfg *Config, filePath string) bool {
// todo: tidy `ConfigFileType.Stat` implementation. there should be a better way.
filename := filepath.Base(filePath)
fileExt := filepath.Ext(filePath)
for _, fileType := range f.Types {
// stat for full paths, if provided.
if fileExt != "" {
if fileExt != "."+fileType {
// full file path provided, ext does match provider file type - skip.
diags.FromComponent(component, filePath).
Trace("Skipping File Type",
"The file type does not match "+fileType)
continue
}
// stat full path!
info, err := os.Stat(filePath)
if err != nil {
diags.FromComponent(component, filePath).
Trace("Config File Not Found",
"No config file was found at the specified path, error: "+err.Error())
return false
}
if info.IsDir() {
// y u disguised as file...
continue
}
// specified config file exists for the given file parser!
f.Path = filePath
diags.FromComponent(component, filePath).
Trace("Config File Found",
fmt.Sprintf("Will attempt to parse %s", filename))
return true
}
// Dynamically build the expected config file path that can be parsed
// with this provider to check for files existence.
cfgFilePath := filePath + string(filepath.Separator) + cfg.FileName + "." + filePath
if _, err := os.Stat(cfgFilePath); err == nil {
f.Path = cfgFilePath
diags.FromComponent(component, filePath).
Trace("Config File Found",
fmt.Sprintf("Will attempt to parse %s", cfgFilePath))
return true
}
}
diags.FromComponent(component, filePath).
Trace("Config File Not Found",
fmt.Sprintf("Unable to find config file for extensions {%s} at %s", strings.Join(f.Types, ", "), filePath))
return false
}
// Parse reads the file based on the generated path computed from Stat and
// unmarshals it into the Config field.
func (f *ConfigFileType) Parse(_ *Config) (string, error) {
file, err := os.ReadFile(f.Path)
if err != nil {
return f.Path, err
}
return f.Path, f.unmarshaler(file, f.Config)
}