Skip to content

Commit

Permalink
* Documents config.ConfigPath to be more clear
Browse files Browse the repository at this point in the history
* Adds a test for config.ConfigPath
* Adds error handling for config.ConfigPath
  • Loading branch information
kevin-cantwell authored and ddvk committed Sep 23, 2024
1 parent 95dd565 commit b93f2ae
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 20 deletions.
5 changes: 4 additions & 1 deletion api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ const (
)

func AuthHttpCtx(reAuth, nonInteractive bool) *transport.HttpClientCtx {
configPath := config.ConfigPath()
configPath, err := config.ConfigPath()
if err != nil {
log.Error.Fatal("failed to get config path")
}
authTokens := config.LoadTokens(configPath)
httpClientCtx := transport.CreateHttpClientCtx(authTokens)

Expand Down
31 changes: 17 additions & 14 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package config

import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"

"github.com/juruen/rmapi/log"
Expand All @@ -18,39 +18,42 @@ const (
configFileEnvVar = "RMAPI_CONFIG"
)

func ConfigPath() (config string) {
configFile, ok := os.LookupEnv(configFileEnvVar)
if ok {
return configFile
/*
ConfigPath returns the path to the config file. It will check the following in order:
- If the RMAPI_CONFIG environment variable is set, it will use that path.
- If a config file exists in the user's home dir as described by os.UserHomeDir, it will use that.
- Otherwise, it will use the XDG config dir, as described by os.UserConfigDir.
*/
func ConfigPath() (string, error) {
if config, ok := os.LookupEnv(configFileEnvVar); ok {
return config, nil
}

user, err := user.Current()
home, err := os.UserHomeDir()
if err != nil {
log.Error.Panicln("failed to get current user:", err)
return "", fmt.Errorf("failed to get current user: %w", err)
}

home := user.HomeDir
config = filepath.Join(home, defaultConfigFile)
config := filepath.Join(home, defaultConfigFile)

//return config in home if exists
if _, err := os.Stat(config); err == nil {
return
return config, nil
}

configDir, err := os.UserConfigDir()
if err != nil {
log.Warning.Println("cannot determine config dir, using HOME", err)
return
return config, nil
}

xdgConfigDir := filepath.Join(configDir, appName)
err = os.MkdirAll(xdgConfigDir, 0700)
if err != nil {
if err := os.MkdirAll(xdgConfigDir, 0700); err != nil {
log.Error.Panicln("cannot create config dir "+xdgConfigDir, err)
}
config = filepath.Join(xdgConfigDir, defaultConfigFileXDG)

return
return config, nil

}

Expand Down
87 changes: 86 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sync"
"testing"

"github.com/juruen/rmapi/model"
"github.com/stretchr/testify/assert"
)

func TestSaveLoadConfig(t *testing.T) {
tokens := model.AuthTokens{"foo", "bar"}
tokens := model.AuthTokens{
DeviceToken: "foo",
UserToken: "bar",
}

f, err := ioutil.TempFile("", "rmapitmp")

Expand All @@ -30,3 +36,82 @@ func TestSaveLoadConfig(t *testing.T) {
assert.Equal(t, "foo", savedTokens.DeviceToken)
assert.Equal(t, "bar", savedTokens.UserToken)
}

func TestConfigPath(t *testing.T) {
// let's not mess with the user's home dir
home := "HOME"
switch runtime.GOOS {
case "windows":
home = "USERPROFILE"
case "plan9":
home = "home"
}
if err := os.Setenv(home, os.TempDir()); err != nil {
t.Error(err)
}

tearDown := func() {
_ = os.Unsetenv(configFileEnvVar)
_ = os.Remove(filepath.Join(os.TempDir(), defaultConfigFile))
}

tests := []struct {
name string
setup func()
want string
wantErr bool
}{
{
name: "no home no env config exists",
setup: func() {},
want: func() string {
xdgConfigDir, err := os.UserConfigDir()
if err != nil {
t.Error(err)
}
xdgConfig := filepath.Join(xdgConfigDir, appName, defaultConfigFileXDG)
return xdgConfig
}(),
},
{
name: "home config exists",
setup: func() {
homeConfig := filepath.Join(os.TempDir(), defaultConfigFile)
if err := ioutil.WriteFile(homeConfig, []byte("test"), 0644); err != nil {
t.Error(err)
}
},
want: filepath.Join(os.TempDir(), defaultConfigFile),
},
{
name: "env config exists",
setup: func() {
if err := os.Setenv(configFileEnvVar, filepath.Join(os.TempDir(), "rmapi.yaml")); err != nil {
t.Error(err)
}
},
want: filepath.Join(os.TempDir(), "rmapi.yaml"),
},
}

// Can't allow parallel execution because of shared file state
wg := sync.WaitGroup{}
for _, tt := range tests {
wg.Add(1)
t.Run(tt.name, func(t *testing.T) {
defer wg.Done()
defer tearDown()
tt.setup()

got, err := ConfigPath()
if (err != nil) != tt.wantErr {
t.Errorf("ConfigPath() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ConfigPath() = %v, want %v", got, tt.want)
}
})
wg.Wait()
}
}
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ func parseOfflineCommands(cmd []string) bool {

switch cmd[0] {
case "reset":
configFile := config.ConfigPath()
err := os.Remove(configFile)
configFile, err := config.ConfigPath()
if err != nil {
log.Error.Fatalln(err)
}
if err := os.Remove(configFile); err != nil {
log.Error.Fatalln(err)
}
return true
case "version":
fmt.Println(version.Version)
Expand Down
4 changes: 2 additions & 2 deletions model/auth.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package model

type AuthTokens struct {
DeviceToken string
UserToken string
DeviceToken string `yaml:"devicetoken"`
UserToken string `yaml:"usertoken"`
}

type DeviceTokenRequest struct {
Expand Down

0 comments on commit b93f2ae

Please sign in to comment.