Skip to content

Commit

Permalink
use default user config/cache directories
Browse files Browse the repository at this point in the history
  • Loading branch information
z0rr0 committed Jul 30, 2023
1 parent 9eefb50 commit 536120c
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 13 deletions.
40 changes: 37 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"os"
"path/filepath"
"sync"
"time"

Expand All @@ -29,18 +30,21 @@ type Config struct {
}

// New reads configuration file.
func New(fileName string, noCache, debug bool, logger *log.Logger) (*Config, error) {
func New(fileName, configDir, cacheDir string, noCache, debug bool, logger *log.Logger) (*Config, error) {
data, err := os.ReadFile(fileName)
if err != nil {
return nil, fmt.Errorf("read config file: %w", err)
}

cfg := &Config{}
err = json.Unmarshal(data, &cfg)
if err != nil {
if err = json.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
}

if err = cfg.setFiles(configDir, cacheDir); err != nil {
return nil, err
}

cfg.setLogger(logger, debug)
if err = cfg.setProxy(); err != nil {
return nil, err
Expand All @@ -66,6 +70,36 @@ func (c *Config) setLogger(logger *log.Logger, debug bool) {
c.Logger = logger
}

// setFiles sets paths for key file and auth cache.
func (c *Config) setFiles(configDir, cacheDir string) error {
if !filepath.IsAbs(c.Translation.KeyFile) {
c.Translation.KeyFile = filepath.Join(configDir, c.Translation.KeyFile)
}

if cacheDir == "" || c.AuthCache == "" || filepath.IsAbs(c.AuthCache) {
// no cache or it has absolute path
return nil
}

info, err := os.Stat(cacheDir)
if err != nil {
if !os.IsNotExist(err) {
return fmt.Errorf("failed read cache directory: %w", err)
}
if err = os.Mkdir(cacheDir, 0700); err != nil {
return fmt.Errorf("create cache directory %q: %w", cacheDir, err)
}
} else {
if !info.IsDir() {
return fmt.Errorf("cache is not a directory: %q", cacheDir)
}
}

// cacheDir is a directory and it exists
c.AuthCache = filepath.Join(cacheDir, c.AuthCache)
return nil
}

// setProxy sets HTTP proxy or uses environment variables.
func (c *Config) setProxy() error {
if c.ProxyURL != "" {
Expand Down
124 changes: 122 additions & 2 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"net/http/httptest"
"os"
"path"
"strings"
"testing"

"github.com/z0rr0/ytapigo/cloud"
Expand Down Expand Up @@ -72,7 +73,7 @@ func TestNew(t *testing.T) {
}
defer deleteFile(configFile, t)

cfg, err := New(configFile, true, true, logger)
cfg, err := New(configFile, "", "", true, true, logger)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -117,7 +118,7 @@ func TestNew(t *testing.T) {
func TestNew_NoFile(t *testing.T) {
configFile := path.Join(os.TempDir(), "ytapigo_config_not_exists.toml")

_, err := New(configFile, true, true, logger)
_, err := New(configFile, "", "", true, true, logger)
if err == nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -204,3 +205,122 @@ func TestConfig_InitCachedToken(t *testing.T) {
t.Errorf("unexpected IAM token: %s", cfg.Translation.IAMToken)
}
}

func TestConfig_setFiles(t *testing.T) {
const testDir = "ytapigo_test_set_files"
var (
tmpDir = os.TempDir()
testConfigDir = path.Join(tmpDir, testDir, "config")
testCacheDir = path.Join(tmpDir, testDir, "cache")
)
tmpFile, err := os.CreateTemp(testCacheDir, "ytapigo_caceh_*.json")
if err != nil {
t.Fatal(err)
}

cleanFunc := func() {
if e := os.RemoveAll(testDir); e != nil {
t.Fatal(e)
}
}

if err = os.MkdirAll(testConfigDir, 0750); err != nil {
t.Fatal(err)
}
if err = os.MkdirAll(testCacheDir, 0750); err != nil {
t.Fatal(err)
}

// clean before and after tests
cleanFunc()
defer cleanFunc()

testCases := []struct {
name string
configDir string
cacheDir string
keyFile string
cacheFile string
expected [2]string // config and cache files paths
err string
}{
{
name: "empty",
keyFile: "key.json",
cacheFile: "cache.json",
expected: [2]string{"key.json", "cache.json"},
},
{
name: "abs_paths",
configDir: testConfigDir,
cacheDir: testCacheDir,
keyFile: path.Join(tmpDir, "abs_path_ytapigo", "key.json"),
cacheFile: path.Join(tmpDir, "abs_path_ytapigo", "cache.json"),
expected: [2]string{
path.Join(tmpDir, "abs_path_ytapigo", "key.json"),
path.Join(tmpDir, "abs_path_ytapigo", "cache.json"),
},
},
{
name: "empty_cache",
configDir: testConfigDir,
cacheDir: testCacheDir,
keyFile: path.Join(tmpDir, "abs_path_ytapigo", "key.json"),
cacheFile: "",
expected: [2]string{path.Join(tmpDir, "abs_path_ytapigo", "key.json"), ""},
},
{
name: "set_all",
configDir: testConfigDir,
cacheDir: testCacheDir,
keyFile: "key.json",
cacheFile: "cache.json",
expected: [2]string{
path.Join(testConfigDir, "key.json"),
path.Join(testCacheDir, "cache.json"),
},
},
{
name: "cache_is_not_dir",
configDir: testConfigDir,
cacheDir: tmpFile.Name(),
keyFile: "key.json",
cacheFile: "cache.json",
err: "cache is not a directory: ",
},
}
for i := range testCases {
tc := testCases[i]
t.Run(tc.name, func(t *testing.T) {
cfg := &Config{
Translation: cloud.Account{KeyFile: tc.keyFile},
AuthCache: tc.cacheFile,
}

tcErr := cfg.setFiles(tc.configDir, tc.cacheDir)
if tcErr != nil {
if tc.err == "" {
t.Errorf("unexpected error: %v", tcErr)
} else if e := tcErr.Error(); !strings.HasPrefix(e, tc.err) {
t.Errorf("not match error: %q, but expected %q", e, tc.err)
}
return
}

// no error from tested function
if tc.err != "" {
t.Errorf("expected error: %q", tc.err)
return
}

// no error and no expected error
if tc.expected[0] != cfg.Translation.KeyFile {
t.Errorf("unexpected key file: %q", cfg.Translation.KeyFile)
}

if tc.expected[1] != cfg.AuthCache {
t.Errorf("unexpected cache file: %q", cfg.AuthCache)
}
})
}
}
47 changes: 39 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/z0rr0/ytapigo/config"
Expand All @@ -33,13 +34,12 @@ var (

func main() {
var (
debug bool
version bool
noCache bool
direction string
timeout = 5 * time.Second
configFile = filepath.Join(os.Getenv("HOME"), ".ytapigo3", "config.json")
start = time.Now()
debug bool
version bool
noCache bool
direction string
timeout = 5 * time.Second
start = time.Now()
)

defer func() {
Expand All @@ -53,6 +53,12 @@ func main() {
}
}()

configDir, cacheDir, err := defaultDirectories()
if err != nil {
panic(err)
}
configFile := filepath.Join(configDir, "config.json")

flag.BoolVar(&debug, "d", false, "debug mode")
flag.BoolVar(&version, "v", false, "print version")
flag.StringVar(&configFile, "c", configFile, "configuration file")
Expand All @@ -72,11 +78,15 @@ func main() {
return
}

cfg, err := config.New(configFile, noCache, debug, logger)
cfg, err := config.New(configFile, configDir, cacheDir, noCache, debug, logger)
if err != nil {
panic(err)
}

cfg.Logger.Printf("configuration"+
"\n\tCONFIG:\t%v\n\tKEY:\t%v\n\tCACHE:\t%v", configFile, cfg.Translation.KeyFile, cfg.AuthCache,
)

ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

Expand All @@ -85,3 +95,24 @@ func main() {
panic(err)
}
}

// defaultDirectories returns default configuration and cache directories.
func defaultDirectories() (string, string, error) {
var (
configDir string
cacheDir string
err error
appFolder = strings.ToLower(Name)
)

if configDir, err = os.UserConfigDir(); err != nil {
return "", "", err
}
configDir = filepath.Join(configDir, appFolder)

if cacheDir, err = os.UserCacheDir(); err != nil {
return "", "", err
}

return configDir, filepath.Join(cacheDir, appFolder), nil
}

0 comments on commit 536120c

Please sign in to comment.