base.Fatalf("go list -export cannot be used with -find")
}
+ suppressDeps := !listJsonFields.needAny("Deps", "DepsErrors")
+
pkgOpts := load.PackageOpts{
- IgnoreImports: *listFind,
- ModResolveTests: *listTest,
- AutoVCS: true,
- // SuppressDeps is set if the user opts to explicitly ask for the json fields they
- // need, don't ask for Deps or DepsErrors. It's not set when using a template string,
- // even if *listFmt doesn't contain .Deps because Deps are used to find import cycles
- // for test variants of packages and users who have been providing format strings
- // might not expect those errors to stop showing up.
- // See issue #52443.
- SuppressDeps: !listJsonFields.needAny("Deps", "DepsErrors"),
+ IgnoreImports: *listFind,
+ ModResolveTests: *listTest,
+ AutoVCS: true,
SuppressBuildInfo: !*listExport && !listJsonFields.needAny("Stale", "StaleReason"),
SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"),
}
delete(m, old)
}
}
- if !pkgOpts.SuppressDeps {
- // Recompute deps lists using new strings, from the leaves up.
- for _, p := range all {
- deps := make(map[string]bool)
- for _, p1 := range p.Internal.Imports {
- deps[p1.ImportPath] = true
- for _, d := range p1.Deps {
- deps[d] = true
- }
- }
- p.Deps = make([]string, 0, len(deps))
- for d := range deps {
- p.Deps = append(p.Deps, d)
- }
- sort.Strings(p.Deps)
- }
+ }
+
+ if !suppressDeps {
+ all := pkgs
+ if !*listDeps {
+ // if *listDeps, then all is already in PackageList order.
+ all = load.PackageList(pkgs)
+ }
+ // Recompute deps lists using new strings, from the leaves up.
+ for _, p := range all {
+ collectDeps(p)
}
}
return pkgs
}
+// collectDeps populates p.Deps and p.DepsErrors by iterating over
+// p.Internal.Imports.
+//
+// TODO(jayconrod): collectDeps iterates over transitive imports for every
+// package. We should only need to visit direct imports.
+func collectDeps(p *load.Package) {
+ deps := make(map[string]*load.Package)
+ var q []*load.Package
+ q = append(q, p.Internal.Imports...)
+ for i := 0; i < len(q); i++ {
+ p1 := q[i]
+ path := p1.ImportPath
+ // The same import path could produce an error or not,
+ // depending on what tries to import it.
+ // Prefer to record entries with errors, so we can report them.
+ p0 := deps[path]
+ if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
+ deps[path] = p1
+ for _, p2 := range p1.Internal.Imports {
+ if deps[p2.ImportPath] != p2 {
+ q = append(q, p2)
+ }
+ }
+ }
+ }
+
+ p.Deps = make([]string, 0, len(deps))
+ for dep := range deps {
+ p.Deps = append(p.Deps, dep)
+ }
+ sort.Strings(p.Deps)
+ for _, dep := range p.Deps {
+ p1 := deps[dep]
+ if p1 == nil {
+ panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
+ }
+ if p1.Error != nil {
+ p.DepsErrors = append(p.DepsErrors, p1.Error)
+ }
+ }
+}
+
// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
// Error information
// Incomplete is above, packed into the other bools
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
- DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
+ DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies, collected by go list before output
// Test information
// If you add to this list you MUST add to p.AllFiles (below) too.
Pos: pos,
Err: err,
}
+ p.Incomplete = true
if path != stk.Top() {
p.Error.setPos(importPos)
ImportStack: stk.Copy(),
Err: err,
}
+ p.Incomplete = true
// Add the importer's position information if the import position exists, and
// the current package being examined is the importer.
}
}
p.Internal.Imports = imports
- if !opts.SuppressDeps {
- p.collectDeps()
- }
- if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && len(p.DepsErrors) == 0 && !opts.SuppressBuildInfo {
+ if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && !p.Incomplete && !opts.SuppressBuildInfo {
// TODO(bcmills): loading VCS metadata can be fairly slow.
// Consider starting this as a background goroutine and retrieving the result
// asynchronously when we're actually ready to build the package, or when we
return false
}
-// collectDeps populates p.Deps and p.DepsErrors by iterating over
-// p.Internal.Imports.
-//
-// TODO(jayconrod): collectDeps iterates over transitive imports for every
-// package. We should only need to visit direct imports.
-func (p *Package) collectDeps() {
- deps := make(map[string]*Package)
- var q []*Package
- q = append(q, p.Internal.Imports...)
- for i := 0; i < len(q); i++ {
- p1 := q[i]
- path := p1.ImportPath
- // The same import path could produce an error or not,
- // depending on what tries to import it.
- // Prefer to record entries with errors, so we can report them.
- p0 := deps[path]
- if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
- deps[path] = p1
- for _, p2 := range p1.Internal.Imports {
- if deps[p2.ImportPath] != p2 {
- q = append(q, p2)
- }
- }
- }
- }
-
- p.Deps = make([]string, 0, len(deps))
- for dep := range deps {
- p.Deps = append(p.Deps, dep)
- }
- sort.Strings(p.Deps)
- for _, dep := range p.Deps {
- p1 := deps[dep]
- if p1 == nil {
- panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
- }
- if p1.Error != nil {
- p.DepsErrors = append(p.DepsErrors, p1.Error)
- }
- }
-}
-
// vcsStatusCache maps repository directories (string)
// to their VCS information.
var vcsStatusCache par.ErrCache[string, vcs.Status]
setPkgErrorf := func(format string, args ...any) {
if p.Error == nil {
p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
+ p.Incomplete = true
}
}
// when -buildvcs=auto (the default).
AutoVCS bool
- // SuppressDeps is true if the caller does not need Deps and DepsErrors to be populated
- // on the package. TestPackagesAndErrors examines the Deps field to determine if the test
- // variant has an import cycle, so SuppressDeps should not be set if TestPackagesAndErrors
- // will be called on the package.
- SuppressDeps bool
-
// SuppressBuildInfo is true if the caller does not need p.Stale, p.StaleReason, or p.Internal.BuildInfo
// to be populated on the package.
SuppressBuildInfo bool
// CheckPackageErrors prints errors encountered loading pkgs and their
// dependencies, then exits with a non-zero status if any errors were found.
func CheckPackageErrors(pkgs []*Package) {
- printed := map[*PackageError]bool{}
+ var anyIncomplete bool
for _, pkg := range pkgs {
- if pkg.Error != nil {
- base.Errorf("%v", pkg.Error)
- printed[pkg.Error] = true
- }
- for _, err := range pkg.DepsErrors {
- // Since these are errors in dependencies,
- // the same error might show up multiple times,
- // once in each package that depends on it.
- // Only print each once.
- if !printed[err] {
- printed[err] = true
- base.Errorf("%v", err)
+ if pkg.Incomplete {
+ anyIncomplete = true
+ }
+ }
+ if anyIncomplete {
+ all := PackageList(pkgs)
+ for _, p := range all {
+ if p.Error != nil {
+ base.Errorf("%v", p.Error)
}
}
}
if treatAsMain[pkg.ImportPath] {
if pkg.Error == nil {
pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
+ pkg.Incomplete = true
}
mains = append(mains, pkg)
}
pkg.Error = &PackageError{
Err: fmt.Errorf("named files must be .go files: %s", pkg.Name),
}
+ pkg.Incomplete = true
return pkg
}
}
if opts.MainOnly && pkg.Name != "main" && pkg.Error == nil {
pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
+ pkg.Incomplete = true
}
setToolFlags(pkg)
}
if pkgErr != nil && pkg.Error == nil {
pkg.Error = &PackageError{Err: pkgErr}
+ pkg.Incomplete = true
}
}
err = p1.Error
break
}
- if len(p1.DepsErrors) > 0 {
- perr := p1.DepsErrors[0]
- err = perr
+ if p1.Incomplete {
+ ps := PackageList([]*Package{p1})
+ for _, p := range ps {
+ if p.Error != nil {
+ err = p.Error
+ break
+ }
+ }
break
}
}
- if pmain.Error != nil || len(pmain.DepsErrors) > 0 {
+ if pmain.Error != nil || pmain.Incomplete {
pmain = nil
}
- if ptest.Error != nil || len(ptest.DepsErrors) > 0 {
+ if ptest.Error != nil || ptest.Incomplete {
ptest = nil
}
- if pxtest != nil && (pxtest.Error != nil || len(pxtest.DepsErrors) > 0) {
+ if pxtest != nil && (pxtest.Error != nil || pxtest.Incomplete) {
pxtest = nil
}
return pmain, ptest, pxtest, err
var imports, ximports []*Package
var stk ImportStack
var testEmbed, xtestEmbed map[string][]string
+ var incomplete bool
stk.Push(p.ImportPath + " (test)")
rawTestImports := str.StringList(p.TestImports)
for i, path := range p.TestImports {
p1, err := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
if err != nil && ptestErr == nil {
ptestErr = err
+ incomplete = true
+ }
+ if p1.Incomplete {
+ incomplete = true
}
p.TestImports[i] = p1.ImportPath
imports = append(imports, p1)
ImportStack: stk.Copy(),
Err: err,
}
+ incomplete = true
embedErr := err.(*EmbedError)
ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
}
stk.Push(p.ImportPath + "_test")
pxtestNeedsPtest := false
+ var pxtestIncomplete bool
rawXTestImports := str.StringList(p.XTestImports)
for i, path := range p.XTestImports {
p1, err := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
if err != nil && pxtestErr == nil {
pxtestErr = err
}
+ if p1.Incomplete {
+ pxtestIncomplete = true
+ }
if p1.ImportPath == p.ImportPath {
pxtestNeedsPtest = true
} else {
embedErr := err.(*EmbedError)
pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
}
+ pxtestIncomplete = pxtestIncomplete || pxtestErr != nil
stk.Pop()
// Test package.
ptest = new(Package)
*ptest = *p
ptest.Error = ptestErr
+ ptest.Incomplete = incomplete
ptest.ForTest = p.ImportPath
ptest.GoFiles = nil
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.Internal.OrigImportPath = p.Internal.OrigImportPath
ptest.Internal.PGOProfile = p.Internal.PGOProfile
ptest.Internal.Build.Directives = append(slices.Clip(p.Internal.Build.Directives), p.Internal.Build.TestDirectives...)
- if !opts.SuppressDeps {
- ptest.collectDeps()
- }
} else {
ptest = p
}
ForTest: p.ImportPath,
Module: p.Module,
Error: pxtestErr,
+ Incomplete: pxtestIncomplete,
EmbedFiles: p.XTestEmbedFiles,
},
Internal: PackageInternal{
if pxtestNeedsPtest {
pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
}
- if !opts.SuppressDeps {
- pxtest.collectDeps()
- }
}
// Arrange for testing.Testing to report true.
p1, err := loadImport(ctx, opts, pre, dep, "", nil, &stk, nil, 0)
if err != nil && pmain.Error == nil {
pmain.Error = err
+ pmain.Incomplete = true
}
pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
}
pmain.Imports = append(pmain.Imports, pxtest.ImportPath)
t.ImportXtest = true
}
- if !opts.SuppressDeps {
- pmain.collectDeps()
- }
// Sort and dedup pmain.Imports.
// Only matters for go list -test output.
cycleErr := recompileForTest(pmain, p, ptest, pxtest)
if cycleErr != nil {
ptest.Error = cycleErr
+ ptest.Incomplete = true
}
if cover != nil {
data, err := formatTestmain(t)
if err != nil && pmain.Error == nil {
pmain.Error = &PackageError{Err: err}
+ pmain.Incomplete = true
}
// Set TestmainGo even if it is empty: the presence of a TestmainGo
// indicates that this package is, in fact, a test main.