Skip to content

Commit

Permalink
Expose current repository name to Java with @AutoBazelRepository
Browse files Browse the repository at this point in the history
Java targets depending on `@bazel_tools//tools/java/runfiles` can add the new `@AutoBazelRepository` to a class to have an annotation processor generate a companion class with a `BAZEL_REPOSITORY` constant containing the repository name of the target that compiled the class.

This requires a small addition to JavaBuilder to parse the repository name out of the target label and pass it to javac as a processor option.

Work towards bazelbuild#16124

Closes bazelbuild#16534.

PiperOrigin-RevId: 487573496
Change-Id: Id9b6526ce32268089c91c6d17363d1e7682f64a4
  • Loading branch information
fmeum authored and Copybara-Service committed Nov 10, 2022
1 parent 76100bb commit 455454a
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,18 @@ public final void initializeJavacOpts() {

/** Computes javacopts for the current rule. */
private ImmutableList<String> computeJavacOpts(Collection<String> extraRuleJavacOpts) {
return ImmutableList.<String>builder()
.addAll(javaToolchain.getJavacOptions(ruleContext))
.addAll(extraRuleJavacOpts)
ImmutableList.Builder<String> javacOpts =
ImmutableList.<String>builder()
.addAll(javaToolchain.getJavacOptions(ruleContext))
.addAll(extraRuleJavacOpts);
if (activePlugins
.plugins()
.processorClasses()
.toSet()
.contains("com.google.devtools.build.runfiles.AutoBazelRepositoryProcessor")) {
javacOpts.add("-Abazel.repository=" + ruleContext.getRepository().getName());
}
return javacOpts
.addAll(computePerPackageJavacOpts(ruleContext, javaToolchain))
.addAll(addModuleJavacopts(ruleContext))
.addAll(ruleContext.getExpander().withDataLocations().tokenized("javacopts"))
Expand Down Expand Up @@ -538,8 +547,8 @@ public JavaTargetAttributes.Builder initCommon() {
public JavaTargetAttributes.Builder initCommon(
Collection<Artifact> extraSrcs, Iterable<String> extraJavacOpts) {
Preconditions.checkState(javacOpts == null);
javacOpts = computeJavacOpts(ImmutableList.copyOf(extraJavacOpts));
activePlugins = collectPlugins();
javacOpts = computeJavacOpts(ImmutableList.copyOf(extraJavacOpts));

JavaTargetAttributes.Builder javaTargetAttributes = new JavaTargetAttributes.Builder(semantics);
javaCompilationHelper =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,28 @@ public JavaInfo createJavaCompileAction(

JavaToolchainProvider toolchainProvider = javaToolchain;

JavaPluginInfo pluginInfo = mergeExportedJavaPluginInfo(plugins, deps);
ImmutableList.Builder<String> allJavacOptsBuilder =
ImmutableList.<String>builder()
.addAll(toolchainProvider.getJavacOptions(starlarkRuleContext.getRuleContext()))
.addAll(
javaSemantics.getCompatibleJavacOptions(
starlarkRuleContext.getRuleContext(), toolchainProvider));
if (pluginInfo
.plugins()
.processorClasses()
.toSet()
.contains("com.google.devtools.build.runfiles.AutoBazelRepositoryProcessor")) {
allJavacOptsBuilder.add(
"-Abazel.repository=" + starlarkRuleContext.getRuleContext().getRepository().getName());
}
allJavacOptsBuilder
.addAll(
JavaCommon.computePerPackageJavacOpts(
starlarkRuleContext.getRuleContext(), toolchainProvider))
.addAll(JavaModuleFlagsProvider.toFlags(addExports, addOpens))
.addAll(tokenize(javacOpts));

JavaLibraryHelper helper =
new JavaLibraryHelper(starlarkRuleContext.getRuleContext())
.setOutput(outputJar)
Expand All @@ -295,18 +317,7 @@ public JavaInfo createJavaCompileAction(
.setSourcePathEntries(sourcepathEntries)
.addAdditionalOutputs(annotationProcessorAdditionalOutputs)
.enableJspecify(enableJSpecify)
.setJavacOpts(
ImmutableList.<String>builder()
.addAll(toolchainProvider.getJavacOptions(starlarkRuleContext.getRuleContext()))
.addAll(
javaSemantics.getCompatibleJavacOptions(
starlarkRuleContext.getRuleContext(), toolchainProvider))
.addAll(
JavaCommon.computePerPackageJavacOpts(
starlarkRuleContext.getRuleContext(), toolchainProvider))
.addAll(JavaModuleFlagsProvider.toFlags(addExports, addOpens))
.addAll(tokenize(javacOpts))
.build());
.setJavacOpts(allJavacOptsBuilder.build());

if (injectingRuleKind != Starlark.NONE) {
helper.setInjectingRuleKind((String) injectingRuleKind);
Expand All @@ -316,7 +327,6 @@ public JavaInfo createJavaCompileAction(
streamProviders(deps, JavaCompilationArgsProvider.class).forEach(helper::addDep);
streamProviders(exports, JavaCompilationArgsProvider.class).forEach(helper::addExport);
helper.setCompilationStrictDepsMode(getStrictDepsMode(Ascii.toUpperCase(strictDepsMode)));
JavaPluginInfo pluginInfo = mergeExportedJavaPluginInfo(plugins, deps);
// Optimization: skip this if there are no annotation processors, to avoid unnecessarily
// disabling the direct classpath optimization if `enable_annotation_processor = False`
// but there aren't any annotation processors.
Expand Down
186 changes: 186 additions & 0 deletions src/test/shell/bazel/bazel_java_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1763,5 +1763,191 @@ EOF
bazel build //java/main:C2 &>"${TEST_log}" || fail "Expected to build"
}

function test_auto_bazel_repository() {
cat >> WORKSPACE <<'EOF'
local_repository(
name = "other_repo",
path = "other_repo",
)
EOF

mkdir -p pkg
cat > pkg/BUILD.bazel <<'EOF'
java_library(
name = "library",
srcs = ["Library.java"],
deps = ["@bazel_tools//tools/java/runfiles"],
visibility = ["//visibility:public"],
)
java_binary(
name = "binary",
srcs = ["Binary.java"],
main_class = "com.example.Binary",
deps = [
":library",
"@bazel_tools//tools/java/runfiles",
],
)
java_test(
name = "test",
srcs = ["Test.java"],
main_class = "com.example.Test",
use_testrunner = False,
deps = [
":library",
"@bazel_tools//tools/java/runfiles",
],
)
EOF

cat > pkg/Library.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
@AutoBazelRepository
public class Library {
public static void printRepositoryName() {
System.out.printf("in pkg/Library.java: '%s'%n", AutoBazelRepository_Library.NAME);
}
}
EOF

cat > pkg/Binary.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
public class Binary {
@AutoBazelRepository
private static class Class1 {
}
public static void main(String[] args) {
System.out.printf("in pkg/Binary.java: '%s'%n", AutoBazelRepository_Binary_Class1.NAME);
Library.printRepositoryName();
}
}
EOF

cat > pkg/Test.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
public class Test {
private static class Class1 {
@AutoBazelRepository
private static class Class2 {
}
}
public static void main(String[] args) {
System.out.printf("in pkg/Test.java: '%s'%n", AutoBazelRepository_Test_Class1_Class2.NAME);
Library.printRepositoryName();
}
}
EOF

mkdir -p other_repo
touch other_repo/WORKSPACE

mkdir -p other_repo/pkg
cat > other_repo/pkg/BUILD.bazel <<'EOF'
java_library(
name = "library2",
srcs = ["Library2.java"],
deps = ["@bazel_tools//tools/java/runfiles"],
)
java_binary(
name = "binary",
srcs = ["Binary.java"],
main_class = "com.example.Binary",
deps = [
":library2",
"@//pkg:library",
"@bazel_tools//tools/java/runfiles",
],
)
java_test(
name = "test",
srcs = ["Test.java"],
main_class = "com.example.Test",
use_testrunner = False,
deps = [
":library2",
"@//pkg:library",
"@bazel_tools//tools/java/runfiles",
],
)
EOF

cat > other_repo/pkg/Library2.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
@AutoBazelRepository
public class Library2 {
public static void printRepositoryName() {
System.out.printf("in external/other_repo/pkg/Library2.java: '%s'%n", AutoBazelRepository_Library2.NAME);
}
}
EOF

cat > other_repo/pkg/Binary.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
import static com.example.AutoBazelRepository_Binary.NAME;
@AutoBazelRepository
public class Binary {
public static void main(String[] args) {
System.out.printf("in external/other_repo/pkg/Binary.java: '%s'%n", NAME);
Library2.printRepositoryName();
Library.printRepositoryName();
}
}
EOF

cat > other_repo/pkg/Test.java <<'EOF'
package com.example;
import com.google.devtools.build.runfiles.AutoBazelRepository;
@AutoBazelRepository
public class Test {
public static void main(String[] args) {
System.out.printf("in external/other_repo/pkg/Test.java: '%s'%n", AutoBazelRepository_Test.NAME);
Library2.printRepositoryName();
Library.printRepositoryName();
}
}
EOF

bazel run //pkg:binary &>"$TEST_log" || fail "Run should succeed"
expect_log "in pkg/Binary.java: ''"
expect_log "in pkg/Library.java: ''"

bazel test --test_output=streamed //pkg:test &>"$TEST_log" || fail "Test should succeed"
expect_log "in pkg/Test.java: ''"
expect_log "in pkg/Library.java: ''"

bazel run @other_repo//pkg:binary &>"$TEST_log" || fail "Run should succeed"
expect_log "in external/other_repo/pkg/Binary.java: 'other_repo'"
expect_log "in external/other_repo/pkg/Library2.java: 'other_repo'"
expect_log "in pkg/Library.java: ''"

bazel test --test_output=streamed \
@other_repo//pkg:test &>"$TEST_log" || fail "Test should succeed"
expect_log "in external/other_repo/pkg/Test.java: 'other_repo'"
expect_log "in external/other_repo/pkg/Library2.java: 'other_repo'"
expect_log "in pkg/Library.java: ''"
}


run_suite "Java integration tests"
29 changes: 29 additions & 0 deletions tools/java/runfiles/AutoBazelRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2022 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.runfiles;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotating a class {@code Fooer} with this annotation generates a class {@code
* AutoBazelRepository_Fooer} defining a {@link String} constant {@code NAME} containing the
* canonical name of the repository containing the Bazel target that compiled the annotated class.
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AutoBazelRepository {}
Loading

0 comments on commit 455454a

Please sign in to comment.