Add dagger version check

Signed-off-by: Tom Chauveau <tom.chauveau@epitech.eu>
This commit is contained in:
Tom Chauveau 2021-05-06 19:20:39 +02:00
parent 99386c3aa8
commit 5f723df36a
4 changed files with 158 additions and 5 deletions

View File

@ -25,6 +25,9 @@ func init() {
rootCmd.PersistentFlags().StringP("log-level", "l", "info", "Log level") rootCmd.PersistentFlags().StringP("log-level", "l", "info", "Log level")
rootCmd.PersistentFlags().StringP("environment", "e", "", "Select an environment") rootCmd.PersistentFlags().StringP("environment", "e", "", "Select an environment")
rootCmd.PersistentPreRun = checkVersionHook
rootCmd.PersistentPostRun = warnVersionHook
rootCmd.AddCommand( rootCmd.AddCommand(
computeCmd, computeCmd,
newCmd, newCmd,
@ -50,6 +53,14 @@ func init() {
viper.AutomaticEnv() viper.AutomaticEnv()
} }
func checkVersionHook(cmd *cobra.Command, args []string) {
go checkVersion()
}
func warnVersionHook(cmd *cobra.Command, args []string) {
warnVersion()
}
func Execute() { func Execute() {
var ( var (
ctx = appcontext.Context() ctx = appcontext.Context()

View File

@ -1,27 +1,41 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io/ioutil"
"net/http"
"os"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
"strings"
"time"
goVersion "github.com/hashicorp/go-version"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper"
) )
const ( const (
defaultVersion = "devel" defaultVersion = "devel"
outdatedMessage = "dagger binary is outdated, go to https://github.com/dagger/dagger/doc/update.md to update dagger."
) )
// set by goreleaser or other builder using // set by goreleaser or other builder using
// -ldflags='-X dagger.io/go/cmd/dagger/cmd.version=<version>' // -ldflags='-X dagger.io/go/cmd/dagger/cmd.version=<version>'
var ( var (
version = defaultVersion version = defaultVersion
versionMessage = ""
) )
// Disable version hook here
// It can lead to a double check if --check flag is enable
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Print dagger version", Short: "Print dagger version",
Args: cobra.NoArgs, PreRun: nil,
PostRun: nil,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if bi, ok := debug.ReadBuildInfo(); ok && version == defaultVersion { if bi, ok := debug.ReadBuildInfo(); ok && version == defaultVersion {
// No specific version provided via version // No specific version provided via version
@ -31,5 +45,131 @@ var versionCmd = &cobra.Command{
version, version,
runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH,
) )
if check := viper.GetBool("check"); check != false {
upToDate, err := isVersionLatest()
if err != nil {
fmt.Println("error: could not check version.")
return
}
if !upToDate {
fmt.Println(outdatedMessage)
} else {
fmt.Println("dagger is up to date.")
}
}
}, },
} }
func init() {
versionCmd.Flags().Bool("check", false, "check if dagger is up to date")
if err := viper.BindPFlags(versionCmd.Flags()); err != nil {
panic(err)
}
}
func isCheckOutdated(path string) bool {
data, err := ioutil.ReadFile(path)
if err != nil {
return true
}
lastCheck, err := time.Parse(time.RFC3339, string(data))
if err != nil {
return true
}
nextCheck := lastCheck.Add(24 * time.Hour)
return !time.Now().Before(nextCheck)
}
func getVersion() (*goVersion.Version, error) {
if version != defaultVersion {
return goVersion.NewVersion(version)
}
if build, ok := debug.ReadBuildInfo(); ok {
return goVersion.NewVersion(build.Main.Version)
}
return nil, errors.New("could not read dagger version")
}
func getOnlineVersion(currentVersion *goVersion.Version) (*goVersion.Version, error) {
req, err := http.NewRequest("GET", "https://releases.dagger.io/dagger/latest_version", nil)
if err != nil {
return nil, err
}
// dagger/<version> (<OS>; <ARCH>)
agent := fmt.Sprintf("dagger/%s (%s; %s)", currentVersion.String(), runtime.GOOS, runtime.GOARCH)
req.Header.Set("User-Agent", agent)
req.Header.Set("X-Dagger-Version", currentVersion.String())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
latestVersion := strings.TrimSuffix(string(data), "\n")
return goVersion.NewVersion(latestVersion)
}
// Compare the binary version with the latest version online
func isVersionLatest() (bool, error) {
currentVersion, err := getVersion()
if err != nil {
return false, err
}
latestVersion, err := getOnlineVersion(currentVersion)
if err != nil {
return false, err
}
if currentVersion.LessThan(latestVersion) {
return false, nil
}
return true, nil
}
func checkVersion() {
home, err := os.UserHomeDir()
if err != nil {
return
}
daggerDirectory := home + "/.dagger"
if folder, err := os.Stat(daggerDirectory); !os.IsNotExist(err) {
if !folder.IsDir() {
return
}
if !isCheckOutdated(daggerDirectory + "/version_check.txt") {
return
}
// Check timestamp
upToDate, err := isVersionLatest()
if err != nil {
return
}
if !upToDate {
versionMessage = outdatedMessage
}
// Update check timestamps file
now := time.Now().Format(time.RFC3339)
ioutil.WriteFile(daggerDirectory+"/version_check.txt", []byte(now), 0644)
}
}
func warnVersion() {
if versionMessage != "" {
fmt.Println(versionMessage)
}
}

1
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/docker/distribution v2.7.1+incompatible github.com/docker/distribution v2.7.1+incompatible
github.com/emicklei/proto v1.9.0 // indirect github.com/emicklei/proto v1.9.0 // indirect
github.com/google/uuid v1.2.0 github.com/google/uuid v1.2.0
github.com/hashicorp/go-version v1.2.0
github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db
github.com/moby/buildkit v0.8.2 github.com/moby/buildkit v0.8.2

1
go.sum
View File

@ -587,6 +587,7 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=