-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgotoolchain.go
148 lines (131 loc) · 3.85 KB
/
gotoolchain.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
145
146
147
148
package main
import (
"fmt"
"os"
"path"
"strings"
"syscall"
"github.com/mjl-/goreleases"
)
func installGoToolchain(file goreleases.File, shortname string) error {
if config.GoToolchainDir == "" {
return fmt.Errorf("go toolchain dir not configured")
}
if !validGoversion(file.Version) {
return fmt.Errorf("bad goversion")
}
perms, err := makeGoreleasesPermissions()
if err != nil {
return err
}
tmpdir, err := os.MkdirTemp(config.GoToolchainDir, "tmp-"+file.Version)
if err != nil {
return fmt.Errorf("creating temp dir for downloading")
}
defer func() {
// Dir will be empty on success: the go directory will have been moved to the go toolchain dir.
os.RemoveAll(tmpdir)
}()
err = goreleases.Fetch(file, tmpdir, perms)
if err != nil {
return fmt.Errorf("fetching toolchain from golang.org/dl/: %v", err)
}
versionDst := path.Join(config.GoToolchainDir, file.Version)
err = os.Rename(path.Join(tmpdir, "go"), versionDst)
if err != nil {
return fmt.Errorf("moving from tmp dir to final destination: %v", err)
}
switch shortname {
case "go", "go-prev":
err := makeToolchainSymlink(file.Version, shortname, perms)
if err != nil {
return fmt.Errorf("activating toolchain under shortname: %v", err)
}
case "":
default:
return fmt.Errorf("invalid shortname")
}
return nil
}
func validGoversion(goversion string) bool {
if !strings.HasPrefix(goversion, "go") || strings.Contains(goversion, "/") || strings.Contains(goversion, "..") || strings.Contains(goversion, "\\") {
return false
}
return true
}
func makeGoreleasesPermissions() (*goreleases.Permissions, error) {
if !config.IsolateBuilds.Enabled {
return nil, nil
}
fi, err := os.Stat(config.GoToolchainDir)
if err != nil {
return nil, fmt.Errorf("state on go toolchain dir: %v", err)
}
st, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return nil, fmt.Errorf("cannot find uid/gid of go toolchain dir due to stat")
}
perms := &goreleases.Permissions{
Uid: int(st.Uid),
Gid: int(st.Gid),
Mode: fi.Mode() &^ os.ModeType,
}
return perms, nil
}
func removeGoToolchain(goversion string) error {
// Verify sanity of request.
if config.GoToolchainDir == "" {
return fmt.Errorf("go toolchain dir not configured")
}
if !validGoversion(goversion) {
return fmt.Errorf("bad goversion")
}
// Return helpful error diagnostic when toolchain isn't there.
_, err := os.Stat(path.Join(config.GoToolchainDir, goversion))
if err != nil && os.IsNotExist(err) {
return fmt.Errorf("version is not installed")
}
return os.RemoveAll(path.Join(config.GoToolchainDir, goversion))
}
func activateGoToolchain(goversion, shortname string) error {
// Verify sanity of request.
if config.GoToolchainDir == "" {
return fmt.Errorf("go toolchain dir not configured")
}
if !validGoversion(goversion) {
return fmt.Errorf("bad goversion")
}
switch shortname {
case "go", "go-prev":
default:
return fmt.Errorf("bad shortname")
}
// Ensure requested toolchain is present.
_, err := os.Stat(path.Join(config.GoToolchainDir, goversion))
if err != nil {
return fmt.Errorf("stat on requested toolchain: %v", err)
}
// Make the symlink.
perms, err := makeGoreleasesPermissions()
if err != nil {
return err
}
return makeToolchainSymlink(goversion, shortname, perms)
}
func makeToolchainSymlink(goversion, shortname string, perms *goreleases.Permissions) error {
// Ignore error for removal, there may not be any active toolchain, that's fine.
shortpath := path.Join(config.GoToolchainDir, shortname)
os.Remove(shortpath)
// Make the symlink, and set permissions.
err := os.Symlink(goversion, shortpath)
if err != nil {
return fmt.Errorf("creating symlink for toolchain to new version: %v", err)
}
if perms != nil {
err = os.Lchown(shortpath, perms.Uid, perms.Gid)
if err != nil {
return fmt.Errorf("chown on symlink for toolchain to new version: %v", err)
}
}
return nil
}