Skip to content

Commit

Permalink
feat: Allow configurable config home directory (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnorbury committed Oct 17, 2023
1 parent 3b53c45 commit 3235143
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 37 deletions.
42 changes: 5 additions & 37 deletions auth/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,20 @@ package auth
import (
"encoding/json"
"fmt"
"github.com/cloudquery/cloudquery-api-go/config"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"

"github.com/adrg/xdg"
)

const (
FirebaseAPIKey = "AIzaSyCxsrwjABEF-dWLzUqmwiL-ct02cnG9GCs"
TokenBaseURL = "https://securetoken.googleapis.com"
EnvVarCloudQueryAPIKey = "CLOUDQUERY_API_KEY"
ExpiryBuffer = 60 * time.Second
tokenFilePath = "cloudquery/token"
)

type tokenResponse struct {
Expand Down Expand Up @@ -131,46 +130,15 @@ func parseToken(response []byte, tr *tokenResponse) error {

// SaveRefreshToken saves the refresh token to the token file
func SaveRefreshToken(refreshToken string) error {
tokenFilePath, err := xdg.DataFile("cloudquery/token")
if err != nil {
return fmt.Errorf("failed to get token file path: %w", err)
}
tokenFile, err := os.OpenFile(tokenFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("failed to open token file %q for writing: %w", tokenFilePath, err)
}
defer func() {
if closeErr := tokenFile.Close(); closeErr != nil {
fmt.Printf("error closing token file: %v", closeErr)
}
}()
if _, err = tokenFile.WriteString(refreshToken); err != nil {
return fmt.Errorf("failed to write token to %q: %w", tokenFilePath, err)
}
return nil
return config.SaveDataString(tokenFilePath, refreshToken)
}

// ReadRefreshToken reads the refresh token from the token file
func ReadRefreshToken() (string, error) {
tokenFilePath, err := xdg.DataFile("cloudquery/token")
if err != nil {
return "", fmt.Errorf("failed to get token file path: %w", err)
}
b, err := os.ReadFile(tokenFilePath)
if err != nil {
return "", fmt.Errorf("failed to read token file: %w", err)
}
return strings.TrimSpace(string(b)), nil
return config.ReadDataString(tokenFilePath)
}

// RemoveRefreshToken removes the token file
func RemoveRefreshToken() error {
tokenFilePath, err := xdg.DataFile("cloudquery/token")
if err != nil {
return fmt.Errorf("failed to get token file path: %w", err)
}
if err := os.RemoveAll(tokenFilePath); err != nil {
return fmt.Errorf("failed to remove token file %q: %w", tokenFilePath, err)
}
return nil
return config.DeleteDataString(tokenFilePath)
}
84 changes: 84 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ var configKeys = []string{
"team",
}

// SetConfigHome sets the configuration home directory - useful for testing
func SetConfigHome(configDir string) error {
return setXDGEnv("XDG_CONFIG_HOME", configDir)
}

// UnsetConfigHome unsets the configuration home directory returning to the default value
func UnsetConfigHome() error {
return unsetXDGEnv("XDG_CONFIG_HOME")
}

// GetValue reads the value of a config key from the config file
func GetValue(key string) (string, error) {
if !slices.Contains(configKeys, key) {
Expand Down Expand Up @@ -88,3 +98,77 @@ func setValue(key string, val *string) error {
}
return nil
}

// SetDataHome sets the data home directory - useful for testing
func SetDataHome(dataHome string) error {
return setXDGEnv("XDG_DATA_HOME", dataHome)
}

// UnsetDataHome unsets the data home directory returning to the default value
func UnsetDataHome() error {
return unsetXDGEnv("XDG_DATA_HOME")
}

// SaveDataString saves a string to a file in the data home directory
func SaveDataString(relPath string, data string) error {
filePath, err := xdg.DataFile(relPath)
if err != nil {
return fmt.Errorf("failed to get file path: %w", err)
}
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("failed to open file %q for writing: %w", filePath, err)
}
defer func() {
if closeErr := file.Close(); closeErr != nil {
fmt.Printf("error closing file: %v", closeErr)
}
}()
if _, err = file.WriteString(data); err != nil {
return fmt.Errorf("failed to write data to %q: %w", filePath, err)
}
return nil
}

// ReadDataString reads a string from a file in the data home directory
func ReadDataString(relPath string) (string, error) {
filePath, err := xdg.DataFile(relPath)
if err != nil {
return "", fmt.Errorf("failed to get file path: %w", err)
}
b, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("failed to read file: %w", err)
}
return strings.TrimSpace(string(b)), nil
}

// DeleteDataString deletes a file in the data home directory
func DeleteDataString(relPath string) error {
filePath, err := xdg.DataFile(relPath)
if err != nil {
return fmt.Errorf("failed to get file path: %w", err)
}
if err := os.RemoveAll(filePath); err != nil {
return fmt.Errorf("failed to remove file %q: %w", filePath, err)
}
return nil
}

func setXDGEnv(key, value string) error {
err := os.Setenv(key, value)
if err != nil {
return fmt.Errorf("failed to set %s: %w", key, err)
}
xdg.Reload()
return nil
}

func unsetXDGEnv(key string) error {
err := os.Unsetenv(key)
if err != nil {
return fmt.Errorf("failed to unset %s: %w", key, err)
}
xdg.Reload()
return nil
}
51 changes: 51 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package config

import (
"github.com/stretchr/testify/require"
"os"
"path"
"testing"

"github.com/adrg/xdg"
Expand Down Expand Up @@ -36,3 +39,51 @@ func TestSetGetValue(t *testing.T) {
t.Fatalf("expected %q, got %q", "", got)
}
}

func TestSetConfigHome(t *testing.T) {
r := require.New(t)
configDir := t.TempDir()

err := SetConfigHome(configDir)
r.NoError(err)

r.Equal(configDir, xdg.ConfigHome)

err = SetValue("team", "set-config-test-value")
r.NoError(err)

// check that the config file was created in the temporary directory,
// not somewhere else
_, err = os.Stat(path.Join(configDir, "cloudquery", "config.json"))
r.NoError(err)

err = UnsetConfigHome()
r.NoError(err)

// check that we are no longer set to the temporary directory
r.NotEqual(configDir, xdg.ConfigHome)
}

func TestSetDataHome(t *testing.T) {
r := require.New(t)
configDir := t.TempDir()

err := SetDataHome(configDir)
r.NoError(err)

r.Equal(configDir, xdg.DataHome)

err = SaveDataString("cloudquery/token", "my-token")
r.NoError(err)

// check that the config file was created in the temporary directory,
// not somewhere else
_, err = os.Stat(path.Join(configDir, "cloudquery", "token"))
r.NoError(err)

err = UnsetDataHome()
r.NoError(err)

// check that we are no longer set to the temporary directory
r.NotEqual(configDir, xdg.DataHome)
}

0 comments on commit 3235143

Please sign in to comment.