1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00
wtf/cfg/config_files.go
Sam Roberts 4bb725db9e golangci-lint configuration file
golangci-lint can run all the currently enabled linters, and as far as I
can tell, does it in under 5 seconds as opposed to over 180 seconds
(compare `time make cilint` and `time make lint`).

Some of the linters that are listed in the "enabled" section but
commented out looked like a good idea to me, and fairly low hanging
fruit to fix, but they are not passing at the moment.

All the linters covered in the current Makefile are run.

TODO:
- replace lint target in Makefile with golangci-lint
- remove .github/workflow/errcheck.yml
2020-05-16 12:34:57 -07:00

225 lines
5.2 KiB
Go

package cfg
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"github.com/olebedev/config"
)
const (
// XdgConfigDir defines the path to the minimal XDG-compatible configuration directory
XdgConfigDir = "~/.config/"
// WtfConfigDirV1 defines the path to the first version of configuration. Do not use this
WtfConfigDirV1 = "~/.wtf/"
// WtfConfigDirV2 defines the path to the second version of the configuration. Use this.
WtfConfigDirV2 = "~/.config/wtf/"
// WtfConfigFile defines the name of the default config file
WtfConfigFile = "config.yml"
)
/* -------------------- Exported Functions -------------------- */
// CreateFile creates the named file in the config directory, if it does not already exist.
// If the file exists it does not recreate it.
// If successful, eturns the absolute path to the file
// If unsuccessful, returns an error
func CreateFile(fileName string) (string, error) {
configDir, err := WtfConfigDir()
if err != nil {
return "", err
}
filePath := fmt.Sprintf("%s/%s", configDir, fileName)
// Check if the file already exists; if it does not, create it
_, err = os.Stat(filePath)
if err != nil {
if os.IsNotExist(err) {
_, err = os.Create(filePath)
if err != nil {
return "", err
}
} else {
return "", err
}
}
return filePath, nil
}
// Initialize takes care of settings up the initial state of WTF configuration
// It ensures necessary directories and files exist
func Initialize(hasCustom bool) {
if !hasCustom {
migrateOldConfig()
}
// These always get created because this is where modules should write any permanent
// data they need to persist between runs (i.e.: log, textfile, etc.)
createWtfConfigDir()
if !hasCustom {
createWtfConfigFile()
chmodConfigFile()
}
}
// WtfConfigDir returns the absolute path to the configuration directory
func WtfConfigDir() (string, error) {
configDir := os.Getenv("XDG_CONFIG_HOME")
if configDir == "" {
configDir = WtfConfigDirV2
} else {
configDir += "/wtf/"
}
configDir, err := expandHomeDir(configDir)
if err != nil {
return "", err
}
return configDir, nil
}
// LoadWtfConfigFile loads the specified config file
func LoadWtfConfigFile(filePath string) *config.Config {
absPath, _ := expandHomeDir(filePath)
cfg, err := config.ParseYamlFile(absPath)
if err != nil {
displayWtfConfigFileLoadError(absPath, err)
os.Exit(1)
}
return cfg
}
/* -------------------- Unexported Functions -------------------- */
// chmodConfigFile sets the mode of the config file to r+w for the owner only
func chmodConfigFile() {
configDir, _ := WtfConfigDir()
relPath := fmt.Sprintf("%s%s", configDir, WtfConfigFile)
absPath, _ := expandHomeDir(relPath)
_, err := os.Stat(absPath)
if err != nil && os.IsNotExist(err) {
return
}
err = os.Chmod(absPath, 0600)
if err != nil {
return
}
}
// createWtfConfigDir creates the necessary directories for storing the default config file
// If ~/.config/wtf is missing, it will try to create it
func createWtfConfigDir() {
wtfConfigDir, _ := WtfConfigDir()
if _, err := os.Stat(wtfConfigDir); os.IsNotExist(err) {
err := os.MkdirAll(wtfConfigDir, os.ModePerm)
if err != nil {
displayWtfConfigDirCreateError(err)
os.Exit(1)
}
}
}
// createWtfConfigFile creates a simple config file in the config directory if
// one does not already exist
func createWtfConfigFile() {
filePath, err := CreateFile(WtfConfigFile)
if err != nil {
displayDefaultConfigCreateError(err)
os.Exit(1)
}
// If the file is empty, write to it
file, _ := os.Stat(filePath)
if file.Size() == 0 {
if ioutil.WriteFile(filePath, []byte(defaultConfigFile), 0600) != nil {
displayDefaultConfigWriteError(err)
os.Exit(1)
}
}
}
// Expand expands the path to include the home directory if the path
// is prefixed with `~`. If it isn't prefixed with `~`, the path is
// returned as-is.
func expandHomeDir(path string) (string, error) {
if len(path) == 0 {
return path, nil
}
if path[0] != '~' {
return path, nil
}
if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
return "", errors.New("cannot expand user-specific home dir")
}
dir, err := home()
if err != nil {
return "", err
}
return filepath.Join(dir, path[1:]), nil
}
// Dir returns the home directory for the executing user.
// An error is returned if a home directory cannot be detected.
func home() (string, error) {
currentUser, err := user.Current()
if err != nil {
return "", err
}
if currentUser.HomeDir == "" {
return "", errors.New("cannot find user-specific home dir")
}
return currentUser.HomeDir, nil
}
// migrateOldConfig copies any existing configuration from the old location
// to the new, XDG-compatible location
func migrateOldConfig() {
srcDir, _ := expandHomeDir(WtfConfigDirV1)
destDir, _ := WtfConfigDir()
// If the old config directory doesn't exist, do not move
if _, err := os.Stat(srcDir); os.IsNotExist(err) {
return
}
// If the new config directory already exists, do not move
if _, err := os.Stat(destDir); err == nil {
return
}
// Time to move
err := Copy(srcDir, destDir)
if err != nil {
panic(err)
}
// Delete the old directory if the new one exists
if _, err := os.Stat(destDir); err == nil {
err := os.RemoveAll(srcDir)
if err != nil {
fmt.Println(err)
}
}
}