/
self-update.go
143 lines (119 loc) · 3.38 KB
/
self-update.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"runtime"
"github.com/AlecAivazis/survey/v2"
"github.com/b4b4r07/afx/pkg/errors"
"github.com/b4b4r07/afx/pkg/github"
"github.com/b4b4r07/afx/pkg/helpers/templates"
"github.com/creativeprojects/go-selfupdate"
"github.com/fatih/color"
"github.com/spf13/cobra"
)
type selfUpdateCmd struct {
metaCmd
opt selfUpdateOpt
annotation map[string]string
}
type selfUpdateOpt struct {
tag bool
}
var (
// selfUpdateLong is long description of self-update command
selfUpdateLong = templates.LongDesc(`
self-update requires afx is pre-compiled one to upgrade.
Those who built afx by go install etc cannot use this feature.
(afx --version returns unset/unset)
`)
// selfUpdateExample is examples for selfUpdate command
selfUpdateExample = templates.Examples(`
# upgrade afx to latest version
$ afx self-update
`)
)
// newSelfUpdateCmd creates a new selfUpdate command
func (m metaCmd) newSelfUpdateCmd() *cobra.Command {
info := color.New(color.FgGreen).SprintFunc()
c := &selfUpdateCmd{
metaCmd: m,
annotation: map[string]string{
"0.1.11": info(`Run "afx state refresh --force" at first!`),
},
}
selfUpdateCmd := &cobra.Command{
Use: "self-update",
Short: "Update afx itself to latest version",
Long: selfUpdateLong,
Example: selfUpdateExample,
DisableFlagsInUseLine: true,
SilenceUsage: true,
SilenceErrors: true,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
m.env.AskWhen(map[string]bool{
"GITHUB_TOKEN": true,
})
return c.run(args)
},
}
return selfUpdateCmd
}
func (c *selfUpdateCmd) run(args []string) error {
switch Version {
case "unset":
fmt.Fprintf(os.Stderr, "%s\n\n %s\n %s\n\n",
"Failed to update to new version!",
"You need to get precompiled version from GitHub releases.",
fmt.Sprintf("This version (%s/%s) is compiled from source code.",
Version, runtime.Version()),
)
return errors.New("failed to run self-update")
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
latest, found, err := selfupdate.DetectLatest(ctx, selfupdate.ParseSlug(Repository))
if err != nil {
return errors.Wrap(err, "error occurred while detecting version")
}
if !found {
return fmt.Errorf("latest version for %s/%s could not be found from GitHub repository",
runtime.GOOS, runtime.GOARCH)
}
if latest.LessOrEqual(Version) {
fmt.Printf("Current version (%s) is the latest\n", Version)
return nil
}
yes := false
if err := survey.AskOne(&survey.Confirm{
Message: fmt.Sprintf("Do you update to %s? (current version: %s)",
latest.Version(), Version),
}, &yes); err != nil {
return errors.Wrap(err, "cannot get answer from console")
}
if !yes {
return nil
}
release, err := github.NewRelease(ctx, "b4b4r07", "afx", "v"+latest.Version(), github.WithVerbose())
if err != nil {
return err
}
asset, err := release.Download(ctx)
if err != nil {
return err
}
if err := release.Unarchive(asset); err != nil {
return err
}
exe, err := os.Executable()
if err != nil {
return errors.New("could not locate executable path")
}
if err := release.Install(exe); err != nil {
return err
}
color.New(color.FgWhite).Printf("Successfully updated to version %s\n", latest.Version())
return nil
}