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

Commit 9775d6e2 authored by Jingwen Chen's avatar Jingwen Chen Committed by Automerger Merge Worker
Browse files

Merge changes Ie5f793a0,I9b9674ba am: 3b171f40 am: 8179ddae am: 57354581

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1561259

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I230ee0637772e621a283c55183c602f9b82c3316
parents f155e3ef 57354581
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import (

func init() {
	RegisterModuleType("filegroup", FileGroupFactory)
	RegisterBp2BuildMutator("filegroup", bp2buildMutator)
	RegisterBp2BuildMutator("filegroup", FilegroupBp2Build)
}

// https://docs.bazel.build/versions/master/be/general.html#filegroup
@@ -51,7 +51,7 @@ func (bfg *bazelFilegroup) Name() string {
func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}

// TODO: Create helper functions to avoid this boilerplate.
func bp2buildMutator(ctx TopDownMutatorContext) {
func FilegroupBp2Build(ctx TopDownMutatorContext) {
	if m, ok := ctx.Module().(*fileGroup); ok {
		name := "__bp2build__" + m.base().BaseModuleName()
		ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
+2 −2
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDow
	f := func(ctx RegisterMutatorsContext) {
		ctx.TopDown(mutatorName, m)
	}
	bp2buildMutators = append(bp2buildMutators, f)
	ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
}

func (ctx *TestContext) Register() {
@@ -100,7 +100,7 @@ func (ctx *TestContext) Register() {

// RegisterForBazelConversion prepares a test context for bp2build conversion.
func (ctx *TestContext) RegisterForBazelConversion() {
	RegisterMutatorsForBazelConversion(ctx.Context.Context, bp2buildMutators)
	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildMutators)
}

func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
+3 −0
Original line number Diff line number Diff line
@@ -31,4 +31,7 @@ type Properties struct {
type BazelTargetModuleProperties struct {
	// The Bazel rule class for this target.
	Rule_class string

	// The target label for the bzl file containing the definition of the rule class.
	Bzl_load_location string
}
+83 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ import (
	"android/soong/android"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/blueprint"
@@ -31,6 +32,60 @@ type BazelAttributes struct {
type BazelTarget struct {
	name            string
	content         string
	ruleClass       string
	bzlLoadLocation string
}

// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file,
// as opposed to a native rule built into Bazel.
func (t BazelTarget) IsLoadedFromStarlark() bool {
	return t.bzlLoadLocation != ""
}

// BazelTargets is a typedef for a slice of BazelTarget objects.
type BazelTargets []BazelTarget

// String returns the string representation of BazelTargets, without load
// statements (use LoadStatements for that), since the targets are usually not
// adjacent to the load statements at the top of the BUILD file.
func (targets BazelTargets) String() string {
	var res string
	for i, target := range targets {
		res += target.content
		if i != len(targets)-1 {
			res += "\n\n"
		}
	}
	return res
}

// LoadStatements return the string representation of the sorted and deduplicated
// Starlark rule load statements needed by a group of BazelTargets.
func (targets BazelTargets) LoadStatements() string {
	bzlToLoadedSymbols := map[string][]string{}
	for _, target := range targets {
		if target.IsLoadedFromStarlark() {
			bzlToLoadedSymbols[target.bzlLoadLocation] =
				append(bzlToLoadedSymbols[target.bzlLoadLocation], target.ruleClass)
		}
	}

	var loadStatements []string
	for bzl, ruleClasses := range bzlToLoadedSymbols {
		loadStatement := "load(\""
		loadStatement += bzl
		loadStatement += "\", "
		ruleClasses = android.SortedUniqueStrings(ruleClasses)
		for i, ruleClass := range ruleClasses {
			loadStatement += "\"" + ruleClass + "\""
			if i != len(ruleClasses)-1 {
				loadStatement += ", "
			}
		}
		loadStatement += ")"
		loadStatements = append(loadStatements, loadStatement)
	}
	return strings.Join(android.SortedUniqueStrings(loadStatements), "\n")
}

type bpToBuildContext interface {
@@ -104,8 +159,8 @@ func propsToAttributes(props map[string]string) string {
	return attributes
}

func GenerateSoongModuleTargets(ctx bpToBuildContext, codegenMode CodegenMode) map[string][]BazelTarget {
	buildFileToTargets := make(map[string][]BazelTarget)
func GenerateSoongModuleTargets(ctx bpToBuildContext, codegenMode CodegenMode) map[string]BazelTargets {
	buildFileToTargets := make(map[string]BazelTargets)
	ctx.VisitAllModules(func(m blueprint.Module) {
		dir := ctx.ModuleDir(m)
		var t BazelTarget
@@ -127,22 +182,44 @@ func GenerateSoongModuleTargets(ctx bpToBuildContext, codegenMode CodegenMode) m
	return buildFileToTargets
}

// Helper method to trim quotes around strings.
func trimQuotes(s string) string {
	if s == "" {
		// strconv.Unquote would error out on empty strings, but this method
		// allows them, so return the empty string directly.
		return ""
	}
	ret, err := strconv.Unquote(s)
	if err != nil {
		// Panic the error immediately.
		panic(fmt.Errorf("Trying to unquote '%s', but got error: %s", s, err))
	}
	return ret
}

func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
	// extract the bazel attributes from the module.
	props := getBuildProperties(ctx, m)

	// extract the rule class name from the attributes. Since the string value
	// will be string-quoted, remove the quotes here.
	ruleClass := strings.Replace(props.Attrs["rule_class"], "\"", "", 2)
	ruleClass := trimQuotes(props.Attrs["rule_class"])
	// Delete it from being generated in the BUILD file.
	delete(props.Attrs, "rule_class")

	// extract the bzl_load_location, and also remove the quotes around it here.
	bzlLoadLocation := trimQuotes(props.Attrs["bzl_load_location"])
	// Delete it from being generated in the BUILD file.
	delete(props.Attrs, "bzl_load_location")

	// Return the Bazel target with rule class and attributes, ready to be
	// code-generated.
	attributes := propsToAttributes(props.Attrs)
	targetName := targetNameForBp2Build(ctx, m)
	return BazelTarget{
		name:            targetName,
		ruleClass:       ruleClass,
		bzlLoadLocation: bzlLoadLocation,
		content: fmt.Sprintf(
			bazelTarget,
			ruleClass,
+200 −26
Original line number Diff line number Diff line
@@ -268,10 +268,176 @@ func TestGenerateBazelTargetModules(t *testing.T) {
	}
}

func TestLoadStatements(t *testing.T) {
	testCases := []struct {
		bazelTargets           BazelTargets
		expectedLoadStatements string
	}{
		{
			bazelTargets: BazelTargets{
				BazelTarget{
					name:            "foo",
					ruleClass:       "cc_library",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
			},
			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
		},
		{
			bazelTargets: BazelTargets{
				BazelTarget{
					name:            "foo",
					ruleClass:       "cc_library",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
				BazelTarget{
					name:            "bar",
					ruleClass:       "cc_library",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
			},
			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
		},
		{
			bazelTargets: BazelTargets{
				BazelTarget{
					name:            "foo",
					ruleClass:       "cc_library",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
				BazelTarget{
					name:            "bar",
					ruleClass:       "cc_binary",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
			},
			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`,
		},
		{
			bazelTargets: BazelTargets{
				BazelTarget{
					name:            "foo",
					ruleClass:       "cc_library",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
				BazelTarget{
					name:            "bar",
					ruleClass:       "cc_binary",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
				BazelTarget{
					name:            "baz",
					ruleClass:       "java_binary",
					bzlLoadLocation: "//build/bazel/rules:java.bzl",
				},
			},
			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")
load("//build/bazel/rules:java.bzl", "java_binary")`,
		},
		{
			bazelTargets: BazelTargets{
				BazelTarget{
					name:            "foo",
					ruleClass:       "cc_binary",
					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
				},
				BazelTarget{
					name:            "bar",
					ruleClass:       "java_binary",
					bzlLoadLocation: "//build/bazel/rules:java.bzl",
				},
				BazelTarget{
					name:      "baz",
					ruleClass: "genrule",
					// Note: no bzlLoadLocation for native rules
				},
			},
			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
load("//build/bazel/rules:java.bzl", "java_binary")`,
		},
	}

	for _, testCase := range testCases {
		actual := testCase.bazelTargets.LoadStatements()
		expected := testCase.expectedLoadStatements
		if actual != expected {
			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
		}
	}

}

func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) {
	testCases := []struct {
		bp                       string
		expectedBazelTarget      string
		expectedBazelTargetCount int
		expectedLoadStatements   string
	}{
		{
			bp: `custom {
    name: "bar",
}`,
			expectedBazelTarget: `my_library(
    name = "bar",
)

my_proto_library(
    name = "bar_my_proto_library_deps",
)

proto_library(
    name = "bar_proto_library_deps",
)`,
			expectedBazelTargetCount: 3,
			expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library")
load("//build/bazel/rules:rules.bzl", "my_library")`,
		},
	}

	dir := "."
	for _, testCase := range testCases {
		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
		ctx := android.NewTestContext(config)
		ctx.RegisterModuleType("custom", customModuleFactory)
		ctx.RegisterBp2BuildMutator("custom_starlark", customBp2BuildMutatorFromStarlark)
		ctx.RegisterForBazelConversion()

		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
		android.FailIfErrored(t, errs)
		_, errs = ctx.ResolveDependencies(config)
		android.FailIfErrored(t, errs)

		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, Bp2Build)[dir]
		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
			t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
		}

		actualBazelTargets := bazelTargets.String()
		if actualBazelTargets != testCase.expectedBazelTarget {
			t.Errorf(
				"Expected generated Bazel target to be '%s', got '%s'",
				testCase.expectedBazelTarget,
				actualBazelTargets,
			)
		}

		actualLoadStatements := bazelTargets.LoadStatements()
		if actualLoadStatements != testCase.expectedLoadStatements {
			t.Errorf(
				"Expected generated load statements to be '%s', got '%s'",
				testCase.expectedLoadStatements,
				actualLoadStatements,
			)
		}
	}
}

func TestModuleTypeBp2Build(t *testing.T) {
	testCases := []struct {
		moduleTypeUnderTest                string
		moduleTypeUnderTestFactory         android.ModuleFactory
		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
		bp                                 string
		expectedBazelTarget                string
		description                        string
@@ -280,6 +446,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "filegroup with no srcs",
			moduleTypeUnderTest:                "filegroup",
			moduleTypeUnderTestFactory:         android.FileGroupFactory,
			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
			bp: `filegroup {
	name: "foo",
	srcs: [],
@@ -294,6 +461,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "filegroup with srcs",
			moduleTypeUnderTest:                "filegroup",
			moduleTypeUnderTestFactory:         android.FileGroupFactory,
			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
			bp: `filegroup {
	name: "foo",
	srcs: ["a", "b"],
@@ -310,6 +478,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "genrule with command line variable replacements",
			moduleTypeUnderTest:                "genrule",
			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
			bp: `genrule {
    name: "foo",
    out: ["foo.out"],
@@ -335,6 +504,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "genrule using $(locations :label)",
			moduleTypeUnderTest:                "genrule",
			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
			bp: `genrule {
    name: "foo",
    out: ["foo.out"],
@@ -360,6 +530,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "genrule using $(location) label should substitute first tool label automatically",
			moduleTypeUnderTest:                "genrule",
			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
			bp: `genrule {
    name: "foo",
    out: ["foo.out"],
@@ -386,6 +557,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "genrule using $(locations) label should substitute first tool label automatically",
			moduleTypeUnderTest:                "genrule",
			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
			bp: `genrule {
    name: "foo",
    out: ["foo.out"],
@@ -412,6 +584,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
			description:                        "genrule without tools or tool_files can convert successfully",
			moduleTypeUnderTest:                "genrule",
			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
			bp: `genrule {
    name: "foo",
    out: ["foo.out"],
@@ -436,6 +609,7 @@ func TestModuleTypeBp2Build(t *testing.T) {
		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
		ctx := android.NewTestContext(config)
		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
		ctx.RegisterForBazelConversion()

		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
Loading