this repo has no description
1package config
2
3import (
4 "fmt"
5 "os"
6 "time"
7
8 "gopkg.in/yaml.v3"
9)
10
11type SecretMapping struct {
12 EncryptedPath string `yaml:"encrypted"`
13 OutputPath string `yaml:"output"`
14}
15
16type FileConfig struct {
17 Path string `yaml:"path"`
18 Output string `yaml:"output,omitempty"`
19}
20
21type GitConfig struct {
22 Repo string `yaml:"repo"`
23 Branch string `yaml:"branch"`
24}
25
26func (g GitConfig) IsValid() bool {
27 return g.Repo != "" && g.Branch != ""
28}
29
30type AppConfig struct {
31 GitConfig GitConfig `yaml:"git,omitempty"`
32 Files []FileConfig `yaml:"files"`
33}
34
35type AgeConfig struct {
36 Identity string `yaml:"identity,omitempty"`
37 Identities []string `yaml:"identities"`
38 Recipients []string `yaml:"recipients,omitempty"`
39}
40
41type Config struct {
42 Interval time.Duration `yaml:"-"`
43 IntervalString string `yaml:"interval"`
44 Age AgeConfig `yaml:"age"`
45 StatePath string `yaml:"statePath"`
46 GitConfig GitConfig `yaml:"git"`
47 Apps map[string]AppConfig `yaml:"apps"`
48}
49
50func Load(path string) (*Config, error) {
51 data, err := os.ReadFile(path)
52 if err != nil {
53 return nil, err
54 }
55
56 var cfg Config
57 if err := yaml.Unmarshal(data, &cfg); err != nil {
58 return nil, err
59 }
60
61 // validate config
62 // must have at least one git config
63 hasAnyGit := cfg.GitConfig.IsValid()
64 if !hasAnyGit {
65 for _, app := range cfg.Apps {
66 if app.GitConfig.IsValid() {
67 hasAnyGit = true
68 break
69 }
70 }
71 }
72 if !hasAnyGit {
73 return nil, fmt.Errorf("no git configuration found: set either top-level git or app-specific git")
74 }
75
76 // validate interval
77 cfg.Interval, err = time.ParseDuration(cfg.IntervalString)
78 if err != nil {
79 return nil, fmt.Errorf("invalid interval: %w", err)
80 }
81 return &cfg, nil
82}
83
84func InitConfig(
85 path,
86 app,
87 repo,
88 branch,
89 key string,
90) error {
91 _, openConfigErr := os.Stat(path)
92 if openConfigErr == nil && app == "" {
93 return fmt.Errorf("config file already exists")
94 }
95 var cfg Config
96 // init new config if not exists
97 if openConfigErr != nil {
98 cfg = Config{
99 IntervalString: "10m",
100 StatePath: ".nox-state.json",
101 Age: AgeConfig{
102 Identities: []string{key},
103 },
104 GitConfig: GitConfig{
105 Repo: repo,
106 Branch: branch,
107 },
108 }
109 } else if app != "" {
110 if cfgPtr, err := Load(path); err != nil {
111 return fmt.Errorf("failed to open config: %w", err)
112 } else {
113 cfg = *cfgPtr
114 }
115 // check if app exists
116 if _, exists := cfg.Apps[app]; exists {
117 return fmt.Errorf("app %s already exists", app)
118 }
119
120 var appConfig AppConfig
121 // check for existing repo
122 if repo != "" && cfg.GitConfig.Repo != repo && cfg.GitConfig.Branch != branch {
123 appConfig.GitConfig = GitConfig{
124 Repo: repo,
125 Branch: branch,
126 }
127 }
128 cfg.Apps[app] = appConfig
129 }
130
131 cfgYaml, err := yaml.Marshal(cfg)
132 if err != nil {
133 return fmt.Errorf("failed to marshal config: %w", err)
134 }
135 return os.WriteFile(path, cfgYaml, 0600)
136}