github.com/mattdotmatt/gauge@v0.3.2-0.20160421115137-425a4cdccb62/plugin/install/check.go (about)

     1  // Copyright 2015 ThoughtWorks, Inc.
     2  
     3  // This file is part of Gauge.
     4  
     5  // Gauge is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  
    10  // Gauge is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  
    15  // You should have received a copy of the GNU General Public License
    16  // along with Gauge.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package install
    19  
    20  import (
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"strings"
    25  	"sync"
    26  
    27  	"github.com/dmotylev/goproperties"
    28  	"github.com/getgauge/gauge/config"
    29  	"github.com/getgauge/gauge/logger"
    30  	"github.com/getgauge/gauge/plugin"
    31  	"github.com/getgauge/gauge/version"
    32  )
    33  
    34  type UpdateFacade struct {
    35  	wg    *sync.WaitGroup
    36  	print chan bool
    37  }
    38  
    39  func (u *UpdateFacade) BufferUpdateDetails() {
    40  	var wg sync.WaitGroup
    41  	u.print = make(chan bool)
    42  	u.wg = &wg
    43  	u.wg.Add(1)
    44  	go printUpdateInfo(u.print, u.wg)
    45  }
    46  
    47  func (u *UpdateFacade) PrintUpdateBuffer() {
    48  	u.print <- true
    49  	u.wg.Wait()
    50  }
    51  
    52  func PrintUpdateInfoWithDetails() {
    53  	updates := checkUpdates()
    54  	if len(updates) > 0 {
    55  		for _, update := range updates {
    56  			logger.Info(fmt.Sprintf("%-10s\t\t%-10s\t%s", update.Name, update.CompatibleVersion, update.Message))
    57  		}
    58  	} else {
    59  		logger.Info("No Updates available.")
    60  	}
    61  }
    62  
    63  func checkUpdates() []UpdateInfo {
    64  	return append(checkGaugeUpdate(), checkPluginUpdates()...)
    65  }
    66  
    67  func printUpdateInfo(print chan bool, wg *sync.WaitGroup) {
    68  	message := make(chan string)
    69  	go func() {
    70  		updates := checkUpdates()
    71  		if len(updates) > 0 {
    72  			message <- "Updates are available. Run gauge --check-updates for more info."
    73  		}
    74  	}()
    75  	waitToPrint(message, print, "", wg)
    76  }
    77  
    78  func waitToPrint(messageChan chan string, printChan chan bool, message string, wg *sync.WaitGroup) {
    79  	select {
    80  	case <-printChan:
    81  		if message != "" {
    82  			logger.Info(message)
    83  		}
    84  		wg.Done()
    85  	case message = <-messageChan:
    86  		waitToPrint(messageChan, printChan, message, wg)
    87  	}
    88  }
    89  
    90  func checkGaugeUpdate() []UpdateInfo {
    91  	var updateInfos []UpdateInfo
    92  	url := config.GaugeUpdateUrl()
    93  	if qp := plugin.QueryParams(); qp != "" {
    94  		url += qp
    95  	}
    96  	v, err := getLatestGaugeVersion(url)
    97  	if err != nil {
    98  		return updateInfos
    99  	}
   100  	latestVersion, err := version.ParseVersion(v)
   101  	if err != nil {
   102  		return updateInfos
   103  	}
   104  	isLatestVersion := version.CurrentGaugeVersion.IsLesserThan(latestVersion)
   105  	if isLatestVersion {
   106  		updateInfos = append(updateInfos, UpdateInfo{"Gauge", latestVersion.String(), "Download the installer from http://getgauge.io/get-started/"})
   107  	}
   108  	return updateInfos
   109  }
   110  
   111  type UpdateInfo struct {
   112  	Name              string
   113  	CompatibleVersion string
   114  	Message           string
   115  }
   116  
   117  func checkPluginUpdates() []UpdateInfo {
   118  	var pluginsToUpdate []UpdateInfo
   119  	plugins, err := plugin.GetAllInstalledPluginsWithVersion()
   120  	if err != nil {
   121  		return pluginsToUpdate
   122  	}
   123  	logger.Debug("Checking updates...")
   124  	for _, plugin := range plugins {
   125  		desc, result := getInstallDescription(plugin.Name, true)
   126  		if result.Error != nil {
   127  			continue
   128  		}
   129  		pluginsToUpdate = append(pluginsToUpdate, createPluginUpdateDetail(plugin.Version.String(), *desc)...)
   130  	}
   131  	return pluginsToUpdate
   132  }
   133  
   134  func createPluginUpdateDetail(currentVersion string, latestVersionDetails installDescription) []UpdateInfo {
   135  	var updateInfo []UpdateInfo
   136  	v, _ := version.ParseVersion(currentVersion)
   137  	v1, _ := version.ParseVersion(latestVersionDetails.Versions[0].Version)
   138  	if v.IsLesserThan(v1) {
   139  		versionDesc, err := latestVersionDetails.getLatestCompatibleVersionTo(version.CurrentGaugeVersion)
   140  		if err != nil {
   141  			return updateInfo
   142  		}
   143  		updateInfo = append(updateInfo, UpdateInfo{latestVersionDetails.Name, versionDesc.Version, fmt.Sprintf("Run 'gauge --update %s'", latestVersionDetails.Name)})
   144  	}
   145  	return updateInfo
   146  }
   147  
   148  var getLatestGaugeVersion = func(url string) (string, error) {
   149  	res, err := http.Get(url)
   150  	if err != nil {
   151  		return "", err
   152  	}
   153  	defer res.Body.Close()
   154  
   155  	v, err := getGaugeVersionProperty(res.Body)
   156  	if err != nil {
   157  		return "", err
   158  	}
   159  	return v, nil
   160  }
   161  
   162  func getGaugeVersionProperty(r io.Reader) (string, error) {
   163  	properties := make(properties.Properties)
   164  
   165  	err := properties.Load(r)
   166  	if err != nil {
   167  		return "", fmt.Errorf("Failed to parse: %s", err.Error())
   168  	}
   169  	return strings.TrimSpace(properties["version"]), nil
   170  }