The Wayback Machine - https://web.archive.org/web/20211118005207/https://github.com/arduino/arduino-cli/commit/bc998ed6a9ebb3db79d8cfe97a5c8d974b4ed309
Skip to content
Permalink
Browse files
Add ways to let users verify if new CLI released (#1416)
* Add ways to let users verify if new CLI released

* Code review fixes

Co-authored-by: per1234 <[email protected]>

* Enhance docs

Co-authored-by: per1234 <[email protected]>

* Fix version check for git-snapshots and nightlies

* Change method to request latest release

* Remove ansi library in favor of color

* Fix go mod errors

* Remove useless function

Co-authored-by: Cristian Maglie <[email protected]>

Co-authored-by: per1234 <[email protected]>
Co-authored-by: Cristian Maglie <[email protected]>
  • Loading branch information
3 people committed Aug 31, 2021
1 parent ff4eb92 commit bc998ed6a9ebb3db79d8cfe97a5c8d974b4ed309
Showing with 248 additions and 42 deletions.
  1. +34 −8 cli/cli.go
  2. +1 −0 cli/config/validate.go
  3. +134 −0 cli/updater/updater.go
  4. +29 −1 cli/version/version.go
  5. +3 −0 configuration/defaults.go
  6. +2 −0 docs/configuration.md
  7. +4 −0 docs/installation.md
  8. +28 −24 i18n/data/en.po
  9. +4 −4 i18n/rice-box.go
  10. +8 −5 inventory/inventory.go
  11. +1 −0 version/version.go
@@ -39,6 +39,7 @@ import (
"github.com/arduino/arduino-cli/cli/output"
"github.com/arduino/arduino-cli/cli/sketch"
"github.com/arduino/arduino-cli/cli/update"
"github.com/arduino/arduino-cli/cli/updater"
"github.com/arduino/arduino-cli/cli/upgrade"
"github.com/arduino/arduino-cli/cli/upload"
"github.com/arduino/arduino-cli/cli/version"
@@ -50,12 +51,14 @@ import (
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
semver "go.bug.st/relaxed-semver"
)

var (
verbose bool
outputFormat string
configFile string
verbose bool
outputFormat string
configFile string
updaterMessageChan chan *semver.Version = make(chan *semver.Version)
)

// NewCommand creates a new ArduinoCli command root
@@ -64,11 +67,12 @@ func NewCommand() *cobra.Command {

// ArduinoCli is the root command
arduinoCli := &cobra.Command{
Use: "arduino-cli",
Short: tr("Arduino CLI."),
Long: tr("Arduino Command Line Interface (arduino-cli)."),
Example: fmt.Sprintf(" %s <%s> [%s...]", os.Args[0], tr("command"), tr("flags")),
PersistentPreRun: preRun,
Use: "arduino-cli",
Short: tr("Arduino CLI."),
Long: tr("Arduino Command Line Interface (arduino-cli)."),
Example: fmt.Sprintf(" %s <%s> [%s...]", os.Args[0], tr("command"), tr("flags")),
PersistentPreRun: preRun,
PersistentPostRun: postRun,
}

arduinoCli.SetUsageTemplate(usageTemplate)
@@ -151,6 +155,20 @@ func preRun(cmd *cobra.Command, args []string) {
feedback.SetOut(colorable.NewColorableStdout())
feedback.SetErr(colorable.NewColorableStderr())

updaterMessageChan = make(chan *semver.Version)
go func() {
if cmd.Name() == "version" {
// The version command checks by itself if there's a new available version
updaterMessageChan <- nil
}
// Starts checking for updates
currentVersion, err := semver.Parse(globals.VersionInfo.VersionString)
if err != nil {
updaterMessageChan <- nil
}
updaterMessageChan <- updater.CheckForUpdate(currentVersion)
}()

//
// Prepare logging
//
@@ -236,3 +254,11 @@ func preRun(cmd *cobra.Command, args []string) {
})
}
}

func postRun(cmd *cobra.Command, args []string) {
latestVersion := <-updaterMessageChan
if latestVersion != nil {
// Notify the user a new version is available
updater.NotifyNewVersionIsAvailable(latestVersion.String())
}
}
@@ -36,6 +36,7 @@ var validMap = map[string]reflect.Kind{
"network.proxy": reflect.String,
"network.user_agent_ext": reflect.String,
"output.no_color": reflect.Bool,
"updater.enable_notification": reflect.Bool,
}

func typeOf(key string) (reflect.Kind, error) {
@@ -0,0 +1,134 @@
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to [email protected].

package updater

import (
"os"
"strings"
"time"

"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/configuration"
"github.com/arduino/arduino-cli/httpclient"
"github.com/arduino/arduino-cli/i18n"
"github.com/arduino/arduino-cli/inventory"
"github.com/fatih/color"
semver "go.bug.st/relaxed-semver"
)

var tr = i18n.Tr

// CheckForUpdate returns the latest available version if greater than
// the one running and it makes sense to check for an update, nil in all other cases
func CheckForUpdate(currentVersion *semver.Version) *semver.Version {
if !shouldCheckForUpdate(currentVersion) {
return nil
}

return ForceCheckForUpdate(currentVersion)
}

// ForceCheckForUpdate always returns the latest available version if greater than
// the one running, nil in all other cases
func ForceCheckForUpdate(currentVersion *semver.Version) *semver.Version {
defer func() {
// Always save the last time we checked for updates at the end
inventory.Store.Set("updater.last_check_time", time.Now())
inventory.WriteStore()
}()

latestVersion, err := semver.Parse(getLatestRelease())
if err != nil {
return nil
}

if currentVersion.GreaterThanOrEqual(latestVersion) {
// Current version is already good enough
return nil
}

return latestVersion
}

// NotifyNewVersionIsAvailable prints information about the new latestVersion
func NotifyNewVersionIsAvailable(latestVersion string) {
feedback.Errorf("\n\n%s %s → %s\n%s",
color.YellowString(tr("A new release of Arduino CLI is available:")),
color.CyanString(globals.VersionInfo.VersionString),
color.CyanString(latestVersion),
color.YellowString("https://arduino.github.io/arduino-cli/latest/installation/#latest-packages"))
}

// shouldCheckForUpdate return true if it actually makes sense to check for new updates,
// false in all other cases.
func shouldCheckForUpdate(currentVersion *semver.Version) bool {
if strings.Contains(currentVersion.String(), "git-snapshot") || strings.Contains(currentVersion.String(), "nightly") {
// This is a dev build, no need to check for updates
return false
}

if !configuration.Settings.GetBool("updater.enable_notification") {
// Don't check if the user disabled the notification
return false
}

if inventory.Store.IsSet("updater.last_check_time") && time.Since(inventory.Store.GetTime("updater.last_check_time")).Hours() < 24 {
// Checked less than 24 hours ago, let's wait
return false
}

// Don't check when running on CI or on non interactive consoles
return !isCI() && configuration.IsInteractive && configuration.HasConsole
}

// based on https://github.com/watson/ci-info/blob/HEAD/index.js
func isCI() bool {
return os.Getenv("CI") != "" || // GitHub Actions, Travis CI, CircleCI, Cirrus CI, GitLab CI, AppVeyor, CodeShip, dsari
os.Getenv("BUILD_NUMBER") != "" || // Jenkins, TeamCity
os.Getenv("RUN_ID") != "" // TaskCluster, dsari
}

// getLatestRelease queries the official Arduino download server for the latest release,
// if there are no errors or issues a version string is returned, in all other case an empty string.
func getLatestRelease() string {
client, err := httpclient.New()
if err != nil {
return ""
}

// We just use this URL to check if there's a new release available and
// never show it to the user, so it's fine to use the Linux one for all OSs.
URL := "https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz"
res, err := client.Head(URL)
if err != nil {
// Yes, we ignore it
return ""
}

// Get redirected URL
location := res.Request.URL.String()

// The location header points to the the latest release of the CLI, it's supposed to be formatted like this:
// https://downloads.arduino.cc/arduino-cli/arduino-cli_0.18.3_Linux_64bit.tar.gz
// so we split it to get the version, if there are not enough splits something must have gone wrong.
split := strings.Split(location, "_")
if len(split) < 2 {
return ""
}

return split[1]
}
@@ -17,11 +17,15 @@ package version

import (
"os"
"strings"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/cli/updater"
"github.com/arduino/arduino-cli/i18n"
"github.com/spf13/cobra"
semver "go.bug.st/relaxed-semver"
)

var tr = i18n.Tr
@@ -39,5 +43,29 @@ func NewCommand() *cobra.Command {
}

func run(cmd *cobra.Command, args []string) {
feedback.Print(globals.VersionInfo)
if strings.Contains(globals.VersionInfo.VersionString, "git-snapshot") || strings.Contains(globals.VersionInfo.VersionString, "nightly") {
// We're using a development version, no need to check if there's a
// new release available
feedback.Print(globals.VersionInfo)
return
}

currentVersion, err := semver.Parse(globals.VersionInfo.VersionString)
if err != nil {
feedback.Errorf("Error parsing current version: %s", err)
os.Exit(errorcodes.ErrGeneric)
}
latestVersion := updater.ForceCheckForUpdate(currentVersion)

versionInfo := globals.VersionInfo
if feedback.GetFormat() == feedback.JSON && latestVersion != nil {
// Set this only we managed to get the latest version
versionInfo.LatestVersion = latestVersion.String()
}

feedback.Print(versionInfo)

if feedback.GetFormat() == feedback.Text && latestVersion != nil {
updater.NotifyNewVersionIsAvailable(latestVersion.String())
}
}
@@ -52,6 +52,9 @@ func SetDefaults(settings *viper.Viper) {
// output settings
settings.SetDefault("output.no_color", false)

// updater settings
settings.SetDefault("updater.enable_notification", true)

// Bind env vars
settings.SetEnvPrefix("ARDUINO")
settings.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
@@ -24,6 +24,8 @@
- `sketch` - configuration options relating to [Arduino sketches][sketch specification].
- `always_export_binaries` - set to `true` to make [`arduino-cli compile`][arduino-cli compile] always save binaries
to the sketch folder. This is the equivalent of using the [`--export-binaries`][arduino-cli compile options] flag.
- `updater` - configuration options related to Arduino CLI updates
- `enable_notification` - set to `false` to disable notifications of new Arduino CLI releases, defaults to `true`

## Configuration methods

@@ -40,6 +40,10 @@ as a parameter like this:
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh -s 0.9.0
```

Arduino CLI checks for new releases every 24 hours. If you don't like this behaviour you can disable it by setting the
[`updater.enable_notification` config](configuration.md#configuration-keys) or the
[env var `ARDUINO_UPDATER_ENABLE_NOTIFICATION`](configuration.md#environment-variables) to `false`.

### Download

Pre-built binaries for all the supported platforms are available for download from the links below.
Loading

0 comments on commit bc998ed

Please sign in to comment.