-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathconfig.go
208 lines (169 loc) · 6.01 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package bw
import (
"log"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/james-lawrence/bw/internal/envx"
"github.com/james-lawrence/bw/internal/systemx"
yaml "gopkg.in/yaml.v2"
"github.com/pkg/errors"
)
const (
// DefaultDir agent and client configuration directory, relative to a absolute path.
DefaultDir = "bearded-wookie"
// DefaultAgentConfig default filename of the agent configuration.
DefaultAgentConfig = "agent.config"
// DefaultDeployspaceDir default directory of the workspace.
DefaultDeployspaceDir = ".bw"
// DefaultDeployspaceConfigDir default configuration directory of the workspace.
DefaultDeployspaceConfigDir = ".bwconfig"
// DefaultEnvironmentName name of the environment to default to.
DefaultEnvironmentName = "default"
// DefaultClientConfig default filename for the client configuration
DefaultClientConfig = "config.yml"
)
var fallbackUser = user.User{
Gid: "0",
Uid: "0",
HomeDir: "/root",
}
// LocateDeployspace - looks for the provided filename up the file tree.
// and returns the path once found, if no path is found then it returns
// the name without a directory, which makes its a relative path.
func LocateDeployspace(name string) string {
// fallback to root so it'll stop immediately.
for dir := systemx.WorkingDirectoryOrDefault("/"); dir != "/"; dir = filepath.Dir(dir) {
path := filepath.Join(dir, name)
if _, err := os.Stat(path); err == nil {
return path
}
}
return name
}
// DefaultConfigFile returns the default configuration file location.
func DefaultConfigFile() string {
return DefaultLocation(filepath.Join(DefaultEnvironmentName, DefaultAgentConfig), "")
}
// DefaultLocation returns the location of file path to be read based using
// the given name and potentially an override path.
// File locations are checked in the following order:
// {override}/{name}
// ${XDG_CONFIG_HOME}/{DefaultDir}/{name}
// ${HOME}/.config/{DefaultDir}/{name}
// /etc/{DefaultDir}/{name}
//
// if none of the files are found then the last location checked is returned.
func DefaultLocation(name, override string) string {
user := systemx.CurrentUserOrDefault(fallbackUser)
envconfig := filepath.Join(os.Getenv("XDG_CONFIG_HOME"), DefaultDir)
home := filepath.Join(user.HomeDir, ".config", DefaultDir)
system := filepath.Join("/etc", DefaultDir)
return locateFile(name, override, envconfig, home, system)
}
// LocateFirstInDir locates the first file in the given directory by name.
func LocateFirstInDir(dir string, names ...string) (result string) {
for _, name := range names {
result = filepath.Join(dir, name)
if _, err := os.Stat(result); err == nil {
break
}
}
return result
}
// LocateFirst locates the first file that exists
func LocateFirst(paths ...string) (name string) {
for _, name = range paths {
if _, err := os.Stat(name); err == nil {
break
}
}
return name
}
// DefaultUserDirLocation returns the user directory location.
func DefaultUserDirLocation(name string) string {
user := systemx.CurrentUserOrDefault(fallbackUser)
envconfig := filepath.Join(os.Getenv("XDG_CONFIG_HOME"), DefaultDir)
home := filepath.Join(user.HomeDir, ".config", DefaultDir)
return DefaultDirectory(name, envconfig, home)
}
// DefaultDirLocation looks for a directory one of the default directory locations.
func DefaultDirLocation(rel string) string {
user := systemx.CurrentUserOrDefault(fallbackUser)
env := filepath.Join(os.Getenv("XDG_CONFIG_HOME"), DefaultDir)
home := filepath.Join(user.HomeDir, ".config", DefaultDir)
system := filepath.Join("/etc", DefaultDir)
return DefaultDirectory(rel, env, home, system)
}
// DefaultCacheDirectory cache directory for storing data.
func DefaultCacheDirectory() string {
user := systemx.CurrentUserOrDefault(fallbackUser)
cachedir := os.Getenv("CACHE_DIRECTORY")
env := filepath.Join(os.Getenv("XDG_CACHE_HOME"), DefaultDir)
home := filepath.Join(user.HomeDir, ".cache", DefaultDir)
system := filepath.Join("/", "var", "cache", DefaultDir)
return DefaultDirectory("", cachedir, env, home, system)
}
// DefaultDirectory finds the first directory root that exists and then returns
// that root directory joined with the relative path provided.
func DefaultDirectory(rel string, roots ...string) (path string) {
for _, root := range roots {
path = filepath.Join(root, rel)
if _, err := os.Stat(root); err == nil {
return path
}
}
return path
}
func locateFile(name string, searchDirs ...string) (result string) {
for _, dir := range searchDirs {
result = filepath.Join(dir, name)
if _, err := os.Stat(result); err == nil {
break
}
}
return result
}
// ExpandAndDecodeFile ...
func ExpandAndDecodeFile(path string, dst interface{}) (err error) {
var (
raw []byte
)
if _, err = os.Stat(path); os.IsNotExist(err) {
return nil
}
if raw, err = os.ReadFile(path); err != nil {
return errors.WithStack(err)
}
if envx.Boolean(false, EnvLogsConfiguration, EnvLogsVerbose) {
log.Println("loaded configuration", path)
}
return ExpandAndDecode(raw, dst)
}
// ExpandAndDecode expands environment variables within the file at the specified
// path and then decodes it as yaml.
func ExpandAndDecode(raw []byte, dst interface{}) (err error) {
return ExpandEnvironAndDecode(raw, dst, os.Getenv)
}
// ExpandEnvironAndDecode ...
func ExpandEnvironAndDecode(raw []byte, dst interface{}, mapping func(string) string) (err error) {
m := func(in string) string {
return normalizeEnv(mapping(in))
}
if envx.Boolean(false, EnvLogsConfiguration, EnvLogsVerbose) {
log.Println("configuration:\n", os.Expand(string(raw), m))
}
return yaml.Unmarshal([]byte(os.Expand(string(raw), m)), dst)
}
// InitializeDeploymentDirectory initializes the directory for the deployments.
func InitializeDeploymentDirectory(root string) (err error) {
if err = os.MkdirAll(filepath.Join(root, DirDeploys), 0755); err != nil {
return errors.WithStack(err)
}
return nil
}
// fixes environment variable value for use in YAML files.
func normalizeEnv(s string) string {
return strings.Replace(s, "\n", "\n\n", -1) // ensure newlines work as expected.
}