github.com/getgauge/gauge@v1.6.9/plugin/install/check.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package install 8 9 import ( 10 "fmt" 11 "net/http" 12 "regexp" 13 "runtime/debug" 14 "strings" 15 "sync" 16 17 "github.com/getgauge/gauge/logger" 18 "github.com/getgauge/gauge/plugin/pluginInfo" 19 "github.com/getgauge/gauge/version" 20 ) 21 22 const gauge_releases_url = "https://github.com/getgauge/gauge/releases" 23 24 type UpdateFacade struct { 25 wg *sync.WaitGroup 26 print chan bool 27 } 28 29 func (u *UpdateFacade) BufferUpdateDetails() { 30 var wg sync.WaitGroup 31 u.print = make(chan bool) 32 u.wg = &wg 33 u.wg.Add(1) 34 go printUpdateInfo(u.print, u.wg) 35 } 36 37 func (u *UpdateFacade) PrintUpdateBuffer() { 38 u.print <- true 39 u.wg.Wait() 40 } 41 42 func PrintUpdateInfoWithDetails() { 43 updates := checkUpdates() 44 if len(updates) > 0 { 45 for _, update := range updates { 46 logger.Infof(true, "%-10s\t\t%-10s\t%s", update.Name, update.CompatibleVersion, update.Message) 47 } 48 } else { 49 logger.Info(true, "No Updates available.") 50 } 51 } 52 53 func checkUpdates() []UpdateInfo { 54 return append(checkGaugeUpdate(), checkPluginUpdates()...) 55 } 56 57 func recoverPanic() { 58 if r := recover(); r != nil { 59 logger.Fatalf(true, "%v\n%s", r, string(debug.Stack())) 60 } 61 } 62 63 func printUpdateInfo(print chan bool, wg *sync.WaitGroup) { 64 message := make(chan string) 65 go func() { 66 defer recoverPanic() 67 updates := checkUpdates() 68 if len(updates) > 0 { 69 message <- "Updates are available. Run `gauge update -c` for more info." 70 } 71 }() 72 waitToPrint(message, print, "", wg) 73 } 74 75 func waitToPrint(messageChan chan string, printChan chan bool, message string, wg *sync.WaitGroup) { 76 select { 77 case <-printChan: 78 if message != "" { 79 logger.Info(true, message) 80 } 81 wg.Done() 82 case message = <-messageChan: 83 waitToPrint(messageChan, printChan, message, wg) 84 } 85 } 86 87 func checkGaugeUpdate() []UpdateInfo { 88 var updateInfos []UpdateInfo 89 v, err := getLatestGaugeVersion(gauge_releases_url + "/latest") 90 if err != nil { 91 return updateInfos 92 } 93 latestVersion, err := version.ParseVersion(v) 94 if err != nil { 95 return updateInfos 96 } 97 isLatestVersion := version.CurrentGaugeVersion.IsLesserThan(latestVersion) 98 if isLatestVersion { 99 updateInfos = append(updateInfos, UpdateInfo{"Gauge", latestVersion.String(), "Download the installer from https://gauge.org/get-started/"}) 100 } 101 return updateInfos 102 } 103 104 type UpdateInfo struct { 105 Name string 106 CompatibleVersion string 107 Message string 108 } 109 110 func checkPluginUpdates() []UpdateInfo { 111 var pluginsToUpdate []UpdateInfo 112 plugins, err := pluginInfo.GetAllInstalledPluginsWithVersion() 113 if err != nil { 114 return pluginsToUpdate 115 } 116 logger.Debugf(true, "Checking updates...") 117 for _, plugin := range plugins { 118 desc, result := getInstallDescription(plugin.Name, true) 119 if result.Error != nil { 120 continue 121 } 122 pluginsToUpdate = append(pluginsToUpdate, createPluginUpdateDetail(plugin.Version.String(), *desc)...) 123 } 124 return pluginsToUpdate 125 } 126 127 func createPluginUpdateDetail(currentVersion string, latestVersionDetails installDescription) []UpdateInfo { 128 var updateInfo []UpdateInfo 129 v, err := version.ParseVersion(currentVersion) 130 if err != nil { 131 return updateInfo 132 } 133 v1, err := version.ParseVersion(latestVersionDetails.Versions[0].Version) 134 if err != nil { 135 return updateInfo 136 } 137 if v.IsLesserThan(v1) { 138 versionDesc, err := latestVersionDetails.getLatestCompatibleVersionTo(version.CurrentGaugeVersion) 139 if err != nil { 140 return updateInfo 141 } 142 updateInfo = append(updateInfo, UpdateInfo{latestVersionDetails.Name, versionDesc.Version, fmt.Sprintf("Run 'gauge update %s'", latestVersionDetails.Name)}) 143 } 144 return updateInfo 145 } 146 147 var getLatestGaugeVersion = func(url string) (string, error) { 148 res, err := http.Get(url) 149 if err != nil { 150 return "", err 151 } 152 defer res.Body.Close() 153 154 v, err := getGaugeVersionFromURL(res.Request.URL.String()) 155 if err != nil { 156 return "", err 157 } 158 return v, nil 159 } 160 161 func getGaugeVersionFromURL(url string) (string, error) { 162 versionString := strings.Replace(url, gauge_releases_url, "", -1) 163 reg, err := regexp.Compile(`tag/v(\d.*)`) 164 if err != nil { 165 return "", fmt.Errorf("unable to compile regex 'tag/v(\\d.*)': %s", err.Error()) 166 } 167 matches := reg.FindStringSubmatch(versionString) 168 if len(matches) < 2 { 169 return "", fmt.Errorf("failed to parse: %s", url) 170 } 171 return matches[1], nil 172 }