Skip to content
This repository was archived by the owner on Mar 12, 2026. It is now read-only.

Commit bd7dc9e

Browse files
briglebclaude
andcommitted
refactor: use XDG config directory with legacy fallback
Change config location priority: 1. ~/.config/bc4/ (XDG standard) - used for new installations 2. ~/Library/Application Support/bc4/ (macOS legacy) - fallback for existing users This provides cross-platform consistency while maintaining backwards compatibility with existing macOS installations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3b23d5c commit bd7dc9e

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

internal/auth/auth.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@ import (
1313
"path/filepath"
1414
"time"
1515

16+
"github.com/needmore/bc4/internal/config"
1617
"github.com/needmore/bc4/internal/utils"
1718
"github.com/pkg/browser"
1819
"golang.org/x/oauth2"
1920

2021
"github.com/needmore/bc4/internal/version"
2122
)
2223

24+
// GetAuthPath returns the path to the auth file (delegates to config package)
25+
func GetAuthPath() string {
26+
return config.GetAuthPath()
27+
}
28+
2329
const (
2430
authURL = "https://launchpad.37signals.com/authorization/new"
2531
tokenURL = "https://launchpad.37signals.com/authorization/token"
@@ -75,7 +81,7 @@ type Client struct {
7581

7682
// NewClient creates a new auth client
7783
func NewClient(clientID, clientSecret string) *Client {
78-
config := &oauth2.Config{
84+
oauthConfig := &oauth2.Config{
7985
ClientID: clientID,
8086
ClientSecret: clientSecret,
8187
Endpoint: oauth2.Endpoint{
@@ -86,13 +92,12 @@ func NewClient(clientID, clientSecret string) *Client {
8692
Scopes: []string{},
8793
}
8894

89-
configDir, _ := os.UserConfigDir()
90-
storePath := filepath.Join(configDir, "bc4", "auth.json")
95+
storePath := config.GetAuthPath()
9196

9297
client := &Client{
9398
clientID: clientID,
9499
clientSecret: clientSecret,
95-
config: config,
100+
config: oauthConfig,
96101
storePath: storePath,
97102
}
98103

internal/config/config.go

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"os"
77
"path/filepath"
8+
"runtime"
89

910
"github.com/needmore/bc4/internal/utils"
1011
"github.com/spf13/viper"
@@ -41,13 +42,62 @@ type PreferencesConfig struct {
4142
Color string `json:"color,omitempty"`
4243
}
4344

45+
var configDir string
4446
var configPath string
4547
var authPath string
4648

49+
// getXDGConfigDir returns the XDG config directory (~/.config/bc4)
50+
func getXDGConfigDir() string {
51+
home, err := os.UserHomeDir()
52+
if err != nil {
53+
return ""
54+
}
55+
return filepath.Join(home, ".config", "bc4")
56+
}
57+
58+
// getLegacyConfigDir returns the legacy macOS config directory (~/Library/Application Support/bc4)
59+
func getLegacyConfigDir() string {
60+
if runtime.GOOS != "darwin" {
61+
return ""
62+
}
63+
home, err := os.UserHomeDir()
64+
if err != nil {
65+
return ""
66+
}
67+
return filepath.Join(home, "Library", "Application Support", "bc4")
68+
}
69+
70+
// resolveConfigDir determines which config directory to use.
71+
// Priority: XDG (~/.config/bc4) first, fall back to legacy macOS location if XDG doesn't exist.
72+
func resolveConfigDir() string {
73+
xdgDir := getXDGConfigDir()
74+
legacyDir := getLegacyConfigDir()
75+
76+
// Check if XDG directory exists
77+
if _, err := os.Stat(xdgDir); err == nil {
78+
return xdgDir
79+
}
80+
81+
// Check if legacy directory exists (macOS only)
82+
if legacyDir != "" {
83+
if _, err := os.Stat(legacyDir); err == nil {
84+
return legacyDir
85+
}
86+
}
87+
88+
// Neither exists, use XDG for new installations
89+
return xdgDir
90+
}
91+
4792
func init() {
48-
configDir, _ := os.UserConfigDir()
49-
configPath = filepath.Join(configDir, "bc4", "config.json")
50-
authPath = filepath.Join(configDir, "bc4", "auth.json")
93+
configDir = resolveConfigDir()
94+
configPath = filepath.Join(configDir, "config.json")
95+
authPath = filepath.Join(configDir, "auth.json")
96+
}
97+
98+
// GetConfigDir returns the resolved config directory
99+
func GetConfigDir() string {
100+
return configDir
51101
}
52102

53103
// Load loads the configuration from file
@@ -140,6 +190,11 @@ func GetConfigPath() string {
140190
return configPath
141191
}
142192

193+
// GetAuthPath returns the path to the auth file
194+
func GetAuthPath() string {
195+
return authPath
196+
}
197+
143198
// IsFirstRun checks if this is the first run (no auth or config)
144199
func IsFirstRun() bool {
145200
// Check for config file

0 commit comments

Comments
 (0)