/
check.go
144 lines (125 loc) · 3.29 KB
/
check.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
144
package cmd
import (
"context"
"fmt"
"runtime"
"strings"
"sync"
"github.com/nao1215/gup/internal/goutil"
"github.com/nao1215/gup/internal/print"
"github.com/spf13/cobra"
"golang.org/x/sync/semaphore"
)
func newCheckCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "check",
Short: "Check the latest version of the binary installed by 'go install'",
Long: `Check the latest version of the binary installed by 'go install'
check subcommand checks if the binary is the latest version
and displays the name of the binary that needs to be updated.
However, do not update`,
ValidArgsFunction: completePathBinaries,
Run: func(cmd *cobra.Command, args []string) {
OsExit(check(cmd, args))
},
}
cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
if err := cmd.RegisterFlagCompletionFunc("jobs", completeNCPUs); err != nil {
panic(err)
}
return cmd
}
func check(cmd *cobra.Command, args []string) int {
if err := goutil.CanUseGoCmd(); err != nil {
print.Err(fmt.Errorf("%s: %w", "you didn't install golang", err))
return 1
}
cpus, err := cmd.Flags().GetInt("jobs")
if err != nil {
print.Err(fmt.Errorf("%s: %w", "can not parse command line argument (--jobs)", err))
return 1
}
pkgs, err := getPackageInfo()
if err != nil {
print.Err(err)
return 1
}
pkgs = extractUserSpecifyPkg(pkgs, args)
if len(pkgs) == 0 {
print.Err("unable to check package: no package information")
return 1
}
return doCheck(pkgs, cpus)
}
func doCheck(pkgs []goutil.Package, cpus int) int {
result := 0
countFmt := "[%" + pkgDigit(pkgs) + "d/%" + pkgDigit(pkgs) + "d]"
var mu sync.Mutex
needUpdatePkgs := []goutil.Package{}
print.Info("check binary under $GOPATH/bin or $GOBIN")
ch := make(chan updateResult)
weighted := semaphore.NewWeighted(int64(cpus))
checker := func(ctx context.Context, p goutil.Package, result chan updateResult) {
if err := weighted.Acquire(ctx, 1); err != nil {
r := updateResult{
pkg: p,
err: err,
}
result <- r
return
}
defer weighted.Release(1)
var err error
if p.ModulePath == "" {
err = fmt.Errorf(" %s is not installed by 'go install' (or permission incorrect)", p.Name)
} else {
var latestVer string
latestVer, err = goutil.GetLatestVer(p.ModulePath)
if err != nil {
err = fmt.Errorf(" %s %w", p.Name, err)
}
p.Version.Latest = latestVer
if !goutil.IsAlreadyUpToDate(*p.Version) {
mu.Lock()
needUpdatePkgs = append(needUpdatePkgs, p)
mu.Unlock()
}
}
r := updateResult{
pkg: p,
err: err,
}
result <- r
}
// check all package
ctx := context.Background()
for _, v := range pkgs {
go checker(ctx, v, ch)
}
// print result
for i := 0; i < len(pkgs); i++ {
v := <-ch
if v.err == nil {
print.Info(fmt.Sprintf(countFmt+" %s (%s)",
i+1, len(pkgs), v.pkg.ModulePath, v.pkg.VersionCheckResultStr()))
} else {
result = 1
print.Err(fmt.Errorf(countFmt+"%s", i+1, len(pkgs), v.err.Error()))
}
}
printUpdatablePkgInfo(needUpdatePkgs)
return result
}
func printUpdatablePkgInfo(pkgs []goutil.Package) {
if len(pkgs) == 0 {
return
}
var p string
for _, v := range pkgs {
p += v.Name + " "
}
fmt.Println("")
print.Info("If you want to update binaries, run the following command.\n" +
strings.Repeat(" ", 11) +
"$ gup update " + p)
}