@@ -16,7 +16,10 @@ import (
1616const (
1717 GH_CONFIG_DIR = "GH_CONFIG_DIR"
1818 XDG_CONFIG_HOME = "XDG_CONFIG_HOME"
19+ XDG_STATE_HOME = "XDG_STATE_HOME"
20+ XDG_DATA_HOME = "XDG_DATA_HOME"
1921 APP_DATA = "AppData"
22+ LOCAL_APP_DATA = "LocalAppData"
2023)
2124
2225// Config path precedence
@@ -38,41 +41,128 @@ func ConfigDir() string {
3841 }
3942
4043 // 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 )
44+ if ! dirExists (path ) {
45+ _ = autoMigrateConfigDir (path )
4346 }
4447
4548 return path
4649}
4750
51+ // State path precedence
52+ // 1. XDG_CONFIG_HOME
53+ // 2. LocalAppData (windows only)
54+ // 3. HOME
55+ func StateDir () string {
56+ var path string
57+ if a := os .Getenv (XDG_STATE_HOME ); a != "" {
58+ path = filepath .Join (a , "gh" )
59+ } else if b := os .Getenv (LOCAL_APP_DATA ); runtime .GOOS == "windows" && b != "" {
60+ path = filepath .Join (b , "GitHub CLI" )
61+ } else {
62+ c , _ := os .UserHomeDir ()
63+ path = filepath .Join (c , ".local" , "state" , "gh" )
64+ }
65+
66+ // If the path does not exist try migrating state from default paths
67+ if ! dirExists (path ) {
68+ _ = autoMigrateStateDir (path )
69+ }
70+
71+ return path
72+ }
73+
74+ // Data path precedence
75+ // 1. XDG_DATA_HOME
76+ // 2. LocalAppData (windows only)
77+ // 3. HOME
78+ func DataDir () string {
79+ var path string
80+ if a := os .Getenv (XDG_DATA_HOME ); a != "" {
81+ path = filepath .Join (a , "gh" )
82+ } else if b := os .Getenv (LOCAL_APP_DATA ); runtime .GOOS == "windows" && b != "" {
83+ path = filepath .Join (b , "GitHub CLI" )
84+ } else {
85+ c , _ := os .UserHomeDir ()
86+ path = filepath .Join (c , ".local" , "share" , "gh" )
87+ }
88+
89+ return path
90+ }
91+
92+ var errSamePath = errors .New ("same path" )
93+ var errNotExist = errors .New ("not exist" )
94+
4895// Check default paths (os.UserHomeDir, and homedir.Dir) for existing configs
4996// If configs exist then move them to newPath
5097// TODO: Remove support for homedir.Dir location in v2
51- func autoMigrateConfigDir (newPath string ) {
98+ func autoMigrateConfigDir (newPath string ) error {
5299 path , err := os .UserHomeDir ()
53100 if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
54- migrateConfigDir (oldPath , newPath )
55- return
101+ return migrateDir (oldPath , newPath )
56102 }
57103
58104 path , err = homedir .Dir ()
59105 if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
60- migrateConfigDir (oldPath , newPath )
106+ return migrateDir (oldPath , newPath )
61107 }
108+
109+ return errNotExist
62110}
63111
64- func dirExists (path string ) bool {
65- f , err := os .Stat (path )
66- return err == nil && f .IsDir ()
112+ // Check default paths (os.UserHomeDir, and homedir.Dir) for existing state file (state.yml)
113+ // If state file exist then move it to newPath
114+ // TODO: Remove support for homedir.Dir location in v2
115+ func autoMigrateStateDir (newPath string ) error {
116+ path , err := os .UserHomeDir ()
117+ if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
118+ return migrateFile (oldPath , newPath , "state.yml" )
119+ }
120+
121+ path , err = homedir .Dir ()
122+ if oldPath := filepath .Join (path , ".config" , "gh" ); err == nil && dirExists (oldPath ) {
123+ return migrateFile (oldPath , newPath , "state.yml" )
124+ }
125+
126+ return errNotExist
127+ }
128+
129+ func migrateFile (oldPath , newPath , file string ) error {
130+ if oldPath == newPath {
131+ return errSamePath
132+ }
133+
134+ oldFile := filepath .Join (oldPath , file )
135+ newFile := filepath .Join (newPath , file )
136+
137+ if ! fileExists (oldFile ) {
138+ return errNotExist
139+ }
140+
141+ _ = os .MkdirAll (filepath .Dir (newFile ), 0755 )
142+ return os .Rename (oldFile , newFile )
67143}
68144
69- var migrateConfigDir = func (oldPath , newPath string ) {
145+ func migrateDir (oldPath , newPath string ) error {
70146 if oldPath == newPath {
71- return
147+ return errSamePath
148+ }
149+
150+ if ! dirExists (oldPath ) {
151+ return errNotExist
72152 }
73153
74154 _ = os .MkdirAll (filepath .Dir (newPath ), 0755 )
75- _ = os .Rename (oldPath , newPath )
155+ return os .Rename (oldPath , newPath )
156+ }
157+
158+ func dirExists (path string ) bool {
159+ f , err := os .Stat (path )
160+ return err == nil && f .IsDir ()
161+ }
162+
163+ func fileExists (path string ) bool {
164+ f , err := os .Stat (path )
165+ return err == nil && ! f .IsDir ()
76166}
77167
78168func ConfigFile () string {
0 commit comments