Skip to content

Commit ff35719

Browse files
authored
[launcher] Add version update command and show launcher version warning (#798)
## Summary This adds a new `version update` command. It does 3 things: * Deletes the version cache (if it exists) * Updates the launcher * Updates the binary (if needed) This can be useful for 2 cases: * launcher is out of date * user wishes to override the version cache. This also adds a warning if the launcher is out of date but does not automatically trigger the update flow. Thoughts? ## How was it tested? <img width="792" alt="image" src="https://user-images.githubusercontent.com/544948/226768704-4cf79e3c-cbe6-41a4-8b17-41762cf14df6.png"> and ran `devbox self-update`
1 parent 2dd3d02 commit ff35719

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

internal/boxcli/root.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"go.jetpack.io/devbox/internal/boxcli/midcobra"
1414
"go.jetpack.io/devbox/internal/cloud/openssh/sshshim"
1515
"go.jetpack.io/devbox/internal/debug"
16+
"go.jetpack.io/devbox/internal/vercheck"
1617
)
1718

1819
var (
@@ -30,6 +31,7 @@ func RootCmd() *cobra.Command {
3031
Use: "devbox",
3132
Short: "Instant, easy, predictable development environments",
3233
PersistentPreRun: func(cmd *cobra.Command, args []string) {
34+
vercheck.CheckLauncherVersion(cmd.ErrOrStderr())
3335
if flags.quiet {
3436
cmd.SetErr(io.Discard)
3537
}
@@ -52,6 +54,7 @@ func RootCmd() *cobra.Command {
5254
command.AddCommand(PlanCmd())
5355
command.AddCommand(RemoveCmd())
5456
command.AddCommand(RunCmd())
57+
command.AddCommand(selfUpdateCmd())
5558
command.AddCommand(ServicesCmd())
5659
command.AddCommand(SetupCmd())
5760
command.AddCommand(ShellCmd())

internal/boxcli/version.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/spf13/cobra"
1111
"go.jetpack.io/devbox/internal/build"
12+
"go.jetpack.io/devbox/internal/vercheck"
1213
)
1314

1415
type versionFlags struct {
@@ -29,6 +30,20 @@ func VersionCmd() *cobra.Command {
2930
command.Flags().BoolVarP(&flags.verbose, "verbose", "v", false, // value
3031
"displays additional version information",
3132
)
33+
command.AddCommand(selfUpdateCmd())
34+
return command
35+
}
36+
37+
func selfUpdateCmd() *cobra.Command {
38+
command := &cobra.Command{
39+
Use: "update",
40+
Short: "Update devbox launcher and binary",
41+
Args: cobra.ExactArgs(0),
42+
RunE: func(cmd *cobra.Command, args []string) error {
43+
return vercheck.SelfUpdate(cmd.OutOrStdout(), cmd.ErrOrStderr())
44+
},
45+
}
46+
3247
return command
3348
}
3449

internal/vercheck/vercheck.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package vercheck
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
10+
"github.com/pkg/errors"
11+
"go.jetpack.io/devbox/internal/boxcli/usererr"
12+
"go.jetpack.io/devbox/internal/cloud/envir"
13+
"go.jetpack.io/devbox/internal/ux"
14+
"go.jetpack.io/devbox/internal/xdg"
15+
"golang.org/x/mod/semver"
16+
)
17+
18+
// Keep this in-sync with latest version in launch.sh. If this version is newer
19+
// Than the version in launch.sh, we'll print a warning.
20+
const expectedLauncherVersion = "v0.1.0"
21+
22+
func CheckLauncherVersion(w io.Writer) {
23+
launcherVersion := os.Getenv("LAUNCHER_VERSION")
24+
if launcherVersion == "" || envir.IsDevboxCloud() {
25+
return
26+
}
27+
28+
// If launcherVersion is invalid, this will return 0 and we won't print a warning
29+
if semver.Compare("v"+launcherVersion, expectedLauncherVersion) < 0 {
30+
ux.Fwarning(
31+
w,
32+
"newer launcher version %s is available (current = v%s), please update "+
33+
"using `devbox version update`\n",
34+
expectedLauncherVersion,
35+
os.Getenv("LAUNCHER_VERSION"),
36+
)
37+
}
38+
}
39+
40+
// SelfUpdate updates the devbox launcher and binary. It ignores and deletes the
41+
// version cache
42+
func SelfUpdate(stdOut, stdErr io.Writer) error {
43+
installScript := ""
44+
if _, err := exec.LookPath("curl"); err == nil {
45+
installScript = "curl -fsSL https://get.jetpack.io/devbox | bash"
46+
} else if _, err := exec.LookPath("wget"); err == nil {
47+
installScript = "wget -qO- https://get.jetpack.io/devbox | bash"
48+
} else {
49+
return usererr.New("curl or wget is required to update devbox. Please install either and try again.")
50+
}
51+
52+
// Delete version cache. Keep this in-sync with whatever logic is in launch.sh
53+
cacheDir := xdg.CacheSubpath("devbox")
54+
versionCacheFile := filepath.Join(cacheDir, "latest-version")
55+
_ = os.Remove(versionCacheFile)
56+
57+
cmd := exec.Command("sh", "-c", installScript)
58+
cmd.Stdout = stdOut
59+
cmd.Stderr = stdErr
60+
if err := cmd.Run(); err != nil {
61+
return errors.WithStack(err)
62+
}
63+
64+
fmt.Fprint(stdErr, "Latest version: ")
65+
exe, err := os.Executable()
66+
if err != nil {
67+
return errors.WithStack(err)
68+
}
69+
cmd = exec.Command(exe, "version")
70+
// The output of version is incidental, so just send it all to stdErr
71+
cmd.Stdout = stdErr
72+
cmd.Stderr = stdErr
73+
return errors.WithStack(cmd.Run())
74+
}

0 commit comments

Comments
 (0)