From 5f0834f9f678a57e40acb427beb68fe7052ac66e Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Tue, 24 Jun 2025 17:47:15 +0100 Subject: [PATCH 01/11] fix: Typo in java.go --- java/gazelle/private/java/java.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/gazelle/private/java/java.go b/java/gazelle/private/java/java.go index 70d774b2..5498a411 100644 --- a/java/gazelle/private/java/java.go +++ b/java/gazelle/private/java/java.go @@ -6,7 +6,7 @@ import ( "github.com/bazel-contrib/rules_jvm/java/gazelle/private/types" ) -// IsTestPackage tries to detect if the directory would contain test files of not. +// IsTestPackage tries to detect if the directory would contain test files or not. // It assumes dir is a forward-slashed package name, not a possibly-back-slashed filepath. func IsTestPackage(pkg string) bool { if strings.HasPrefix(pkg, "javatests/") { From f91fc893fcdae356bc3fb15b2570b0030ad1176a Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Tue, 24 Jun 2025 17:48:25 +0100 Subject: [PATCH 02/11] refactor: Move labelLess to sorted_set/comparisons.go --- java/gazelle/private/sorted_set/BUILD.bazel | 10 ++++++++-- .../gazelle/private/sorted_set/comparisons.go | 19 +++++++++++++++++++ java/gazelle/resolve.go | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 java/gazelle/private/sorted_set/comparisons.go diff --git a/java/gazelle/private/sorted_set/BUILD.bazel b/java/gazelle/private/sorted_set/BUILD.bazel index 9f0d4081..01e28509 100644 --- a/java/gazelle/private/sorted_set/BUILD.bazel +++ b/java/gazelle/private/sorted_set/BUILD.bazel @@ -2,10 +2,16 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "sorted_set", - srcs = ["btreeset.go"], + srcs = [ + "btreeset.go", + "comparisons.go", + ], importpath = "github.com/bazel-contrib/rules_jvm/java/gazelle/private/sorted_set", visibility = ["//java/gazelle:__subpackages__"], - deps = ["@com_github_google_btree//:btree"], + deps = [ + "@bazel_gazelle//label", + "@com_github_google_btree//:btree", + ], ) go_test( diff --git a/java/gazelle/private/sorted_set/comparisons.go b/java/gazelle/private/sorted_set/comparisons.go new file mode 100644 index 00000000..2a779b07 --- /dev/null +++ b/java/gazelle/private/sorted_set/comparisons.go @@ -0,0 +1,19 @@ +package sorted_set + +import "github.com/bazelbuild/bazel-gazelle/label" + +// LabelLess is a comparison function for a SortedSet that holds label.Label instances. +func LabelLess(l, r label.Label) bool { + // In UTF-8, / sorts before : + // We want relative labels to come before absolute ones, so explicitly sort relative before absolute. + if l.Relative { + if r.Relative { + return l.String() < r.String() + } + return true + } + if r.Relative { + return false + } + return l.String() < r.String() +} diff --git a/java/gazelle/resolve.go b/java/gazelle/resolve.go index 7d0e6c82..4ee69362 100644 --- a/java/gazelle/resolve.go +++ b/java/gazelle/resolve.go @@ -103,7 +103,7 @@ func (jr *Resolver) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.Re } func (jr *Resolver) populateAttr(c *config.Config, pc *javaconfig.Config, r *rule.Rule, attrName string, requiredPackageNames *sorted_set.SortedSet[types.PackageName], ix *resolve.RuleIndex, isTestRule bool, from label.Label, ownPackageNames *sorted_set.SortedSet[types.PackageName]) { - labels := sorted_set.NewSortedSetFn[label.Label]([]label.Label{}, labelLess) + labels := sorted_set.NewSortedSetFn[label.Label]([]label.Label{}, sorted_set.LabelLess) for _, imp := range requiredPackageNames.SortedSlice() { dep := jr.resolveSinglePackage(c, pc, imp, ix, from, isTestRule, ownPackageNames) From 1757c0313ddecb7ca29b1803f720e9df25b1a1e7 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Tue, 24 Jun 2025 17:48:51 +0100 Subject: [PATCH 03/11] feat: Add java_export_index --- .../private/java_export_index/BUILD.bazel | 16 ++ .../java_export_index/java_export_index.go | 216 ++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 java/gazelle/private/java_export_index/BUILD.bazel create mode 100644 java/gazelle/private/java_export_index/java_export_index.go diff --git a/java/gazelle/private/java_export_index/BUILD.bazel b/java/gazelle/private/java_export_index/BUILD.bazel new file mode 100644 index 00000000..164198ad --- /dev/null +++ b/java/gazelle/private/java_export_index/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "java_export_index", + srcs = ["java_export_index.go"], + importpath = "github.com/bazel-contrib/rules_jvm/java/gazelle/private/java_export_index", + visibility = ["//visibility:public"], + deps = [ + "//java/gazelle/private/sorted_set", + "//java/gazelle/private/types", + "@bazel_gazelle//label", + "@bazel_gazelle//resolve", + "@bazel_gazelle//rule", + "@com_github_rs_zerolog//:zerolog", + ], +) diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go new file mode 100644 index 00000000..e78d01d6 --- /dev/null +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -0,0 +1,216 @@ +package java_export_index + +import ( + "github.com/bazel-contrib/rules_jvm/java/gazelle/private/sorted_set" + "github.com/bazel-contrib/rules_jvm/java/gazelle/private/types" + "github.com/bazelbuild/bazel-gazelle/label" + "github.com/bazelbuild/bazel-gazelle/resolve" + "github.com/bazelbuild/bazel-gazelle/rule" + "github.com/rs/zerolog" +) + +// JavaExportResolveInfo captures metadata about a java_export rule. +// We could capture this in private attributes, but we need to access it from every java_library +// exported by the given java_export, and we can't access other rule.Rule instances during resolve. +type JavaExportResolveInfo struct { + Rule *rule.Rule + Label label.Label + InternalVisibility *sorted_set.SortedSet[label.Label] +} + +func NewJavaExportResolveInfoFromRule(r *rule.Rule, file *rule.File) *JavaExportResolveInfo { + lbl := label.New("", file.Pkg, r.Name()) + exportPackageVisibility := label.New("", file.Pkg, "__pkg__") + return &JavaExportResolveInfo{ + Rule: r, + Label: lbl, + InternalVisibility: sorted_set.NewSortedSetFn([]label.Label{exportPackageVisibility}, sorted_set.LabelLess), + } +} + +// JavaExportIndex holds information about `java_export` targets and which symbols they make available, +// so that other java targets can depend on the right `java_export` instead of fine-grained dependencies. +type JavaExportIndex struct { + langName string + logger zerolog.Logger + + // readyForResolve is an internal flag that will turn true when the index is ready to perform resolution. + // It should be set after we've generated all the java_library targets, but before starting resolution. + // Before this flag, it's expected that `javaExports` only contains sparse information + readyForResolve bool + + // packagesToLabelsDeclaringThem and labelsToResolveInputs are used to calculate the transitive closure of `java_exports` targets. + // They are filled out _during_ the `GenerateRules` phase, and used at the end to populate javaExports and labelToJavaExport. + packagesToLabelsDeclaringThem map[types.PackageName]label.Label + labelsToResolveInputs map[label.Label]types.ResolveInput + + // javaExports and labelToJavaExport are used to resolve the dependencies of `java_library` targets, + // to decide whether they're going to depend on a `java_export` or a fine-grained dependency. + // They are filled _after_ the `GenerateRules` phase, and used during the `Resolve` phase. + javaExports map[label.Label]*JavaExportResolveInfo + labelToJavaExport map[label.Label]label.Label +} + +func NewJavaExportIndex(langName string, logger zerolog.Logger) *JavaExportIndex { + return &JavaExportIndex{ + langName: langName, + logger: logger, + readyForResolve: false, + packagesToLabelsDeclaringThem: make(map[types.PackageName]label.Label), + labelsToResolveInputs: make(map[label.Label]types.ResolveInput), + javaExports: make(map[label.Label]*JavaExportResolveInfo), + labelToJavaExport: make(map[label.Label]label.Label), + } +} + +func (jei *JavaExportIndex) ProcessResolveInputForRule(file *rule.File, r *rule.Rule, resolveInput types.ResolveInput) { + pkg := "" + if file != nil { + pkg = file.Pkg + } + lbl := label.New("", pkg, r.Name()) + + jei.labelsToResolveInputs[lbl] = resolveInput + for _, javaPackage := range resolveInput.PackageNames.SortedSlice() { + jei.packagesToLabelsDeclaringThem[javaPackage] = lbl + } +} + +// FinishBeforeResolve processes all the `java_exports` we've recorded when traversing the repository, to: +// - Gather all the transitive dependencies by traversing the `ResolveInput`s of relevant targets. +// - With that information, populate the map of `labelToJavaExport`. +func (jei *JavaExportIndex) FinishBeforeResolve() { + for javaExportLabel, javaExport := range jei.javaExports { + jei.calculateImportsForJavaExport(javaExportLabel, javaExport) + } + + jei.readyForResolve = true +} + +func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExportLabel label.Label, javaExport *JavaExportResolveInfo) { + var parseErrors []error + deps, errors := attrLabels("deps", javaExport.Rule, javaExportLabel) + parseErrors = append(parseErrors, errors...) + exports, errors := attrLabels("exports", javaExport.Rule, javaExportLabel) + parseErrors = append(parseErrors, errors...) + runtimeDeps, errors := attrLabels("runtime_deps", javaExport.Rule, javaExportLabel) + parseErrors = append(parseErrors, errors...) + + if len(parseErrors) > 0 { + jei.logger.Error(). + Errs("errors", errors). + Msgf("Errors parsing labels from fields of %s", javaExportLabel.String()) + } + + labelsToVisit := make([]label.Label, len(deps)) + _ = copy(labelsToVisit, deps) + labelsToVisit = append(labelsToVisit, exports...) + labelsToVisit = append(labelsToVisit, runtimeDeps...) + + transitiveDeps := make(map[label.Label]bool) + for _, depLabel := range labelsToVisit { + transitiveDeps[depLabel] = true + } + + var imports []resolve.ImportSpec + // Breadth-first traversal on the transitive closure of the export, + // resolving all the packages to the labels that export them. + for len(labelsToVisit) > 0 { + dep := labelsToVisit[0] + labelsToVisit = labelsToVisit[1:] + + // Visit the dependency + resolveInputForDep := jei.labelsToResolveInputs[dep] + for _, pkg := range resolveInputForDep.PackageNames.SortedSlice() { + imports = append(imports, resolve.ImportSpec{ + Lang: jei.langName, Imp: pkg.Name, + }) + } + + jei.labelToJavaExport[dep] = javaExportLabel + visibilityLbl := label.New("", dep.Pkg, "__pkg__") + javaExport.InternalVisibility.Add(visibilityLbl) + + // Queue every transitive dependency to be visited + for _, importedPkg := range resolveInputForDep.ImportedPackageNames.SortedSlice() { + lblToVisit := jei.packagesToLabelsDeclaringThem[importedPkg] + if lblToVisit == label.NoLabel { + jei.logger.Debug(). + Str("package", importedPkg.Name). + Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") + continue + } + _, isExportedByAnotherJavaExport := jei.IsExportedByJavaExport(lblToVisit) + if isExportedByAnotherJavaExport { + continue + } + if ok := transitiveDeps[lblToVisit]; !ok { + labelsToVisit = append(labelsToVisit, lblToVisit) + transitiveDeps[lblToVisit] = true + } + } + } +} + +func (jei *JavaExportIndex) RecordJavaExport(r *rule.Rule, f *rule.File) { + lbl := label.New("", f.Pkg, r.Name()) + srcs := r.AttrStrings("srcs") + if len(srcs) > 0 { + jei.logger.Error(). + Str("label", lbl.String()). + Msg("java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`") + } + jei.javaExports[lbl] = NewJavaExportResolveInfoFromRule(r, f) +} + +func (jei *JavaExportIndex) IsJavaExport(lbl label.Label) bool { + _, is := jei.javaExports[lbl] + return is +} + +func (jei *JavaExportIndex) IsExportedByJavaExport(lbl label.Label) (*JavaExportResolveInfo, bool) { + exportLbl, isExported := jei.labelToJavaExport[lbl] + if isExported { + export, exists := jei.javaExports[exportLbl] + if !exists { + jei.logger.Fatal(). + Str("label", lbl.String()). + Str("java_export", exportLbl.String()). + Msg("Label is exported by java_export, but target is not recorded") + } + return export, true + } + return nil, false +} + +func (jei *JavaExportIndex) VisibilityForLabel(lbl label.Label) *sorted_set.SortedSet[label.Label] { + regularReturn := sorted_set.NewSortedSetFn[label.Label]([]label.Label{label.New("", "", "__subpackages__")}, sorted_set.LabelLess) + if jei.IsJavaExport(lbl) { + return regularReturn + } + + exporter, isExportedByJavaExport := jei.IsExportedByJavaExport(lbl) + if isExportedByJavaExport { + return exporter.InternalVisibility + } + + return regularReturn +} + +func attrLabels(attr string, r *rule.Rule, ruleLabel label.Label) ([]label.Label, []error) { + depsStrings := r.AttrStrings(attr) + deps := make([]label.Label, 0, len(depsStrings)) + errors := make([]error, 0) + for _, depString := range depsStrings { + lbl, err := label.Parse(depString) + if err != nil { + errors = append(errors, err) + } + if lbl.Pkg == "" { + lbl.Pkg = ruleLabel.Pkg + lbl.Relative = false + } + deps = append(deps, lbl) + } + return deps, errors +} From 345923770b6b5de2fc55658548ded4c65b6d2383 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Tue, 24 Jun 2025 17:49:24 +0100 Subject: [PATCH 04/11] feat: Optionally respect java_exports during resolve --- java/gazelle/BUILD.bazel | 1 + java/gazelle/configure.go | 23 + java/gazelle/generate.go | 10 +- java/gazelle/javaconfig/config.go | 22 + java/gazelle/lang.go | 38 +- .../private/java_export_index/BUILD.bazel | 1 - .../java_export_index/java_export_index.go | 14 +- java/gazelle/private/types/types.go | 28 + java/gazelle/resolve.go | 91 +- .../testdata/java_export_targets/BUILD.in | 1 + .../testdata/java_export_targets/BUILD.out | 1 + .../testdata/java_export_targets/MODULE.bazel | 17 + .../testdata/java_export_targets/WORKSPACE | 0 .../export/BUILD.in | 8 + .../export/BUILD.out | 19 + .../export/DependOnLib.java | 9 + .../lib/BUILD.in | 0 .../lib/BUILD.out | 10 + .../lib/Lib.java | 7 + .../java_export_targets/maven_install.json | 1087 +++++++++++++++++ .../main/java/com/example/module1/BUILD.in | 8 + .../main/java/com/example/module1/BUILD.out | 20 + .../java/com/example/module1/Module1.java | 13 + .../java/com/example/module1/foo/BUILD.in | 0 .../java/com/example/module1/foo/BUILD.out | 10 + .../com/example/module1/foo/Module1Foo.java | 11 + .../main/java/com/example/module2/BUILD.in | 11 + .../main/java/com/example/module2/BUILD.out | 11 + .../java/com/example/module2/bar/BUILD.in | 0 .../java/com/example/module2/bar/BUILD.out | 15 + .../com/example/module2/bar/DependOnBaz.java | 9 + .../com/example/module2/bar/Module2Bar.java | 7 + .../java/com/example/module2/baz/BUILD.in | 0 .../java/com/example/module2/baz/BUILD.out | 11 + .../com/example/module2/baz/Module2Baz.java | 7 + .../src/main/java/com/example/nested/BUILD.in | 8 + .../main/java/com/example/nested/BUILD.out | 16 + .../java/com/example/nested/UseChild.java | 9 + .../com/example/nested/child_export/BUILD.in | 8 + .../com/example/nested/child_export/BUILD.out | 15 + .../nested/child_export/ChildExport.java | 7 + .../example/other_deps/plain_deps/BUILD.in | 9 + .../example/other_deps/plain_deps/BUILD.out | 18 + .../other_deps/plain_deps/PlainDep.java | 9 + .../other_deps/plain_deps/dep/BUILD.in | 0 .../other_deps/plain_deps/dep/BUILD.out | 11 + .../other_deps/plain_deps/dep/PlainDep.java | 7 + .../other_deps/plain_deps/expectedStderr.txt | 1 + .../com/example/other_deps/runtime/BUILD.in | 8 + .../com/example/other_deps/runtime/BUILD.out | 15 + .../other_deps/runtime/RuntimeDep.java | 7 + .../example/other_deps/third_party/BUILD.in | 8 + .../example/other_deps/third_party/BUILD.out | 16 + .../third_party/ThirdPartyDeps.java | 13 + .../src/main/java/com/example/user/BUILD.in | 0 .../src/main/java/com/example/user/BUILD.out | 24 + .../java/com/example/user/UseAllModules.java | 27 + 57 files changed, 1738 insertions(+), 18 deletions(-) create mode 100644 java/gazelle/testdata/java_export_targets/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/MODULE.bazel create mode 100644 java/gazelle/testdata/java_export_targets/WORKSPACE create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/DependOnLib.java create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/Lib.java create mode 100644 java/gazelle/testdata/java_export_targets/maven_install.json create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/Module1.java create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/Module1Foo.java create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/DependOnBaz.java create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/Module2Bar.java create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/Module2Baz.java create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/UseChild.java create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/ChildExport.java create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/PlainDep.java create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/PlainDep.java create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/RuntimeDep.java create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/ThirdPartyDeps.java create mode 100644 java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java diff --git a/java/gazelle/BUILD.bazel b/java/gazelle/BUILD.bazel index 12eafeb9..14a2e699 100644 --- a/java/gazelle/BUILD.bazel +++ b/java/gazelle/BUILD.bazel @@ -17,6 +17,7 @@ go_library( deps = [ "//java/gazelle/javaconfig", "//java/gazelle/private/java", + "//java/gazelle/private/java_export_index", "//java/gazelle/private/javaparser", "//java/gazelle/private/logconfig", "//java/gazelle/private/maven", diff --git a/java/gazelle/configure.go b/java/gazelle/configure.go index e2b405b3..488f8d67 100644 --- a/java/gazelle/configure.go +++ b/java/gazelle/configure.go @@ -66,6 +66,7 @@ func (jc *Configurer) KnownDirectives() []string { javaconfig.JavaGenerateProto, javaconfig.JavaMavenRepositoryName, javaconfig.JavaAnnotationProcessorPlugin, + javaconfig.JavaResolveToJavaExports, } } @@ -146,7 +147,29 @@ func (jc *Configurer) Configure(c *config.Config, rel string, f *rule.File) { jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %q: couldn't parse annotation processor class-name: %v", javaconfig.JavaAnnotationProcessorPlugin, parts[1], err) } cfg.AddAnnotationProcessorPlugin(*annotationClassName, *processorClassName) + + case javaconfig.JavaResolveToJavaExports: + if !cfg.CanSetResolveToJavaExports() { + jc.lang.logger.Fatal(). + Msgf("Detected multiple attempts to initialize directive %q. Please only initialize it once for the entire repository.", + javaconfig.JavaResolveToJavaExports) + } + if rel != "" { + jc.lang.logger.Fatal(). + Msgf("Enabling or disabling directive %q must be done from the root of the repository.", + javaconfig.JavaResolveToJavaExports) + } + switch d.Value { + case "true": + cfg.SetResolveToJavaExports(true) + case "false": + cfg.SetResolveToJavaExports(false) + default: + jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %s: possible values are true/false", + javaconfig.JavaResolveToJavaExports, d.Value) + } } + } } diff --git a/java/gazelle/generate.go b/java/gazelle/generate.go index 98d83358..e1875fed 100644 --- a/java/gazelle/generate.go +++ b/java/gazelle/generate.go @@ -200,7 +200,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes } if productionJavaFiles.Len() > 0 { - l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, annotationProcessorClasses, false, javaLibraryKind, &res) + l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, annotationProcessorClasses, false, javaLibraryKind, &res, cfg) } var testHelperJavaClasses *sorted_set.SortedSet[types.ClassName] @@ -236,7 +236,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes testJavaImportsWithHelpers.Add(tf.pkg) srcs = append(srcs, tf.pathRelativeToBazelWorkspaceRoot) } - l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, annotationProcessorClasses, true, javaLibraryKind, &res) + l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, annotationProcessorClasses, true, javaLibraryKind, &res, cfg) } } @@ -471,7 +471,7 @@ func accumulateJavaFile(cfg *javaconfig.Config, testJavaFiles, testHelperJavaFil } } -func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace string, name string, srcsRelativeToBazelWorkspace []string, packages, imports *sorted_set.SortedSet[types.PackageName], exports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult) { +func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace, name string, srcsRelativeToBazelWorkspace []string, packages, imports, exports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult, cfg *javaconfig.Config) { const ruleKind = "java_library" r := rule.NewRule(ruleKind, name) @@ -508,6 +508,10 @@ func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBa AnnotationProcessors: annotationProcessorClasses, } res.Imports = append(res.Imports, resolveInput) + + if cfg.ResolveToJavaExports() { + l.javaExportIndex.ProcessResolveInputForRule(file, r, resolveInput) + } } func (l javaLang) generateJavaBinary(file *rule.File, m types.ClassName, libName string, testonly bool, res *language.GenerateResult) { diff --git a/java/gazelle/javaconfig/config.go b/java/gazelle/javaconfig/config.go index a3cc492c..fe8f6108 100644 --- a/java/gazelle/javaconfig/config.go +++ b/java/gazelle/javaconfig/config.go @@ -53,6 +53,13 @@ const ( // JavaAnnotationProcessorPlugin tells the code generator about specific java_plugin targets needed to process // specific annotations. JavaAnnotationProcessorPlugin = "java_annotation_processor_plugin" + + // JavaResolveToJavaExports tells the code generator to favour resolving dependencies to java_exports where possible. + // If enabled, generated libraries will try to depend on java_exports targets that export a given package, instead of the underlying library. + // This allows monorepos to closely match a traditional Gradle/Maven model where subprojects are published in jars. + // Can be either "true" or "false". Defaults to "false". + // Inherited by children packages, can only be set at the root of the repository. + JavaResolveToJavaExports = "java_resolve_to_java_exports" ) // Configs is an extension of map[string]*Config. It provides finding methods @@ -75,6 +82,7 @@ func (c *Config) NewChild() *Config { extensionEnabled: c.extensionEnabled, isModuleRoot: false, generateProto: true, + resolveToJavaExports: c.resolveToJavaExports, mavenInstallFile: c.mavenInstallFile, moduleGranularity: c.moduleGranularity, repoRoot: c.repoRoot, @@ -105,6 +113,7 @@ type Config struct { extensionEnabled bool isModuleRoot bool generateProto bool + resolveToJavaExports *types.LateInit[bool] mavenInstallFile string moduleGranularity string repoRoot string @@ -128,6 +137,7 @@ func New(repoRoot string) *Config { extensionEnabled: true, isModuleRoot: false, generateProto: true, + resolveToJavaExports: types.NewLateInit[bool](false), mavenInstallFile: "maven_install.json", moduleGranularity: "package", repoRoot: repoRoot, @@ -294,6 +304,18 @@ func (c *Config) AddAnnotationProcessorPlugin(annotationClass types.ClassName, p c.annotationProcessorFullQualifiedClassToPluginClass[fullyQualifiedAnnotationClass].Add(processorClass) } +func (c *Config) ResolveToJavaExports() bool { + return c.resolveToJavaExports.Value() +} + +func (c *Config) CanSetResolveToJavaExports() bool { + return !c.resolveToJavaExports.IsInitialized() +} + +func (c *Config) SetResolveToJavaExports(resolve bool) { + c.resolveToJavaExports.Initialize(resolve) +} + func equalStringSlices(l, r []string) bool { if len(l) != len(r) { return false diff --git a/java/gazelle/lang.go b/java/gazelle/lang.go index 99ac83fe..c1bd070b 100644 --- a/java/gazelle/lang.go +++ b/java/gazelle/lang.go @@ -2,9 +2,11 @@ package gazelle import ( "context" + "github.com/bazel-contrib/rules_jvm/java/gazelle/javaconfig" "os" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/java" + "github.com/bazel-contrib/rules_jvm/java/gazelle/private/java_export_index" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/javaparser" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/logconfig" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/maven" @@ -31,6 +33,9 @@ type javaLang struct { // Key is the path to the java package from the Bazel workspace root. javaPackageCache map[string]*java.Package + // javaExportIndex holds information about java_export targets and which symbols they make available. + javaExportIndex *java_export_index.JavaExportIndex + // hasHadErrors triggers the extension to fail at destroy time. // // this is used to return != 0 when some errors during the generation were @@ -64,6 +69,7 @@ func NewLanguage() language.Language { logger: logger, javaLogLevel: javaLevel, javaPackageCache: make(map[string]*java.Package), + javaExportIndex: java_export_index.NewJavaExportIndex(languageName, logger), } l.logger = l.logger.Hook(shutdownServerOnFatalLogHook{ @@ -112,11 +118,25 @@ var javaLibraryKind = rule.KindInfo{ }, } +var javaExportKind = rule.KindInfo{ + NonEmptyAttrs: map[string]bool{ + "deps": true, + "exports": true, + "runtime_deps": true, + }, + ResolveAttrs: map[string]bool{ + "deps": true, + "exports": true, + "runtime_deps": true, + }, +} + func (l javaLang) Kinds() map[string]rule.KindInfo { kinds := map[string]rule.KindInfo{ "java_binary": kindWithRuntimeDeps, "java_junit5_test": kindWithRuntimeDeps, "java_library": javaLibraryKind, + "java_export": javaExportKind, "java_test": kindWithRuntimeDeps, "java_test_suite": kindWithRuntimeDeps, "java_proto_library": kindWithoutRuntimeDeps, @@ -152,6 +172,7 @@ var baseJavaLoads = []rule.LoadInfo{ Symbols: []string{ "java_junit5_test", "java_test_suite", + "java_export", }, }, } @@ -183,10 +204,25 @@ func (l javaLang) Loads() []rule.LoadInfo { return loads } -func (l javaLang) Fix(c *config.Config, f *rule.File) {} +func (l javaLang) Fix(c *config.Config, f *rule.File) { + + // We can't put this code in `GenerateRule`, because it doesn't parse the BUILD file at that point, + // so we can't identify the `java_export`s already in the file. + // And we can't do it at `Imports()` time, because we need to hook into `DoneGeneratingRules` + // to know when to populate l.javaExportIndex. + packageConfig := c.Exts[languageName].(javaconfig.Configs)[f.Pkg] + if packageConfig != nil && packageConfig.ResolveToJavaExports() { + for _, r := range f.Rules { + if r.Kind() == "java_export" { + l.javaExportIndex.RecordJavaExport(r, f) + } + } + } +} func (l javaLang) DoneGeneratingRules() { l.parser.ServerManager().Shutdown() + l.javaExportIndex.FinishBeforeResolve() } func (l javaLang) AfterResolvingDeps(_ context.Context) { diff --git a/java/gazelle/private/java_export_index/BUILD.bazel b/java/gazelle/private/java_export_index/BUILD.bazel index 164198ad..3d9d6983 100644 --- a/java/gazelle/private/java_export_index/BUILD.bazel +++ b/java/gazelle/private/java_export_index/BUILD.bazel @@ -9,7 +9,6 @@ go_library( "//java/gazelle/private/sorted_set", "//java/gazelle/private/types", "@bazel_gazelle//label", - "@bazel_gazelle//resolve", "@bazel_gazelle//rule", "@com_github_rs_zerolog//:zerolog", ], diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index e78d01d6..28c1f89b 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -4,7 +4,6 @@ import ( "github.com/bazel-contrib/rules_jvm/java/gazelle/private/sorted_set" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/types" "github.com/bazelbuild/bazel-gazelle/label" - "github.com/bazelbuild/bazel-gazelle/resolve" "github.com/bazelbuild/bazel-gazelle/rule" "github.com/rs/zerolog" ) @@ -112,7 +111,6 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExportLabel label. transitiveDeps[depLabel] = true } - var imports []resolve.ImportSpec // Breadth-first traversal on the transitive closure of the export, // resolving all the packages to the labels that export them. for len(labelsToVisit) > 0 { @@ -120,21 +118,15 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExportLabel label. labelsToVisit = labelsToVisit[1:] // Visit the dependency - resolveInputForDep := jei.labelsToResolveInputs[dep] - for _, pkg := range resolveInputForDep.PackageNames.SortedSlice() { - imports = append(imports, resolve.ImportSpec{ - Lang: jei.langName, Imp: pkg.Name, - }) - } - jei.labelToJavaExport[dep] = javaExportLabel visibilityLbl := label.New("", dep.Pkg, "__pkg__") javaExport.InternalVisibility.Add(visibilityLbl) // Queue every transitive dependency to be visited + resolveInputForDep := jei.labelsToResolveInputs[dep] for _, importedPkg := range resolveInputForDep.ImportedPackageNames.SortedSlice() { - lblToVisit := jei.packagesToLabelsDeclaringThem[importedPkg] - if lblToVisit == label.NoLabel { + lblToVisit, found := jei.packagesToLabelsDeclaringThem[importedPkg] + if !found || lblToVisit == label.NoLabel { jei.logger.Debug(). Str("package", importedPkg.Name). Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") diff --git a/java/gazelle/private/types/types.go b/java/gazelle/private/types/types.go index 1e9dd02d..b6d9fecf 100644 --- a/java/gazelle/private/types/types.go +++ b/java/gazelle/private/types/types.go @@ -166,3 +166,31 @@ func ParseResolvableJavaPackage(s string) (*ResolvableJavaPackage, error) { isTestSuite: isTestSuite, }, nil } + +type LateInit[T any] struct { + value T + initialized bool +} + +func NewLateInit[T any](valueWhileUninitialized T) *LateInit[T] { + return &LateInit[T]{ + value: valueWhileUninitialized, + initialized: false, + } +} + +func (lib *LateInit[T]) Initialize(value T) { + if lib.initialized { + panic("Trying to initialize a LateInit that's already initialized.") + } + lib.value = value + lib.initialized = true +} + +func (lib *LateInit[T]) IsInitialized() bool { + return lib.initialized +} + +func (lib *LateInit[T]) Value() T { + return lib.value +} diff --git a/java/gazelle/resolve.go b/java/gazelle/resolve.go index 4ee69362..bdd8dc35 100644 --- a/java/gazelle/resolve.go +++ b/java/gazelle/resolve.go @@ -50,10 +50,12 @@ func (*Resolver) Name() string { func (jr *Resolver) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec { log := jr.lang.logger.With().Str("step", "Imports").Str("rel", f.Pkg).Str("rule", r.Name()).Logger() - if !isJavaLibrary(r.Kind()) && r.Kind() != "java_test_suite" { + if !isJavaLibrary(r.Kind()) && r.Kind() != "java_test_suite" && r.Kind() != "java_export" { return nil } + lbl := label.New("", f.Pkg, r.Name()) + var out []resolve.ImportSpec if pkgs := r.PrivateAttr(packagesKey); pkgs != nil { for _, pkg := range pkgs.([]types.ResolvableJavaPackage) { @@ -61,7 +63,7 @@ func (jr *Resolver) Imports(c *config.Config, r *rule.Rule, f *rule.File) []reso } } - log.Debug().Str("out", fmt.Sprintf("%#v", out)).Str("label", label.New("", f.Pkg, r.Name()).String()).Msg("return") + log.Debug().Str("out", fmt.Sprintf("%#v", out)).Str("label", lbl.String()).Msg("return") return out } @@ -70,6 +72,7 @@ func (*Resolver) Embeds(r *rule.Rule, from label.Label) []label.Label { if isJavaProtoLibrary(r.Kind()) { embedStrings = append(embedStrings, r.AttrString("proto")) } + embedLabels := make([]label.Label, 0, len(embedStrings)) for _, s := range embedStrings { l, err := label.Parse(s) @@ -96,6 +99,20 @@ func (jr *Resolver) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.Re } } + // If the current library is exported under a `java_export`, it shouldn't be visible for targets outside the java_export. + if packageConfig.ResolveToJavaExports() && isJavaLibrary(r.Kind()) { + visibility := jr.lang.javaExportIndex.VisibilityForLabel(from) + + var asStrings []string + for _, vis := range visibility.SortedSlice() { + asStrings = append(asStrings, vis.String()) + } + // The rule attr replacement code is buggy, because while in `rule.SetAttr` we can replace the RHS of the expression, attr.val is always unchanged. I suspect it has to do with pointer magic. + // Fixed in https://github.com/bazel-contrib/bazel-gazelle/issues/2045 + r.DelAttr("visibility") + r.SetAttr("visibility", asStrings) + } + jr.populateAttr(c, packageConfig, r, "deps", resolveInput.ImportedPackageNames, ix, isTestRule, from, resolveInput.PackageNames) jr.populateAttr(c, packageConfig, r, "exports", resolveInput.ExportedPackageNames, ix, isTestRule, from, resolveInput.PackageNames) @@ -115,6 +132,7 @@ func (jr *Resolver) populateAttr(c *config.Config, pc *javaconfig.Config, r *rul } setLabelAttrIncludingExistingValues(r, attrName, labels) + } func (jr *Resolver) populatePluginsAttr(c *config.Config, ix *resolve.RuleIndex, resolveInput types.ResolveInput, packageConfig *javaconfig.Config, from label.Label, isTestRule bool, r *rule.Rule) { @@ -194,6 +212,19 @@ func (jr *Resolver) resolveSinglePackage(c *config.Config, pc *javaconfig.Config } matches := ix.FindRulesByImportWithConfig(c, importSpec, languageName) + + if pc.ResolveToJavaExports() { + matches = jr.tryResolvingToJavaExport(matches, from) + } else { + nonExportMatches := make([]resolve.FindResult, 0) + for _, match := range matches { + if !jr.lang.javaExportIndex.IsJavaExport(match.Label) { + nonExportMatches = append(nonExportMatches, match) + } + } + matches = nonExportMatches + } + if len(matches) == 1 { return matches[0].Label } @@ -295,6 +326,62 @@ func (jr *Resolver) resolveSinglePackage(c *config.Config, pc *javaconfig.Config return label.NoLabel } +// tryResolvingToJavaExport attempts to narrow down a list of resolution candidates by preferring java_export targets when appropriate. +// A dependency will be resolved to a `java_export` target when the following are all true. +// - The dependency is contained in a java_export target, and +// - There is exactly one java_export target that contains the dependency, and +// - That java_export does not export the target under consideration (`from`). +// +// Returns a subset of `results`, either by picking an appropriate `java_export`, or by eliminating ineligible `java_export`s. +// The program will issue a fatal error if it finds that more than one java_export contains the required dependency. +func (jr *Resolver) tryResolvingToJavaExport(results []resolve.FindResult, from label.Label) []resolve.FindResult { + coveredByTheSameExport := func(one, other label.Label) bool { + oneExport, oneIsCoveredByExport := jr.lang.javaExportIndex.IsExportedByJavaExport(one) + otherExport, otherIsCoveredByExport := jr.lang.javaExportIndex.IsExportedByJavaExport(other) + + if !oneIsCoveredByExport && !otherIsCoveredByExport { + return true + } else if oneIsCoveredByExport && otherIsCoveredByExport { + return oneExport.Label == otherExport.Label + } + return false + } + + var javaExportsThatCoverThisDep []resolve.FindResult + var nonJavaExportResults []resolve.FindResult + for _, result := range results { + if jr.lang.javaExportIndex.IsJavaExport(result.Label) { + javaExportsThatCoverThisDep = append(javaExportsThatCoverThisDep, result) + } else { + if !coveredByTheSameExport(from, result.Label) { + dependencyExporter, dependencyIsCovered := jr.lang.javaExportIndex.IsExportedByJavaExport(result.Label) + if dependencyIsCovered { + javaExportsThatCoverThisDep = append(javaExportsThatCoverThisDep, resolve.FindResult{Label: dependencyExporter.Label}) + } + } + nonJavaExportResults = append(nonJavaExportResults, result) + } + } + + if len(javaExportsThatCoverThisDep) == 0 { + return results + } else if len(javaExportsThatCoverThisDep) == 1 { + return javaExportsThatCoverThisDep + } else if len(javaExportsThatCoverThisDep) > 1 { + var exportStrings []string + for _, exportResult := range javaExportsThatCoverThisDep { + exportStrings = append(exportStrings, exportResult.Label.String()) + } + jr.lang.logger.Fatal(). + Str("rule", from.Pkg). + Strs("java_exports", exportStrings). + Msg("resolveSinglePackage found MULTIPLE java_export targets exporting this rule") + } + + // If we don't find any relevant java_export, resolve normally. + return nonJavaExportResults +} + func isJavaLibrary(kind string) bool { return kind == "java_library" || isJavaProtoLibrary(kind) } diff --git a/java/gazelle/testdata/java_export_targets/BUILD.in b/java/gazelle/testdata/java_export_targets/BUILD.in new file mode 100644 index 00000000..f3963d7e --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/BUILD.in @@ -0,0 +1 @@ +# gazelle:java_resolve_to_java_exports true diff --git a/java/gazelle/testdata/java_export_targets/BUILD.out b/java/gazelle/testdata/java_export_targets/BUILD.out new file mode 100644 index 00000000..f3963d7e --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/BUILD.out @@ -0,0 +1 @@ +# gazelle:java_resolve_to_java_exports true diff --git a/java/gazelle/testdata/java_export_targets/MODULE.bazel b/java/gazelle/testdata/java_export_targets/MODULE.bazel new file mode 100644 index 00000000..22d41d62 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/MODULE.bazel @@ -0,0 +1,17 @@ +bazel_dep(name = "rules_java", version = "8.13.0") +bazel_dep(name = "contrib_rules_jvm", version = "0.29.0") + +bazel_dep(name = "rules_jvm_external", version = "6.7") +maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") + +maven.install( + artifacts = [ + "com.google.guava:guava:33.4.6-jre", + ], + repositories = [ + "https://repo1.maven.org/maven2", + ], + lock_file = "//:maven_install.json", +) + +use_repo(maven, "maven") diff --git a/java/gazelle/testdata/java_export_targets/WORKSPACE b/java/gazelle/testdata/java_export_targets/WORKSPACE new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.in b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.in new file mode 100644 index 00000000..211926cb --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "export_export", + maven_coordinates = "com.example:export_different_package:0.1", + visibility = ["//:__subpackages__"], + exports = [":export"], +) diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.out b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.out new file mode 100644 index 00000000..01b8f038 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/BUILD.out @@ -0,0 +1,19 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "export_export", + maven_coordinates = "com.example:export_different_package:0.1", + visibility = ["//:__subpackages__"], + exports = [":export"], +) + +java_library( + name = "export", + srcs = ["DependOnLib.java"], + visibility = [ + "//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export:__pkg__", + "//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib:__pkg__", + ], + deps = ["//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib"], +) diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/DependOnLib.java b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/DependOnLib.java new file mode 100644 index 00000000..1ee5286d --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export/DependOnLib.java @@ -0,0 +1,9 @@ +package com.example.export_depending_on_different_package.export; + +import com.example.export_depending_on_different_package.lib.Lib; + +public class DependOnLib { + public static String module() { + return "DependOnLib + " + Lib.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.in b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.out b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.out new file mode 100644 index 00000000..0337ce07 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/BUILD.out @@ -0,0 +1,10 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library( + name = "lib", + srcs = ["Lib.java"], + visibility = [ + "//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export:__pkg__", + "//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib:__pkg__", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/Lib.java b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/Lib.java new file mode 100644 index 00000000..75269d2f --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/lib/Lib.java @@ -0,0 +1,7 @@ +package com.example.export_depending_on_different_package.lib; + +public class Lib { + public static String module() { + return "Lib"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/maven_install.json b/java/gazelle/testdata/java_export_targets/maven_install.json new file mode 100644 index 00000000..98b7dfc0 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/maven_install.json @@ -0,0 +1,1087 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": 562593050, + "__RESOLVED_ARTIFACTS_HASH": 1946412428, + "conflict_resolution": { + "com.google.errorprone:error_prone_annotations:2.30.0": "com.google.errorprone:error_prone_annotations:2.36.0", + "com.google.guava:failureaccess:1.0.1": "com.google.guava:failureaccess:1.0.3", + "com.google.guava:guava:33.3.1-android": "com.google.guava:guava:33.4.6-jre", + "io.opencensus:opencensus-api:0.31.0": "io.opencensus:opencensus-api:0.31.1", + "org.checkerframework:checker-qual:3.12.0": "org.checkerframework:checker-qual:3.42.0" + }, + "artifacts": { + "com.google.android:annotations": { + "shasums": { + "jar": "ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15" + }, + "version": "4.1.1.4" + }, + "com.google.api.grpc:proto-google-common-protos": { + "shasums": { + "jar": "43ec7807459aaa4012e838a1be4ef2d590cf233305da60af5b54f08ec8cf2302" + }, + "version": "2.48.0" + }, + "com.google.auth:google-auth-library-credentials": { + "shasums": { + "jar": "5dbf1207d14e093f67995f457cb69c3cf49bed1364150b23465e09acada65d96" + }, + "version": "1.24.1" + }, + "com.google.auth:google-auth-library-oauth2-http": { + "shasums": { + "jar": "88a75cd4448ea2f3b46e48a89497a6cf0985a5fa4e21274af4940e07f59f6eaf" + }, + "version": "1.24.1" + }, + "com.google.auto.value:auto-value": { + "shasums": { + "jar": "aaf8d637bfed3c420436b9facf1b7a88d12c8785374e4202382783005319c2c3" + }, + "version": "1.11.0" + }, + "com.google.auto.value:auto-value-annotations": { + "shasums": { + "jar": "5a055ce4255333b3346e1a8703da5bf8ff049532286fdcd31712d624abe111dd" + }, + "version": "1.11.0" + }, + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.code.gson:gson": { + "shasums": { + "jar": "57928d6e5a6edeb2abd3770a8f95ba44dce45f3b23b7a9dc2b309c581552a78b" + }, + "version": "2.11.0" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "77440e270b0bc9a249903c5a076c36a722c4886ca4f42675f2903a1c53ed61a5" + }, + "version": "2.36.0" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "cbfc3906b19b8f55dd7cfd6dfe0aa4532e834250d7f080bd8d211a3e246b59cb" + }, + "version": "1.0.3" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "958a035b74ff6c7d0cdff9c384524b645eb618f7117b60e1ee915f9cffd0e716" + }, + "version": "33.4.6-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.http-client:google-http-client": { + "shasums": { + "jar": "390618d7b51704240b8fd28e1230fa35d220f93f4b4ba80f63e38db00dacb09e" + }, + "version": "1.44.2" + }, + "com.google.http-client:google-http-client-gson": { + "shasums": { + "jar": "1119b66685195310375b717de2215d6c5d14fa8ed9f57e07b4fecd461e7b9db7" + }, + "version": "1.44.2" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64" + }, + "version": "3.0.0" + }, + "com.google.protobuf:protobuf-java": { + "shasums": { + "jar": "8540247fad9e06baefa8fb45eb313802d019f485f14300e0f9d6b556ed88e753" + }, + "version": "3.25.5" + }, + "com.google.re2j:re2j": { + "shasums": { + "jar": "4f657af51ab8bb0909bcc3eb40862d26125af8cbcf92aaaba595fed77f947bc0" + }, + "version": "1.7" + }, + "com.google.truth:truth": { + "shasums": { + "jar": "14c297bc64ca8bc15b6baf67f160627e4562ec91624797e312e907b431113508" + }, + "version": "1.4.2" + }, + "com.squareup.okhttp:okhttp": { + "shasums": { + "jar": "88ac9fd1bb51f82bcc664cc1eb9c225c90dc4389d660231b4cc737bebfe7d0aa" + }, + "version": "2.7.5" + }, + "com.squareup.okio:okio": { + "shasums": { + "jar": "a27f091d34aa452e37227e2cfa85809f29012a8ef2501a9b5a125a978e4fcbc1" + }, + "version": "2.10.0" + }, + "commons-codec:commons-codec": { + "shasums": { + "jar": "e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d" + }, + "version": "1.11" + }, + "io.grpc:grpc-api": { + "shasums": { + "jar": "bdcefde43d7c542e748adb7b2bccc46db16313ba86ab46f8ba3b54677c7c5883" + }, + "version": "1.60.1" + }, + "io.grpc:grpc-context": { + "shasums": { + "jar": "4ab6efb9cbadc88f8dc723ada3a61785da367697373d4432aef5222312aa70f6" + }, + "version": "1.60.1" + }, + "io.netty:netty-buffer": { + "shasums": { + "jar": "46d74e79125aacc055c31f18152fdc5d4a569aa8d60091203d0baa833973ac3c" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-codec": { + "shasums": { + "jar": "9eccce9a8d827bb8ce84f9c3183fec58bd1c96a51010cf711297746034af3701" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-codec-http": { + "shasums": { + "jar": "dc0d6af5054630a70ff0ef354f20aa7a6e46738c9fc5636ed3d4fe77e38bd48d" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-codec-http2": { + "shasums": { + "jar": "b546c75445a487bb7bcd5a94779caecce33582cf7be31b8b39fc0e65b1ee26fc" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-codec-socks": { + "shasums": { + "jar": "976052a3c9bb280bc6d99f3a29e6404677cf958c3de05b205093d38c006b880c" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-common": { + "shasums": { + "jar": "9851ec66548b9e0d41164ce98943cdd4bbe305f68ddbd24eae52e4501a0d7b1a" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-handler": { + "shasums": { + "jar": "d5a08d7de364912e4285968de4d4cce3f01da4bb048d5c6937e5f2af1f8e148a" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-handler-proxy": { + "shasums": { + "jar": "ad54ab4fe9c47ef3e723d71251126db53e8db543871adb9eafc94446539eff52" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-resolver": { + "shasums": { + "jar": "a2e9b4ae7caa92fc5bd747e11d1dec20d81b18fc00959554302244ac5c56ce70" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-tcnative-boringssl-static": { + "shasums": { + "jar": "bb8349bda3ba043c09f5c732c5b2d47f18ac4dafce248cb850cfbd0599e5ba01", + "linux-aarch_64": "9fd6f905bce8472ca9e24f8728962b91b9319c84fcbb618ab87f6b9774c063ed", + "linux-x86_64": "45ce55b49f4c16de65278d9f4608a9f06460f290f1e3b4fc3f2452866519d618", + "osx-aarch_64": "834d3df2f9eb3aa08d49326409c454e2f9c75a49c3f0454b7cab64619b1614dc", + "osx-x86_64": "3a16b7ca4e891f9ad51e9ae9eb167c5e81d7f55a0001edf2471b693f4f8c12e1", + "windows-x86_64": "855d930366fae9bec3872569975959e1e31dd752dffc9f925eae8436f933e11a" + }, + "version": "2.0.65.Final" + }, + "io.netty:netty-tcnative-classes": { + "shasums": { + "jar": "84ef0241ada1b4ed92785e10c16edbeb063348959a3b0ef740712badd09fa128" + }, + "version": "2.0.65.Final" + }, + "io.netty:netty-transport": { + "shasums": { + "jar": "a42dd68390ca14b4ff2d40628a096c76485b4adb7c19602d5289321a0669e704" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-transport-classes-epoll": { + "shasums": { + "jar": "8e59cec67de3b9f8afe4eccec11ed8ce4423948eeaf4ca512bf69324052ed510" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-transport-native-epoll": { + "shasums": { + "linux-x86_64": "dcd60c6b3076af307ab877201a136e1f1066c9be809aaed827391a23909f9135" + }, + "version": "4.1.110.Final" + }, + "io.netty:netty-transport-native-unix-common": { + "shasums": { + "jar": "51717bb7471141950390c6713a449fdb1054d07e60737ee7dda7083796cdee48" + }, + "version": "4.1.110.Final" + }, + "io.opencensus:opencensus-api": { + "shasums": { + "jar": "f1474d47f4b6b001558ad27b952e35eda5cc7146788877fc52938c6eba24b382" + }, + "version": "0.31.1" + }, + "io.opencensus:opencensus-contrib-grpc-metrics": { + "shasums": { + "jar": "b28fc72490edd49c4c40a3c216b709200833fb361f7f602f1c7c9a527f7b7f63" + }, + "version": "0.31.0" + }, + "io.opencensus:opencensus-contrib-http-util": { + "shasums": { + "jar": "3ea995b55a4068be22989b70cc29a4d788c2d328d1d50613a7a9afd13fdd2d0a" + }, + "version": "0.31.1" + }, + "io.perfmark:perfmark-api": { + "shasums": { + "jar": "c7b478503ec524e55df19b424d46d27c8a68aeb801664fadd4f069b71f52d0f6" + }, + "version": "0.27.0" + }, + "junit:junit": { + "shasums": { + "jar": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3" + }, + "version": "4.13.2" + }, + "org.apache.httpcomponents:httpclient": { + "shasums": { + "jar": "c8bc7e1c51a6d4ce72f40d2ebbabf1c4b68bfe76e732104b04381b493478e9d6" + }, + "version": "4.5.14" + }, + "org.apache.httpcomponents:httpcore": { + "shasums": { + "jar": "6c9b3dd142a09dc468e23ad39aad6f75a0f2b85125104469f026e52a474e464f" + }, + "version": "4.4.16" + }, + "org.apache.tomcat:annotations-api": { + "shasums": { + "jar": "253829d3c12b7381d1044fc22c6436cff025fe0d459e4a329413e560a7d0dd13" + }, + "version": "6.0.53" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "ccaedd33af0b7894d9f2f3b644f4d19e43928e32902e61ac4d10777830f5aac7" + }, + "version": "3.42.0" + }, + "org.codehaus.mojo:animal-sniffer-annotations": { + "shasums": { + "jar": "c720e6e5bcbe6b2f48ded75a47bccdb763eede79d14330102e0d352e3d89ed92" + }, + "version": "1.24" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9" + }, + "version": "1.3" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "b8ab1da5cdc89cb084d41e1f28f20a42bd431538642a5741c52bbfae3fa3e656" + }, + "version": "1.4.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-common": { + "shasums": { + "jar": "a7112c9b3cefee418286c9c9372f7af992bd1e6e030691d52f60cb36dbec8320" + }, + "version": "1.4.20" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478" + }, + "version": "13.0" + }, + "org.jspecify:jspecify": { + "shasums": { + "jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab" + }, + "version": "1.0.0" + }, + "org.ow2.asm:asm": { + "shasums": { + "jar": "3c6fac2424db3d4a853b669f4e3d1d9c3c552235e19a319673f887083c2303a1" + }, + "version": "9.6" + } + }, + "dependencies": { + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.protobuf:protobuf-java" + ], + "com.google.auth:google-auth-library-oauth2-http": [ + "com.google.auth:google-auth-library-credentials", + "com.google.auto.value:auto-value-annotations", + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.http-client:google-http-client", + "com.google.http-client:google-http-client-gson" + ], + "com.google.code.gson:gson": [ + "com.google.errorprone:error_prone_annotations" + ], + "com.google.guava:guava": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.jspecify:jspecify" + ], + "com.google.http-client:google-http-client": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "io.grpc:grpc-context", + "io.opencensus:opencensus-api", + "io.opencensus:opencensus-contrib-http-util", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore" + ], + "com.google.http-client:google-http-client-gson": [ + "com.google.code.gson:gson", + "com.google.http-client:google-http-client" + ], + "com.google.truth:truth": [ + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "junit:junit", + "org.checkerframework:checker-qual", + "org.ow2.asm:asm" + ], + "com.squareup.okhttp:okhttp": [ + "com.squareup.okio:okio" + ], + "com.squareup.okio:okio": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-common" + ], + "io.grpc:grpc-context": [ + "io.grpc:grpc-api" + ], + "io.netty:netty-buffer": [ + "io.netty:netty-common" + ], + "io.netty:netty-codec": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http2": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-socks": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-handler": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-resolver", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-handler-proxy": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-resolver": [ + "io.netty:netty-common" + ], + "io.netty:netty-tcnative-boringssl-static": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64": [ + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-classes" + ], + "io.netty:netty-transport": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-resolver" + ], + "io.netty:netty-transport-classes-epoll": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-epoll:jar:linux-x86_64": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.opencensus:opencensus-api": [ + "io.grpc:grpc-context" + ], + "io.opencensus:opencensus-contrib-grpc-metrics": [ + "com.google.guava:guava", + "io.opencensus:opencensus-api" + ], + "io.opencensus:opencensus-contrib-http-util": [ + "com.google.guava:guava", + "io.opencensus:opencensus-api" + ], + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ], + "org.apache.httpcomponents:httpclient": [ + "commons-codec:commons-codec", + "org.apache.httpcomponents:httpcore" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains:annotations" + ] + }, + "packages": { + "com.google.android:annotations": [ + "android.annotation" + ], + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.api", + "com.google.apps.card.v1", + "com.google.cloud", + "com.google.cloud.audit", + "com.google.cloud.location", + "com.google.geo.type", + "com.google.logging.type", + "com.google.longrunning", + "com.google.rpc", + "com.google.rpc.context", + "com.google.shopping.type", + "com.google.type" + ], + "com.google.auth:google-auth-library-credentials": [ + "com.google.auth" + ], + "com.google.auth:google-auth-library-oauth2-http": [ + "com.google.auth.http", + "com.google.auth.oauth2" + ], + "com.google.auto.value:auto-value": [ + "autovalue.shaded.com.google.auto.common", + "autovalue.shaded.com.google.auto.service", + "autovalue.shaded.com.google.common.annotations", + "autovalue.shaded.com.google.common.base", + "autovalue.shaded.com.google.common.cache", + "autovalue.shaded.com.google.common.collect", + "autovalue.shaded.com.google.common.escape", + "autovalue.shaded.com.google.common.eventbus", + "autovalue.shaded.com.google.common.graph", + "autovalue.shaded.com.google.common.hash", + "autovalue.shaded.com.google.common.html", + "autovalue.shaded.com.google.common.io", + "autovalue.shaded.com.google.common.math", + "autovalue.shaded.com.google.common.net", + "autovalue.shaded.com.google.common.primitives", + "autovalue.shaded.com.google.common.reflect", + "autovalue.shaded.com.google.common.util.concurrent", + "autovalue.shaded.com.google.common.xml", + "autovalue.shaded.com.google.errorprone.annotations", + "autovalue.shaded.com.google.errorprone.annotations.concurrent", + "autovalue.shaded.com.google.escapevelocity", + "autovalue.shaded.com.google.j2objc.annotations", + "autovalue.shaded.com.squareup.javapoet", + "autovalue.shaded.net.ltgt.gradle.incap", + "autovalue.shaded.org.checkerframework.checker.nullness.qual", + "autovalue.shaded.org.checkerframework.framework.qual", + "autovalue.shaded.org.objectweb.asm", + "com.google.auto.value.extension", + "com.google.auto.value.extension.memoized.processor", + "com.google.auto.value.extension.serializable.processor", + "com.google.auto.value.extension.serializable.serializer", + "com.google.auto.value.extension.serializable.serializer.impl", + "com.google.auto.value.extension.serializable.serializer.interfaces", + "com.google.auto.value.extension.serializable.serializer.runtime", + "com.google.auto.value.extension.toprettystring.processor", + "com.google.auto.value.processor" + ], + "com.google.auto.value:auto-value-annotations": [ + "com.google.auto.value", + "com.google.auto.value.extension.memoized", + "com.google.auto.value.extension.serializable", + "com.google.auto.value.extension.toprettystring" + ], + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.code.gson:gson": [ + "com.google.gson", + "com.google.gson.annotations", + "com.google.gson.internal", + "com.google.gson.internal.bind", + "com.google.gson.internal.bind.util", + "com.google.gson.internal.reflect", + "com.google.gson.internal.sql", + "com.google.gson.reflect", + "com.google.gson.stream" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.http-client:google-http-client": [ + "com.google.api.client.http", + "com.google.api.client.http.apache", + "com.google.api.client.http.javanet", + "com.google.api.client.http.json", + "com.google.api.client.json", + "com.google.api.client.json.rpc2", + "com.google.api.client.json.webtoken", + "com.google.api.client.testing.http", + "com.google.api.client.testing.http.apache", + "com.google.api.client.testing.http.javanet", + "com.google.api.client.testing.json", + "com.google.api.client.testing.json.webtoken", + "com.google.api.client.testing.util", + "com.google.api.client.util", + "com.google.api.client.util.escape", + "com.google.api.client.util.store" + ], + "com.google.http-client:google-http-client-gson": [ + "com.google.api.client.json.gson" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "com.google.protobuf:protobuf-java": [ + "com.google.protobuf", + "com.google.protobuf.compiler" + ], + "com.google.re2j:re2j": [ + "com.google.re2j" + ], + "com.google.truth:truth": [ + "com.google.common.truth" + ], + "com.squareup.okhttp:okhttp": [ + "com.squareup.okhttp", + "com.squareup.okhttp.internal", + "com.squareup.okhttp.internal.framed", + "com.squareup.okhttp.internal.http", + "com.squareup.okhttp.internal.io", + "com.squareup.okhttp.internal.tls" + ], + "com.squareup.okio:okio": [ + "okio", + "okio.internal" + ], + "commons-codec:commons-codec": [ + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.cli", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net" + ], + "io.grpc:grpc-api": [ + "io.grpc" + ], + "io.netty:netty-buffer": [ + "io.netty.buffer", + "io.netty.buffer.search" + ], + "io.netty:netty-codec": [ + "io.netty.handler.codec", + "io.netty.handler.codec.base64", + "io.netty.handler.codec.bytes", + "io.netty.handler.codec.compression", + "io.netty.handler.codec.json", + "io.netty.handler.codec.marshalling", + "io.netty.handler.codec.protobuf", + "io.netty.handler.codec.serialization", + "io.netty.handler.codec.string", + "io.netty.handler.codec.xml" + ], + "io.netty:netty-codec-http": [ + "io.netty.handler.codec.http", + "io.netty.handler.codec.http.cookie", + "io.netty.handler.codec.http.cors", + "io.netty.handler.codec.http.multipart", + "io.netty.handler.codec.http.websocketx", + "io.netty.handler.codec.http.websocketx.extensions", + "io.netty.handler.codec.http.websocketx.extensions.compression", + "io.netty.handler.codec.rtsp", + "io.netty.handler.codec.spdy" + ], + "io.netty:netty-codec-http2": [ + "io.netty.handler.codec.http2" + ], + "io.netty:netty-codec-socks": [ + "io.netty.handler.codec.socks", + "io.netty.handler.codec.socksx", + "io.netty.handler.codec.socksx.v4", + "io.netty.handler.codec.socksx.v5" + ], + "io.netty:netty-common": [ + "io.netty.util", + "io.netty.util.collection", + "io.netty.util.concurrent", + "io.netty.util.internal", + "io.netty.util.internal.logging", + "io.netty.util.internal.shaded.org.jctools.queues", + "io.netty.util.internal.shaded.org.jctools.queues.atomic", + "io.netty.util.internal.shaded.org.jctools.util", + "io.netty.util.internal.svm" + ], + "io.netty:netty-handler": [ + "io.netty.handler.address", + "io.netty.handler.flow", + "io.netty.handler.flush", + "io.netty.handler.ipfilter", + "io.netty.handler.logging", + "io.netty.handler.pcap", + "io.netty.handler.ssl", + "io.netty.handler.ssl.ocsp", + "io.netty.handler.ssl.util", + "io.netty.handler.stream", + "io.netty.handler.timeout", + "io.netty.handler.traffic" + ], + "io.netty:netty-handler-proxy": [ + "io.netty.handler.proxy" + ], + "io.netty:netty-resolver": [ + "io.netty.resolver" + ], + "io.netty:netty-tcnative-classes": [ + "io.netty.internal.tcnative" + ], + "io.netty:netty-transport": [ + "io.netty.bootstrap", + "io.netty.channel", + "io.netty.channel.embedded", + "io.netty.channel.group", + "io.netty.channel.internal", + "io.netty.channel.local", + "io.netty.channel.nio", + "io.netty.channel.oio", + "io.netty.channel.pool", + "io.netty.channel.socket", + "io.netty.channel.socket.nio", + "io.netty.channel.socket.oio" + ], + "io.netty:netty-transport-classes-epoll": [ + "io.netty.channel.epoll" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty.channel.unix" + ], + "io.opencensus:opencensus-api": [ + "io.opencensus.common", + "io.opencensus.internal", + "io.opencensus.metrics", + "io.opencensus.metrics.data", + "io.opencensus.metrics.export", + "io.opencensus.resource", + "io.opencensus.stats", + "io.opencensus.tags", + "io.opencensus.tags.propagation", + "io.opencensus.tags.unsafe", + "io.opencensus.trace", + "io.opencensus.trace.config", + "io.opencensus.trace.export", + "io.opencensus.trace.internal", + "io.opencensus.trace.propagation", + "io.opencensus.trace.samplers", + "io.opencensus.trace.unsafe" + ], + "io.opencensus:opencensus-contrib-grpc-metrics": [ + "io.opencensus.contrib.grpc.metrics" + ], + "io.opencensus:opencensus-contrib-http-util": [ + "io.opencensus.contrib.http", + "io.opencensus.contrib.http.util" + ], + "io.perfmark:perfmark-api": [ + "io.perfmark" + ], + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.function", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.management", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "org.apache.httpcomponents:httpclient": [ + "org.apache.http.auth", + "org.apache.http.auth.params", + "org.apache.http.client", + "org.apache.http.client.config", + "org.apache.http.client.entity", + "org.apache.http.client.methods", + "org.apache.http.client.params", + "org.apache.http.client.protocol", + "org.apache.http.client.utils", + "org.apache.http.conn", + "org.apache.http.conn.params", + "org.apache.http.conn.routing", + "org.apache.http.conn.scheme", + "org.apache.http.conn.socket", + "org.apache.http.conn.ssl", + "org.apache.http.conn.util", + "org.apache.http.cookie", + "org.apache.http.cookie.params", + "org.apache.http.impl.auth", + "org.apache.http.impl.client", + "org.apache.http.impl.conn", + "org.apache.http.impl.conn.tsccm", + "org.apache.http.impl.cookie", + "org.apache.http.impl.execchain" + ], + "org.apache.httpcomponents:httpcore": [ + "org.apache.http", + "org.apache.http.annotation", + "org.apache.http.concurrent", + "org.apache.http.config", + "org.apache.http.entity", + "org.apache.http.impl", + "org.apache.http.impl.bootstrap", + "org.apache.http.impl.entity", + "org.apache.http.impl.io", + "org.apache.http.impl.pool", + "org.apache.http.io", + "org.apache.http.message", + "org.apache.http.params", + "org.apache.http.pool", + "org.apache.http.protocol", + "org.apache.http.ssl", + "org.apache.http.util" + ], + "org.apache.tomcat:annotations-api": [ + "javax.annotation", + "javax.annotation.security", + "javax.ejb", + "javax.persistence", + "javax.xml.ws" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.count.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.codehaus.mojo:animal-sniffer-annotations": [ + "org.codehaus.mojo.animal_sniffer" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest", + "org.hamcrest.core", + "org.hamcrest.internal" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.experimental", + "kotlin.internal", + "kotlin.io", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.system", + "kotlin.text", + "kotlin.time" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jspecify:jspecify": [ + "org.jspecify.annotations" + ], + "org.ow2.asm:asm": [ + "org.objectweb.asm", + "org.objectweb.asm.signature" + ] + }, + "repositories": { + "https://repo1.maven.org/maven2/": [ + "com.google.android:annotations", + "com.google.api.grpc:proto-google-common-protos", + "com.google.auth:google-auth-library-credentials", + "com.google.auth:google-auth-library-oauth2-http", + "com.google.auto.value:auto-value", + "com.google.auto.value:auto-value-annotations", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:listenablefuture", + "com.google.http-client:google-http-client", + "com.google.http-client:google-http-client-gson", + "com.google.j2objc:j2objc-annotations", + "com.google.protobuf:protobuf-java", + "com.google.re2j:re2j", + "com.google.truth:truth", + "com.squareup.okhttp:okhttp", + "com.squareup.okio:okio", + "commons-codec:commons-codec", + "io.grpc:grpc-api", + "io.grpc:grpc-context", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-resolver", + "io.netty:netty-tcnative-boringssl-static", + "io.netty:netty-tcnative-boringssl-static:jar:linux-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:linux-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-aarch_64", + "io.netty:netty-tcnative-boringssl-static:jar:osx-x86_64", + "io.netty:netty-tcnative-boringssl-static:jar:windows-x86_64", + "io.netty:netty-tcnative-classes", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-native-epoll:jar:linux-x86_64", + "io.netty:netty-transport-native-unix-common", + "io.opencensus:opencensus-api", + "io.opencensus:opencensus-contrib-grpc-metrics", + "io.opencensus:opencensus-contrib-http-util", + "io.perfmark:perfmark-api", + "junit:junit", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.tomcat:annotations-api", + "org.checkerframework:checker-qual", + "org.codehaus.mojo:animal-sniffer-annotations", + "org.hamcrest:hamcrest-core", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains:annotations", + "org.jspecify:jspecify", + "org.ow2.asm:asm" + ] + }, + "services": { + "com.google.auto.value:auto-value": { + "com.google.auto.value.extension.AutoValueExtension": [ + "com.google.auto.value.extension.memoized.processor.MemoizeExtension", + "com.google.auto.value.extension.serializable.processor.SerializableAutoValueExtension", + "com.google.auto.value.extension.toprettystring.processor.ToPrettyStringExtension" + ], + "com.google.auto.value.extension.serializable.serializer.interfaces.SerializerExtension": [ + "com.google.auto.value.extension.serializable.serializer.impl.ImmutableListSerializerExtension", + "com.google.auto.value.extension.serializable.serializer.impl.ImmutableMapSerializerExtension", + "com.google.auto.value.extension.serializable.serializer.impl.OptionalSerializerExtension" + ], + "javax.annotation.processing.Processor": [ + "com.google.auto.value.extension.memoized.processor.MemoizedValidator", + "com.google.auto.value.extension.toprettystring.processor.ToPrettyStringValidator", + "com.google.auto.value.processor.AutoAnnotationProcessor", + "com.google.auto.value.processor.AutoBuilderProcessor", + "com.google.auto.value.processor.AutoOneOfProcessor", + "com.google.auto.value.processor.AutoValueBuilderProcessor", + "com.google.auto.value.processor.AutoValueProcessor" + ] + }, + "io.netty:netty-common": { + "reactor.blockhound.integration.BlockHoundIntegration": [ + "io.netty.util.internal.Hidden$NettyBlockHoundIntegration" + ] + } + }, + "version": "2" +} diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.in b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.in new file mode 100644 index 00000000..ffedaf9a --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "module_export", + maven_coordinates = "com.example:module1:0.1", + visibility = ["//:__subpackages__"], + exports = [":module1"], +) diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.out b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.out new file mode 100644 index 00000000..dbde5e60 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/BUILD.out @@ -0,0 +1,20 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "module_export", + maven_coordinates = "com.example:module1:0.1", + visibility = ["//:__subpackages__"], + exports = [":module1"], +) + +java_library( + name = "module1", + srcs = ["Module1.java"], + visibility = [ + "//module1/src/main/java/com/example/module1:__pkg__", + "//module1/src/main/java/com/example/module1/foo:__pkg__", + ], + exports = ["//module1/src/main/java/com/example/module1/foo"], + deps = ["//module1/src/main/java/com/example/module1/foo"], +) diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/Module1.java b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/Module1.java new file mode 100644 index 00000000..17cdb966 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/Module1.java @@ -0,0 +1,13 @@ +package com.example.module1; + +import com.example.module1.foo.Module1Foo; + +public class Module1 { + public static String module(Module1Foo foo) { + return "Module1 + " + foo.nonStaticModule(); + } + + public Module1Foo getFoo() { + return new Module1Foo(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.in b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.out b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.out new file mode 100644 index 00000000..f8442db6 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/BUILD.out @@ -0,0 +1,10 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library( + name = "foo", + srcs = ["Module1Foo.java"], + visibility = [ + "//module1/src/main/java/com/example/module1:__pkg__", + "//module1/src/main/java/com/example/module1/foo:__pkg__", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/Module1Foo.java b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/Module1Foo.java new file mode 100644 index 00000000..f39a474c --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module1/src/main/java/com/example/module1/foo/Module1Foo.java @@ -0,0 +1,11 @@ +package com.example.module1.foo; + +public class Module1Foo { + public static String module() { + return "Module1Foo"; + } + + public String nonStaticModule() { + return "Module1Foo"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.in b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.in new file mode 100644 index 00000000..a3850e8e --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.in @@ -0,0 +1,11 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "module2", + maven_coordinates = "com.example:module2:0.1", + visibility = ["//:__subpackages__"], + exports = [ + # baz should be imported transitively + "//module2/src/main/java/com/example/module2/bar", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.out b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.out new file mode 100644 index 00000000..a3850e8e --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/BUILD.out @@ -0,0 +1,11 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "module2", + maven_coordinates = "com.example:module2:0.1", + visibility = ["//:__subpackages__"], + exports = [ + # baz should be imported transitively + "//module2/src/main/java/com/example/module2/bar", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.in b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.out b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.out new file mode 100644 index 00000000..5e82444c --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/BUILD.out @@ -0,0 +1,15 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library( + name = "bar", + srcs = [ + "DependOnBaz.java", + "Module2Bar.java", + ], + visibility = [ + "//module2/src/main/java/com/example/module2:__pkg__", + "//module2/src/main/java/com/example/module2/bar:__pkg__", + "//module2/src/main/java/com/example/module2/baz:__pkg__", + ], + deps = ["//module2/src/main/java/com/example/module2/baz"], +) diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/DependOnBaz.java b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/DependOnBaz.java new file mode 100644 index 00000000..bef349cf --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/DependOnBaz.java @@ -0,0 +1,9 @@ +package com.example.module2.bar; + +import com.example.module2.baz.Module2Baz; + +public class DependOnBaz { + public static String module() { + return "Module2DependOnBaz: " + Module2Baz.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/Module2Bar.java b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/Module2Bar.java new file mode 100644 index 00000000..cb97a91e --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/bar/Module2Bar.java @@ -0,0 +1,7 @@ +package com.example.module2.bar; + +public class Module2Bar { + public static String module() { + return "Module2Bar" + DependOnBaz.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.in b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.out b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.out new file mode 100644 index 00000000..6aca557b --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/BUILD.out @@ -0,0 +1,11 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library( + name = "baz", + srcs = ["Module2Baz.java"], + visibility = [ + "//module2/src/main/java/com/example/module2:__pkg__", + "//module2/src/main/java/com/example/module2/bar:__pkg__", + "//module2/src/main/java/com/example/module2/baz:__pkg__", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/Module2Baz.java b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/Module2Baz.java new file mode 100644 index 00000000..051643a0 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/module2/src/main/java/com/example/module2/baz/Module2Baz.java @@ -0,0 +1,7 @@ +package com.example.module2.baz; + +public class Module2Baz { + public static String module() { + return "Module2Baz"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.in b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.in new file mode 100644 index 00000000..ab29d0ac --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "nested_export", + maven_coordinates = "com.example:nested:0.1", + visibility = ["//:__subpackages__"], + exports = [":nested"], +) diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.out b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.out new file mode 100644 index 00000000..e74e2d67 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/BUILD.out @@ -0,0 +1,16 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "nested_export", + maven_coordinates = "com.example:nested:0.1", + visibility = ["//:__subpackages__"], + exports = [":nested"], +) + +java_library( + name = "nested", + srcs = ["UseChild.java"], + visibility = ["//nested/src/main/java/com/example/nested:__pkg__"], + deps = ["//nested/src/main/java/com/example/nested/child_export:child_export_export"], +) diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/UseChild.java b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/UseChild.java new file mode 100644 index 00000000..b7928679 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/UseChild.java @@ -0,0 +1,9 @@ +package com.example.nested; + +import com.example.nested.child_export.ChildExport; + +public class UseChild { + public static String module() { + return "Parent of " + ChildExport.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.in b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.in new file mode 100644 index 00000000..578638e7 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "child_export_export", + maven_coordinates = "com.example:nested-child:0.1", + visibility = ["//:__subpackages__"], + exports = [":child_export"], +) diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.out b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.out new file mode 100644 index 00000000..73f68fd1 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/BUILD.out @@ -0,0 +1,15 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "child_export_export", + maven_coordinates = "com.example:nested-child:0.1", + visibility = ["//:__subpackages__"], + exports = [":child_export"], +) + +java_library( + name = "child_export", + srcs = ["ChildExport.java"], + visibility = ["//nested/src/main/java/com/example/nested/child_export:__pkg__"], +) diff --git a/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/ChildExport.java b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/ChildExport.java new file mode 100644 index 00000000..946ef9a4 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/nested/src/main/java/com/example/nested/child_export/ChildExport.java @@ -0,0 +1,7 @@ +package com.example.nested.child_export; + +public class ChildExport { + public static String module() { + return "ChildExport"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.in b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.in new file mode 100644 index 00000000..ae35c5fe --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.in @@ -0,0 +1,9 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "plain_deps_export", + srcs = ["PlainDep.java"], + maven_coordinates = "com.example:plain_deps:0.1", + visibility = ["//:__subpackages__"], + deps = ["//other_deps/src/main/java/com/example/other_deps/plain_deps/dep"], +) diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.out b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.out new file mode 100644 index 00000000..4dbfed8a --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/BUILD.out @@ -0,0 +1,18 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "plain_deps_export", + srcs = ["PlainDep.java"], + maven_coordinates = "com.example:plain_deps:0.1", + visibility = ["//:__subpackages__"], + deps = ["//other_deps/src/main/java/com/example/other_deps/plain_deps/dep"], +) + +java_library( + name = "plain_deps", + srcs = ["PlainDep.java"], + visibility = ["//:__subpackages__"], + deps = [":plain_deps_export"], +) + diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/PlainDep.java b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/PlainDep.java new file mode 100644 index 00000000..b12c2711 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/PlainDep.java @@ -0,0 +1,9 @@ +package com.example.other_deps.plain_deps; + +import com.example.other_deps.plain_deps.dep.PlainDep; + +public class PlainSrc { + public static String module() { + return "PlainSrc + " + PlainDep.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.in b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.out b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.out new file mode 100644 index 00000000..ee2a0edb --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/BUILD.out @@ -0,0 +1,11 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library( + name = "dep", + srcs = ["PlainDep.java"], + visibility = [ + "//other_deps/src/main/java/com/example/other_deps/plain_deps:__pkg__", + "//other_deps/src/main/java/com/example/other_deps/plain_deps/dep:__pkg__", + ], +) + diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/PlainDep.java b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/PlainDep.java new file mode 100644 index 00000000..101c0eae --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/dep/PlainDep.java @@ -0,0 +1,7 @@ +package com.example.other_deps.plain_deps.dep; + +public class PlainDep { + public static String module() { + return "PlainDep"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt new file mode 100644 index 00000000..dae71f90 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt @@ -0,0 +1 @@ +{"level":"error","label":"//other_deps/src/main/java/com/example/other_deps/plain_deps:plain_deps_export","message":"java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`"} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.in b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.in new file mode 100644 index 00000000..d179a3cf --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "runtime_deps_export", + maven_coordinates = "com.example:runtime_deps:0.1", + visibility = ["//:__subpackages__"], + runtime_deps = [":runtime_deps"], +) diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.out b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.out new file mode 100644 index 00000000..908fc8b7 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/BUILD.out @@ -0,0 +1,15 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "runtime_deps_export", + maven_coordinates = "com.example:runtime_deps:0.1", + visibility = ["//:__subpackages__"], + runtime_deps = [":runtime_deps"], +) + +java_library( + name = "runtime", + srcs = ["RuntimeDep.java"], + visibility = ["//:__subpackages__"], +) diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/RuntimeDep.java b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/RuntimeDep.java new file mode 100644 index 00000000..e0382698 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/runtime/RuntimeDep.java @@ -0,0 +1,7 @@ +package com.example.other_deps.runtime; + +public class RuntimeDep { + public static String module() { + return "RuntimeDep"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.in b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.in new file mode 100644 index 00000000..7688bc0c --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.in @@ -0,0 +1,8 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "third_party_export", + maven_coordinates = "com.example:third_party:0.1", + visibility = ["//:__subpackages__"], + exports = [":third_party"], +) diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.out b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.out new file mode 100644 index 00000000..ecdb9009 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/BUILD.out @@ -0,0 +1,16 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") +load("@rules_java//java:defs.bzl", "java_library") + +java_export( + name = "third_party_export", + maven_coordinates = "com.example:third_party:0.1", + visibility = ["//:__subpackages__"], + exports = [":third_party"], +) + +java_library( + name = "third_party", + srcs = ["ThirdPartyDeps.java"], + visibility = ["//other_deps/src/main/java/com/example/other_deps/third_party:__pkg__"], + deps = ["@maven//:com_google_guava_guava"], +) diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/ThirdPartyDeps.java b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/ThirdPartyDeps.java new file mode 100644 index 00000000..df1014b6 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/third_party/ThirdPartyDeps.java @@ -0,0 +1,13 @@ +package com.example.other_deps.third_party; + +import java.nio.file.Paths; +import com.google.common.collect.ImmutableList; + +public class ThirdPartyDeps { + public static String module() { + return String.format( + "ThirdParty(stdlib=%s, thirdParty=%s)", + Paths.get("/tmp/path"), + ImmutableList.of("Hello", "World")); + } +} diff --git a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.in b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out new file mode 100644 index 00000000..1e21756a --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out @@ -0,0 +1,24 @@ +load("@rules_java//java:defs.bzl", "java_binary", "java_library") + +java_library( + name = "user", + srcs = ["UseAllModules.java"], + visibility = ["//:__subpackages__"], + deps = [ + "//export_depending_on_different_package/src/main/java/com/example/export_depending_on_different_package/export:export_export", + "//module1/src/main/java/com/example/module1:module_export", + "//module2/src/main/java/com/example/module2", + "//nested/src/main/java/com/example/nested:nested_export", + "//nested/src/main/java/com/example/nested/child_export:child_export_export", + "//other_deps/src/main/java/com/example/other_deps/plain_deps", + "//other_deps/src/main/java/com/example/other_deps/runtime", + "//other_deps/src/main/java/com/example/other_deps/third_party:third_party_export", + ], +) + +java_binary( + name = "UseAllModules", + main_class = "com.example.user.UseAllModules", + visibility = ["//visibility:public"], + runtime_deps = [":user"], +) diff --git a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java new file mode 100644 index 00000000..3db83ae8 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java @@ -0,0 +1,27 @@ +package com.example.user; + +import com.example.module1.Module1; +import com.example.module1.foo.Module1Foo; +import com.example.module2.bar.Module2Bar; +import com.example.module2.baz.Module2Baz; +import com.example.nested.UseChild; +import com.example.nested.child_export.ChildExport; +import com.example.export_depending_on_different_package.export.DependOnLib; +import com.example.other_deps.runtime.RuntimeDep; +import com.example.other_deps.plain_deps.PlainDep; +import com.example.other_deps.third_party.ThirdPartyDeps; + +public class UseAllModules { + public static void main(String[] args) { + System.out.println(Module1.module(new Module1Foo())); + System.out.println(Module1Foo.module()); + System.out.println(Module2Bar.module()); + System.out.println(Module2Baz.module()); + System.out.println(UseChild.module()); + System.out.println(ChildExport.module()); + System.out.println(DependOnLib.module()); + System.out.println(PlainDep.module()); + System.out.println(RuntimeDep.module()); + System.out.println(ThirdPartyDeps.module()); + } +} From c077f84964ea8adda802abf80ef08799c0b2ddae Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Wed, 25 Jun 2025 07:50:00 +0100 Subject: [PATCH 05/11] refactor: Remove extra parameter in calculateImportsForJavaExport --- .../java_export_index/java_export_index.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index 28c1f89b..11284633 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -79,26 +79,26 @@ func (jei *JavaExportIndex) ProcessResolveInputForRule(file *rule.File, r *rule. // - Gather all the transitive dependencies by traversing the `ResolveInput`s of relevant targets. // - With that information, populate the map of `labelToJavaExport`. func (jei *JavaExportIndex) FinishBeforeResolve() { - for javaExportLabel, javaExport := range jei.javaExports { - jei.calculateImportsForJavaExport(javaExportLabel, javaExport) + for _, javaExport := range jei.javaExports { + jei.calculateImportsForJavaExport(javaExport) } jei.readyForResolve = true } -func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExportLabel label.Label, javaExport *JavaExportResolveInfo) { +func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExportResolveInfo) { var parseErrors []error - deps, errors := attrLabels("deps", javaExport.Rule, javaExportLabel) + deps, errors := attrLabels("deps", javaExport.Rule, javaExport.Label) parseErrors = append(parseErrors, errors...) - exports, errors := attrLabels("exports", javaExport.Rule, javaExportLabel) + exports, errors := attrLabels("exports", javaExport.Rule, javaExport.Label) parseErrors = append(parseErrors, errors...) - runtimeDeps, errors := attrLabels("runtime_deps", javaExport.Rule, javaExportLabel) + runtimeDeps, errors := attrLabels("runtime_deps", javaExport.Rule, javaExport.Label) parseErrors = append(parseErrors, errors...) if len(parseErrors) > 0 { jei.logger.Error(). Errs("errors", errors). - Msgf("Errors parsing labels from fields of %s", javaExportLabel.String()) + Msgf("Errors parsing labels from fields of %s", javaExport.Label.String()) } labelsToVisit := make([]label.Label, len(deps)) @@ -118,7 +118,7 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExportLabel label. labelsToVisit = labelsToVisit[1:] // Visit the dependency - jei.labelToJavaExport[dep] = javaExportLabel + jei.labelToJavaExport[dep] = javaExport.Label visibilityLbl := label.New("", dep.Pkg, "__pkg__") javaExport.InternalVisibility.Add(visibilityLbl) From c2dd3e0417aca1e341b64a33756e879d5bc085de Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Wed, 25 Jun 2025 08:54:33 +0100 Subject: [PATCH 06/11] fix: Respect repository_name and readyForResolve --- java/gazelle/generate.go | 8 +-- java/gazelle/lang.go | 2 +- .../java_export_index/java_export_index.go | 50 +++++++++++++------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/java/gazelle/generate.go b/java/gazelle/generate.go index e1875fed..3e3e9340 100644 --- a/java/gazelle/generate.go +++ b/java/gazelle/generate.go @@ -200,7 +200,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes } if productionJavaFiles.Len() > 0 { - l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, annotationProcessorClasses, false, javaLibraryKind, &res, cfg) + l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, annotationProcessorClasses, false, javaLibraryKind, &res, cfg, args.Config.RepoName) } var testHelperJavaClasses *sorted_set.SortedSet[types.ClassName] @@ -236,7 +236,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes testJavaImportsWithHelpers.Add(tf.pkg) srcs = append(srcs, tf.pathRelativeToBazelWorkspaceRoot) } - l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, annotationProcessorClasses, true, javaLibraryKind, &res, cfg) + l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, annotationProcessorClasses, true, javaLibraryKind, &res, cfg, args.Config.RepoName) } } @@ -471,7 +471,7 @@ func accumulateJavaFile(cfg *javaconfig.Config, testJavaFiles, testHelperJavaFil } } -func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace, name string, srcsRelativeToBazelWorkspace []string, packages, imports, exports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult, cfg *javaconfig.Config) { +func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace, name string, srcsRelativeToBazelWorkspace []string, packages, imports, exports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult, cfg *javaconfig.Config, repoName string) { const ruleKind = "java_library" r := rule.NewRule(ruleKind, name) @@ -510,7 +510,7 @@ func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBa res.Imports = append(res.Imports, resolveInput) if cfg.ResolveToJavaExports() { - l.javaExportIndex.ProcessResolveInputForRule(file, r, resolveInput) + l.javaExportIndex.ProcessResolveInputForRule(repoName, file, r, resolveInput) } } diff --git a/java/gazelle/lang.go b/java/gazelle/lang.go index c1bd070b..3bd825b6 100644 --- a/java/gazelle/lang.go +++ b/java/gazelle/lang.go @@ -214,7 +214,7 @@ func (l javaLang) Fix(c *config.Config, f *rule.File) { if packageConfig != nil && packageConfig.ResolveToJavaExports() { for _, r := range f.Rules { if r.Kind() == "java_export" { - l.javaExportIndex.RecordJavaExport(r, f) + l.javaExportIndex.RecordJavaExport(c.RepoName, r, f) } } } diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index 11284633..fcf68877 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -17,8 +17,8 @@ type JavaExportResolveInfo struct { InternalVisibility *sorted_set.SortedSet[label.Label] } -func NewJavaExportResolveInfoFromRule(r *rule.Rule, file *rule.File) *JavaExportResolveInfo { - lbl := label.New("", file.Pkg, r.Name()) +func NewJavaExportResolveInfoFromRule(repoName string, r *rule.Rule, file *rule.File) *JavaExportResolveInfo { + lbl := label.New(repoName, file.Pkg, r.Name()) exportPackageVisibility := label.New("", file.Pkg, "__pkg__") return &JavaExportResolveInfo{ Rule: r, @@ -30,6 +30,7 @@ func NewJavaExportResolveInfoFromRule(r *rule.Rule, file *rule.File) *JavaExport // JavaExportIndex holds information about `java_export` targets and which symbols they make available, // so that other java targets can depend on the right `java_export` instead of fine-grained dependencies. type JavaExportIndex struct { + // langName and logger are fields we must store from the language.Language, so that we can use them in the implementation. langName string logger zerolog.Logger @@ -62,12 +63,12 @@ func NewJavaExportIndex(langName string, logger zerolog.Logger) *JavaExportIndex } } -func (jei *JavaExportIndex) ProcessResolveInputForRule(file *rule.File, r *rule.Rule, resolveInput types.ResolveInput) { +func (jei *JavaExportIndex) ProcessResolveInputForRule(repoName string, file *rule.File, r *rule.Rule, resolveInput types.ResolveInput) { pkg := "" if file != nil { pkg = file.Pkg } - lbl := label.New("", pkg, r.Name()) + lbl := label.New(repoName, pkg, r.Name()) jei.labelsToResolveInputs[lbl] = resolveInput for _, javaPackage := range resolveInput.PackageNames.SortedSlice() { @@ -75,6 +76,17 @@ func (jei *JavaExportIndex) ProcessResolveInputForRule(file *rule.File, r *rule. } } +func (jei *JavaExportIndex) RecordJavaExport(repoName string, r *rule.Rule, f *rule.File) { + lbl := label.New(repoName, f.Pkg, r.Name()) + srcs := r.AttrStrings("srcs") + if len(srcs) > 0 { + jei.logger.Error(). + Str("label", lbl.String()). + Msg("java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`") + } + jei.javaExports[lbl] = NewJavaExportResolveInfoFromRule(repoName, r, f) +} + // FinishBeforeResolve processes all the `java_exports` we've recorded when traversing the repository, to: // - Gather all the transitive dependencies by traversing the `ResolveInput`s of relevant targets. // - With that information, populate the map of `labelToJavaExport`. @@ -132,7 +144,7 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") continue } - _, isExportedByAnotherJavaExport := jei.IsExportedByJavaExport(lblToVisit) + _, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lblToVisit) if isExportedByAnotherJavaExport { continue } @@ -144,23 +156,23 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport } } -func (jei *JavaExportIndex) RecordJavaExport(r *rule.Rule, f *rule.File) { - lbl := label.New("", f.Pkg, r.Name()) - srcs := r.AttrStrings("srcs") - if len(srcs) > 0 { - jei.logger.Error(). - Str("label", lbl.String()). - Msg("java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`") - } - jei.javaExports[lbl] = NewJavaExportResolveInfoFromRule(r, f) -} - func (jei *JavaExportIndex) IsJavaExport(lbl label.Label) bool { _, is := jei.javaExports[lbl] return is } func (jei *JavaExportIndex) IsExportedByJavaExport(lbl label.Label) (*JavaExportResolveInfo, bool) { + if !jei.readyForResolve { + jei.logger.Fatal(). + Str("label", lbl.String()). + Msg("Tried to get check if label is exported by a java_export before the java export index was ready for resolve. This is likely an internal bug, please contact the maintainers.") + } + return jei.isExportedByJavaExport(lbl) +} + +// isExportedByJavaExport is the private version of IsExportedByJavaExport. +// It exists so that we can call it while we finish the index, while it's still not ready for resolution. +func (jei *JavaExportIndex) isExportedByJavaExport(lbl label.Label) (*JavaExportResolveInfo, bool) { exportLbl, isExported := jei.labelToJavaExport[lbl] if isExported { export, exists := jei.javaExports[exportLbl] @@ -176,6 +188,11 @@ func (jei *JavaExportIndex) IsExportedByJavaExport(lbl label.Label) (*JavaExport } func (jei *JavaExportIndex) VisibilityForLabel(lbl label.Label) *sorted_set.SortedSet[label.Label] { + if !jei.readyForResolve { + jei.logger.Fatal(). + Str("target", lbl.String()). + Msg("Tried to get visibility for target before the java export index was ready for resolve. This is likely an internal bug, please contact the maintainers.") + } regularReturn := sorted_set.NewSortedSetFn[label.Label]([]label.Label{label.New("", "", "__subpackages__")}, sorted_set.LabelLess) if jei.IsJavaExport(lbl) { return regularReturn @@ -202,6 +219,7 @@ func attrLabels(attr string, r *rule.Rule, ruleLabel label.Label) ([]label.Label lbl.Pkg = ruleLabel.Pkg lbl.Relative = false } + lbl.Repo = ruleLabel.Repo deps = append(deps, lbl) } return deps, errors From 2649ca5f0867e511e9b752e0d8b2ac10e5e49577 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Wed, 25 Jun 2025 08:57:35 +0100 Subject: [PATCH 07/11] run format --- java/gazelle/lang.go | 2 +- java/gazelle/testdata/java_export_targets/MODULE.bazel | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/java/gazelle/lang.go b/java/gazelle/lang.go index 3bd825b6..98348d85 100644 --- a/java/gazelle/lang.go +++ b/java/gazelle/lang.go @@ -2,9 +2,9 @@ package gazelle import ( "context" - "github.com/bazel-contrib/rules_jvm/java/gazelle/javaconfig" "os" + "github.com/bazel-contrib/rules_jvm/java/gazelle/javaconfig" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/java" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/java_export_index" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/javaparser" diff --git a/java/gazelle/testdata/java_export_targets/MODULE.bazel b/java/gazelle/testdata/java_export_targets/MODULE.bazel index 22d41d62..a0b153e9 100644 --- a/java/gazelle/testdata/java_export_targets/MODULE.bazel +++ b/java/gazelle/testdata/java_export_targets/MODULE.bazel @@ -1,17 +1,15 @@ bazel_dep(name = "rules_java", version = "8.13.0") bazel_dep(name = "contrib_rules_jvm", version = "0.29.0") - bazel_dep(name = "rules_jvm_external", version = "6.7") -maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( artifacts = [ "com.google.guava:guava:33.4.6-jre", ], + lock_file = "//:maven_install.json", repositories = [ "https://repo1.maven.org/maven2", ], - lock_file = "//:maven_install.json", ) - use_repo(maven, "maven") From af701701701d51e85d601034429897a552649666 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Thu, 26 Jun 2025 14:59:50 +0100 Subject: [PATCH 08/11] Enable java_export resolution by default --- java/gazelle/javaconfig/config.go | 4 ++-- java/gazelle/private/types/types.go | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/java/gazelle/javaconfig/config.go b/java/gazelle/javaconfig/config.go index fe8f6108..3604f3e4 100644 --- a/java/gazelle/javaconfig/config.go +++ b/java/gazelle/javaconfig/config.go @@ -57,7 +57,7 @@ const ( // JavaResolveToJavaExports tells the code generator to favour resolving dependencies to java_exports where possible. // If enabled, generated libraries will try to depend on java_exports targets that export a given package, instead of the underlying library. // This allows monorepos to closely match a traditional Gradle/Maven model where subprojects are published in jars. - // Can be either "true" or "false". Defaults to "false". + // Can be either "true" or "false". Defaults to "true". // Inherited by children packages, can only be set at the root of the repository. JavaResolveToJavaExports = "java_resolve_to_java_exports" ) @@ -137,7 +137,7 @@ func New(repoRoot string) *Config { extensionEnabled: true, isModuleRoot: false, generateProto: true, - resolveToJavaExports: types.NewLateInit[bool](false), + resolveToJavaExports: types.NewLateInit[bool](true), mavenInstallFile: "maven_install.json", moduleGranularity: "package", repoRoot: repoRoot, diff --git a/java/gazelle/private/types/types.go b/java/gazelle/private/types/types.go index b6d9fecf..444f98b0 100644 --- a/java/gazelle/private/types/types.go +++ b/java/gazelle/private/types/types.go @@ -167,6 +167,9 @@ func ParseResolvableJavaPackage(s string) (*ResolvableJavaPackage, error) { }, nil } +// LateInit represents a value that can be initialized exactly once. +// It can still be accessed before it's initialized, but once initialized its value cannot change. +// Useful for configuration that "will be initialized at some point, but we're not sure when". type LateInit[T any] struct { value T initialized bool From 6d8e157a4378f66871a9bcfb9b7c9e4fd86f78ff Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Thu, 26 Jun 2025 17:08:46 +0100 Subject: [PATCH 09/11] fix tests and clean up --- java/gazelle/generate.go | 2 +- java/gazelle/lang.go | 2 +- .../java_export_index/java_export_index.go | 24 +++++++++++++++---- java/gazelle/resolve.go | 17 ++++++------- java/gazelle/resolve_test.go | 1 + 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/java/gazelle/generate.go b/java/gazelle/generate.go index 3e3e9340..f32aa84c 100644 --- a/java/gazelle/generate.go +++ b/java/gazelle/generate.go @@ -510,7 +510,7 @@ func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBa res.Imports = append(res.Imports, resolveInput) if cfg.ResolveToJavaExports() { - l.javaExportIndex.ProcessResolveInputForRule(repoName, file, r, resolveInput) + l.javaExportIndex.RecordRuleWithResolveInput(repoName, file, r, resolveInput) } } diff --git a/java/gazelle/lang.go b/java/gazelle/lang.go index 98348d85..74bea1fb 100644 --- a/java/gazelle/lang.go +++ b/java/gazelle/lang.go @@ -222,7 +222,7 @@ func (l javaLang) Fix(c *config.Config, f *rule.File) { func (l javaLang) DoneGeneratingRules() { l.parser.ServerManager().Shutdown() - l.javaExportIndex.FinishBeforeResolve() + l.javaExportIndex.FinalizeIndex() } func (l javaLang) AfterResolvingDeps(_ context.Context) { diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index fcf68877..f49ef24e 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -63,12 +63,19 @@ func NewJavaExportIndex(langName string, logger zerolog.Logger) *JavaExportIndex } } -func (jei *JavaExportIndex) ProcessResolveInputForRule(repoName string, file *rule.File, r *rule.Rule, resolveInput types.ResolveInput) { +// RecordRuleWithResolveInput lets the index know about a rule that might declare some packages, and might depend on some other packages later. +// Must be called before FinalizeIndex. +func (jei *JavaExportIndex) RecordRuleWithResolveInput(repoName string, file *rule.File, r *rule.Rule, resolveInput types.ResolveInput) { pkg := "" if file != nil { pkg = file.Pkg } lbl := label.New(repoName, pkg, r.Name()) + if jei.readyForResolve { + jei.logger.Fatal(). + Str("label", lbl.String()). + Msg("Tried to record rule after the index was finalized. This is likely an internal bug, please contact the maintainers.") + } jei.labelsToResolveInputs[lbl] = resolveInput for _, javaPackage := range resolveInput.PackageNames.SortedSlice() { @@ -76,8 +83,15 @@ func (jei *JavaExportIndex) ProcessResolveInputForRule(repoName string, file *ru } } +// RecordJavaExport lets the index know about a java_export rule, for later resolution. +// Must be called before FinalizeIndex. func (jei *JavaExportIndex) RecordJavaExport(repoName string, r *rule.Rule, f *rule.File) { lbl := label.New(repoName, f.Pkg, r.Name()) + if jei.readyForResolve { + jei.logger.Fatal(). + Str("label", lbl.String()). + Msg("Tried to record java_export after the index was finalized. This is likely an internal bug, please contact the maintainers.") + } srcs := r.AttrStrings("srcs") if len(srcs) > 0 { jei.logger.Error(). @@ -87,10 +101,10 @@ func (jei *JavaExportIndex) RecordJavaExport(repoName string, r *rule.Rule, f *r jei.javaExports[lbl] = NewJavaExportResolveInfoFromRule(repoName, r, f) } -// FinishBeforeResolve processes all the `java_exports` we've recorded when traversing the repository, to: +// FinalizeIndex processes all the `java_exports` we've recorded when traversing the repository, to: // - Gather all the transitive dependencies by traversing the `ResolveInput`s of relevant targets. // - With that information, populate the map of `labelToJavaExport`. -func (jei *JavaExportIndex) FinishBeforeResolve() { +func (jei *JavaExportIndex) FinalizeIndex() { for _, javaExport := range jei.javaExports { jei.calculateImportsForJavaExport(javaExport) } @@ -187,6 +201,8 @@ func (jei *JavaExportIndex) isExportedByJavaExport(lbl label.Label) (*JavaExport return nil, false } +// VisibilityForLabel returns the visibility that a target label.Label should have, according to the JavaExportIndex. +// Returns nil if the JavaExportIndex doesn't have an opinion on what visibility a target should have. func (jei *JavaExportIndex) VisibilityForLabel(lbl label.Label) *sorted_set.SortedSet[label.Label] { if !jei.readyForResolve { jei.logger.Fatal(). @@ -203,7 +219,7 @@ func (jei *JavaExportIndex) VisibilityForLabel(lbl label.Label) *sorted_set.Sort return exporter.InternalVisibility } - return regularReturn + return nil } func attrLabels(attr string, r *rule.Rule, ruleLabel label.Label) ([]label.Label, []error) { diff --git a/java/gazelle/resolve.go b/java/gazelle/resolve.go index bdd8dc35..f97d4ec0 100644 --- a/java/gazelle/resolve.go +++ b/java/gazelle/resolve.go @@ -102,15 +102,16 @@ func (jr *Resolver) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.Re // If the current library is exported under a `java_export`, it shouldn't be visible for targets outside the java_export. if packageConfig.ResolveToJavaExports() && isJavaLibrary(r.Kind()) { visibility := jr.lang.javaExportIndex.VisibilityForLabel(from) - - var asStrings []string - for _, vis := range visibility.SortedSlice() { - asStrings = append(asStrings, vis.String()) + if visibility != nil { + var asStrings []string + for _, vis := range visibility.SortedSlice() { + asStrings = append(asStrings, vis.String()) + } + // The rule attr replacement code is buggy, because while in `rule.SetAttr` we can replace the RHS of the expression, attr.val is always unchanged. I suspect it has to do with pointer magic. + // Fixed in https://github.com/bazel-contrib/bazel-gazelle/issues/2045 + r.DelAttr("visibility") + r.SetAttr("visibility", asStrings) } - // The rule attr replacement code is buggy, because while in `rule.SetAttr` we can replace the RHS of the expression, attr.val is always unchanged. I suspect it has to do with pointer magic. - // Fixed in https://github.com/bazel-contrib/bazel-gazelle/issues/2045 - r.DelAttr("visibility") - r.SetAttr("visibility", asStrings) } jr.populateAttr(c, packageConfig, r, "deps", resolveInput.ImportedPackageNames, ix, isTestRule, from, resolveInput.PackageNames) diff --git a/java/gazelle/resolve_test.go b/java/gazelle/resolve_test.go index 54761fd6..505ac4c3 100644 --- a/java/gazelle/resolve_test.go +++ b/java/gazelle/resolve_test.go @@ -257,6 +257,7 @@ func InitTestResolversAndExtensions(langs []language.Language) (mapResolver, []i // TODO There has to be a better way to make this generic. if jLang, ok := lang.(*javaLang); ok { jLang.mavenResolver = NewTestMavenResolver() + jLang.javaExportIndex.FinalizeIndex() } for kind := range lang.Kinds() { From 5a2767f0536d3b34a5ca358fe3e91ced422ce2cb Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Mon, 30 Jun 2025 11:49:32 +0100 Subject: [PATCH 10/11] Add test case for review comment --- .../java_export_index/java_export_index.go | 55 ++++++++++++++++++- .../testdata/java_export_targets/README.md | 24 ++++++++ .../java_export_targets/expectedStderr.txt | 3 + .../other_deps/plain_deps/expectedStderr.txt | 1 - .../main/java/com/example/shared_dep/BUILD.in | 0 .../com/example/shared_dep/Dependent.java | 9 +++ .../example/shared_dep/export_one/BUILD.in | 10 ++++ .../example/shared_dep/export_one/BUILD.out | 10 ++++ .../example/shared_dep/export_two/BUILD.in | 10 ++++ .../example/shared_dep/export_two/BUILD.out | 10 ++++ .../example/shared_dep/shared_dep/BUILD.in | 0 .../shared_dep/shared_dep/SharedDep.java | 7 +++ .../src/main/java/com/example/user/BUILD.out | 1 + .../java/com/example/user/UseAllModules.java | 2 + 14 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 java/gazelle/testdata/java_export_targets/README.md create mode 100644 java/gazelle/testdata/java_export_targets/expectedStderr.txt delete mode 100644 java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/Dependent.java create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.out create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/BUILD.in create mode 100644 java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/SharedDep.java diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index f49ef24e..10b55447 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -6,6 +6,7 @@ import ( "github.com/bazelbuild/bazel-gazelle/label" "github.com/bazelbuild/bazel-gazelle/rule" "github.com/rs/zerolog" + "sort" ) // JavaExportResolveInfo captures metadata about a java_export rule. @@ -104,15 +105,37 @@ func (jei *JavaExportIndex) RecordJavaExport(repoName string, r *rule.Rule, f *r // FinalizeIndex processes all the `java_exports` we've recorded when traversing the repository, to: // - Gather all the transitive dependencies by traversing the `ResolveInput`s of relevant targets. // - With that information, populate the map of `labelToJavaExport`. +type exportConflict struct { + dep label.Label + wantedToExportFrom label.Label + alreadyExportedFrom label.Label +} + func (jei *JavaExportIndex) FinalizeIndex() { + + exportConflicts := sorted_set.NewSortedSetFn[exportConflict]([]exportConflict{}, func(a, b exportConflict) bool { + return sorted_set.LabelLess(a.wantedToExportFrom, b.wantedToExportFrom) + }) + for _, javaExport := range jei.javaExports { - jei.calculateImportsForJavaExport(javaExport) + jei.calculateImportsForJavaExport(javaExport, exportConflicts) + } + + // We need to collect and sort the conflicts to get a deterministic ordering of output for tests. + for _, conflict := range exportConflicts.SortedSlice() { + conflictingExports := []string{conflict.wantedToExportFrom.String(), conflict.alreadyExportedFrom.String()} + sort.Strings(conflictingExports) + + jei.logger.Error(). + Str("dependency", conflict.dep.String()). + Strs("java_exports", conflictingExports). + Msg("Two `java_export` targets want to export the same dependency. This can lead to incorrect results, please disambiguate, e.g. by having export depend on other export explicitly.") } jei.readyForResolve = true } -func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExportResolveInfo) { +func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExportResolveInfo, conflicts *sorted_set.SortedSet[exportConflict]) { var parseErrors []error deps, errors := attrLabels("deps", javaExport.Rule, javaExport.Label) parseErrors = append(parseErrors, errors...) @@ -132,6 +155,20 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport labelsToVisit = append(labelsToVisit, exports...) labelsToVisit = append(labelsToVisit, runtimeDeps...) + for _, lbl := range labelsToVisit { + if jei.IsJavaExport(lbl) { + continue + } + exportingExport, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lbl) + if isExportedByAnotherJavaExport { + conflicts.Add(exportConflict{ + dep: lbl, + wantedToExportFrom: javaExport.Label, + alreadyExportedFrom: exportingExport.Label, + }) + } + } + transitiveDeps := make(map[label.Label]bool) for _, depLabel := range labelsToVisit { transitiveDeps[depLabel] = true @@ -143,6 +180,10 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport dep := labelsToVisit[0] labelsToVisit = labelsToVisit[1:] + if jei.IsJavaExport(dep) { + continue + } + // Visit the dependency jei.labelToJavaExport[dep] = javaExport.Label visibilityLbl := label.New("", dep.Pkg, "__pkg__") @@ -158,8 +199,16 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") continue } - _, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lblToVisit) + if jei.IsJavaExport(lblToVisit) { + continue + } + exportingExport, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lblToVisit) if isExportedByAnotherJavaExport { + conflicts.Add(exportConflict{ + dep: lblToVisit, + wantedToExportFrom: javaExport.Label, + alreadyExportedFrom: exportingExport.Label, + }) continue } if ok := transitiveDeps[lblToVisit]; !ok { diff --git a/java/gazelle/testdata/java_export_targets/README.md b/java/gazelle/testdata/java_export_targets/README.md new file mode 100644 index 00000000..8ee535fc --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/README.md @@ -0,0 +1,24 @@ +Tests checking that different configurations of `java_export` targets are handled correctly. + +## Subdirectory: `user` + +This is the code that makes use of all the dependencies. +If you're reading these tests for the first time, it's the best place to start. + +## Subdirectory: `shared_dep` + +This test case tests that when two `java_exports` export the same package, an appropriate error message is displayed. +Let's say we have the following repository: + +```starlark +java_library(name = "A") +java_export(name = "X", exports = [":B"]) +java_export(name = "Y", exports = [":B"]) +java_library(name = "B") +``` + +Then if `:A` wants to depend on `:B`, it has to choose whether it should depend on `:X` or `:Y`. +The implementation picks whatever `java_export` was processed first, based on Gazelle's directory order traversal. +Because this traversal is not deterministic, we can't write deterministic `BUILD.out` files for either `//shared_dep/src/main/java/com/example/shared_dep:BUILD.out` or `//shared_dep/s/m/j/c/e/shared_dep/shared_dep:BUILD.out`. + +## Subdirectory: `nested` diff --git a/java/gazelle/testdata/java_export_targets/expectedStderr.txt b/java/gazelle/testdata/java_export_targets/expectedStderr.txt new file mode 100644 index 00000000..25e47cff --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/expectedStderr.txt @@ -0,0 +1,3 @@ +{"level":"error","label":"//other_deps/src/main/java/com/example/other_deps/plain_deps:plain_deps_export","message":"java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`"} +{"level":"error","dependency":"//nested/src/main/java/com/example/nested/child_export","java_exports":["//nested/src/main/java/com/example/nested/child_export:child_export_export","//nested/src/main/java/com/example/nested:nested_export"],"message":"Two `java_export` targets want to export the same dependency. This can lead to incorrect results, please disambiguate, e.g. by having export depend on other export explicitly."} +{"level":"error","dependency":"//shared_dep/src/main/java/com/example/shared_dep/shared_dep","java_exports":["//shared_dep/src/main/java/com/example/shared_dep/export_one","//shared_dep/src/main/java/com/example/shared_dep/export_two"],"message":"Two `java_export` targets want to export the same dependency. This can lead to incorrect results, please disambiguate, e.g. by having export depend on other export explicitly."} diff --git a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt b/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt deleted file mode 100644 index dae71f90..00000000 --- a/java/gazelle/testdata/java_export_targets/other_deps/src/main/java/com/example/other_deps/plain_deps/expectedStderr.txt +++ /dev/null @@ -1 +0,0 @@ -{"level":"error","label":"//other_deps/src/main/java/com/example/other_deps/plain_deps:plain_deps_export","message":"java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`"} diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/BUILD.in b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/Dependent.java b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/Dependent.java new file mode 100644 index 00000000..a09d9835 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/Dependent.java @@ -0,0 +1,9 @@ +package com.example.shared_dep; + +import com.example.shared_deps.shared_dep.SharedDep; + +public class Dependent { + public static String module() { + return "Dependent +" + SharedDep.module(); + } +} diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.in b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.in new file mode 100644 index 00000000..4d9e8743 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.in @@ -0,0 +1,10 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "export_one", + maven_coordinates = "com.example:shared_dep_one:0.1", + visibility = ["//:__subpackages__"], + exports = [ + "//shared_dep/src/main/java/com/example/shared_dep/shared_dep", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.out b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.out new file mode 100644 index 00000000..4d9e8743 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_one/BUILD.out @@ -0,0 +1,10 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "export_one", + maven_coordinates = "com.example:shared_dep_one:0.1", + visibility = ["//:__subpackages__"], + exports = [ + "//shared_dep/src/main/java/com/example/shared_dep/shared_dep", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.in b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.in new file mode 100644 index 00000000..54b2ba59 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.in @@ -0,0 +1,10 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "export_two", + maven_coordinates = "com.example:shared_dep_two:0.1", + visibility = ["//:__subpackages__"], + exports = [ + "//shared_dep/src/main/java/com/example/shared_dep/shared_dep", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.out b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.out new file mode 100644 index 00000000..54b2ba59 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/export_two/BUILD.out @@ -0,0 +1,10 @@ +load("@contrib_rules_jvm//java:defs.bzl", "java_export") + +java_export( + name = "export_two", + maven_coordinates = "com.example:shared_dep_two:0.1", + visibility = ["//:__subpackages__"], + exports = [ + "//shared_dep/src/main/java/com/example/shared_dep/shared_dep", + ], +) diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/BUILD.in b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/BUILD.in new file mode 100644 index 00000000..e69de29b diff --git a/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/SharedDep.java b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/SharedDep.java new file mode 100644 index 00000000..568ed803 --- /dev/null +++ b/java/gazelle/testdata/java_export_targets/shared_dep/src/main/java/com/example/shared_dep/shared_dep/SharedDep.java @@ -0,0 +1,7 @@ +package com.example.shared_deps.shared_dep; + +public class SharedDep { + public static String module() { + return "SharedDep"; + } +} diff --git a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out index 1e21756a..582fbe82 100644 --- a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out +++ b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/BUILD.out @@ -13,6 +13,7 @@ java_library( "//other_deps/src/main/java/com/example/other_deps/plain_deps", "//other_deps/src/main/java/com/example/other_deps/runtime", "//other_deps/src/main/java/com/example/other_deps/third_party:third_party_export", + "//shared_dep/src/main/java/com/example/shared_dep", ], ) diff --git a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java index 3db83ae8..5ec26da6 100644 --- a/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java +++ b/java/gazelle/testdata/java_export_targets/user/src/main/java/com/example/user/UseAllModules.java @@ -10,6 +10,7 @@ import com.example.other_deps.runtime.RuntimeDep; import com.example.other_deps.plain_deps.PlainDep; import com.example.other_deps.third_party.ThirdPartyDeps; +import com.example.shared_dep.Dependent; public class UseAllModules { public static void main(String[] args) { @@ -23,5 +24,6 @@ public static void main(String[] args) { System.out.println(PlainDep.module()); System.out.println(RuntimeDep.module()); System.out.println(ThirdPartyDeps.module()); + System.out.println(Dependent.module()); } } From 06c5c92193416b47ddfb59fa72ffb24e26ae0539 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Tue, 1 Jul 2025 08:27:45 +0100 Subject: [PATCH 11/11] fix: Add sorting for java_exports --- .../java_export_index/java_export_index.go | 145 +++++++++++++----- .../java_export_targets/expectedStderr.txt | 1 - 2 files changed, 110 insertions(+), 36 deletions(-) diff --git a/java/gazelle/private/java_export_index/java_export_index.go b/java/gazelle/private/java_export_index/java_export_index.go index 10b55447..32f7cbd2 100644 --- a/java/gazelle/private/java_export_index/java_export_index.go +++ b/java/gazelle/private/java_export_index/java_export_index.go @@ -1,12 +1,13 @@ package java_export_index import ( + "sort" + "github.com/bazel-contrib/rules_jvm/java/gazelle/private/sorted_set" "github.com/bazel-contrib/rules_jvm/java/gazelle/private/types" "github.com/bazelbuild/bazel-gazelle/label" "github.com/bazelbuild/bazel-gazelle/rule" "github.com/rs/zerolog" - "sort" ) // JavaExportResolveInfo captures metadata about a java_export rule. @@ -15,15 +16,43 @@ import ( type JavaExportResolveInfo struct { Rule *rule.Rule Label label.Label + DirectDependencies map[label.Label]bool InternalVisibility *sorted_set.SortedSet[label.Label] } -func NewJavaExportResolveInfoFromRule(repoName string, r *rule.Rule, file *rule.File) *JavaExportResolveInfo { +func (jei *JavaExportIndex) NewJavaExportResolveInfoFromRule(repoName string, r *rule.Rule, file *rule.File) *JavaExportResolveInfo { lbl := label.New(repoName, file.Pkg, r.Name()) exportPackageVisibility := label.New("", file.Pkg, "__pkg__") + + var parseErrors []error + deps, errors := attrLabels("deps", r, lbl) + parseErrors = append(parseErrors, errors...) + exports, errors := attrLabels("exports", r, lbl) + parseErrors = append(parseErrors, errors...) + runtimeDeps, errors := attrLabels("runtime_deps", r, lbl) + parseErrors = append(parseErrors, errors...) + + if len(parseErrors) > 0 { + jei.logger.Error(). + Errs("errors", errors). + Msgf("Errors parsing labels from fields of %s", lbl.String()) + } + + directDependencies := make(map[label.Label]bool, len(deps)+len(exports)+len(runtimeDeps)) + for _, d := range deps { + directDependencies[d] = true + } + for _, d := range exports { + directDependencies[d] = true + } + for _, d := range runtimeDeps { + directDependencies[d] = true + } + return &JavaExportResolveInfo{ Rule: r, Label: lbl, + DirectDependencies: directDependencies, InternalVisibility: sorted_set.NewSortedSetFn([]label.Label{exportPackageVisibility}, sorted_set.LabelLess), } } @@ -99,7 +128,7 @@ func (jei *JavaExportIndex) RecordJavaExport(repoName string, r *rule.Rule, f *r Str("label", lbl.String()). Msg("java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`") } - jei.javaExports[lbl] = NewJavaExportResolveInfoFromRule(repoName, r, f) + jei.javaExports[lbl] = jei.NewJavaExportResolveInfoFromRule(repoName, r, f) } // FinalizeIndex processes all the `java_exports` we've recorded when traversing the repository, to: @@ -117,8 +146,36 @@ func (jei *JavaExportIndex) FinalizeIndex() { return sorted_set.LabelLess(a.wantedToExportFrom, b.wantedToExportFrom) }) + // To ensure that we properly capture which java_exports export dependencies, + // we want to process the java_exports in topological order, starting with the ones that don't depend on other java_exports. + // To ensure this order, we rely on the following property: + // - If `java_export(X)` should transitively depend on `java_export(Y)`, + // - then X will have more transitive dependencies than Y, because it has _at least_ the same dependencies as Y. + // + // Therefore, we sort the java_exports by lowest number of transitive dependencies before calculating their imports. + + // Map to memoize the number of transitive dependencies for a given label. + transitiveDependencyCounts := make(map[label.Label]int) + // Map to memoize the translation from a label.Label's ResolveInputs to a set of its direct dependencies + labelsToDependencies := make(map[label.Label]map[label.Label]bool) + + // We want the exports with the _lowest_ amount of transitive dependencies to be processed first, + // So that other java_exports that might depend on them can do so. + sortedJavaExports := sorted_set.NewSortedSetFn[*JavaExportResolveInfo]([]*JavaExportResolveInfo{}, func(a, b *JavaExportResolveInfo) bool { + if transitiveDependencyCounts[a.Label] < transitiveDependencyCounts[b.Label] { + return true + } else { + return sorted_set.LabelLess(a.Label, b.Label) + } + }) + for _, javaExport := range jei.javaExports { - jei.calculateImportsForJavaExport(javaExport, exportConflicts) + jei.calculateTransitiveDependencies(javaExport.Label, transitiveDependencyCounts, labelsToDependencies) + sortedJavaExports.Add(javaExport) + } + + for _, javaExport := range sortedJavaExports.SortedSlice() { + jei.calculateImportsForJavaExport(javaExport, exportConflicts, labelsToDependencies) } // We need to collect and sort the conflicts to get a deterministic ordering of output for tests. @@ -135,25 +192,56 @@ func (jei *JavaExportIndex) FinalizeIndex() { jei.readyForResolve = true } -func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExportResolveInfo, conflicts *sorted_set.SortedSet[exportConflict]) { - var parseErrors []error - deps, errors := attrLabels("deps", javaExport.Rule, javaExport.Label) - parseErrors = append(parseErrors, errors...) - exports, errors := attrLabels("exports", javaExport.Rule, javaExport.Label) - parseErrors = append(parseErrors, errors...) - runtimeDeps, errors := attrLabels("runtime_deps", javaExport.Rule, javaExport.Label) - parseErrors = append(parseErrors, errors...) +func (jei *JavaExportIndex) calculateTransitiveDependencies(lbl label.Label, transitiveDependencies map[label.Label]int, labelsToDependencies map[label.Label]map[label.Label]bool) int { + storedTransitiveDeps, depHasBeenVisited := transitiveDependencies[lbl] + if depHasBeenVisited { + return storedTransitiveDeps + } - if len(parseErrors) > 0 { - jei.logger.Error(). - Errs("errors", errors). - Msgf("Errors parsing labels from fields of %s", javaExport.Label.String()) + transitiveDepsForLabel := 0 + + var directDependencies map[label.Label]bool + + if jei.IsJavaExport(lbl) { + export, _ := jei.javaExports[lbl] + directDependencies = export.DirectDependencies + } else { + if dependencies, depsAreMemoized := labelsToDependencies[lbl]; depsAreMemoized { + directDependencies = dependencies + } else { + directDependencies = make(map[label.Label]bool) + + resolveInputForDep := jei.labelsToResolveInputs[lbl] + for _, importedPkg := range resolveInputForDep.ImportedPackageNames.SortedSlice() { + lblToVisit, found := jei.packagesToLabelsDeclaringThem[importedPkg] + if !found || lblToVisit == label.NoLabel { + jei.logger.Debug(). + Str("package", importedPkg.Name). + Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") + continue + } + directDependencies[lblToVisit] = true + } + + labelsToDependencies[lbl] = directDependencies + } } - labelsToVisit := make([]label.Label, len(deps)) - _ = copy(labelsToVisit, deps) - labelsToVisit = append(labelsToVisit, exports...) - labelsToVisit = append(labelsToVisit, runtimeDeps...) + for dep := range directDependencies { + transitiveDepsForLabel += jei.calculateTransitiveDependencies(dep, transitiveDependencies, labelsToDependencies) + transitiveDepsForLabel += 1 // To account for the dep we're processing + } + + transitiveDependencies[lbl] = transitiveDepsForLabel + return transitiveDepsForLabel +} + +func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExportResolveInfo, conflicts *sorted_set.SortedSet[exportConflict], labelsToDependencies map[label.Label]map[label.Label]bool) { + + labelsToVisit := make([]label.Label, 0, len(javaExport.DirectDependencies)) + for dep, _ := range javaExport.DirectDependencies { + labelsToVisit = append(labelsToVisit, dep) + } for _, lbl := range labelsToVisit { if jei.IsJavaExport(lbl) { @@ -190,25 +278,12 @@ func (jei *JavaExportIndex) calculateImportsForJavaExport(javaExport *JavaExport javaExport.InternalVisibility.Add(visibilityLbl) // Queue every transitive dependency to be visited - resolveInputForDep := jei.labelsToResolveInputs[dep] - for _, importedPkg := range resolveInputForDep.ImportedPackageNames.SortedSlice() { - lblToVisit, found := jei.packagesToLabelsDeclaringThem[importedPkg] - if !found || lblToVisit == label.NoLabel { - jei.logger.Debug(). - Str("package", importedPkg.Name). - Msg("Found no label for imported java package. It's probably a standard library package, or a package from maven") - continue - } + for lblToVisit := range labelsToDependencies[dep] { if jei.IsJavaExport(lblToVisit) { continue } - exportingExport, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lblToVisit) + _, isExportedByAnotherJavaExport := jei.isExportedByJavaExport(lblToVisit) if isExportedByAnotherJavaExport { - conflicts.Add(exportConflict{ - dep: lblToVisit, - wantedToExportFrom: javaExport.Label, - alreadyExportedFrom: exportingExport.Label, - }) continue } if ok := transitiveDeps[lblToVisit]; !ok { diff --git a/java/gazelle/testdata/java_export_targets/expectedStderr.txt b/java/gazelle/testdata/java_export_targets/expectedStderr.txt index 25e47cff..b7c31495 100644 --- a/java/gazelle/testdata/java_export_targets/expectedStderr.txt +++ b/java/gazelle/testdata/java_export_targets/expectedStderr.txt @@ -1,3 +1,2 @@ {"level":"error","label":"//other_deps/src/main/java/com/example/other_deps/plain_deps:plain_deps_export","message":"java_export rule contained a non-empty `srcs` attribute, but it will be ignored during resolution. Instead, please use the `exports` or `runtime_deps` attributes and depend on the generated `java_library`"} -{"level":"error","dependency":"//nested/src/main/java/com/example/nested/child_export","java_exports":["//nested/src/main/java/com/example/nested/child_export:child_export_export","//nested/src/main/java/com/example/nested:nested_export"],"message":"Two `java_export` targets want to export the same dependency. This can lead to incorrect results, please disambiguate, e.g. by having export depend on other export explicitly."} {"level":"error","dependency":"//shared_dep/src/main/java/com/example/shared_dep/shared_dep","java_exports":["//shared_dep/src/main/java/com/example/shared_dep/export_one","//shared_dep/src/main/java/com/example/shared_dep/export_two"],"message":"Two `java_export` targets want to export the same dependency. This can lead to incorrect results, please disambiguate, e.g. by having export depend on other export explicitly."}