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  }