/
list.go
144 lines (135 loc) · 3.7 KB
/
list.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 (
"crypto/tls"
"fmt"
"github.com/hashicorp/go-version"
"io"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/spf13/cobra"
"golang.org/x/mod/modfile"
)
func loadLocalChainsYaml() error {
// try to load a local chains.yaml, but do not panic for any error, will fall back to embedded chains.
cwd, err := os.Getwd()
if err != nil {
return err
}
chainsYamlSearchPath := filepath.Join(cwd, "chains.yaml")
err = loadChainsYaml(chainsYamlSearchPath)
if err != nil {
fmt.Printf("No config found at %s, using embedded chains. pass -f to configure chains.yaml path.\n", chainsYamlSearchPath)
return nil
}
fmt.Printf("Loaded chains from %s\n", chainsYamlSearchPath)
return nil
}
func ListCmd() *cobra.Command {
var listCmd = &cobra.Command{
Use: "list",
Short: "List the docker images. Currently only supports cosmos-based images.",
Run: func(cmd *cobra.Command, args []string) {
cmdFlags := cmd.Flags()
configFile, _ := cmdFlags.GetString(flagFile)
if configFile == "" {
if err := loadLocalChainsYaml(); err != nil {
fmt.Println(err)
}
} else {
// if flag is explicitly provided, panic on error since intent was to override embedded chains.
if err := loadChainsYaml(configFile); err != nil {
panic(err)
}
}
list()
},
}
listCmd.PersistentFlags().StringP(flagFile, "f", "", "chains.yaml config file path (searches for chains.yaml in current directory by default)")
return listCmd
}
func printError(err error) {
fmt.Printf(" error: %s\n", err)
}
func list() {
requires := []string{
"cosmos-sdk",
"ibc-go",
}
stats := map[string]map[string]int{}
for _, r := range requires {
stats[r] = map[string]int{}
}
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
for _, chain := range chains {
fmt.Printf("\n%s:\n", chain.Name)
if chain.GithubOrganization == "" || chain.GithubRepo == "" {
printError(fmt.Errorf("not enough repo info; missing organization or repo"))
continue
}
url := fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/main/go.mod",
chain.GithubOrganization, chain.GithubRepo)
resp, err := http.Get(url)
if err != nil {
printError(fmt.Errorf("GET %s: %w", url, err))
continue
}
if resp.StatusCode != http.StatusOK {
printError(fmt.Errorf("GET %s: %s", url, resp.Status))
continue
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
printError(err)
continue
}
mod, err := modfile.Parse("", body, nil)
if err != nil {
printError(fmt.Errorf("parsing go.mod: %w", err))
continue
}
newStats := 0
for _, require := range mod.Require {
for _, r := range requires {
if strings.Contains(require.Mod.Path, r) {
fmt.Printf(" %s@%s\n", r, require.Mod.Version)
v, err := version.NewVersion(require.Mod.Version)
if err != nil {
printError(fmt.Errorf("parsing module version: %w", err))
continue
}
segments := v.Segments()
majorVersion := strconv.Itoa(segments[0]) + "." + strconv.Itoa(segments[1])
if _, found := stats[r][majorVersion]; !found {
stats[r][majorVersion] = 0
}
stats[r][majorVersion]++
newStats++
}
}
}
if newStats == 0 {
printError(fmt.Errorf("no versions found"))
}
}
fmt.Printf("\nSummary:\n")
for _, r := range requires {
fmt.Printf("\n %s versions:\n", r)
total := 0
versions := make([]string, 0, len(stats[r]))
for v := range stats[r] {
versions = append(versions, v)
}
sort.Strings(versions)
for _, version := range versions {
count := stats[r][version]
fmt.Printf(" %s (%d)\n", version, count)
total += count
}
fmt.Printf(" total: %d chains\n", total)
}
}