From 2f2748b123eed0bda8160f0bc9b83e39010e68fa Mon Sep 17 00:00:00 2001 From: Mufeed Ali Date: Sat, 19 Jul 2025 22:56:15 +0530 Subject: [PATCH] feat: XDG_CONFIG_HOME support - If a user has already set the XDG_CONFIG_HOME variable, they expect config to be placed there. - This change allows users who set the variable to take advantage of it. - It should not break existing users' experience in any way. --- README.md | 2 +- cmd/root.go | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2b88020..c731312 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Run `bootdev login` to authenticate with your Boot.dev account. After authentica ## Configuration -The Boot.dev CLI offers a couple of configuration options that are stored in a config file (default is `~/.bootdev.yaml`). +The Boot.dev CLI offers a couple of configuration options that are stored in a config file (default is `~/.bootdev.yaml` or `$XDG_CONFIG_HOME/bootdev/config.yaml`). All commands have `-h`/`--help` flags if you want to see available options on the command line. diff --git a/cmd/root.go b/cmd/root.go index 7e674a7..dcdd6f0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,6 +14,7 @@ import ( ) var cfgFile string +var xdgCfgHome string var rootCmd = &cobra.Command{ Use: "bootdev", @@ -34,7 +35,8 @@ func Execute(currentVersion string) error { func init() { cobra.OnInitialize(initConfig) - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bootdev.yaml)") + xdgCfgHome = os.Getenv("XDG_CONFIG_HOME") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bootdev.yaml or $XDG_CONFIG_HOME/bootdev/config.yaml)") } func readViperConfig(paths []string) error { @@ -68,10 +70,28 @@ func initConfig() { // viper's built in config path thing sucks, let's do it ourselves defaultPath := path.Join(home, ".bootdev.yaml") configPaths := []string{} - configPaths = append(configPaths, path.Join(home, ".config", "bootdev", "config.yaml")) + + // If `$HOME/.bootdev.yaml` already exists, prefer that. configPaths = append(configPaths, defaultPath) + + if xdgCfgHome != "" { + // If $XDG_CONFIG_HOME is set by the user, consider that our primary path. + defaultPath = path.Join(xdgCfgHome, "bootdev", "config.yaml") + + // Create the config directory if it doesn't exist yet + err = os.MkdirAll(path.Dir(defaultPath), 0755) + cobra.CheckErr(err) + + // Add the new XDG-based defaultPath to the config paths as well. + configPaths = append(configPaths, defaultPath) + } else { + // Add search path but do not create it and do not consider it the default. + configPaths = append(configPaths, path.Join(home, ".config", "bootdev", "config.yaml")) + } + if err := readViperConfig(configPaths); err != nil { - viper.SafeWriteConfigAs(defaultPath) + err = viper.SafeWriteConfigAs(defaultPath) + cobra.CheckErr(err) viper.SetConfigFile(defaultPath) err = viper.ReadInConfig() cobra.CheckErr(err)