Skip to content

Commit c045822

Browse files
matloobprattmic
authored andcommitted
[release-branch.go1.19] cmd/go: do not exit with non-zero code from go list -e -export
go list -e -export puts errors running build actions on the load.Package corresponding to the failed action rather than exiting with a non zero exit code. Fixes #60710. Fixes #60650. Updates #25842. Change-Id: I1fea85cc5a0557f514fe9d4ed3b6a858376fdcde Reviewed-on: https://go-review.googlesource.com/c/go/+/437298 Run-TryBot: Bryan Mills <[email protected]> Reviewed-by: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Bryan Mills <[email protected]> Reviewed-by: Michael Matloob <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/502195 TryBot-Bypass: Bryan Mills <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 0b0f86e commit c045822

File tree

6 files changed

+87
-44
lines changed

6 files changed

+87
-44
lines changed

src/cmd/go/internal/list/list.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,9 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
690690
needStale := (listJson && listJsonFields.needAny("Stale", "StaleReason")) || strings.Contains(*listFmt, ".Stale")
691691
if needStale || *listExport || *listCompiled {
692692
b := work.NewBuilder("")
693+
if *listE {
694+
b.AllowErrors = true
695+
}
693696
b.IsCmdList = true
694697
b.NeedExport = *listExport
695698
b.NeedCompiledGoFiles = *listCompiled

src/cmd/go/internal/work/action.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type Builder struct {
4343
NeedError bool // list needs p.Error
4444
NeedExport bool // list needs p.Export
4545
NeedCompiledGoFiles bool // list needs p.CompiledGoFiles
46+
AllowErrors bool // errors don't immediately exit the program
4647

4748
objdirSeq int // counter for NewObjdir
4849
pkgSeq int

src/cmd/go/internal/work/exec.go

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,10 @@ func (b *Builder) Do(ctx context.Context, root *Action) {
149149
defer b.exec.Unlock()
150150

151151
if err != nil {
152-
if err == errPrintedOutput {
153-
base.SetExitStatus(2)
152+
if b.AllowErrors {
153+
if a.Package.Error == nil {
154+
a.Package.Error = &load.PackageError{Err: err}
155+
}
154156
} else {
155157
base.Errorf("%s", err)
156158
}
@@ -508,8 +510,8 @@ func (b *Builder) build(ctx context.Context, a *Action) (err error) {
508510
}
509511

510512
defer func() {
511-
if err != nil && err != errPrintedOutput {
512-
err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
513+
if err != nil {
514+
err = fmt.Errorf("go build %s: %v", p.ImportPath, err)
513515
}
514516
if err != nil && b.IsCmdList && b.NeedError && p.Error == nil {
515517
p.Error = &load.PackageError{Err: err}
@@ -821,9 +823,11 @@ OverlayLoop:
821823
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
822824
output += "note: module requires Go " + p.Module.GoVersion + "\n"
823825
}
824-
b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
826+
825827
if err != nil {
826-
return errPrintedOutput
828+
return errors.New(fmt.Sprint(formatOutput(b.WorkDir, p.Dir, p.Desc(), output)))
829+
} else {
830+
b.showOutput(a, p.Dir, p.Desc(), output)
827831
}
828832
}
829833
if err != nil {
@@ -1502,9 +1506,8 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
15021506
var out []byte
15031507
out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
15041508
if err != nil {
1505-
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1506-
b.Print(err.Error() + "\n")
1507-
return nil, nil, errPrintedOutput
1509+
prefix, suffix := formatOutput(b.WorkDir, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1510+
return nil, nil, errors.New(fmt.Sprint(prefix, suffix+err.Error()))
15081511
}
15091512
if len(out) > 0 {
15101513
cflags, err = splitPkgConfigOutput(out)
@@ -1517,9 +1520,8 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
15171520
}
15181521
out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
15191522
if err != nil {
1520-
b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1521-
b.Print(err.Error() + "\n")
1522-
return nil, nil, errPrintedOutput
1523+
prefix, suffix := formatOutput(b.WorkDir, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1524+
return nil, nil, errors.New(fmt.Sprint(prefix, suffix+err.Error()))
15231525
}
15241526
if len(out) > 0 {
15251527
// NOTE: we don't attempt to parse quotes and unescapes here. pkg-config
@@ -1611,7 +1613,7 @@ func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) {
16111613
// BuildInstallFunc is the action for installing a single package or executable.
16121614
func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) {
16131615
defer func() {
1614-
if err != nil && err != errPrintedOutput {
1616+
if err != nil {
16151617
// a.Package == nil is possible for the go install -buildmode=shared
16161618
// action that installs libmangledname.so, which corresponds to
16171619
// a list of packages, not just one.
@@ -2015,15 +2017,7 @@ func (b *Builder) Showcmd(dir string, format string, args ...any) {
20152017
// If a is not nil and a.output is not nil, showOutput appends to that slice instead of
20162018
// printing to b.Print.
20172019
func (b *Builder) showOutput(a *Action, dir, desc, out string) {
2018-
prefix := "# " + desc
2019-
suffix := "\n" + out
2020-
if reldir := base.ShortPath(dir); reldir != dir {
2021-
suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir)
2022-
suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir)
2023-
suffix = strings.ReplaceAll(suffix, "\n\t"+dir, "\n\t"+reldir)
2024-
}
2025-
suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK")
2026-
2020+
prefix, suffix := formatOutput(b.WorkDir, dir, desc, out)
20272021
if a != nil && a.output != nil {
20282022
a.output = append(a.output, prefix...)
20292023
a.output = append(a.output, suffix...)
@@ -2035,12 +2029,41 @@ func (b *Builder) showOutput(a *Action, dir, desc, out string) {
20352029
b.Print(prefix, suffix)
20362030
}
20372031

2038-
// errPrintedOutput is a special error indicating that a command failed
2039-
// but that it generated output as well, and that output has already
2040-
// been printed, so there's no point showing 'exit status 1' or whatever
2041-
// the wait status was. The main executor, builder.do, knows not to
2042-
// print this error.
2043-
var errPrintedOutput = errors.New("already printed output - no need to show error")
2032+
// formatOutput prints "# desc" followed by the given output.
2033+
// The output is expected to contain references to 'dir', usually
2034+
// the source directory for the package that has failed to build.
2035+
// formatOutput rewrites mentions of dir with a relative path to dir
2036+
// when the relative path is shorter. This is usually more pleasant.
2037+
// For example, if fmt doesn't compile and we are in src/html,
2038+
// the output is
2039+
//
2040+
// $ go build
2041+
// # fmt
2042+
// ../fmt/print.go:1090: undefined: asdf
2043+
// $
2044+
//
2045+
// instead of
2046+
//
2047+
// $ go build
2048+
// # fmt
2049+
// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
2050+
// $
2051+
//
2052+
// formatOutput also replaces references to the work directory with $WORK.
2053+
// formatOutput returns the output in a prefix with the description and a
2054+
// suffix with the actual output.
2055+
func formatOutput(workDir, dir, desc, out string) (prefix, suffix string) {
2056+
prefix = "# " + desc
2057+
suffix = "\n" + out
2058+
if reldir := base.ShortPath(dir); reldir != dir {
2059+
suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir)
2060+
suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir)
2061+
suffix = strings.ReplaceAll(suffix, "\n\t"+dir, "\n\t"+reldir)
2062+
}
2063+
suffix = strings.ReplaceAll(suffix, " "+workDir, " $WORK")
2064+
2065+
return prefix, suffix
2066+
}
20442067

20452068
var cgoLine = lazyregexp.New(`\[[^\[\]]+\.(cgo1|cover)\.go:[0-9]+(:[0-9]+)?\]`)
20462069
var cgoTypeSigRe = lazyregexp.New(`\b_C2?(type|func|var|macro)_\B`)
@@ -2054,9 +2077,10 @@ func (b *Builder) run(a *Action, dir string, desc string, env []string, cmdargs
20542077
if desc == "" {
20552078
desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " "))
20562079
}
2057-
b.showOutput(a, dir, desc, b.processOutput(out))
20582080
if err != nil {
2059-
err = errPrintedOutput
2081+
err = errors.New(fmt.Sprint(formatOutput(b.WorkDir, dir, desc, b.processOutput(out))))
2082+
} else {
2083+
b.showOutput(a, dir, desc, b.processOutput(out))
20602084
}
20612085
}
20622086
return err
@@ -2400,11 +2424,10 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
24002424
}
24012425
}
24022426

2403-
b.showOutput(a, p.Dir, desc, b.processOutput(output))
2404-
if err != nil {
2405-
err = errPrintedOutput
2406-
} else if os.Getenv("GO_BUILDER_NAME") != "" {
2407-
return errors.New("C compiler warning promoted to error on Go builders")
2427+
if err != nil || os.Getenv("GO_BUILDER_NAME") != "" {
2428+
err = errors.New(fmt.Sprintf(formatOutput(b.WorkDir, p.Dir, desc, b.processOutput(output))))
2429+
} else {
2430+
b.showOutput(a, p.Dir, desc, b.processOutput(output))
24082431
}
24092432
}
24102433
return err
@@ -3358,8 +3381,8 @@ func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFL
33583381
if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
33593382
return "", "", errors.New("must have SWIG version >= 3.0.6")
33603383
}
3361-
b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out)) // swig error
3362-
return "", "", errPrintedOutput
3384+
// swig error
3385+
return "", "", errors.New(fmt.Sprint(formatOutput(b.WorkDir, p.Dir, p.Desc(), b.processOutput(out))))
33633386
}
33643387
return "", "", err
33653388
}

src/cmd/go/internal/work/gc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package work
77
import (
88
"bufio"
99
"bytes"
10+
"errors"
1011
"fmt"
1112
"io"
1213
"log"
@@ -502,8 +503,7 @@ func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) er
502503
return nil
503504
}
504505
if err := packInternal(absAfile, absOfiles); err != nil {
505-
b.showOutput(a, p.Dir, p.Desc(), err.Error()+"\n")
506-
return errPrintedOutput
506+
return errors.New(fmt.Sprint(formatOutput(b.WorkDir, p.Dir, p.Desc(), err.Error()+"\n")))
507507
}
508508
return nil
509509
}

src/cmd/go/testdata/script/build_cwd_newline.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,9 @@ stderr 'package example: invalid package directory .*uh-oh'
3535
[!cgo] ! go test -v main_nocgo.go main_test.go
3636
stderr 'package command-line-arguments: invalid package directory .*uh-oh'
3737

38-
# Note: this command fails on release-branch.go1.19 but succeeds
39-
# on release-branch.go1.20 and later. I (bcmills) suspect it may
40-
# have been fixed by CL 437298.
41-
! go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' .
42-
stderr 'package example: invalid package directory .*uh-oh'
38+
go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' .
4339
! stdout .
40+
! stderr .
4441
! exists obj_
4542

4643
# The cgo tool should only accept the source file if the working directory
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
go list -e -export ./...
2+
! stderr '.'
3+
go list -e -export -json ...
4+
5+
-- go.mod --
6+
module example.com
7+
-- p1/p1.go --
8+
package p1
9+
10+
const Name = "p1"
11+
-- p2/main.go --
12+
package main
13+
14+
import "fmt"
15+
import "example.com/p1"
16+
17+
func main() {
18+
fmt.Println(p1.Name == 5)
19+
}

0 commit comments

Comments
 (0)