github.com/henvic/wedeploycli@v1.7.6-0.20200319005353-3630f582f284/config/config.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "os" 6 "regexp" 7 "runtime" 8 "strings" 9 "sync" 10 11 "github.com/hashicorp/errwrap" 12 version "github.com/hashicorp/go-version" 13 "github.com/henvic/wedeploycli/color" 14 "github.com/henvic/wedeploycli/defaults" 15 "github.com/henvic/wedeploycli/remotes" 16 "github.com/henvic/wedeploycli/verbose" 17 "gopkg.in/ini.v1" 18 ) 19 20 // Config of the application 21 type Config struct { 22 Path string 23 24 Params Params 25 26 m sync.Mutex 27 file *ini.File 28 } 29 30 // GetParams gets the configuration parameters in a concurrent safe way. 31 func (c *Config) GetParams() Params { 32 c.m.Lock() 33 defer c.m.Unlock() 34 return c.Params 35 } 36 37 // SetParams updates the set of params. 38 func (c *Config) SetParams(p Params) { 39 c.m.Lock() 40 defer c.m.Unlock() 41 c.Params = p 42 } 43 44 // Params for the configuration 45 type Params struct { 46 DefaultRemote string `ini:"default_remote"` 47 NoAutocomplete bool `ini:"disable_autocomplete_autoinstall"` 48 NoColor bool `ini:"disable_colors"` 49 NotifyUpdates bool `ini:"notify_updates"` 50 ReleaseChannel string `ini:"release_channel"` 51 LastUpdateCheck string `ini:"last_update_check"` 52 PastVersion string `ini:"past_version"` 53 NextVersion string `ini:"next_version"` 54 EnableAnalytics bool `ini:"enable_analytics"` 55 AnalyticsID string `ini:"analytics_id"` 56 EnableCURL bool `ini:"enable_curl"` 57 Remotes *remotes.List `ini:"-"` 58 } 59 60 var parseRemoteSectionNameRegex = regexp.MustCompile(`remote \"(.*)\"`) 61 62 // Load the configuration 63 func (c *Config) Load() error { 64 if err := c.openOrCreate(); err != nil { 65 return err 66 } 67 68 c.load() 69 70 var params = c.GetParams() 71 72 if params.Remotes == nil { 73 params.Remotes = &remotes.List{} 74 } 75 76 c.SetParams(params) 77 78 c.loadDefaultRemotes() 79 return c.validateDefaultRemote() 80 } 81 82 func (c *Config) openOrCreate() error { 83 if c.configExists() { 84 return c.read() 85 } 86 87 verbose.Debug("Config file not found.") 88 c.file = ini.Empty() 89 c.banner() 90 return nil 91 } 92 93 func (c *Config) loadDefaultRemotes() { 94 var params = c.GetParams() 95 var rl = params.Remotes 96 97 switch rl.Get(defaults.CloudRemote).Infrastructure { 98 case defaults.Infrastructure: 99 case "": 100 rl.Set(defaults.CloudRemote, remotes.Entry{ 101 Infrastructure: defaults.Infrastructure, 102 InfrastructureComment: "Default cloud remote", 103 }) 104 default: 105 _, _ = fmt.Fprintln(os.Stderr, color.Format( 106 color.FgHiRed, 107 "Warning: Non-standard wedeploy remote cloud detected")) 108 } 109 } 110 111 func (c *Config) validateDefaultRemote() error { 112 var params = c.Params 113 var rl = params.Remotes 114 var keys = rl.Keys() 115 116 for _, k := range keys { 117 if params.DefaultRemote == k { 118 return nil 119 } 120 } 121 122 return fmt.Errorf(`Remote "%v" is set as default, but not found. 123 Please fix your ~/.lcp file`, c.Params.DefaultRemote) 124 } 125 126 // Save the configuration 127 func (c *Config) Save() error { 128 var cfg = c.file 129 var params = c.GetParams() 130 var err = cfg.ReflectFrom(¶ms) 131 132 if err != nil { 133 return errwrap.Wrapf("can't load configuration: {{err}}", err) 134 } 135 136 c.updateRemotes() 137 c.simplify() 138 139 err = cfg.SaveToIndent(c.Path, " ") 140 141 if err != nil { 142 return errwrap.Wrapf("can't save configuration: {{err}}", err) 143 } 144 145 return nil 146 } 147 148 func (c *Config) setDefaults() { 149 var params = c.GetParams() 150 151 params.EnableAnalytics = true 152 params.NotifyUpdates = true 153 params.ReleaseChannel = defaults.StableReleaseChannel 154 params.DefaultRemote = defaults.CloudRemote 155 156 // By design Windows users should see no color unless they enable it 157 // Issue #51. 158 // https://github.com/wedeploy/cli/issues/51 159 if runtime.GOOS == "windows" { 160 params.NoColor = true 161 } 162 163 c.SetParams(params) 164 } 165 166 func (c *Config) configExists() bool { 167 var _, err = os.Stat(c.Path) 168 169 switch { 170 case err == nil: 171 return true 172 case os.IsNotExist(err): 173 return false 174 default: 175 panic(err) 176 } 177 } 178 179 func (c *Config) load() { 180 c.setDefaults() 181 182 var params = c.GetParams() 183 184 if err := c.file.MapTo(¶ms); err != nil { 185 panic(err) 186 } 187 188 c.SetParams(params) 189 } 190 191 func (c *Config) read() error { 192 var err error 193 c.file, err = ini.Load(c.Path) 194 195 if err != nil { 196 return errwrap.Wrapf("error reading configuration file: {{err}}\n"+ 197 "Fix "+c.Path+" by hand or erase it.", err) 198 } 199 200 c.readRemotes() 201 c.checkNextVersionCacheIsNewer() 202 203 return nil 204 } 205 206 func (c *Config) checkNextVersionCacheIsNewer() { 207 if defaults.Version == "master" { 208 return 209 } 210 211 vThis, err := version.NewVersion(defaults.Version) 212 213 if err != nil { 214 verbose.Debug(err) 215 return 216 } 217 218 var params = c.GetParams() 219 220 vNext, err := version.NewVersion(params.NextVersion) 221 222 if err != nil { 223 verbose.Debug(err) 224 return 225 } 226 227 if vThis.GreaterThan(vNext) { 228 params.NextVersion = "" 229 c.SetParams(params) 230 } 231 } 232 233 func parseRemoteSectionName(parsable string) (parsed string, is bool) { 234 var matches = parseRemoteSectionNameRegex.FindStringSubmatch(parsable) 235 236 if len(matches) == 2 { 237 parsed = matches[1] 238 is = true 239 } 240 241 return parsed, is 242 } 243 244 func (c *Config) listRemotes() []string { 245 var list = []string{} 246 247 for _, k := range c.file.SectionStrings() { 248 var key, is = parseRemoteSectionName(k) 249 250 if !is { 251 continue 252 } 253 254 list = append(list, key) 255 } 256 257 return list 258 } 259 260 func (c *Config) getRemote(key string) *ini.Section { 261 return c.file.Section(`remote "` + key + `"`) 262 } 263 264 func (c *Config) deleteRemote(key string) { 265 c.file.DeleteSection(`remote "` + key + `"`) 266 } 267 268 func (c *Config) readRemotes() { 269 var rl = &remotes.List{} 270 271 for _, k := range c.listRemotes() { 272 remote := c.getRemote(k) 273 infrastructure := remote.Key("infrastructure") 274 service := remote.Key("service") 275 username := remote.Key("username") 276 token := remote.Key("token") 277 comment := remote.Comment 278 279 rl.Set(k, remotes.Entry{ 280 Comment: strings.TrimSpace(comment), 281 Infrastructure: strings.TrimSpace(infrastructure.String()), 282 InfrastructureComment: strings.TrimSpace(infrastructure.Comment), 283 Service: strings.TrimSpace(service.String()), 284 ServiceComment: strings.TrimSpace(service.Comment), 285 Username: strings.TrimSpace(username.String()), 286 UsernameComment: strings.TrimSpace(username.Comment), 287 Token: strings.TrimSpace(token.String()), 288 TokenComment: strings.TrimSpace(token.Comment), 289 }) 290 } 291 292 var params = c.GetParams() 293 params.Remotes = rl 294 c.SetParams(params) 295 } 296 297 func (c *Config) simplify() { 298 var mainSection = c.file.Section("") 299 var omitempty = []string{"past_version", "next_version", "last_update_check"} 300 301 for _, k := range omitempty { 302 var key = mainSection.Key(k) 303 if key.Value() == "" && key.Comment == "" { 304 mainSection.DeleteKey(k) 305 } 306 } 307 } 308 309 func (c *Config) simplifyRemotes() { 310 for _, k := range c.listRemotes() { 311 remote := c.getRemote(k) 312 infrastructure := remote.Key("infrastructure") 313 service := remote.Key("service") 314 315 if infrastructure.Value() == "" && infrastructure.Comment == "" { 316 remote.DeleteKey("infrastructure") 317 } 318 319 if service.Value() == "" && service.Comment == "" { 320 remote.DeleteKey("service") 321 } 322 323 if len(remote.Keys()) == 0 && remote.Comment == "" { 324 c.deleteRemote(k) 325 } 326 327 var omitempty = []string{"username", "token"} 328 329 for _, k := range omitempty { 330 var key = remote.Key(k) 331 if key.Value() == "" && key.Comment == "" { 332 remote.DeleteKey(k) 333 } 334 } 335 } 336 } 337 338 func (c *Config) updateRemotes() { 339 var params = c.GetParams() 340 var rl = params.Remotes 341 342 for _, k := range c.listRemotes() { 343 if !rl.Has(k) { 344 c.deleteRemote(k) 345 } 346 } 347 348 for _, k := range rl.Keys() { 349 var v = rl.Get(k) 350 remote := c.getRemote(k) 351 352 keyInfrastructure := remote.Key("infrastructure") 353 keyInfrastructure.SetValue(v.Infrastructure) 354 keyInfrastructure.Comment = v.InfrastructureComment 355 356 keyService := remote.Key("service") 357 keyService.SetValue(v.Service) 358 keyService.Comment = v.ServiceComment 359 360 keyUsername := remote.Key("username") 361 keyUsername.SetValue(v.Username) 362 keyUsername.Comment = v.UsernameComment 363 364 keyToken := remote.Key("token") 365 keyToken.SetValue(v.Token) 366 keyToken.Comment = v.TokenComment 367 368 remote.Comment = v.Comment 369 } 370 371 c.simplifyRemotes() 372 } 373 374 func (c *Config) banner() { 375 c.file.Section("DEFAULT").Comment = `; Configuration file for Liferay Cloud 376 ; https://www.liferay.com/products/dxp-cloud` 377 }