Skip to content

Commit 1d7ffc2

Browse files
committed
Add support for LocalAppData and .local/state/ fallback
1 parent 602167c commit 1d7ffc2

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

internal/config/config_file.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
XDG_CONFIG_HOME = "XDG_CONFIG_HOME"
1919
XDG_STATE_HOME = "XDG_STATE_HOME"
2020
APP_DATA = "AppData"
21+
LOCAL_APP_DATA = "LocalAppData"
2122
)
2223

2324
// Config path precedence
@@ -39,24 +40,34 @@ func ConfigDir() string {
3940
}
4041

4142
// If the path does not exist try migrating config from default paths
42-
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
43+
if !dirExists(path) {
4344
_ = autoMigrateConfigDir(path)
4445
}
4546

4647
return path
4748
}
4849

50+
// State path precedence
51+
// 1. XDG_CONFIG_HOME
52+
// 2. LocalAppData (windows only)
53+
// 3. HOME
4954
func StateDir() string {
50-
if path := os.Getenv(XDG_STATE_HOME); path != "" {
51-
path = filepath.Join(path, "gh")
52-
if !dirExists(path) {
53-
_ = os.MkdirAll(path, 0755)
54-
_ = autoMigrateStateDir(path)
55-
}
56-
return path
55+
var path string
56+
if a := os.Getenv(XDG_STATE_HOME); a != "" {
57+
path = filepath.Join(a, "gh")
58+
} else if b := os.Getenv(LOCAL_APP_DATA); runtime.GOOS == "windows" && b != "" {
59+
path = filepath.Join(b, "GitHub CLI")
60+
} else {
61+
c, _ := os.UserHomeDir()
62+
path = filepath.Join(c, ".local", "state", "gh")
5763
}
5864

59-
return ConfigDir()
65+
// If the path does not exist try migrating state from default paths
66+
if !dirExists(path) {
67+
_ = autoMigrateStateDir(path)
68+
}
69+
70+
return path
6071
}
6172

6273
var errSamePath = errors.New("same path")

internal/config/config_file_test.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -346,21 +346,22 @@ func Test_StateDir(t *testing.T) {
346346
tempDir := t.TempDir()
347347

348348
tests := []struct {
349-
name string
350-
env map[string]string
351-
output string
349+
name string
350+
onlyWindows bool
351+
env map[string]string
352+
output string
352353
}{
353354
{
354355
name: "HOME/USERPROFILE specified",
355356
env: map[string]string{
356357
"XDG_STATE_HOME": "",
357358
"GH_CONFIG_DIR": "",
358359
"XDG_CONFIG_HOME": "",
359-
"AppData": "",
360+
"LocalAppData": "",
360361
"USERPROFILE": tempDir,
361362
"HOME": tempDir,
362363
},
363-
output: filepath.Join(tempDir, ".config", "gh"),
364+
output: filepath.Join(tempDir, ".local", "state", "gh"),
364365
},
365366
{
366367
name: "XDG_STATE_HOME specified",
@@ -370,15 +371,28 @@ func Test_StateDir(t *testing.T) {
370371
output: filepath.Join(tempDir, "gh"),
371372
},
372373
{
373-
name: "GH_CONFIG_DIR specified",
374+
name: "LocalAppData specified",
375+
onlyWindows: true,
374376
env: map[string]string{
375-
"GH_CONFIG_DIR": filepath.Join(tempDir, "gh_config_dir"),
377+
"LocalAppData": tempDir,
376378
},
377-
output: filepath.Join(tempDir, "gh_config_dir"),
379+
output: filepath.Join(tempDir, "GitHub CLI"),
380+
},
381+
{
382+
name: "XDG_STATE_HOME and LocalAppData specified",
383+
onlyWindows: true,
384+
env: map[string]string{
385+
"XDG_STATE_HOME": tempDir,
386+
"LocalAppData": tempDir,
387+
},
388+
output: filepath.Join(tempDir, "gh"),
378389
},
379390
}
380391

381392
for _, tt := range tests {
393+
if tt.onlyWindows && runtime.GOOS != "windows" {
394+
continue
395+
}
382396
t.Run(tt.name, func(t *testing.T) {
383397
if tt.env != nil {
384398
for k, v := range tt.env {
@@ -443,7 +457,7 @@ func Test_autoMigrateStateDir_migration(t *testing.T) {
443457
homeDir := t.TempDir()
444458
migrateDir := t.TempDir()
445459
homeConfigDir := filepath.Join(homeDir, ".config", "gh")
446-
migrateConfigDir := filepath.Join(migrateDir, ".config", "gh")
460+
migrateStateDir := filepath.Join(migrateDir, ".local", "state", "gh")
447461

448462
homeEnvVar := "HOME"
449463
if runtime.GOOS == "windows" {
@@ -458,14 +472,14 @@ func Test_autoMigrateStateDir_migration(t *testing.T) {
458472
err = ioutil.WriteFile(filepath.Join(homeConfigDir, "state.yml"), nil, 0755)
459473
assert.NoError(t, err)
460474

461-
err = autoMigrateStateDir(migrateConfigDir)
475+
err = autoMigrateStateDir(migrateStateDir)
462476
assert.NoError(t, err)
463477

464478
files, err := ioutil.ReadDir(homeConfigDir)
465479
assert.NoError(t, err)
466480
assert.Equal(t, 0, len(files))
467481

468-
files, err = ioutil.ReadDir(migrateConfigDir)
482+
files, err = ioutil.ReadDir(migrateStateDir)
469483
assert.NoError(t, err)
470484
assert.Equal(t, 1, len(files))
471485
assert.Equal(t, "state.yml", files[0].Name())

internal/update/update.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package update
33
import (
44
"fmt"
55
"io/ioutil"
6+
"os"
7+
"path/filepath"
68
"regexp"
79
"strconv"
810
"strings"
@@ -83,9 +85,14 @@ func setStateEntry(stateFilePath string, t time.Time, r ReleaseInfo) error {
8385
if err != nil {
8486
return err
8587
}
86-
_ = ioutil.WriteFile(stateFilePath, content, 0600)
8788

88-
return nil
89+
err = os.MkdirAll(filepath.Dir(stateFilePath), 0755)
90+
if err != nil {
91+
return err
92+
}
93+
94+
err = ioutil.WriteFile(stateFilePath, content, 0600)
95+
return err
8996
}
9097

9198
func versionGreaterThan(v, w string) bool {

0 commit comments

Comments
 (0)