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

Commit bc83b504 authored by Sam Delmerico's avatar Sam Delmerico Committed by Gerrit Code Review
Browse files

Merge "convert java proto libraries with bp2build"

parents 2ace628b c768102b
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