1
2
3
4
5 package modfetch
6
7 import (
8 "context"
9 "fmt"
10 "io"
11 "sort"
12 "strings"
13
14 "cmd/go/internal/gover"
15 "cmd/go/internal/modfetch/codehost"
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29
30 type toolchainRepo struct {
31 path string
32 repo Repo
33 }
34
35 func (r *toolchainRepo) ModulePath() string {
36 return r.path
37 }
38
39 func (r *toolchainRepo) Versions(ctx context.Context, prefix string) (*Versions, error) {
40
41 versions, err := r.repo.Versions(ctx, "")
42 if err != nil {
43 return nil, err
44 }
45 versions.Origin = nil
46 var list []string
47 have := make(map[string]bool)
48 goPrefix := ""
49 if r.path == "toolchain" {
50 goPrefix = "go"
51 }
52 for _, v := range versions.List {
53 v, ok := dlToGo(v)
54 if !ok {
55 continue
56 }
57 if !have[v] {
58 have[v] = true
59 list = append(list, goPrefix+v)
60 }
61 }
62
63
64
65
66
67
68 if v := gover.Local(); !have[v] {
69 list = append(list, goPrefix+v)
70 }
71
72 if r.path == "go" {
73 sort.Slice(list, func(i, j int) bool {
74 return gover.Compare(list[i], list[j]) < 0
75 })
76 } else {
77 sort.Slice(list, func(i, j int) bool {
78 return gover.Compare(gover.FromToolchain(list[i]), gover.FromToolchain(list[j])) < 0
79 })
80 }
81 versions.List = list
82 return versions, nil
83 }
84
85 func (r *toolchainRepo) Stat(ctx context.Context, rev string) (*RevInfo, error) {
86
87
88
89
90
91 prefix := ""
92 v := rev
93 v = strings.TrimPrefix(v, "go")
94 if r.path == "toolchain" {
95 prefix = "go"
96 }
97
98 if !gover.IsValid(v) {
99 return nil, fmt.Errorf("invalid %s version %s", r.path, rev)
100 }
101
102
103
104
105 if r.path == "go" && gover.Compare(v, gover.Local()) <= 0 {
106 return &RevInfo{Version: prefix + v}, nil
107 }
108
109
110
111 if r.path == "toolchain" && v == gover.Local() {
112 return &RevInfo{Version: prefix + v}, nil
113 }
114
115 if gover.IsLang(v) {
116
117
118 return nil, fmt.Errorf("go language version %s is not a toolchain version", rev)
119 }
120
121
122
123
124
125
126 info, err := r.repo.Stat(ctx, goToDL(v, "linux", "amd64"))
127 if err != nil {
128 return nil, err
129 }
130
131
132
133 return &RevInfo{Version: prefix + v, Time: info.Time}, nil
134 }
135
136 func (r *toolchainRepo) Latest(ctx context.Context) (*RevInfo, error) {
137 versions, err := r.Versions(ctx, "")
138 if err != nil {
139 return nil, err
140 }
141 var max string
142 for _, v := range versions.List {
143 if max == "" || gover.ModCompare(r.path, v, max) > 0 {
144 max = v
145 }
146 }
147 return r.Stat(ctx, max)
148 }
149
150 func (r *toolchainRepo) GoMod(ctx context.Context, version string) (data []byte, err error) {
151 return []byte("module " + r.path + "\n"), nil
152 }
153
154 func (r *toolchainRepo) Zip(ctx context.Context, dst io.Writer, version string) error {
155 return fmt.Errorf("invalid use of toolchainRepo: Zip")
156 }
157
158 func (r *toolchainRepo) CheckReuse(ctx context.Context, old *codehost.Origin) error {
159 return fmt.Errorf("invalid use of toolchainRepo: CheckReuse")
160 }
161
162
163 func goToDL(v, goos, goarch string) string {
164 return "v0.0.1-go" + v + ".linux-amd64"
165 }
166
167
168 func dlToGo(v string) (string, bool) {
169
170
171 _, v, ok := strings.Cut(v, "-")
172 if !ok {
173 return "", false
174 }
175
176 i := strings.LastIndex(v, ".")
177 if i < 0 || !strings.Contains(v[i+1:], "-") {
178 return "", false
179 }
180 return strings.TrimPrefix(v[:i], "go"), true
181 }
182
View as plain text