From ee331d11274d4976d72a43f5f2f089649577e5a4 Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Thu, 6 Aug 2020 15:24:47 -0700
Subject: [PATCH 1/2] env: Config dir
---
env/paths.go | 85 ++++++++++++++++++++++++++++++++++++++-
env/paths_darwin_test.go | 19 +++++++++
env/paths_linux_test.go | 16 ++++++++
env/paths_windows_test.go | 13 ++++++
4 files changed, 131 insertions(+), 2 deletions(-)
diff --git a/env/paths.go b/env/paths.go
index e234579..daf317c 100644
--- a/env/paths.go
+++ b/env/paths.go
@@ -30,7 +30,11 @@ func MustAppPath(opt ...PathOption) string {
return path
}
-// AppPath returns path for a files or directory in an app support directory.
+// AppPath returns where to store app (data) files.
+//
+// Darwin: ~/Library/Application Support
+// Windows: %LOCALAPPDATA% (~/AppData/Local)
+// Linux: ~/.local/share
//
// darwin:
// env.AppPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
@@ -104,7 +108,84 @@ func appDir(dirs ...string) (string, error) {
}
}
-// LogsPath returns directory for app files.
+// ConfigPath returns where to store config files.
+//
+// Darwin: ~/Library/Application Support
+// Windows: %APPDATA% (~/AppData/Roaming)
+// Linux: ~/.config
+//
+// darwin:
+// env.ConfigPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "~/Library/Application Support/MyApp/test.txt"
+//
+// windows:
+// env.ConfigPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "%APPDATA%/MyApp/test.txt"
+//
+// linux:
+// env.ConfigPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "~/.config/MyApp/test.txt"
+//
+func ConfigPath(opt ...PathOption) (string, error) {
+ opts, err := newOptions(opt...)
+ if err != nil {
+ return "", err
+ }
+ dir, err := configDir(opts.Dirs...)
+ if err != nil {
+ return "", err
+ }
+ if opts.Mkdir {
+ if err := mkdir(dir); err != nil {
+ return "", err
+ }
+ }
+ return filepath.Join(dir, opts.File), nil
+}
+
+func configDir(dirs ...string) (string, error) {
+ switch runtime.GOOS {
+ case "darwin":
+ return appDir(dirs...)
+ case "windows":
+ dir := os.Getenv("APPDATA")
+ if dir == "" {
+ return "", errors.Errorf("APPDATA not set")
+ }
+ return filepath.Join(dir, filepath.Join(dirs...)), nil
+ case "linux":
+ dir := os.Getenv("XDG_CONFIG_HOME")
+ if dir != "" {
+ return filepath.Join(dir, filepath.Join(dirs...)), nil
+ }
+ home, err := HomeDir()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(home, ".config"), nil
+ default:
+ return "", errors.Errorf("unsupported platform %s", runtime.GOOS)
+ }
+}
+
+// LogsPath returns directory for log files.
+//
+// Darwin: ~/Library/Logs
+// Windows: %LOCALAPPDATA% (~/AppData/Local)
+// Linux: ~/.cache
+//
+// darwin:
+// env.AppPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "~/Library/Application Support/MyApp/test.txt"
+//
+// windows:
+// env.AppPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "%LOCALAPPDATA%/MyApp/test.txt"
+//
+// linux:
+// env.AppPath(env.Dir("MyApp"), env.File("test.txt"), env.Mkdir())
+// => "~/.cache/MyApp/test.txt"
+//
func LogsPath(opt ...PathOption) (string, error) {
opts, err := newOptions(opt...)
if err != nil {
diff --git a/env/paths_darwin_test.go b/env/paths_darwin_test.go
index df92a9a..d587491 100644
--- a/env/paths_darwin_test.go
+++ b/env/paths_darwin_test.go
@@ -1,6 +1,8 @@
package env_test
import (
+ "os"
+ "path/filepath"
"strings"
"testing"
@@ -12,7 +14,24 @@ func TestDirs(t *testing.T) {
appDir, err := env.AppPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(appDir, "/Library/Application Support/KeysTest"))
+ defer os.RemoveAll(appDir)
+
logsDir, err := env.LogsPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(logsDir, "/Library/Logs/KeysTest"))
+ defer os.RemoveAll(logsDir)
+ exists, err := env.PathExists(logsDir)
+ require.NoError(t, err)
+ require.False(t, exists)
+
+ configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
+ require.NoError(t, err)
+ require.True(t, strings.HasSuffix(configPath, "/Library/Application Support/KeysTest/test.txt"))
+ configDir, file := filepath.Split(configPath)
+ require.True(t, strings.HasSuffix(configDir, "/Library/Application Support/KeysTest/"))
+ require.Equal(t, "test.txt", file)
+ defer os.RemoveAll(configDir)
+ exists, err = env.PathExists(configDir)
+ require.NoError(t, err)
+ require.True(t, exists)
}
diff --git a/env/paths_linux_test.go b/env/paths_linux_test.go
index a1c0606..8103979 100644
--- a/env/paths_linux_test.go
+++ b/env/paths_linux_test.go
@@ -1,6 +1,8 @@
package env_test
import (
+ "os"
+ "path/filepath"
"strings"
"testing"
@@ -12,7 +14,21 @@ func TestDirs(t *testing.T) {
appDir, err := env.AppPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(appDir, `/.local/share/KeysTest`))
+ defer os.RemoveAll(appDir)
+
logsDir, err := env.LogsPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(logsDir, `/.cache/KeysTest`))
+ defer os.RemoveAll(logsDir)
+
+ configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
+ require.NoError(t, err)
+ require.True(t, strings.HasSuffix(configPath, "/.config/KeysTest/test.txt"))
+ configDir, file := filepath.Split(configPath)
+ require.True(t, strings.HasSuffix(configDir, "/.config/KeysTest/"))
+ require.Equal(t, "test.txt", file)
+ defer os.RemoveAll(configDir)
+ exists, err = env.PathExists(configDir)
+ require.NoError(t, err)
+ require.True(t, exists)
}
diff --git a/env/paths_windows_test.go b/env/paths_windows_test.go
index ee16eab..5bae1d3 100644
--- a/env/paths_windows_test.go
+++ b/env/paths_windows_test.go
@@ -2,6 +2,7 @@ package env_test
import (
"os"
+ "path/filepath"
"strings"
"testing"
@@ -13,10 +14,22 @@ func TestDirs(t *testing.T) {
appDir, err := env.AppPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(appDir, `\AppData\Local\KeysTest`))
+
logsDir, err := env.LogsPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(logsDir, `\AppData\Local\KeysTest`))
+ configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
+ require.NoError(t, err)
+ require.True(t, strings.HasSuffix(configPath, `\AppData\Roaming\KeysTest\test.txt`))
+ configDir, file := filepath.Split(configPath)
+ require.True(t, strings.HasSuffix(configDir, `\AppData\Roaming\KeysTest\`))
+ require.Equal(t, "test.txt", file)
+ defer os.RemoveAll(configDir)
+ exists, err = env.PathExists(configDir)
+ require.NoError(t, err)
+ require.True(t, exists)
+
err = os.Setenv("LOCALAPPDATA", "")
require.NoError(t, err)
_, err = env.AppPath(env.Dir("KeysTest"))
From 6693acfe547da5a15c4adc7b0542cd17a689e49e Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Thu, 6 Aug 2020 16:09:22 -0700
Subject: [PATCH 2/2] Tests
---
env/paths.go | 78 +++++++++++++++++++++++++++++++--------
env/paths_darwin_test.go | 33 +++++++++++------
env/paths_linux_test.go | 68 ++++++++++++++++++++++++++++------
env/paths_windows_test.go | 22 ++++++++---
4 files changed, 156 insertions(+), 45 deletions(-)
diff --git a/env/paths.go b/env/paths.go
index daf317c..e4631b4 100644
--- a/env/paths.go
+++ b/env/paths.go
@@ -95,14 +95,14 @@ func appDir(dirs ...string) (string, error) {
return filepath.Join(dir, filepath.Join(dirs...)), nil
case "linux":
dir := os.Getenv("XDG_DATA_HOME")
- if dir == "" {
- home, err := HomeDir()
- if err != nil {
- return "", err
- }
- dir = filepath.Join(home, ".local", "share", filepath.Join(dirs...))
+ if dir != "" {
+ return filepath.Join(dir, filepath.Join(dirs...)), nil
+ }
+ home, err := HomeDir()
+ if err != nil {
+ return "", err
}
- return dir, nil
+ return filepath.Join(home, ".local", "share", filepath.Join(dirs...)), nil
default:
return "", errors.Errorf("unsupported platform %s", runtime.GOOS)
}
@@ -162,7 +162,7 @@ func configDir(dirs ...string) (string, error) {
if err != nil {
return "", err
}
- return filepath.Join(home, ".config"), nil
+ return filepath.Join(home, ".config", filepath.Join(dirs...)), nil
default:
return "", errors.Errorf("unsupported platform %s", runtime.GOOS)
}
@@ -218,15 +218,15 @@ func logsDir(dirs ...string) (string, error) {
}
return filepath.Join(dir, filepath.Join(dirs...)), nil
case "linux":
- dir := os.Getenv("XDG_DATA_HOME")
- if dir == "" {
- home, err := HomeDir()
- if err != nil {
- return "", err
- }
- dir = filepath.Join(home, ".cache", filepath.Join(dirs...))
+ dir := os.Getenv("XDG_CACHE_HOME")
+ if dir != "" {
+ return filepath.Join(dir, filepath.Join(dirs...)), nil
+ }
+ home, err := HomeDir()
+ if err != nil {
+ return "", err
}
- return dir, nil
+ return filepath.Join(home, ".cache", filepath.Join(dirs...)), nil
default:
return "", errors.Errorf("unsupported platform %s", runtime.GOOS)
}
@@ -242,3 +242,49 @@ func HomeDir() (string, error) {
}
return usr.HomeDir, nil
}
+
+// MustHomeDir returns current user home directory.
+func MustHomeDir() string {
+ usr, err := user.Current()
+ if err != nil {
+ panic(err)
+ }
+ return usr.HomeDir
+}
+
+// All returns all (unique) directories for the environment.
+func All(dir ...string) ([]string, error) {
+ dirs := []string{}
+ appDir, err := AppPath(Dir(dir...))
+ if err != nil {
+ return nil, err
+ }
+ dirs = append(dirs, appDir)
+
+ configDir, err := ConfigPath(Dir(dir...))
+ if err != nil {
+ return nil, err
+ }
+ if !contains(dirs, configDir) {
+ dirs = append(dirs, configDir)
+ }
+
+ logsDir, err := LogsPath(Dir(dir...))
+ if err != nil {
+ return nil, err
+ }
+ if !contains(dirs, logsDir) {
+ dirs = append(dirs, logsDir)
+ }
+
+ return dirs, nil
+}
+
+func contains(arr []string, s string) bool {
+ for _, a := range arr {
+ if s == a {
+ return true
+ }
+ }
+ return false
+}
diff --git a/env/paths_darwin_test.go b/env/paths_darwin_test.go
index d587491..80bf777 100644
--- a/env/paths_darwin_test.go
+++ b/env/paths_darwin_test.go
@@ -3,35 +3,44 @@ package env_test
import (
"os"
"path/filepath"
- "strings"
"testing"
"github.com/keys-pub/keys/env"
"github.com/stretchr/testify/require"
)
-func TestDirs(t *testing.T) {
- appDir, err := env.AppPath(env.Dir("KeysTest"))
+func TestPaths(t *testing.T) {
+ appDir, err := env.AppPath(env.Dir("KeysEnvTest"))
require.NoError(t, err)
- require.True(t, strings.HasSuffix(appDir, "/Library/Application Support/KeysTest"))
- defer os.RemoveAll(appDir)
+ require.Equal(t, filepath.Join(env.MustHomeDir(), "/Library/Application Support/KeysEnvTest"), appDir)
+ exists, err := env.PathExists(appDir)
+ require.NoError(t, err)
+ require.False(t, exists)
- logsDir, err := env.LogsPath(env.Dir("KeysTest"))
+ logsDir, err := env.LogsPath(env.Dir("KeysEnvTest"))
require.NoError(t, err)
- require.True(t, strings.HasSuffix(logsDir, "/Library/Logs/KeysTest"))
- defer os.RemoveAll(logsDir)
- exists, err := env.PathExists(logsDir)
+ require.Equal(t, filepath.Join(env.MustHomeDir(), "/Library/Logs/KeysEnvTest"), logsDir)
+ exists, err = env.PathExists(logsDir)
require.NoError(t, err)
require.False(t, exists)
- configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
+ configPath, err := env.ConfigPath(env.Dir("KeysEnvTest"), env.File("test.txt"), env.Mkdir())
require.NoError(t, err)
- require.True(t, strings.HasSuffix(configPath, "/Library/Application Support/KeysTest/test.txt"))
+ require.Equal(t, configPath, filepath.Join(env.MustHomeDir(), "/Library/Application Support/KeysEnvTest/test.txt"))
configDir, file := filepath.Split(configPath)
- require.True(t, strings.HasSuffix(configDir, "/Library/Application Support/KeysTest/"))
+ require.Equal(t, configDir, filepath.Join(env.MustHomeDir(), "/Library/Application Support/KeysEnvTest")+"/")
require.Equal(t, "test.txt", file)
defer os.RemoveAll(configDir)
exists, err = env.PathExists(configDir)
require.NoError(t, err)
require.True(t, exists)
}
+
+func TestAllDirs(t *testing.T) {
+ dirs, err := env.All("KeysEnvTest")
+ require.NoError(t, err)
+ require.Equal(t, []string{
+ filepath.Join(env.MustHomeDir(), "/Library/Application Support/KeysEnvTest"),
+ filepath.Join(env.MustHomeDir(), "/Library/Logs/KeysEnvTest"),
+ }, dirs)
+}
diff --git a/env/paths_linux_test.go b/env/paths_linux_test.go
index 8103979..80a67bc 100644
--- a/env/paths_linux_test.go
+++ b/env/paths_linux_test.go
@@ -3,32 +3,78 @@ package env_test
import (
"os"
"path/filepath"
- "strings"
"testing"
"github.com/keys-pub/keys/env"
"github.com/stretchr/testify/require"
)
-func TestDirs(t *testing.T) {
- appDir, err := env.AppPath(env.Dir("KeysTest"))
+func TestPaths(t *testing.T) {
+ appDir, err := env.AppPath(env.Dir("KeysEnvTest"))
require.NoError(t, err)
- require.True(t, strings.HasSuffix(appDir, `/.local/share/KeysTest`))
- defer os.RemoveAll(appDir)
+ require.Equal(t, filepath.Join(env.MustHomeDir(), `/.local/share/KeysEnvTest`), appDir)
+ exists, err := env.PathExists(appDir)
+ require.NoError(t, err)
+ require.False(t, exists)
- logsDir, err := env.LogsPath(env.Dir("KeysTest"))
+ logsDir, err := env.LogsPath(env.Dir("KeysEnvTest"))
+ require.NoError(t, err)
+ require.Equal(t, filepath.Join(env.MustHomeDir(), `/.cache/KeysEnvTest`), logsDir)
+ exists, err = env.PathExists(logsDir)
require.NoError(t, err)
- require.True(t, strings.HasSuffix(logsDir, `/.cache/KeysTest`))
- defer os.RemoveAll(logsDir)
+ require.False(t, exists)
- configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
+ configPath, err := env.ConfigPath(env.Dir("KeysEnvTest"), env.File("test.txt"), env.Mkdir())
require.NoError(t, err)
- require.True(t, strings.HasSuffix(configPath, "/.config/KeysTest/test.txt"))
+ require.Equal(t, filepath.Join(env.MustHomeDir(), "/.config/KeysEnvTest/test.txt"), configPath)
configDir, file := filepath.Split(configPath)
- require.True(t, strings.HasSuffix(configDir, "/.config/KeysTest/"))
+ require.Equal(t, filepath.Join(env.MustHomeDir(), "/.config/KeysEnvTest/")+"/", configDir)
require.Equal(t, "test.txt", file)
defer os.RemoveAll(configDir)
exists, err = env.PathExists(configDir)
require.NoError(t, err)
require.True(t, exists)
}
+
+func TestAppPathXDG(t *testing.T) {
+ prev := os.Getenv("XDG_DATA_HOME")
+ defer func() { os.Setenv("XDG_DATA_HOME", prev) }()
+ err := os.Setenv("XDG_DATA_HOME", "/test/data")
+ require.NoError(t, err)
+
+ configPath, err := env.AppPath(env.Dir("KeysEnvTest"))
+ require.NoError(t, err)
+ require.Equal(t, "/test/data/KeysEnvTest", configPath)
+}
+
+func TestConfigPathXDG(t *testing.T) {
+ prev := os.Getenv("XDG_CONFIG_HOME")
+ defer func() { os.Setenv("XDG_CONFIG_HOME", prev) }()
+ err := os.Setenv("XDG_CONFIG_HOME", "/test/config")
+ require.NoError(t, err)
+
+ configPath, err := env.ConfigPath(env.Dir("KeysEnvTest"))
+ require.NoError(t, err)
+ require.Equal(t, "/test/config/KeysEnvTest", configPath)
+}
+
+func TestLogsPathXDG(t *testing.T) {
+ prev := os.Getenv("XDG_CACHE_HOME")
+ defer func() { os.Setenv("XDG_CACHE_HOME", prev) }()
+ err := os.Setenv("XDG_CACHE_HOME", "/test/cache")
+ require.NoError(t, err)
+
+ configPath, err := env.LogsPath(env.Dir("KeysEnvTest"))
+ require.NoError(t, err)
+ require.Equal(t, "/test/cache/KeysEnvTest", configPath)
+}
+
+func TestAllDirs(t *testing.T) {
+ dirs, err := env.All("KeysEnvTest")
+ require.NoError(t, err)
+ require.Equal(t, []string{
+ filepath.Join(env.MustHomeDir(), "/.local/share/KeysEnvTest"),
+ filepath.Join(env.MustHomeDir(), "/.config/KeysEnvTest"),
+ filepath.Join(env.MustHomeDir(), "/.cache/KeysEnvTest"),
+ }, dirs)
+}
diff --git a/env/paths_windows_test.go b/env/paths_windows_test.go
index 5bae1d3..bd8e59e 100644
--- a/env/paths_windows_test.go
+++ b/env/paths_windows_test.go
@@ -10,28 +10,38 @@ import (
"github.com/stretchr/testify/require"
)
-func TestDirs(t *testing.T) {
+func TestPaths(t *testing.T) {
appDir, err := env.AppPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(appDir, `\AppData\Local\KeysTest`))
+ exists, err := env.PathExists(appDir)
+ require.NoError(t, err)
+ require.False(t, exists)
logsDir, err := env.LogsPath(env.Dir("KeysTest"))
require.NoError(t, err)
require.True(t, strings.HasSuffix(logsDir, `\AppData\Local\KeysTest`))
+ exists, err = env.PathExists(logsDir)
+ require.NoError(t, err)
+ require.False(t, exists)
configPath, err := env.ConfigPath(env.Dir("KeysTest"), env.File("test.txt"), env.Mkdir())
require.NoError(t, err)
- require.True(t, strings.HasSuffix(configPath, `\AppData\Roaming\KeysTest\test.txt`))
+ require.Equal(t, filepath.Join(env.MustHomeDir(), `\AppData\Roaming\KeysTest\test.txt`), configPath)
configDir, file := filepath.Split(configPath)
- require.True(t, strings.HasSuffix(configDir, `\AppData\Roaming\KeysTest\`))
+ require.Equal(t, filepath.Join(env.MustHomeDir(), `\AppData\Roaming\KeysTest`)+`\`, configDir)
require.Equal(t, "test.txt", file)
defer os.RemoveAll(configDir)
exists, err = env.PathExists(configDir)
require.NoError(t, err)
require.True(t, exists)
+}
- err = os.Setenv("LOCALAPPDATA", "")
+func TestAllDirs(t *testing.T) {
+ dirs, err := env.All("KeysEnvTest")
require.NoError(t, err)
- _, err = env.AppPath(env.Dir("KeysTest"))
- require.EqualError(t, err, "LOCALAPPDATA not set")
+ require.Equal(t, []string{
+ filepath.Join(env.MustHomeDir(), `\AppData\Local\KeysEnvTest`),
+ filepath.Join(env.MustHomeDir(), `\AppData\Roaming\KeysEnvTest`),
+ }, dirs)
}