Skip to content

Commit 82cabb4

Browse files
authored
Fix GOROOT mismatch issues (ko-build#303)
Print a warning if GOROOT is unset and ko's default build context differs from $(go env GOROOT) and use the result of $(go env GOROOT).
1 parent 3c21033 commit 82cabb4

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

pkg/build/gobuild.go

+50-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ import (
4343
const (
4444
appDir = "/ko-app"
4545
defaultAppFilename = "ko-app"
46+
47+
gorootWarningTemplate = `NOTICE!
48+
-----------------------------------------------------------------
49+
ko and go have mismatched GOROOT:
50+
go/build.Default.GOROOT = %q
51+
$(go env GOROOT) = %q
52+
53+
Inferring GOROOT=%q
54+
55+
Run this to remove this warning:
56+
export GOROOT=$(go env GOROOT)
57+
58+
For more information see:
59+
https://github.com/google/ko/issues/106
60+
-----------------------------------------------------------------
61+
`
4662
)
4763

4864
// GetBase takes an importpath and returns a base image.
@@ -158,26 +174,59 @@ func moduleInfo(ctx context.Context) (*modules, error) {
158174
return &modules, nil
159175
}
160176

177+
// getGoroot shells out to `go env GOROOT` to determine
178+
// the GOROOT for the installed version of go so that we
179+
// can set it in our buildContext. By default, the GOROOT
180+
// of our buildContext is set to the GOROOT at install
181+
// time for `ko`, which means that we break when certain
182+
// package managers update go or when using a pre-built
183+
// `ko` binary that expects a different GOROOT.
184+
//
185+
// See https://github.com/google/ko/issues/106
186+
func getGoroot(ctx context.Context) (string, error) {
187+
output, err := exec.CommandContext(ctx, "go", "env", "GOROOT").Output()
188+
return strings.TrimSpace(string(output)), err
189+
}
190+
161191
// NewGo returns a build.Interface implementation that:
162192
// 1. builds go binaries named by importpath,
163193
// 2. containerizes the binary on a suitable base,
164194
func NewGo(ctx context.Context, options ...Option) (Interface, error) {
195+
// TODO: We could do moduleInfo() and getGoroot() concurrently.
165196
module, err := moduleInfo(ctx)
166197
if err != nil {
167198
return nil, err
168199
}
169200

201+
goroot, err := getGoroot(ctx)
202+
if err != nil {
203+
// On error, print the output and set goroot to "" to avoid using it later.
204+
log.Printf("Unexpected error running \"go env GOROOT\": %v\n%v", err, goroot)
205+
goroot = ""
206+
} else if goroot == "" {
207+
log.Printf(`Unexpected: $(go env GOROOT) == ""`)
208+
}
209+
210+
// If $(go env GOROOT) successfully returns a non-empty string that differs from
211+
// the default build context GOROOT, print a warning and use $(go env GOROOT).
212+
bc := gb.Default
213+
if goroot != "" && bc.GOROOT != goroot {
214+
log.Printf(gorootWarningTemplate, bc.GOROOT, goroot, goroot)
215+
bc.GOROOT = goroot
216+
}
217+
170218
gbo := &gobuildOpener{
171219
build: build,
172220
mod: module,
173-
buildContext: &gb.Default,
221+
buildContext: &bc,
174222
}
175223

176224
for _, option := range options {
177225
if err := option(gbo); err != nil {
178226
return nil, err
179227
}
180228
}
229+
181230
return gbo.Open()
182231
}
183232

0 commit comments

Comments
 (0)