Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c768102b authored by Sam Delmerico's avatar Sam Delmerico
Browse files

convert java proto libraries with bp2build

Allow java_libraries that depend on protobufs to be converted with
bp2build.

Bug: 215230097
Test: build/bazel/ci/bp2build.sh
Change-Id: I3ce52389e7e4e82755605ee277c1e527a6aebc6b
parent 5ee913f5
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ import (
	"strings"

	"android/soong/bazel"

	"github.com/google/blueprint"
)

func init() {
@@ -28,6 +30,11 @@ var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx Registrati
	ctx.RegisterModuleType("filegroup", FileGroupFactory)
})

// IsFilegroup checks that a module is a filegroup type
func IsFilegroup(ctx bazel.OtherModuleContext, m blueprint.Module) bool {
	return ctx.OtherModuleType(m) == "filegroup"
}

// https://docs.bazel.build/versions/master/be/general.html#filegroup
type bazelFilegroupAttributes struct {
	Srcs bazel.LabelListAttribute
+20 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ package android

import (
	"android/soong/bazel"
	"regexp"
	"strings"

	"github.com/google/blueprint"
@@ -26,6 +27,14 @@ const (
	canonicalPathFromRootDefault = true
)

var (
	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")

	ProtoSrcLabelPartition = bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup}
)

// TODO(ccross): protos are often used to communicate between multiple modules.  If the only
// way to convert a proto to source is to reference it as a source file, and external modules cannot
// reference source files in other modules, then every module that owns a proto file will need to
@@ -165,12 +174,11 @@ type protoAttrs struct {

// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
// information necessary for language-specific handling.
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, module Module, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
	var info Bp2buildProtoInfo
	if srcs.IsEmpty() {
		return info, false
	}
	m := module.base()

	info.Name = m.Name() + "_proto"
	attrs := protoAttrs{
@@ -205,3 +213,13 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, module Module, srcs baz

	return info, true
}

func isProtoFilegroup(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
	m, exists := ctx.ModuleFromName(label.OriginalModuleName)
	labelStr := label.Label
	if !exists || !IsFilegroup(ctx, m) {
		return labelStr, false
	}
	likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
	return labelStr, likelyProtos
}
+124 −0
Original line number Diff line number Diff line
// Copyright 2021 Google Inc. 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 bp2build

import (
	"fmt"
	"testing"

	"android/soong/android"
	"android/soong/java"
)

func runJavaProtoTestCase(t *testing.T, tc bp2buildTestCase) {
	t.Helper()
	(&tc).moduleTypeUnderTest = "java_library_static"
	(&tc).moduleTypeUnderTestFactory = java.LibraryFactory
	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}

func TestJavaProto(t *testing.T) {
	testCases := []struct {
		protoType                string
		javaLibraryType          string
		javaLibraryNameExtension string
	}{
		{
			protoType:                "nano",
			javaLibraryType:          "java_nano_proto_library",
			javaLibraryNameExtension: "java_proto_nano",
		},
		{
			protoType:                "micro",
			javaLibraryType:          "java_micro_proto_library",
			javaLibraryNameExtension: "java_proto_micro",
		},
		{
			protoType:                "lite",
			javaLibraryType:          "java_lite_proto_library",
			javaLibraryNameExtension: "java_proto_lite",
		},
		{
			protoType:                "stream",
			javaLibraryType:          "java_stream_proto_library",
			javaLibraryNameExtension: "java_proto_stream",
		},
		{
			protoType:                "full",
			javaLibraryType:          "java_proto_library",
			javaLibraryNameExtension: "java_proto",
		},
	}

	bp := `java_library_static {
    name: "java-protos",
    proto: {
        type: "%s",
    },
    srcs: ["a.proto"],
}`

	protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
		"srcs":                `["a.proto"]`,
		"strip_import_prefix": `""`,
	})

	for _, tc := range testCases {
		javaLibraryName := fmt.Sprintf("java-protos_%s", tc.javaLibraryNameExtension)

		runJavaProtoTestCase(t, bp2buildTestCase{
			description: fmt.Sprintf("java_proto %s", tc.protoType),
			blueprint:   fmt.Sprintf(bp, tc.protoType),
			expectedBazelTargets: []string{
				protoLibrary,
				makeBazelTarget(
					tc.javaLibraryType,
					javaLibraryName,
					attrNameToString{
						"deps": `[":java-protos_proto"]`,
					}),
				makeBazelTarget("java_library", "java-protos", attrNameToString{
					"deps": fmt.Sprintf(`[":%s"]`, javaLibraryName),
				}),
			},
		})
	}
}

func TestJavaProtoDefault(t *testing.T) {
	runJavaProtoTestCase(t, bp2buildTestCase{
		description: "java_proto",
		blueprint: `java_library_static {
    name: "java-protos",
    srcs: ["a.proto"],
}
`,
		expectedBazelTargets: []string{
			makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
				"srcs":                `["a.proto"]`,
				"strip_import_prefix": `""`,
			}),
			makeBazelTarget(
				"java_lite_proto_library",
				"java-protos_java_proto_lite",
				attrNameToString{
					"deps": `[":java-protos_proto"]`,
				}),
			makeBazelTarget("java_library", "java-protos", attrNameToString{
				"deps": `[":java-protos_java_proto_lite"]`,
			}),
		},
	})
}
+6 −27
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ package cc
import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"

	"android/soong/android"
@@ -34,12 +33,6 @@ const (
	protoSrcPartition = "proto"
)

var (
	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
)

// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
// properties which apply to either the shared or static version of a cc_library module.
type staticOrSharedAttributes struct {
@@ -61,46 +54,32 @@ type staticOrSharedAttributes struct {
	Enabled bazel.BoolAttribute
}

// groupSrcsByExtension partitions `srcs` into groups based on file extension.
func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
	// Check that a module is a filegroup type
	isFilegroup := func(m blueprint.Module) bool {
		return ctx.OtherModuleType(m) == "filegroup"
	}

	// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
	// macro.
	addSuffixForFilegroup := func(suffix string) bazel.LabelMapper {
		return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
			m, exists := ctx.ModuleFromName(label.OriginalModuleName)
			labelStr := label.Label
			if !exists || !isFilegroup(m) {
			if !exists || !android.IsFilegroup(ctx, m) {
				return labelStr, false
			}
			return labelStr + suffix, true
		}
	}

	isProtoFilegroup := func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
		m, exists := ctx.ModuleFromName(label.OriginalModuleName)
		labelStr := label.Label
		if !exists || !isFilegroup(m) {
			return labelStr, false
		}
		likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
		return labelStr, likelyProtos
	}

	// TODO(b/190006308): Handle language detection of sources in a Bazel rule.
	partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
		protoSrcPartition: bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup},
	labels := bazel.LabelPartitions{
		protoSrcPartition: android.ProtoSrcLabelPartition,
		cSrcPartition:     bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
		asSrcPartition:    bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
		// C++ is the "catch-all" group, and comprises generated sources because we don't
		// know the language of these sources until the genrule is executed.
		cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
	})
	}

	return partitioned
	return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
}

// bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ type bp2buildProtoDeps struct {
func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
	var ret bp2buildProtoDeps

	protoInfo, ok := android.Bp2buildProtoProperties(ctx, m, protoSrcs)
	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
	if !ok {
		return ret
	}
Loading