diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java index 99f8e90ad4c1e1..d08164e15334d0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java @@ -342,6 +342,7 @@ private void createProtoCompileAction(SupportData supportData, Collection transitiveImports = ProtoCommon.collectTransitiveImports(ruleContext, protoSources); - NestedSet protoPathFlags = ProtoCommon.collectTransitiveProtoPathFlags(ruleContext); - NestedSet protosInDirectDeps = ProtoCommon.computeProtosInDirectDeps(ruleContext); + String protoSourceRoot = ProtoCommon.getProtoSourceRoot(ruleContext); + NestedSet directProtoSourceRoots = + ProtoCommon.getProtoSourceRootsOfDirectDependencies(ruleContext, protoSourceRoot); + NestedSet protoPathFlags = + ProtoCommon.collectTransitiveProtoPathFlags(ruleContext, protoSourceRoot); + final SupportData supportData = SupportData.create( Predicates.alwaysTrue() /* nonWeakDepsPredicate */, @@ -55,6 +59,7 @@ public ConfiguredTarget create(RuleContext ruleContext) protosInDirectDeps, transitiveImports, protoPathFlags, + directProtoSourceRoots, !protoSources.isEmpty()); Artifact descriptorSetOutput = @@ -74,7 +79,8 @@ public ConfiguredTarget create(RuleContext ruleContext) descriptorSetOutput, true /* allowServices */, dependenciesDescriptorSets, - protoPathFlags); + protoPathFlags, + directProtoSourceRoots); Runfiles dataRunfiles = ProtoCommon.createDataRunfilesProvider(transitiveImports, ruleContext) @@ -90,7 +96,8 @@ public ConfiguredTarget create(RuleContext ruleContext) checkDepsProtoSources, descriptorSetOutput, transitiveDescriptorSetOutput, - protoPathFlags); + protoPathFlags, + protoSourceRoot); return new RuleConfiguredTargetBuilder(ruleContext) .setFilesToBuild(NestedSetBuilder.create(STABLE_ORDER, descriptorSetOutput)) diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java index 374b534cd9f194..2b6f88e2e66aa9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java @@ -100,29 +100,66 @@ public static NestedSet collectDependenciesDescriptorSets(RuleContext } /** - * Returns all proto source roots in this lib and in its transitive dependencies, each prefixed - * by {@code --proto_path}. + * Returns all proto source roots in this lib ({@code currentProtoSourceRoot}) and in its + * transitive dependencies, each prefixed by {@code --proto_path}. * - * Build will fail if the {@code proto_source_root} of the current lib is different than the - * package name. + * Assumes {@code currentProtoSourceRoot} is the same as the package name. */ - public static NestedSet collectTransitiveProtoPathFlags(RuleContext ruleContext) { + public static NestedSet collectTransitiveProtoPathFlags( + RuleContext ruleContext, String currentProtoSourceRoot) { NestedSetBuilder protoPathFlags = NestedSetBuilder.stableOrder(); // first add the protoSourceRoot of the current target, if any + if (currentProtoSourceRoot != null && !currentProtoSourceRoot.isEmpty()) { + protoPathFlags.add("--proto_path=" + currentProtoSourceRoot); + } + + for (ProtoSourcesProvider provider : ruleContext.getPrerequisites( + "deps", Mode.TARGET, ProtoSourcesProvider.class)) { + protoPathFlags.addTransitive(provider.getTransitiveProtoPathFlags()); + } + + return protoPathFlags.build(); + } + + /** + * Returns the {@code proto_source_root} of the current library or null if none is specified. + * + * Build will fail if the {@code proto_source_root} of the current library is different than the + * package name. + */ + @Nullable + public static String getProtoSourceRoot(RuleContext ruleContext) { String protoSourceRoot = ruleContext.attributes().get("proto_source_root", Type.STRING); if (protoSourceRoot != null && !protoSourceRoot.isEmpty()) { checkProtoSourceRootIsTheSameAsPackage(protoSourceRoot, ruleContext); - protoPathFlags.add("--proto_path=" + protoSourceRoot); + } + return protoSourceRoot; + } + + /** + * Returns a set of the {@code proto_source_root} collected from the current library and the + * direct dependencies. + * + * Assumes {@code currentProtoSourceRoot} is the same as the package name. + */ + public static NestedSet getProtoSourceRootsOfDirectDependencies( + RuleContext ruleContext, String currentProtoSourceRoot) { + NestedSetBuilder protoSourceRoots = NestedSetBuilder.stableOrder(); + if (currentProtoSourceRoot != null && !currentProtoSourceRoot.isEmpty()) { + protoSourceRoots.add(currentProtoSourceRoot); } for (ProtoSourcesProvider provider : ruleContext.getPrerequisites( - "deps", Mode.TARGET, ProtoSourcesProvider.class)) { - protoPathFlags.addTransitive(provider.getTransitiveProtoPathFlags()); + "deps", Mode.TARGET, ProtoSourcesProvider.class)) { + String protoSourceRoot = provider.getProtoSourceRoot(); + if (protoSourceRoot != null && !protoSourceRoot.isEmpty()) { + protoSourceRoots.add(provider.getProtoSourceRoot()); + } } - return protoPathFlags.build(); + return protoSourceRoots.build(); } private static void checkProtoSourceRootIsTheSameAsPackage( diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java index 374bf9b9fe5290..015c02c3f0e81b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java @@ -322,6 +322,7 @@ CustomCommandLine.Builder createProtoCompilerCommandLine() throws MissingPrerequ addIncludeMapArguments( result, areDepsStrict ? supportData.getProtosInDirectDeps() : null, + supportData.getDirectProtoSourceRoots(), supportData.getTransitiveImports()); if (areDepsStrict) { @@ -360,7 +361,8 @@ public static void writeDescriptorSet( Artifact output, boolean allowServices, NestedSet transitiveDescriptorSets, - NestedSet protoSourceRoots) { + NestedSet protoSourceRoots, + NestedSet directProtoSourceRoots) { if (protosToCompile.isEmpty()) { ruleContext.registerAction( FileWriteAction.createEmptyWithInputs( @@ -376,6 +378,7 @@ public static void writeDescriptorSet( transitiveSources, protosInDirectDeps, protoSourceRoots, + directProtoSourceRoots, ruleContext.getLabel(), ImmutableList.of(output), "Descriptor Set", @@ -423,6 +426,7 @@ public static void registerActions( NestedSet transitiveSources, NestedSet protosInDirectDeps, NestedSet protoSourceRoots, + NestedSet directProtoSourceRoots, Label ruleLabel, Iterable outputs, String flavorName, @@ -435,6 +439,7 @@ public static void registerActions( transitiveSources, protosInDirectDeps, protoSourceRoots, + directProtoSourceRoots, ruleLabel, outputs, flavorName, @@ -452,6 +457,7 @@ private static SpawnAction.Builder createActions( NestedSet transitiveSources, @Nullable NestedSet protosInDirectDeps, NestedSet protoSourceRoots, + NestedSet directProtoSourceRoots, Label ruleLabel, Iterable outputs, String flavorName, @@ -487,6 +493,7 @@ private static SpawnAction.Builder createActions( protosToCompile, transitiveSources, protoSourceRoots, + directProtoSourceRoots, areDepsStrict(ruleContext) ? protosInDirectDeps : null, ruleLabel, allowServices, @@ -524,11 +531,13 @@ static CustomCommandLine createCommandLineFromToolchains( Iterable protosToCompile, NestedSet transitiveSources, NestedSet transitiveProtoPathFlags, + NestedSet directProtoSourceRoots, @Nullable NestedSet protosInDirectDeps, Label ruleLabel, boolean allowServices, ImmutableList protocOpts) { CustomCommandLine.Builder cmdLine = CustomCommandLine.builder(); + cmdLine.addAll(transitiveProtoPathFlags); cmdLine.addAll(transitiveProtoPathFlags); @@ -565,7 +574,7 @@ static CustomCommandLine createCommandLineFromToolchains( cmdLine.addAll(protocOpts); // Add include maps - addIncludeMapArguments(cmdLine, protosInDirectDeps, transitiveSources); + addIncludeMapArguments(cmdLine, protosInDirectDeps, directProtoSourceRoots, transitiveSources); if (protosInDirectDeps != null) { cmdLine.addFormatted(STRICT_DEPS_FLAG_TEMPLATE, ruleLabel); @@ -586,6 +595,7 @@ static CustomCommandLine createCommandLineFromToolchains( static void addIncludeMapArguments( CustomCommandLine.Builder commandLine, @Nullable NestedSet protosInDirectDependencies, + NestedSet directProtoSourceRoots, NestedSet transitiveImports) { commandLine.addAll( VectorArg.of(transitiveImports) @@ -596,7 +606,14 @@ static void addIncludeMapArguments( "--direct_dependencies", VectorArg.join(":") .each(protosInDirectDependencies) - .mapped(ProtoCompileActionBuilder::expandToPathIgnoringRepository)); + .mapped((Artifact proto, Consumer args) -> { + for (String directProtoSourceRoot : directProtoSourceRoots) { + expandToPathIgnoringSourceRoot(proto, directProtoSourceRoot, args); + } + expandToPathIgnoringRepository(proto, args); + }) + ); + } else { // The proto compiler requires an empty list to turn on strict deps checking commandLine.add("--direct_dependencies="); @@ -627,6 +644,20 @@ private static String getPathIgnoringRepository(Artifact artifact) { .toString(); } + private static void expandToPathIgnoringSourceRoot( + Artifact artifact, String directProtoSourceRoot, Consumer args) { + try { + String relativePath = artifact.getRootRelativePath() + .relativeTo( + artifact.getOwnerLabel().getPackageIdentifier().getRepository().getPathUnderExecRoot()) + .relativeTo(directProtoSourceRoot) + .toString(); + args.accept(relativePath); + } catch (IllegalArgumentException exception) { + // do nothing + } + } + /** * Describes a toolchain and the value to replace for a $(OUT) that might appear in its * commandLine() (e.g., "bazel-out/foo.srcjar"). diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoSourcesProvider.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoSourcesProvider.java index bf2ed12b3b8e97..25ea43b0907c4b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoSourcesProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoSourcesProvider.java @@ -42,7 +42,8 @@ public static ProtoSourcesProvider create( NestedSet checkDepsProtoSources, Artifact directDescriptorSet, NestedSet transitiveDescriptorSets, - NestedSet protoPathFlags) { + NestedSet protoPathFlags, + String protoSourceRoot) { return new AutoValue_ProtoSourcesProvider( transitiveImports, transitiveProtoSources, @@ -50,7 +51,8 @@ public static ProtoSourcesProvider create( checkDepsProtoSources, directDescriptorSet, transitiveDescriptorSets, - protoPathFlags); + protoPathFlags, + protoSourceRoot); } /** @@ -135,5 +137,10 @@ public static ProtoSourcesProvider create( */ public abstract NestedSet getTransitiveProtoPathFlags(); + /** + * The {@code proto_source_root} of the current library. + */ + public abstract String getProtoSourceRoot(); + ProtoSourcesProvider() {} } diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/SupportData.java b/src/main/java/com/google/devtools/build/lib/rules/proto/SupportData.java index 9e02d190d5d827..ad2c09c3ee6b6b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/SupportData.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/SupportData.java @@ -34,10 +34,11 @@ public static SupportData create( NestedSet protosInDirectDeps, NestedSet transitiveImports, NestedSet transitiveProtoPathFlags, + NestedSet directProtoSourceRoots, boolean hasProtoSources) { return new AutoValue_SupportData( nonWeakDepsPredicate, protoSources, transitiveImports, protosInDirectDeps, - transitiveProtoPathFlags, hasProtoSources); + transitiveProtoPathFlags, directProtoSourceRoots, hasProtoSources); } public abstract Predicate getNonWeakDepsPredicate(); @@ -57,6 +58,11 @@ public static SupportData create( */ public abstract NestedSet getTransitiveProtoPathFlags(); + /** + * The {@code proto_source_root}'s collected from the current library and the direct dependencies. + */ + public abstract NestedSet getDirectProtoSourceRoots(); + public abstract boolean hasProtoSources(); SupportData() {} diff --git a/src/test/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilderTest.java b/src/test/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilderTest.java index 9881b194b3788d..7cb4912a27174b 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilderTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilderTest.java @@ -83,6 +83,7 @@ public void commandLine_basic() throws Exception { artifact("//:dont-care", "import1.proto"), artifact("//:dont-care", "import2.proto")), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); CustomCommandLine cmdLine = @@ -94,6 +95,7 @@ public void commandLine_basic() throws Exception { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.stableOrder().build(), + /*directProtoSourceRoots=*/ NestedSetBuilder.stableOrder().build(), null /* protosInDirectDeps */, Label.parseAbsoluteUnchecked("//foo:bar"), true /* allowServices */, @@ -120,6 +122,7 @@ public void commandline_derivedArtifact() { NestedSetBuilder.emptySet(STABLE_ORDER) /* protosInDirectDeps */, NestedSetBuilder.emptySet(STABLE_ORDER) /* transitiveImports */, /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); CustomCommandLine cmdLine = @@ -128,6 +131,7 @@ public void commandline_derivedArtifact() { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), null /* protosInDirectDeps */, Label.parseAbsoluteUnchecked("//foo:bar"), true /* allowServices */, @@ -155,6 +159,7 @@ public void commandLine_strictDeps() throws Exception { artifact("//:dont-care", "import1.proto"), artifact("//:dont-care", "import2.proto")), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); CustomCommandLine cmdLine = @@ -163,6 +168,7 @@ public void commandLine_strictDeps() throws Exception { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), supportData.getProtosInDirectDeps(), Label.parseAbsoluteUnchecked("//foo:bar"), true /* allowServices */, @@ -189,6 +195,7 @@ public void otherParameters() throws Exception { NestedSetBuilder.emptySet(STABLE_ORDER) /* protosInDirectDeps */, NestedSetBuilder.emptySet(STABLE_ORDER), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); CustomCommandLine cmdLine = @@ -197,6 +204,7 @@ public void otherParameters() throws Exception { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), supportData.getProtosInDirectDeps(), Label.parseAbsoluteUnchecked("//foo:bar"), false /* allowServices */, @@ -233,6 +241,7 @@ public String toString() { NestedSetBuilder.emptySet(STABLE_ORDER) /* protosInDirectDeps */, NestedSetBuilder.emptySet(STABLE_ORDER), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); CustomCommandLine cmdLine = @@ -241,6 +250,7 @@ public String toString() { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), supportData.getProtosInDirectDeps(), Label.parseAbsoluteUnchecked("//foo:bar"), true /* allowServices */, @@ -264,6 +274,7 @@ public void exceptionIfSameName() throws Exception { NestedSetBuilder.emptySet(STABLE_ORDER) /* protosInDirectDeps */, NestedSetBuilder.emptySet(STABLE_ORDER), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), true /* hasProtoSources */); ProtoLangToolchainProvider toolchain1 = @@ -288,6 +299,7 @@ public void exceptionIfSameName() throws Exception { supportData.getDirectProtoSources(), supportData.getTransitiveImports(), /*transitiveProtoPathFlags=*/ NestedSetBuilder.emptySet(STABLE_ORDER), + /*directProtoSourceRoots=*/ NestedSetBuilder.emptySet(STABLE_ORDER), supportData.getProtosInDirectDeps(), Label.parseAbsoluteUnchecked("//foo:bar"), true /* allowServices */, @@ -383,7 +395,8 @@ private static Iterable protoArgv( NestedSet transitiveImportsNestedSet = NestedSetBuilder.wrap(STABLE_ORDER, transitiveImports); ProtoCompileActionBuilder.addIncludeMapArguments( - commandLine, protosInDirectDependenciesBuilder, transitiveImportsNestedSet); + commandLine, protosInDirectDependenciesBuilder, + NestedSetBuilder.emptySet(STABLE_ORDER), transitiveImportsNestedSet); return commandLine.build().arguments(); } } diff --git a/src/test/shell/bazel/bazel_proto_library_test.sh b/src/test/shell/bazel/bazel_proto_library_test.sh new file mode 100755 index 00000000000000..0446d49639ace7 --- /dev/null +++ b/src/test/shell/bazel/bazel_proto_library_test.sh @@ -0,0 +1,423 @@ +#!/bin/bash +# +# Copyright 2016 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. +# +# Tests the examples provided in Bazel +# + +# Load the test setup defined in the parent directory +CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${CURRENT_DIR}/../integration_test_setup.sh" \ + || { echo "integration_test_setup.sh not found!" >&2; exit 1; } + +# Appends to "WORKSPACE" the declaration of 2 local repositories. +# Assumes the main content of WORKSPACE was created previously. +function add_local_repos_to_workspace() { + cat >> WORKSPACE <> "$workspace"WORKSPACE << EOF +# proto_library, cc_proto_library, and java_proto_library rules implicitly +# depend on @com_google_protobuf for protoc and proto runtimes. +# This statement defines the @com_google_protobuf repo. +http_archive( + name = "com_google_protobuf", + sha256 = "cef7f1b5a7c5fba672bec2a319246e8feba471f04dcebfe362d55930ee7c1c30", + strip_prefix = "protobuf-3.5.0", + urls = ["https://github.com/google/protobuf/archive/v3.5.0.zip"], +) + +# java_lite_proto_library rules implicitly depend on @com_google_protobuf_javalite//:javalite_toolchain, +# which is the JavaLite proto runtime (base classes and common utilities). +http_archive( + name = "com_google_protobuf_javalite", + sha256 = "d8a2fed3708781196f92e1e7e7e713cf66804bd2944894401057214aff4f468e", + strip_prefix = "protobuf-5e8916e881c573c5d83980197a6f783c132d4276", + urls = ["https://github.com/google/protobuf/archive/5e8916e881c573c5d83980197a6f783c132d4276.zip"], +) +EOF +} + +# Creates directories and files with the structure: +# x/ +# person/ +# BUILD +# person.proto (imports "bar/bar.proto", has proto_source_root = "x/person") +# phonenumber/ +# phonenumber.proto +# phonebook/ +# BUILD +# phonebook.proto (imports "person.proto" & "phonenumber/phonenumber.proto") +# +# The BUILD files could use directly "proto_library" rules or a macro called +# "proto_library_macro" that should be created beforehand using write_macro(). +# +# Expected arguments: +# 1. The name of the proto library rule. Can be "proto_library" or +# "proto_library_macro". +# 2. A row in the BUILD file that specifies the proto_source_root attribute on +# proto_library. Should be left empty if a macro is used. +# 3. A load statement that includes a macro containing a wrapper around +# proto_library. +function write_setup() { + mkdir -p x/person/phonenumber + proto_library_name=$1 + proto_source_root=$2 + include_macro=$3 + + cat > x/person/BUILD << EOF +package(default_visibility = ["//visibility:public"]) +$include_macro +$proto_library_name( + name = "person_proto", + srcs = ["person.proto"], + deps = [":phonenumber_proto"], + $proto_source_root +) + +$proto_library_name( + name = "phonenumber_proto", + srcs = ["phonenumber/phonenumber.proto"], +) +EOF + + cat > x/person/person.proto << EOF +syntax = "proto2"; + +option java_package = "person"; +option java_outer_classname = "Person"; + +import "phonenumber/phonenumber.proto"; + +message PersonProto { + optional string name = 1; + + optional PhoneNumberProto phone = 2; +} +EOF + + cat > x/person/phonenumber/phonenumber.proto << EOF +syntax = "proto2"; + +option java_package = "person.phonenumber"; +option java_outer_classname = "PhoneNumber"; + +message PhoneNumberProto { + required string number = 1; +} +EOF + + mkdir -p x/phonebook + + cat > x/phonebook/BUILD << EOF +$proto_library_name( + name = "phonebook", + srcs = ["phonebook.proto"], + deps = ["//x/person:person_proto"], +) +EOF + + cat > x/phonebook/phonebook.proto << EOF +import "person.proto"; +import "phonenumber/phonenumber.proto"; + +message Agenda { + required PersonProto person = 1; + required PhoneNumberProto number = 2; +} +EOF +} + +# Creates the files in the following directory structure: +# proto_library/ +# BUILD <- empty +# src/ +# BUILD <- has target "all" for all .proto +# address.proto <- imports "person.proto" +# person.proto <- imports "address.proto" +# zip_code.proto +function write_regression_setup() { + mkdir -p proto_library/src + touch proto_library/BUILD + + cat > proto_library/src/BUILD << EOF +proto_library( + name = "all", + srcs = glob(["*.proto"]), + proto_source_root = package_name(), +) +EOF + + cat > proto_library/src/address.proto < proto_library/src/person.proto < proto_library/src/zip_code.proto < a/b/src/BUILD < a/b/src/address.proto < a/b/src/zip_code.proto < c/d/src/BUILD < c/d/src/person.proto < macros/BUILD << EOF +export_files(["proto_library_macro.bzl]) +EOF + + cat > macros/proto_library_macro.bzl << EOF +def proto_library_macro(name, srcs, deps = []): + native.proto_library( + name = name, + srcs = srcs, + deps = deps, + proto_source_root = native.package_name() + ) +EOF +} + +# Creates the directories and files from the following structure +# java/com/google/src/ +# BUILD +# A.java +function write_java_library() { + # should depend on x/foo:foo + mkdir -p java/com/google/src + cat > java/com/google/src/BUILD << EOF +java_library( + name = "top", + srcs = ["A.java"], + deps = [":jpl"] +) + +java_proto_library( + name = "jpl", + deps = ["//x/person:person_proto"] +) +EOF + + cat > java/com/google/src/A.java << EOF +import person.Person.PersonProto; +import person.phonenumber.PhoneNumber.PhoneNumberProto; + +public class A { + private PersonProto person; + + public A(PersonProto person) { + this.person = person; + PhoneNumberProto number = person.getPhone(); + } +} + +EOF + +} + +############# TESTS ############# + +function test_proto_source_root() { + write_workspace "" + write_setup "proto_library" "proto_source_root = 'x/person'" "" + bazel build //x/person:person_proto > "$TEST_log" || fail "Expected success" +} + +function test_proto_source_root_fails() { + write_workspace "" + # Don't specify the "proto_source_root" attribute and expect failure. + write_setup "proto_library" "" "" + bazel build //x/person:person_proto >& "$TEST_log" && fail "Expected failure" + expect_log "phonenumber/phonenumber.proto: File not found." +} + +function test_proto_source_root_macro() { + write_workspace "" + write_macro + write_setup "proto_library_macro" "" "load('//macros:proto_library_macro.bzl', 'proto_library_macro')" + bazel build //x/person:person_proto > "$TEST_log" || fail "Expected success" +} + +function test_proto_source_root_with_java_library() { + write_workspace "" + write_setup "proto_library" "proto_source_root = 'x/person'" "" + write_java_library + bazel build //java/com/google/src:top \ + --strict_java_deps=off > "$TEST_log" || fail "Expected success" +} + +function test_proto_source_root_glob() { + write_workspace "" + write_regression_setup + bazel build //proto_library/src:all >& "$TEST_log" || fail "Expected success" +} + +function test_proto_source_root_glob() { + write_workspace "" + write_regression_setup + bazel build //proto_library/src:all --strict_proto_deps=off >& "$TEST_log" \ + || fail "Expected success" +} + +# TODO(elenairina): Enable this after #4665 is fixed. +function DISABLED_test_proto_source_root_multiple_workspaces() { + write_workspace "a/b/" + write_workspace "c/d/" + write_workspace "" + add_local_repos_to_workspace + write_workspaces_setup + + bazel build @main_repo//src:all_protos >& "$TEST_log" || fail "Expected success" +} + +run_suite "Integration tests for proto_library" \ No newline at end of file