-
Notifications
You must be signed in to change notification settings - Fork 1
/
pm_loader.go
123 lines (106 loc) · 2.78 KB
/
pm_loader.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
package pm
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"github.com/telnet2/pm/envmap"
"gopkg.in/yaml.v3"
)
type ConfigFile struct {
Services map[string]*Runnable `yaml:"services"`
}
// WriteFile writes *ConfigFile into a file
func (cf *ConfigFile) WriteFile(yamlFile string) error {
data, err := yaml.Marshal(cf)
if err != nil {
return err
}
return os.WriteFile(yamlFile, data, 0640)
}
func (cf *ConfigFile) String() string {
data, _ := yaml.Marshal(cf)
return string(data)
}
// ExpandEnvs expands env vars used in this runnable.
func ExpandEnvs(r *Runnable) {
envs := make(envmap.EnvMap)
// 1. Load system env vars.
envs.LoadSystem()
// 2. Load the env list.
envs.Load(r.Env)
// 3. Load from env files
envs.LoadFile(calculateRelDir(r.ConfDir, r.EnvFile))
// 4. Expand env-vars that appear in the fields with the "envexp" tag.
envs.Expand(r)
// Expand variables
if r.CommandEx != "" {
// If CommandEx exists, use it without expansion.
r.Command = r.CommandEx
r.CommandEx = ""
}
r.envMap = envs
}
// LoadYaml loads config from io.Reader
func LoadYaml(ctx context.Context, r io.Reader) (*ConfigFile, error) {
data := ConfigFile{}
decoder := yaml.NewDecoder(r)
for {
if err := decoder.Decode(&data); err != nil {
if err == io.EOF {
for id, s := range data.Services {
// Replace a new line
s.Command = regexp.MustCompile(`[\r\n\t]`).ReplaceAllString(s.Command, "")
s.Id = id
s.ConfDir = CtxConfDir(ctx)
ExpandEnvs(s)
s.LogDir = calculateRelDir(s.ConfDir, s.LogDir)
s.WorkDir = calculateRelDir(s.ConfDir, s.WorkDir)
if s.LogDir != "" {
_ = os.MkdirAll(s.LogDir, os.ModePerm)
if fi, err := os.Stat(s.LogDir); err != nil || !fi.IsDir() {
return nil, fmt.Errorf("can't open log_dir: %s", s.LogDir)
}
}
}
return &data, nil
} else {
return nil, err
}
}
}
}
// calculateRelDir calculates the abs dir from a given relative with respect to the config file's dir.
func calculateRelDir(base, dir string) string {
if dir != "" {
// if `dir`` is relative dir,
// then calculate its directory based on the config file's dir.
if !filepath.IsAbs(dir) {
return filepath.Join(base, dir)
}
}
return dir
}
// LoadYamlFile loads a config from a given yaml file.
func LoadYamlFile(ctx context.Context, f string) (*ConfigFile, error) {
if filepath.IsAbs(f) {
// if the file is in absolute path, update the conf dir.
confDir := filepath.Dir(f)
ctx = WithConfDir(ctx, confDir)
} else {
// if the file is relative path, combine with the conf dir.
confDir := CtxConfDir(ctx)
if confDir != "" {
f = filepath.Join(confDir, f)
} else {
ctx = WithConfDir(ctx, filepath.Dir(f))
}
}
fl, err := os.Open(f)
if err != nil {
return nil, err
}
return LoadYaml(ctx, fl)
}