mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-08 01:11:06 +08:00
feat: better version comparison
This commit is contained in:
parent
11fd50f78d
commit
71194108de
@ -5,34 +5,24 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitHubHelper is a utility class for interacting with GitHub
|
// GitHubHelper is a utility class for interacting with GitHub
|
||||||
type GitHubHelper struct {
|
type GitHubHelper struct {
|
||||||
validPrereleaseRegex *regexp.Regexp
|
|
||||||
validReleaseRegex *regexp.Regexp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGitHubHelper returns a new GitHub Helper
|
// NewGitHubHelper returns a new GitHub Helper
|
||||||
func NewGitHubHelper() *GitHubHelper {
|
func NewGitHubHelper() *GitHubHelper {
|
||||||
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?`
|
return &GitHubHelper{}
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionTags gets the list of tags on the Wails repo
|
// GetVersionTags gets the list of tags on the Wails repo
|
||||||
// It retuns a list of sorted tags in descending order
|
// 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
|
var err error
|
||||||
|
|
||||||
resp, err := http.Get("https://api.github.com/repos/wailsapp/wails/tags")
|
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
|
// Convert tag data to Version structs
|
||||||
for _, tag := range data {
|
for _, tag := range data {
|
||||||
version := tag["name"].(string)
|
version := tag["name"].(string)
|
||||||
semver, err := semver.NewVersion(version)
|
semver, err := NewSemanticVersion(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
@ -61,32 +51,41 @@ func (g *GitHubHelper) GetVersionTags() ([]*semver.Version, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reverse Sort
|
// Reverse Sort
|
||||||
sort.Sort(sort.Reverse(semver.Collection(result)))
|
sort.Sort(sort.Reverse(SemverCollection(result)))
|
||||||
|
|
||||||
return result, err
|
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
|
// 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()
|
tags, err := g.GetVersionTags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if g.isRelease(tag) {
|
if tag.IsRelease() {
|
||||||
return "v" + tag.String(), nil
|
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
79
cmd/semver.go
Normal 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]
|
||||||
|
}
|
@ -1,11 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
@ -14,13 +11,16 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
|
var prereleaseRequired bool
|
||||||
|
|
||||||
// var forceRebuild = false
|
// var forceRebuild = false
|
||||||
checkSpinner := spinner.NewSpinner()
|
checkSpinner := spinner.NewSpinner()
|
||||||
checkSpinner.SetSpinSpeed(50)
|
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.").
|
updateCmd := app.Command("update", "Check for Updates.").
|
||||||
LongDescription(commandDescription)
|
LongDescription(commandDescription).
|
||||||
|
BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired)
|
||||||
|
|
||||||
updateCmd.Action(func() error {
|
updateCmd.Action(func() error {
|
||||||
|
|
||||||
@ -30,49 +30,79 @@ func init() {
|
|||||||
|
|
||||||
// Get versions
|
// Get versions
|
||||||
checkSpinner.Start(message)
|
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 {
|
if err != nil {
|
||||||
checkSpinner.Error(err.Error())
|
checkSpinner.Error(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
checkSpinner.Success()
|
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()
|
||||||
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
|
fmt.Println(" Current Version : " + cmd.Version)
|
||||||
homeDir, err := homedir.Dir()
|
if prereleaseRequired {
|
||||||
if err != nil {
|
fmt.Printf(" Latest Prerelease : v%s\n", desiredVersion)
|
||||||
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)
|
|
||||||
} else {
|
} 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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user