Skip to content

Commit 6a0d57d

Browse files
defang upgrade command (#439)
* defang update command * print update instructions we decided we didn't feel comfortable with proactively trying to run other processes to update. we may revisit this in the future, but for now this is a practical compromise. * improve detection of homebrew installation * TIL: Println doesn't unescape newlines * print with term * dont print more than once * s/update/upgrade/g * mention defang upgrade in the upgrade hint --------- Co-authored-by: Jordan Stephens <[email protected]>
1 parent 5cc8798 commit 6a0d57d

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/cmd/cli/command/commands.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ func SetupCommands(version string) {
154154
tosCmd.Flags().Bool("agree-tos", false, "agree to the Defang terms of service")
155155
RootCmd.AddCommand(tosCmd)
156156

157+
// Upgrade command
158+
RootCmd.AddCommand(upgradeCmd)
159+
157160
// Token command
158161
tokenCmd.Flags().Duration("expires", 24*time.Hour, "validity duration of the token")
159162
tokenCmd.Flags().String("scope", "", fmt.Sprintf("scope of the token; one of %v (required)", scope.All())) // TODO: make it an Option
@@ -317,8 +320,8 @@ var RootCmd = &cobra.Command{
317320
version := cmd.Root().Version // HACK to avoid circular dependency with RootCmd
318321
term.Debug("Fabric:", v.Fabric, "CLI:", version, "CLI-Min:", v.CliMin)
319322
if hasTty && isNewer(version, v.CliMin) {
320-
term.Warn("Your CLI version is outdated. Please update to the latest version.")
321-
os.Setenv("DEFANG_HIDE_UPDATE", "1") // hide the update hint at the end
323+
term.Warn("Your CLI version is outdated. Please upgrade to the latest version by running:\n\ndefang upgrade")
324+
os.Setenv("DEFANG_HIDE_UPDATE", "1") // hide the upgrade hint at the end
322325
}
323326
}
324327

@@ -959,6 +962,16 @@ var tosCmd = &cobra.Command{
959962
},
960963
}
961964

965+
var upgradeCmd = &cobra.Command{
966+
Use: "upgrade",
967+
Args: cobra.NoArgs,
968+
Aliases: []string{"update"},
969+
Short: "Upgrade the Defang CLI to the latest version",
970+
RunE: func(cmd *cobra.Command, args []string) error {
971+
return cli.Upgrade(cmd.Context())
972+
},
973+
}
974+
962975
func configureLoader(cmd *cobra.Command) compose.Loader {
963976
f := cmd.Flags()
964977
o := compose.LoaderOptions{}

src/pkg/cli/upgrade.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/exec"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/DefangLabs/defang/src/pkg/term"
11+
)
12+
13+
func Upgrade(ctx context.Context) error {
14+
// Find path to the current executable to determine how to upgrade
15+
ex, err := os.Executable()
16+
if err != nil {
17+
return err
18+
}
19+
term.Debugf(" - Executable: %s\n", ex)
20+
21+
ex, err = filepath.EvalSymlinks(ex)
22+
if err != nil {
23+
return err
24+
}
25+
term.Debugf(" - Evaluated: %s\n", ex)
26+
27+
if strings.HasPrefix(ex, homebrewPrefix(ctx)) {
28+
printInstructions("brew upgrade defang")
29+
return nil
30+
}
31+
32+
if strings.HasPrefix(ex, "/nix/store/") {
33+
// Detect whether the user has used Flakes or nix-env
34+
if strings.Contains("-defang-cli-", ex) {
35+
printInstructions("nix-env -if https://github.com/DefangLabs/defang/archive/main.tar.gz")
36+
} else {
37+
printInstructions("nix profile install github:DefangLabs/defang#defang-bin --refresh")
38+
}
39+
return nil
40+
}
41+
42+
// Check if we're running in PowerShell
43+
if _, exists := os.LookupEnv("PSModulePath"); exists {
44+
printInstructions(`pwsh -c "iwr https://s.defang.io/defang_win_amd64.zip -OutFile defang.zip"`)
45+
46+
return nil
47+
}
48+
49+
// Default to the shell script
50+
printInstructions(`. <(curl -Ls https://s.defang.io/install)`)
51+
52+
return nil
53+
}
54+
55+
func homebrewPrefix(ctx context.Context) string {
56+
output, err := exec.CommandContext(ctx, "brew", "config").Output()
57+
if err != nil {
58+
return ""
59+
}
60+
homebrewPrefix := ""
61+
// filter out the line which includes HOMEBREW_PREFIX
62+
for _, line := range strings.Split(string(output), "\n") {
63+
config_key := "HOMEBREW_PREFIX: "
64+
if strings.HasPrefix(line, config_key) {
65+
// remove the prefix from the line
66+
homebrewPrefix = strings.TrimPrefix(line, config_key)
67+
break
68+
}
69+
}
70+
return homebrewPrefix
71+
}
72+
73+
func printInstructions(cmd string) {
74+
term.Info("To upgrade defang, run the following command:\n\n", cmd)
75+
}

0 commit comments

Comments
 (0)