Skip to content

Commit 6cc3694

Browse files
committed
Add ways to let users verify if new CLI released
1 parent 4010bcd commit 6cc3694

File tree

17 files changed

+255
-45
lines changed

17 files changed

+255
-45
lines changed

Diff for: arduino/discovery/discovery_client/go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
141141
github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4=
142142
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
143143
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072/go.mod h1:sGdS7A6CAETR53zkdjGkgoFlh1vSm7MtX+i8XfEsTMA=
144+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
144145
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
145146
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
146147
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=

Diff for: cli/cli.go

+34-8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/arduino/arduino-cli/cli/output"
4040
"github.com/arduino/arduino-cli/cli/sketch"
4141
"github.com/arduino/arduino-cli/cli/update"
42+
"github.com/arduino/arduino-cli/cli/updater"
4243
"github.com/arduino/arduino-cli/cli/upgrade"
4344
"github.com/arduino/arduino-cli/cli/upload"
4445
"github.com/arduino/arduino-cli/cli/version"
@@ -49,12 +50,14 @@ import (
4950
"github.com/rifflock/lfshook"
5051
"github.com/sirupsen/logrus"
5152
"github.com/spf13/cobra"
53+
semver "go.bug.st/relaxed-semver"
5254
)
5355

5456
var (
55-
verbose bool
56-
outputFormat string
57-
configFile string
57+
verbose bool
58+
outputFormat string
59+
configFile string
60+
updaterMessageChan chan *semver.Version = make(chan *semver.Version)
5861
)
5962

6063
// NewCommand creates a new ArduinoCli command root
@@ -63,11 +66,12 @@ func NewCommand() *cobra.Command {
6366

6467
// ArduinoCli is the root command
6568
arduinoCli := &cobra.Command{
66-
Use: "arduino-cli",
67-
Short: tr("Arduino CLI."),
68-
Long: tr("Arduino Command Line Interface (arduino-cli)."),
69-
Example: fmt.Sprintf(" %s <%s> [%s...]", os.Args[0], tr("command"), tr("flags")),
70-
PersistentPreRun: preRun,
69+
Use: "arduino-cli",
70+
Short: tr("Arduino CLI."),
71+
Long: tr("Arduino Command Line Interface (arduino-cli)."),
72+
Example: fmt.Sprintf(" %s <%s> [%s...]", os.Args[0], tr("command"), tr("flags")),
73+
PersistentPreRun: preRun,
74+
PersistentPostRun: postRun,
7175
}
7276

7377
arduinoCli.SetUsageTemplate(usageTemplate)
@@ -142,6 +146,20 @@ func preRun(cmd *cobra.Command, args []string) {
142146
os.Exit(errorcodes.ErrBadArgument)
143147
}
144148

149+
updaterMessageChan = make(chan *semver.Version)
150+
go func() {
151+
if cmd.Name() == "version" {
152+
// The version command checks by itself if there's a new available version
153+
updaterMessageChan <- nil
154+
}
155+
// Starts checking for updates
156+
currentVersion, err := semver.Parse(globals.VersionInfo.VersionString)
157+
if err != nil {
158+
updaterMessageChan <- nil
159+
}
160+
updaterMessageChan <- updater.CheckForUpdate(currentVersion)
161+
}()
162+
145163
//
146164
// Prepare logging
147165
//
@@ -226,3 +244,11 @@ func preRun(cmd *cobra.Command, args []string) {
226244
})
227245
}
228246
}
247+
248+
func postRun(cmd *cobra.Command, args []string) {
249+
latestVersion := <-updaterMessageChan
250+
if latestVersion != nil {
251+
// Notify the user a new version is available
252+
updater.NotifyNewVersionIsAvailable(latestVersion.String())
253+
}
254+
}

Diff for: cli/config/validate.go

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ var validMap = map[string]reflect.Kind{
3535
"metrics.enabled": reflect.Bool,
3636
"network.proxy": reflect.String,
3737
"network.user_agent_ext": reflect.String,
38+
"updater.disable_notification": reflect.Bool,
3839
}
3940

