@@ -3,7 +3,6 @@ package config
33import (
44 "encoding/json"
55 "errors"
6- "fmt"
76 "os"
87 "path/filepath"
98 "runtime"
@@ -65,99 +64,116 @@ func Home() (string, error) {
6564 return dir , nil
6665}
6766
68- // Read loads the config from the stored JSON file.
69- func Read (file string ) (* Config , error ) {
67+ func New (path string ) (* Config , error ) {
7068 c := & Config {}
71- err := c .Read ( file )
69+ err := c .load ( path , os . Getenv ( fileEnvKey ) )
7270 return c , err
7371}
7472
7573// Update sets new values where given.
7674func (c * Config ) Update (key , host , dir , xapi string ) {
75+ key = strings .TrimSpace (key )
7776 if key != "" {
7877 c .APIKey = key
7978 }
8079
80+ host = strings .TrimSpace (host )
8181 if host != "" {
8282 c .API = host
8383 }
8484
85+ dir = strings .TrimSpace (dir )
8586 if dir != "" {
8687 c .Dir = dir
8788 }
8889
90+ xapi = strings .TrimSpace (xapi )
8991 if xapi != "" {
9092 c .XAPI = xapi
9193 }
92-
93- c .configure ()
9494}
9595
96- // Expand takes inputs for a config file location and builds an absolute path.
97- func Expand (path , env , home string ) string {
98- if path == "" {
99- path = env
100- }
101-
102- if path != "" && path [0 ] == '~' {
103- path = strings .Replace (path , "~/" , fmt .Sprintf ("%s/" , home ), 1 )
104- }
105-
106- if path == "" {
107- path = filepath .Join (home , File )
96+ // Write saves the config as JSON.
97+ func (c * Config ) Write () error {
98+ // truncates existing file if it exists
99+ f , err := os .Create (c .File )
100+ if err != nil {
101+ return err
108102 }
103+ defer f .Close ()
109104
110- return path
105+ e := json .NewEncoder (f )
106+ return e .Encode (c )
111107}
112108
113- // Read loads the config from the stored JSON file.
114- func (c * Config ) Read (file string ) error {
115- home , err := c .homeDir ()
109+ func (c * Config ) load (argPath , envPath string ) error {
110+ path , err := c .resolvePath (argPath , envPath )
116111 if err != nil {
117112 return err
118113 }
114+ c .File = path
119115
120- c .File = Expand (file , os .Getenv (fileEnvKey ), home )
116+ if err := c .read (); err != nil {
117+ return err
118+ }
121119
120+ // in case people manually update the config file
121+ // with weird formatting
122+ c .APIKey = strings .TrimSpace (c .APIKey )
123+ c .Dir = strings .TrimSpace (c .Dir )
124+ c .API = strings .TrimSpace (c .API )
125+ c .XAPI = strings .TrimSpace (c .XAPI )
126+
127+ return c .setDefaults ()
128+ }
129+
130+ func (c * Config ) read () error {
122131 if _ , err := os .Stat (c .File ); err != nil {
123132 if os .IsNotExist (err ) {
124- c .configure ()
125133 return nil
126134 }
127135 return err
128136 }
129-
130137 f , err := os .Open (c .File )
131138 if err != nil {
132139 return err
133140 }
134141 defer f .Close ()
135142
136143 d := json .NewDecoder (f )
137- err = d .Decode (& c )
138- if err != nil {
139- return err
144+ return d .Decode (& c )
145+ }
146+
147+ // IsAuthenticated returns true if the config contains an API key.
148+ // This does not check whether or not that key is valid.
149+ func (c * Config ) IsAuthenticated () bool {
150+ return c .APIKey != ""
151+ }
152+
153+ // homeDir caches the lookup of the user's home directory.
154+ func (c * Config ) homeDir () (string , error ) {
155+ if c .home != "" {
156+ return c .home , nil
140157 }
141- c .configure ()
142- return nil
158+ return Home ()
143159}
144160
145- // Write() saves the config as JSON.
146- func (c * Config ) Write () error {
147- // truncates existing file if it exists
148- f , err := os .Create (c .File )
161+ func (c * Config ) resolvePath (argPath , envPath string ) (string , error ) {
162+ path := argPath
163+ if path == "" {
164+ path = envPath
165+ }
166+ if path == "" {
167+ path = filepath .Join ("~" , File )
168+ }
169+ h , err := c .homeDir ()
149170 if err != nil {
150- return err
171+ return "" , err
151172 }
152- defer f .Close ()
153-
154- e := json .NewEncoder (f )
155- return e .Encode (c )
173+ return strings .Replace (path , "~" , h , 1 ), nil
156174}
157175
158- func (c * Config ) configure () (* Config , error ) {
159- c .sanitize ()
160-
176+ func (c * Config ) setDefaults () error {
161177 if c .API == "" {
162178 c .API = hostAPI
163179 }
@@ -166,44 +182,15 @@ func (c *Config) configure() (*Config, error) {
166182 c .XAPI = hostXAPI
167183 }
168184
169- homeDir , err := c .homeDir ()
185+ h , err := c .homeDir ()
170186 if err != nil {
171- return c , err
187+ return err
172188 }
173189
174190 if c .Dir == "" {
175- // fall back to default value
176- c .Dir = filepath .Join (homeDir , DirExercises )
177- } else {
178- // replace '~' with user's home
179- c .Dir = strings .Replace (c .Dir , "~/" , fmt .Sprintf ("%s/" , homeDir ), 1 )
180- }
181-
182- if c .File == "" {
183- c .File = filepath .Join (homeDir , File )
184- }
185-
186- return c , nil
187- }
188-
189- // IsAuthenticated returns true if the config contains an API key.
190- // This does not check whether or not that key is valid.
191- func (c * Config ) IsAuthenticated () bool {
192- return c .APIKey != ""
193- }
194-
195- // See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
196- // we can't cross compile using cgo and use user.Current()
197- func (c * Config ) homeDir () (string , error ) {
198- if c .home != "" {
199- return c .home , nil
191+ c .Dir = filepath .Join (h , DirExercises )
200192 }
201- return Home ()
202- }
193+ c .Dir = strings .Replace (c .Dir , "~" , h , 1 )
203194
204- func (c * Config ) sanitize () {
205- c .APIKey = strings .TrimSpace (c .APIKey )
206- c .Dir = strings .TrimSpace (c .Dir )
207- c .API = strings .TrimSpace (c .API )
208- c .XAPI = strings .TrimSpace (c .XAPI )
195+ return nil
209196}
0 commit comments