@@ -16,7 +16,9 @@ import (
1616const (
1717 GH_CONFIG_DIR = "GH_CONFIG_DIR"
1818 XDG_CONFIG_HOME = "XDG_CONFIG_HOME"
19+ XDG_STATE_HOME = "XDG_STATE_HOME"
1920 APP_DATA = "AppData"
21+ LOCAL_APP_DATA = "LocalAppData"
2022)
2123
2224// Config path precedence
@@ -38,41 +40,110 @@ func ConfigDir() string {
3840 }
3941
4042 // If the path does not exist try migrating config from default paths
41- if _ , err := os . Stat (path ); errors . Is ( err , os . ErrNotExist ) {
42- autoMigrateConfigDir (path )
43+ if ! dirExists (path ) {
44+ _ = autoMigrateConfigDir (path )
4345 }
4446
4547 return path
4648}
4749
50+ // State path precedence
51+ // 1. XDG_CONFIG_HOME
52+ // 2. LocalAppData (windows only)
53+ // 3. HOME
54+ func StateDir () string {
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" )
63+ }
64+
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
71+ }
72+
73+ var errSamePath = errors .New ("same path" )
74+ var errNotExist = errors .New ("not exist" )
75+
4876// Check default paths (os.UserHomeDir, and homedir.Dir) for existing configs
4977// If configs exist then move them to newPath
5078// TODO: Remove support for homedir.Dir location in v2
51- func autoMigrateConfigDir (newPath string ) {
79+ func autoMigrateConfigDir (newPath string ) error {
5280 path , err := os .UserHomeDir ()
5381 if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
54- migrateConfigDir (oldPath , newPath )
55- return
82+ return migrateDir (oldPath , newPath )
5683 }
5784
5885 path , err = homedir .Dir ()
5986 if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
60- migrateConfigDir (oldPath , newPath )
87+ return migrateDir (oldPath , newPath )
6188 }
89+
90+ return errNotExist
6291}
6392
64- func dirExists (path string ) bool {
65- f , err := os .Stat (path )
66- return err == nil && f .IsDir ()
93+ // Check default paths (os.UserHomeDir, and homedir.Dir) for existing state file (state.yml)
94+ // If state file exist then move it to newPath
95+ // TODO: Remove support for homedir.Dir location in v2
96+ func autoMigrateStateDir (newPath string ) error {
97+ path , err := os .UserHomeDir ()
98+ if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
99+ return migrateFile (oldPath , newPath , "state.yml" )
100+ }
101+
102+ path , err = homedir .Dir ()
103+ if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
104+ return migrateFile (oldPath , newPath , "state.yml" )
105+ }
106+
107+ return errNotExist
108+ }
109+
110+ func migrateFile (oldPath , newPath , file string ) error {
111+ if oldPath == newPath {
112+ return errSamePath
113+ }
114+
115+ oldFile := filepath .Join (oldPath , file )
116+ newFile := filepath .Join (newPath , file )
117+
118+ if ! fileExists (oldFile ) {
119+ return errNotExist
120+ }
121+
122+ _ = os .MkdirAll (filepath .Dir (newFile ), 0755 )
123+ return os .Rename (oldFile , newFile )
67124}
68125
69- var migrateConfigDir = func (oldPath , newPath string ) {
126+ func migrateDir (oldPath , newPath string ) error {
70127 if oldPath == newPath {
71- return
128+ return errSamePath
129+ }
130+
131+ if ! dirExists (oldPath ) {
132+ return errNotExist
72133 }
73134
74135 _ = os .MkdirAll (filepath .Dir (newPath ), 0755 )
75- _ = os .Rename (oldPath , newPath )
136+ return os .Rename (oldPath , newPath )
137+ }
138+
139+ func dirExists (path string ) bool {
140+ f , err := os .Stat (path )
141+ return err == nil && f .IsDir ()
142+ }
143+
144+ func fileExists (path string ) bool {
145+ f , err := os .Stat (path )
146+ return err == nil && ! f .IsDir ()
76147}
77148
78149func ConfigFile () string {
0 commit comments