"log"
"os"
"os/exec"
+ "reflect"
"strings"
"sync"
}
}
+func Error(err error) {
+ // We use errors.Join to return multiple errors from various routines.
+ // If we receive multiple errors joined with a basic errors.Join,
+ // handle each one separately so that they all have the leading "go: " prefix.
+ // A plain interface check is not good enough because there might be
+ // other kinds of structured errors that are logically one unit and that
+ // add other context: only handling the wrapped errors would lose
+ // that context.
+ if err != nil && reflect.TypeOf(err).String() == "*errors.joinError" {
+ for _, e := range err.(interface{ Unwrap() []error }).Unwrap() {
+ Error(e)
+ }
+ return
+ }
+ Errorf("go: %v", err)
+}
+
+func Fatal(err error) {
+ Error(err)
+ Exit()
+}
+
var exitStatus = 0
var exitMu sync.Mutex
// This also mimics what os.RemoveAll(dir) would do.
if err := os.RemoveAll(d); err != nil && !printedErrors {
printedErrors = true
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
}
if !cfg.BuildN {
if err := os.RemoveAll(logFile); err != nil && !printedErrors {
printedErrors = true
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
}
}
if err != nil {
if _, statErr := os.Stat(dir); !os.IsNotExist(statErr) {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
}
}
if !cfg.BuildN {
if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
}
}
if !cfg.BuildN {
if err := os.RemoveAll(fuzzDir); err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
}
}
}
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
continue
return
}
}
- base.Errorf("go: %v", err)
+ base.Error(err)
}
b := work.NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
buildcfg.Check()
if cfg.ExperimentErr != nil {
- base.Fatalf("go: %v", cfg.ExperimentErr)
+ base.Fatal(cfg.ExperimentErr)
}
for _, arg := range args {
env = append(env, ExtraEnvVars()...)
if err := fsys.Init(base.Cwd()); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
base.Fatalf("go: arguments must be KEY=VALUE: invalid argument: %s", arg)
}
if err := checkEnvWrite(key, val); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if _, ok := add[key]; ok {
base.Fatalf("go: multiple values for key: %s", key)
}
if err := checkBuildConfig(add, nil); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
gotmp, okGOTMP := add["GOTMPDIR"]
del := make(map[string]bool)
for _, arg := range args {
if err := checkEnvWrite(arg, ""); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
del[arg] = true
}
if err := checkBuildConfig(nil, del); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
updateEnvFile(nil, del)
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"os"
if !*listE {
for _, m := range mods {
if m.Error != nil {
- base.Errorf("go: %v", m.Error.Err)
+ base.Error(errors.New(m.Error.Err))
}
}
if err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
base.ExitIfErrors()
}
}
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
}
rmods, err := modload.ListModules(ctx, args, mode, *listReuse)
if err != nil && !*listE {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
for i, arg := range args {
rmod := rmods[i]
data.p, data.err = rp.Import(cfg.BuildContext, buildMode)
goto Happy
} else if !errors.Is(err, modindex.ErrNotIndexed) {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
data.p, data.err = buildContext.ImportDir(r.dir, buildMode)
import (
"context"
"encoding/json"
+ "errors"
"os"
"runtime"
// 'go mod graph', and similar commands.
_, err := modload.LoadModGraph(ctx, "")
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
for _, m := range modFile.Require {
// be updated after loading the build list. This may require setting
// the mode to "mod" or "readonly" depending on haveExplicitArgs.
if err := modload.WriteGoMod(ctx, modload.WriteOpts{}); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
for _, m := range mods {
b, err := json.MarshalIndent(m, "", "\t")
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
os.Stdout.Write(append(b, '\n'))
if m.Error != "" {
} else {
for _, m := range mods {
if m.Error != "" {
- base.Errorf("go: %v", m.Error)
+ base.Error(errors.New(m.Error))
}
}
base.ExitIfErrors()
// workspace mode; see comment above.
if haveExplicitArgs || modload.WorkFilePath() != "" {
if err := modload.WriteGoMod(ctx, modload.WriteOpts{}); err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
// (after we've written the checksums for the modules that were downloaded
// successfully).
if infosErr != nil {
- base.Errorf("go: %v", infosErr)
+ base.Error(infosErr)
}
}
data, err := lockedfile.Read(gomod)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
modFile, err := modfile.Parse(gomod, data, nil)
out, err := modFile.Format()
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if *editPrint {
return out, nil
})
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
goVersion := graphGo.String()
if goVersion != "" && gover.Compare(gover.Local(), goVersion) < 0 {
toolchain.TryVersion(ctx, goVersion)
- base.Fatalf("go: %v", &gover.TooNewError{
+ base.Fatal(&gover.TooNewError{
What: "-go flag",
GoVersion: goVersion,
})
mg, err := modload.LoadModGraph(ctx, goVersion)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
w := bufio.NewWriter(os.Stdout)
vdir = filepath.Join(modload.VendorDir())
}
if err := os.RemoveAll(vdir); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
modpkgs := make(map[module.Version][]string)
}
if err := os.MkdirAll(vdir, 0777); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if err := os.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
for _, embed := range embeds {
embedDst := filepath.Join(dst, embed)
// Copy the file as is done by copyDir below.
r, err := os.Open(filepath.Join(src, embed))
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
w, err := os.Create(embedDst)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if _, err := io.Copy(w, r); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
r.Close()
if err := w.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
}
if strings.HasSuffix(info.Name(), ".go") {
f, err := fsys.Open(filepath.Join(dir, info.Name()))
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
defer f.Close()
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) {
files, err := os.ReadDir(src)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if err := os.MkdirAll(dst, 0777); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
for _, file := range files {
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
copiedFiles[file.Name()] = true
r, err := os.Open(filepath.Join(src, file.Name()))
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
dstPath := filepath.Join(dst, file.Name())
copiedFiles[dstPath] = true
w, err := os.Create(dstPath)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if _, err := io.Copy(w, r); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
r.Close()
if err := w.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
}
mg, err := modload.LoadModGraph(ctx, "")
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
mods := mg.BuildList()[modload.MainModules.Len():]
// Use a slice of result channels, so that the output is deterministic.
mods, err := modload.ListModules(ctx, args, 0, "")
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
byModule := make(map[string][]string)
return "", ErrToolchain
}
if err := checkCacheDir(ctx); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
// The par.Cache here avoids duplicate work.
// TODO(bcmills): modload.EditBuildList should catch this instead.
toolchain.TryVersion(ctx, tooNew.GoVersion)
}
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
newReqs := reqsFromGoMod(modload.ModFile())
for _, arg := range search.CleanPatterns(rawArgs) {
q, err := newQuery(arg)
if err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
continue
}
if tooNew := (*gover.TooNewError)(nil); errors.As(err, &tooNew) {
toolchain.TryVersion(ctx, tooNew.GoVersion)
}
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
buildList := mg.BuildList()
var tentative []module.Version
for _, cs := range upgrades {
if cs.err != nil {
- base.Errorf("go: %v", cs.err)
+ base.Error(cs.err)
continue
}
}
for _, err := range sumErrs {
if err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
}
base.ExitIfErrors()
if err != nil {
if tooNew := (*gover.TooNewError)(nil); errors.As(err, &tooNew) {
toolchain.TryVersion(ctx, tooNew.GoVersion)
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
var constraint *modload.ConstraintError
if !errors.As(err, &constraint) {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
if cfg.BuildV {
if tooNew := (*gover.TooNewError)(nil); errors.As(err, &tooNew) {
toolchain.TryVersion(ctx, tooNew.GoVersion)
}
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
r.buildList = mg.BuildList()
if !ok {
mg, err := rs.Graph(ctx)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
v = mg.Selected(path)
}
}
}
if inconsistent {
- base.Fatalf("go: %v", errGoModDirty)
+ base.Fatal(errGoModDirty)
}
// Now we can treat the rest of the module graph as effectively “pruned
}
if err := fsys.Init(base.Cwd()); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
// Disable any prompting for passwords by Git.
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
}
if RootMode == NeedRoot {
- base.Fatalf("go: %v", ErrNoModRoot)
+ base.Fatal(ErrNoModRoot)
}
if !mustUseModules {
// GO111MODULE is 'auto', and we can't find a module root.
}
base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd)
}
- base.Fatalf("go: %v", ErrNoModRoot)
+ base.Fatal(ErrNoModRoot)
}
var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'")
return nil, err
}
if f.Go != nil && gover.Compare(f.Go.Version, gover.Local()) > 0 && cfg.CmdName != "work edit" {
- base.Fatalf("go: %v", &gover.TooNewError{What: base.ShortPath(path), GoVersion: f.Go.Version})
+ base.Fatal(&gover.TooNewError{What: base.ShortPath(path), GoVersion: f.Go.Version})
}
return f, nil
}
var err error
rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
var err error
rs, err = convertPruning(ctx, rs, pruned)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
} else {
var err error
modPath, err = findModulePath(modRoot)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
} else if err := module.CheckImportPath(modPath); err != nil {
if pathErr, ok := err.(*module.InvalidPathError); ok {
pathErr.Err = errors.New("is a local import path")
}
}
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
} else if _, _, ok := module.SplitPathVersion(modPath); !ok {
if strings.HasPrefix(modPath, "gopkg.in/") {
invalidMajorVersionMsg := fmt.Errorf("module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\n\tgo mod init %s", suggestGopkgIn(modPath))
fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(convertedFrom))
}
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
rs := requirementsFromModFiles(ctx, nil, []*modfile.File{modFile}, nil)
rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
requirements = rs
if err := commitRequirements(ctx, WriteOpts{}); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
// Suggest running 'go mod tidy' unless the project is empty. Even if we
// preserve checksums for) additional entities from compatRS, which are
// only needed for compatibility with ld.TidyCompatibleVersion.
if err := modfetch.WriteGoSum(ctx, keep, mustHaveCompleteRequirements()); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
}
if !ExplicitWriteGoMod && opts.ResolveMissingImports {
if err := commitRequirements(ctx, WriteOpts{}); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
tags := imports.Tags()
imports, testImports, err := imports.ScanFiles(gofiles, tags)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
loaded = loadFromRoots(ctx, loaderParams{
if !ExplicitWriteGoMod {
if err := commitRequirements(ctx, WriteOpts{}); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
}
meta.GoVersion = goVersion
rawGoVersion.Store(mod, meta.GoVersion)
if gover.Compare(goVersion, gover.Local()) > 0 {
- base.Fatalf("go: %v", &gover.TooNewError{What: mod.Path + " in " + base.ShortPath(vendorFile), GoVersion: goVersion})
+ base.Fatal(&gover.TooNewError{What: mod.Path + " in " + base.ShortPath(vendorFile), GoVersion: goVersion})
}
}
// All other tokens are reserved for future use.
b := work.NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
b.Print = printStderr
var err error
pkgs, err = load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args[:1])
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
} else {
pkgs = load.PackagesAndErrors(ctx, pkgOpts, args[:1])
b := work.NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
b := work.NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
builderWorkDirs.Range(func(bi, _ any) bool {
leakedBuilders++
if err := bi.(*Builder).Close(); err != nil {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
return true
})
b := NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
b := NewBuilder("")
defer func() {
if err := b.Close(); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}()
pkgOpts := load.PackageOpts{MainOnly: true}
pkgs, err := load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
load.CheckPackageErrors(pkgs)
patterns := make([]string, len(args))
instrumentInit()
buildModeInit()
if err := fsys.Init(base.Cwd()); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
// Make sure -pkgdir is absolute, because we run commands
workGraph, err := modload.LoadModGraph(ctx, "")
if tooNew := (*gover.TooNewError)(nil); errors.As(err, &tooNew) {
toolchain.TryVersion(ctx, tooNew.GoVersion)
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
_ = workGraph
mustSelectFor := map[module.Version][]module.Version{}
wf, err := modload.ReadWorkFile(workFilePath)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
modload.UpdateWorkFile(wf)
if err := modload.WriteWorkFile(workFilePath, wf); err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
}
}
workFile, err := modload.ReadWorkFile(gowork)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
workDir := filepath.Dir(gowork) // Absolute, since gowork itself is absolute.
if os.IsNotExist(err) {
keepDirs[absDir] = ""
} else {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
return
}
if os.IsNotExist(err) {
base.Errorf("go: directory %v does not exist", absArg)
} else {
- base.Errorf("go: %v", err)
+ base.Error(err)
}
continue
} else if !info.IsDir() {
if cmd != envcmd.CmdEnv {
buildcfg.Check()
if cfg.ExperimentErr != nil {
- base.Fatalf("go: %v", cfg.ExperimentErr)
+ base.Fatal(cfg.ExperimentErr)
}
}