Skip to content

Commit

Permalink
go/packages: correctly handle context canceled
Browse files Browse the repository at this point in the history
If the context is canceled for packages.Load, the following log message is
written numerous times to stderr and returned as a load error per-package:

internal error: error "context canceled" (*errors.errorString) without
position

Check if the context was canceled and return nil, ctx.Err() instead.

ld.Config.Context is equivalent to ld.Context as Config is an embedded struct
within loader. Use ld.Context to refer to ld.Config.Context (for consistency).

Signed-off-by: Christian Stewart <christian@aperture.us>
  • Loading branch information
paralin committed Mar 14, 2024
1 parent ca94c96 commit d42480e
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions go/packages/packages.go
Expand Up @@ -759,6 +759,11 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
}(lpkg)
}
wg.Wait()

// Check if the context was canceled and return nil, context.Canceled if so.
if err := ld.Context.Err(); err != nil {
return nil, err
}
}

result := make([]*Package, len(initial))
Expand Down Expand Up @@ -817,6 +822,7 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
// loadRecursive loads the specified package and its dependencies,
// recursively, in parallel, in topological order.
// It is atomic and idempotent.
// May return early if ld.Context is canceled.
// Precondition: ld.Mode&NeedTypes.
func (ld *loader) loadRecursive(lpkg *loaderPackage) {
lpkg.loadOnce.Do(func() {
Expand All @@ -838,6 +844,7 @@ func (ld *loader) loadRecursive(lpkg *loaderPackage) {
// loadPackage loads the specified package.
// It must be called only once per Package,
// after immediate dependencies are loaded.
// May return early if ld.Context is canceled.
// Precondition: ld.Mode & NeedTypes.
func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" {
Expand Down Expand Up @@ -966,6 +973,12 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
}

files, errs := ld.parseFiles(lpkg.CompiledGoFiles)
// parseFiles may return nil, nil if ld.Context.Err() != nil
// check if the context was canceled and return early if so.
// ld.Context will be checked again after loadPackage returns.
if err := ld.Context.Err(); err != nil {
return
}
for _, err := range errs {
appendError(err)
}
Expand Down Expand Up @@ -1126,16 +1139,20 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
//
// Because files are scanned in parallel, the token.Pos
// positions of the resulting ast.Files are not ordered.
//
// May return nil, nil if ld.Context is canceled.
func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
var wg sync.WaitGroup
n := len(filenames)
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, file := range filenames {
if ld.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = ld.Config.Context.Err()
continue
if err := ld.Context.Err(); err != nil {
// If the context was canceled: return nil, nil
// The context will be checked just after the call to parseFiles.
// Wait for all parseFile calls to be interrupted
wg.Wait()
return nil, nil
}
wg.Add(1)
go func(i int, filename string) {
Expand Down

0 comments on commit d42480e

Please sign in to comment.