this repo has no description
at main 136 lines 3.0 kB view raw
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}