package figures import ( "encoding/json" "errors" "fmt" "io/ioutil" "os" "path/filepath" ) var ConfigFileNotFoundErr = errors.New("config file for provided path not found") // fileExists checks if a file exists at a given path func fileExists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } type figuration struct { applicationName string } // NewFiguration creates a new figuration for the provided application func NewFiguration(applicationName string) figuration { return figuration{ applicationName: applicationName, } } // GetConfigFilePath returns the path of a given file within the UserConfigDir. func (fig figuration) GetConfigFilePath(filename string) (string, error) { configDir, err := os.UserConfigDir() if err != nil { return "", fmt.Errorf("error getting current config: %w", err) } // Get or make config dir path configDir = filepath.Join(configDir, fig.applicationName) _ = os.MkdirAll(configDir, 0o755) // Get the path to the provided file name within the config directory configFilePath := filepath.Join(configDir, filename) return configFilePath, err } // ReadConfig populates a provided struct with the data in config file of a given name func (fig figuration) ReadConfig(name string, data interface{}) error { configPath, err := fig.GetConfigFilePath(name) if err != nil { return err } if !fileExists(configPath) { return fmt.Errorf("error reading config from file %s: %w", name, ConfigFileNotFoundErr) } content, err := ioutil.ReadFile(configPath) if err != nil { return fmt.Errorf("error reading config from file: %w", err) } err = json.Unmarshal(content, data) if err != nil { return fmt.Errorf("failed parsing json from config file: %w", err) } return nil } // WriteConfig writes data from the provided struct to the config file with the provided name func (fig figuration) WriteConfig(name string, data interface{}) error { configPath, err := fig.GetConfigFilePath(name) if err != nil { return err } contents, err := json.Marshal(data) if err != nil { return fmt.Errorf("failed converting config to json: %w", err) } if err = ioutil.WriteFile(configPath, contents, 0o600); err != nil { return fmt.Errorf("error writing config to file: %w", err) } return nil } type Config interface { ApplicationName() string Filename() string } // ReadConfig populates the provided struct matching the Config interface with config values from the user's config store func ReadConfig(config Config) error { return NewFiguration(config.ApplicationName()).ReadConfig(config.Filename(), config) } // WriteConfig writes the provided struct matching the Config interface to the users config store func WriteConfig(config Config) error { return NewFiguration(config.ApplicationName()).WriteConfig(config.Filename(), config) }