5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-04 02:51:56 +08:00

feat: better version comparison

This commit is contained in:
Lea Anthony 2019-05-10 23:01:50 +10:00
parent 11fd50f78d
commit 71194108de
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
3 changed files with 177 additions and 69 deletions

View File

@ -5,34 +5,24 @@ import (
"fmt"
"io/ioutil"
"net/http"
"regexp"
"sort"
"github.com/Masterminds/semver"
)
// GitHubHelper is a utility class for interacting with GitHub
type GitHubHelper struct {
validPrereleaseRegex *regexp.Regexp
validReleaseRegex *regexp.Regexp
}
// NewGitHubHelper returns a new GitHub Helper
func NewGitHubHelper() *GitHubHelper {
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?`
const SemPreVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`
return &GitHubHelper{
validPrereleaseRegex: regexp.MustCompile(SemPreVerRegex),
validReleaseRegex: regexp.MustCompile(SemVerRegex),
}
return &GitHubHelper{}
}
// GetVersionTags gets the list of tags on the Wails repo
// It retuns a list of sorted tags in descending order
func (g *GitHubHelper) GetVersionTags() ([]*semver.Version, error) {
func (g *GitHubHelper) GetVersionTags() ([]*SemanticVersion, error) {
result := []*SemanticVersion{}
result := []*semver.Version{}
var err error
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
@ -53,7 +43,7 @@ func (g *GitHubHelper) GetVersionTags() ([]*semver.Version, error) {
// Convert tag data to Version structs
for _, tag := range data {
version := tag["name"].(string)
semver, err := semver.NewVersion(version)
semver, err := NewSemanticVersion(version)
if err != nil {
return result, err
}
@ -61,32 +51,41 @@ func (g *GitHubHelper) GetVersionTags() ([]*semver.Version, error) {
}
// Reverse Sort
sort.Sort(sort.Reverse(semver.Collection(result)))
sort.Sort(sort.Reverse(SemverCollection(result)))
return result, err
}
func (g *GitHubHelper) isRelease(tag *semver.Version) bool {
return g.validReleaseRegex.MatchString(tag.String())
}
func (g *GitHubHelper) isPreRelease(tag *semver.Version) bool {
return g.validPrereleaseRegex.MatchString(tag.String())
}
// GetLatestStableRelease gets the latest stable release on GitHub
func (g *GitHubHelper) GetLatestStableRelease() (result string, err error) {
func (g *GitHubHelper) GetLatestStableRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return "", err
return nil, err
}
for _, tag := range tags {
if g.isRelease(tag) {
return "v" + tag.String(), nil
if tag.IsRelease() {
return tag, nil
}
}
return "", fmt.Errorf("no release tag found")
return nil, fmt.Errorf("no release tag found")
}
// GetLatestPreRelease gets the latest prerelease on GitHub
func (g *GitHubHelper) GetLatestPreRelease() (result *SemanticVersion, err error) {
tags, err := g.GetVersionTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
if tag.IsPreRelease() {
return tag, nil
}
}
return nil, fmt.Errorf("no prerelease tag found")
}

79
cmd/semver.go Normal file
View File

@ -0,0 +1,79 @@
package cmd
import (
"regexp"
"github.com/masterminds/semver"
)
type SemanticVersion struct {
Version *semver.Version
validPrereleaseRegex *regexp.Regexp
validReleaseRegex *regexp.Regexp
}
// NewSemanticVersion creates a new SemanticVersion object with the given version string
func NewSemanticVersion(version string) (*SemanticVersion, error) {
semverVersion, err := semver.NewVersion(version)
if err != nil {
return nil, err
}
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?`
const SemPreVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`
return &SemanticVersion{
Version: semverVersion,
validPrereleaseRegex: regexp.MustCompile(SemPreVerRegex),
validReleaseRegex: regexp.MustCompile(SemVerRegex),
}, nil
}
// IsRelease returns true if it's a release version
func (s *SemanticVersion) IsRelease() bool {
return s.validReleaseRegex.MatchString(s.Version.String())
}
// IsPreRelease returns true if it's a prerelease version
func (s *SemanticVersion) IsPreRelease() bool {
return s.validPrereleaseRegex.MatchString(s.Version.String())
}
func (s *SemanticVersion) String() string {
return s.Version.String()
}
func (s *SemanticVersion) IsGreaterThan(version *SemanticVersion) (bool, error) {
// Set up new constraint
constraint, err := semver.NewConstraint("> " + version.Version.String())
if err != nil {
return false, err
}
// Check if the desired one is greater than the requested on
success, msgs := constraint.Validate(s.Version)
if !success {
return false, msgs[0]
}
return true, nil
}
// SemverCollection is a collection of SemanticVersion objects
type SemverCollection []*SemanticVersion
// Len returns the length of a collection. The number of Version instances
// on the slice.
func (c SemverCollection) Len() int {
return len(c)
}
// Less is needed for the sort interface to compare two Version objects on the
// slice. If checks if one is less than the other.
func (c SemverCollection) Less(i, j int) bool {
return c[i].Version.LessThan(c[j].Version)
}
// Swap is needed for the sort interface to replace the Version objects
// at two different positions in the slice.
func (c SemverCollection) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}

View File

@ -1,11 +1,8 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/leaanthony/spinner"
"github.com/mitchellh/go-homedir"
@ -14,13 +11,16 @@ import (
func init() {
var prereleaseRequired bool
// var forceRebuild = false
checkSpinner := spinner.NewSpinner()
checkSpinner.SetSpinSpeed(50)
commandDescription := `This command checks if there are updates to Wails.`
commandDescription := `This command allows you to update your version of Wails.`
updateCmd := app.Command("update", "Check for Updates.").
LongDescription(commandDescription)
LongDescription(commandDescription).
BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired)
updateCmd.Action(func() error {
@ -30,49 +30,79 @@ func init() {
// Get versions
checkSpinner.Start(message)
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
github := cmd.NewGitHubHelper()
var desiredVersion *cmd.SemanticVersion
var err error
if prereleaseRequired {
desiredVersion, err = github.GetLatestPreRelease()
} else {
desiredVersion, err = github.GetLatestStableRelease()
}
if err != nil {
checkSpinner.Error(err.Error())
return err
}
checkSpinner.Success()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
checkSpinner.Error(err.Error())
return err
}
data := []map[string]interface{}{}
err = json.Unmarshal(body, &data)
if err != nil {
return err
}
latestVersion := data[0]["name"].(string)
fmt.Println()
fmt.Println("Current Version: " + cmd.Version)
fmt.Println(" Latest Version: " + latestVersion)
if latestVersion != cmd.Version {
updateSpinner := spinner.NewSpinner()
updateSpinner.SetSpinSpeed(40)
updateSpinner.Start("Updating to : " + latestVersion)
// Run command in non module directory
homeDir, err := homedir.Dir()
if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!")
}
err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "github.com/wailsapp/wails/.../."}, homeDir)
if err != nil {
updateSpinner.Error(err.Error())
return err
}
updateSpinner.Success()
logger.Yellow("Wails updated to " + latestVersion)
fmt.Println(" Current Version : " + cmd.Version)
if prereleaseRequired {
fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion)
} else {
logger.Yellow("Looks like you're up to date!")
fmt.Printf(" Latest Release : v%s\n", desiredVersion)
}
return nil
return updateToVersion(desiredVersion)
})
}
func updateToVersion(version *cmd.SemanticVersion) error {
// Early exit
if version.String() == cmd.Version {
logger.Green("Looks like you're up to date!")
return nil
}
compareVersion := cmd.Version
if version.IsPreRelease() {
compareVersion += "-0"
}
currentVersion, err := cmd.NewSemanticVersion(compareVersion)
if err != nil {
return err
}
// Compare
success, err := version.IsGreaterThan(currentVersion)
if !success {
logger.Red("The requested version is lower than the current version. Aborting.")
return nil
}
desiredVersion := "v" + version.String()
fmt.Println()
updateSpinner := spinner.NewSpinner()
updateSpinner.SetSpinSpeed(40)
updateSpinner.Start("Installing Wails " + desiredVersion)
// Run command in non module directory
homeDir, err := homedir.Dir()
if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!")
}
err = cmd.NewProgramHelper().RunCommandArray([]string{"go", "get", "github.com/wailsapp/wails/cmd/wails@" + desiredVersion}, homeDir)
if err != nil {
updateSpinner.Error(err.Error())
return err
}
updateSpinner.Success()
fmt.Println()
logger.Green("Wails updated to " + desiredVersion)
return nil
}