4041
func typeOf(key string) (reflect.Kind, error) {

Diff for: cli/updater/updater.go

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package updater
17+
18+
import (
19+
"os"
20+
"strings"
21+
"time"
22+
23+
"github.com/arduino/arduino-cli/cli/feedback"
24+
"github.com/arduino/arduino-cli/cli/globals"
25+
"github.com/arduino/arduino-cli/configuration"
26+
"github.com/arduino/arduino-cli/httpclient"
27+
"github.com/arduino/arduino-cli/inventory"
28+
"github.com/mgutz/ansi"
29+
semver "go.bug.st/relaxed-semver"
30+
)
31+
32+
// CheckForUpdate returns the latest available version if greater than
33+
// the one running and it makes sense to check for an udpate, nil in all other cases
34+
func CheckForUpdate(currentVersion *semver.Version) *semver.Version {
35+
if !shouldCheckForUpdate(currentVersion) {
36+
return nil
37+
}
38+
39+
return checkForUpdate(currentVersion)
40+
}
41+
42+
// ForceCheckForUpdate always returns the latest available version if greater than
43+
// the one running, nil in all other cases
44+
func ForceCheckForUpdate(currentVersion *semver.Version) *semver.Version {
45+
return checkForUpdate(currentVersion)
46+
}
47+
48+
func checkForUpdate(currentVersion *semver.Version) *semver.Version {
49+
defer func() {
50+
// Always save the last time we checked for updates at the end
51+
inventory.Store.Set("updater.last_check_time", time.Now())
52+
inventory.WriteStore()
53+
}()
54+
55+
latestVersion, err := semver.Parse(getLatestRelease())
56+
if err != nil {
57+
return nil
58+
}
59+
60+
if currentVersion.GreaterThanOrEqual(latestVersion) {
61+
// Current version is already good enough
62+
return nil
63+
}
64+
65+
return latestVersion
66+
}
67+
68+
// NotifyNewVersionIsAvailable prints information about the new latestVersion
69+
func NotifyNewVersionIsAvailable(latestVersion string) {
70+
feedback.Errorf("\n\n%s %s → %s\n%s",
71+
ansi.Color("A new release of arduino-cli is available:", "yellow"),
72+
ansi.Color(globals.VersionInfo.VersionString, "cyan"),
73+
ansi.Color(latestVersion, "cyan"),
74+
ansi.Color("https://arduino.github.io/arduino-cli/latest/installation/#latest-packages", "yellow"))
75+
}
76+
77+
// shouldCheckForUpdate return true if it actually makes sense to check for new updates,
78+
// false in all other cases.
79+
func shouldCheckForUpdate(currentVersion *semver.Version) bool {
80+
if strings.Contains(currentVersion.String(), "git") {
81+
// This is a dev build, no need to check for updates
82+
return false
83+
}
84+
85+
if configuration.Settings.GetBool("updater.disable_notification") {
86+
// Don't check if the user disable the notification
87+
return false
88+
}
89+
90+
if inventory.Store.IsSet("updater.last_check_time") && time.Since(inventory.Store.GetTime("updater.last_check_time")).Hours() < 24 {
91+
// Checked less than 24 hours ago, let's wait
92+
return false
93+
}
94+
95+
// Don't check when running on CI or on non interactive consoles
96+
return !isCI() && configuration.IsInteractive && configuration.HasConsole
97+
}
98+
99+
// based on https://github.com/watson/ci-info/blob/HEAD/index.js
100+
func isCI() bool {
101+
return os.Getenv("CI") != "" || // GitHub Actions, Travis CI, CircleCI, Cirrus CI, GitLab CI, AppVeyor, CodeShip, dsari
102+
os.Getenv("BUILD_NUMBER") != "" || // Jenkins, TeamCity
103+
os.Getenv("RUN_ID") != "" // TaskCluster, dsari
104+
}
105+
106+
// getLatestRelease queries the official Arduino download server for the latest release,
107+
// if there are no errors or issues a version string is returned, in all other case an empty string.
108+
func getLatestRelease() string {
109+
client, err := httpclient.New()
110+
if err != nil {
111+
return ""
112+
}
113+
114+
// We just use this URL to check if there's a new release available and
115+
// never show it to the user, so it's fine to use the Linux one for all OSs.
116+
URL := "https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz"
117+
res, err := client.Get(URL)
118+
if err != nil {
119+
// Yes, we ignore it
120+
return ""
121+
}
122+
123+
// Get redirected URL
124+
location := res.Request.URL.String()
125+
126+
// The location header points to the the latest release of the CLI, it's supposed to be formatted like this:
127+
// https://downloads.arduino.cc/arduino-cli/arduino-cli_0.18.3_Linux_64bit.tar.gz
128+
// so we split it to get the version, if there are not enough splits something must have gone wrong.
129+
split := strings.Split(location, "_")
130+
if len(split) < 2 {
131+
return ""
132+
}
133+
134+
return split[1]
135+
}

Diff for: cli/version/version.go

+29-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ package version
1717

1818
import (
1919
"os"
20+
"strings"
2021

22+
"github.com/arduino/arduino-cli/cli/errorcodes"
2123
"github.com/arduino/arduino-cli/cli/feedback"
2224
"github.com/arduino/arduino-cli/cli/globals"
25+
"github.com/arduino/arduino-cli/cli/updater"
2326
"github.com/arduino/arduino-cli/i18n"
2427
"github.com/spf13/cobra"
28+
semver "go.bug.st/relaxed-semver"
2529
)
2630

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

4145
func run(cmd *cobra.Command, args []string) {
42-
feedback.Print(globals.VersionInfo)
46+
if strings.Contains(globals.VersionInfo.VersionString, "git-snapshot") {
47+
// We're using a development version, no need to check if there's a
48+
// new release available
49+
feedback.Print(globals.VersionInfo)
50+
return
51+
}
52+
53+
currentVersion, err := semver.Parse(globals.VersionInfo.VersionString)
54+
if err != nil {
55+
feedback.Errorf("Error parsing current version: %s", err)
56+
os.Exit(errorcodes.ErrGeneric)
57+
}
58+
latestVersion := updater.ForceCheckForUpdate(currentVersion)
59+
60+
versionInfo := globals.VersionInfo
61+
if feedback.GetFormat() == feedback.JSON && latestVersion != nil {
62+
// Set this only we managed to get the latest version
63+
versionInfo.LatestVersion = latestVersion.String()
64+
}
65+
66+
feedback.Print(versionInfo)
67+
68+
if feedback.GetFormat() == feedback.Text && latestVersion != nil {
69+
updater.NotifyNewVersionIsAvailable(latestVersion.String())
70+
}
4371
}

Diff for: client_example/go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
129129
github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4=
130130
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
131131
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072/go.mod h1:sGdS7A6CAETR53zkdjGkgoFlh1vSm7MtX+i8XfEsTMA=
132+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
132133
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
133134
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
134135
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=

Diff for: commands/daemon/term_example/go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
129129
github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4=
130130
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
131131
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072/go.mod h1:sGdS7A6CAETR53zkdjGkgoFlh1vSm7MtX+i8XfEsTMA=
132+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
132133
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
133134
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
134135
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=

Diff for: configuration/defaults.go

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ func SetDefaults(settings *viper.Viper) {
4949
settings.SetDefault("metrics.enabled", true)
5050
settings.SetDefault("metrics.addr", ":9090")
5151

52+
// updater settings
53+
settings.SetDefault("updater.disable_notification", false)
54+
5255
// Bind env vars
5356
settings.SetEnvPrefix("ARDUINO")
5457
settings.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

Diff for: docs/configuration.md

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
- `sketch` - configuration options relating to [Arduino sketches][sketch specification].
2525
- `always_export_binaries` - set to `true` to make [`arduino-cli compile`][arduino-cli compile] always save binaries
2626
to the sketch folder. This is the equivalent of using the [`--export-binaries`][arduino-cli compile options] flag.
27+
- `updater` - configuration options related to Arduino CLI updates
28+
- `disable_notification` - set to `true` to disable notifications of new Arduino CLI releases, defaults to `false`
2729

2830
## Configuration methods
2931

Diff for: docs/installation.md

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ as a parameter like this:
4040
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh -s 0.9.0
4141
```
4242

43+
The Arduino CLI verifies every 24 hours if there are new releases, if you don't like this behaviour you can disable it
44+
by setting the `updater.disable_notification` config or the env var `ARDUINO_UPDATER_DISABLE_NOTIFICATION` to `true`.
45+
4346
### Download
4447

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

Diff for: docsgen/go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
171171
github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4=
172172
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
173173
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072/go.mod h1:sGdS7A6CAETR53zkdjGkgoFlh1vSm7MtX+i8XfEsTMA=
174+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
175+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
174176
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
175177
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
176178
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=

Diff for: go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ require (
2424
github.com/mattn/go-colorable v0.1.2
2525
github.com/mattn/go-isatty v0.0.8
2626
github.com/mattn/go-runewidth v0.0.9 // indirect
27+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
2728
github.com/miekg/dns v1.1.43 // indirect
2829
github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228 // indirect
2930
github.com/pkg/errors v0.9.1

Diff for: go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
172172
github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4=
173173
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
174174
github.com/mdlayher/taskstats v0.0.0-20190313225729-7cbba52ee072/go.mod h1:sGdS7A6CAETR53zkdjGkgoFlh1vSm7MtX+i8XfEsTMA=
175+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
176+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
175177
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
176178
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
177179
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=

0 commit comments

Comments
 (0)