diff --git a/tools/driver/packages/packages.go b/tools/driver/packages/packages.go index d2d645f..5b847a6 100644 --- a/tools/driver/packages/packages.go +++ b/tools/driver/packages/packages.go @@ -16,11 +16,10 @@ import ( "sync" "github.com/peterebden/go-cli-init/v5/logging" + "github.com/please-build/go-rules/tools/please_go/packageinfo" "golang.org/x/sync/errgroup" "golang.org/x/term" "golang.org/x/tools/go/packages" - - "github.com/please-build/go-rules/tools/please_go/packageinfo" ) var log = logging.MustGetLogger() @@ -421,7 +420,7 @@ func loadStdlibPackages() ([]*packages.Package, error) { } else if err != nil { return nil, err } - pkgs = append(pkgs, packageinfo.FromBuildPackageForModule(pkg)) + pkgs = append(pkgs, packageinfo.FromBuildPackageForModule(pkg, "")) } return pkgs, nil } diff --git a/tools/please_go/packageinfo/moduleinfo.go b/tools/please_go/packageinfo/moduleinfo.go index dd2af63..2a5159f 100644 --- a/tools/please_go/packageinfo/moduleinfo.go +++ b/tools/please_go/packageinfo/moduleinfo.go @@ -62,10 +62,7 @@ func WriteModuleInfo(importPath string, srcRoot, importconfig string, installPkg } else if err != nil { return fmt.Errorf("failed to import directory %s: %w", dir, err) } - pkg := FromBuildPackageForModule(bpkg) - - pkg.ExportFile = imports[pkg.PkgPath] - pkgs = append(pkgs, pkg) + pkgs = append(pkgs, FromBuildPackageForModule(bpkg, imports[bpkg.ImportPath])) } // If we're doing the stdlib, limit it to just things in the importconfig (i.e. no cmd/ packages) pkgs = slices.DeleteFunc(pkgs, func(pkg *packages.Package) bool { @@ -117,7 +114,7 @@ func loadImportConfig(filename string) (map[string]string, error) { } // FromBuildPackageForModule creates a packages Package from a build Package for a module. -func FromBuildPackageForModule(bpkg *build.Package) *packages.Package { +func FromBuildPackageForModule(bpkg *build.Package, exportFile string) *packages.Package { goFiles := make([]string, len(bpkg.GoFiles)+len(bpkg.TestGoFiles)+len(bpkg.XTestGoFiles)) for i, file := range bpkg.GoFiles { goFiles[i] = filepath.Join(bpkg.Dir, file) @@ -145,5 +142,6 @@ func FromBuildPackageForModule(bpkg *build.Package) *packages.Package { OtherFiles: slices.Concat(bpkg.CFiles, bpkg.CXXFiles, bpkg.MFiles, bpkg.HFiles, bpkg.SFiles, bpkg.SwigFiles, bpkg.SwigCXXFiles, bpkg.SysoFiles), EmbedPatterns: bpkg.EmbedPatterns, Imports: imports, + ExportFile: exportFile, } } diff --git a/tools/please_go/packageinfo/packageinfo.go b/tools/please_go/packageinfo/packageinfo.go index 9aea922..3856dc8 100644 --- a/tools/please_go/packageinfo/packageinfo.go +++ b/tools/please_go/packageinfo/packageinfo.go @@ -47,18 +47,11 @@ func WritePackageInfo(importPath string, srcRoot string, imports map[string]stri } else if err != nil { return fmt.Errorf("failed to import directory %s: %w", dir, err) } - pkg := fromBuildPackage(bpkg, subrepo, module) - - if subrepo != "" { - _, pkgPath, ok := strings.Cut(imports[pkg.PkgPath], pkg.PkgPath) - if !ok { - return fmt.Errorf("Cannot determine export file path for package %s from %s", pkg.PkgPath, imports[pkg.PkgPath]) - } - // This is a really gross hack to sneak both paths through the one field. - pkg.ExportFile = filepath.Join(subrepo, pkgPath) + "|" + imports[pkg.PkgPath] - } else { - pkg.ExportFile = imports[pkg.PkgPath] + pkg, err := fromBuildPackage(bpkg, subrepo, module, imports[importPath]) + if err != nil { + return fmt.Errorf("creating packages.Package: %w", err) } + pkgs = append(pkgs, pkg) } @@ -95,7 +88,8 @@ func fromBuildPackage( bpkg *build.Package, subrepo string, module string, -) *packages.Package { + exportFile string, +) (*packages.Package, error) { goFiles := make([]string, len(bpkg.GoFiles)+len(bpkg.TestGoFiles)+len(bpkg.XTestGoFiles)) compiledGoFiles := make([]string, len(goFiles)) for i, file := range slices.Concat(bpkg.GoFiles, bpkg.TestGoFiles, bpkg.XTestGoFiles) { @@ -115,6 +109,15 @@ func fromBuildPackage( imports[imp] = &packages.Package{ID: imp, PkgPath: imp} } + if subrepo != "" { + _, pkgPath, ok := strings.Cut(exportFile, bpkg.ImportPath) + if !ok { + return nil, fmt.Errorf("Cannot determine export file path for package %s from %s", bpkg.ImportPath, exportFile) + } + // This is a really gross hack to sneak both paths through the one field. + exportFile = filepath.Join(subrepo, pkgPath) + "|" + exportFile + } + name := bpkg.Name id := bpkg.ImportPath if len(bpkg.XTestGoFiles) > 0 || len(bpkg.XTestImports) > 0 { @@ -130,9 +133,10 @@ func fromBuildPackage( GoFiles: goFiles, CompiledGoFiles: compiledGoFiles, OtherFiles: slices.Concat(bpkg.CFiles, bpkg.CXXFiles, bpkg.MFiles, bpkg.HFiles, bpkg.SFiles, bpkg.SwigFiles, bpkg.SwigCXXFiles, bpkg.SysoFiles), + ExportFile: exportFile, EmbedPatterns: bpkg.EmbedPatterns, Imports: imports, - } + }, nil } // modulePath returns the import path for a module, or the given one if the module isn't set. diff --git a/tools/please_go/packageinfo/packageinfo_test.go b/tools/please_go/packageinfo/packageinfo_test.go index 6cabddc..a80007e 100644 --- a/tools/please_go/packageinfo/packageinfo_test.go +++ b/tools/please_go/packageinfo/packageinfo_test.go @@ -69,3 +69,66 @@ func Hello() { assert.Equal(t, expected, pkgs) } + +func TestWritePackageInfo_ExternalTest(t *testing.T) { + tmpDir := t.TempDir() + + // Create a simple package "foo" with only an external test file + fooDir := filepath.Join(tmpDir, "foo") + err := os.MkdirAll(fooDir, 0755) + require.NoError(t, err) + + testSrc := `package foo_test + +import ( + "testing" + "module/foo" +) + +func TestHello(t *testing.T) { +} +` + err = os.WriteFile(filepath.Join(fooDir, "foo_test.go"), []byte(testSrc), 0644) + require.NoError(t, err) + + imports := map[string]string{ + "module/foo/foo_test_lib": "foo/foo_test_lib.a", + } + + var buf bytes.Buffer + err = WritePackageInfo( + "module/foo/foo_test_lib", + fooDir, + imports, + "", + "", + true, // includeTests = true + &buf, + ) + require.NoError(t, err) + + var pkgs []*packages.Package + err = json.Unmarshal(buf.Bytes(), &pkgs) + require.NoError(t, err) + + expected := []*packages.Package{ + { + ID: "module/foo/foo_test_lib_test", + Name: "foo_test", + PkgPath: "module/foo/foo_test_lib_test", + GoFiles: []string{filepath.Join(fooDir, "foo_test.go")}, + CompiledGoFiles: []string{filepath.Join(fooDir, "foo_test.go")}, + ExportFile: "foo/foo_test_lib.a", + Imports: map[string]*packages.Package{ + "module/foo": { + ID: "module/foo", + }, + "testing": { + ID: "testing", + }, + }, + }, + } + + assert.Equal(t, expected, pkgs) +}