Skip to content

package loader loads ./... differently than Go tools' loader? #1265

@garysferrao

Description

@garysferrao

background

i came across an interesting case in this thread on Go's slack channel: https://gophers.slack.com/archives/C029RQSEE/p1755713320936029

GitLab CI would like us to use GOPATH: $CI_PROJECT_DIR/.go if we'd like to use Go modules cache: https://docs.gitlab.com/ci/caching/#cache-go-dependencies

but this causes an error when trying to list ./...:
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/packages"
	"sigs.k8s.io/controller-tools/pkg/loader"
)

func main() {
	// allow environment (GOMODCACHE/GOPATH) to influence loading
	cfg := &packages.Config{
		Mode: packages.NeedName | packages.NeedFiles | packages.NeedModule | packages.NeedDeps,
		Env:  os.Environ(),
		Dir:  ".",
	}

	pkgs, err := packages.Load(cfg, "./...")
	if err != nil {
		fmt.Fprintf(os.Stderr, "packages.Load error: %v\n", err)
		os.Exit(2)
	}
	fmt.Printf("discovered %d root packages\n\n%", len(pkgs))
	for _, p := range pkgs {
		modDir := "<none>"
		modPath := "<none>"
		if p.Module != nil {
			modDir = p.Module.Dir
			modPath = p.Module.Path
		}
		fmt.Printf("pkg: %-40s module.path: %-40s module.dir: %s\n",
			p.PkgPath, modPath, modDir)

		// quick detection for module-cache location
		if modDir != "<none>" && strings.Contains(modDir, string(filepath.Separator)+"pkg"+string(filepath.Separator)+"mod"+string(filepath.Separator)) {
			fmt.Printf("  -> note: this package's module dir looks like it came from pkg/mod (module cache)\n")
		}
		if len(p.Errors) > 0 {
			fmt.Printf("  -> package had %d error(s)\n", len(p.Errors))
			for _, e := range p.Errors {
				fmt.Printf("     - %v\n", e)
			}
		}
	}

	fmt.Println("\n\n")

	// load roots just like controller-gen would do for "./..."
	pkgs2, err := loader.LoadRootsWithConfig(cfg, "./...")
	if err != nil {
		fmt.Fprintf(os.Stderr, "loader.LoadRootsWithConfig error: %v\n", err)
		os.Exit(2)
	}

	fmt.Printf("discovered %d root packages\n\n", len(pkgs2))
	for _, p := range pkgs2 {
		modDir := "<none>"
		modPath := "<none>"
		if p.Module != nil {
			modDir = p.Module.Dir
			modPath = p.Module.Path
		}
		fmt.Printf("pkg: %-40s module.path: %-40s module.dir: %s\n",
			p.PkgPath, modPath, modDir)

		// quick detection for module-cache location
		if modDir != "<none>" && strings.Contains(modDir, string(filepath.Separator)+"pkg"+string(filepath.Separator)+"mod"+string(filepath.Separator)) {
			fmt.Printf("  -> note: this package's module dir looks like it came from pkg/mod (module cache)\n")
		}
		if len(p.Errors) > 0 {
			fmt.Printf("  -> package had %d error(s)\n", len(p.Errors))
			for _, e := range p.Errors {
				fmt.Printf("     - %v\n", e)
			}
		}
	}
}
loader.LoadRootsWithConfig error: load packages in root ".go/gopkg.in/[email protected]": err: exit status 1: stderr: go: gopkg.in/[email protected]: missing go.sum entry for go.mod file; to add it:
        go mod download gopkg.in/check.v1

whereas the golang.org/x/tools/go/packages's Load() can print the list much faster and without errors.


would this be a known behaviour or is it a bug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions